refactor: 全面 fail-fast 化(去兜底)+ 泛型补译/解引用宽度修复

- 全量降级点改 fail-fast:23 文件约 140+ 处静默 i32/i8*/void/continue 兜底改为 HandlesType.fatal_error(python traceback 风格)或 VLogger.error 终止,暴露上游根因;保留语言语义默认(无注解 i32/infer 链/CIf/star 回退)
- 泛型特化 Phase B 补译 reemit 强制发射方法体(修复 list[...] define 缺失)
- c.Deref 读取宽度仅按赋值直接 RHS 推断(修复 CurAssignAnnot 残留误判 i32)
- 类型别名清理:t.CChar|t.CPtr→str、t.CInt→int 等
This commit is contained in:
TermiNexus committed 2026-08-13 02:11:49 +08:00
1 parent 8f484f6860
commit 9d3483e97e
39 files changed
+1086 -738

No files matched your search

+1 -1
View File
@@ -481,7 +481,7 @@ def get_includes_binary_dir() -> str:
def print_config():
"""打印当前配置"""
buf: t.CChar | t.CPtr = VLogger.fmt_buf()
buf: str = VLogger.fmt_buf()
if buf is None:
return
if ProjectName is not None:
+14 -7
View File
@@ -125,7 +125,7 @@ def TranslateFileGetTrans(mb: memhub.MemBuddy | t.CPtr, file_path: str,
# <source line>
# SyntaxError: <message>
HandlesType.dump_parse_traceback(file_path)
fb_parse: t.CChar | t.CPtr = VLogger.fmt_buf()
fb_parse: str = VLogger.fmt_buf()
if fb_parse is not None:
err_line: t.CInt = ast.get_parse_err_line()
err_col: t.CInt = ast.get_parse_err_col()
@@ -216,6 +216,10 @@ def TranslateFileGetTrans(mb: memhub.MemBuddy | t.CPtr, file_path: str,
gen.extract_module_docstrings(tree, sha1_val)
ret: int = tr.translate(tree)
if ret != 0:
fb_tf: str = VLogger.fmt_buf()
if fb_tf is not None:
viperlib.snprintf(fb_tf, 1024, "文件翻译失败: %s", file_path)
VLogger.error(fb_tf, "Translate")
return None
return tr
@@ -396,7 +400,7 @@ def compile_ll_to_obj(ir_path: str, output_dir: str, module_name: str, cc_cmd: s
asan_path, ir_path)
opt_ret: int = stdlib.system(opt_cmd)
if opt_ret != 0:
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "opt ASan 插桩失败 (module=%s)", module_name)
VLogger.error(fb, "ASAN")
@@ -414,7 +418,7 @@ def compile_ll_to_obj(ir_path: str, output_dir: str, module_name: str, cc_cmd: s
# 避免 subprocess 管道捕获丢失输出
sys_ret: int = stdlib.system(cmd)
if sys_ret != 0:
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "编译失败 (module=%s, cmd=%s)", module_name, cmd)
VLogger.error(fb, "LLC")
@@ -430,17 +434,20 @@ def _CollectObjFilesImpl(base_dir: str, bd_len: t.CSizeT,
"""
find_data: w32.win32file.WIN32_FIND_DATAA | t.CPtr = _mbuddy.alloc(w32.win32file.WIN32_FIND_DATAA.__sizeof__())
if find_data is None:
VLogger.warning("_CollectObjFilesImpl 分配 find_data 失败,少收集 .obj", "collect")
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:
VLogger.warning("_CollectObjFilesImpl 分配 pattern 失败,少收集 .obj", "collect")
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:
VLogger.warning("_CollectObjFilesImpl 无法打开目录,少收集 .obj", "collect")
return out_pos
while True:
@@ -543,7 +550,7 @@ def link_obj_to_exe(output_dir: str, module_name: str, linker_cmd: str, linker_f
if includes_binary_dir is not None:
extra_len = collect_obj_files(includes_binary_dir, extra_objs, EXTRA_BUF_SIZE)
if extra_len > 0:
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "附加 %d 字节的 includes.binary .obj 文件", extra_len)
VLogger.info(fb, "link")
@@ -585,7 +592,7 @@ def link_obj_to_exe(output_dir: str, module_name: str, linker_cmd: str, linker_f
VLogger.error("subprocess.run 返回 None", "link")
return 1
if result.returncode != 0:
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "链接失败,返回码: %d", result.returncode)
VLogger.error(fb, "link")
@@ -628,7 +635,7 @@ def compile_module_to_obj(ir_buf: bytes, ir_len: t.CSizeT,
# Step 1: 写 .ll 文件
ret: int = write_ir_to_file(ir_buf, ir_len, temp_dir, module_name)
if ret != 0:
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "写 .ll 失败: %s", module_name)
VLogger.error(fb, "compile")
@@ -714,7 +721,7 @@ def link_objs_to_exe(obj_paths: str, obj_paths_len: t.CSizeT,
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()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "链接失败,返回码: %d, 命令: %s", result.returncode, cmd)
VLogger.error(fb, "link")
+33 -17
View File
@@ -84,7 +84,8 @@ class AssignGenMixin:
if k == ast.ASTKind.Constant:
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(val_node)
if cn.const_kind != ast.CONST_INT:
return 0
# 非 INT 常量:直接报错终止(fail-fast)
HandlesType.fatal_error(val_node, "CDefine 值提取失败:无法从表达式解析编译期常量", "TypeError")
return cn.int_val
# Case 2: BinOp — 如 FOREGROUND_RED | FOREGROUND_GREEN
@@ -100,7 +101,8 @@ class AssignGenMixin:
return left_val + right_val
if bop.op == ast.OpKind.Sub:
return left_val - right_val
return 0
# 未知 BinOp 运算符:直接报错终止(fail-fast)
HandlesType.fatal_error(val_node, "CDefine 值提取失败:无法从表达式解析编译期常量", "TypeError")
# Case 3: Name — 引用已注册的 CDefine 常量
if k == ast.ASTKind.Name:
@@ -109,7 +111,8 @@ class AssignGenMixin:
looked_up: int = HandlesType.lookup_cdefine_constant(nm.id)
if HandlesType.is_cdefine_found() != 0:
return looked_up
return 0
# 引用未注册:直接报错终止(fail-fast)
HandlesType.fatal_error(val_node, "CDefine 值提取失败:无法从表达式解析编译期常量", "TypeError")
# Case 4: Call — 如 t.CUnsignedLong(-11)
if k == ast.ASTKind.Call:
@@ -121,7 +124,8 @@ class AssignGenMixin:
first_arg: ast.AST | t.CPtr = cl_args_list.get(0)
arg_val: int = self.extract_cdefine_int_value(first_arg)
return arg_val
return 0
# Call 无参数:直接报错终止(fail-fast)
HandlesType.fatal_error(val_node, "CDefine 值提取失败:无法从表达式解析编译期常量", "TypeError")
# Case 5: UnaryOp — 如 -11
if k == ast.ASTKind.UnaryOp:
@@ -133,9 +137,11 @@ class AssignGenMixin:
return operand_val
if uop.op == ast.OpKind.Invert:
return ~operand_val
return 0
# 未知 UnaryOp 运算符:直接报错终止(fail-fast)
HandlesType.fatal_error(val_node, "CDefine 值提取失败:无法从表达式解析编译期常量", "TypeError")
return 0
# 未知节点类型:直接报错终止(fail-fast)
HandlesType.fatal_error(val_node, "CDefine 值提取失败:无法从表达式解析编译期常量", "TypeError")
# ============================================================
# _register_cdefine_from_value - 注册 CDefine 常量(浮点/整数自动识别)
@@ -158,8 +164,16 @@ class AssignGenMixin:
rec_d: t.CDouble = 0.0
if self._recover_cdefine_float(name, t.CPtr(c.Addr(rec_d))) != 0:
use_val = rec_d
else:
# 源文件恢复失败:直接报错终止(fail-fast),避免注册被 pool 覆写的错误浮点值
HandlesType.fatal_error(val_node, "CDefine 浮点值源文件恢复失败", "InternalCompilerError")
return
HandlesType.register_cdefine_double(pool, name, use_val)
return
if val_node is None:
# CDefine 声明缺少值节点:直接报错终止(fail-fast)
HandlesType.fatal_error(None, f"CDefine 值提取失败:'{name}' 缺少初始值", "TypeError")
return
val_fp: int = self.extract_cdefine_int_value(val_node)
HandlesType.register_cdefine_constant(pool, name, val_fp)
@@ -484,17 +498,19 @@ class AssignGenMixin:
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, elem_node)
llvmlite.build_store(builder, store_val, elem_ptr)
if elem_val is None:
# 元素翻译失败:直接报错终止(fail-fast),暴露上游根因
HandlesType.fatal_error(elem_node, "全局数组初始化元素翻译失败", "TypeError")
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, elem_node)
llvmlite.build_store(builder, store_val, elem_ptr)
i += 1
return 0
+1 -1
View File
@@ -29,7 +29,7 @@ class BaseGenMixin:
# 符号表/函数表
SymTab: HandlesVar.SymbolTable | t.CPtr
Funcs: HandlesExprCall.FuncEntry | t.CPtr
FuncCount: t.CInt
FuncCount: int
# 导入/模块信息
ImportedModules: str
FromImports: str
+168 -155
View File
@@ -88,11 +88,11 @@ class CallGenMixin:
TempDirLen: t.CSizeT
# --- 闭包名表(原 _g_closure_names/_g_closure_count) ---
ClosureNames: t.CChar | t.CPtr
ClosureNames: str
ClosureCount: int
# --- 函数指针签名表(原 _g_funcptr_names/_g_funcptr_rets/_g_funcptr_count) ---
FuncptrNames: t.CChar | t.CPtr
FuncptrNames: str
FuncptrRets: t.CUInt64T | t.CPtr
FuncptrCount: int
@@ -236,7 +236,7 @@ class CallGenMixin:
cur: llvmlite.Function | t.CPtr = mod.FuncHead
# 第一遍:精确匹配
while cur is not None:
cur_name: t.CChar | t.CPtr = llvmlite.function_get_name(cur)
cur_name: str = llvmlite.function_get_name(cur)
if cur_name is not None:
if string.strcmp(cur_name, name) == 0:
return cur
@@ -253,7 +253,7 @@ class CallGenMixin:
# cur 永不推进 → parse 无限循环。本模块同名 define 必须优先。
cur = mod.FuncHead
while cur is not None:
cur_name2: t.CChar | t.CPtr = llvmlite.function_get_name(cur)
cur_name2: str = llvmlite.function_get_name(cur)
if cur_name2 is not None:
cur_len: t.CSizeT = string.strlen(cur_name2)
if cur_len > name_len + 1:
@@ -271,7 +271,7 @@ class CallGenMixin:
# 本模块无同名 define:回退到 stub declare(跨模块方法/函数调用)
cur = mod.FuncHead
while cur is not None:
cur_name3: t.CChar | t.CPtr = llvmlite.function_get_name(cur)
cur_name3: str = 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:
@@ -598,7 +598,7 @@ class CallGenMixin:
"""
if call_name is None:
return 0
first_dot: t.CChar | t.CPtr = string.strchr(call_name, '.')
first_dot: str = 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))
@@ -728,7 +728,16 @@ class CallGenMixin:
# 掩盖了缺陷。
match pointee:
case llvmlite.LLVMType.Int(pointee_width):
if pointee_width == 8 and trans is not None and trans.CurAssignAnnot is not None:
# 仅当 c.Deref 是赋值语句的直接 RHS(如 v: int = c.Deref(p))
# 时才用注解推断读取宽度(对齐 TPC _infer_deref_target_type
# 的直接 RHS 检查);嵌套在 while 条件/比较/binop/类型转换
# 调用中(如 while c.Deref(p) != 0、total += t.CInt(c.Deref(p)))
# 不推断,否则 i8* 会被残留 CurAssignAnnot 误判为 i32*
# 读 4 字节 → StringIterTest ASCII sum/manual strcmp 失败。
if pointee_width == 8 and trans is not None \
and trans.CurAssignAnnot is not None \
and trans.CurAssignNode is not None \
and t.CUInt64T(cl) == t.CUInt64T(trans.CurAssignNode):
dref_ty: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
trans.Pool, trans.CurAssignAnnot,
trans._imported_modules, trans._from_imports, trans)
@@ -746,8 +755,9 @@ class CallGenMixin:
case _:
pass
return llvmlite.build_load(builder, pointee, ptr_val)
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
return llvmlite.build_load(builder, i8_ty, ptr_val)
# 非指针参数即类型推断退化:fail-fast,绝不按 i8 兜底读取(会读到垃圾宽度)
HandlesType.fatal_error(cl, "c.Deref 参数不是指针类型(类型推断退化)", "TypeError")
return None
def translate_c_derefas(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
@@ -1028,8 +1038,8 @@ class CallGenMixin:
llvmlite.build_store(builder, loaded, dst_cast)
return loaded
def _asm_append_cstr(self, dst: t.CChar | t.CPtr, dst_size: t.CSizeT,
src: t.CChar | t.CPtr):
def _asm_append_cstr(self, dst: str, dst_size: t.CSizeT,
src: str):
"""将 C 字符串 src 追加到 dst 末尾"""
if dst is None or src is None:
return
@@ -1045,12 +1055,12 @@ class CallGenMixin:
dst[dlen + i] = '\0'
def _asm_escape_for_ir(self, pool: memhub.MemBuddy | t.CPtr,
src: t.CChar | t.CPtr) -> t.CChar | t.CPtr:
src: str) -> str:
"""转义汇编文本用于 LLVM IR 字符串字面量"""
if src is None:
return None
slen: t.CSizeT = string.strlen(src)
buf: t.CChar | t.CPtr = pool.alloc(slen * 4 + 8)
buf: str = pool.alloc(slen * 4 + 8)
if buf is None:
return None
pos: t.CSizeT = 0
@@ -1292,7 +1302,7 @@ class CallGenMixin:
string.memset(clobbers, 0, 8 * ASM_MAX_OPERANDS)
# 分配 asm 文本缓冲区
asm_text: t.CChar | t.CPtr = pool.alloc(ASM_TEXT_BUF_SIZE)
asm_text: str = pool.alloc(ASM_TEXT_BUF_SIZE)
if asm_text is None:
return None
asm_text[0] = '\0'
@@ -1545,6 +1555,8 @@ class CallGenMixin:
if out_pn_head is not None and out_pn_n > 0:
ret_ty = llvmlite.Struct(pool, out_pn_head, out_pn_n, None)
else:
HandlesType.fatal_error(
cl, "c.Asm 输出操作数类型缺失(变量 alloca 类型退化)", "TypeError")
ret_ty = llvmlite.Int32(pool)
else:
out_op: HandlesExprCall.AsmOperand | t.CPtr = self._asm_get_operand(operands, first_output_idx)
@@ -1553,6 +1565,8 @@ class CallGenMixin:
if out_op.Value.Ty.Pointee is not None:
ret_ty = out_op.Value.Ty.Pointee
else:
HandlesType.fatal_error(
cl, "c.Asm 输出操作数类型缺失(变量 alloca 类型退化)", "TypeError")
ret_ty = llvmlite.Int32(pool)
# 判断 void — 直接基于 output_count 判断,避免 match 类型匹配问题
@@ -1613,7 +1627,7 @@ class CallGenMixin:
if fv_fi < fv_count:
orig_idx2: int = fv_orig_indices[fv_fi]
new_idx2: int = orig_to_new[orig_idx2]
ph_buf2: t.CChar | t.CPtr = pool.alloc(16)
ph_buf2: str = pool.alloc(16)
if ph_buf2 is not None:
viperlib.snprintf(ph_buf2, 16, "$%d", new_idx2)
self._asm_append_cstr(asm_text, ASM_TEXT_BUF_SIZE, ph_buf2)
@@ -1626,7 +1640,7 @@ class CallGenMixin:
# ============================================================
# 5. 构建约束字符串(按重排后的顺序:输出在前,输入在后)
# ============================================================
const_buf: t.CChar | t.CPtr = pool.alloc(ASM_CONST_BUF_SIZE)
const_buf: str = pool.alloc(ASM_CONST_BUF_SIZE)
if const_buf is None:
return None
const_buf[0] = '\0'
@@ -1667,7 +1681,7 @@ class CallGenMixin:
# ============================================================
# 6. 构建参数列表文本(仅输入操作数)
# ============================================================
args_buf: t.CChar | t.CPtr = pool.alloc(ASM_ARGS_BUF_SIZE)
args_buf: str = pool.alloc(ASM_ARGS_BUF_SIZE)
if args_buf is None:
return None
args_buf[0] = '\0'
@@ -1687,7 +1701,7 @@ class CallGenMixin:
first_arg = 0
# 类型文本
ty_buf: t.CChar | t.CPtr = pool.alloc(64)
ty_buf: str = pool.alloc(64)
if ty_buf is not None:
ty_buf[0] = '\0'
llvmlite.TypePrint(ty_buf, 64, aval.Ty, pool)
@@ -1698,19 +1712,19 @@ class CallGenMixin:
# ============================================================
# 7. 转义汇编文本
# ============================================================
escaped_asm: t.CChar | t.CPtr = self._asm_escape_for_ir(pool, asm_text)
escaped_asm: str = self._asm_escape_for_ir(pool, asm_text)
if escaped_asm is None:
return None
# ============================================================
# 8. 生成 IR 行并发射
# ============================================================
line: t.CChar | t.CPtr = pool.alloc(ASM_LINE_BUF_SIZE)
line: str = pool.alloc(ASM_LINE_BUF_SIZE)
if line is None:
return None
line[0] = '\0'
ssa_name: t.CChar | t.CPtr = None
ssa_name: str = None
if is_void == 0:
ssa_name = pool.alloc(16)
if ssa_name is not None:
@@ -1718,7 +1732,7 @@ class CallGenMixin:
builder.Counter += 1
# 获取返回类型文本
ret_ty_buf: t.CChar | t.CPtr = pool.alloc(64)
ret_ty_buf: str = pool.alloc(64)
if ret_ty_buf is not None:
ret_ty_buf[0] = '\0'
llvmlite.TypePrint(ret_ty_buf, 64, ret_ty, pool)
@@ -1750,8 +1764,8 @@ class CallGenMixin:
# 多输出:extractvalue 取第 out_emit_idx 个元素后 store
if oo.Value is not None and oo.Value.Ty is not None \
and oo.Value.Ty.Pointee is not None:
ev_name: t.CChar | t.CPtr = pool.alloc(32)
ev_line: t.CChar | t.CPtr = pool.alloc(ASM_LINE_BUF_SIZE)
ev_name: str = pool.alloc(32)
ev_line: str = pool.alloc(ASM_LINE_BUF_SIZE)
if ev_name is not None and ev_line is not None:
# ssa_name 形如 "%N"(纯数字 ID),构造唯一名
# "%asm.N.e{i}"(字母开头,避免 %N.e{i} 被解析为
@@ -1800,7 +1814,7 @@ class CallGenMixin:
out_count: int = 0
# 模板文本缓冲区
text: t.CChar | t.CPtr = pool.alloc(LLVMIR_TEMPLATE_BUF)
text: str = pool.alloc(LLVMIR_TEMPLATE_BUF)
if text is None:
return None
text[0] = '\0'
@@ -1897,7 +1911,7 @@ class CallGenMixin:
oi: int
for oi in range(out_count):
oa: llvmlite.Value | t.CPtr = (llvmlite.Value | t.CPtr)(t.CVoid(out_alloca[oi], t.CPtr))
rn: str = (t.CChar | t.CPtr)(t.CVoid(out_regname[oi], t.CPtr))
rn: str = (str)(t.CVoid(out_regname[oi], t.CPtr))
if oa is None or oa.Ty is None or oa.Ty.Pointee is None or rn is None:
continue
reg_val: llvmlite.Value | t.CPtr = llvmlite.new_value(pool)
@@ -2020,7 +2034,7 @@ class CallGenMixin:
# 方案1: 检查当前模块是否有 ClassName.__init__ 的声明(stub 注入)
# 方案2: 检查全局默认参数表是否有 ClassName.__init__ 的条目(翻译时填充,更可靠)
if is_oop == 0 and class_name is not None:
init_lookup_name: t.CChar | t.CPtr = pool.alloc(128)
init_lookup_name: str = pool.alloc(128)
if init_lookup_name is not None:
viperlib.snprintf(init_lookup_name, 128, "%s.__init__", class_name)
# 方案1: 检查当前模块的函数声明
@@ -2263,7 +2277,7 @@ class CallGenMixin:
if renum_entry is None:
renum_entry = HandlesStruct.find_struct(class_name)
if renum_entry is None:
fb_re: t.CChar | t.CPtr = VLogger.fmt_buf()
fb_re: str = VLogger.fmt_buf()
if fb_re is not None:
viperlib.snprintf(fb_re, 1024, "REnum construct: type %s not registered", class_name)
VLogger.error(fb_re, "RENUM")
@@ -2286,7 +2300,7 @@ class CallGenMixin:
# 写入 __tag 字段(索引 0)
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
tag_name_buf: t.CChar | t.CPtr = pool.alloc(32)
tag_name_buf: str = pool.alloc(32)
if tag_name_buf is not None:
viperlib.snprintf(tag_name_buf, 32, "%d", tag_value)
tag_const: llvmlite.Value | t.CPtr = llvmlite.ConstInt(
@@ -2540,7 +2554,7 @@ class CallGenMixin:
cmop_struct_ty = cmop_entry.Ty
# 构造方法查找名: ClassName.method_name
lookup_name: t.CChar | t.CPtr = pool.alloc(128)
lookup_name: str = pool.alloc(128)
if lookup_name is None:
return None
viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, method_name)
@@ -2551,7 +2565,7 @@ class CallGenMixin:
# 确定调用名
call_name: str = lookup_name
if found_func is not None:
found_name: t.CChar | t.CPtr = llvmlite.function_get_name(found_func)
found_name: str = llvmlite.function_get_name(found_func)
if found_name is not None:
call_name = found_name
else:
@@ -2566,7 +2580,7 @@ class CallGenMixin:
# fallback: 从 from_imports 查找类所属模块的 SHA1(含截断处理)
cls_sha1 = self._lookup_mod_sha1(pool, trans._from_imports, class_name)
if cls_sha1 is None:
err_msg: t.CChar | t.CPtr = pool.alloc(256)
err_msg: str = pool.alloc(256)
if err_msg is not None:
viperlib.snprintf(err_msg, 256, "类 '%s' 方法 '%s' 找不到模块 SHA1", class_name, method_name)
HandlesType.fatal_error(node, err_msg)
@@ -2587,7 +2601,7 @@ class CallGenMixin:
elif string.strcmp(method_name, "__getitem__") == 0 or string.strcmp(method_name, "__new__") == 0:
# fail-fast:__getitem__/__new__ 必返回指针,返回类型缺失意味着
# stub declare 损坏,静默推断会截断指针(32 位)崩溃,立即终止。
err_cm1: t.CChar | t.CPtr = pool.alloc(256)
err_cm1: str = pool.alloc(256)
if err_cm1 is not None:
viperlib.snprintf(err_cm1, 256,
"方法 '%s' 返回类型无法确定(stub declare 返回类型缺失)", method_name)
@@ -2605,14 +2619,14 @@ class CallGenMixin:
if cmop_struct_ty is not None:
call_ret_ty = llvmlite.Ptr(pool, cmop_struct_ty)
else:
err_cm2: t.CChar | t.CPtr = pool.alloc(256)
err_cm2: str = pool.alloc(256)
if err_cm2 is not None:
viperlib.snprintf(err_cm2, 256,
"方法 '%s' 的 self 结构体类型未知(字段类型退化,依赖模块未预注册?)", method_name)
HandlesType.fatal_error(node, err_cm2)
HandlesType.fatal_error(node, "self 结构体类型未知")
elif string.strcmp(method_name, "__getitem__") == 0:
err_cm3: t.CChar | t.CPtr = pool.alloc(256)
err_cm3: str = pool.alloc(256)
if err_cm3 is not None:
viperlib.snprintf(err_cm3, 256,
"方法 '%s.__getitem__' 的 stub declare 未注入(依赖模块 vpi 缺失或拓扑顺序错误),无法确定返回类型",
@@ -2690,38 +2704,14 @@ class CallGenMixin:
total_count += 1
mdf_pi += 1
continue
# 无默认值时用零值兜底(需要 found_func 获取参数类型)
if found_func is not None:
param_node_z: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func)
skip_z: int = 0
while skip_z <= mdf_pi and param_node_z is not None:
param_node_z = llvmlite.param_get_next(param_node_z)
skip_z += 1
if param_node_z is not None:
zero_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(param_node_z)
zero_val: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, zero_ty)
if zero_val is not None:
llvmlite.value_set_next(zero_val, None)
llvmlite.value_set_next(tail, zero_val)
tail = zero_val
total_count += 1
# 无默认值即必传参数缺失:fail-fast,绝不零值兜底
HandlesType.fatal_error(
node, f"调用 '{lookup_name}' 缺少参数(无默认值)", "TypeError")
mdf_pi += 1
elif found_func is not None:
# 无默认参数信息但有 found_func:用零值填充(保留原有逻辑)
param_node: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func)
skip_idx: int = 0
while skip_idx < total_count and param_node is not None:
param_node = llvmlite.param_get_next(param_node)
skip_idx += 1
while param_node is not None:
missing_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(param_node)
zero_val2: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, missing_ty)
if zero_val2 is not None:
llvmlite.value_set_next(zero_val2, None)
llvmlite.value_set_next(tail, zero_val2)
tail = zero_val2
total_count += 1
param_node = llvmlite.param_get_next(param_node)
# 无默认参数信息但有 found_func:剩余形参即调用缺参(无默认值),fail-fast
HandlesType.fatal_error(
node, f"调用 '{lookup_name}' 缺少参数(无默认值)", "TypeError")
# 参数类型强制转换:按 found_func 的形参类型 coerce 每个实参(跳过 self/cls 参数 0)
# 修复: 构造器调用 __init__(ptr, base, 4096) 时 size 形参是 i64 (t.CSizeT),
@@ -2857,7 +2847,7 @@ class CallGenMixin:
# _lookup_method_ret_ty_via_vpi - 从 vpi stub 返回注解缓存精确获取方法返回类型
#
# 方法定义处(.vpi stub)的返回注解(如 json.JsonValue._pool_alloc →
# "t.CChar | t.CPtr")在 stub 注入时由 VpiReader 缓存(_cache_vpi_return_annots_text)。
# "str")在 stub 注入时由 VpiReader 缓存(_cache_vpi_return_annots_text)。
# 此函数按 模块SHA1 + 类名 + 方法名 查缓存并纯字符串解析为 LLVMType。
# 无需硬编码白名单——返回类型始终来自方法定义处。
# ============================================================
@@ -3256,7 +3246,7 @@ class CallGenMixin:
return None
# 构造查找名: ClassName.method_name
lookup_name: t.CChar | t.CPtr = pool.alloc(128)
lookup_name: str = pool.alloc(128)
if lookup_name is None:
return None
viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, method_name)
@@ -3267,7 +3257,7 @@ class CallGenMixin:
# 确定调用名
call_name: str = lookup_name
if found_func is not None:
found_name: t.CChar | t.CPtr = llvmlite.function_get_name(found_func)
found_name: str = llvmlite.function_get_name(found_func)
if found_name is not None:
call_name = found_name
else:
@@ -3358,7 +3348,7 @@ class CallGenMixin:
trans.SymTab, obj_nm.id)
if var_entry is not None and var_entry.AnnotClassName is not None:
annot_val: str = var_entry.AnnotClassName
dot_ptr: t.CChar | t.CPtr = string.strrchr(annot_val, '.')
dot_ptr: str = string.strrchr(annot_val, '.')
if dot_ptr is not None:
return dot_ptr + 1
return annot_val
@@ -3429,7 +3419,7 @@ class CallGenMixin:
llvmlite.value_set_next(rhs_val, None)
llvmlite.value_set_next(obj_val, rhs_val)
# setter 函数名带 $set 后缀
setter_name_buf: t.CChar | t.CPtr = pool.alloc(128)
setter_name_buf: str = pool.alloc(128)
if setter_name_buf is None:
return 0
viperlib.snprintf(setter_name_buf, 128, "%s$set", target_attr.attr)
@@ -3466,7 +3456,7 @@ class CallGenMixin:
return 0
llvmlite.value_set_next(obj_val, None)
# deleter 函数名带 $del 后缀
del_name_buf: t.CChar | t.CPtr = pool.alloc(128)
del_name_buf: str = pool.alloc(128)
if del_name_buf is None:
return 0
viperlib.snprintf(del_name_buf, 128, "%s$del", target_attr.attr)
@@ -3580,7 +3570,7 @@ class CallGenMixin:
mc_entry = HandlesStruct.find_struct(class_name)
# 构造方法查找名: ClassName.method_name
lookup_name: t.CChar | t.CPtr = pool.alloc(128)
lookup_name: str = pool.alloc(128)
if lookup_name is None:
return None
viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, method_name)
@@ -3593,7 +3583,7 @@ class CallGenMixin:
# 用对象实际特化名(mc_entry.Name)构造后缀匹配,获得精确返回类型。
if found_func is None and mc_entry is not None and mc_entry.Name is not None:
if string.strcmp(mc_entry.Name, class_name) != 0:
spec_lookup: t.CChar | t.CPtr = pool.alloc(160)
spec_lookup: str = pool.alloc(160)
if spec_lookup is not None:
viperlib.snprintf(spec_lookup, 160, "%s.%s", mc_entry.Name, method_name)
found_func = self.find_func_in_module(mod, spec_lookup)
@@ -3606,7 +3596,7 @@ class CallGenMixin:
while mro_ptr is not None and mro_ptr[mi] != 0:
anc: str = (str | t.CPtr)(t.CVoid(mro_ptr[mi], t.CPtr))
if anc is not None:
parent_lookup: t.CChar | t.CPtr = pool.alloc(128)
parent_lookup: str = pool.alloc(128)
if parent_lookup is not None:
viperlib.snprintf(parent_lookup, 128, "%s.%s", anc, method_name)
parent_func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, parent_lookup)
@@ -3619,7 +3609,7 @@ class CallGenMixin:
# 确定调用名
call_name: str = lookup_name
if found_func is not None:
found_name: t.CChar | t.CPtr = llvmlite.function_get_name(found_func)
found_name: str = llvmlite.function_get_name(found_func)
if found_name is not None:
call_name = found_name
else:
@@ -3805,7 +3795,7 @@ class CallGenMixin:
if pi_k < can:
arg_node_k = cargs.get(pi_k)
else:
pname_k: t.CChar | t.CPtr = llvmlite.param_get_name(cur_param_k)
pname_k: str = llvmlite.param_get_name(cur_param_k)
if pname_k is not None:
ki_k: int
for ki_k in range(kwc):
@@ -3820,10 +3810,8 @@ class CallGenMixin:
arg_val_k = HandlesExpr.translate_value(
builder, pool, mod, arg_node_k, None, 0, trans)
if arg_val_k is None:
# 缺失参数:零值兜底(保持参数数量匹配)
pty_k: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur_param_k)
if pty_k is not None:
arg_val_k = llvmlite.ConstZero(pool, pty_k)
# 缺失参数且无默认值必传:fail-fast,绝不零值兜底(会静默吞掉调用错误)
HandlesType.fatal_error(cl, f"方法 '{lookup_name}' 缺少必传参数", "TypeError")
if arg_val_k is not None:
pty_k2: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur_param_k)
if pty_k2 is not None:
@@ -3936,21 +3924,9 @@ class CallGenMixin:
total_count += 1
mdf_pi += 1
continue
# 无默认值时用零值兜底(需要 found_func 获取参数类型)
if found_func is not None:
param_node_z: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func)
skip_z: int = 0
while skip_z <= mdf_pi and param_node_z is not None:
param_node_z = llvmlite.param_get_next(param_node_z)
skip_z += 1
if param_node_z is not None:
zero_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(param_node_z)
zero_val: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, zero_ty)
if zero_val is not None:
llvmlite.value_set_next(zero_val, None)
llvmlite.value_set_next(tail, zero_val)
tail = zero_val
total_count += 1
# 无默认值即必传参数缺失:fail-fast,绝不零值兜底
HandlesType.fatal_error(
cl, f"调用 '{lookup_name}' 缺少参数(无默认值)", "TypeError")
mdf_pi += 1
# 虚方法分发:如果类有虚表且该方法在虚表中,走间接调用
@@ -4030,7 +4006,7 @@ class CallGenMixin:
while mro_sp is not None and mro_sp[mi_sp] != 0:
anc_sp: str = (str | t.CPtr)(t.CVoid(mro_sp[mi_sp], t.CPtr))
if anc_sp is not None:
probe_sp: t.CChar | t.CPtr = pool.alloc(160)
probe_sp: str = pool.alloc(160)
if probe_sp is not None:
viperlib.snprintf(probe_sp, 160, "%s.%s", anc_sp, method_name)
if HandlesExprCall.find_func_global(probe_sp) is not None:
@@ -4038,7 +4014,7 @@ class CallGenMixin:
break
mi_sp += 1
if anc is None:
err_sp: t.CChar | t.CPtr = pool.alloc(256)
err_sp: str = pool.alloc(256)
if err_sp is not None:
viperlib.snprintf(err_sp, 256, "super(): 当前类 %s 的父类链未定义方法 %s",
cur_class, method_name)
@@ -4104,7 +4080,7 @@ class CallGenMixin:
anc_ptr_sp: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, anc_entry_sp.Ty)
self_arg = llvmlite.build_bitcast(builder, adj_sp, anc_ptr_sp)
# 4. 查找父类方法函数 + 构造调用名(SHA1 mangled)
anc_lookup: t.CChar | t.CPtr = pool.alloc(160)
anc_lookup: str = pool.alloc(160)
if anc_lookup is None:
return None
viperlib.snprintf(anc_lookup, 160, "%s.%s", anc, method_name)
@@ -4114,7 +4090,7 @@ class CallGenMixin:
if anc_sha1_sp is None:
anc_sha1_sp = trans.ModuleSha1
if found_func is not None:
fname_sp: t.CChar | t.CPtr = llvmlite.function_get_name(found_func)
fname_sp: str = llvmlite.function_get_name(found_func)
if fname_sp is not None:
call_name = fname_sp
else:
@@ -4186,6 +4162,15 @@ class CallGenMixin:
pool, anc_sha1_sp, anc, method_name)
if looked_sp is not None:
ret_ty_sp = looked_sp
else:
vpi_ret_sp: llvmlite.LLVMType | t.CPtr = self._lookup_method_ret_ty_via_vpi(
pool, anc_sha1_sp, anc, method_name)
if vpi_ret_sp is not None:
ret_ty_sp = vpi_ret_sp
else:
# 查找链(函数/text.ll/vpi stub)全部未命中:fail-fast,
# 绝不静默保持默认 i32(会截断指针/i64 返回值)
self._fail_method_ret_ty(method_name, cl)
# 7. 跨模块:创建 declare;生成 call
if found_func is None:
self._ensure_method_declare(pool, mod, call_name, ret_ty_sp, head, arg_count_sp)
@@ -4242,7 +4227,7 @@ class CallGenMixin:
# 跳过 % 前缀后逐字符比较
# ============================================================
def _kwarg_name_matches(self, kw_arg: str,
param_name: t.CChar | t.CPtr) -> int:
param_name: str) -> int:
"""检查关键字参数名 kw_arg 是否匹配参数名 param_name(跳过 % 前缀)"""
if kw_arg is None or param_name is None:
return 0
@@ -4295,7 +4280,7 @@ class CallGenMixin:
# 方案1: 检查当前模块是否有 ClassName.__init__ 的声明(stub 注入)
# 方案2: 检查全局默认参数表是否有 ClassName.__init__ 的条目(翻译时填充,更可靠)
if is_oop == 0 and class_name is not None:
kw_init_lookup: t.CChar | t.CPtr = pool.alloc(128)
kw_init_lookup: str = pool.alloc(128)
if kw_init_lookup is not None:
viperlib.snprintf(kw_init_lookup, 128, "%s.__init__", class_name)
# 方案1: 检查当前模块的函数声明
@@ -4438,6 +4423,9 @@ class CallGenMixin:
else:
fe = HandlesStruct.get_field_by_index(class_name, ai)
if fe is None:
# 位置参数越界(字段表无对应项):fail-fast,绝不静默跳过
HandlesType.fatal_error(
arg, f"结构体 '{class_name}' 位置参数越界(无对应字段)", "TypeError")
continue
field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
builder, struct_ty, fe.Ty, tmp, fe.Index)
@@ -4458,6 +4446,9 @@ class CallGenMixin:
fe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field_by_class(
class_name, kw.arg, kw_sha1)
if fe is None:
# 关键字字段不存在:fail-fast(AttributeError),绝不静默跳过
HandlesType.fatal_error(
kw, f"结构体 '{class_name}' 无字段 '{kw.arg}'", "AttributeError")
continue
kw_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, kw.value, None, 0, trans)
@@ -4523,7 +4514,7 @@ class CallGenMixin:
builder, pool, mod, arg, None, 0, trans)
else:
# 查找匹配的关键字参数
param_name: t.CChar | t.CPtr = llvmlite.param_get_name(cur_param)
param_name: str = llvmlite.param_get_name(cur_param)
if param_name is not None:
for ki in range(kw_count):
kw: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(ki))
@@ -4564,7 +4555,7 @@ class CallGenMixin:
# 旧逻辑(IsDeclared==1 时用 func_name 裸名)是错误的:stub 注入的 declare Name 已带 SHA1 前缀,
# 用裸名会导致 call @_PathToModuleName 而 define 是 @"sha1._PathToModuleName",链接报 undefined reference
call_name: str = func_name
found_name: t.CChar | t.CPtr = llvmlite.function_get_name(found_func)
found_name: str = llvmlite.function_get_name(found_func)
if found_name is not None:
call_name = found_name
@@ -4715,14 +4706,19 @@ class CallGenMixin:
# 且缺少 __new__ 方法名后缀,导致链接报 undefined reference。
# ============================================================
def _infer_generic_ctor_type_arg(self, pool: memhub.MemBuddy | t.CPtr,
arg_node: ast.AST | t.CPtr) -> str:
"""从构造实参 AST 推断泛型类型实参名;无法推断时默认 "int"(与 TPC 一致)
arg_node: ast.AST | t.CPtr,
class_name: str) -> str:
"""从构造实参 AST 推断泛型类型实参名;无法推断时 fail-fast(绝不默认 "int")
裸名泛型类构造(Box(42) → Box[int])需要从实参推断类型实参。
对应 TPC _HandleGenericClassNewLlvm 的推断逻辑(常量/类型转换调用)。
注意:本函数仅做 AST 静态推断,不发射 IR(避免重复翻译实参)。
"""
if pool is None or arg_node is None:
HandlesType.fatal_error(
None,
f"无法从实参推断泛型类 '{class_name}' 的类型实参,请显式标注如 {class_name}[类型](...)",
"TypeError")
return "int"
k: int = arg_node.kind()
# 常量: 42→int, 3.14→double, "abc"→str
@@ -4751,6 +4747,11 @@ class CallGenMixin:
return "double"
if string.strstr(fn_at.attr, "Int") is not None or string.strstr(fn_at.attr, "UInt") is not None or string.strstr(fn_at.attr, "Char") is not None or string.strstr(fn_at.attr, "Short") is not None or string.strstr(fn_at.attr, "Long") is not None:
return "int"
# 无法从 AST 静态推断:fail-fast,绝不静默默认 "int"(会特化出错误类型)
HandlesType.fatal_error(
arg_node,
f"无法从实参推断泛型类 '{class_name}' 的类型实参,请显式标注如 {class_name}[类型](...)",
"TypeError")
return "int"
def _translate_generic_ctor_call(self, pool: memhub.MemBuddy | t.CPtr,
@@ -5022,7 +5023,7 @@ class CallGenMixin:
funcs_ptr, func_count, trans)
# 内置强转函数: str(x)/bytes(x) → i8*, int(x) → i32
# 等价于 (t.CChar | t.CPtr)(x) / (t.CInt32T)(x)
# 等价于 (str)(x) / (t.CInt32T)(x)
# 单参数:str(val) → bitcast val to i8*
# int(val) → trunc/sext val to i32
# 泛型类型参数: 类特化/泛型函数上下文中的 T(x) 先解析 T 为具体类型名
@@ -5349,7 +5350,9 @@ class CallGenMixin:
# 模块属性前向引用回退为 i32),GEP base 会是 i32 而非指针,
# 导致 llc 报错 "base of getelementptr must be a pointer"
if HandlesExpr.is_ptr_type(obj_val.Ty) == 0:
return llvmlite.const_int64(pool, 0)
# 类型推断失败(非指针/结构体):fail-fast,绝不返回 0 掩盖错误
HandlesType.fatal_error(
len_at.value, "len() 参数类型推断失败(非指针/结构体)", "TypeError")
i64_ty_len: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
# 注意: 必须用 const_int64 而非 ConstInt(...,"0")
# ConstInt 的 name 参数 "0" 会被当作 IR 文本值输出 i64 0
@@ -5407,7 +5410,7 @@ class CallGenMixin:
len_cls_nm: str = HandlesStruct.get_class_name_by_type(
pool, len_struct_ty)
if len_cls_nm is not None:
len_lookup: t.CChar | t.CPtr = pool.alloc(128)
len_lookup: str = pool.alloc(128)
if len_lookup is not None:
viperlib.snprintf(len_lookup, 128, "%s.__len__", len_cls_nm)
len_fn2: llvmlite.Function | t.CPtr = self.find_func_in_module(
@@ -5415,7 +5418,7 @@ class CallGenMixin:
if len_fn2 is not None:
len_ret_ty2: llvmlite.LLVMType | t.CPtr = \
llvmlite.function_get_ret_ty(len_fn2)
len_fn_name2: t.CChar | t.CPtr = \
len_fn_name2: str = \
llvmlite.function_get_name(len_fn2)
if len_ret_ty2 is not None and len_fn_name2 is not None:
# self 参数类型对齐(按方法首个形参 bitcast)
@@ -5538,7 +5541,7 @@ class CallGenMixin:
if var_entry is not None and var_entry.AnnotClassName is not None:
annot_val: str = var_entry.AnnotClassName
# 解析模块限定名 "memhub.MemBuddy" → mod_nm="memhub", cls_nm="MemBuddy"
dot_ptr: t.CChar | t.CPtr = string.strrchr(annot_val, '.')
dot_ptr: str = string.strrchr(annot_val, '.')
cls_nm2: str = annot_val
mod_nm2: str = None
if dot_ptr is not None:
@@ -5673,7 +5676,7 @@ class CallGenMixin:
if field_info is not None:
field_annot: str = HandlesStruct.get_field_annot_class_name(field_info)
if field_annot is not None:
dot_p: t.CChar | t.CPtr = string.strrchr(field_annot, 46)
dot_p: str = string.strrchr(field_annot, 46)
if dot_p is not None:
field_cls_nm = dot_p + 1
else:
@@ -5715,15 +5718,10 @@ class CallGenMixin:
# 可能返回 i32 0 (非指针),直接 GEP 会导致
# "base of getelementptr must be a pointer" 错误
if lm_obj.Ty is None or HandlesExpr.is_ptr_type(lm_obj.Ty) == 0:
lm_node_kind: int = lm_at.value.kind()
fb_lm: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_lm is not None:
viperlib.snprintf(fb_lm, 1024,
"list 方法 '%s' 的目标对象非指针 (node kind=%d),"
"translate_value 类型推断失败",
lm_name, lm_node_kind)
VLogger.critical(fb_lm, "LIST-METHOD")
return None
# translate_value 类型推断失败(目标对象非指针):
# fail-fast,绝不 VLogger.critical 后 return None 静默吞掉
HandlesType.fatal_error(
lm_at.value, f"list 方法 '{lm_name}' 目标对象非指针", "TypeError")
i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
@@ -5816,6 +5814,12 @@ class CallGenMixin:
elif string.strcmp(lm_name, "append") == 0:
if can >= 1:
ap_sha1: str = self._lookup_module_sha1("_list")
if ap_sha1 is None:
# 依赖模块未编译(_list 未预加入编译链):fail-fast,
# 绝不静默跳过 append(元素永远不会被加入列表)
HandlesType.fatal_error(
cl, "list.append: 找不到 _list 模块 SHA1(依赖模块未编译)",
"InternalCompilerError")
if ap_sha1 is not None:
ap_mlen: t.CSizeT = string.strlen(ap_sha1) + 13
ap_mangled: str = pool.alloc(ap_mlen)
@@ -5974,7 +5978,7 @@ class CallGenMixin:
if hint_bare is not None:
hi_bare: t.CSizeT
for hi_bare in range(can):
hty_bare: str = self._infer_generic_ctor_type_arg(pool, cargs.get(hi_bare))
hty_bare: str = self._infer_generic_ctor_type_arg(pool, cargs.get(hi_bare), func_name)
if string.strcmp(hty_bare, "int") != 0:
hint_bare.append(hty_bare)
tpi_bare: t.CSizeT = 0
@@ -5983,7 +5987,7 @@ class CallGenMixin:
if tpi_bare < len(hint_bare):
ta_bare = hint_bare.get(tpi_bare)
elif tpi_bare < can:
ta_bare = self._infer_generic_ctor_type_arg(pool, cargs.get(tpi_bare))
ta_bare = self._infer_generic_ctor_type_arg(pool, cargs.get(tpi_bare), func_name)
inferred_args_bare.append(ta_bare)
spec_name_bare: str = HandlesClassDef._specialize_generic_class(
trans, func_name, inferred_args_bare)
@@ -6040,7 +6044,7 @@ class CallGenMixin:
# 模块函数(SHA1.func)或子模块函数(SHA1.submod.func)的后缀匹配保留。
found_func = self.find_func_in_module(mod, func_name)
if found_func is not None:
ff_name: t.CChar | t.CPtr = llvmlite.function_get_name(found_func)
ff_name: str = llvmlite.function_get_name(found_func)
if ff_name is not None:
ff_dots: int = 0
ffi2: t.CSizeT = 0
@@ -6050,7 +6054,7 @@ class CallGenMixin:
ffi2 += 1
if ff_dots >= 2:
# 提取第 2 段(SHA1.Class.method → Class;SHA1.submod.func → submod)
seg2: t.CChar | t.CPtr = pool.alloc(64)
seg2: str = pool.alloc(64)
if seg2 is not None:
seg2[0] = '\0'
si: t.CSizeT = 0
@@ -6318,7 +6322,7 @@ class CallGenMixin:
# 用于在别名处理后重新推断返回类型,避免 _infer_external_func_ret_ty 用别名匹配失败
orig_func_name: str = None
if found_func is not None:
found_name: t.CChar | t.CPtr = llvmlite.function_get_name(found_func)
found_name: str = llvmlite.function_get_name(found_func)
if found_name is not None:
call_name = found_name
else:
@@ -6340,7 +6344,7 @@ class CallGenMixin:
is_xmod_imported = HandlesImports.is_module_imported(
trans._imported_modules, xmod_nm.id)
if is_xmod_imported == 0:
err_ni: t.CChar | t.CPtr = pool.alloc(256)
err_ni: str = pool.alloc(256)
if err_ni is not None:
viperlib.snprintf(err_ni, 256,
"跨模块调用 '%s.%s':模块 '%s' 未导入(请先 import %s)",
@@ -6393,7 +6397,7 @@ class CallGenMixin:
call_name = alias_mangled
else:
# 已导入模块但 SHA1 未注册:该模块未被编译,立即报错
err_msg_imp: t.CChar | t.CPtr = pool.alloc(256)
err_msg_imp: str = pool.alloc(256)
if err_msg_imp is not None:
viperlib.snprintf(err_msg_imp, 256, "模块 '%s' 已导入但 SHA1 未注册(该模块未被编译)", xmod_nm.id)
HandlesType.fatal_error(xmod_nm, err_msg_imp)
@@ -6417,7 +6421,7 @@ class CallGenMixin:
viperlib.snprintf(fmangled, fmangled_len, "%s.%s", from_sha1, func_name)
call_name = fmangled
else:
err_msg2: t.CChar | t.CPtr = pool.alloc(256)
err_msg2: str = pool.alloc(256)
if err_msg2 is not None:
viperlib.snprintf(err_msg2, 256, "跨模块调用 '%s.%s' 找不到模块 SHA1", xmod_nm.id, func_name)
HandlesType.fatal_error(xmod_nm, err_msg2)
@@ -6464,13 +6468,13 @@ class CallGenMixin:
viperlib.snprintf(bare_mangled, bare_mangled_len, "%s.%s", bare_sha1, bare_func_name)
call_name = bare_mangled
else:
err_msg3: t.CChar | t.CPtr = pool.alloc(256)
err_msg3: str = pool.alloc(256)
if err_msg3 is not None:
viperlib.snprintf(err_msg3, 256, "裸名调用 '%s' 未定义且未导入", func_name)
HandlesType.fatal_error(node, err_msg3)
HandlesType.fatal_error(node, "裸名调用未定义且未导入")
else:
err_msg4: t.CChar | t.CPtr = pool.alloc(256)
err_msg4: str = pool.alloc(256)
if err_msg4 is not None:
viperlib.snprintf(err_msg4, 256, "裸名调用 '%s' 未定义且未导入", func_name)
HandlesType.fatal_error(node, err_msg4)
@@ -6501,13 +6505,13 @@ class CallGenMixin:
# ============================================================
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, '.')
cf_dot: str = string.strchr(call_name, '.')
cf_last: str = 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_sha1: str = 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)
cf_bare: str = 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'
@@ -6544,7 +6548,7 @@ class CallGenMixin:
# 保持白名单类型继续,Phase A 多遍循环下遍重译——
# 届时依赖已生成 text.ll,可精确解析(治本:依赖先翻译)。
if self._dep_text_ll_exists(pool, cf_sha1) != 0:
cf_err: t.CChar | t.CPtr = VLogger.fmt_buf()
cf_err: str = VLogger.fmt_buf()
if cf_err is not None:
viperlib.snprintf(
cf_err, 1024,
@@ -6558,7 +6562,7 @@ class CallGenMixin:
else:
if trans is not None:
trans._deps_pending = 1
cf_dbg: t.CChar | t.CPtr = VLogger.fmt_buf()
cf_dbg: str = VLogger.fmt_buf()
if cf_dbg is not None:
viperlib.snprintf(
cf_dbg, 1024,
@@ -6597,11 +6601,13 @@ class CallGenMixin:
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
"""isinstance(obj, Cls):运行时 vtable 子类集合比较,返回 i1"""
if obj_node is None or cls_node is None:
return llvmlite.const_int(pool, 1, 0)
# 参数缺失即调用错误:fail-fast,绝不返回 True 掩盖
HandlesType.fatal_error(cls_node, "isinstance() 参数类型推断失败", "TypeError")
obj_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, obj_node, None, 0, trans)
if obj_val is None or obj_val.Ty is None:
return llvmlite.const_int(pool, 1, 0)
# obj 类型推断失败:fail-fast,绝不返回 True 掩盖
HandlesType.fatal_error(cls_node, "isinstance() 参数类型推断失败", "TypeError")
# 对象指针规整:二级指针(变量 alloca / 联合 Class|t.CPtr)先 load
obj_ptr: llvmlite.Value | t.CPtr = obj_val
match obj_val.Ty:
@@ -6624,7 +6630,8 @@ class CallGenMixin:
res: llvmlite.Value | t.CPtr = None
cls_names: t.CSizeT | t.CPtr = self._extract_isinstance_class_names(pool, cls_node)
if cls_names is None:
return llvmlite.const_int(pool, 1, 0)
# 类名提取失败:fail-fast,绝不返回 True 掩盖
HandlesType.fatal_error(cls_node, "isinstance() 参数类型推断失败", "TypeError")
ci: int = 0
while cls_names[ci] != 0:
cn: str = (str | t.CPtr)(t.CVoid(cls_names[ci], t.CPtr))
@@ -6666,7 +6673,8 @@ class CallGenMixin:
k += 1
ci += 1
if res is None:
return llvmlite.const_int(pool, 1, 0)
# 未产生任何比较结果(obj 非指针且类全部为 CVTable):推断失败,fail-fast
HandlesType.fatal_error(cls_node, "isinstance() 参数类型推断失败", "TypeError")
return res
def _extract_isinstance_class_names(self, pool: memhub.MemBuddy | t.CPtr,
@@ -6788,7 +6796,7 @@ class CallGenMixin:
return None
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
buf: t.CChar | t.CPtr = pool.alloc(256)
buf: str = pool.alloc(256)
if buf is None:
return None
viperlib.snprintf(buf, 256, "%s.vtable", class_name)
@@ -6801,7 +6809,7 @@ class CallGenMixin:
if sha1 is None:
return None
mangled: str = HandlesFunctions._mangle_name_with_sha1(sha1, vn)
ref_name: t.CChar | t.CPtr = pool.alloc(256)
ref_name: str = pool.alloc(256)
if ref_name is None:
return None
# vtable 名含 sha1 点号前缀,一律 @"..." 引号形式
@@ -7052,9 +7060,13 @@ class CallGenMixin:
tail = arg_val
arg_count += 1
# 3. 按实参类型 + 注册的返回类型构造签名(未注册返回类型时默认 i32)
# 3. 按实参类型 + 注册的返回类型构造签名(未注册即 t.Callable 注解缺失,fail-fast)
ret_ty: llvmlite.LLVMType | t.CPtr = self.lookup_func_ptr_ret(func_name)
if ret_ty is None:
HandlesType.fatal_error(
None,
f"函数指针变量 '{func_name}' 的返回类型未注册(t.Callable 注解缺失)",
"TypeError")
ret_ty = i32_ty
fp_first: llvmlite.ParamNode | t.CPtr = None
fp_prev: llvmlite.ParamNode | t.CPtr = None
@@ -7179,7 +7191,7 @@ class CallGenMixin:
# "(null)" 兜底。静默输出 "(null)" 会掩盖表达式翻译失败
# (变量未定义/类型退化等),运行期 printf 打出 "(null)" 会
# 误导为数据问题而非编译器 bug。
fb_pp: t.CChar | t.CPtr = VLogger.fmt_buf()
fb_pp: str = VLogger.fmt_buf()
if fb_pp is not None:
viperlib.snprintf(fb_pp, 1024, "print 参数翻译失败(表达式返回 None): [arg=%d]", ai)
VLogger.error(fb_pp, "PRINT")
@@ -7208,7 +7220,7 @@ class CallGenMixin:
case _:
pass
token: t.CChar | t.CPtr = None
token: str = None
chain_arg: int = 1 # 1=该 token 消耗一个参数,0=纯文本
arg_bits: int = HandlesExpr.get_llvm_type_bits(arg_val.Ty)
arg_fbits: int = HandlesExpr.get_llvm_float_bits(arg_val.Ty)
@@ -7314,7 +7326,7 @@ class CallGenMixin:
t.CInt / t.CInt32T → i32
t.CInt64T → i64
t.CDouble → double
t.CPtr / t.CChar | t.CPtr → i8*
t.CPtr / str → i8*
str / bytes → i8*
无类型参数时默认 i32(vsnprintf 中 va_arg(ap) 常用于读取 i32)
"""
@@ -7325,7 +7337,8 @@ class CallGenMixin:
pool, type_node, trans._imported_modules, trans._from_imports, trans)
if resolved is not None:
return resolved
# 回退为 i32
# 类型节点存在但解析失败:fail-fast,绝不回退 i32(会按错宽度读变参槽位)
HandlesType.fatal_error(type_node, "va_arg 类型解析失败", "TypeError")
return llvmlite.Int32(pool)
def _translate_va_arg_sugar(self, pool: memhub.MemBuddy | t.CPtr,
@@ -7638,19 +7651,19 @@ class CallGenMixin:
return 1
def _build_func_type_str(self, pool: memhub.MemBuddy | t.CPtr,
func: llvmlite.Function | t.CPtr) -> t.CChar | t.CPtr:
func: llvmlite.Function | t.CPtr) -> str:
"""生成函数类型文本(stdlib 分配)"""
if func is None:
return None
# 类型文本可能较长(SHA1 限定命名结构体 + 多参数),用 1024 缓冲
ty_buf: t.CChar | t.CPtr = pool.alloc(1024)
ty_buf: str = pool.alloc(1024)
if ty_buf is None:
return None
ty_buf[0] = '\0'
# 返回类型
ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(func)
ret_part: t.CChar | t.CPtr = pool.alloc(512)
ret_part: str = pool.alloc(512)
if ret_part is not None and ret_ty is not None:
ret_part[0] = '\0'
llvmlite.TypePrint(ret_part, 512, ret_ty, pool)
@@ -7660,7 +7673,7 @@ class CallGenMixin:
# 参数类型(全部经 _asm_append_cstr 有界追加,防止 strcat 无界写穿 1024 缓冲)
cur: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(func)
first: int = 1
param_part: t.CChar | t.CPtr = pool.alloc(512)
param_part: str = pool.alloc(512)
while cur is not None:
if first == 0:
self._asm_append_cstr(ty_buf, 1024, ", ")
@@ -7676,7 +7689,7 @@ class CallGenMixin:
# 深拷贝到 stdlib 区(TypeStr 跨文件永久存活)
ts_len: t.CSizeT = string.strlen(ty_buf)
ts_copy: t.CChar | t.CPtr = stdlib.malloc(ts_len + 1)
ts_copy: str = stdlib.malloc(ts_len + 1)
if ts_copy is None:
return None
string.strcpy(ts_copy, ty_buf)
@@ -7705,7 +7718,7 @@ class CallGenMixin:
# Name 深拷贝到 stdlib 区:全局表跨文件永久存活,pool 内名字会被 1b 每文件
# reset_to(mark1) 回收导致悬空(vtable 生成 find_func_global 后 strcmp 崩溃)
name_len: t.CSizeT = string.strlen(name)
name_copy: t.CChar | t.CPtr = stdlib.malloc(name_len + 1)
name_copy: str = stdlib.malloc(name_len + 1)
if name_copy is None:
return 1
string.strcpy(name_copy, name)
@@ -7787,7 +7800,7 @@ class CallGenMixin:
entry: HandlesExprCall.FuncDefaultsEntry | t.CPtr = (HandlesExprCall.FuncDefaultsEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
# Name 深拷贝到 stdlib(全局表跨文件永久存活)
nm_len: t.CSizeT = string.strlen(name)
nm_copy: t.CChar | t.CPtr = stdlib.malloc(nm_len + 1)
nm_copy: str = stdlib.malloc(nm_len + 1)
if nm_copy is None:
return 1
string.strcpy(nm_copy, name)
@@ -7814,7 +7827,7 @@ class CallGenMixin:
ints[di] = dcn.int_val
if dcn.const_kind == ast.CONST_STR and dcn.str_val is not None:
slen: t.CSizeT = string.strlen(dcn.str_val)
scopy: t.CChar | t.CPtr = stdlib.malloc(slen + 1)
scopy: str = stdlib.malloc(slen + 1)
if scopy is not None:
string.strcpy(scopy, dcn.str_val)
strs[di] = t.CSizeT(scopy)
+85 -60
View File
@@ -762,9 +762,15 @@ class ClassGenMixin:
if left_bits >= right_bits:
return left_ty
return right_ty
return llvmlite.Int32(pool)
# fail-fast:BinOp 但非 BitOr(未知联合运算),不再静默回退 i32
HandlesType.fatal_error(
ann_node, f"枚举成员类型注解解析失败: {HandlesType.annotation_to_str(ann_node)}", "TypeError")
return llvmlite.Int32(pool) # 不可达(fatal_error 已退出)
return llvmlite.Int32(pool)
# fail-fast:未知注解节点 kind,不再静默回退 i32
HandlesType.fatal_error(
ann_node, f"枚举成员类型注解解析失败: {HandlesType.annotation_to_str(ann_node)}", "TypeError")
return llvmlite.Int32(pool) # 不可达(fatal_error 已退出)
def _is_state_annotation(self, node: ast.AST | t.CPtr) -> int:
"""检查注解节点是否为 t.State,返回 1=是 / 0=否"""
@@ -816,7 +822,7 @@ class ClassGenMixin:
children: list[ast.AST | t.CPtr] | t.CPtr = cd.children
if children is None:
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "%s has no body", class_name)
VLogger.warning(fb, "ENUM")
@@ -917,7 +923,7 @@ class ClassGenMixin:
member_count += 1
if member_count == 0:
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "%s has no members", class_name)
VLogger.warning(fb, "ENUM")
@@ -941,7 +947,7 @@ class ClassGenMixin:
entry: HandlesEnum.EnumEntry | t.CPtr = HandlesEnum.register_enum(
pool, class_name, base_ty)
if entry is None:
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "failed to register %s", class_name)
VLogger.error(fb, "ENUM")
@@ -962,7 +968,7 @@ class ClassGenMixin:
if mname is not None and mty2 is not None:
HandlesEnum.add_enum_member(pool, entry, mname, mval, mty2)
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "registered %s with %d members, base_bits=%d",
class_name, member_count, max_bits)
@@ -1078,7 +1084,7 @@ class ClassGenMixin:
children: list[ast.AST | t.CPtr] | t.CPtr = cd.children
if children is None:
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "%s has no body", class_name)
VLogger.warning(fb, "UNION")
@@ -1143,7 +1149,7 @@ class ClassGenMixin:
field_count += 1
if field_count == 0:
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "%s has no fields", class_name)
VLogger.warning(fb, "UNION")
@@ -1167,14 +1173,14 @@ class ClassGenMixin:
# 构造命名结构体类型名: "sha1.ClassName" 或 "ClassName"
union_type_name: str = class_name
if trans.ModuleSha1 is not None:
union_name_buf: t.CChar | t.CPtr = pool.alloc(64)
union_name_buf: str = pool.alloc(64)
if union_name_buf is not None:
viperlib.snprintf(union_name_buf, 64, "%s.%s", trans.ModuleSha1, class_name)
union_type_name = union_name_buf
union_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, pnode, 1, union_type_name)
if union_ty is None:
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "failed to create type for %s", class_name)
VLogger.error(fb, "UNION")
@@ -1193,7 +1199,7 @@ class ClassGenMixin:
entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.register_struct(
pool, class_name, union_ty, trans.ModuleSha1)
if entry is None:
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "failed to register %s", class_name)
VLogger.error(fb, "UNION")
@@ -1219,7 +1225,7 @@ class ClassGenMixin:
if fname is not None and fty2 is not None:
HandlesStruct.add_field(pool, entry, fname, fty2, None, None)
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "registered %s with %d fields, max_size=%d",
class_name, field_count, max_size)
@@ -1307,7 +1313,7 @@ class ClassGenMixin:
children: list[ast.AST | t.CPtr] | t.CPtr = cd.children
if children is None:
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "%s has no body", class_name)
VLogger.warning(fb, "RENUM")
@@ -1369,7 +1375,7 @@ class ClassGenMixin:
variant_count += 1
if variant_count == 0:
fb2: t.CChar | t.CPtr = VLogger.fmt_buf()
fb2: str = VLogger.fmt_buf()
if fb2 is not None:
viperlib.snprintf(fb2, 1024, "%s has no variants", class_name)
VLogger.warning(fb2, "RENUM")
@@ -1425,7 +1431,7 @@ class ClassGenMixin:
first_node = tail_node
if first_node is None:
fb3: t.CChar | t.CPtr = VLogger.fmt_buf()
fb3: str = VLogger.fmt_buf()
if fb3 is not None:
viperlib.snprintf(fb3, 1024, "failed to build field list for %s", class_name)
VLogger.error(fb3, "RENUM")
@@ -1434,7 +1440,7 @@ class ClassGenMixin:
# 构造命名结构体类型名: "sha1.ClassName" 或 "ClassName"
renum_type_name: str = class_name
if trans.ModuleSha1 is not None:
renum_name_buf: t.CChar | t.CPtr = pool.alloc(64)
renum_name_buf: str = pool.alloc(64)
if renum_name_buf is not None:
viperlib.snprintf(renum_name_buf, 64, "%s.%s", trans.ModuleSha1, class_name)
renum_type_name = renum_name_buf
@@ -1442,7 +1448,7 @@ class ClassGenMixin:
renum_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(
pool, first_node, total_positions, renum_type_name)
if renum_ty is None:
fb4: t.CChar | t.CPtr = VLogger.fmt_buf()
fb4: str = VLogger.fmt_buf()
if fb4 is not None:
viperlib.snprintf(fb4, 1024, "failed to create type for %s", class_name)
VLogger.error(fb4, "RENUM")
@@ -1462,7 +1468,7 @@ class ClassGenMixin:
entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.register_struct(
pool, class_name, renum_ty, trans.ModuleSha1)
if entry is None:
fb5: t.CChar | t.CPtr = VLogger.fmt_buf()
fb5: str = VLogger.fmt_buf()
if fb5 is not None:
viperlib.snprintf(fb5, 1024, "failed to register %s", class_name)
VLogger.error(fb5, "RENUM")
@@ -1485,7 +1491,7 @@ class ClassGenMixin:
payload_ty: llvmlite.LLVMType | t.CPtr = i32_ty
if psize2 > 4:
payload_ty = i64_ty
field_name_buf: t.CChar | t.CPtr = pool.alloc(16)
field_name_buf: str = pool.alloc(16)
if field_name_buf is not None:
viperlib.snprintf(field_name_buf, 16, "_p%d", pos)
HandlesStruct.add_field(pool, entry, field_name_buf, payload_ty, None, None)
@@ -1495,7 +1501,7 @@ class ClassGenMixin:
# 注册变体字段名别名已在变体遍历时直接完成(避免 CSizeT→str 转换问题)
fb6: t.CChar | t.CPtr = VLogger.fmt_buf()
fb6: str = VLogger.fmt_buf()
if fb6 is not None:
viperlib.snprintf(fb6, 1024, "registered %s with %d variants, %d positions",
class_name, variant_count, total_positions)
@@ -1557,7 +1563,7 @@ class ClassGenMixin:
break
if tag >= RENUM_VARIANT_PER_CLASS:
# 每类固定 32 槽:变体超过上限继续写会越界污染相邻类槽,fail-fast 报错
fb_rv: t.CChar | t.CPtr = VLogger.fmt_buf()
fb_rv: str = VLogger.fmt_buf()
if fb_rv is not None:
viperlib.snprintf(fb_rv, 1024,
"REnum 变体数超过上限 %d: %s", RENUM_VARIANT_PER_CLASS, class_name)
@@ -2017,8 +2023,8 @@ class ClassGenMixin:
# 深拷贝字符串到 stdlib 区
key_len: t.CSizeT = string.strlen(spec_key)
name_len: t.CSizeT = string.strlen(spec_name)
key_copy: t.CChar | t.CPtr = stdlib.malloc(key_len + 1)
name_copy: t.CChar | t.CPtr = stdlib.malloc(name_len + 1)
key_copy: str = stdlib.malloc(key_len + 1)
name_copy: str = stdlib.malloc(name_len + 1)
if key_copy is None or name_copy is None:
return
string.strcpy(key_copy, spec_key)
@@ -2068,7 +2074,7 @@ class ClassGenMixin:
# 等循环特化把编译变死循环)。所有返回路径都必须 -1(见各 return 前)。
self.GenericSpecDepth += 1
if self.GenericSpecDepth > GENERIC_SPEC_MAX_DEPTH:
err_spec: t.CChar | t.CPtr = trans.Pool.alloc(256)
err_spec: str = trans.Pool.alloc(256)
if err_spec is not None:
viperlib.snprintf(err_spec, 256,
"泛型特化递归过深(疑似泛型循环套用),类: %s 深度=%d",
@@ -2112,6 +2118,9 @@ class ClassGenMixin:
# 防重入:先标记 MethodsEmitted=1,避免补译过程中方法体/返回类型注解
# 再次触发 _specialize_generic_class(如 __iter__ 返回 list[T]|t.CPtr)
# 导致无限递归补译 → OOM。补译完成后已设置,无需恢复。
# 注意:此处提前置位后调用 _translate_oop_methods 必须传 reemit=1
# (补译模式),否则其 MethodsEmitted==1 防重复检查会拦截补译,
# 方法体永不发射 → 特化方法只有 call 无 define → 链接 undefined symbol。
pre_existing.MethodsEmitted = 1
tp_names_pre: list[str] | t.CPtr = template_cd.type_params
spec_cd_pre: ast.ClassDef | t.CPtr = self._clone_classdef_for_spec(
@@ -2134,7 +2143,7 @@ class ClassGenMixin:
if tpl_file_pre is not None:
HandlesType.set_current_file(tpl_file_pre)
HandlesType.push_trace(tpl_file_pre, template_cd.lineno)
self._translate_oop_methods(trans, spec_cd_pre, pre_existing.Ty, spec_name, 0)
self._translate_oop_methods(trans, spec_cd_pre, pre_existing.Ty, spec_name, 0, 1)
if tpl_file_pre is not None:
HandlesType.pop_trace()
HandlesType.set_current_file(saved_cur_pre)
@@ -2324,10 +2333,10 @@ class ClassGenMixin:
ty_deep: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType(pool, existing.Ty)
if ty_deep is not None:
existing.Ty = ty_deep
old_name: t.CChar | t.CPtr = llvmlite.get_struct_name(existing.Ty)
old_name: str = llvmlite.get_struct_name(existing.Ty)
if old_name is not None:
on_len: t.CSizeT = string.strlen(old_name)
on_copy: t.CChar | t.CPtr = stdlib.malloc(on_len + 1)
on_copy: str = stdlib.malloc(on_len + 1)
if on_copy is not None:
string.strcpy(on_copy, old_name)
c.DerefAs(existing.Ty, llvmlite.LLVMType.Struct(
@@ -2595,7 +2604,7 @@ class ClassGenMixin:
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool))
vtable_node: llvmlite.ParamNode | t.CPtr = pool.alloc(llvmlite.ParamNode.__sizeof__())
if vtable_node is None:
fb_vn: t.CChar | t.CPtr = VLogger.fmt_buf()
fb_vn: str = VLogger.fmt_buf()
if fb_vn is not None:
viperlib.snprintf(fb_vn, 1024, "failed to alloc vtable node for %s", class_name)
VLogger.error(fb_vn, "CLASS")
@@ -2631,13 +2640,13 @@ class ClassGenMixin:
# reset_to(mark1) 存活 → 用 stdlib 深拷贝;Phase 1a 仍用 pool(无需跨文件)。
type_name: str = class_name
if trans.ModuleSha1 is not None:
name_buf: t.CChar | t.CPtr = pool.alloc(64)
name_buf: str = pool.alloc(64)
if name_buf is not None:
viperlib.snprintf(name_buf, 64, "%s.%s", trans.ModuleSha1, class_name)
type_name = name_buf
if trans._declare_only == 0 and type_name is not None:
tn_len: t.CSizeT = string.strlen(type_name)
tn_copy: t.CChar | t.CPtr = stdlib.malloc(tn_len + 1)
tn_copy: str = stdlib.malloc(tn_len + 1)
if tn_copy is not None:
string.strcpy(tn_copy, type_name)
type_name = tn_copy
@@ -2645,7 +2654,7 @@ class ClassGenMixin:
# 创建 StructType(命名结构体)
struct_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, first_node, total_field_count, type_name)
if struct_ty is None:
fb_st: t.CChar | t.CPtr = VLogger.fmt_buf()
fb_st: str = VLogger.fmt_buf()
if fb_st is not None:
viperlib.snprintf(fb_st, 1024, "failed to create StructType for %s", class_name)
VLogger.error(fb_st, "CLASS")
@@ -2680,7 +2689,7 @@ class ClassGenMixin:
entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.register_struct(
pool, class_name, struct_ty, trans.ModuleSha1)
if entry is None:
fb_re: t.CChar | t.CPtr = VLogger.fmt_buf()
fb_re: str = VLogger.fmt_buf()
if fb_re is not None:
viperlib.snprintf(fb_re, 1024, "failed to register %s", class_name)
VLogger.error(fb_re, "CLASS")
@@ -2697,7 +2706,7 @@ class ClassGenMixin:
# find_struct(ParentName) strcmp 解引用 → 用 stdlib 拷贝保证跨文件存活
if HandlesStruct.get_stdlib_alloc() != 0:
pn_len: t.CSizeT = string.strlen(parent_name)
pn_buf: t.CChar | t.CPtr = stdlib.malloc(pn_len + 1)
pn_buf: str = stdlib.malloc(pn_len + 1)
if pn_buf is not None:
string.strcpy(pn_buf, parent_name)
entry.ParentName = pn_buf
@@ -2729,9 +2738,9 @@ class ClassGenMixin:
fdef = (ast.AST | t.CPtr)(t.CVoid(fdef_addr, t.CPtr))
# 恢复注解类名指针
fannot_addr: t.CSizeT = field_annot_buf[fi]
fannot: t.CChar | t.CPtr = None
fannot: str = None
if fannot_addr != 0:
fannot = (t.CChar | t.CPtr)(t.CVoid(fannot_addr, t.CPtr))
fannot = (str)(t.CVoid(fannot_addr, t.CPtr))
if fname is not None and fty2 is not None:
HandlesStruct.add_field(pool, entry, fname, fty2, fdef, fannot)
@@ -2750,8 +2759,8 @@ class ClassGenMixin:
# ============================================================
# _vtable_strcat — 将 src 追加到 dst 末尾
# ============================================================
def _vtable_strcat(self, dst: t.CChar | t.CPtr, dst_size: t.CSizeT,
src: t.CChar | t.CPtr):
def _vtable_strcat(self, dst: str, dst_size: t.CSizeT,
src: str):
"""将 src 追加到 dst 末尾"""
if dst is None or src is None:
return
@@ -2787,7 +2796,7 @@ class ClassGenMixin:
# 例如: void ({i32, i32}*, i32)
# ============================================================
def _format_func_type_str(self, pool: memhub.MemBuddy | t.CPtr,
buf: t.CChar | t.CPtr, buf_size: t.CSizeT,
buf: str, buf_size: t.CSizeT,
func: llvmlite.Function | t.CPtr) -> int:
"""从 Function 对象生成函数类型字符串"""
if buf is None or func is None or buf_size == 0:
@@ -2795,7 +2804,7 @@ class ClassGenMixin:
buf[0] = '\0'
# 打印返回类型(使用访问器函数避免跨模块直接字段访问)
ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(func)
ret_buf: t.CChar | t.CPtr = pool.alloc(128)
ret_buf: str = pool.alloc(128)
if ret_buf is not None and ret_ty is not None:
ret_buf[0] = '\0'
llvmlite.TypePrint(ret_buf, 128, ret_ty, pool)
@@ -2805,7 +2814,7 @@ class ClassGenMixin:
# 遍历参数(使用访问器函数避免跨模块直接字段访问)
cur: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(func)
first: int = 1
param_buf: t.CChar | t.CPtr = pool.alloc(128)
param_buf: str = pool.alloc(128)
_pc: int = 0
while cur is not None:
_pc += 1
@@ -2942,20 +2951,20 @@ class ClassGenMixin:
while mro_ptr is not None and mro_ptr[mro_i] != 0:
anc: str = (str | t.CPtr)(t.CVoid(mro_ptr[mro_i], t.CPtr))
if anc is not None:
probe_buf: t.CChar | t.CPtr = pool.alloc(128)
probe_buf: str = pool.alloc(128)
if probe_buf is not None:
viperlib.snprintf(probe_buf, 128, "%s.%s", anc, pmethod_name)
if HandlesExprCall.find_func_global(probe_buf) is not None:
def_class = anc
break
mro_i += 1
pfname_buf: t.CChar | t.CPtr = pool.alloc(128)
pfname_buf: str = pool.alloc(128)
if pfname_buf is not None:
viperlib.snprintf(pfname_buf, 128, "%s.%s", def_class, pmethod_name)
full_names_buf[method_count] = t.CSizeT(pfname_buf)
# 复制方法名(短名)
pmname_len: t.CSizeT = string.strlen(pmethod_name)
pmname_buf: t.CChar | t.CPtr = stdlib.malloc(pmname_len + 1)
pmname_buf: str = stdlib.malloc(pmname_len + 1)
if pmname_buf is not None:
string.strcpy(pmname_buf, pmethod_name)
method_names_buf[method_count] = t.CSizeT(pmname_buf)
@@ -3009,14 +3018,14 @@ class ClassGenMixin:
if already_in_vt == 1:
continue
# 构造 full_name = "ClassName.method_name"
fname_buf: t.CChar | t.CPtr = pool.alloc(128)
fname_buf: str = pool.alloc(128)
if fname_buf is not None:
viperlib.snprintf(fname_buf, 128, "%s.%s", class_name, mname)
full_names_buf[method_count] = t.CSizeT(fname_buf)
# 复制方法名
mname_len: t.CSizeT = string.strlen(mname)
mname_buf: t.CChar | t.CPtr = stdlib.malloc(mname_len + 1)
mname_buf: str = stdlib.malloc(mname_len + 1)
if mname_buf is not None:
string.strcpy(mname_buf, mname)
method_names_buf[method_count] = t.CSizeT(mname_buf)
@@ -3095,7 +3104,7 @@ class ClassGenMixin:
# 3. 构造初始化字符串
# 大 vtable(如 MemBuddy 28+ 方法)每个方法 bitcast 约 100+ 字节,
# 4096 可能写满导致截断/strlen 越界,用 16384 预留足够空间。
init_buf: t.CChar | t.CPtr = pool.alloc(16384)
init_buf: str = pool.alloc(16384)
if init_buf is None:
return 0
init_buf[0] = '\0'
@@ -3158,11 +3167,14 @@ class ClassGenMixin:
self._vtable_strcat(init_buf, 16384, mangled_name)
self._vtable_strcat(init_buf, 16384, " to i8*)")
continue
self._vtable_strcat(init_buf, 16384, "i8* null")
# fail-fast:func 无效且全局表 TypeStr 回退也失败,
# 不再写 "i8* null" 静默掩盖缺失实现。
HandlesType.fatal_error(
cd, f"vtable 方法 '{full_name}' 找不到函数实现", "InternalCompilerError")
continue
# 构造函数类型字符串
func_ty_buf: t.CChar | t.CPtr = pool.alloc(512)
func_ty_buf: str = pool.alloc(512)
if func_ty_buf is None:
self._vtable_strcat(init_buf, 16384, "i8* null")
continue
@@ -3184,7 +3196,7 @@ class ClassGenMixin:
self._vtable_strcat(init_buf, 16384, " }")
# 4. 构造 VTable 全局变量名
vtable_name_buf: t.CChar | t.CPtr = pool.alloc(128)
vtable_name_buf: str = pool.alloc(128)
if vtable_name_buf is None:
return 0
viperlib.snprintf(vtable_name_buf, 128, "%s.vtable", class_name)
@@ -3226,10 +3238,15 @@ class ClassGenMixin:
cd: ast.ClassDef | t.CPtr,
struct_ty: llvmlite.LLVMType | t.CPtr,
class_name: str,
mark_only: int = 0) -> int:
mark_only: int = 0,
reemit: int = 0) -> int:
"""扫描 class body 中的方法并翻译,生成 __before_init__
mark_only: 0=全量翻译(默认),1=只设置 IsOOP/HasNew/HasInit 标志(不翻译方法体)
reemit: 1=补译模式(_specialize_generic_class Phase B 补译分支调用)。
补译分支为防重入已提前置 MethodsEmitted=1,但方法体尚未发射,
必须跳过下方 MethodsEmitted==1 的防重复检查强制发射,否则补译
被自身拦截 → 特化方法只有 call 无 define → 链接 undefined symbol。
"""
if trans is None or cd is None or struct_ty is None or class_name is None:
return 0
@@ -3310,7 +3327,9 @@ class ClassGenMixin:
# 时补译方法体并置 1)之后,同一特化类又经 translate_class_def 全量
# 翻译进入本方法 → 重复生成 __before_init__ → ld.lld duplicate symbol。
# 已生成过则直接跳过(方法+__before_init__ 都产出过,跳过安全)。
if oop_entry is not None and oop_entry.MethodsEmitted == 1:
# reemit=1(补译模式)时跳过本检查:补译分支为防重入已提前置
# MethodsEmitted=1,但方法体尚未发射,必须强制发射。
if oop_entry is not None and oop_entry.MethodsEmitted == 1 and reemit == 0:
return 0
# 防重入:方法体翻译前先标记 MethodsEmitted=1。
@@ -3398,7 +3417,7 @@ class ClassGenMixin:
# 提取装饰器元数据(@property/@staticmethod/@classmethod/@x.setter/@x.deleter)
func_meta: int = self._extract_func_meta(fd.decorator_list)
# property setter/deleter 函数名带 $set/$del 后缀,避免与 getter 冲突
method_name_buf: t.CChar | t.CPtr = pool.alloc(128)
method_name_buf: str = pool.alloc(128)
if method_name_buf is None:
return 0
viperlib.snprintf(method_name_buf, 128, "%s", fd.name)
@@ -3421,7 +3440,7 @@ class ClassGenMixin:
is_class_m = 1
# 构建方法全名: ClassName.method_name
full_name_buf: t.CChar | t.CPtr = pool.alloc(128)
full_name_buf: str = pool.alloc(128)
if full_name_buf is None:
return 0
viperlib.snprintf(full_name_buf, 128, "%s.%s", class_name, method_name)
@@ -3494,7 +3513,7 @@ class ClassGenMixin:
fd_first_arg: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(fd_ags.args.get(0))
if fd_first_arg is not None and fd_first_arg.arg is not None:
first_pname = fd_first_arg.arg
first_pname_buf: t.CChar | t.CPtr = pool.alloc(32)
first_pname_buf: str = pool.alloc(32)
if first_pname_buf is not None:
viperlib.snprintf(first_pname_buf, 32, "%%%s", first_pname)
llvmlite.add_param(pool, func, self_ptr_ty, first_pname_buf)
@@ -3528,7 +3547,7 @@ class ClassGenMixin:
param_ty = llvmlite.Ptr(pool, aelem_ty)
case _:
param_ty = resolved
pname: t.CChar | t.CPtr = pool.alloc(32)
pname: str = pool.alloc(32)
if pname is not None:
viperlib.snprintf(pname, 32, "%%%s", arg.arg)
llvmlite.add_param(pool, func, param_ty, pname)
@@ -3564,7 +3583,7 @@ class ClassGenMixin:
cfirst: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(cags.args.get(0))
if cfirst is not None and cfirst.arg is not None:
self_var_name = cfirst.arg
self_ssa_name_buf: t.CChar | t.CPtr = pool.alloc(32)
self_ssa_name_buf: str = pool.alloc(32)
if self_ssa_name_buf is not None:
viperlib.snprintf(self_ssa_name_buf, 32, "%%%s", cfirst.arg)
self_ssa_name = self_ssa_name_buf
@@ -3591,6 +3610,12 @@ class ClassGenMixin:
if arg2.annotation is not None:
resolved2: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
pool, arg2.annotation, imported_modules, from_imports, trans)
if resolved2 is None:
# fail-fast:参数有注解但类型解析失败,不再静默保持 i32
HandlesType.fatal_error(
arg2, f"方法 '{class_name}.{method_name}' 参数 '{arg2.arg}' 类型解析失败",
"NameError")
resolved2 = i32_ty # 不可达(fatal_error 已退出)
if resolved2 is not None:
# 与 add_param 保持一致:裸类形参 → Ptr(struct)(对象即指针)
# CArray 形参 → 元素指针 ty*(数组衰减,与 add_param 一致)
@@ -3611,7 +3636,7 @@ class ClassGenMixin:
if cls_nm_oc is not None:
HandlesVar.set_var_annot_class_name(
trans.SymTab, arg2.arg, cls_nm_oc)
pname2: t.CChar | t.CPtr = pool.alloc(32)
pname2: str = pool.alloc(32)
if pname2 is not None:
viperlib.snprintf(pname2, 32, "%%%s", arg2.arg)
param_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(
@@ -3725,7 +3750,7 @@ class ClassGenMixin:
void_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool)
# 构建函数名: ClassName.__before_init__
full_name_buf: t.CChar | t.CPtr = pool.alloc(128)
full_name_buf: str = pool.alloc(128)
if full_name_buf is None:
return 0
viperlib.snprintf(full_name_buf, 128, "%s.__before_init__", class_name)
@@ -3804,7 +3829,7 @@ class ClassGenMixin:
vt_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, vt_ty)
# 构造 vtable 全局变量名
vt_name_buf: t.CChar | t.CPtr = pool.alloc(128)
vt_name_buf: str = pool.alloc(128)
if vt_name_buf is not None:
viperlib.snprintf(vt_name_buf, 128, "%s.vtable", class_name)
vt_full_name: str = vt_name_buf
@@ -3820,7 +3845,7 @@ class ClassGenMixin:
llvmlite.value_set_ty(vt_ref, vt_ptr_ty)
llvmlite.value_set_isconst(vt_ref, 1)
# Name 格式: @"mangled" 或 @mangled
vt_ref_name: t.CChar | t.CPtr = pool.alloc(256)
vt_ref_name: str = pool.alloc(256)
if vt_ref_name is not None:
vt_ref_name[0] = '\0'
if self._vtable_name_needs_quote(vt_mangled) != 0:
+168 -140
View File
@@ -105,13 +105,13 @@ class ExprGenMixin:
# 转义 LLVM IR 字符串字面量
# ============================================================
def escape_llvm_string(self, pool: memhub.MemBuddy | t.CPtr,
src: t.CChar | t.CPtr) -> t.CChar | t.CPtr:
src: str) -> str:
"""将字符串转换为 LLVM IR 字符串字面量 c"...\\00" """
if src is None:
return None
slen: t.CSizeT = string.strlen(src)
alloc_size: t.CSizeT = 4 * slen + 8
buf: t.CChar | t.CPtr = pool.alloc(alloc_size)
buf: str = pool.alloc(alloc_size)
if buf is None:
return None
pos: t.CSizeT = 0
@@ -386,7 +386,7 @@ class ExprGenMixin:
cls_ugi: str = self._sub_base_class_name(pool, trans, sub_node)
if cls_ugi is None:
return 0
lookup_ugi: t.CChar | t.CPtr = pool.alloc(128)
lookup_ugi: str = pool.alloc(128)
if lookup_ugi is None:
return 0
viperlib.snprintf(lookup_ugi, 128, "%s.__getitem__", cls_ugi)
@@ -566,7 +566,7 @@ class ExprGenMixin:
str_val: str,
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
"""创建全局字符串常量并返回 i8* bitcast"""
escaped: t.CChar | t.CPtr = self.escape_llvm_string(pool, str_val)
escaped: str = self.escape_llvm_string(pool, str_val)
if escaped is None:
return None
@@ -581,7 +581,7 @@ class ExprGenMixin:
trans._label_counter += 1
# 字符串名加 SHA1 前缀,和函数导出规则一致,避免跨模块重名
gv_name: t.CChar | t.CPtr = pool.alloc(48)
gv_name: str = pool.alloc(48)
if gv_name is None:
return None
if trans.ModuleSha1 is not None:
@@ -602,7 +602,7 @@ class ExprGenMixin:
gv.Initializer = escaped
arr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, arr_ty)
gv_ref_name: t.CChar | t.CPtr = pool.alloc(64)
gv_ref_name: str = pool.alloc(64)
if gv_ref_name is None:
return None
viperlib.snprintf(gv_ref_name, 64, "@%s", gv.Name)
@@ -669,9 +669,13 @@ class ExprGenMixin:
# ============================================================
def _infer_elem_type_from_value(self, pool: memhub.MemBuddy | t.CPtr,
value: llvmlite.Value | t.CPtr) -> str:
"""从 LLVM Value 的类型推断 list 元素类型名"""
"""从 LLVM Value 的类型推断 list 元素类型名
fail-fast:值类型缺失/无法映射时返回 None(调用方携带节点报错终止),
绝不静默回退 "str"(掩盖上游 Value 类型缺失根因)。
"""
if value is None or value.Ty is None:
return "str"
return None
ty: llvmlite.LLVMType | t.CPtr = value.Ty
bits: int = self.get_llvm_type_bits(ty)
if bits != 0:
@@ -683,7 +687,7 @@ class ExprGenMixin:
return "CInt8T"
if bits == 16:
return "CInt16T"
return "int"
return None
if self.is_ptr_type(ty) != 0:
return "str"
fbits: int = self.get_llvm_float_bits(ty)
@@ -692,7 +696,7 @@ class ExprGenMixin:
return "CDouble"
if fbits == 32:
return "CFloat"
return "str"
return None
# ============================================================
# _find_pool_var — 查找上下文中的 pool 变量
@@ -741,7 +745,7 @@ class ExprGenMixin:
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)
ref_name_fb: str = 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)
@@ -788,12 +792,21 @@ class ExprGenMixin:
inferred_type_name: str = elem_type_name
first_elem_val: llvmlite.Value | t.CPtr = None
if inferred_type_name is None:
inferred_type_name = "str"
if elts_count > 0:
first_elem_node: ast.AST | t.CPtr = elts.get(0)
first_elem_val = self.translate_value(builder, pool, mod, first_elem_node, None, 0, trans)
if first_elem_val is not None:
inferred_type_name = self._infer_elem_type_from_value(pool, first_elem_val)
if first_elem_val is None or first_elem_val.Ty is None:
# fail-fast:首元素翻译失败/Value 类型缺失,立即终止编译(暴露上游根因)
HandlesType.fatal_error(
first_elem_node, "list 字面量元素类型推断失败(Value 类型缺失)", "TypeError")
inferred_type_name = self._infer_elem_type_from_value(pool, first_elem_val)
if inferred_type_name is None:
# fail-fast:首元素 Value 类型无法映射为 list 元素类型,立即终止编译
HandlesType.fatal_error(
first_elem_node, "list 字面量元素类型推断失败(Value 类型缺失)", "TypeError")
else:
# 空 list 无元素可推断,保持默认 str(list[str])
inferred_type_name = "str"
# 查找 pool 变量
pool_alloca: llvmlite.Value | t.CPtr = self._find_pool_var(trans)
@@ -964,7 +977,7 @@ class ExprGenMixin:
return None
# 编译期格式串缓冲(pool 分配)
fmt_buf: t.CChar | t.CPtr = pool.alloc(FSTR_BUF_SIZE)
fmt_buf: str = pool.alloc(FSTR_BUF_SIZE)
if fmt_buf is None:
return None
fmt_buf[0] = '\0'
@@ -1005,7 +1018,8 @@ class ExprGenMixin:
if c_fmt is None:
c_fmt = self._fstr_infer_c_fmt(pool, val, fv.value, trans)
if c_fmt is None:
c_fmt = "%d"
# fail-fast:f-string 格式无法推断(值类型缺失),立即终止编译
HandlesType.fatal_error(fv.value, "f-string 格式无法推断(值类型缺失)", "TypeError")
# 追加格式说明符
if string.strlen(fmt_buf) + string.strlen(c_fmt) < FSTR_BUF_SIZE - 1:
string.strcat(fmt_buf, c_fmt)
@@ -1035,7 +1049,7 @@ class ExprGenMixin:
fv: ast.FormattedValue | t.CPtr = (ast.FormattedValue | t.CPtr)(node)
if fv is None or fv.value is None:
return None
fmt_buf: t.CChar | t.CPtr = pool.alloc(FSTR_BUF_SIZE)
fmt_buf: str = pool.alloc(FSTR_BUF_SIZE)
if fmt_buf is None:
return None
fmt_buf[0] = '\0'
@@ -1056,7 +1070,8 @@ class ExprGenMixin:
if c_fmt is None:
c_fmt = self._fstr_infer_c_fmt(pool, val, fv.value, trans)
if c_fmt is None:
c_fmt = "%d"
# fail-fast:f-string 格式无法推断(值类型缺失),立即终止编译
HandlesType.fatal_error(fv.value, "f-string 格式无法推断(值类型缺失)", "TypeError")
if string.strlen(fmt_buf) + string.strlen(c_fmt) < FSTR_BUF_SIZE - 1:
string.strcat(fmt_buf, c_fmt)
cast_val: llvmlite.Value | t.CPtr = self._fstr_cast_value(
@@ -1072,7 +1087,7 @@ class ExprGenMixin:
def _fstr_finalize(self, builder: llvmlite.IRBuilder | t.CPtr,
pool: memhub.MemBuddy | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
fmt_buf: t.CChar | t.CPtr,
fmt_buf: str,
arg_head: llvmlite.Value | t.CPtr,
arg_tail: llvmlite.Value | t.CPtr,
arg_count: int,
@@ -1108,7 +1123,7 @@ class ExprGenMixin:
llvmlite.build_call(builder, "snprintf", buf_ptr, 3 + arg_count, i32_ty, 1)
return buf_ptr
def _fstr_append_literal(self, fmt_buf: t.CChar | t.CPtr,
def _fstr_append_literal(self, fmt_buf: str,
lit: str) -> None:
"""追加字面量到格式串(% 转义为 %%)"""
if fmt_buf is None or lit is None:
@@ -1135,7 +1150,7 @@ class ExprGenMixin:
si += 1
fmt_buf[cur_len] = '\0'
def _fstr_append_raw(self, fmt_buf: t.CChar | t.CPtr, s: str) -> None:
def _fstr_append_raw(self, fmt_buf: str, s: str) -> None:
"""追加原始字符串(不做 % 转义)"""
if fmt_buf is None or s is None:
return
@@ -1152,7 +1167,7 @@ class ExprGenMixin:
if spec_node is None or pool is None or val is None:
return None
# 1. 提取 spec 字符串(JoinedStr 仅常量拼接)
spec: t.CChar | t.CPtr = pool.alloc(FSTR_SPEC_MAX)
spec: str = pool.alloc(FSTR_SPEC_MAX)
if spec is None:
return None
spec[0] = '\0'
@@ -1197,9 +1212,9 @@ class ExprGenMixin:
if ch1 == '<' or ch1 == '>' or ch1 == '^' or ch1 == '=':
align_char = ch1
pos += 2
c_flags: t.CChar | t.CPtr = pool.alloc(FSTR_FMT_MAX)
c_width: t.CChar | t.CPtr = pool.alloc(32)
c_prec: t.CChar | t.CPtr = pool.alloc(32)
c_flags: str = pool.alloc(FSTR_FMT_MAX)
c_width: str = pool.alloc(32)
c_prec: str = pool.alloc(32)
if c_flags is None or c_width is None or c_prec is None:
return None
c_flags[0] = '\0'
@@ -1254,7 +1269,7 @@ class ExprGenMixin:
return None # 多余字符无法解析
# 3. 长度修饰(按值类型位宽)
len_mod: t.CChar | t.CPtr = pool.alloc(4)
len_mod: str = pool.alloc(4)
if len_mod is None:
return None
len_mod[0] = '\0'
@@ -1269,7 +1284,7 @@ class ExprGenMixin:
string.strcpy(len_mod, "hh")
# 4. 组装 C 格式串
out: t.CChar | t.CPtr = pool.alloc(FSTR_FMT_MAX)
out: str = pool.alloc(FSTR_FMT_MAX)
if out is None:
return None
out[0] = '\0'
@@ -1299,7 +1314,7 @@ class ExprGenMixin:
elif fmt_type == 'f' or fmt_type == 'F':
string.strcat(out, "f")
elif fmt_type == 'e' or fmt_type == 'E' or fmt_type == 'g' or fmt_type == 'G':
tmp_ch: t.CChar | t.CPtr = pool.alloc(2)
tmp_ch: str = pool.alloc(2)
if tmp_ch is None:
return None
tmp_ch[0] = fmt_type
@@ -1316,7 +1331,7 @@ class ExprGenMixin:
string.strcat(out, "d")
elif fmt_type == 'x' or fmt_type == 'X' or fmt_type == 'o' or fmt_type == 'u':
string.strcat(out, len_mod)
tmp_ch2: t.CChar | t.CPtr = pool.alloc(2)
tmp_ch2: str = pool.alloc(2)
if tmp_ch2 is None:
return None
tmp_ch2[0] = fmt_type
@@ -1333,7 +1348,7 @@ class ExprGenMixin:
"""无 format_spec 时按值类型推断 C printf 格式(对齐 TPC 无 spec 分支,带 % 前缀)"""
if val is None or pool is None:
return None
out: t.CChar | t.CPtr = pool.alloc(16)
out: str = pool.alloc(16)
if out is None:
return None
out[0] = '\0'
@@ -1359,7 +1374,9 @@ class ExprGenMixin:
return "%f"
if HandlesExpr.is_ptr_type(val.Ty) != 0:
return "%s"
return "%d"
# fail-fast:值类型缺失(非整数/浮点/指针),无法推断 C 格式,立即终止编译
HandlesType.fatal_error(arg_node, "f-string 格式无法推断(值类型缺失)", "TypeError")
return None
def _fstr_cast_value(self, builder: llvmlite.IRBuilder | t.CPtr,
pool: memhub.MemBuddy | t.CPtr,
@@ -1454,7 +1471,7 @@ class ExprGenMixin:
# 2. 创建三个基本块
cnt: int = trans._label_counter
trans._label_counter = cnt + 1
name_buf: t.CChar | t.CPtr = pool.alloc(32)
name_buf: str = pool.alloc(32)
if name_buf is None:
return None
viperlib.snprintf(name_buf, 32, "ifexp.then.%d", cnt)
@@ -1476,7 +1493,8 @@ class ExprGenMixin:
builder, pool, mod, ie.body, None, 0, trans)
then_blk_for_phi: llvmlite.BasicBlock | t.CPtr = trans._cur_builder.CurBlock
if body_val is None:
body_val = llvmlite.const_int32(pool, 0)
# fail-fast:三元表达式 then 分支翻译失败,立即终止编译(暴露上游根因)
HandlesType.fatal_error(ie.body, "三元表达式分支翻译失败", "TypeError")
# 暂不 br,等类型对齐后再 br
# 5. else 分支
@@ -1485,7 +1503,8 @@ class ExprGenMixin:
builder, pool, mod, ie.orelse, None, 0, trans)
else_blk_for_phi: llvmlite.BasicBlock | t.CPtr = trans._cur_builder.CurBlock
if orelse_val is None:
orelse_val = llvmlite.const_int32(pool, 0)
# fail-fast:三元表达式 else 分支翻译失败,立即终止编译(暴露上游根因)
HandlesType.fatal_error(ie.orelse, "三元表达式分支翻译失败", "TypeError")
# 暂不 br,等类型对齐后再 br
# 类型对齐 (两分支类型可能不同)
@@ -1528,7 +1547,8 @@ class ExprGenMixin:
phi_ty: llvmlite.LLVMType | t.CPtr = body_val.Ty
if phi_ty is None:
phi_ty = llvmlite.Int32(pool)
# fail-fast:三元表达式分支类型缺失,立即终止编译(暴露上游根因)
HandlesType.fatal_error(node, "三元表达式分支类型缺失", "TypeError")
inc1: llvmlite.PhiIncoming | t.CPtr = llvmlite.new_phi_incoming(
pool, body_val, then_blk_for_phi)
@@ -1824,17 +1844,12 @@ class ExprGenMixin:
lhs = llvmlite.ConstNull(pool, rhs.Ty, "null")
else:
# 类型不匹配:数值vs指针 或 不同级指针
# 用 fmt_buf 构造可读消息(Viper % 格式化在部分路径生成 null)
fmt_msg: t.CChar | t.CPtr = VLogger.fmt_buf()
if fmt_msg is not None:
viperlib.snprintf(
fmt_msg, 1024,
"比较类型不匹配(行 %d): lhs 层级=%d (ty=%p), rhs 层级=%d (ty=%p)",
cmp.lineno, lhs_ptr_level, lhs.Ty, rhs_ptr_level, rhs.Ty)
VLogger.error(fmt_msg, "Compare")
else:
VLogger.error("比较类型不匹配: 数值与指针/不同级指针比较", "Compare")
return None
# fail-fast:比较类型不匹配立即终止编译(暴露上游根因),
# 不再 VLogger.error + 返回 None 静默跳过
HandlesType.fatal_error(
cmp,
f"比较类型不匹配: 数值与指针/不同级指针比较 (lhs 层级={lhs_ptr_level}, rhs 层级={rhs_ptr_level})",
"TypeError")
else:
# None 比较: None 被翻译为 i8* null(一级指针)
# 如果 lhs 是指针,将 rhs (i8* null) bitcast 为 lhs 的指针类型
@@ -1890,8 +1905,8 @@ class ExprGenMixin:
rhs_is_ptr_now: int = self.is_ptr_type(rhs.Ty)
if lhs_is_ptr_now != 0 and rhs_is_ptr_now != 0:
# 两边都是指针,用 TypePrint 比较类型字符串
lhs_ty_buf: t.CChar | t.CPtr = pool.alloc(128)
rhs_ty_buf: t.CChar | t.CPtr = pool.alloc(128)
lhs_ty_buf: str = pool.alloc(128)
rhs_ty_buf: str = pool.alloc(128)
if lhs_ty_buf is not None and rhs_ty_buf is not None:
llvmlite.TypePrint(lhs_ty_buf, 128, lhs.Ty, pool)
llvmlite.TypePrint(rhs_ty_buf, 128, rhs.Ty, pool)
@@ -2044,7 +2059,7 @@ class ExprGenMixin:
# move_to_end 保证 BB 文本顺序与控制流顺序一致,标签名用 counter 安全)
cnt: int = builder.Counter
builder.Counter = cnt + 1
name_buf: t.CChar | t.CPtr = pool.alloc(32)
name_buf: str = pool.alloc(32)
if name_buf is None:
return None
viperlib.snprintf(name_buf, 32, "bool.merge.%d", cnt)
@@ -2841,7 +2856,9 @@ class ExprGenMixin:
if mod_alloca.Ty is not None:
load_ty = mod_alloca.Ty.Pointee
if load_ty is None:
load_ty = llvmlite.Int32(pool)
# fail-fast:global 变量存储类型缺失,立即终止编译(暴露上游根因)
HandlesType.fatal_error(
node, f"变量 '{nm_id}' 存储类型缺失", "TypeError")
return llvmlite.build_load(builder, load_ty, mod_alloca)
# nonlocal 变量:通过闭包 env 访问
@@ -2865,7 +2882,9 @@ class ExprGenMixin:
if alloca.Ty is not None:
load_ty = alloca.Ty.Pointee
if load_ty is None:
load_ty = llvmlite.Int32(pool)
# fail-fast:局部变量存储类型缺失,立即终止编译(暴露上游根因)
HandlesType.fatal_error(
node, f"变量 '{nm_id}' 存储类型缺失", "TypeError")
# 结构体值变量(alloca 类型为 Struct,如 `x: Cls | t.CPtr`):
# 按"对象即指针"语义返回其地址(alloca 指针),而非加载结构体值。
# 结构体值无法参与 ptrtoint/方法调用等地址相关操作,加载值会导致
@@ -2901,13 +2920,15 @@ class ExprGenMixin:
fn_ref: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(
trans.Module, nm_id)
if fn_ref is not None:
fn_name: t.CChar | t.CPtr = llvmlite.function_get_name(fn_ref)
fn_name: str = llvmlite.function_get_name(fn_ref)
if fn_name is None:
return None
# 构造函数类型:ret_ty + 参数 ParamNode 链表
fn_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(fn_ref)
if fn_ret_ty is None:
fn_ret_ty = llvmlite.Int32(pool)
# fail-fast:函数返回类型缺失,无法构造函数指针(暴露上游根因)
HandlesType.fatal_error(
node, f"函数 '{nm_id}' 返回类型缺失,无法构造函数指针", "TypeError")
fn_pp: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(fn_ref)
fn_first_node: llvmlite.ParamNode | t.CPtr = None
fn_prev_node: llvmlite.ParamNode | t.CPtr = None
@@ -2933,7 +2954,7 @@ class ExprGenMixin:
return None
llvmlite.value_set_ty(fn_ref_v, llvmlite.Ptr(pool, fn_ty))
llvmlite.value_set_isconst(fn_ref_v, 1)
fn_ref_name: t.CChar | t.CPtr = pool.alloc(256)
fn_ref_name: str = pool.alloc(256)
if fn_ref_name is not None:
fn_ref_name[0] = '\0'
if HandlesClassDef._vtable_name_needs_quote(fn_name) != 0:
@@ -2976,27 +2997,24 @@ class ExprGenMixin:
while fi_orig[og_len_fi] != ' ' and fi_orig[og_len_fi] != '\0':
og_len_fi += 1
if og_len_fi > 0:
og_buf_fi: t.CChar | t.CPtr = pool.alloc(og_len_fi + 1)
og_buf_fi: str = pool.alloc(og_len_fi + 1)
if og_buf_fi is not None:
string.strncpy(og_buf_fi, fi_orig, og_len_fi)
og_buf_fi[og_len_fi] = '\0'
fi_gname = og_buf_fi
# stub 已注入全局(精确类型)→ 直接引用;未注入 → external 声明
# stub 已注入全局(精确类型)→ 直接引用;未注入 → fail-fast
# (不再创建 external i8* 声明,否则 llc 报 "use of undefined value",
# 静默回退掩盖 stub 未注入的上游根因)
gv_fi: llvmlite.GlobalVariable | t.CPtr = self.find_global_in_module(
trans.Module, fi_gname)
ref_fi: llvmlite.Value | t.CPtr = None
if gv_fi is not None and gv_fi.Ty is not None:
ref_fi = self.make_global_ref(pool, fi_gname, gv_fi.Ty)
else:
i8_ptr_hint_fi: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(
pool, llvmlite.Int8(pool))
ext_gv_fi: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(
pool, fi_gname, i8_ptr_hint_fi)
if ext_gv_fi is not None:
ext_gv_fi.Linkage = "external"
ext_gv_fi.Initializer = None
llvmlite.module_add_global(trans.Module, ext_gv_fi)
ref_fi = self.make_global_ref(pool, fi_gname, i8_ptr_hint_fi)
HandlesType.fatal_error(
node,
f"跨模块全局变量 '{fi_gname}' 类型未知(stub 未注入)",
"TypeError")
if ref_fi is not None and ref_fi.Ty is not None:
lty_fi: llvmlite.LLVMType | t.CPtr = ref_fi.Ty.Pointee
if lty_fi is not None:
@@ -3004,19 +3022,21 @@ class ExprGenMixin:
return ref_fi
# 所有查找路径均失败
# fail-fast: 仅对符合 CDefine 命名约定(ALL_CAPS)的名字报错
# 避免对 match/self/pool 等关键字和变量名误报
# 跨模块 CDefine 查找已在上方完成,此处不重复
if self._is_cdefine_name_pattern(nm_id) != 0:
err_buf2: str = pool.alloc(256)
if err_buf2 is not None:
cur_sha1: str = "(unknown)"
if trans is not None and trans.ModuleSha1 is not None:
cur_sha1 = trans.ModuleSha1
viperlib.snprintf(err_buf2, 256,
"[CD] FATAL: Name '%s' NOT found (CDefine local+cross + global + nonlocal + alloca + module alias) in module sha1=%s\n",
nm_id, cur_sha1)
VLogger.error(err_buf2, "CD")
# fail-fast:未定义名称立即终止编译(NameError,暴露上游根因),
# 不再静默返回 None(否则下游 store/call 到 None 崩溃,掩盖名称查找失败)。
# 豁免:关键字/内建名(self/pool/true/false/None/match 上下文关键字、_、
# CIf 系等特殊名字)——这些名字不注册 SymTab 属正常,调用方有合法语义
# 处理路径(如 CIf 未定义名特判走 else),保持返回 None 不报错。
if nm_id is None:
return None
if string.strcmp(nm_id, "self") == 0 or string.strcmp(nm_id, "pool") == 0 \
or string.strcmp(nm_id, "true") == 0 or string.strcmp(nm_id, "false") == 0 \
or string.strcmp(nm_id, "None") == 0 or string.strcmp(nm_id, "match") == 0 \
or string.strcmp(nm_id, "_") == 0 \
or string.strcmp(nm_id, "CIf") == 0 or string.strcmp(nm_id, "CIfdef") == 0 \
or string.strcmp(nm_id, "CIfndef") == 0:
return None
HandlesType.fatal_error(node, f"未定义名称 '{nm_id}'", "NameError")
return None
# ============================================================
@@ -3094,9 +3114,21 @@ class ExprGenMixin:
return llvmlite.Float(pool)
if string.strstr(struct_name, "list[CChar]") is not None:
return llvmlite.Int8(pool)
# str/bytes/CPtr/其他指针类型 → i8*
# str/bytes/CPtr 等已知指针元素类型 → i8*(元素存储为 8 字节地址)
i8_ty_d: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
return llvmlite.Ptr(pool, i8_ty_d)
if string.strstr(struct_name, "list[str]") is not None:
return llvmlite.Ptr(pool, i8_ty_d)
if string.strstr(struct_name, "list[bytes]") is not None:
return llvmlite.Ptr(pool, i8_ty_d)
if string.strstr(struct_name, "list[CPtr]") is not None:
return llvmlite.Ptr(pool, i8_ty_d)
# fail-fast:未知 list[T] 元素类型无法映射 LLVM 类型,立即终止编译
# (不再静默回退 Ptr(i8),暴露上游元素类型缺失根因)
HandlesType.fatal_error(
None,
f"list 元素类型未知:'{struct_name}' 无法映射 LLVM 类型",
"TypeError")
return None
# ============================================================
# list_setitem_inline — 内联生成 list[T] __setitem__ 逻辑
@@ -3347,7 +3379,7 @@ class ExprGenMixin:
# (对齐 TPC _HandleSubscriptLlvm: if ClassName and has_function(__getitem__))
cls_nm_rd_ptr: str = self._get_custom_struct_cls_nm(pool, inner_ty)
if not (cls_nm_rd_ptr is None):
gi_lookup_rd: t.CChar | t.CPtr = pool.alloc(128)
gi_lookup_rd: str = pool.alloc(128)
if gi_lookup_rd is not None:
viperlib.snprintf(gi_lookup_rd, 128, "%s.__getitem__", cls_nm_rd_ptr)
if HandlesExprCall.find_func_in_module(mod, gi_lookup_rd) is not None:
@@ -3425,7 +3457,7 @@ class ExprGenMixin:
# 否则普通结构体指针按下标做 GEP 数组访问
cls_nm_sub: str = HandlesStruct.get_class_name_by_type(pool, pointee)
if not (cls_nm_sub is None):
gi_lookup_sub: t.CChar | t.CPtr = pool.alloc(128)
gi_lookup_sub: str = pool.alloc(128)
if gi_lookup_sub is not None:
viperlib.snprintf(gi_lookup_sub, 128, "%s.__getitem__", cls_nm_sub)
if HandlesExprCall.find_func_in_module(mod, gi_lookup_sub) is not None:
@@ -3476,7 +3508,7 @@ class ExprGenMixin:
# 否则普通结构体指针按下标做 GEP 数组访问
cls_nm_rd_gen: str = self._get_custom_struct_cls_nm(pool, elem_ty2)
if not (cls_nm_rd_gen is None):
gi_lookup_gen: t.CChar | t.CPtr = pool.alloc(128)
gi_lookup_gen: str = pool.alloc(128)
if gi_lookup_gen is not None:
viperlib.snprintf(gi_lookup_gen, 128, "%s.__getitem__", cls_nm_rd_gen)
if HandlesExprCall.find_func_in_module(mod, gi_lookup_gen) is not None:
@@ -3552,7 +3584,7 @@ class ExprGenMixin:
if name is None or ty is None:
return None
ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, ty)
ref_name: t.CChar | t.CPtr = pool.alloc(64)
ref_name: str = pool.alloc(64)
if ref_name is None:
return None
viperlib.snprintf(ref_name, 64, "@%s", name)
@@ -4088,7 +4120,7 @@ class ExprGenMixin:
enum_nm.id)
if base_ty is not None:
# 生成数字字符串作为常量名(LLVM IR 要求常量输出数字值)
name_buf: t.CChar | t.CPtr = pool.alloc(32)
name_buf: str = pool.alloc(32)
if name_buf is not None:
viperlib.snprintf(name_buf, 32, "%lld", member.Value)
return llvmlite.ConstInt(pool, base_ty, member.Value, name_buf)
@@ -4113,7 +4145,7 @@ class ExprGenMixin:
base_ty_e: llvmlite.LLVMType | t.CPtr = HandlesEnum.get_enum_base_type(
inner_at_e.attr)
if base_ty_e is not None:
name_buf_e: t.CChar | t.CPtr = pool.alloc(32)
name_buf_e: str = pool.alloc(32)
if name_buf_e is not None:
viperlib.snprintf(name_buf_e, 32, "%lld", member_e.Value)
return llvmlite.ConstInt(pool, base_ty_e, member_e.Value, name_buf_e)
@@ -4177,7 +4209,7 @@ class ExprGenMixin:
is_submod: int = 0
if trans._imported_modules is not None:
submod_len: t.CSizeT = string.strlen(nm_ma.id) + string.strlen(at.attr) + 2
submod_buf: t.CChar | t.CPtr = pool.alloc(submod_len)
submod_buf: str = pool.alloc(submod_len)
if submod_buf is not None:
viperlib.snprintf(submod_buf, submod_len, "%s.%s", nm_ma.id, at.attr)
if HandlesImports.is_module_imported(trans._imported_modules, submod_buf) == 1:
@@ -4214,19 +4246,13 @@ class ExprGenMixin:
# 此处返回 None,让上层嵌套属性访问路径处理
if string.strcmp(nm_ma.id, "t") == 0 and string.strcmp(at.attr, "ASM_DESCR") == 0:
return None
# CDefine 未找到且属性名符合 ALL_CAPS 约定: 报 FATAL 错误
# CDefine 未找到且属性名符合 ALL_CAPS 约定: fail-fast 终止编译
# 不再创建未定义的外部全局变量引用(否则 llc 报 "use of undefined value")
if self._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
HandlesType.fatal_error(
at,
f"跨模块 CDefine 未找到: '{nm_ma.id}.{at.attr}'(CDefine cross-module lookup failed)",
"TypeError")
# 非 CDefine: 使用 i8* 作为类型提示 (模块级变量通常存储指针)
i8_ptr_hint: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool))
mod_gv_ref: llvmlite.Value | t.CPtr = self._resolve_module_attribute_global(
@@ -4246,7 +4272,7 @@ class ExprGenMixin:
if HandlesVar.lookup_var(trans.SymTab, inner_nm.id) is None:
# 构建限定模块名: "w32.win32file"
qual_len: t.CSizeT = string.strlen(inner_nm.id) + string.strlen(inner_at.attr) + 2
qual_buf: t.CChar | t.CPtr = pool.alloc(qual_len)
qual_buf: str = pool.alloc(qual_len)
if qual_buf is not None:
viperlib.snprintf(qual_buf, qual_len, "%s.%s", inner_nm.id, inner_at.attr)
if HandlesImports.is_module_imported(trans._imported_modules, qual_buf) == 1:
@@ -4276,20 +4302,15 @@ class ExprGenMixin:
if HandlesType.is_cdefine_double() != 0:
return llvmlite.ConstFloat(pool, llvmlite.Double(pool), dchk_nst)
return llvmlite.const_int32(pool, cdef_val_nested)
# CDefine 未找到: 报 FATAL 错误(不再创建未定义的全局变量引用)
# CDefine 未找到: fail-fast 终止编译(不再创建未定义的全局变量引用)
# 之前此处创建 @INVALID_HANDLE_VALUE 等前向引用,但全局未定义,
# 导致 llc 报 "use of undefined value" 错误。
# 正确做法是报错终止,让开发者修复跨模块 CDefine 查找失败的根本原因。
if self._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")
HandlesType.fatal_error(
at,
f"嵌套属性跨模块 CDefine 未找到: '{qual_buf}.{at.attr}'(CDefine cross-module lookup failed)",
"TypeError")
return None
# 对于 Name 类型的 obj,直接查找 alloca(不 load 结构体);
@@ -4463,7 +4484,7 @@ class ExprGenMixin:
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: 字段未找到,打印诊断信息
# fast-fail: 字段未找到,立即终止编译(不再打印诊断后返回 None)
if trans is not None:
diag_annot: str = None
diag_var_nm: str = None
@@ -4475,16 +4496,19 @@ class ExprGenMixin:
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")
diag_var_txt: str = "?"
if diag_var_nm is not None:
diag_var_txt = diag_var_nm
diag_annot_txt: str = "None"
if diag_annot is not None:
diag_annot_txt = diag_annot
sha1_attr: str = "?"
if trans.ModuleSha1 is not None:
sha1_attr = trans.ModuleSha1
HandlesType.fatal_error(
at,
f"属性访问失败: .{at.attr} (var={diag_var_txt} annot={diag_annot_txt} sha1={sha1_attr})",
"TypeError")
return None
case _:
# fast-fail: 对非指针类型做属性访问(如 i32.x),
@@ -4562,7 +4586,7 @@ class ExprGenMixin:
# 做 GEP 数组访问(走下方指针遍历路径)
cls_nm_ptr_chk: str = self._get_custom_struct_cls_nm(pool, inner_ty)
if not (cls_nm_ptr_chk is None):
si_lookup_gsp: t.CChar | t.CPtr = pool.alloc(128)
si_lookup_gsp: str = pool.alloc(128)
if si_lookup_gsp is not None:
viperlib.snprintf(si_lookup_gsp, 128, "%s.__setitem__", cls_nm_ptr_chk)
if HandlesExprCall.find_func_in_module(mod, si_lookup_gsp) is not None:
@@ -4654,7 +4678,7 @@ class ExprGenMixin:
# 否则普通结构体指针按下标做 GEP 数组访问
cls_nm_gen: str = self._get_custom_struct_cls_nm(pool, elem_ty2)
if not (cls_nm_gen is None):
si_lookup_gen: t.CChar | t.CPtr = pool.alloc(128)
si_lookup_gen: str = pool.alloc(128)
if si_lookup_gen is not None:
viperlib.snprintf(si_lookup_gen, 128, "%s.__setitem__", cls_nm_gen)
if find_func_in_module(mod, si_lookup_gen) is not None:
@@ -4866,7 +4890,7 @@ class ExprGenMixin:
# 普通结构体:GEP 获取字段指针
return llvmlite.build_gep_struct(
builder, struct_ty, field_info.Ty, obj_ptr, field_info.Index)
# fast-fail: 字段未找到,打印诊断信息
# fast-fail: 字段未找到,立即终止编译(不再打印诊断后返回 None)
if trans is not None:
diag_annot_g: str = None
diag_var_nm_g: str = None
@@ -4878,16 +4902,19 @@ class ExprGenMixin:
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")
diag_var_txt_g: str = "?"
if diag_var_nm_g is not None:
diag_var_txt_g = diag_var_nm_g
diag_annot_txt_g: str = "None"
if diag_annot_g is not None:
diag_annot_txt_g = diag_annot_g
sha1_attr_g: str = "?"
if trans.ModuleSha1 is not None:
sha1_attr_g = trans.ModuleSha1
HandlesType.fatal_error(
at,
f"属性写入失败: .{at.attr} (var={diag_var_txt_g} annot={diag_annot_txt_g} sha1={sha1_attr_g})",
"TypeError")
return None
case _:
# fast-fail: 对非指针类型做属性写入(如 i32.x = ...),
@@ -4997,7 +5024,7 @@ class ExprGenMixin:
return None
# 在继承链中查找 dunder 方法
lookup_name: t.CChar | t.CPtr = pool.alloc(128)
lookup_name: str = pool.alloc(128)
if lookup_name is None:
return None
viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, dunder)
@@ -5011,7 +5038,7 @@ class ExprGenMixin:
while mro_ptr is not None and mro_ptr[mi] != 0:
anc: str = (str | t.CPtr)(t.CVoid(mro_ptr[mi], t.CPtr))
if anc is not None:
parent_lookup: t.CChar | t.CPtr = pool.alloc(128)
parent_lookup: str = pool.alloc(128)
if parent_lookup is not None:
viperlib.snprintf(parent_lookup, 128, "%s.%s", anc, dunder)
parent_func: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, parent_lookup)
@@ -5097,7 +5124,7 @@ class ExprGenMixin:
return None
# 在继承链中查找 dunder 方法
lookup_name: t.CChar | t.CPtr = pool.alloc(128)
lookup_name: str = pool.alloc(128)
if lookup_name is None:
return None
viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, dunder)
@@ -5111,7 +5138,7 @@ class ExprGenMixin:
while mro_ptr is not None and mro_ptr[mi] != 0:
anc: str = (str | t.CPtr)(t.CVoid(mro_ptr[mi], t.CPtr))
if anc is not None:
parent_lookup: t.CChar | t.CPtr = pool.alloc(128)
parent_lookup: str = pool.alloc(128)
if parent_lookup is not None:
viperlib.snprintf(parent_lookup, 128, "%s.%s", anc, dunder)
parent_func: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, parent_lookup)
@@ -5259,10 +5286,11 @@ class ExprGenMixin:
# 常见触发场景:CDefine 常量查找失败返回指针 null,与另一指针做 `|`。
if lhs_bits == 0 and rhs_bits == 0:
if op == ast.OpKind.BitOr or op == ast.OpKind.BitAnd or op == ast.OpKind.BitXor or op == ast.OpKind.LShift or op == ast.OpKind.RShift:
VLogger.error(
# fail-fast:位运算操作数类型非法,立即终止编译(暴露上游根因)
HandlesType.fatal_error(
node,
"位运算操作数类型非法: lhs/rhs 均为非整数类型(指针或结构体),无法执行位运算",
"BinOp")
return None
"TypeError")
if op == ast.OpKind.Add:
return llvmlite.build_add(builder, lhs, rhs)
+61 -39
View File
@@ -67,7 +67,7 @@ class FuncGenMixin:
# ============================================================
def extract_func_attrs(self, pool: memhub.MemBuddy | t.CPtr,
decorator_list: list[ast.AST | t.CPtr] | t.CPtr,
imported_modules: str) -> t.CChar | t.CPtr:
imported_modules: str) -> str:
"""从 decorator_list 提取 c.Attribute 属性,返回 LLVM IR 属性字符串"""
if decorator_list is None:
return None
@@ -75,7 +75,7 @@ class FuncGenMixin:
if dn == 0:
return None
attrs_buf: t.CChar | t.CPtr = pool.alloc(256)
attrs_buf: str = pool.alloc(256)
if attrs_buf is None:
return None
attrs_buf[0] = '\0'
@@ -153,7 +153,7 @@ class FuncGenMixin:
return None
def _append_llvm_attr(self, attrs_buf: t.CChar | t.CPtr, attr_name: str) -> int:
def _append_llvm_attr(self, attrs_buf: str, attr_name: str) -> int:
"""将属性名映射到 LLVM 属性名并追加到缓冲区
返回 1 表示已追加,0 表示不支持该属性
@@ -191,7 +191,7 @@ class FuncGenMixin:
self._append_str(attrs_buf, llvm_name)
return 1
def _append_str(self, buf: t.CChar | t.CPtr, s: str,
def _append_str(self, buf: str, s: str,
max_len: t.CSizeT = 256) -> None:
"""将字符串追加到 buf 末尾(有界,防 strcpy 越界写穿定长缓冲)"""
if buf is None or s is None:
@@ -455,7 +455,7 @@ class FuncGenMixin:
param_ty = llvmlite.Ptr(pool, aelem_ty)
case _:
param_ty = resolved
pname: t.CChar | t.CPtr = pool.alloc(32)
pname: str = pool.alloc(32)
if pname is not None:
viperlib.snprintf(pname, 32, "%%%s", arg.arg)
llvmlite.add_param(pool, func, param_ty, pname)
@@ -589,6 +589,13 @@ class FuncGenMixin:
if arg_e.annotation is not None:
resolved_e: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
pool, arg_e.annotation, imported_modules, from_imports, trans)
if resolved_e is None:
# fail-fast:外部声明函数参数有注解但类型解析失败,
# 不再静默保持 i32(声明签名错误会在 ABI 层暴露)
HandlesType.fatal_error(
arg_e, f"参数 '{arg_e.arg}' 类型解析失败: {HandlesType.annotation_to_str(arg_e.annotation)}",
"NameError")
resolved_e = i32_ty # 不可达(fatal_error 已退出)
if resolved_e is not None:
# 裸类形参 → Ptr(struct)(对象即指针,与方法形参一致)
# CArray 形参 → 元素指针 ty*(C 数组衰减)
@@ -599,13 +606,13 @@ class FuncGenMixin:
param_ty_e = llvmlite.Ptr(pool, aelem_ty_e)
case _:
param_ty_e = resolved_e
pname_e: t.CChar | t.CPtr = pool.alloc(32)
pname_e: str = pool.alloc(32)
if pname_e is not None:
viperlib.snprintf(pname_e, 32, "%%%s", arg_e.arg)
llvmlite.add_param(pool, func, param_ty_e, pname_e)
# 提取 @c.Attribute 装饰器属性并设置到函数
func_attrs_e: t.CChar | t.CPtr = self.extract_func_attrs(pool, fd.decorator_list, imported_modules)
func_attrs_e: str = self.extract_func_attrs(pool, fd.decorator_list, imported_modules)
if func_attrs_e is not None:
llvmlite.function_set_attrs(func, func_attrs_e)
@@ -623,21 +630,21 @@ class FuncGenMixin:
# 复用前向声明:清除 IsDeclared 标记,转为 define
func.IsDeclared = 0
# 装饰器属性设置(前向声明时未设置)
func_attrs_reuse: t.CChar | t.CPtr = self.extract_func_attrs(pool, fd.decorator_list, imported_modules)
func_attrs_reuse: str = self.extract_func_attrs(pool, fd.decorator_list, imported_modules)
if func_attrs_reuse is not None:
llvmlite.function_set_attrs(func, func_attrs_reuse)
else:
# 创建新的 LLVM 函数(使用 SHA1 混淆名)
func = llvmlite.create_function(pool, mod, mangled_name, ret_ty)
if func is None:
fb_cf: t.CChar | t.CPtr = VLogger.fmt_buf()
fb_cf: str = VLogger.fmt_buf()
if fb_cf is not None:
viperlib.snprintf(fb_cf, 1024, "create_function %s failed", fd.name)
VLogger.error(fb_cf, "FUNC")
return 0
# 提取 @c.Attribute 装饰器属性并设置到函数
func_attrs: t.CChar | t.CPtr = self.extract_func_attrs(pool, fd.decorator_list, imported_modules)
func_attrs: str = self.extract_func_attrs(pool, fd.decorator_list, imported_modules)
if func_attrs is not None:
llvmlite.function_set_attrs(func, func_attrs)
@@ -691,7 +698,7 @@ class FuncGenMixin:
param_ty = llvmlite.Ptr(pool, aelem_ty)
case _:
param_ty = resolved
pname: t.CChar | t.CPtr = pool.alloc(32)
pname: str = pool.alloc(32)
if pname is not None:
viperlib.snprintf(pname, 32, "%%%s", arg.arg)
llvmlite.add_param(pool, func, param_ty, pname)
@@ -749,6 +756,12 @@ class FuncGenMixin:
if arg2.annotation is not None:
resolved2: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
pool, arg2.annotation, imported_modules, from_imports, trans)
if resolved2 is None:
# fail-fast:参数有注解但类型解析失败,不再静默保持 i32
HandlesType.fatal_error(
arg2, f"参数 '{arg2.arg}' 类型解析失败: {HandlesType.annotation_to_str(arg2.annotation)}",
"NameError")
resolved2 = i32_ty # 不可达(fatal_error 已退出)
if resolved2 is not None:
# 与 add_param 保持一致:裸类形参 → Ptr(struct)(对象即指针);
# CArray 形参 → 元素指针 ty*(数组衰减,alloca 类型须与形参一致,
@@ -771,7 +784,7 @@ class FuncGenMixin:
if cls_nm is not None:
HandlesVar.set_var_annot_class_name(
trans.SymTab, arg2.arg, cls_nm)
pname2: t.CChar | t.CPtr = pool.alloc(32)
pname2: str = pool.alloc(32)
if pname2 is not None:
viperlib.snprintf(pname2, 32, "%%%s", arg2.arg)
param_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(
@@ -933,7 +946,7 @@ class FuncGenMixin:
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
# 1. 构建提升后的函数名: __closure_{name}(加 SHA1 前缀避免跨模块冲突)
promoted_name: t.CChar | t.CPtr = pool.alloc(64)
promoted_name: str = pool.alloc(64)
if promoted_name is not None:
viperlib.snprintf(promoted_name, 64, "__closure_%s", func_name)
mangled_promoted: str = self._mangle_name(trans, promoted_name)
@@ -981,7 +994,7 @@ class FuncGenMixin:
pty_slot_n: str | t.CPtr = (t.CVoid | t.CPtr)(
t.CUInt64T(param_tys) + param_count * 8)
pty_slot_n[0] = pty_n
pname_n: t.CChar | t.CPtr = pool.alloc(32)
pname_n: str = pool.alloc(32)
if pname_n is not None:
viperlib.snprintf(pname_n, 32, "%%%s", arg_n.arg)
llvmlite.add_param(pool, func, pty_n, pname_n)
@@ -1039,7 +1052,7 @@ class FuncGenMixin:
if cls_nm_p is not None:
HandlesVar.set_var_annot_class_name(
trans.SymTab, arg_p.arg, cls_nm_p)
pname2_n: t.CChar | t.CPtr = pool.alloc(32)
pname2_n: str = pool.alloc(32)
if pname2_n is not None:
viperlib.snprintf(pname2_n, 32, "%%%s", arg_p.arg)
p_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, pty2_n, pname2_n)
@@ -1162,7 +1175,7 @@ class FuncGenMixin:
# 1. 优先查全局堆地址映射(_prepare_chain_nonlocals 已为
# 链内 nonlocal 建堆并 store 到 @nlheap.*;不同层捕获
# 不同变量时(ClosureTest2 Test 7)level2 的 b 经此共享)
gname_ck: t.CChar | t.CPtr = self._nl_heap_global_name(
gname_ck: str = self._nl_heap_global_name(
pool, trans, nl_name)
if gname_ck is not None \
and self._nl_heap_global_exists(mod, gname_ck) != 0:
@@ -1257,7 +1270,7 @@ class FuncGenMixin:
fn_func_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, fn_func_ty)
# 创建函数引用 Value(类型为 i32(i8*)*,使用 SHA1 混淆名)
fn_ptr_name: t.CChar | t.CPtr = pool.alloc(64)
fn_ptr_name: str = pool.alloc(64)
if fn_ptr_name is not None:
# SHA1 前缀名含 '.' 需要加引号(如 @"sha1.__closure_func")
if string.strchr(mangled_promoted, '.') is not None:
@@ -1348,12 +1361,12 @@ class FuncGenMixin:
# ============================================================
def _nl_heap_global_name(self, pool: memhub.MemBuddy | t.CPtr,
trans: HT.Translator | t.CPtr,
name: str) -> t.CChar | t.CPtr:
name: str) -> str:
"""构造 nonlocal 堆地址全局映射变量名 nlheap_{sha1}.{name}"""
if pool is None or trans is None or name is None:
return None
mangled: str = self._mangle_name(trans, name)
buf: t.CChar | t.CPtr = pool.alloc(160)
buf: str = pool.alloc(160)
if buf is not None:
viperlib.snprintf(buf, 160, "nlheap_%s", mangled)
return buf
@@ -1367,12 +1380,12 @@ class FuncGenMixin:
"""获取 nonlocal 堆地址全局映射变量的引用(@"..." 引号包裹)"""
if pool is None or trans is None or name is None:
return None
gname: t.CChar | t.CPtr = self._nl_heap_global_name(pool, trans, name)
gname: str = self._nl_heap_global_name(pool, trans, name)
if gname is None:
return None
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
ref_buf: t.CChar | t.CPtr = pool.alloc(176)
ref_buf: str = pool.alloc(176)
if ref_buf is None:
return None
viperlib.snprintf(ref_buf, 176, "@\"%s\"", gname)
@@ -1432,7 +1445,7 @@ class FuncGenMixin:
continue
dup: int = 0
for di in range(count):
if string.strcmp((t.CChar | t.CPtr)(
if string.strcmp((str)(
t.CUInt64T(names) + di * 8), nm_x.id) == 0:
dup = 1
break
@@ -1490,7 +1503,7 @@ class FuncGenMixin:
nl_ty: llvmlite.LLVMType | t.CPtr = local_alloca.Ty.Pointee
if nl_ty is None:
continue
gname: t.CChar | t.CPtr = self._nl_heap_global_name(pool, trans, nl_name)
gname: str = self._nl_heap_global_name(pool, trans, nl_name)
if gname is None:
continue
# 建堆(按类型字节大小)并拷贝当前值——每次本函数执行都新建共享堆,
@@ -1578,14 +1591,14 @@ class FuncGenMixin:
# _PreRegisterClassMembers fallback 崩溃(FuncGen.py L437)
lambda_id: int = trans._lambda_count
trans._lambda_count += 1
pname_buf: t.CChar | t.CPtr = pool.alloc(64)
pname_buf: str = pool.alloc(64)
if pname_buf is None:
return None
viperlib.snprintf(pname_buf, 64, "__lambda_%d", lambda_id)
mangled_promoted: str = self._mangle_name(trans, pname_buf)
# 2. 解析参数(名称 + 类型,类型默认 i32,有注解则解析)
param_names: t.CChar | t.CPtr = pool.alloc(32 * 64) # 64 参数 × 32 字节名
param_names: str = pool.alloc(32 * 64) # 64 参数 × 32 字节名
if param_names is None:
return None
string.memset(param_names, 0, 32 * 64)
@@ -1610,6 +1623,12 @@ class FuncGenMixin:
if arg_n.annotation is not None:
resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
pool, arg_n.annotation, trans._imported_modules, trans._from_imports, trans)
if resolved is None:
# fail-fast:lambda 参数有注解但类型解析失败,不再静默保持 i32
HandlesType.fatal_error(
arg_n, f"参数 '{arg_n.arg}' 类型解析失败: {HandlesType.annotation_to_str(arg_n.annotation)}",
"NameError")
resolved = i32_ty # 不可达(fatal_error 已退出)
if resolved is not None:
match resolved:
case llvmlite.LLVMType.Struct(_, _, _):
@@ -1624,7 +1643,7 @@ class FuncGenMixin:
param_count += 1
# 3. 收集捕获变量(body 中的外部 Name 引用)
cap_names: t.CChar | t.CPtr = pool.alloc(64 * 64) # 64 捕获 × 64 字节名
cap_names: str = pool.alloc(64 * 64) # 64 捕获 × 64 字节名
if cap_names is None:
return None
string.memset(cap_names, 0, 64 * 64)
@@ -1652,7 +1671,7 @@ class FuncGenMixin:
p_ty2: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(ty_slot2[0])
if p_ty2 is None:
p_ty2 = i32_ty
pname_l: t.CChar | t.CPtr = pool.alloc(32)
pname_l: str = pool.alloc(32)
if pname_l is not None:
viperlib.snprintf(pname_l, 32, "%%%s", param_names + pi2 * 32)
llvmlite.add_param(pool, func, p_ty2, pname_l)
@@ -1691,7 +1710,7 @@ class FuncGenMixin:
# 9. 捕获变量:从 env 堆槽加载值到局部 alloca
for ci in range(cap_count):
cap_addr: t.CUInt64T = t.CUInt64T(cap_names) + ci * 64
cap_slot: t.CChar | t.CPtr = (t.CChar | t.CPtr)(cap_addr)
cap_slot: str = (str)(cap_addr)
if cap_slot[0] == '\0':
continue
ty_addr3: t.CUInt64T = t.CUInt64T(cap_tys) + ci * 8
@@ -1727,8 +1746,11 @@ class FuncGenMixin:
ty_slot4: str | t.CPtr = (t.CVoid | t.CPtr)(ty_addr4)
p_ty3: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(ty_slot4[0])
if p_ty3 is None:
p_ty3 = i32_ty
pname_ref: t.CChar | t.CPtr = pool.alloc(32)
# fail-fast:lambda 参数类型槽缺失(内部状态不一致),不再静默保持 i32
HandlesType.fatal_error(
lam, f"lambda 参数 '{param_names + pi3 * 32}' 类型信息缺失", "InternalCompilerError")
p_ty3 = i32_ty # 不可达(fatal_error 已退出)
pname_ref: str = pool.alloc(32)
if pname_ref is not None:
viperlib.snprintf(pname_ref, 32, "%%%s", param_names + pi3 * 32)
param_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, p_ty3, pname_ref)
@@ -1750,11 +1772,11 @@ class FuncGenMixin:
if ret_val is not None:
llvmlite.build_ret(func_builder, ret_val)
else:
zero_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0)
llvmlite.build_ret(func_builder, zero_val)
# fail-fast:lambda 体类型转换失败,不再静默 ret 0
HandlesType.fatal_error(lam.body, "lambda 体表达式翻译失败", "TypeError")
else:
zero_val2: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0)
llvmlite.build_ret(func_builder, zero_val2)
# fail-fast:lambda 体翻译失败,不再静默 ret 0
HandlesType.fatal_error(lam.body, "lambda 体表达式翻译失败", "TypeError")
# 12. 退出 lambda 作用域,恢复父函数状态
HandlesVar.exit_scope(trans.SymTab)
@@ -1777,7 +1799,7 @@ class FuncGenMixin:
if env_ptr is not None:
for ci3 in range(cap_count):
cap_addr3: t.CUInt64T = t.CUInt64T(cap_names) + ci3 * 64
cap_slot3: t.CChar | t.CPtr = (t.CChar | t.CPtr)(cap_addr3)
cap_slot3: str = (str)(cap_addr3)
if cap_slot3[0] == '\0':
continue
al_addr: t.CUInt64T = t.CUInt64T(cap_allocas) + ci3 * 8
@@ -1832,7 +1854,7 @@ class FuncGenMixin:
fn_param_node: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, i8_ptr_ty)
fn_func_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func(pool, i32_ty, fn_param_node, 1)
fn_func_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, fn_func_ty)
fn_ptr_name: t.CChar | t.CPtr = pool.alloc(64)
fn_ptr_name: str = pool.alloc(64)
if fn_ptr_name is not None:
if string.strchr(mangled_promoted, '.') is not None:
viperlib.snprintf(fn_ptr_name, 64, "@\"%s\"", mangled_promoted)
@@ -1872,9 +1894,9 @@ class FuncGenMixin:
# ============================================================
def _lambda_scan_body(self, trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr,
param_names: t.CChar | t.CPtr,
param_names: str,
param_count: int,
cap_names: t.CChar | t.CPtr,
cap_names: str,
cap_allocas: t.CVoid | t.CPtr,
cap_tys: t.CVoid | t.CPtr,
cap_count: int) -> int:
@@ -2040,7 +2062,7 @@ class FuncGenMixin:
pool, arg.annotation, None, None, None)
if resolved is not None:
param_ty = resolved
pname: t.CChar | t.CPtr = pool.alloc(32)
pname: str = pool.alloc(32)
if pname is not None:
viperlib.snprintf(pname, 32, "%%%s", arg.arg)
llvmlite.add_param(pool, func, param_ty, pname)
+17 -10
View File
@@ -9,6 +9,7 @@ import stdio
import sys
import w32.fileio as fileio
import lib.core.StubMerger as StubMerger
import lib.core.Handles.HandlesType as HandlesType
# ============================================================
@@ -65,7 +66,7 @@ class ImportsGenMixin:
return imported_modules
if imported_modules is None:
nlen: t.CSizeT = string.strlen(name)
buf: t.CChar | t.CPtr = pool.alloc(nlen + 1)
buf: str = pool.alloc(nlen + 1)
if buf is not None:
string.strcpy(buf, name)
return buf
@@ -74,7 +75,7 @@ class ImportsGenMixin:
old_len: t.CSizeT = string.strlen(imported_modules)
name_len: t.CSizeT = string.strlen(name)
new_len: t.CSizeT = old_len + 1 + name_len
buf2: t.CChar | t.CPtr = pool.alloc(new_len + 1)
buf2: str = pool.alloc(new_len + 1)
if buf2 is not None:
string.strcpy(buf2, imported_modules)
buf2[old_len] = ' '
@@ -90,7 +91,7 @@ class ImportsGenMixin:
if name is None or imported_modules is None:
return 0
name_len: t.CSizeT = string.strlen(name)
cur: t.CChar | t.CPtr = imported_modules
cur: str = imported_modules
total_len: t.CSizeT = string.strlen(imported_modules)
ci: t.CSizeT = 0
while ci < total_len:
@@ -129,7 +130,7 @@ class ImportsGenMixin:
"""
if local_name is None or module_name is None:
return from_imports
entry: t.CChar | t.CPtr = pool.alloc(256)
entry: str = pool.alloc(256)
if entry is None:
return from_imports
if original_name is not None and string.strcmp(original_name, local_name) != 0:
@@ -142,7 +143,7 @@ class ImportsGenMixin:
old_len: t.CSizeT = string.strlen(from_imports)
entry_len: t.CSizeT = string.strlen(entry)
new_len: t.CSizeT = old_len + 1 + entry_len
buf: t.CChar | t.CPtr = pool.alloc(new_len + 1)
buf: str = pool.alloc(new_len + 1)
if buf is not None:
string.strcpy(buf, from_imports)
buf[old_len] = ' '
@@ -162,7 +163,7 @@ class ImportsGenMixin:
if local_name is None or from_imports is None:
return None
name_len: t.CSizeT = string.strlen(local_name)
cur: t.CChar | t.CPtr = from_imports
cur: str = from_imports
ci: t.CSizeT = 0
total_len: t.CSizeT = string.strlen(from_imports)
while ci < total_len:
@@ -236,7 +237,7 @@ class ImportsGenMixin:
if name is None or from_imports is None:
return None
name_len: t.CSizeT = string.strlen(name)
cur: t.CChar | t.CPtr = from_imports
cur: str = from_imports
ci: t.CSizeT = 0
total_len: t.CSizeT = string.strlen(from_imports)
star_mod: str = None
@@ -380,6 +381,8 @@ class ImportsGenMixin:
if level <= 0:
return module
if current_package is None:
# 相对导入但无当前包上下文:直接报错终止(fail-fast),暴露上游根因
HandlesType.fatal_error(None, f"相对导入解析失败:level={level} module='{module}'", "ImportError")
return module
# 从 current_package 开始,上溯 (level-1) 级
@@ -396,12 +399,14 @@ class ImportsGenMixin:
found = 1
i += 1
if found == 0:
# 无更多父级,包变为空
# 无更多父级(相对导入越界):直接报错终止(fail-fast)
HandlesType.fatal_error(None, f"相对导入解析失败:level={level} module='{module}'", "ImportError")
pkg = None
break
# 截断到最后一个 '.' 处
new_pkg: str = pool.alloc(last_dot + 1)
if new_pkg is None:
HandlesType.fatal_error(None, f"相对导入解析失败:level={level} module='{module}'", "ImportError")
return module
string.strncpy(new_pkg, pkg, last_dot)
new_pkg[last_dot] = '\0'
@@ -412,13 +417,15 @@ class ImportsGenMixin:
# from . import Y → 模块就是包本身
return pkg
if pkg is None:
# 包已上溯到空,直接用 module
# 包已上溯到空(相对导入越界):直接报错终止(fail-fast)
HandlesType.fatal_error(None, f"相对导入解析失败:level={level} module='{module}'", "ImportError")
return module
# 拼接 pkg + "." + module
pkg_len2: t.CSizeT = string.strlen(pkg)
mod_len: t.CSizeT = string.strlen(module)
buf: str = pool.alloc(pkg_len2 + 1 + mod_len + 1)
if buf is None:
HandlesType.fatal_error(None, f"相对导入解析失败:level={level} module='{module}'", "ImportError")
return module
string.strcpy(buf, pkg)
buf[pkg_len2] = '.'
@@ -612,7 +619,7 @@ class ImportsGenMixin:
# SHA1 在项目文件列表而非 includes 扫描存储器,不应报错)
if self._is_local_module_file(mod_name) != 0:
return 1
err_buf: t.CChar | t.CPtr = stdlib.malloc(256)
err_buf: str = stdlib.malloc(256)
if err_buf is not None:
viperlib.snprintf(err_buf, 256,
"模块 '%s' 未注册 SHA1(includes 扫描未找到该模块,请检查 project.json 的 includes 路径配置)",
+16 -13
View File
@@ -123,6 +123,8 @@ class StmtGenMixin:
return trans.MatchH.Handle(node)
elif k == ast.ASTKind.Delete:
return self.translate_delete(trans, node)
# 未知语句类型:直接报错终止(fail-fast),暴露上游解析问题
HandlesType.fatal_error(node, f"未知语句类型 kind={k}", "SyntaxError")
return 0
def translate_delete(self, trans: HT.Translator | t.CPtr,
@@ -194,12 +196,12 @@ class StmtGenMixin:
if var_alloca is not None and var_alloca.Ty is not None:
var_ty = var_alloca.Ty.Pointee
# Void 类型视为无效(Pointee 访问异常时可能返回 Void),
# 设为 None 让 add_nonlocal_name 回退为 i32,避免生成
# 类型无效直接报错终止(fail-fast),避免生成
# "bitcast ... to void*" / "load void, void*" 非法 IR
if var_ty is not None:
match var_ty:
case llvmlite.LLVMType.Void():
var_ty = None
HandlesType.fatal_error(nm_node, f"nonlocal 变量 '{nm.id}' 类型无效(Void/无法解析)", "TypeError")
case _:
pass
HT.add_nonlocal_name(trans, nm.id, var_ty)
@@ -225,7 +227,8 @@ class StmtGenMixin:
func_name: str = HandlesExpr.get_func_name(func_node)
if func_name is None:
return 0
# 函数名解析失败:直接报错终止(fail-fast)
HandlesType.fatal_error(call_node, "表达式语句的函数名解析失败", "SyntaxError")
# printf / print 走特殊路径(print 是类型感知格式化,不映射到 printf)
if string.strcmp(func_name, "printf") == 0:
@@ -276,7 +279,7 @@ class StmtGenMixin:
# 创建死代码 BB,用于后续语句(break 后面的代码不可达)
cnt: int = trans._label_counter
trans._label_counter = cnt + 1
name_buf: t.CChar | t.CPtr = pool.alloc(32)
name_buf: str = pool.alloc(32)
viperlib.snprintf(name_buf, 32, "dead.%d", cnt)
dead_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
llvmlite.position_at_end(builder, dead_bb)
@@ -299,7 +302,7 @@ class StmtGenMixin:
# 创建死代码 BB,用于后续语句
cnt: int = trans._label_counter
trans._label_counter = cnt + 1
name_buf: t.CChar | t.CPtr = pool.alloc(32)
name_buf: str = pool.alloc(32)
viperlib.snprintf(name_buf, 32, "dead.%d", cnt)
dead_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
llvmlite.position_at_end(builder, dead_bb)
@@ -846,8 +849,8 @@ class StmtGenMixin:
# 获取变量类型(从注册时存储的类型信息)
var_ty: llvmlite.LLVMType | t.CPtr = HT.get_nonlocal_type(trans, name)
if var_ty is None or self._is_void_type(var_ty) != 0:
# Void 类型视为无效(会导致 "load void, void*" 非法 IR),回退为 i32
var_ty = llvmlite.Int32(pool)
# 类型缺失/无效直接报错终止(fail-fast),避免生成 "load void, void*" 非法 IR
HandlesType.fatal_error(None, f"nonlocal 变量 '{name}' 类型缺失,无法 load", "TypeError")
# bitcast raw i8* to var_ty*
var_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, var_ty)
@@ -872,8 +875,8 @@ class StmtGenMixin:
# 获取变量类型
var_ty: llvmlite.LLVMType | t.CPtr = HT.get_nonlocal_type(trans, name)
if var_ty is None or self._is_void_type(var_ty) != 0:
# Void 类型视为无效(会导致 "bitcast ... to void*" 非法 IR),回退为 i32
var_ty = llvmlite.Int32(pool)
# 类型缺失/无效直接报错终止(fail-fast),避免生成 "bitcast ... to void*" 非法 IR
HandlesType.fatal_error(None, f"nonlocal 变量 '{name}' 类型缺失,无法 load", "TypeError")
# bitcast raw i8* to var_ty*
var_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, var_ty)
@@ -926,7 +929,7 @@ class StmtGenMixin:
return existing
if self.EnumCount >= ENUM_MAX:
fb_et: t.CChar | t.CPtr = VLogger.fmt_buf()
fb_et: str = VLogger.fmt_buf()
if fb_et is not None:
viperlib.snprintf(fb_et, 1024, "table full, cannot register %s", name)
VLogger.error(fb_et, "ENUM")
@@ -945,7 +948,7 @@ class StmtGenMixin:
# 复制类名
name_len: t.CSizeT = string.strlen(name)
name_buf: t.CChar | t.CPtr = pool.alloc(name_len + 1)
name_buf: str = pool.alloc(name_len + 1)
if name_buf is not None:
string.strcpy(name_buf, name)
entry.Name = name_buf
@@ -966,7 +969,7 @@ class StmtGenMixin:
return -1
if enum_entry.MemberCount >= ENUM_MEMBER_MAX:
fb_em: t.CChar | t.CPtr = VLogger.fmt_buf()
fb_em: str = VLogger.fmt_buf()
if fb_em is not None:
viperlib.snprintf(fb_em, 1024, "member table full for %s", enum_entry.Name)
VLogger.error(fb_em, "ENUM")
@@ -979,7 +982,7 @@ class StmtGenMixin:
# 复制成员名
name_len: t.CSizeT = string.strlen(member_name)
name_buf: t.CChar | t.CPtr = pool.alloc(name_len + 1)
name_buf: str = pool.alloc(name_len + 1)
if name_buf is not None:
string.strcpy(name_buf, member_name)
me.Name = name_buf
+17 -17
View File
@@ -172,7 +172,7 @@ class StructGenMixin:
return existing
if self.StructCount >= STRUCT_MAX:
fb_st: t.CChar | t.CPtr = VLogger.fmt_buf()
fb_st: str = VLogger.fmt_buf()
if fb_st is not None:
viperlib.snprintf(fb_st, 1024, "table full, cannot register %s", name)
VLogger.error(fb_st, "STRUCT")
@@ -197,7 +197,7 @@ class StructGenMixin:
# Name 越界读 → G3 LinkedNode.prepend 挂起根因。stdlib 分配不随
# pool reset 回收,多遍去重(Ty 比较)避免重复分配。)
name_len: t.CSizeT = string.strlen(name)
name_buf: t.CChar | t.CPtr = stdlib.malloc(name_len + 1)
name_buf: str = stdlib.malloc(name_len + 1)
if name_buf is not None:
string.strcpy(name_buf, name)
entry.Name = name_buf
@@ -209,7 +209,7 @@ class StructGenMixin:
# SHA1 同样统一 stdlib(跨 1a/1b 存活,防 strcmp 悬空)
if sha1 is not None:
sha1_len: t.CSizeT = string.strlen(sha1)
sha1_buf: t.CChar | t.CPtr = stdlib.malloc(sha1_len + 1)
sha1_buf: str = stdlib.malloc(sha1_len + 1)
if sha1_buf is not None:
string.strcpy(sha1_buf, sha1)
entry.ModuleSha1 = sha1_buf
@@ -227,7 +227,7 @@ class StructGenMixin:
return 0
# 复制 SHA1 字符串(统一 stdlib,跨 1a/1b 存活防 strcmp 悬空)
sha1_len: t.CSizeT = string.strlen(sha1)
sha1_buf: t.CChar | t.CPtr = stdlib.malloc(sha1_len + 1)
sha1_buf: str = stdlib.malloc(sha1_len + 1)
if sha1_buf is None:
return 0
string.strcpy(sha1_buf, sha1)
@@ -248,7 +248,7 @@ class StructGenMixin:
field_name: str,
field_ty: llvmlite.LLVMType | t.CPtr,
default_val: ast.AST | t.CPtr = None,
annot_class_name: t.CChar | t.CPtr = None) -> int:
annot_class_name: str = None) -> int:
"""向结构体添加字段,返回字段索引(-1 失败)
default_val: 字段默认值 AST 节点(可选,None=无默认值)
@@ -258,7 +258,7 @@ class StructGenMixin:
return -1
if struct_entry.FieldCount >= FIELD_MAX:
fb_sf: t.CChar | t.CPtr = VLogger.fmt_buf()
fb_sf: str = VLogger.fmt_buf()
if fb_sf is not None:
viperlib.snprintf(fb_sf, 1024, "field table full for %s", struct_entry.Name)
VLogger.error(fb_sf, "STRUCT")
@@ -273,7 +273,7 @@ class StructGenMixin:
# 否则 lookup_field 的 strcmp(fe.Name, ...) 读悬空越界挂起,
# 与 register_struct 的 Name 悬空同根因)
name_len: t.CSizeT = string.strlen(field_name)
name_buf: t.CChar | t.CPtr = stdlib.malloc(name_len + 1)
name_buf: str = stdlib.malloc(name_len + 1)
if name_buf is not None:
string.strcpy(name_buf, field_name)
fe.Name = name_buf
@@ -293,7 +293,7 @@ class StructGenMixin:
fe.Ty = field_ty
if annot_class_name is not None:
annot_len: t.CSizeT = string.strlen(annot_class_name)
annot_buf: t.CChar | t.CPtr = stdlib.malloc(annot_len + 1)
annot_buf: str = stdlib.malloc(annot_len + 1)
if annot_buf is not None:
string.strcpy(annot_buf, annot_class_name)
fe.AnnotClassName = annot_buf
@@ -346,7 +346,7 @@ class StructGenMixin:
dst_c.float_val = src_c.float_val
if src_c.str_val is not None:
s_len: t.CSizeT = string.strlen(src_c.str_val)
s_copy: t.CChar | t.CPtr = stdlib.malloc(s_len + 1)
s_copy: str = stdlib.malloc(s_len + 1)
if s_copy is not None:
string.strcpy(s_copy, src_c.str_val)
dst_c.str_val = s_copy
@@ -593,7 +593,7 @@ class StructGenMixin:
entry = self.find_struct(class_name)
if entry is None:
# 诊断:目标类未注册
fb_lfbc: t.CChar | t.CPtr = VLogger.fmt_buf()
fb_lfbc: str = VLogger.fmt_buf()
if fb_lfbc is not None:
viperlib.snprintf(fb_lfbc, 1024,
"lookup_field_by_class: 类 '%s' 未注册 (struct_count=%d)",
@@ -611,14 +611,14 @@ class StructGenMixin:
for fi in range(entry.FieldCount):
fe: HandlesStruct.FieldEntry | t.CPtr = self._get_field_entry(entry, fi)
if fe is not None:
fb_fn: t.CChar | t.CPtr = VLogger.fmt_buf()
fb_fn: str = VLogger.fmt_buf()
if fb_fn is not None:
if fe.Name is not None:
viperlib.snprintf(fb_fn, 1024, " 字段[%d]: '%s'", fi, fe.Name)
else:
viperlib.snprintf(fb_fn, 1024, " 字段[%d]: (null)", fi)
VLogger.warning(fb_fn, "STRUCT")
fb_fields: t.CChar | t.CPtr = VLogger.fmt_buf()
fb_fields: str = VLogger.fmt_buf()
if fb_fields is not None:
viperlib.snprintf(fb_fields, 1024,
"lookup_field_by_class: 类 '%s' 已注册 (FieldCount=%d) 但字段 '%s' 未找到",
@@ -795,7 +795,7 @@ class StructGenMixin:
# 构造 "SHA1.ClassName" 格式进行比较
entry2_sha1: str = entry2.ModuleSha1
if entry2_sha1 is not None:
full_nm: t.CChar | t.CPtr = pool.alloc(128)
full_nm: str = pool.alloc(128)
if full_nm is not None:
viperlib.snprintf(full_nm, 128, "%s.%s", entry2_sha1, entry2.Name)
if string.strcmp(full_nm, ty_name) == 0:
@@ -891,7 +891,7 @@ class StructGenMixin:
src: str = (str | t.CPtr)(t.CVoid(addr, t.CPtr))
if src is not None:
slen: t.CSizeT = string.strlen(src)
dup: t.CChar | t.CPtr = stdlib.malloc(slen + 1)
dup: str = stdlib.malloc(slen + 1)
if dup is not None:
string.strcpy(dup, src)
arr[i] = t.CSizeT(dup)
@@ -990,7 +990,7 @@ class StructGenMixin:
return None
return entry.ParentName
def set_vtable_methods(self, name: str, methods: t.CChar | t.CPtr, count: int) -> int:
def set_vtable_methods(self, name: str, methods: str, count: int) -> int:
"""设置虚表方法名数组,返回 1=成功 / 0=失败"""
if name is None:
return 0
@@ -1076,7 +1076,7 @@ class StructGenMixin:
case _:
pass
# 获取结构体名称(非 Struct 类型返回 None)
sname: t.CChar | t.CPtr = llvmlite.get_struct_name(ty)
sname: str = llvmlite.get_struct_name(ty)
if sname is None:
return
# 检查是否为跨模块引用(名称包含 '.')
@@ -1095,7 +1095,7 @@ class StructGenMixin:
total_len: t.CSizeT = string.strlen(sname)
class_name_len: t.CSizeT = string.strlen(class_name)
sha1_len: t.CSizeT = total_len - class_name_len - 1
sha1_buf: t.CChar | t.CPtr = pool.alloc(32)
sha1_buf: str = pool.alloc(32)
if sha1_buf is None:
return
# 32 字节缓冲:strncpy 不截断,前缀超过 31 字符会越界写 + 手动 NUL 再越界
+12 -11
View File
@@ -244,7 +244,7 @@ class TranslatorGenMixin:
# 按数组声明长度 arr_count 计算(元素不足时补零,可能多于 elts_count)
cnt_total: t.CSizeT = t.CSizeT(arr_count)
buf_size: t.CSizeT = 64 + cnt_total * 32
buf: t.CChar | t.CPtr = pool.alloc(buf_size)
buf: str = pool.alloc(buf_size)
if buf is None:
return None
@@ -298,7 +298,7 @@ class TranslatorGenMixin:
return None
# 构造内部字符串常量名称: .str.{var_name}
str_name_buf: t.CChar | t.CPtr = pool.alloc(64)
str_name_buf: str = pool.alloc(64)
if str_name_buf is None:
return None
viperlib.snprintf(str_name_buf, 64, ".str.%s", var_name)
@@ -311,7 +311,7 @@ class TranslatorGenMixin:
# 生成 GEP 初始化器文本
str_len: t.CSizeT = string.strlen(str_val)
init_buf: t.CChar | t.CPtr = pool.alloc(128)
init_buf: str = pool.alloc(128)
if init_buf is None:
return None
viperlib.snprintf(init_buf, 128,
@@ -437,7 +437,7 @@ class TranslatorGenMixin:
gv.Linkage = None
if init_kind == 1:
# 整数初始值
init_buf: t.CChar | t.CPtr = pool.alloc(48)
init_buf: str = pool.alloc(48)
if init_buf is not None:
viperlib.snprintf(init_buf, 48, "%lld", init_val)
gv.Initializer = init_buf
@@ -447,14 +447,16 @@ class TranslatorGenMixin:
if arr_init is not None:
gv.Initializer = arr_init
else:
gv.Initializer = "zeroinitializer"
# 初始化器构建失败:直接报错终止(fail-fast),不再回退 zeroinitializer
HandlesType.fatal_error(node, f"模块级变量 '{var_name}' 初始化器构建失败", "TypeError")
elif init_kind == 3:
# 字符串字面量 → 创建字符串常量全局 + GEP 引用
str_init: str = self._build_string_ptr_initializer(pool, mod, var_name, init_str_val)
if str_init is not None:
gv.Initializer = str_init
else:
gv.Initializer = "zeroinitializer"
# 初始化器构建失败:直接报错终止(fail-fast),不再回退 zeroinitializer
HandlesType.fatal_error(node, f"模块级变量 '{var_name}' 初始化器构建失败", "TypeError")
else:
# 使用 zeroinitializer 而非 "0":指针类型必须用 null/zeroinitializer,
# 整数/聚合类型也兼容 zeroinitializer,避免 "integer constant must have integer type"
@@ -462,7 +464,7 @@ class TranslatorGenMixin:
# 创建 Value 引用(@var_name, 类型为 var_ty*)
var_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, var_ty)
ref_name: t.CChar | t.CPtr = pool.alloc(64)
ref_name: str = pool.alloc(64)
if ref_name is not None:
viperlib.snprintf(ref_name, 64, "@%s", var_name)
gv_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, var_ptr_ty, ref_name)
@@ -641,12 +643,11 @@ class TranslatorGenMixin:
if trans._nonlocal_types is not None:
ty_addr2: t.CUInt64T = t.CUInt64T(trans._nonlocal_types) + trans._nonlocal_name_count * 8
ty_slot2: str | t.CPtr = (t.CVoid | t.CPtr)(ty_addr2)
# var_ty 为 None 时存入 i32 作为默认类型
# var_ty 为 None 时直接报错终止(fail-fast),不再默认 i32
stored_ty: llvmlite.LLVMType | t.CPtr = var_ty
if stored_ty is None:
pool: memhub.MemBuddy | t.CPtr = trans.Pool
if pool is not None:
stored_ty = llvmlite.Int32(pool)
HandlesType.fatal_error(None, f"nonlocal 变量 '{name}' 类型缺失,无法注册", "TypeError")
return
ty_slot2[0] = stored_ty
trans._nonlocal_name_count += 1
trans._closure_env_count += 1
+20 -16
View File
@@ -512,7 +512,7 @@ class TypeGenMixin:
self.ConstEvalOk = 1
return x_val
# 定位日志:跨模块 CDefine 查找失败(t.CArray count 场景)
fb_cdf: t.CChar | t.CPtr = VLogger.fmt_buf()
fb_cdf: str = VLogger.fmt_buf()
if fb_cdf is not None:
viperlib.snprintf(fb_cdf, 1024,
"[CDEF-MISS] name=%s fi=%s im=%s",
@@ -945,7 +945,7 @@ class TypeGenMixin:
type_name: str) -> llvmlite.LLVMType | t.CPtr:
"""将 t.CXxx / c.CXxx 类型名映射到 LLVMType
注意: t.CChar | t.CPtr = i8* = str = bytes
注意: str = i8* = str = bytes
"""
if type_name is None:
return None
@@ -995,7 +995,7 @@ class TypeGenMixin:
return llvmlite.Double(pool)
elif string.strcmp(type_name, "CFloat128T") == 0:
return llvmlite.FP128(pool)
# 指针/void: t.CPtr = i8*, t.CChar | t.CPtr = i8* = str = bytes
# 指针/void: t.CPtr = i8*, str = i8* = str = bytes
elif string.strcmp(type_name, "CPtr") == 0:
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
elif string.strcmp(type_name, "CVoid") == 0:
@@ -1316,7 +1316,7 @@ class TypeGenMixin:
if at.value is not None:
prefix: str = self.annotation_to_str(at.value)
if prefix is not None:
buf: t.CChar | t.CPtr = stdlib.malloc(
buf: str = stdlib.malloc(
string.strlen(prefix) + string.strlen(at.attr) + 2)
if buf is not None:
viperlib.snprintf(buf,
@@ -1330,7 +1330,7 @@ class TypeGenMixin:
sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(annot)
base: str = self.annotation_to_str(sub.value)
if base is not None:
buf2: t.CChar | t.CPtr = stdlib.malloc(string.strlen(base) + 5)
buf2: str = stdlib.malloc(string.strlen(base) + 5)
if buf2 is not None:
viperlib.snprintf(buf2, string.strlen(base) + 5,
"%s[...]", base)
@@ -1343,7 +1343,7 @@ class TypeGenMixin:
left_s: str = self.annotation_to_str(bo.left)
right_s: str = self.annotation_to_str(bo.right)
if left_s is not None and right_s is not None:
buf3: t.CChar | t.CPtr = stdlib.malloc(
buf3: str = stdlib.malloc(
string.strlen(left_s) + string.strlen(right_s) + 5)
if buf3 is not None:
viperlib.snprintf(buf3,
@@ -1420,7 +1420,7 @@ class TypeGenMixin:
if val_nm2.id is not None and string.strcmp(val_nm2.id, "t") == 0:
return at.attr
# 返回模块限定名 "module.Class"(如 "memhub.MemBuddy")
mod_qual_buf: t.CChar | t.CPtr = stdlib.malloc(
mod_qual_buf: str = stdlib.malloc(
string.strlen(val_nm2.id) + string.strlen(at.attr) + 2)
if mod_qual_buf is not None:
viperlib.snprintf(mod_qual_buf,
@@ -1699,7 +1699,7 @@ class TypeGenMixin:
gp_sub_node: ast.AST | t.CPtr = self._parse_type_string(pool, gp_ta, nm.ctx)
if gp_sub_node is not None:
return self.resolve_annotation_type(pool, gp_sub_node, imported_modules, from_imports, trans)
# str = bytes = t.CChar | t.CPtr = i8*
# str = bytes = str = i8*
if string.strcmp(nm.id, "str") == 0:
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
elif string.strcmp(nm.id, "int") == 0:
@@ -1910,8 +1910,12 @@ class TypeGenMixin:
other_cls_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(other_cls_nm)
if other_cls_ty is not None:
return llvmlite.Ptr(pool, other_cls_ty)
# CPtr 单独使用或其他无效类型 → i8*
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
# fail-fast:CPtr 标记下 other 侧类型完全无法解析,
# 不再静默退化为 i8*,暴露上游类型错误根因。
# (t.CVoid | t.CPtr → i8* 的合法语义分支在 other_is_cvoid 处已提前返回)
HandlesType.fatal_error(
node, f"联合类型 '{HandlesType.annotation_to_str(node)}' 中类型无法解析", "NameError")
return llvmlite.Ptr(pool, llvmlite.Int8(pool)) # 不可达(fatal_error 已退出)
return llvmlite.Ptr(pool, other_ty)
# 无 CPtr 标记:返回第一个非 None(装饰器标记如 CExport/CExtern 被忽略)
@@ -2123,13 +2127,13 @@ class TypeGenMixin:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node)
if nm.id is not None and param_types is not None:
# 在 param_types 中查找: "name:bits" 格式
search_key: t.CChar | t.CPtr = pool.alloc(64)
search_key: str = pool.alloc(64)
if search_key is not None:
viperlib.snprintf(search_key, 64, "%s:", nm.id)
found: t.CChar | t.CPtr = string.strstr(param_types, search_key)
found: str = string.strstr(param_types, search_key)
if found is not None:
colon_pos: t.CSizeT = string.strlen(nm.id) + 1
bits_str: t.CChar | t.CPtr = found + colon_pos
bits_str: str = found + colon_pos
bits: int = 0
for bi in range(4):
ch: t.CChar = bits_str[bi]
@@ -2196,7 +2200,7 @@ class TypeGenMixin:
return None
buf_size: t.CSizeT = an * 32 + 1
buf: t.CChar | t.CPtr = pool.alloc(buf_size)
buf: str = pool.alloc(buf_size)
if buf is None:
return None
buf[0] = '\0'
@@ -2217,7 +2221,7 @@ class TypeGenMixin:
bits: int = self.get_llvm_type_bits(param_ty)
if bits == 0:
bits = 32
tmp: t.CChar | t.CPtr = pool.alloc(32)
tmp: str = pool.alloc(32)
if tmp is not None:
viperlib.snprintf(tmp, 32, "%s:%d", arg.arg, bits)
if ai > 0:
@@ -2225,7 +2229,7 @@ class TypeGenMixin:
self._strappend(buf, buf_size, tmp)
return buf
def _strappend(self, dst: t.CChar | t.CPtr, dst_size: t.CSizeT, src: t.CChar | t.CPtr):
def _strappend(self, dst: str, dst_size: t.CSizeT, src: str):
"""将 src 追加到 dst 末尾"""
if dst is None or src is None:
return
+21 -9
View File
@@ -369,11 +369,11 @@ class AnnAssignHandle(HandlesBase.Mixin):
f"变量类型注解解析失败,变量名: {nm.id}",
"TypeError")
else:
# fast-fail: AnnAssign 必须有 annotation
VLogger.error(
# fail-fast: AnnAssign 必须有 annotation,缺少时立即终止(禁止兜底 i32)
HandlesType.fatal_error(
aa,
f"AnnAssign 缺少类型注解,变量名: {nm.id}",
"HandlesAnnAssign")
var_ty = llvmlite.Int32(pool)
"SyntaxError")
# 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间)
HandlesStruct.ensure_struct_def_in_module(pool, self.Trans.Module, var_ty)
@@ -441,11 +441,11 @@ class AnnAssignHandle(HandlesBase.Mixin):
f"变量类型注解解析失败,变量名: {nm.id}",
"TypeError")
else:
# fast-fail: AnnAssign 必须有 annotation
VLogger.error(
# fail-fast: AnnAssign 必须有 annotation,缺少时立即终止(禁止兜底 i32)
HandlesType.fatal_error(
aa,
f"AnnAssign 缺少类型注解,变量名: {nm.id}",
"HandlesAnnAssign")
var_ty = llvmlite.Int32(pool)
"SyntaxError")
# t.Callable 函数指针:注册返回类型签名(供函数指针间接调用精确返回类型)
callable_ret: llvmlite.LLVMType | t.CPtr = HandlesType.try_extract_callable_ret(
@@ -533,7 +533,11 @@ class AnnAssignHandle(HandlesBase.Mixin):
alloca: llvmlite.Value | t.CPtr = HandlesVar.get_or_create_sym(
self.Trans.SymTab, pool, builder, nm.id, var_ty)
if alloca is None:
return 0
# fail-fast: 存储创建失败,立即终止(禁止静默跳过)
HandlesType.fatal_error(
aa,
f"无法为变量 {nm.id} 创建存储",
"TypeError")
# 存储原始类型注解的类名(方法调用检测时,Ptr(i8) 回退到类名查找结构体)
if annot is not None:
cls_nm_hd: str = HandlesType.extract_class_name_from_annotation(
@@ -573,7 +577,10 @@ class AnnAssignHandle(HandlesBase.Mixin):
builder, pool, mod, alloca, aa.value, self.Trans)
else:
# 供 c.Deref(i8*) 推断读取宽度:v: int = c.Deref(p) → 读 i32
# CurAssignNode 记录 RHS 节点:translate_c_deref 据此判定 Deref
# 是否为赋值直接 RHS(对齐 TPC _infer_deref_target_type)。
self.Trans.CurAssignAnnot = aa.annotation
self.Trans.CurAssignNode = aa.value
rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, aa.value,
None, 0, self.Trans)
@@ -619,6 +626,11 @@ class AnnAssignHandle(HandlesBase.Mixin):
if target_ty is not None:
rhs_val = HandlesExpr.coerce_to_type(builder, rhs_val, target_ty, node)
llvmlite.build_store(builder, rhs_val, alloca)
# 清除赋值上下文(防残留):CurAssignAnnot/CurAssignNode 只在该
# AnnAssign 的 RHS 翻译期间有效,否则后续 while 条件/比较等处的
# c.Deref 会被残留注解误判读取宽度(i8* 被 bitcast i32* 读 4 字节)。
self.Trans.CurAssignAnnot = None
self.Trans.CurAssignNode = None
return 0
+35 -19
View File
@@ -60,13 +60,15 @@ class AssignHandle(HandlesBase.Mixin):
mod: llvmlite.LLVMModule | t.CPtr = self.Trans.Module
# 翻译 RHS 值
# 无注解赋值无目标类型可推断,清空 CurAssignAnnot(防残留误判 c.Deref 宽度)
# 无注解赋值无目标类型可推断,清空 CurAssignAnnot/CurAssignNode
# (防残留误判 c.Deref 宽度)
self.Trans.CurAssignAnnot = None
self.Trans.CurAssignNode = None
rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, asgn.value, None, 0, self.Trans)
if rhs_val is None:
# 增强错误信息:包含文件名 + lineno + AST 节点详情,便于定位
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = 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()
@@ -164,8 +166,11 @@ class AssignHandle(HandlesBase.Mixin):
break
fty: llvmlite.LLVMType | t.CPtr = llvmlite.paramnode_get_ty(fcur)
fcur = llvmlite.paramnode_get_next(fcur)
if fty is None:
# fail-fast: 字段类型缺失,立即终止
HandlesType.fatal_error(target, "元组解包字段类型缺失", "TypeError")
# 守卫:非 Name 元素无法解包,跳过
if fty is None or tgt_elt.kind() != ast.ASTKind.Name:
if tgt_elt.kind() != ast.ASTKind.Name:
continue
tgt_nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(tgt_elt)
if tgt_nm2.id is None:
@@ -203,9 +208,11 @@ class AssignHandle(HandlesBase.Mixin):
if sub_node is not None and sub_node.slice is not None:
list_idx_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, sub_node.slice, None, 0, self.Trans)
if list_idx_val is not None:
HandlesExpr.list_setitem_inline(
builder, pool, list_obj, list_idx_val, rhs_val, target)
if list_idx_val is None:
# fail-fast: list 下标翻译失败,立即终止
HandlesType.fatal_error(target, "list 下标翻译失败", "TypeError")
HandlesExpr.list_setitem_inline(
builder, pool, list_obj, list_idx_val, rhs_val, target)
continue
# 普通 Subscript 赋值
elem_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_subscript_ptr(
@@ -369,7 +376,7 @@ class AssignHandle(HandlesBase.Mixin):
if attr_node.value is not None and attr_node.value.kind() == ast.ASTKind.Name:
obj_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(attr_node.value)
obj_name = obj_nm.id
err_buf: t.CChar | t.CPtr = pool.alloc(256)
err_buf: str = pool.alloc(256)
if err_buf is not None:
viperlib.snprintf(err_buf, 256,
"attribute ptr is None: %s.%s",
@@ -390,7 +397,11 @@ class AssignHandle(HandlesBase.Mixin):
mod_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var(
self.Trans.SymTab, nm.id)
if mod_alloca is None:
continue
# fail-fast: global 变量未注册,无法赋值
HandlesType.fatal_error(
target,
f"global 变量 '{nm.id}' 未注册,无法赋值",
"NameError")
target_ty: llvmlite.LLVMType | t.CPtr = None
if mod_alloca.Ty is not None:
target_ty = mod_alloca.Ty.Pointee
@@ -404,18 +415,22 @@ class AssignHandle(HandlesBase.Mixin):
nl_ptr: llvmlite.Value | t.CPtr = HandlesNonlocal.get_nonlocal_var_ptr(
self.Trans, nm.id)
if nl_ptr is None:
continue
# fail-fast: nonlocal 变量指针解析失败
HandlesType.fatal_error(
target,
f"nonlocal 变量 '{nm.id}' 指针解析失败",
"NameError")
# 从 nl_ptr 的类型推断 nonlocal 变量实际类型,
# 不再强制 i32(会截断指针/结构体/i64 导致闭包数据损坏)
nl_target_ty: llvmlite.LLVMType | t.CPtr = None
if nl_ptr.Ty is not None:
nl_target_ty = nl_ptr.Ty.Pointee
if nl_target_ty is None:
# fast-fail: nl_ptr 类型信息丢失,无法安全 store
VLogger.error(
f"nonlocal 变量类型信息丢失,无法写入: {nm.id}",
"HandlesAssign")
continue
# fail-fast: nl_ptr 类型信息丢失,无法安全 store
HandlesType.fatal_error(
target,
f"nonlocal 变量 '{nm.id}' 类型信息丢失,无法写入",
"TypeError")
rhs_coerced: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(
builder, rhs_val, nl_target_ty, node)
llvmlite.build_store(builder, rhs_coerced, nl_ptr)
@@ -428,7 +443,7 @@ class AssignHandle(HandlesBase.Mixin):
mod_gv: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var(
self.Trans.SymTab, nm.id)
if mod_gv is not None:
fb_g: t.CChar | t.CPtr = VLogger.fmt_buf()
fb_g: str = VLogger.fmt_buf()
msg_g: str = "global 声明缺失"
if fb_g is not None:
viperlib.snprintf(fb_g, 1024, "变量 '%s' 是模块级全局变量,函数内赋值需用 global 声明(否则创建局部变量遮蔽全局,导致全局保持 null 崩溃)", nm.id)
@@ -457,10 +472,11 @@ class AssignHandle(HandlesBase.Mixin):
if existing is None:
new_vars += 1
else:
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "alloca failed for %s", nm.id)
VLogger.error(fb, "ASGN")
# fail-fast: 变量存储创建失败,立即终止
HandlesType.fatal_error(
target,
f"变量 '{nm.id}' 存储创建失败",
"TypeError")
return new_vars
+56 -48
View File
@@ -12,6 +12,7 @@ import lib.core.Handles.HandlesTranslator as HT
import lib.core.Handles.HandlesVar as HandlesVar
import lib.core.Handles.HandlesExpr as HandlesExpr
import lib.core.Handles.HandlesNonlocal as HandlesNonlocal
import lib.core.Handles.HandlesType as HandlesType
# ============================================================
@@ -78,40 +79,41 @@ class AugAssignHandle(HandlesBase.Mixin):
field_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_attribute_ptr(
builder, pool, mod, target, self.Trans)
if field_ptr is None:
VLogger.error("attribute ptr is None", "AUGASGN")
return 0
# fail-fast: 属性指针解析失败
HandlesType.fatal_error(target, "attribute ptr is None", "TypeError")
# 2. 确定字段类型并加载当前值
target_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
if field_ptr.Ty is not None:
target_ty: llvmlite.LLVMType | t.CPtr = None
if field_ptr.Ty is not None and field_ptr.Ty.Pointee is not None:
target_ty = field_ptr.Ty.Pointee
if target_ty is None:
# fail-fast: 字段类型信息缺失,禁止兜底 i32
HandlesType.fatal_error(target, "字段类型信息缺失", "TypeError")
cur_val: llvmlite.Value | t.CPtr = llvmlite.build_load(
builder, target_ty, field_ptr)
if cur_val is None:
VLogger.error("cannot load attribute", "AUGASGN")
return 0
# fail-fast: 属性当前值加载失败
HandlesType.fatal_error(target, "无法加载 attribute 当前值", "TypeError")
# 3. 翻译 RHS 值
rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, aug.value, None, 0, self.Trans)
if rhs_val is None:
VLogger.error("rhs is None", "AUGASGN")
return 0
# fail-fast: RHS 翻译失败
HandlesType.fatal_error(target, "rhs 翻译失败", "TypeError")
# 4. 应用二元运算
result: llvmlite.Value | t.CPtr = _apply_aug_op(
pool, builder, aug.op, cur_val, rhs_val, node, self.Trans, target)
if result is None:
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "binop failed for attr op=%d", aug.op)
VLogger.error(fb, "AUGASGN")
return 0
# fail-fast: attribute 二元运算失败
HandlesType.fatal_error(target, f"attribute 二元运算失败 op={aug.op}", "TypeError")
# 5. 类型对齐并存储
result = HandlesExpr.coerce_to_type(builder, result, target_ty, node)
if result is None:
return 0
# fail-fast: 类型对齐失败
HandlesType.fatal_error(target, "类型对齐失败", "TypeError")
llvmlite.build_store(builder, result, field_ptr)
return 0
@@ -126,46 +128,48 @@ class AugAssignHandle(HandlesBase.Mixin):
elem_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_subscript_ptr(
builder, pool, mod, target, self.Trans)
if elem_ptr is None:
VLogger.error("subscript ptr is None", "AUGASGN")
return 0
# fail-fast: 下标指针解析失败
HandlesType.fatal_error(target, "subscript ptr is None", "TypeError")
# 2. 确定元素类型并加载当前值
target_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
target_ty: llvmlite.LLVMType | t.CPtr = None
if elem_ptr.Ty is not None and elem_ptr.Ty.Pointee is not None:
target_ty = elem_ptr.Ty.Pointee
if target_ty is None:
# fail-fast: 元素类型信息缺失,禁止兜底 i32
HandlesType.fatal_error(target, "元素类型信息缺失", "TypeError")
cur_val: llvmlite.Value | t.CPtr = llvmlite.build_load(
builder, target_ty, elem_ptr)
if cur_val is None:
VLogger.error("cannot load subscript element", "AUGASGN")
return 0
# fail-fast: 元素当前值加载失败
HandlesType.fatal_error(target, "无法加载 subscript 元素当前值", "TypeError")
# 3. 翻译 RHS 值
rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, aug.value, None, 0, self.Trans)
if rhs_val is None:
VLogger.error("rhs is None", "AUGASGN")
return 0
# fail-fast: RHS 翻译失败
HandlesType.fatal_error(target, "rhs 翻译失败", "TypeError")
# 4. 应用二元运算
result: llvmlite.Value | t.CPtr = _apply_aug_op(
pool, builder, aug.op, cur_val, rhs_val, node, self.Trans, target)
if result is None:
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "binop failed for sub op=%d", aug.op)
VLogger.error(fb, "AUGASGN")
return 0
# fail-fast: subscript 二元运算失败
HandlesType.fatal_error(target, f"subscript 二元运算失败 op={aug.op}", "TypeError")
# 5. 类型对齐并存储
result = HandlesExpr.coerce_to_type(builder, result, target_ty, node)
if result is None:
return 0
# fail-fast: 类型对齐失败
HandlesType.fatal_error(target, "类型对齐失败", "TypeError")
llvmlite.build_store(builder, result, elem_ptr)
return 0
if tk != ast.ASTKind.Name:
VLogger.error("only Name/Attribute/Subscript target supported", "AUGASGN")
return 0
# fail-fast: 不支持的 AugAssign 目标类型
HandlesType.fatal_error(
target, "AugAssign 目标类型不支持,仅支持 Name/Attribute/Subscript", "TypeError")
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target)
if nm is None or nm.id is None:
@@ -174,7 +178,6 @@ class AugAssignHandle(HandlesBase.Mixin):
pool: memhub.MemBuddy | t.CPtr = self.Trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = self.Trans._cur_builder
mod: llvmlite.LLVMModule | t.CPtr = self.Trans.Module
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
# 1. 确定变量作用域类型: 0=local, 1=global, 2=nonlocal
scope_type: int = 0
@@ -186,15 +189,17 @@ class AugAssignHandle(HandlesBase.Mixin):
# 2. 加载当前值
cur_val: llvmlite.Value | t.CPtr = None
target_alloca: llvmlite.Value | t.CPtr = None
target_ty: llvmlite.LLVMType | t.CPtr = i32_ty
target_ty: llvmlite.LLVMType | t.CPtr = None
if scope_type == 1:
# global 变量
target_alloca = HandlesVar.lookup_module_var(
self.Trans.SymTab, nm.id)
if target_alloca is not None:
if target_alloca.Ty is not None:
target_ty = target_alloca.Ty.Pointee
if target_alloca.Ty is None:
# fail-fast: 变量类型信息缺失,禁止兜底 i32
HandlesType.fatal_error(target, "变量类型信息缺失", "TypeError")
target_ty = target_alloca.Ty.Pointee
cur_val = llvmlite.build_load(builder, target_ty, target_alloca)
elif scope_type == 2:
# nonlocal 变量(通过闭包 env)
@@ -205,39 +210,42 @@ class AugAssignHandle(HandlesBase.Mixin):
# 普通局部变量
target_alloca = HandlesVar.lookup_var(self.Trans.SymTab, nm.id)
if target_alloca is not None:
if target_alloca.Ty is not None:
target_ty = target_alloca.Ty.Pointee
if target_alloca.Ty is None:
# fail-fast: 变量类型信息缺失,禁止兜底 i32
HandlesType.fatal_error(target, "变量类型信息缺失", "TypeError")
target_ty = target_alloca.Ty.Pointee
cur_val = llvmlite.build_load(builder, target_ty, target_alloca)
if cur_val is None:
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "cannot load target %s", nm.id)
VLogger.error(fb, "AUGASGN")
return 0
# fail-fast: 目标变量当前值加载失败
HandlesType.fatal_error(
target,
f"无法加载目标变量 '{nm.id}' 的当前值",
"TypeError")
# 3. 翻译 RHS 值
rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, aug.value, None, 0, self.Trans)
if rhs_val is None:
VLogger.error("rhs is None", "AUGASGN")
return 0
# fail-fast: RHS 翻译失败
HandlesType.fatal_error(target, "rhs 翻译失败", "TypeError")
# 4. 类型对齐 + 应用二元运算
# 注意: AugAssign 不走运算符重载(语义上需要 __iadd__ 而非 __add__)
result: llvmlite.Value | t.CPtr = _apply_aug_op(
pool, builder, aug.op, cur_val, rhs_val, node, self.Trans, target)
if result is None:
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "binop failed for op=%d", aug.op)
VLogger.error(fb, "AUGASGN")
return 0
# fail-fast: 二元运算失败
HandlesType.fatal_error(
target,
f"对变量 '{nm.id}' 应用二元运算失败 op={aug.op}",
"TypeError")
# 5. 存储结果
result = HandlesExpr.coerce_to_type(builder, result, target_ty, node)
if result is None:
return 0
# fail-fast: 类型对齐失败
HandlesType.fatal_error(target, "类型对齐失败", "TypeError")
if scope_type == 1:
# global 变量
+1 -1
View File
@@ -147,7 +147,7 @@ def NewTypeRegistry(pool: memhub.MemBuddy | t.CPtr) -> TypeRegistry | t.CPtr:
# Returns:
# 写入的字符数(不含 NUL),失败返回 -1
# ============================================================
def TypeToLLVM(buf: t.CChar | t.CPtr, buf_size: t.CSizeT,
def TypeToLLVM(buf: str, buf_size: t.CSizeT,
ti: TypeInfo | t.CPtr) -> int:
if buf is None:
return -1
+7 -5
View File
@@ -946,8 +946,8 @@ VTBL_METHOD_MAX: t.CDefine = 32
# _vtable_strcat — 将 src 追加到 dst 末尾
def _vtable_strcat(dst: t.CChar | t.CPtr, dst_size: t.CSizeT,
src: t.CChar | t.CPtr):
def _vtable_strcat(dst: str, dst_size: t.CSizeT,
src: str):
"""将 src 追加到 dst 末尾(委托到 gen._vtable_strcat)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
@@ -970,7 +970,7 @@ def _vtable_name_needs_quote(name: str) -> int:
# 格式: ret_ty (param1_ty, param2_ty, ...)
# 例如: void ({i32, i32}*, i32)
def _format_func_type_str(pool: memhub.MemBuddy | t.CPtr,
buf: t.CChar | t.CPtr, buf_size: t.CSizeT,
buf: str, buf_size: t.CSizeT,
func: llvmlite.Function | t.CPtr) -> int:
"""从 Function 对象生成函数类型字符串(委托到 gen._format_func_type_str)"""
import lib.core.Gen.Generator as Generator
@@ -1056,16 +1056,18 @@ def _translate_oop_methods(trans: HT.Translator | t.CPtr,
cd: ast.ClassDef | t.CPtr,
struct_ty: llvmlite.LLVMType | t.CPtr,
class_name: str,
mark_only: int = 0) -> int:
mark_only: int = 0,
reemit: int = 0) -> int:
"""扫描 class body 中的方法并翻译,生成 __before_init__
mark_only: 0=全量翻译(默认),1=只设置 IsOOP/HasNew/HasInit 标志(不翻译方法体)
reemit: 1=补译模式(泛型特化 Phase B 补译调用,强制发射方法体)
(委托到 gen._translate_oop_methods)
"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g._translate_oop_methods(trans, cd, struct_ty, class_name, mark_only)
return g._translate_oop_methods(trans, cd, struct_ty, class_name, mark_only, reemit)
return 0
+2 -2
View File
@@ -35,7 +35,7 @@ ENUM_MEMBER_MAX: t.CDefine = 128
# ============================================================
@t.NoVTable
class EnumMember:
Name: t.CChar | t.CPtr # 成员名(字符串)
Name: str # 成员名(字符串)
Value: t.CInt64T # 成员的整数值
Ty: llvmlite.LLVMType | t.CPtr # 成员的 LLVM 类型(用于混用类型场景)
@@ -45,7 +45,7 @@ class EnumMember:
# ============================================================
@t.NoVTable
class EnumEntry:
Name: t.CChar | t.CPtr # 枚举类名
Name: str # 枚举类名
BaseTy: llvmlite.LLVMType | t.CPtr # 基准类型(所有成员类型中最大的)
MemberCount: int # 成员数量
Members: EnumMember | t.CPtr # 成员数组(ENUM_MEMBER_MAX 个槽位)
+1 -1
View File
@@ -76,7 +76,7 @@ def get_func_name(func_node: ast.AST | t.CPtr) -> str:
# 转义 LLVM IR 字符串字面量
# ============================================================
def escape_llvm_string(pool: memhub.MemBuddy | t.CPtr,
src: t.CChar | t.CPtr) -> t.CChar | t.CPtr:
src: str) -> str:
"""将字符串转换为 LLVM IR 字符串字面量 c"...\\00"(委托到 gen.escape_llvm_string)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
+7 -7
View File
@@ -388,8 +388,8 @@ class AsmOperand:
# ============================================================
# _asm_append_cstr — 将 C 字符串 src 追加到 dst 末尾
# ============================================================
def _asm_append_cstr(dst: t.CChar | t.CPtr, dst_size: t.CSizeT,
src: t.CChar | t.CPtr):
def _asm_append_cstr(dst: str, dst_size: t.CSizeT,
src: str):
"""将 C 字符串 src 追加到 dst 末尾(委托到 gen._asm_append_cstr)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
@@ -402,7 +402,7 @@ def _asm_append_cstr(dst: t.CChar | t.CPtr, dst_size: t.CSizeT,
# \n → \0A, " → \22, \ → \5C
# ============================================================
def _asm_escape_for_ir(pool: memhub.MemBuddy | t.CPtr,
src: t.CChar | t.CPtr) -> t.CChar | t.CPtr:
src: str) -> str:
"""转义汇编文本用于 LLVM IR 字符串字面量(委托到 gen._asm_escape_for_ir)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
@@ -704,7 +704,7 @@ def _ensure_method_declare(pool: memhub.MemBuddy | t.CPtr,
# _lookup_method_ret_ty_via_vpi - 从 vpi stub 返回注解缓存精确获取方法返回类型
#
# 方法定义处(.vpi stub)的返回注解(如 json.JsonValue._pool_alloc →
# "t.CChar | t.CPtr")在 stub 注入时由 VpiReader 缓存(_cache_vpi_return_annots_text)。
# "str")在 stub 注入时由 VpiReader 缓存(_cache_vpi_return_annots_text)。
# 此函数按 模块SHA1 + 类名 + 方法名 查缓存并纯字符串解析为 LLVMType。
# 无需硬编码白名单——返回类型始终来自方法定义处。
# ============================================================
@@ -1018,7 +1018,7 @@ def _translate_method_call(pool: memhub.MemBuddy | t.CPtr,
# 跳过 % 前缀后逐字符比较
# ============================================================
def _kwarg_name_matches(kw_arg: str,
param_name: t.CChar | t.CPtr) -> int:
param_name: str) -> int:
"""检查关键字参数名 kw_arg 是否匹配参数名 param_name(跳过 % 前缀)(委托到 gen._kwarg_name_matches)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
@@ -1516,7 +1516,7 @@ class FuncEntry:
# TypeStr: 函数类型文本(stdlib 深拷贝,跨文件安全)
# 1b 每文件 reset_to(mark1) 回收 pool 内 Function 对象后,
# vtable 生成 find_func_global 读类型改用此文本,避免悬空。
TypeStr: t.CChar | t.CPtr
TypeStr: str
# ============================================================
# 初始化函数表
@@ -1587,7 +1587,7 @@ def _init_global_func_table() -> int:
# 用 stdlib.malloc 分配返回,跨文件永久存活(1b reset 不回收)。
# 返回 None 表示失败。
def _build_func_type_str(pool: memhub.MemBuddy | t.CPtr,
func: llvmlite.Function | t.CPtr) -> t.CChar | t.CPtr:
func: llvmlite.Function | t.CPtr) -> str:
"""生成函数类型文本(stdlib 分配)(委托到 gen._build_func_type_str)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
+49 -28
View File
@@ -123,7 +123,7 @@ class ForHandle(HandlesBase.Mixin):
elif string.strcmp(fn_pre, "enumerate") == 0 or string.strcmp(fn_pre, "zip") == 0:
pass # 多变量迭代,在下方非 range 分支处理
else:
err_msg: t.CChar | t.CPtr = pool.alloc(256)
err_msg: str = pool.alloc(256)
if err_msg is not None:
viperlib.snprintf(err_msg, 256, "仅支持 range()/enumerate()/zip() 或指针迭代,got call '%s'", fn_pre)
HandlesType.fatal_error(iter_node, err_msg)
@@ -215,28 +215,36 @@ class ForHandle(HandlesBase.Mixin):
stop_val: llvmlite.Value | t.CPtr = None
step_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 1)
if arg_count == 1:
if arg_count == 0:
# fail-fast: range 无参数,立即终止
HandlesType.fatal_error(call, "range 需要至少一个参数", "SyntaxError")
elif arg_count == 1:
stop_val = HandlesExpr.translate_value(
builder, pool, trans.Module, args.get(0),
trans._funcs, trans._func_count, trans)
if stop_val is None:
# fail-fast: range 参数翻译失败
HandlesType.fatal_error(args.get(0), "range 参数翻译失败", "TypeError")
elif arg_count >= 2:
start_val = HandlesExpr.translate_value(
builder, pool, trans.Module, args.get(0),
trans._funcs, trans._func_count, trans)
if start_val is None:
# fail-fast: range 参数翻译失败
HandlesType.fatal_error(args.get(0), "range 参数翻译失败", "TypeError")
stop_val = HandlesExpr.translate_value(
builder, pool, trans.Module, args.get(1),
trans._funcs, trans._func_count, trans)
if stop_val is None:
# fail-fast: range 参数翻译失败
HandlesType.fatal_error(args.get(1), "range 参数翻译失败", "TypeError")
if arg_count >= 3:
step_val = HandlesExpr.translate_value(
builder, pool, trans.Module, args.get(2),
trans._funcs, trans._func_count, trans)
if stop_val is None:
stop_val = llvmlite.const_int32(pool, 0)
if start_val is None:
start_val = llvmlite.const_int32(pool, 0)
if step_val is None:
step_val = llvmlite.const_int32(pool, 1)
if step_val is None:
# fail-fast: range 参数翻译失败
HandlesType.fatal_error(args.get(2), "range 参数翻译失败", "TypeError")
# 4. 创建/查找循环变量 alloca
var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
@@ -274,7 +282,7 @@ class ForHandle(HandlesBase.Mixin):
cnt: int = trans._label_counter
trans._label_counter = cnt + 1
name_buf: t.CChar | t.CPtr = pool.alloc(32)
name_buf: str = pool.alloc(32)
viperlib.snprintf(name_buf, 32, "for.cond.%d", cnt)
cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
@@ -436,7 +444,7 @@ class ForHandle(HandlesBase.Mixin):
cnt: int = trans._label_counter
trans._label_counter = cnt + 1
name_buf: t.CChar | t.CPtr = pool.alloc(32)
name_buf: str = pool.alloc(32)
viperlib.snprintf(name_buf, 32, "ptr.cond.%d", cnt)
cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
@@ -571,7 +579,7 @@ class ForHandle(HandlesBase.Mixin):
cnt: int = trans._label_counter
trans._label_counter = cnt + 1
name_buf: t.CChar | t.CPtr = pool.alloc(32)
name_buf: str = pool.alloc(32)
viperlib.snprintf(name_buf, 32, "arr.cond.%d", cnt)
cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
@@ -759,7 +767,7 @@ class ForHandle(HandlesBase.Mixin):
cnt: int = trans._label_counter
trans._label_counter = cnt + 1
name_buf: t.CChar | t.CPtr = pool.alloc(32)
name_buf: str = pool.alloc(32)
viperlib.snprintf(name_buf, 32, "lst.cond.%d", cnt)
cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
@@ -870,7 +878,7 @@ class ForHandle(HandlesBase.Mixin):
cnt: int = trans._label_counter
trans._label_counter = cnt + 1
name_buf: t.CChar | t.CPtr = pool.alloc(32)
name_buf: str = pool.alloc(32)
viperlib.snprintf(name_buf, 32, "dict.cond.%d", cnt)
cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
@@ -1009,7 +1017,8 @@ class ForHandle(HandlesBase.Mixin):
call: ast.Call | t.CPtr) -> int:
"""zip 迭代: for a, b in zip(x, y)"""
if call is None or call.args is None:
return 0
# fail-fast: zip 参数缺失
HandlesType.fatal_error(call, "zip 参数缺失", "SyntaxError")
cargs: list[ast.AST | t.CPtr] | t.CPtr = call.args
if len(cargs) < 2:
HandlesType.fatal_error(for_node, "zip 需要至少两个参数")
@@ -1061,20 +1070,26 @@ class ForHandle(HandlesBase.Mixin):
sv: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, trans.Module, cargs1.get(0),
trans._funcs, trans._func_count, trans)
if sv is not None:
r1_stop = HandlesExpr.coerce_to_type(builder, sv, i64_ty, cargs1.get(0))
if sv is None:
# fail-fast: range 参数翻译失败
HandlesType.fatal_error(cargs1.get(0), "range 参数翻译失败", "TypeError")
r1_stop = HandlesExpr.coerce_to_type(builder, sv, i64_ty, cargs1.get(0))
if n1 >= 2:
sv2: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, trans.Module, cargs1.get(1),
trans._funcs, trans._func_count, trans)
if sv2 is not None:
r1_start = HandlesExpr.coerce_to_type(builder, sv2, i64_ty, cargs1.get(1))
if sv2 is None:
# fail-fast: range 参数翻译失败
HandlesType.fatal_error(cargs1.get(1), "range 参数翻译失败", "TypeError")
r1_start = HandlesExpr.coerce_to_type(builder, sv2, i64_ty, cargs1.get(1))
if n1 >= 3:
sv3: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, trans.Module, cargs1.get(2),
trans._funcs, trans._func_count, trans)
if sv3 is not None:
r1_step = HandlesExpr.coerce_to_type(builder, sv3, i64_ty, cargs1.get(2))
if sv3 is None:
# fail-fast: range 参数翻译失败
HandlesType.fatal_error(cargs1.get(2), "range 参数翻译失败", "TypeError")
r1_step = HandlesExpr.coerce_to_type(builder, sv3, i64_ty, cargs1.get(2))
elif kind1 == SEQ_KIND_STR:
elem1_ty = i8_ty
s1_ptr = HandlesExpr.translate_value(
@@ -1125,20 +1140,26 @@ class ForHandle(HandlesBase.Mixin):
svz: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, trans.Module, cargs2.get(0),
trans._funcs, trans._func_count, trans)
if svz is not None:
r2_stop = HandlesExpr.coerce_to_type(builder, svz, i64_ty, cargs2.get(0))
if svz is None:
# fail-fast: range 参数翻译失败
HandlesType.fatal_error(cargs2.get(0), "range 参数翻译失败", "TypeError")
r2_stop = HandlesExpr.coerce_to_type(builder, svz, i64_ty, cargs2.get(0))
if n2 >= 2:
svz2: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, trans.Module, cargs2.get(1),
trans._funcs, trans._func_count, trans)
if svz2 is not None:
r2_start = HandlesExpr.coerce_to_type(builder, svz2, i64_ty, cargs2.get(1))
if svz2 is None:
# fail-fast: range 参数翻译失败
HandlesType.fatal_error(cargs2.get(1), "range 参数翻译失败", "TypeError")
r2_start = HandlesExpr.coerce_to_type(builder, svz2, i64_ty, cargs2.get(1))
if n2 >= 3:
svz3: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, trans.Module, cargs2.get(2),
trans._funcs, trans._func_count, trans)
if svz3 is not None:
r2_step = HandlesExpr.coerce_to_type(builder, svz3, i64_ty, cargs2.get(2))
if svz3 is None:
# fail-fast: range 参数翻译失败
HandlesType.fatal_error(cargs2.get(2), "range 参数翻译失败", "TypeError")
r2_step = HandlesExpr.coerce_to_type(builder, svz3, i64_ty, cargs2.get(2))
elif kind2 == SEQ_KIND_STR:
elem2_ty = i8_ty
s2_ptr = HandlesExpr.translate_value(
@@ -1189,7 +1210,7 @@ class ForHandle(HandlesBase.Mixin):
cnt: int = trans._label_counter
trans._label_counter = cnt + 1
name_buf: t.CChar | t.CPtr = pool.alloc(32)
name_buf: str = pool.alloc(32)
viperlib.snprintf(name_buf, 32, "seq.cond.%d", cnt)
cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
+3 -3
View File
@@ -57,7 +57,7 @@ SCOPE_FUNCTION: t.CDefine = 1
def extract_func_attrs(pool: memhub.MemBuddy | t.CPtr,
decorator_list: list[ast.AST | t.CPtr] | t.CPtr,
imported_modules: str) -> t.CChar | t.CPtr:
imported_modules: str) -> str:
"""从 decorator_list 提取 c.Attribute 属性,返回 LLVM IR 属性字符串(委托到 gen.extract_func_attrs)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
@@ -75,7 +75,7 @@ def _get_attr_name_from_node(node: ast.AST | t.CPtr) -> str:
return None
def _append_llvm_attr(attrs_buf: t.CChar | t.CPtr, attr_name: str) -> int:
def _append_llvm_attr(attrs_buf: str, attr_name: str) -> int:
"""将属性名映射到 LLVM 属性名并追加到缓冲区(委托到 gen._append_llvm_attr)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
@@ -84,7 +84,7 @@ def _append_llvm_attr(attrs_buf: t.CChar | t.CPtr, attr_name: str) -> int:
return 0
def _append_str(buf: t.CChar | t.CPtr, s: str) -> None:
def _append_str(buf: str, s: str) -> None:
"""将字符串追加到 buf 末尾(用 strlen+strcpy 模拟 strcat)(委托到 gen._append_str)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
+3 -2
View File
@@ -245,7 +245,8 @@ class IfHandle(HandlesBase.Mixin):
# 2. 转换为 i1 条件
# Compare/Not 表达式已返回 i1,直接使用;指针类型与 null 比较;其他类型与 0 比较
if cond_val is None:
cond_val = llvmlite.const_int32(pool, 0)
# fail-fast: if 条件表达式翻译失败
HandlesType.fatal_error(if_node.test, "if 条件表达式翻译失败", "TypeError")
cond_bits: int = HandlesExpr.get_llvm_type_bits(cond_val.Ty)
if cond_bits == 1:
cond_i1: llvmlite.Value | t.CPtr = cond_val
@@ -263,7 +264,7 @@ class IfHandle(HandlesBase.Mixin):
cnt: int = trans._label_counter
trans._label_counter = cnt + 1
name_buf: t.CChar | t.CPtr = pool.alloc(32)
name_buf: str = pool.alloc(32)
viperlib.snprintf(name_buf, 32, "if.then.%d", cnt)
then_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
+1 -1
View File
@@ -19,7 +19,7 @@ import lib.core.StubMerger as StubMerger
# HandlesImports - 导入语句处理(P6-D 对象化后的委托层)
#
# 管理 _imported_modules 和 _from_imports 字符串
# 注意:str = bytes = t.CChar | t.CPtr = i8*
# 注意:str = bytes = str = i8*
#
# P6-D 对象化重构(wiki/14-oo-refactor.md):
# 全部模块级函数已迁移为 lib.core.Gen.ImportsGenMixin 的方法
+1 -1
View File
@@ -26,7 +26,7 @@ import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign
# 2. translate_children() - 遍历 AST 子节点并分派翻译
#
# trans 单参模式:所有共享状态从 trans 获取,无需 11 个参数
# 注意: str = bytes = t.CChar | t.CPtr = i8*
# 注意: str = bytes = str = i8*
#
# P6-E 对象化重构:全部函数已迁移为 lib.core.Gen.TranslatorGenMixin
# 的方法,本模块保留同名模块级函数作为"一行委托"(同 P2-P5 模式):
+47 -21
View File
@@ -12,6 +12,7 @@ import lib.core.Handles.HandlesBody as HandlesBody
import lib.core.Handles.HandlesVar as HandlesVar
import lib.core.Handles.HandlesClassDef as HandlesClassDef
import lib.core.Handles.HandlesStruct as HandlesStruct
import lib.core.Handles.HandlesType as HandlesType
# ============================================================
@@ -89,7 +90,8 @@ class MatchHandle(HandlesBase.Mixin):
builder, pool, trans.Module, subject_node,
trans._funcs, trans._func_count, trans)
if subject_val is None:
return 0
# fail-fast: match subject 翻译失败
HandlesType.fatal_error(subject_node, "match subject 翻译失败", "TypeError")
# 2. 检测是否 REnum match
is_renum: int = 0
@@ -274,8 +276,11 @@ class MatchHandle(HandlesBase.Mixin):
if renum_se is not None:
renum_sty = renum_se.Ty
if renum_sty is None:
# 找不到结构体类型时无法构造,直接放弃 REnum 路径
return 0
# fail-fast: REnum 结构体未注册,无法构造
HandlesType.fatal_error(
node,
f"REnum 结构体 '{renum_name}' 未注册",
"NameError")
i64_ty0: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
int_val: llvmlite.Value | t.CPtr = subject_ptr
# 非 i64 整数值先扩展/截断到 i64(inttoptr 要求同宽)
@@ -298,18 +303,21 @@ class MatchHandle(HandlesBase.Mixin):
tag_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
builder, subject_ptr, i32_ptr_ty)
if tag_ptr is None:
return 0
# fail-fast: REnum tag 指针转换失败
HandlesType.fatal_error(node, "REnum tag 指针转换失败", "TypeError")
tag_val: llvmlite.Value | t.CPtr = llvmlite.build_load(
builder, i32_ty, tag_ptr)
if tag_val is None:
return 0
# fail-fast: REnum tag 读取失败
HandlesType.fatal_error(node, "REnum tag 读取失败", "TypeError")
# 2. 创建 default/end BB
cnt: int = trans._label_counter
trans._label_counter = cnt + 1
name_buf: t.CChar | t.CPtr = pool.alloc(32)
name_buf: str = pool.alloc(32)
if name_buf is None:
return 0
# fail-fast: 标签缓冲区分配失败
HandlesType.fatal_error(node, "标签缓冲区分配失败", "TypeError")
viperlib.snprintf(name_buf, 32, "match.default.%d", cnt)
default_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(
pool, func, name_buf)
@@ -320,7 +328,8 @@ class MatchHandle(HandlesBase.Mixin):
# 3. 准备收集数组(用 CSizeT 数组存指针)
cases_list: list[ast.AST | t.CPtr] | t.CPtr = node.cases
if cases_list is None:
return 0
# fail-fast: match cases 缺失
HandlesType.fatal_error(node, "match cases 缺失", "TypeError")
case_count: t.CSizeT = len(cases_list)
# BB 指针数组、case 值指针数组、default 标记数组、nobreak 标记数组
@@ -329,7 +338,8 @@ class MatchHandle(HandlesBase.Mixin):
def_arr: t.CInt | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES)
nb_arr: t.CInt | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES)
if bb_arr is None or cv_arr is None or def_arr is None or nb_arr is None:
return 0
# fail-fast: match 分派数组分配失败
HandlesType.fatal_error(node, "match 分派数组分配失败", "TypeError")
collected: int = 0
has_default: int = 0
@@ -363,7 +373,7 @@ class MatchHandle(HandlesBase.Mixin):
tag: int = HandlesClassDef._lookup_renum_variant_in_class(
renum_name, vnm)
if tag >= 0:
tag_buf: t.CChar | t.CPtr = pool.alloc(32)
tag_buf: str = pool.alloc(32)
if tag_buf is not None:
viperlib.snprintf(tag_buf, 32, "%d", tag)
cv = llvmlite.ConstInt(pool, i32_ty, tag,
@@ -574,8 +584,11 @@ class MatchHandle(HandlesBase.Mixin):
if alt_idx >= 1:
payload_idx = alt_idx
else:
j = j + 1
continue
# fail-fast: payload 越界且别名查找失败
HandlesType.fatal_error(
node,
f"REnum 变体字段 '{bind_name}' 在结构体 '{renum_name}' 中越界且别名查找失败",
"TypeError")
# 获取字段类型
fe: HandlesStruct.FieldEntry | t.CPtr = (
HandlesStruct._get_field_entry(
@@ -584,15 +597,24 @@ class MatchHandle(HandlesBase.Mixin):
if fe is not None:
field_ty = fe.Ty
if field_ty is None:
field_ty = llvmlite.Int8(pool)
# fail-fast: 变体字段类型缺失,禁止兜底 i8
HandlesType.fatal_error(
sub_pat,
f"REnum 变体字段类型缺失: {bind_name}",
"TypeError")
# GEP 取字段地址
elem_ptr: llvmlite.Value | t.CPtr = (
llvmlite.build_gep_struct(
builder, renum_ty, field_ty,
casted_ptr, payload_idx))
if elem_ptr is not None:
HandlesVar.define_var(
trans.SymTab, bind_name, elem_ptr)
if elem_ptr is None:
# fail-fast: 变体字段地址计算失败
HandlesType.fatal_error(
sub_pat,
f"REnum 变体字段 '{bind_name}' 地址计算失败",
"TypeError")
HandlesVar.define_var(
trans.SymTab, bind_name, elem_ptr)
j = j + 1
# ============================================================
@@ -621,14 +643,16 @@ class MatchHandle(HandlesBase.Mixin):
# 未知类型,尝试 ptrtoint
subj_val = llvmlite.build_ptrtoint(builder, subject_val, i32_ty)
if subj_val is None:
return 0
# fail-fast: subject 转 i32 失败
HandlesType.fatal_error(node, "match subject 转换为 i32 失败", "TypeError")
# 2. 创建 default/end BB
cnt: int = trans._label_counter
trans._label_counter = cnt + 1
name_buf: t.CChar | t.CPtr = pool.alloc(32)
name_buf: str = pool.alloc(32)
if name_buf is None:
return 0
# fail-fast: 标签缓冲区分配失败
HandlesType.fatal_error(node, "标签缓冲区分配失败", "TypeError")
viperlib.snprintf(name_buf, 32, "match.default.%d", cnt)
default_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(
pool, func, name_buf)
@@ -639,7 +663,8 @@ class MatchHandle(HandlesBase.Mixin):
# 3. 收集 case 信息
cases_list: list[ast.AST | t.CPtr] | t.CPtr = node.cases
if cases_list is None:
return 0
# fail-fast: match cases 缺失
HandlesType.fatal_error(node, "match cases 缺失", "TypeError")
case_count: t.CSizeT = len(cases_list)
bb_arr: t.CSizeT | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES)
@@ -647,7 +672,8 @@ class MatchHandle(HandlesBase.Mixin):
def_arr: t.CInt | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES)
nb_arr: t.CInt | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES)
if bb_arr is None or cv_arr is None or def_arr is None or nb_arr is None:
return 0
# fail-fast: match 分派数组分配失败
HandlesType.fatal_error(node, "match 分派数组分配失败", "TypeError")
collected: int = 0
has_default: int = 0
+8 -1
View File
@@ -8,6 +8,7 @@ import lib.core.Handles.HandlesBase as HandlesBase
import lib.core.Handles.HandlesTranslator as HT
import lib.core.Handles.HandlesExpr as HandlesExpr
import lib.core.Handles.HandlesVar as HandlesVar
import lib.core.Handles.HandlesType as HandlesType
# ============================================================
@@ -175,7 +176,13 @@ class ReturnHandle(HandlesBase.Mixin):
zero_f: llvmlite.Value | t.CPtr = llvmlite.ConstFloat(pool, ret_ty, 0.0)
llvmlite.build_ret(builder, zero_f)
return 0
val = llvmlite.const_int32(pool, 0)
if ret_ty is None:
# fail-fast: 裸 return 无法确定函数返回类型,禁止硬编码 i32 零值兜底
HandlesType.fatal_error(rt, "函数返回类型无法确定", "TypeError")
val = llvmlite.ConstZero(pool, ret_ty)
if val is None:
# fail-fast: 无法按返回类型构造零值
HandlesType.fatal_error(rt, "函数返回类型无法确定", "TypeError")
# 类型转换:确保 val 类型与函数返回类型匹配
# 处理 i1(bool 比较结果)→ i8(t.CBool)等情况
+8 -8
View File
@@ -41,11 +41,11 @@ MRO_MAX: t.CDefine = 16
# ============================================================
@t.NoVTable
class FieldEntry:
Name: t.CChar | t.CPtr # 字段名(字符串)
Name: str # 字段名(字符串)
Index: int # 字段在结构体中的索引
Ty: llvmlite.LLVMType | t.CPtr # 字段的 LLVM 类型
DefaultVal: ast.AST | t.CPtr # 默认值 AST 节点(None=无默认值)
AnnotClassName: t.CChar | t.CPtr # 原始类型注解的类名(str 别名在结构体字段中触发编译器 bug,改用显式联合类型)
AnnotClassName: str # 原始类型注解的类名(str 别名在结构体字段中触发编译器 bug,改用显式联合类型)
# ============================================================
@@ -53,7 +53,7 @@ class FieldEntry:
# ============================================================
@t.NoVTable
class StructEntry:
Name: t.CChar | t.CPtr # 类名
Name: str # 类名
Ty: llvmlite.LLVMType | t.CPtr # LLVM StructType
FieldCount: int # 字段数量
Fields: FieldEntry | t.CPtr # 字段数组(FIELD_MAX 个槽位)
@@ -63,12 +63,12 @@ class StructEntry:
HasNew: int # 1=有__new__方法 / 0=无
HasVTable: int # 1=有虚表 / 0=无虚表
IsNoVTable: int # 1=明确标记 @t.NoVTable / 0=未标记
ParentName: t.CChar | t.CPtr # 父类名(None=无父类,多继承时为第一个父类,兼容旧调用)
ParentName: str # 父类名(None=无父类,多继承时为第一个父类,兼容旧调用)
ParentNames: t.CSizeT | t.CPtr # 多继承父类名数组(每元素 str 指针,ParentCount 个;stdlib 深拷贝)
ParentCount: t.CInt # 父类数量(0=无父类,1=单继承,>1=多继承)
VTableMethodCount: int # 虚表中的方法数量
VTableMethods: t.CChar | t.CPtr # 虚表方法名数组(每个方法名 str,VTableMethodCount 个)
ModuleSha1: t.CChar | t.CPtr # 定义该类的模块 SHA1(None=无 SHA1)
VTableMethods: str # 虚表方法名数组(每个方法名 str,VTableMethodCount 个)
ModuleSha1: str # 定义该类的模块 SHA1(None=无 SHA1)
MethodsEmitted: int # 1=方法体已翻译 / 0=未译(Phase 1a mark_only 未译,Phase B 据此补译)
@@ -200,7 +200,7 @@ def add_field(pool: memhub.MemBuddy | t.CPtr,
field_name: str,
field_ty: llvmlite.LLVMType | t.CPtr,
default_val: ast.AST | t.CPtr = None,
annot_class_name: t.CChar | t.CPtr = None) -> int:
annot_class_name: str = None) -> int:
"""向结构体添加字段,返回字段索引(-1 失败,委托到 gen.add_field)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
@@ -496,7 +496,7 @@ def get_parent_name(name: str) -> str:
return None
def set_vtable_methods(name: str, methods: t.CChar | t.CPtr, count: int) -> int:
def set_vtable_methods(name: str, methods: str, count: int) -> int:
"""设置虚表方法名数组,返回 1=成功 / 0=失败(委托到 gen.set_vtable_methods)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
@@ -94,6 +94,14 @@ class Translator:
# i8* Deref 固定读 1 字节 + sext 截断)。
CurAssignAnnot: ast.AST | t.CPtr
# 当前赋值语句的 RHS 节点(AnnAssign 翻译 rhs 前设置,rhs 翻译后清除)。
# 供 c.Deref 判定"是否为赋值直接 RHS":仅 v: int = c.Deref(p) 时用
# CurAssignAnnot 推断读取宽度;嵌套在 while 条件/比较/binop/类型转换
# 调用中(如 while c.Deref(p) != 0、total += t.CInt(c.Deref(p)))不推断,
# 否则 i8* 会被残留 CurAssignAnnot 误判为 i32* 读 4 字节(对齐 TPC
# _infer_deref_target_type 的直接 RHS 检查)。
CurAssignNode: ast.AST | t.CPtr
# 循环控制流目标(break/continue)
_break_bb: llvmlite.BasicBlock | t.CPtr
_continue_bb: llvmlite.BasicBlock | t.CPtr
+1 -1
View File
@@ -573,7 +573,7 @@ def build_param_types_str(pool: memhub.MemBuddy | t.CPtr,
return None
def _strappend(dst: t.CChar | t.CPtr, dst_size: t.CSizeT, src: t.CChar | t.CPtr):
def _strappend(dst: str, dst_size: t.CSizeT, src: str):
"""将 src 追加到 dst 末尾(委托到 gen._strappend)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
+2 -2
View File
@@ -40,10 +40,10 @@ MAX_VARS: t.CDefine = 256
@t.NoVTable
class VarEntry:
"""变量表条目"""
Name: t.CChar | t.CPtr
Name: str
Alloca: llvmlite.Value | t.CPtr
Used: t.CInt
AnnotClassName: t.CChar | t.CPtr # 原始类型注解的类名(str 别名在结构体字段中触发编译器 bug,改用显式联合类型)
AnnotClassName: str # 原始类型注解的类名(str 别名在结构体字段中触发编译器 bug,改用显式联合类型)
IsPtrElement: t.CInt # 标志: 1=注解为 bytes|t.CPtr 或 str|t.CPtr, 下标按 8 字节步长
+4 -2
View File
@@ -10,6 +10,7 @@ import lib.core.Handles.HandlesBase as HandlesBase
import lib.core.Handles.HandlesTranslator as HT
import lib.core.Handles.HandlesExpr as HandlesExpr
import lib.core.Handles.HandlesBody as HandlesBody
import lib.core.Handles.HandlesType as HandlesType
# ============================================================
@@ -77,7 +78,7 @@ class WhileHandle(HandlesBase.Mixin):
cnt: int = trans._label_counter
trans._label_counter = cnt + 1
name_buf: t.CChar | t.CPtr = pool.alloc(32)
name_buf: str = pool.alloc(32)
viperlib.snprintf(name_buf, 32, "while.cond.%d", cnt)
cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
@@ -96,7 +97,8 @@ class WhileHandle(HandlesBase.Mixin):
builder, pool, trans.Module, while_node.test,
trans._funcs, trans._func_count, trans)
if cond_val is None:
cond_val = llvmlite.const_int32(pool, 0)
# fail-fast: while 条件表达式翻译失败
HandlesType.fatal_error(while_node.test, "while 条件表达式翻译失败", "TypeError")
# Compare/Not 表达式已返回 i1,直接使用;指针类型与 null 比较;其他类型与 0 比较
cond_bits: int = HandlesExpr.get_llvm_type_bits(cond_val.Ty)
+16 -3
View File
@@ -210,6 +210,8 @@ def scan_directory_recursive(pool: memhub.MemBuddy | t.CPtr,
"""递归扫描目录,收集 .vp/.py 文件(inc_dir 为所属 includes 根目录)"""
if pool is None or root_dir is None or result is None:
return 1
# 子目录递归失败计数(不静默忽略,汇总处 fail-fast 终止)
subdir_failed: int = 0
# 构造搜索模式: root_dir/*
root_len: t.CSizeT = string.strlen(root_dir)
@@ -275,7 +277,8 @@ def scan_directory_recursive(pool: memhub.MemBuddy | t.CPtr,
if is_dir != 0:
# 递归扫描子目录
scan_directory_recursive(pool, full_path, rel_path, result, inc_dir)
if scan_directory_recursive(pool, full_path, rel_path, result, inc_dir) != 0:
subdir_failed += 1
else:
# 检查是否为 .vp 或 .py 文件(.vp 为 Viper 源,.py 向后兼容)
is_py: int = 0
@@ -294,16 +297,26 @@ def scan_directory_recursive(pool: memhub.MemBuddy | t.CPtr,
sha1: str = compute_file_sha1(pool, full_path)
if sha1 is not None:
add_file_entry(result, pool, full_path, rel_path, sha1, inc_dir)
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "扫描: %s -> %s", rel_path, sha1)
VLogger.debug(fb, "scan")
else:
fb_sha: str = VLogger.fmt_buf()
if fb_sha is not None:
viperlib.snprintf(fb_sha, 1024, "SHA1 计算失败: %s", full_path)
VLogger.warning(fb_sha, "scan")
# 继续搜索下一个文件
if win32file.FindNextFileA(handle, find_data) == 0:
break
win32file.FindClose(handle)
if subdir_failed > 0:
fb_sdf: str = VLogger.fmt_buf()
if fb_sdf is not None:
viperlib.snprintf(fb_sdf, 1024, "子目录扫描失败 %d 个", subdir_failed)
VLogger.error(fb_sdf, "scan")
return 0
@@ -338,7 +351,7 @@ def scan_includes(pool: memhub.MemBuddy | t.CPtr,
continue
dir_buf: bytes = stdlib.malloc(d_len + 1)
if dir_buf is None:
continue
VLogger.error("includes 目录分配失败,终止扫描", "scan")
string.strncpy(dir_buf, includes_dirs + d_start, d_len)
dir_buf[d_len] = '\0'
scan_directory_recursive(pool, dir_buf, None, result, dir_buf)
+59 -17
View File
@@ -496,7 +496,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
log: VLogger.Logger | t.CPtr) -> int:
"""Phase1: 扫描 includes 目录,按需翻译并生成 stub"""
if includes_dir is None or temp_dir is None:
VLogger.warning("includes_dir 或 temp_dir 为空,跳过", "Phase1")
VLogger.error("includes_dir 或 temp_dir 为空,无法运行 Phase1", "Phase1")
return 1
# 设置全局 temp_dir(供跨模块 CDefine 查找使用)
@@ -666,6 +666,13 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
stdlib.free(src_buf_a)
if p1a_failed > 0:
fb_p1apre: str = VLogger.fmt_buf()
if fb_p1apre is not None:
viperlib.snprintf(fb_p1apre, 1024, "Phase 1a-pre 有 %d 个文件扫描失败", p1a_failed)
VLogger.error(fb_p1apre, "Phase1")
return 1
# ============================================================
# 依赖图按需翻译:构建可达 SHA1 集合
#
@@ -682,6 +689,9 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
if reachable_set is not None:
string.memset(reachable_set, 0, StubMerger.MAX_INCLUDES_SHA1 * 17)
reachable_count = StubMerger._BuildReachableSha1Set(mb, Config.SourceDir, temp_dir, reachable_set)
if reachable_count < 0:
VLogger.error("可达集合构建失败,终止", "Phase1")
return 1
if reachable_count > 0:
use_reachable = 1
# 用可达集合重新生成 _sha1_map.txt(按图求索的最终产物)
@@ -691,6 +701,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
string.memset(sha1_set, 0, StubMerger.MAX_INCLUDES_SHA1 * 17)
set_count = StubMerger._load_includes_sha1_set(mb, temp_dir, sha1_set)
else:
VLogger.warning("可达集合为空,回退全量扫描", "Phase1")
stdlib.free(reachable_set)
reachable_set = None
@@ -750,15 +761,15 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
tc_ptr: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(topo_count_box, t.CPtr))
if tc_ptr is not None:
topo_count = tc_ptr[0]
fb_topo: t.CChar | t.CPtr = VLogger.fmt_buf()
fb_topo: str = VLogger.fmt_buf()
if fb_topo is not None:
viperlib.snprintf(fb_topo, 1024,
"拓扑排序: %d 个类, %d 个文件按依赖顺序处理",
class_count_scanned, topo_count)
VLogger.info(fb_topo, "Phase1")
else:
VLogger.warning("拓扑排序失败,回退到字母序", "Phase1")
topo_count = 0
VLogger.error("拓扑排序失败(类继承依赖无法解析),终止编译", "Phase1")
return 1
else:
VLogger.warning("类继承预扫描无结果,回退到字母序", "Phase1")
topo_count = 0
@@ -777,7 +788,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
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()
fb_gpre: str = VLogger.fmt_buf()
if fb_gpre is not None:
viperlib.snprintf(fb_gpre, 1024, "预注册 %d 个泛型类模板文件", generic_file_count)
VLogger.info(fb_gpre, "Phase1")
@@ -946,6 +957,13 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
stdlib.free(tr_r._nonlocal_names)
stdlib.free(src_buf_r)
if p1a_fl > 0:
fb_p1ar: str = VLogger.fmt_buf()
if fb_p1ar is not None:
viperlib.snprintf(fb_p1ar, 1024, "Phase 1a 有 %d 个文件 struct 注册失败", p1a_fl)
VLogger.error(fb_p1ar, "Phase1")
return 1
# 释放拓扑排序资源
if class_names_buf is not None:
mb.free(class_names_buf)
@@ -984,11 +1002,13 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
# 返回类型推断错误(如 HashTable.__getitem__ 被推断为 Ptr(HashTable)
# 而 define 返回 i8*)→ 运行时返回值截断崩溃。
# ============================================================
p1bpre_failed: int = 0
dir_len_pv: t.CSizeT = string.strlen(temp_dir)
for i_pv in range(result.Count):
entry_addr_pv: t.CUInt64T = t.CUInt64T(result.Entries) + i_pv * entry_size
entry_pv: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(entry_addr_pv, t.CPtr))
if entry_pv is None or entry_pv.Sha1 is None:
p1bpre_failed += 1
continue
sha1_pv: str = entry_pv.Sha1
in_set_pv: int = 0
@@ -1001,6 +1021,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
# vpi 已存在则跳过
vpi_path_pv: str = StubMerger._sliced_path(temp_dir, dir_len_pv, sha1_pv, "vpi")
if vpi_path_pv is None:
p1bpre_failed += 1
continue
vf_pv: fileio.File | t.CPtr = fileio.File(vpi_path_pv, fileio.MODE.R)
if not vf_pv.closed:
@@ -1012,15 +1033,18 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
file_path_pv: str = entry_pv.Path
f_pv: fileio.File | t.CPtr = fileio.File(file_path_pv, fileio.MODE.R)
if f_pv.closed:
p1bpre_failed += 1
continue
src_buf_pv: bytes = stdlib.malloc(SRC_BUF_SIZE)
if src_buf_pv is None:
f_pv.close()
p1bpre_failed += 1
continue
bytes_read_pv: LONG = f_pv.read_all(src_buf_pv, SRC_BUF_SIZE)
f_pv.close()
if bytes_read_pv <= 0:
stdlib.free(src_buf_pv)
p1bpre_failed += 1
continue
if bytes_read_pv < SRC_BUF_SIZE:
src_buf_pv[bytes_read_pv] = 0
@@ -1029,12 +1053,14 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
lx_pv: ast.Lexer | t.CPtr = ast.new_lexer(mb)
if lx_pv is None:
stdlib.free(src_buf_pv)
p1bpre_failed += 1
continue
ast._lexer_init(lx_pv, src_buf_pv, mb)
tokens_pv: ast.Token | t.CPtr = ast.tokenize(lx_pv)
tree_pv: ast.AST | t.CPtr = ast.parse_tokens(mb, tokens_pv)
if tree_pv is None:
stdlib.free(src_buf_pv)
p1bpre_failed += 1
continue
pyi_buf_pv: bytes = stdlib.malloc(PYI_BUF_SIZE)
if pyi_buf_pv is not None:
@@ -1048,8 +1074,17 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
pf_pv.close()
stdlib.free(pyi_path_pv)
stdlib.free(pyi_buf_pv)
else:
p1bpre_failed += 1
stdlib.free(src_buf_pv)
if p1bpre_failed > 0:
fb_p1bpre: str = VLogger.fmt_buf()
if fb_p1bpre is not None:
viperlib.snprintf(fb_p1bpre, 1024, "Phase 1b-pre 有 %d 个文件 vpi 预生成失败", p1bpre_failed)
VLogger.error(fb_p1bpre, "Phase1")
return 1
# 遍历每个文件
translated: int = 0
skipped: int = 0
@@ -1102,14 +1137,14 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
stdlib.free(text_path)
# text.ll 不存在,需要重新翻译
rp: str = entry.RelPath
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "text.ll 不存在,重新翻译: %s (sha1=%s)", rp, sha1)
VLogger.info(fb, "Phase1")
else:
# stub 不存在,需要翻译
rp: str = entry.RelPath
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "翻译: %s (sha1=%s)", rp, sha1)
VLogger.info(fb, "Phase1")
@@ -1120,14 +1155,14 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
file_path: str = entry.Path
f: fileio.File | t.CPtr = fileio.File(file_path, fileio.MODE.R)
if f is None:
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "无法打开(None): %s", file_path)
VLogger.error(fb, "Phase1")
failed += 1
continue
if f.closed:
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "无法打开: %s", file_path)
VLogger.error(fb, "Phase1")
@@ -1143,7 +1178,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
bytes_read: LONG = f.read_all(src_buf, SRC_BUF_SIZE)
f.close()
if bytes_read <= 0:
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "读取失败: %s", file_path)
VLogger.error(fb, "Phase1")
@@ -1165,7 +1200,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
tokens: ast.Token | t.CPtr = ast.tokenize(lx)
tree: ast.AST | t.CPtr = ast.parse_tokens(mb, tokens)
if tree is None:
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "AST 解析失败: %s", file_path)
VLogger.error(fb, "Phase1")
@@ -1207,7 +1242,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
# (崩溃点漂移排查:把"翻译过程中随机崩"变成确定性定位)
pre_rc: t.CInt = mb.check_alive_blocks(mark1)
if pre_rc != 0:
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024,
"内存损坏(翻译前存活块, rc=%d): %s", pre_rc, file_path)
@@ -1218,12 +1253,12 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
# 诊断:translate 正常返回(若挂起在 translate 内部,此行不会打印,
# 用于区分"translate 内部挂起"与"后续 dump 挂起")
if ret == 0:
fb_done: t.CChar | t.CPtr = VLogger.fmt_buf()
fb_done: str = VLogger.fmt_buf()
if fb_done is not None:
viperlib.snprintf(fb_done, 1024, "翻译完成(translate返回): %s", file_path)
VLogger.info(fb_done, "Phase1")
if ret != 0:
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "翻译失败: %s", file_path)
VLogger.error(fb, "Phase1")
@@ -1318,7 +1353,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
# rc 语义(self_check):1/2=越界,3=对齐错,4=free list 成环/超步数
chk_rc: t.CInt = mb.check_alive_blocks(mark1)
if chk_rc != 0:
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024,
"内存损坏(存活块 header, rc=%d): %s", chk_rc, file_path)
@@ -1330,18 +1365,25 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
mb.reset_to(mark1)
sc_rc: t.CInt = mb.self_check()
if sc_rc != 0:
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024,
"内存损坏(free list, rc=%d): %s", sc_rc, file_path)
VLogger.error(fb, "Phase1")
stdlib.exit(1)
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "完成: 翻译=%d 跳过=%d 失败=%d", translated, skipped, failed)
VLogger.info(fb, "Phase1")
if failed > 0:
fb_fail: str = VLogger.fmt_buf()
if fb_fail is not None:
viperlib.snprintf(fb_fail, 1024, "Phase1 有 %d 个文件翻译失败", failed)
VLogger.error(fb_fail, "Phase1")
return 1
# 释放可达 SHA1 集合(如果分配了)
if reachable_set is not None:
stdlib.free(reachable_set)
+46 -32
View File
@@ -149,7 +149,7 @@ def _ScanDirForPyFiles(mb: memhub.MemBuddy | t.CPtr,
ent.Path = full_path
ent.Sha1 = sha1_val
file_count += 1
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "%s (sha1=%s)", fname, sha1_val)
VLogger.info(fb, "project")
@@ -186,7 +186,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
global _g_canary
_g_canary = 305419896
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "多文件项目编译: %s", source_dir)
VLogger.info(fb, "project")
@@ -199,7 +199,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
string.memset(entries, 0, MAX_SRC_FILES * entry_size)
file_count: int = _ScanDirForPyFiles(mb, source_dir, entries, entry_size, 0, MAX_SRC_FILES)
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "共 %d 个源文件", file_count)
VLogger.info(fb, "project")
@@ -221,9 +221,11 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
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 None:
VLogger.error("includes 扫描失败,无法填充 Sha1Store", "project")
if inc_scan_result is not None:
inc_filled: int = StubMerger.PopulateSha1MapStore(inc_scan_result)
fb_inc: t.CChar | t.CPtr = VLogger.fmt_buf()
fb_inc: str = 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")
@@ -254,8 +256,12 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
rel_path_am = p_str + src_dir_len_am + 1
# 同步追加到内存存储器(供跨模块 CDefine 查找)
# rel_path_am 格式如 "lib/core/StubMerger.vp",与 _sha1_map.txt 一致
if StubMerger.AppendToSha1MapStore(ent_am.Sha1, rel_path_am) == 0:
app_filled += 1
if StubMerger.AppendToSha1MapStore(ent_am.Sha1, rel_path_am) != 0:
fb_apf: str = VLogger.fmt_buf()
if fb_apf is not None:
viperlib.snprintf(fb_apf, 1024, "AppendToSha1MapStore 失败: %s", rel_path_am)
VLogger.error(fb_apf, "project")
app_filled += 1
# 写入 _sha1_map.txt(人类可读输出)
if not mf.closed and line_am is not None:
viperlib.snprintf(line_am, 512, "%s:%s\n", ent_am.Sha1, rel_path_am)
@@ -265,7 +271,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
stdlib.free(line_am)
if not mf.closed:
mf.close()
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "已追加 %d 个 App 文件到 _sha1_map.txt 和内存存储器", app_filled)
VLogger.info(fb, "project")
@@ -368,7 +374,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
for si_inc_f in range(store_count_inc_pre):
if inc_fail_flags[si_inc_f] != 0:
rel_f: str = store_rel_inc_pre + t.CSizeT(si_inc_f) * StubMerger.MAX_REL_PATH_LEN
fb_inc_f: t.CChar | t.CPtr = VLogger.fmt_buf()
fb_inc_f: str = VLogger.fmt_buf()
if fb_inc_f is not None:
viperlib.snprintf(fb_inc_f, 1024,
"includes 预注册失败: %s(文件无法翻译,可能是语法/解析/编译错误),终止编译",
@@ -376,7 +382,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
VLogger.error(fb_inc_f, "prePhaseA")
sys.exit(1)
stdlib.free(inc_fail_flags)
fb_inc_pre: t.CChar | t.CPtr = VLogger.fmt_buf()
fb_inc_pre: str = 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")
@@ -402,10 +408,10 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
pkg_pre = HandlesImports.compute_package_from_relpath(mb, rel_path_pre)
tr_pre: HandlesTranslator.Translator | t.CPtr = BuildPipeline.TranslateFileGetTrans(mb, ent_pre.Path, ent_pre.Sha1, pkg_pre, 1)
if tr_pre is None:
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "预注册失败: %s", ent_pre.Path)
VLogger.warning(fb, "PhaseA")
VLogger.error(fb, "PhaseA")
struct_count_after: int = HandlesStruct.get_struct_count()
# 收敛检查:本遍没有新结构体注册 → 所有类已注册
if struct_count_after == struct_count_before:
@@ -473,7 +479,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
app_deps_buf[app_deps_len] = '\0'
if tr_a._deps_pending != 0:
# 依赖模块 text.ll 未生成(同项目文件顺序),不写盘,下遍重试
fb_dp: t.CChar | t.CPtr = VLogger.fmt_buf()
fb_dp: str = VLogger.fmt_buf()
if fb_dp is not None:
viperlib.snprintf(fb_dp, 1024,
"Phase A 依赖未就绪,下遍重试: %s", ent.Path)
@@ -483,7 +489,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
# dump stub IR (declarations only)
stub_buf_a: bytes = stdlib.malloc(PHASE_A_IR_SIZE)
if stub_buf_a is None:
continue
VLogger.error("stub 缓冲区分配失败", "PhaseA")
tr_a.dump_ir(stub_buf_a, PHASE_A_IR_SIZE, llvmlite.OUTPUT_STUB)
stub_len_a: t.CSizeT = string.strlen(stub_buf_a)
@@ -500,7 +506,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
# dump text IR (definitions only)
text_buf_a: bytes = stdlib.malloc(PHASE_A_IR_SIZE)
if text_buf_a is None:
continue
VLogger.error("text 缓冲区分配失败", "PhaseA")
tr_a.dump_ir(text_buf_a, PHASE_A_IR_SIZE, llvmlite.OUTPUT_TEXT)
text_len_a: t.CSizeT = string.strlen(text_buf_a)
@@ -542,7 +548,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
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()
fb_err: str = VLogger.fmt_buf()
if fb_err is not None:
viperlib.snprintf(fb_err, 1024,
"Phase A 无法完成翻译: %s(请检查依赖模块是否已编译/注册)", ent_err.Path)
@@ -594,14 +600,14 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
# 组合本地 stub + 所有依赖 stub + 本地 text → 完整 IR
combined_ir: bytes = stdlib.malloc(COMBINED_IR_SIZE)
if combined_ir is None:
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "combined_ir 分配失败: %s", ent.Path)
VLogger.error(fb, "PhaseB")
continue
combined_len: t.CSizeT = StubMerger.BuildCombinedIR(temp_dir, ent.Sha1, combined_ir, COMBINED_IR_SIZE)
if combined_len == 0:
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "BuildCombinedIR 失败: %s", ent.Path)
VLogger.error(fb, "PhaseB")
@@ -614,7 +620,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
cc_cmd, cc_flags)
stdlib.free(combined_ir)
if cret != 0:
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "llc 编译失败,终止编译: %s", ent.Path)
VLogger.error(fb, "PhaseB")
@@ -622,7 +628,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
compiled_count += 1
# 显示编译完成的文件
fb_comp: t.CChar | t.CPtr = VLogger.fmt_buf()
fb_comp: str = 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")
@@ -643,7 +649,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
if op_sliced_len < 512:
string.strcpy(main_obj_path, obj_path_sliced)
else:
VLogger.warning("main_obj_path 缓冲区不足", "PhaseB")
VLogger.error("main_obj_path 缓冲区不足,终止编译", "PhaseB")
else:
# 其他模块: 追加到 obj_paths
if obj_pos + op_sliced_len + 2 < OBJ_PATHS_SIZE:
@@ -654,9 +660,9 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
obj_pos += op_sliced_len
obj_paths[obj_pos] = '\0'
else:
VLogger.warning(".obj 路径缓冲区不足", "PhaseB")
VLogger.error(".obj 路径缓冲区不足", "PhaseB")
stdlib.free(obj_path_sliced)
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "编译完成: %d/%d", compiled_count, file_count)
VLogger.success(fb, "PhaseB")
@@ -674,7 +680,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
td_len_mi: t.CSizeT = string.strlen(temp_dir)
# 诊断日志:确认 Phase B+ 入口和 Sha1Store 状态
fb_pbp_enter: t.CChar | t.CPtr = VLogger.fmt_buf()
fb_pbp_enter: str = VLogger.fmt_buf()
if fb_pbp_enter is not None:
viperlib.snprintf(fb_pbp_enter, 1024,
"PhaseB+ 入口: store_count=%d includes_binary_dir=%s",
@@ -697,7 +703,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
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()
fb_reach: str = VLogger.fmt_buf()
if fb_reach is not None:
viperlib.snprintf(fb_reach, 1024, "可达 includes SHA1: %d 个", reachable_count)
VLogger.info(fb_reach, "PhaseB+")
@@ -760,7 +766,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
stdlib.free(check_pat_mi)
if check_fd_mi is not None:
stdlib.free(check_fd_mi)
continue
VLogger.error("includes 源路径分配失败,终止编译", "PhaseB+")
viperlib.snprintf(src_fp_mi, inc_dir_len_mi + 1 + rel_path_len_mi + 1,
"%s/%s", incdir_mi, inc_rel_mi)
@@ -874,7 +880,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
diag_text_ex = 1
df_diag_t.close()
stdlib.free(diag_text)
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024,
"BuildCombinedIR 失败: %s (stub=%d text=%d is_decl=%d)",
@@ -895,7 +901,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
stdlib.free(inc_combined_mi)
if inc_cret_mi != 0:
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "llc 编译失败,终止编译: %s", src_fp_mi)
VLogger.error(fb, "PhaseB+")
@@ -903,7 +909,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
inc_compiled += 1
# 显示编译完成的 includes 文件
fb_inc_comp: t.CChar | t.CPtr = VLogger.fmt_buf()
fb_inc_comp: str = 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+")
@@ -921,6 +927,8 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
string.strcpy(obj_paths + obj_pos, inc_obj_sliced)
obj_pos += inc_obj_len
obj_paths[obj_pos] = '\0'
else:
VLogger.error("includes .obj 路径缓冲区溢出,终止编译", "PhaseB+")
stdlib.free(inc_obj_sliced)
# 释放本次迭代的临时内存
@@ -932,7 +940,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
stdlib.free(src_fp_mi)
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "编译缺失 includes: %d 个", inc_compiled)
VLogger.info(fb, "PhaseB+")
@@ -953,6 +961,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
viperlib.snprintf(exe_path, od_len2 + lo_len + 2, "%s/%s", output_dir, linker_output)
else:
exe_path = linker_output
VLogger.error("exe_path 分配失败,终止编译", "PhaseC")
# 构造最终 .obj 路径列表:main_obj_path 在前,reachable .obj 在后
final_obj_paths: bytes = stdlib.malloc(OBJ_PATHS_SIZE + 512)
@@ -991,6 +1000,11 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
string.strcpy(final_obj_paths + fop_pos, obj_path_pc)
fop_pos += op_len_pc
final_obj_paths[fop_pos] = '\0'
else:
fb_pc: str = VLogger.fmt_buf()
if fb_pc is not None:
viperlib.snprintf(fb_pc, 1024, "可达模块 .obj 缺失: %s", obj_path_pc)
VLogger.error(fb_pc, "PhaseC")
stdlib.free(obj_path_pc)
final_obj_paths[fop_pos] = '\0'
@@ -1008,18 +1022,18 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
None)
if lret == 0:
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "输出: %s", exe_path)
VLogger.success(fb, "PhaseC")
if args.get_bool("run"):
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "执行: %s", exe_path)
VLogger.info(fb, "run")
rp: subprocess.CompletedProcess | t.CPtr = subprocess.run(exe_path, False, False)
if rp is not None:
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "退出码: %d", rp.returncode)
VLogger.info(fb, "run")
+64 -15
View File
@@ -281,7 +281,7 @@ def _is_in_sha1_set(sha1: str, sha1_set: str, set_count: int) -> int:
# ============================================================
def WriteIncludesSha1Map(mb: memhub.MemBuddy | t.CPtr, temp_dir: str,
scan_result: IncludesScanner.ScanResult | t.CPtr,
filter_set: t.CChar | t.CPtr,
filter_set: str,
filter_count: int) -> int:
"""将 includes 扫描结果写入 _sha1_map.txt(人类可读输出,程序内部使用内存存储器)
@@ -371,18 +371,21 @@ def PopulateSha1MapStore(scan_result: IncludesScanner.ScanResult | t.CPtr) -> in
string.memset(_sha1_store_rel, 0, MAX_INCLUDES * MAX_REL_PATH_LEN)
string.memset(_sha1_store_incdir, 0, MAX_INCLUDES * MAX_INC_DIR_LEN)
_sha1_store_count = 0
p_bad: int = 0
entry_size_p: t.CSizeT = IncludesScanner.FileEntry.__sizeof__()
for i in range(scan_result.Count):
if _sha1_store_count >= MAX_INCLUDES:
break
VLogger.error("includes SHA1 存储超上限,终止", "StubMerger")
ea: t.CUInt64T = t.CUInt64T(scan_result.Entries) + i * entry_size_p
ent: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(ea, t.CPtr))
if ent is None or ent.Sha1 is None or ent.RelPath is None:
p_bad += 1
continue
# 构建完整路径 includes/{RelPath}(_PathToModuleName 需要)
rp_len: t.CSizeT = string.strlen(ent.RelPath)
full_path_buf: bytes = stdlib.malloc(rp_len + 10)
if full_path_buf is None:
p_bad += 1
continue
viperlib.snprintf(full_path_buf, rp_len + 10, "includes/%s", ent.RelPath)
mod_name: str = Utils.PathToModuleName(full_path_buf, 1)
@@ -415,6 +418,11 @@ def PopulateSha1MapStore(scan_result: IncludesScanner.ScanResult | t.CPtr) -> in
string.strncpy(_sha1_store_incdir + idx_inc, ent.IncDir, MAX_INC_DIR_LEN - 1)
_sha1_store_incdir[idx_inc + MAX_INC_DIR_LEN - 1] = '\0'
_sha1_store_count += 1
if p_bad > 0:
fb_pbad: str = VLogger.fmt_buf()
if fb_pbad is not None:
viperlib.snprintf(fb_pbad, 1024, "includes SHA1 存储有 %d 个条目失败", p_bad)
VLogger.error(fb_pbad, "StubMerger")
return _sha1_store_count
@@ -948,11 +956,23 @@ def _LoadAndAppendStub(temp_dir: str, td_len: t.CSizeT, dep_sha1: str,
df_ls: fileio.File | t.CPtr = fileio.File(dep_path, fileio.MODE.R)
if df_ls.closed:
stdlib.free(dep_path)
# 依赖 stub 缺失:includes 映射内的模块缺失属编译错误(fail-fast),
# 非映射模块(如 t/c 内部库、用户文件)按设计跳过
if LookupSha1RelPath(dep_sha1) is not None:
fb_ls: str = VLogger.fmt_buf()
if fb_ls is not None:
viperlib.snprintf(fb_ls, 1024, "依赖 stub 缺失: %s", dep_sha1)
VLogger.error(fb_ls, "StubMerger")
return out_pos
dep_br_ls: t.CInt64T = df_ls.read_all(dep_buf, STUB_READ_BUF_SIZE)
df_ls.close()
stdlib.free(dep_path)
if dep_br_ls <= 0:
if LookupSha1RelPath(dep_sha1) is not None:
fb_ls2: str = VLogger.fmt_buf()
if fb_ls2 is not None:
viperlib.snprintf(fb_ls2, 1024, "依赖 stub 为空: %s", dep_sha1)
VLogger.error(fb_ls2, "StubMerger")
return out_pos
if dep_br_ls < STUB_READ_BUF_SIZE:
dep_buf[dep_br_ls] = '\0'
@@ -1106,11 +1126,23 @@ def _LoadAndAppendTextDeclares(temp_dir: str, td_len: t.CSizeT, dep_sha1: str,
tf_lt: fileio.File | t.CPtr = fileio.File(text_path, fileio.MODE.R)
if tf_lt.closed:
stdlib.free(text_path)
# 依赖 text 缺失:includes 映射内的模块缺失属编译错误(fail-fast),
# 非映射模块(如 t/c 内部库、用户文件)按设计跳过
if LookupSha1RelPath(dep_sha1) is not None:
fb_lt: str = VLogger.fmt_buf()
if fb_lt is not None:
viperlib.snprintf(fb_lt, 1024, "依赖 text 缺失: %s", dep_sha1)
VLogger.error(fb_lt, "StubMerger")
return out_pos
text_br: t.CInt64T = tf_lt.read_all(dep_buf, STUB_READ_BUF_SIZE)
tf_lt.close()
stdlib.free(text_path)
if text_br <= 0:
if LookupSha1RelPath(dep_sha1) is not None:
fb_lt2: str = VLogger.fmt_buf()
if fb_lt2 is not None:
viperlib.snprintf(fb_lt2, 1024, "依赖 text 为空: %s", dep_sha1)
VLogger.error(fb_lt2, "StubMerger")
return out_pos
if text_br < STUB_READ_BUF_SIZE:
dep_buf[text_br] = '\0'
@@ -1302,8 +1334,8 @@ def _LoadAndAppendTextDeclares(temp_dir: str, td_len: t.CSizeT, dep_sha1: str,
# 所有内存由 stdlib.malloc 分配,调用者负责释放。
# ============================================================
def _BuildIncludesSha1Map(temp_dir: str, td_len: t.CSizeT,
sha1_list: t.CChar | t.CPtr,
mod_list: t.CChar | t.CPtr) -> int:
sha1_list: str,
mod_list: str) -> int:
"""从全局内存存储器复制 sha1→module_name 映射到调用者数组
temp_dir/td_len 参数保留以兼容现有调用者,但不再使用。
@@ -1340,7 +1372,7 @@ def _BuildIncludesSha1Map(temp_dir: str, td_len: t.CSizeT,
# Returns:
# SHA1 字符串指针(指向 sha1_arr 内部,无需释放),未找到返回 None
# ============================================================
def _FindSha1ByModName(sha1_arr: t.CChar | t.CPtr, mod_arr: t.CChar | t.CPtr,
def _FindSha1ByModName(sha1_arr: str, mod_arr: str,
count: int, mod_name: str) -> str:
"""从模块名查找 SHA1(精确匹配 + 包名回退)
@@ -1385,7 +1417,7 @@ def _FindSha1ByModName(sha1_arr: t.CChar | t.CPtr, mod_arr: t.CChar | t.CPtr,
# Returns:
# 新的 count(如果已存在则不变)
# ============================================================
def _AddSha1ToSet(set_buf: t.CChar | t.CPtr, count: int, sha1: str) -> int:
def _AddSha1ToSet(set_buf: str, count: int, sha1: str) -> int:
"""将 SHA1 加入集合,返回新 count"""
if set_buf is None or sha1 is None:
return count
@@ -1423,7 +1455,7 @@ 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,
reachable_set: str,
app_deps: str = None) -> int:
"""构建可达 SHA1 集合(依赖图按需翻译)
@@ -1450,7 +1482,7 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str,
stdlib.free(sha1_arr)
stdlib.free(mod_arr)
return -1
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "SHA1 映射: %d 个", map_count)
VLogger.debug(fb, "Reachable")
@@ -1473,7 +1505,12 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str,
if ad_len > 0 and ad_len < 8192:
string.strcpy(worklist, app_deps)
wl_len = ad_len
else:
VLogger.error("app_deps 过长,无法构建可达集合", "StubMerger")
else:
# app_deps 缺失:Phase1 场景(未翻译 App 源文件)为设计性回退,
# 显式 warning 暴露回退,不再静默
VLogger.warning("app_deps 缺失,回退非递归扫描 source_dir", "Reachable")
# 回退到自己的非递归扫描
dir_len: t.CSizeT = string.strlen(source_dir)
pattern: bytes = stdlib.malloc(dir_len + 8)
@@ -1496,7 +1533,7 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str,
handle: win32base.HANDLE = win32file.FindFirstFileA(pattern, find_data)
if handle == win32base.INVALID_HANDLE_VALUE:
fb_fd: t.CChar | t.CPtr = VLogger.fmt_buf()
fb_fd: str = VLogger.fmt_buf()
if fb_fd is not None:
viperlib.snprintf(fb_fd, 1024, "未找到源文件(.vp/.py): %s", pattern)
VLogger.warning(fb_fd, "Reachable")
@@ -1573,7 +1610,7 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str,
worklist[wl_len - 1] = '\0'
wl_len -= 1
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "源文件直接依赖: '%s'", worklist)
VLogger.debug(fb, "Reachable")
@@ -1636,7 +1673,7 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str,
worklist[wl_len] = ' '
wl_len += 1
worklist[wl_len] = '\0'
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "预加入容器模块后: '%s'", worklist)
VLogger.debug(fb, "Reachable")
@@ -1685,6 +1722,8 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str,
processed[proc_len] = ' '
proc_len = proc_len + 1
processed[proc_len] = '\0'
else:
VLogger.error("依赖 worklist 溢出", "StubMerger")
# 查找 SHA1
found_sha1: str = _FindSha1ByModName(sha1_arr, mod_arr, map_count, mod_buf)
@@ -1707,6 +1746,8 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str,
worklist[wl_len] = ' '
wl_len = wl_len + 1
worklist[wl_len] = '\0'
else:
VLogger.error("依赖 worklist 溢出", "StubMerger")
# deps_str 为空字符串视为无依赖(合法情况,如叶子模块)
else:
# 依赖未在内存中找到
@@ -1733,7 +1774,7 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str,
stdlib.free(app_mod_path)
if is_app_src == 0:
# fast-fail: includes 文件依赖未在内存中找到,Phase 1a-pre 未正确填充
fb_ff: t.CChar | t.CPtr = VLogger.fmt_buf()
fb_ff: str = 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")
@@ -1749,7 +1790,7 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str,
stdlib.free(worklist)
stdlib.free(processed)
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "可达 SHA1: %d 个", reachable_count)
VLogger.debug(fb, "Reachable")
@@ -1856,6 +1897,10 @@ def BuildCombinedIR(temp_dir: str, local_sha1: str,
df_deps.close()
stdlib.free(deps_path)
# deps.txt 缺失但存在 includes 映射:依赖无法按需过滤,fail-fast 终止
if deps_loaded == 0 and inc_count > 0:
VLogger.error("依赖文件 deps.txt 缺失,无法合并 includes stub", "StubMerger")
# 2c. 递归扫描 temp_dir 中所有 .stub.ll,按需加载
all_sha1_arr: str = stdlib.malloc(MAX_INCLUDES_SHA1 * 17)
all_count: int = 0
@@ -1946,7 +1991,7 @@ def BuildCombinedIR(temp_dir: str, local_sha1: str,
if chk_path is not None:
chk_f: fileio.File | t.CPtr = fileio.File(chk_path, fileio.MODE.R)
if chk_f.closed:
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "依赖模块 '%s' (sha1=%s) 的 stub 文件不存在: %s,立即终止编译", mod_nm, found_s, chk_path)
VLogger.error(fb, "BuildCombinedIR")
@@ -1960,8 +2005,12 @@ def BuildCombinedIR(temp_dir: str, local_sha1: str,
return out_pos
tf: fileio.File | t.CPtr = fileio.File(text_path, fileio.MODE.R)
if tf.closed:
# 本地 text.ll 缺失:合并 IR 无法生成定义块,fail-fast 终止
fb_tlp: str = VLogger.fmt_buf()
if fb_tlp is not None:
viperlib.snprintf(fb_tlp, 1024, "本地 text.ll 缺失: %s", text_path)
VLogger.error(fb_tlp, "StubMerger")
stdlib.free(text_path)
# text.ll 不存在的情况,继续
else:
text_content: bytes = stdlib.malloc(STUB_READ_BUF_SIZE)
if text_content is None:
+3 -3
View File
@@ -194,14 +194,14 @@ _mbuddy: memhub.MemBuddy | t.CPtr
_g_logger: Logger | t.CPtr
# 全局格式化缓冲区(用于带变量的日志消息,1024 字节)
_fmt_buf: t.CChar | t.CPtr
_fmt_buf: str
def fmt_buf() -> t.CChar | t.CPtr:
def fmt_buf() -> str:
"""获取全局格式化缓冲区(1024 字节)。
用法:
buf: t.CChar | t.CPtr = VLogger.fmt_buf()
buf: str = VLogger.fmt_buf()
if buf is not None:
viperlib.snprintf(buf, 1024, "翻译: %s (sha1=%s)", rp, sha1)
log.info(buf, "Phase1")
+20 -19
View File
@@ -249,7 +249,7 @@ def main() -> int:
if mf_inc_bin_asan is not None:
n_asan: int = Utils.CleanDir(mf_inc_bin_asan)
if log is not None:
fb_asan: t.CChar | t.CPtr = VLogger.fmt_buf()
fb_asan: str = VLogger.fmt_buf()
if fb_asan is not None:
viperlib.snprintf(fb_asan, 1024, "ASan 模式清理 includes 缓存: %d 个文件(将重建 asan obj)", n_asan)
log.info(fb_asan, "asan")
@@ -308,14 +308,14 @@ def main() -> int:
if Config.TempDir is not None:
n: int = Utils.CleanDir(Config.TempDir)
if log is not None:
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb: str = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "%s: 删除 %d 个文件", Config.TempDir, n)
log.info(fb, "clean")
if Config.OutputDir is not None:
n2: int = Utils.CleanDir(Config.OutputDir)
if log is not None:
fb2: t.CChar | t.CPtr = VLogger.fmt_buf()
fb2: str = VLogger.fmt_buf()
if fb2 is not None:
viperlib.snprintf(fb2, 1024, "%s: 删除 %d 个文件", Config.OutputDir, n2)
log.info(fb2, "clean")
@@ -324,7 +324,7 @@ def main() -> int:
if mf_inc_bin_clean is not None:
n3: int = Utils.CleanDir(mf_inc_bin_clean)
if log is not None:
fb3: t.CChar | t.CPtr = VLogger.fmt_buf()
fb3: str = VLogger.fmt_buf()
if fb3 is not None:
viperlib.snprintf(fb3, 1024, "%s: 删除 %d 个文件", mf_inc_bin_clean, n3)
log.info(fb3, "clean")
@@ -338,7 +338,7 @@ def main() -> int:
if mf_inc_bin_rb is not None:
n_rb: int = Utils.CleanDir(mf_inc_bin_rb)
if log is not None:
fb_rb: t.CChar | t.CPtr = VLogger.fmt_buf()
fb_rb: str = VLogger.fmt_buf()
if fb_rb is not None:
viperlib.snprintf(fb_rb, 1024, "%s: 删除 %d 个文件(includes 将重新编译)", mf_inc_bin_rb, n_rb)
log.info(fb_rb, "rebuild-includes")
@@ -351,7 +351,7 @@ def main() -> int:
if Config.TempDir is not None:
n_cc: int = Utils.CleanDir(Config.TempDir)
if log is not None:
fb_cc: t.CChar | t.CPtr = VLogger.fmt_buf()
fb_cc: str = VLogger.fmt_buf()
if fb_cc is not None:
viperlib.snprintf(fb_cc, 1024, "%s: 删除 %d 个文件(.vpi/.stub.ll 缓存)", Config.TempDir, n_cc)
log.info(fb_cc, "clear-cache")
@@ -371,7 +371,7 @@ def main() -> int:
if string.strcmp(phase_mode, "2") == 0 or string.strcmp(phase_mode, "all") == 0:
do_phase2 = 1
if log is not None:
fb3: t.CChar | t.CPtr = VLogger.fmt_buf()
fb3: str = VLogger.fmt_buf()
if fb3 is not None:
viperlib.snprintf(fb3, 1024, "模式: %s (phase1=%d phase2=%d)", phase_mode, do_phase1, do_phase2)
log.info(fb3, "phase")
@@ -382,7 +382,9 @@ def main() -> int:
ph1_temp: str = Config.TempDir
if ph1_temp is None:
ph1_temp = "."
Phase1.RunPhase1(mb, Config.IncludesDirs, ph1_temp, log)
if Phase1.RunPhase1(mb, Config.IncludesDirs, ph1_temp, log) != 0:
VLogger.error("Phase1 失败,终止编译", "Phase1")
return 1
# 如果仅 Phase1(不执行 Phase2),直接退出
if do_phase2 == 0:
if log is not None:
@@ -440,7 +442,7 @@ def main() -> int:
ef.close()
src_path = path_buf
if log is not None:
fb4: t.CChar | t.CPtr = VLogger.fmt_buf()
fb4: str = VLogger.fmt_buf()
if fb4 is not None:
viperlib.snprintf(fb4, 1024, "入口文件: %s", src_path)
log.info(fb4, "project")
@@ -451,7 +453,7 @@ def main() -> int:
f: fileio.File | t.CPtr = fileio.File(src_path, fileio.MODE.R)
if f.closed:
if log is not None:
fb5: t.CChar | t.CPtr = VLogger.fmt_buf()
fb5: str = VLogger.fmt_buf()
if fb5 is not None:
viperlib.snprintf(fb5, 1024, "无法打开文件: %s", src_path)
log.error(fb5, "fileio")
@@ -470,7 +472,7 @@ def main() -> int:
f.close()
if bytes_read < 0:
if log is not None:
fb6: t.CChar | t.CPtr = VLogger.fmt_buf()
fb6: str = VLogger.fmt_buf()
if fb6 is not None:
viperlib.snprintf(fb6, 1024, "读取文件失败 (错误码: %d)", bytes_read)
log.error(fb6, "fileio")
@@ -483,7 +485,7 @@ def main() -> int:
src_buf[SRC_BUF_SIZE - 1] = 0
if log is not None:
log.info("文件读取完成", "fileio")
fb7: t.CChar | t.CPtr = VLogger.fmt_buf()
fb7: str = VLogger.fmt_buf()
if fb7 is not None:
viperlib.snprintf(fb7, 1024, "读取 %d 字节", bytes_read)
log.info(fb7, "fileio")
@@ -518,7 +520,7 @@ def main() -> int:
# output_name 从文件名推导(如 test.vp -> test.exe),保持可读性
module_name: str = Utils.compute_sha1(mb, src_buf)
if module_name is None:
module_name = "main"
VLogger.error("SHA1 计算失败", "main")
output_name: str = "test_prog.exe"
# 从文件名提取 output_name(去掉路径和 .vp/.py 扩展名)
src_len: t.CSizeT = string.strlen(src_path)
@@ -632,9 +634,8 @@ def main() -> int:
final_ir = combined_buf
final_ir_len = combined_len
else:
if log is not None:
log.warning("BuildCombinedIR 失败,使用原始 IR", "stub")
stdlib.free(combined_buf)
VLogger.error("BuildCombinedIR 失败,终止编译", "stub")
br: BuildPipeline.BuildResult | t.CPtr = BuildPipeline.run_pipeline(
final_ir, final_ir_len, temp_dir, output_dir, module_name,
@@ -644,7 +645,7 @@ def main() -> int:
if br is not None and br.Success == 1:
if log is not None:
log.success("编译管线完成")
fb8: t.CChar | t.CPtr = VLogger.fmt_buf()
fb8: str = VLogger.fmt_buf()
if fb8 is not None:
viperlib.snprintf(fb8, 1024, "输出: %s/%s", output_dir, linker_output)
log.info(fb8)
@@ -654,14 +655,14 @@ def main() -> int:
if exe_path is not None:
viperlib.snprintf(exe_path, 256, "%s/%s", output_dir, linker_output)
if log is not None:
fb9: t.CChar | t.CPtr = VLogger.fmt_buf()
fb9: str = VLogger.fmt_buf()
if fb9 is not None:
viperlib.snprintf(fb9, 1024, "执行: %s", exe_path)
log.info(fb9, "run")
r: subprocess.CompletedProcess | t.CPtr = subprocess.run(exe_path, False, False)
if r is not None:
if log is not None:
fb10: t.CChar | t.CPtr = VLogger.fmt_buf()
fb10: str = VLogger.fmt_buf()
if fb10 is not None:
viperlib.snprintf(fb10, 1024, "退出码: %d", r.returncode)
log.info(fb10, "run")
@@ -669,7 +670,7 @@ def main() -> int:
if log is not None:
log.error("编译管线失败", "pipeline")
if br is not None and br.ErrorMsg is not None:
fb11: t.CChar | t.CPtr = VLogger.fmt_buf()
fb11: str = VLogger.fmt_buf()
if fb11 is not None:
viperlib.snprintf(fb11, 1024, "编译管线失败: %s", br.ErrorMsg)
log.error(fb11, "FATAL")