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:
1 parent
8f484f6860
commit
9d3483e97e
39 files changed
+1086
-738
No files matched your search
@@ -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:
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 路径配置)",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 再越界
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 变量
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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 个槽位)
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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 的方法
|
||||
|
||||
@@ -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 模式):
|
||||
|
||||
@@ -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,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)等情况
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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 字节步长
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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:
|
||||
|
||||
@@ -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
@@ -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")
|
||||
|
||||
Reference in new issue
Block a user