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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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