import lib.core.Gen.GenTypes as GenTypes import t, c from stdint import * import ast import llvmlite import memhub import string import stdio import viperlib import lib.core.Gen.Translator as HT import lib.Stub.StubMerger.StubMergerStore as StubMergerStore import lib.core.Gen.Expr.ExprGenBase as ExprGenBase import lib.core.Gen.GenApi as GenApi # ============================================================ # ExprGenName - ExprGenMixin 拆分(阶段 D):Name/Subscript/下标访问 # ============================================================ novirtual class ExprGenName(ExprGenBase.ExprGenBase): """Name/Subscript/下标访问""" def _cut_from_import_mod(self, pool: memhub.MemBuddy*, raw: str) -> str: """截断 lookup_from_import 返回的模块名到独立缓冲 lookup_from_import 返回指向 from_imports 内部的指针(非 NUL 结尾, 后随空格分隔的其他条目,如 "ast.tokens TokenType:ast.tokens ...")。 不截断则 LookupSha1ByModName 收到整串查不到 → mangle 退化裸名 → 全局引用不带 SHA1 前缀 → 链接 undefined symbol(_op_head 根因, 对齐 ExprGenCdef._lookup_cross_module_cdefine 的截断逻辑)。 截断到空格/冒号/NUL;raw 无效返回 None。 """ if raw is None: return None mbl_c: sizet = 0 while raw[mbl_c] != ' ' and raw[mbl_c] != '\0' and raw[mbl_c] != ':': mbl_c += 1 if mbl_c == 0: return None buf_c: str = pool.alloc(mbl_c + 1) if buf_c is None: return None string.strncpy(buf_c, raw, mbl_c) buf_c[mbl_c] = '\0' return buf_c def translate_name_value(self, builder: llvmlite.IRBuilder*, pool: memhub.MemBuddy*, node: ast.AST*, trans: HT.Translator* = None, target_ty: llvmlite.LLVMType* = None, use_ctx: str = None) -> llvmlite.Value*: """翻译变量引用(Name 节点)→ load target_ty:调用方(translate_value)下传的**使用处类型**(赋值目标 / 形参类型 / 返回类型)。被两处读取:① 下方 CDefine 整数常量物化点 (决定物化宽度);② **结构体值局部变量**在使用处明确要求同型结构体值时 改为 load 出值(见下方 Struct 分支说明)。其余变量 load 逐字沿用原有逻辑。 use_ctx:使用处**真实站点种类**标签,仅透传给宽度不足报文(见 cdefine_use_width_value),不参与任何判定。 """ # mod 必须取自 trans.Module:函数签名无 mod 参数,若用裸名 mod 会被 # 解析为 None → create_global_string 的 module_add_global(None, gv) 被 # add_global 的 `if self is None: return` 静默丢弃 → 字符串 CDefine 的 # global 定义丢失但 _label_counter/IR 引用已生成 → llc 报 # "use of undefined value '@.str.{sha1}.N'(SysLibTest _cleanup 根因)" mod: llvmlite.LLVMModule* = trans.Module nm: ast.Name* = ast.Name*(node) if nm is None: return None nm_id: str = nm.id if nm_id is None: return None # CDefine 编译期常量:返回常量值(浮点 CDefine → double 常量,整数 → i32;否则 double 函数里 return 会生成 ret i32 0 报错)。注意同名变量优先——当前作用域已存在变量时不得被 CDefine 表条目遮蔽(vpi stub 注入会把依赖模块的 CDefine 注册进导入方表,可能误解析局部变量为常量),守卫与下方跨模块 CDefine 查找的 lookup_var 检查一致 cdef_val_d: double = self.Gen.TypeGenCDef.lookup_cdefine_double(nm_id) if self.Gen.TypeGenCDef.is_cdefine_found() != 0: if trans is None or self.Gen.VarGen.lookup_var(trans.SymTab, nm_id) is None: if self.Gen.TypeGenCDef.is_cdefine_str() != 0: # 字符串 CDefine(如 ZLIB_VERSION: t.CDefine = "1.3.2"): # 返回 global string(i8*),供 return ZLIB_VERSION 等使用。 cdef_sv: str = self.Gen.TypeGenCDef.lookup_cdefine_string(nm_id) if cdef_sv is not None: return self.Gen.ExprGenConst.create_global_string(builder, pool, mod, cdef_sv, trans) self.Gen.TypeGenErr.fatal_error(node, f"CDefine 字符串值缺失: {nm_id}", "InternalCompilerError") if self.Gen.TypeGenCDef.is_cdefine_double() != 0: return llvmlite.ConstFloat(pool, llvmlite.Double(pool), cdef_val_d) # 整数 CDefine:重新查表取 64 位全精度值(double 往返会丢精度, # 9223372036854775807 → 9.223372036854776e18 舍入错位,生成错常量) cdef_val_c: int64 = self.Gen.TypeGenCDef.lookup_cdefine_constant(nm_id) # 使用处宽度(经 translate_value 的 target_ty 下传;站点种类由 # use_ctx 携带,仅供报文使用): # 更宽 ⇒ 就地升宽物化;更窄 ⇒ fail-fast;取不到 ⇒ 既有默认 32/64。 uw_val: llvmlite.Value* = self.Gen.ExprGenCdef.cdefine_use_width_value(pool, node, nm_id, cdef_val_c, target_ty, use_ctx) if uw_val is not None: return uw_val return self.Gen.ExprGenCdef._const_int_for_cdefine(pool, cdef_val_c) # 本地表未找到:尝试跨模块 .vpi 查找(保证多模块查表存表一致) # 仅对符合 CDefine 命名约定(ALL_CAPS)的名字触发跨模块查找, # 避免对普通变量名(mb/name/ptr/pool/self 等)误触发,造成严重性能损耗 if self.Gen.ExprGenCdef._is_cdefine_name_pattern(nm_id) != 0: if trans is not None: # ALL_CAPS 也可能是普通变量(如 Gargantua 的 # CAM/FWD/RIGHT/UP: V3|t.CPtr 模块级全局)。若当前作用域 # (含模块级 Root,lookup_var 逐级上溯)已存在同名变量, # 优先按变量处理,跳过跨模块 CDefine 查找——否则 ALL_CAPS # 命中 star-import 模块(from stdint import *)→ 无谓读源 # 文件,且多 includes 目录下还可能触发 XMOD-CD 误报 # (ExprGenCdef._build_source_path_from_sha1 拼错路径)。 if self.Gen.VarGen.lookup_var(trans.SymTab, nm_id) is None: cdef_val: int64 = self.Gen.ExprGenCdef._lookup_cross_module_cdefine(pool, nm_id, trans._from_imports, trans._imported_modules, 0, node) if self.Gen.TypeGenCDef.is_cdefine_found() != 0: if self.Gen.TypeGenCDef.is_cdefine_str() != 0: cdef_sv2: str = self.Gen.TypeGenCDef.lookup_cdefine_string(nm_id) if cdef_sv2 is not None: return self.Gen.ExprGenConst.create_global_string(builder, pool, mod, cdef_sv2, trans) self.Gen.TypeGenErr.fatal_error(node, f"CDefine 字符串值缺失: {nm_id}", "InternalCompilerError") # 跨模块浮点 CDefine 已缓存为 double(is_cdefine_double), # 需返回浮点常量而非截断的整数 dchk_nm: double = self.Gen.TypeGenCDef.lookup_cdefine_double(nm_id) if self.Gen.TypeGenCDef.is_cdefine_double() != 0: return llvmlite.ConstFloat(pool, llvmlite.Double(pool), dchk_nm) # 使用处宽度同口径(跨模块 CDefine) uw_x: llvmlite.Value* = self.Gen.ExprGenCdef.cdefine_use_width_value(pool, node, nm_id, cdef_val, target_ty, use_ctx) if uw_x is not None: return uw_x return self.Gen.ExprGenCdef._const_int_for_cdefine(pool, cdef_val) # CDefine 查找失败:from-import 的模块级全局变量(如 # from Phase1 import PYI_BUF_SIZE;PYI_BUF_SIZE: sizet = 262144 是 # i64 全局、非宏,语义同 C 的 extern size_t PYI_BUF_SIZE)。from-import # 确认名称确实来自某模块后,按后缀匹配查找该全局并加载。 if trans is not None and trans._from_imports is not None: fi_mod_raw: str = self.Gen.ImportsGen.lookup_from_import(trans._from_imports, nm_id, 0) if fi_mod_raw is not None: # 带源模块 SHA1 前缀精确查找,避免多模块同名全局后缀匹配串扰。 # fi_mod_raw 非 NUL 结尾,先截断再查 SHA1(否则整串查不到退化裸名) fi_mod_cut: str = self._cut_from_import_mod(pool, fi_mod_raw) if fi_mod_cut is None: fi_mod_cut = fi_mod_raw fi_gv_q: str = self.Gen.FuncGenBase._mangle_name_with_sha1(StubMergerStore.LookupSha1ByModName(fi_mod_cut), nm_id) fi_gv: llvmlite.GlobalVariable* = self.Gen.ExprGenAttr.find_global_in_module(trans.Module, fi_gv_q) if fi_gv is not None and fi_gv.Ty is not None: fi_ref: llvmlite.Value* = self.Gen.ExprGenAttr.make_global_ref(pool, fi_gv.Name, fi_gv.Ty) if fi_ref is not None and fi_ref.Ty is not None: fi_pty: llvmlite.LLVMType* = fi_ref.Ty.Pointee if fi_pty is not None: match fi_pty: case llvmlite.LLVMType.Array(_, _): # 数组全局按 C 语义退化为基址(对齐 L3383-3388) return fi_ref case _: pass return llvmlite.build_load(builder, fi_pty, fi_ref) # global 变量:从模块作用域查找(global 声明优先级最高) if trans is not None: if GenApi.is_global_name(trans, nm_id) != 0: mod_alloca: llvmlite.Value* = self.Gen.VarGen.lookup_module_var(trans.SymTab, nm_id) if mod_alloca is not None: load_ty: llvmlite.LLVMType* = None if mod_alloca.Ty is not None: load_ty = mod_alloca.Ty.Pointee if load_ty is None: # fail-fast:global 变量存储类型缺失,立即终止编译(暴露上游根因) self.Gen.TypeGenErr.fatal_error(node, f"变量 '{nm_id}' 存储类型缺失", "TypeError") # 全局数组(如 pyzlib.pyzlib_error_msg: CArray[char, 512]): # 按 C 语义衰减为基址返回(对齐下方局部数组分支 L3383-3388)。 # 否则 load [512 x i8] 数组值当 i8* 传 → set_error 的 strncpy # dest 是数组值(栈拷贝)而非数组基址 → 写入丢失 → get_error # 为空(test_pyzlib "error message is empty" 根因)。 match load_ty: case llvmlite.LLVMType.Array(_, _): return mod_alloca case _: pass # t.CVolatile 全局:load 带 volatile 限定符(禁优化器消除重复读) vol_g: int = 0 if trans is not None: ve_g: GenTypes.VarEntry* = self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm_id) vol_g = self.Gen.VarGen.var_is_volatile(ve_g) return llvmlite.build_load(builder, load_ty, mod_alloca, vol_g) # nonlocal 变量:通过闭包 env 访问 if GenApi.is_nonlocal_name(trans, nm_id) != 0: return self.Gen.StmtGenDecl.load_nonlocal_var(trans, nm_id) # *args va_list:变量名直接解析为指向 24 字节 va_list 缓冲区的 i8* 地址 # (对齐 TPC _direct_values[vararg_name] = va_list_ptr;不 load 缓冲区内容, # 转发时按值传该地址即可,如 sprintf → vsnprintf(..., args)) if trans is not None and trans._vararg_name is not None: if nm_id is not None and string.strcmp(nm_id, trans._vararg_name) == 0: if trans._va_list_ptr is not None: return trans._va_list_ptr # 局部变量查找(必须先于模块别名检查) # 否则与模块同名的局部变量(如 `import t, c` 后的局部变量 c)会被误判为模块别名, # 导致 SymTab 已注册的局部变量查找不到(rhs_val is None bug 根因) alloca: llvmlite.Value* = self.Gen.VarGen.lookup_var(trans.SymTab, nm_id) if alloca is not None: load_ty: llvmlite.LLVMType* = None if alloca.Ty is not None: load_ty = alloca.Ty.Pointee if load_ty is None: # fail-fast:局部变量存储类型缺失,立即终止编译(暴露上游根因) self.Gen.TypeGenErr.fatal_error(node, f"变量 '{nm_id}' 存储类型缺失", "TypeError") # 结构体值变量(alloca 类型为 Struct,如 `addr: SocketAddr`): # 右值默认按"对象即指针"语义返回其地址(alloca 指针),而非加载结构体值—— # 加载值后无法参与 ptrtoint/方法接收者等地址相关操作 # (会造成 `ptrtoint %Struct … to i64` 无效指令,llc invalid cast opcode)。 # 使用处**明确要求同型结构体值**时才 load 出值,见下方 Struct 分支。 match load_ty: case llvmlite.LLVMType.Struct(_, _, _): # 结构体值局部变量的右值默认返回 alloca 地址("对象即指针"语义; # 字段访问基座 / c.Addr 取址 / 方法接收者都在**别的**路径直接取地址, # 不经此处)。但使用处**明确要求同型的非指针结构体值**时必须像标量 # 一样 load 出值,否则调用方 coerce_to_type 会以 # 「非基本类型的值/指针隐式转换已禁止(构造物化除外)」拒绝: # 现场 includes/socket.vp:121 `return addr` —— _MakeAddr 的返回类型 # 是结构体值 SocketAddr,而 addr 是结构体值局部变量, # 源 %"…SocketAddr"* → 目标 %"…SocketAddr"。 # 判据用 _same_agg_ty(同一非基本类型),保证 load 后类型与使用处 # 完全一致;target_ty 为指针时(裸类形参 = Ptr(struct))不命中, # 故 point_sum(p) 这类实参传址行为不变。 if target_ty is not None: if self.Gen.ExprGenBase._same_agg_ty(pool, load_ty, target_ty) != 0: vol_s: int = 0 if trans is not None: ve_s: GenTypes.VarEntry* = self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm_id) vol_s = self.Gen.VarGen.var_is_volatile(ve_s) return llvmlite.build_load(builder, load_ty, alloca, vol_s) return alloca case llvmlite.LLVMType.Array(_, _): # 数组变量按 C 语义退化为指针(返回数组基址),而非整体 # load 数组值——如 printf("%s", str_arr) 应传数组首地址, # load [N x i8] 值传给 %s 会读到错误数据崩溃 # (ClassArrayTest TestCharArray 运行时崩溃根因)。 return alloca # t.CVolatile 局部变量:load 带 volatile 限定符 vol_l: int = 0 if trans is not None: ve_l: GenTypes.VarEntry* = self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm_id) vol_l = self.Gen.VarGen.var_is_volatile(ve_l) return llvmlite.build_load(builder, load_ty, alloca, vol_l) # REPL 模式(M2)会话变量:局部表未命中的名字若是会话变量,从 ctx 槽按类型读回。 # 位置在两处:① 局部查找之后(片段自己声明的局部名/参数优先,走原路径); # ② 模块别名/模块函数引用之前(会话名不得被 printf 等本模块 declare 抢走)。 # 非 REPL(trans.ReplCtx is None)时 repl_try_read 立即返回 None ⇒ 原路径逐字不变。 if trans is not None and trans.ReplCtx is not None: sess_val: llvmlite.Value* = self.Gen.VarGen.repl_try_read(trans, nm_id, node) if sess_val is not None: return sess_val # 模块别名检查:SymTab 查找失败后才检查 # 如果 nm_id 是已导入模块名(如 win32file, fileio)且未被声明为局部变量, # 返回 None 让上层处理(用于属性访问 win32file.CreateFileA) if trans is not None and trans._imported_modules is not None: if self.Gen.ImportsGen.is_module_imported(trans._imported_modules, nm_id) != 0: return None # 模块级函数引用:函数名作为值传递(如 CreateThread(..., _thread_alloc_free, ...))。 # 之前缺失此查找导致函数名参数翻译返回 None 被跳过,后续参数整体前移 # (lpStartAddress 变成对象地址,线程从数据区执行直接崩溃)。 # 注意:不能直接返回 Function 对象,也不能直接 build_bitcast(Function)—— # Function 布局是 {Next, Name, RetTy, Params, ...},value_get_ty 会错位读到 # Name 字段,TypePrint 输出 "void",生成 `bitcast void ... to i8*` 非法 IR; # 且 Function.Next 是模块函数链表指针,参数链表构建对其赋值会截断函数链表, # 最终打印出 `declare void @()` 空名函数。正确做法:按 Function 的 # RetTy/Params 构造真实函数类型,用 new_value 包装成普通 Value 再 bitcast。 if trans is not None and trans.Module is not None: fn_ref: llvmlite.Function* = self.Gen.CallGenBase.find_func_in_module(trans.Module, nm_id) if fn_ref is not None: fn_name: str = llvmlite.function_get_name(fn_ref) if fn_name is None: return None # 构造函数类型:ret_ty + 参数 ParamNode 链表 fn_ret_ty: llvmlite.LLVMType* = llvmlite.function_get_ret_ty(fn_ref) if fn_ret_ty is None: # fail-fast:函数返回类型缺失,无法构造函数指针(暴露上游根因) self.Gen.TypeGenErr.fatal_error(node, f"函数 '{nm_id}' 返回类型缺失,无法构造函数指针", "TypeError") fn_pp: llvmlite.Param* = llvmlite.function_get_param_head(fn_ref) fn_first_node: llvmlite.ParamNode* = None fn_prev_node: llvmlite.ParamNode* = None fn_pcount: int = 0 while fn_pp is not None: fn_pty: llvmlite.LLVMType* = llvmlite.param_get_ty(fn_pp) fn_pn: llvmlite.ParamNode* = llvmlite.new_param_node(pool, fn_pty) if fn_pn is not None: if fn_first_node is None: fn_first_node = fn_pn if fn_prev_node is not None: llvmlite.paramnode_set_next(fn_prev_node, fn_pn) fn_prev_node = fn_pn fn_pcount += 1 fn_pp = llvmlite.param_get_next(fn_pp) fn_ty: llvmlite.LLVMType* = llvmlite.Func(pool, fn_ret_ty, fn_first_node, fn_pcount) if fn_ty is None: return None # 构造函数指针 Value(new_value 包装,避免触碰 Function.Next) fn_ref_v: llvmlite.Value* = llvmlite.new_value(pool) if fn_ref_v is None: 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: str = pool.alloc(256) if fn_ref_name is not None: fn_ref_name[0] = '\0' if self.Gen.ClassGenVTable._vtable_name_needs_quote(fn_name) != 0: viperlib.snprintf(fn_ref_name, 256, "@\"%s\"", fn_name) else: viperlib.snprintf(fn_ref_name, 256, "@%s", fn_name) llvmlite.value_set_name(fn_ref_v, fn_ref_name) fn_i8ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, llvmlite.Int8(pool)) return llvmlite.build_bitcast(builder, fn_ref_v, fn_i8ptr_ty) # ============================================================ # 跨模块 from-import 全局变量读取(如 from .tokens import _op_head) # 根因:模块级全局(非 CDefine/非函数)from-import 后无本模块 SymTab # 条目,所有查找路径未命中 → translate_name_value 返回 None → 赋值被 # 静默跳过 → 变量未初始化 → 垃圾指针解引用崩溃(AstTest 的 # _read_operator 里 `cur = _op_head` 丢失导致 while 循环读未初始化 %6)。 # 语义对齐模块属性全局(sys._mbuddy):external @{全局名} 引用 + load, # 定义由源模块提供(COFF 按名链接)。别名导入用源模块内真实名。 # ============================================================ if trans is not None and trans._from_imports is not None: if trans.Module is not None: # 是 from-import 名称(禁用 star 回退,避免误归 star 模块) fi_mod: str = self.Gen.ImportsGen.lookup_from_import(trans._from_imports, nm_id, 0) if fi_mod is not None: # 排除已注册类名/枚举名:这些是类型,不作为全局变量值读取 fi_is_class: int = 0 if self.Gen.StructGen.get_struct_type(nm_id) is not None: fi_is_class = 1 # 排除 ALL_CAPS CDefine(上方已处理本地+跨模块查找) if self.Gen.ExprGenCdef._is_cdefine_name_pattern(nm_id) != 0: fi_is_class = 1 if fi_is_class == 0: fi_gname: str = nm_id fi_orig: str = self.Gen.ImportsGen.lookup_from_import_original(trans._from_imports, nm_id) if fi_orig is not None: og_len_fi: sizet = 0 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: 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 已注入全局(精确类型)→ 直接引用;未注入 → fail-fast # (不再创建 external i8* 声明,否则 llc 报 "use of undefined value", # 静默回退掩盖 stub 未注入的上游根因) # 带源模块 SHA1 前缀精确查找(避免多模块同名全局后缀匹配串扰); # fi_mod 非 NUL 结尾,先截断再查 SHA1(否则退化裸名 → undefined) fi_mod_cut2: str = self._cut_from_import_mod(pool, fi_mod) if fi_mod_cut2 is None: fi_mod_cut2 = fi_mod gv_fi_q: str = self.Gen.FuncGenBase._mangle_name_with_sha1(StubMergerStore.LookupSha1ByModName(fi_mod_cut2), fi_gname) gv_fi: llvmlite.GlobalVariable* = self.Gen.ExprGenAttr.find_global_in_module(trans.Module, gv_fi_q) ref_fi: llvmlite.Value* = None if gv_fi is not None and gv_fi.Ty is not None: ref_fi = self.Gen.ExprGenAttr.make_global_ref(pool, gv_fi.Name, gv_fi.Ty) else: # 依赖模块 vpi/stub 未注入:Phase A 按文件序翻译时依赖模块 # (如 lexer 先于 ast.tokens)可能晚于本文件,其 .vpi 尚未生成 # (LoadDepVpiIntoModule 无从注入)→ 返回 None,不在此 # fail-fast——否则清缓存后 lexer 先于 tokens 翻译必然误报 # "stub 未注入"。 return None if ref_fi is not None and ref_fi.Ty is not None: lty_fi: llvmlite.LLVMType* = ref_fi.Ty.Pointee if lty_fi is not None: return llvmlite.build_load(builder, lty_fi, ref_fi) return ref_fi # 所有查找路径均失败 # 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 self.Gen.TypeGenErr.fatal_error(node, f"未定义名称 '{nm_id}'", "NameError") return None # ============================================================ # list_getitem_inline — 内联生成 list[T] __getitem__ 逻辑 # # list 结构布局 (6 字段 × 8 字节): # __data__(0) __count__(8) __capacity__(16) __pool__(24) __elem_size__(32) __iter_index__(40) # 返回元素地址 (i8*),调用方根据元素类型 load 正确的值 # ============================================================ def list_getitem_inline(self, builder: llvmlite.IRBuilder*, pool: memhub.MemBuddy*, lm_obj: llvmlite.Value*, idx_val: llvmlite.Value*, node: ast.AST* = None) -> llvmlite.Value*: """内联生成 list __getitem__ 逻辑,返回元素地址 (i8*)""" if builder is None or pool is None or lm_obj is None or idx_val is None: return None i64_ty: llvmlite.LLVMType* = llvmlite.Int64(pool) i8_ty: llvmlite.LLVMType* = llvmlite.Int8(pool) i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty) # 加载 __data__ (偏移 0, index 0) g_idx0: llvmlite.Value* = llvmlite.const_int64(pool, 0) g_dpp: llvmlite.Value* = llvmlite.build_gep(builder, i64_ty, lm_obj, g_idx0) if g_dpp is None: return None g_data: llvmlite.Value* = llvmlite.build_load(builder, i8_ptr_ty, g_dpp) # 加载 __elem_size__ (偏移 32, index 4) g_idx4: llvmlite.Value* = llvmlite.const_int64(pool, 4) g_epp: llvmlite.Value* = llvmlite.build_gep(builder, i64_ty, lm_obj, g_idx4) if g_epp is None: return None g_esize: llvmlite.Value* = llvmlite.build_load(builder, i64_ty, g_epp) if g_data is None or g_esize is None: return None g_idx_i64: llvmlite.Value* = self.coerce_to_type(builder, idx_val, i64_ty, node) if g_idx_i64 is None: return None g_offset: llvmlite.Value* = llvmlite.build_mul(builder, g_idx_i64, g_esize) if g_offset is None: return None # 返回元素地址 (i8*),不 load return llvmlite.build_gep(builder, i8_ty, g_data, g_offset) # ============================================================ # _list_elem_type_from_name — 从 list 类型名提取元素 LLVM 类型 # # 类型名格式: .list[] # 用 strstr 检查完整模式,避免子串提取 # 支持: list[int]→i32, list[str]/list[bytes]→i8*, list[CInt]→i32 等 # 默认: i32 # ============================================================ def _list_elem_type_from_name(self, pool: memhub.MemBuddy*, struct_name: str) -> llvmlite.LLVMType*: """从 list 类型名提取元素 LLVM 类型""" if pool is None or struct_name is None: return None # 用 strstr 检查完整模式 if string.strstr(struct_name, "list[int]") is not None: return llvmlite.Int32(pool) if string.strstr(struct_name, "list[CInt]") is not None: return llvmlite.Int32(pool) if string.strstr(struct_name, "list[CInt8T]") is not None: return llvmlite.Int8(pool) if string.strstr(struct_name, "list[CInt16T]") is not None: return llvmlite.Int16(pool) if string.strstr(struct_name, "list[CInt32T]") is not None: return llvmlite.Int32(pool) if string.strstr(struct_name, "list[CInt64T]") is not None: return llvmlite.Int64(pool) if string.strstr(struct_name, "list[CSizeT]") is not None: return llvmlite.Int64(pool) if string.strstr(struct_name, "list[CDouble]") is not None: return llvmlite.Double(pool) if string.strstr(struct_name, "list[CFloat]") is not None: return llvmlite.Float(pool) if string.strstr(struct_name, "list[CChar]") is not None: return llvmlite.Int8(pool) # str/bytes/CPtr 等已知指针元素类型 → i8*(元素存储为 8 字节地址) i8_ty_d: llvmlite.LLVMType* = llvmlite.Int8(pool) 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) # 未知 list[T] 元素类型(自定义结构体元素,如 # list[rawptr[7565e081d88517ac.AST]] / list[sha1.Foo|t.CPtr]): # 元素槽存对象指针(8 字节)。从元素类型文本还原对象指针 LLVM 类型 # Ptr(%Struct),使 list.get/__getitem__/pop 内联返回值的 LLVM 类型 # 携带元素原型类——链式方法调用(mod.children.get(0).kind())的接收者 # 才能经 LLVM 类型解析出类名 AST(T29 修复);否则统一 Ptr(i8) 丢失 # 类名,.kind() 被当未绑定外部函数(AstTest NewAstTest fatal: 'kind' # 根因:list 元素类名没有沿 get(0) 调用结果值类型传播到后续分派)。 elem_obj_ty_l: llvmlite.LLVMType* = \ self._list_elem_obj_ty_from_struct_name(pool, struct_name) if elem_obj_ty_l is not None: return elem_obj_ty_l # 结构体未注册(依赖模块未就绪等):回退 Ptr(i8)(8 字节槽位宽一致, # load 值正确),由 AnnotClassName/方法分派回退机制保证语义。 # 禁止 fail-fast(误杀合法自定义类元素列表的访问)。 return llvmlite.Ptr(pool, i8_ty_d) # ============================================================ # _list_elem_obj_ty_from_struct_name — 从 list 特化类型名还原元素对象指针类型 # # struct_name 形如 "{_list_sha1}.list[rawptr[{sha1}.AST]]" 或 # "{_list_sha1}.list[{sha1}.AST|t.CPtr]"(联合元素)。取 '[' 与最后 ']' # 之间的元素描述文本:剥 rawptr[...] 包装、按 '|' 联合分段、去首尾空白, # 逐段按已注册结构体还原(元素类带模块 SHA1 前缀时 find_struct 走 # find_struct_by_module 精确匹配,规避跨模块同名歧义);命中返回 # llvmlite.Ptr(entry.Ty)(list 元素槽 8 字节存对象指针)。全部未命中 # 返回 None(调用方回退 Ptr(i8) 旧行为,不影响已支持的内置元素)。 # ============================================================ def _list_elem_obj_ty_from_struct_name(self, pool: memhub.MemBuddy*, struct_name: str) -> llvmlite.LLVMType*: """从 list 特化类型名还原元素对象指针 LLVM 类型,失败返回 None""" if pool is None or struct_name is None: return None lb_e: str = string.strchr(struct_name, '[') if lb_e is None: return None rb_e: str = string.strrchr(struct_name, ']') if rb_e is None: return None elen_e: sizet = sizet(uint64(rb_e) - uint64(lb_e)) - 1 if elen_e == 0 or elen_e > 512: return None elem_buf_e: str = pool.alloc(elen_e + 1) if elem_buf_e is None: return None string.strncpy(elem_buf_e, lb_e + 1, elen_e) elem_buf_e[elen_e] = '\0' # 剥 rawptr[...] 包装(元素声明为对象指针,如 rawptr[sha1.AST]) cur_e: str = elem_buf_e if string.strncmp(cur_e, "rawptr[", 7) == 0: cur_e = cur_e + 7 # 按 '|' 联合分段(A|B),段内去首尾空白/尾部 ']'/引号;段文本直接 # 交给 find_struct(内置名 CPtr/str/int 等不注册 struct → 天然返回 # None 跳过;带 "sha1.Class" 前缀走模块归属精确匹配) total_e: sizet = string.strlen(cur_e) seg_s_e: sizet = 0 i_e: sizet = 0 while i_e <= total_e: hit_e: int = 0 if i_e == total_e: hit_e = 1 elif cur_e[i_e] == '|': hit_e = 1 if hit_e == 0: i_e += 1 continue b_e: sizet = i_e a_e: sizet = seg_s_e # 尾部另需剥 '*':实参归一后元素文本是 `T*` 形(如 "{sha}.AST*", # 见 TypeGenResolve._norm_type_arg_name 的指针书写归一),而 # find_struct 只认类名本身;不剥则对象元素还原失败、静默退回 Ptr(i8) # 丢元素类名(链式 .get(0).kind() 分派回退根因)。 while b_e > a_e and (cur_e[b_e - 1] == ' ' or cur_e[b_e - 1] == ']' \ or cur_e[b_e - 1] == '\'' or cur_e[b_e - 1] == '"' \ or cur_e[b_e - 1] == '*'): b_e -= 1 while a_e < b_e and (cur_e[a_e] == ' ' or cur_e[a_e] == '\'' \ or cur_e[a_e] == '"'): a_e += 1 if b_e > a_e: seg_len_e: sizet = b_e - a_e if seg_len_e < 256: seg_buf_e: str = pool.alloc(seg_len_e + 1) if seg_buf_e is not None: string.strncpy(seg_buf_e, cur_e + a_e, seg_len_e) seg_buf_e[seg_len_e] = '\0' s_entry_e: GenTypes.StructEntry* = \ self.Gen.StructGen.find_struct(seg_buf_e) if s_entry_e is not None and s_entry_e.Ty is not None: return llvmlite.Ptr(pool, s_entry_e.Ty) if i_e == total_e: break seg_s_e = i_e + 1 i_e += 1 return None # ============================================================ # list_setitem_inline — 内联生成 list[T] __setitem__ 逻辑 # # 直接存储 rhs_val 到元素地址 (coerce 为 i8* 后 store) # ============================================================ def list_setitem_inline(self, builder: llvmlite.IRBuilder*, pool: memhub.MemBuddy*, lm_obj: llvmlite.Value*, idx_val: llvmlite.Value*, rhs_val: llvmlite.Value*, node: ast.AST* = None) -> int: """内联生成 list __setitem__ 逻辑,返回 0""" if builder is None or pool is None or lm_obj is None or idx_val is None or rhs_val is None: return 0 i64_ty: llvmlite.LLVMType* = llvmlite.Int64(pool) i8_ty: llvmlite.LLVMType* = llvmlite.Int8(pool) i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty) # 加载 __data__ (偏移 0, index 0) s_idx0: llvmlite.Value* = llvmlite.const_int64(pool, 0) s_dpp: llvmlite.Value* = llvmlite.build_gep(builder, i64_ty, lm_obj, s_idx0) if s_dpp is None: return 0 s_data: llvmlite.Value* = llvmlite.build_load(builder, i8_ptr_ty, s_dpp) # 加载 __elem_size__ (偏移 32, index 4) s_idx4: llvmlite.Value* = llvmlite.const_int64(pool, 4) s_epp: llvmlite.Value* = llvmlite.build_gep(builder, i64_ty, lm_obj, s_idx4) if s_epp is None: return 0 s_esize: llvmlite.Value* = llvmlite.build_load(builder, i64_ty, s_epp) if s_data is None or s_esize is None: return 0 s_idx_i64: llvmlite.Value* = self.coerce_to_type(builder, idx_val, i64_ty, node) if s_idx_i64 is None: return 0 s_offset: llvmlite.Value* = llvmlite.build_mul(builder, s_idx_i64, s_esize) if s_offset is None: return 0 s_addr: llvmlite.Value* = llvmlite.build_gep(builder, i8_ty, s_data, s_offset) if s_addr is None: return 0 # 元素类型 T:从 list 特化类型名解析(list[int]→i32、list[str]→i8*)。 # 此前固定 i8*(8 字节)store(inttoptr 值)覆盖相邻元素——与 # CallGenMixin list 内置分支同根因(ListTest pop FAILED expect 30)。 s_sty: llvmlite.LLVMType* = self.Gen.StructGen.get_struct_type_from_value(lm_obj) s_name: str = None if s_sty is not None: s_name = llvmlite.get_struct_name(s_sty) s_elem_ty: llvmlite.LLVMType* = None if s_name is not None: s_elem_ty = self._list_elem_type_from_name(pool, s_name) if s_elem_ty is None: s_elem_ty = i8_ptr_ty s_val_ptr: llvmlite.Value* = self.coerce_to_type(builder, rhs_val, s_elem_ty, node) if s_val_ptr is None: return 0 s_ep: llvmlite.Value* = llvmlite.build_bitcast(builder, s_addr, llvmlite.Ptr(pool, s_elem_ty)) if s_ep is not None: llvmlite.build_store(builder, s_val_ptr, s_ep) return 0 # ============================================================ # is_list_subscript — 检查 Subscript 节点是否是 list[T] 类型 # # 返回 list 对象指针 (Ptr(list[T])) 或 None # ============================================================ def is_list_subscript(self, node: ast.AST*, trans: HT.Translator*) -> llvmlite.Value*: """检查 Subscript 节点是否是 list[T] 类型,返回 list 对象指针或 None""" if node is None or trans is None: return None sub: ast.Subscript* = ast.Subscript*(node) if sub is None or sub.value is None: return None if sub.value.kind() != ast.ASTKind.Name: return None nm: ast.Name* = ast.Name*(sub.value) if nm is None or nm.id is None: return None alloca: llvmlite.Value* = self.Gen.VarGen.lookup_var(trans.SymTab, nm.id) if alloca is None or alloca.Ty is None: return None if self.is_ptr_type(alloca.Ty) == 0: return None pointee: llvmlite.LLVMType* = alloca.Ty.Pointee if pointee is None: return None # 检查 pointee 是否是 Ptr(Struct) inner_ty: llvmlite.LLVMType* = None match pointee: case llvmlite.LLVMType.Ptr(it): inner_ty = it case _: return None if inner_ty is None: return None # 检查 inner_ty 是否是 Struct 且名称包含 "list[" struct_name: str = None match inner_ty: case llvmlite.LLVMType.Struct(_, _, sname): struct_name = sname case _: return None if struct_name is None: return None if string.strstr(struct_name, "list[") is None: return None # 是 list 类型: load 出 list 对象指针 builder: llvmlite.IRBuilder* = trans._cur_builder return llvmlite.build_load(builder, pointee, alloca) # _nonlocal_subscript_ptr:nonlocal 数组/指针的下标元素指针——嵌套(提升)函数体内访问 nonlocal 变量时,其实际存储是运行时共享堆(env[ni] 存堆地址),不能 lookup_var 找外层函数 alloca(其 SSA 编号属外层函数,当前函数引用会错乱崩溃)。正确路径:从 env 读堆地址(_load_raw_var_ptr)→ bitcast → GEP def _nonlocal_subscript_ptr(self, builder: llvmlite.IRBuilder*, pool: memhub.MemBuddy*, trans: HT.Translator*, nm_id: str, idx_val: llvmlite.Value*) -> llvmlite.Value*: """nonlocal 数组/指针下标:从 env 读堆地址 → bitcast → GEP,返回元素指针""" if trans is None or nm_id is None or idx_val is None: return None nl_ty: llvmlite.LLVMType* = GenApi.get_nonlocal_type(trans, nm_id) if nl_ty is None: return None raw_nl: llvmlite.Value* = self.Gen.StmtGenDecl._load_raw_var_ptr(trans, nm_id) if raw_nl is None: return None match nl_ty: case llvmlite.LLVMType.Array(elem_ty_nl, _cnt_nl): arr_ptr_nl: llvmlite.Value* = llvmlite.build_bitcast(builder, raw_nl, llvmlite.Ptr(pool, nl_ty)) if arr_ptr_nl is None: return None return llvmlite.build_gep_array(builder, nl_ty, elem_ty_nl, arr_ptr_nl, self._zext_index_to_i32(builder, idx_val)) case llvmlite.LLVMType.Ptr(inner_nl): arr_ptr_nl2: llvmlite.Value* = llvmlite.build_bitcast(builder, raw_nl, llvmlite.Ptr(pool, nl_ty)) if arr_ptr_nl2 is None: return None return llvmlite.build_gep(builder, inner_nl, arr_ptr_nl2, idx_val) case _: arr_ptr_nl3: llvmlite.Value* = llvmlite.build_bitcast(builder, raw_nl, llvmlite.Ptr(pool, nl_ty)) if arr_ptr_nl3 is None: return None return llvmlite.build_gep(builder, nl_ty, arr_ptr_nl3, idx_val) return None # ============================================================ # 翻译下标表达式 Subscript(value, slice, ctx) — ptr[i] / arr[i] # # 指针遍历: ptr 是指针变量,load 出指针值后 GEP + load # 数组遍历: arr 是数组变量,用 alloca 指针做双索引 GEP [0, i] + load # list[T]: 泛型类不注册 struct,subscript 走 __getitem__ 内联路径 # ============================================================ def translate_subscript(self, builder: llvmlite.IRBuilder*, pool: memhub.MemBuddy*, mod: llvmlite.LLVMModule*, node: ast.AST*, trans: HT.Translator* = None) -> llvmlite.Value*: """翻译下标表达式,返回加载的元素值""" if node is None or builder is None: return None sub: ast.Subscript* = ast.Subscript*(node) if sub is None: return None # 切片形式 a[start:end](如 path[n:]):返回 i8* 基指针 + start 偏移。 # 此前 Slice AST 被当作单索引 translate_value → 无 Slice 分支返回 None → # 作为函数实参时整个参数被丢弃(spawn_elf 的 # create_process(path[n:], entry) 丢 name → entry 错位成第一参数 → # p.entry 垃圾 → 用户进程 iretq 到垃圾地址 → PF)。 if sub.slice is not None and sub.slice.kind() == ast.ASTKind.Slice: slc: rawptr[ast.Slice] = rawptr[ast.Slice](sub.slice) base_v: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, sub.value, None, 0, trans) if base_v is None: return None if slc.lower is None: return base_v start_v: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, slc.lower, None, 0, trans) if start_v is None: return None i64_sc: llvmlite.LLVMType* = llvmlite.Int64(pool) start_w: llvmlite.Value* = start_v if start_v.Ty is not None: bt_sc: int = self.Gen.ExprGenBase.get_llvm_type_bits(start_v.Ty) if bt_sc != 0 and bt_sc < 64: start_w = llvmlite.build_sext(builder, start_v, i64_sc) if start_w is None: return None i8_sc: llvmlite.LLVMType* = llvmlite.Int8(pool) return llvmlite.build_gep(builder, i8_sc, base_v, start_w) # 翻译索引 idx_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, sub.slice, None, 0, trans) if idx_val is None: return None # 嵌套下标读取: a[i][j] —— 递归取内层指针后 load # (与 get_subscript_ptr 嵌套分支对称;如 gfx.vp 的 # a.m[i][k] * b.m[k][j],内层 translate_value 会把行加载为 # Array 值(非指针)→ 通用路径失败 → "rhs 翻译失败") if sub.value is not None and sub.value.kind() == ast.ASTKind.Subscript: inner_ptr_r: llvmlite.Value* = self.get_subscript_ptr(builder, pool, mod, sub.value, trans) if inner_ptr_r is None or inner_ptr_r.Ty is None: return None inner_elem_r: llvmlite.LLVMType* = inner_ptr_r.Ty.Pointee if inner_elem_r is None: return None match inner_elem_r: case llvmlite.LLVMType.Array(arr_ie_r, _): elem_ptr_r: llvmlite.Value* = llvmlite.build_gep_array(builder, inner_elem_r, arr_ie_r, inner_ptr_r, self._zext_index_to_i32(builder, idx_val)) if elem_ptr_r is not None: return llvmlite.build_load(builder, arr_ie_r, elem_ptr_r) return None case _: elem_ptr_r2: llvmlite.Value* = llvmlite.build_gep(builder, inner_elem_r, inner_ptr_r, idx_val) if elem_ptr_r2 is not None: return llvmlite.build_load(builder, inner_elem_r, elem_ptr_r2) return None # 如果 value 是 Name,尝试从 alloca 类型推断 if sub.value is not None and sub.value.kind() == ast.ASTKind.Name: nm: ast.Name* = ast.Name*(sub.value) if nm.id is not None and trans is not None: # rawptr[t.CVolatile | T] 变量(volatile 指针指向物):本分支内 # 的**元素 load**(p[i] 解引用)带 volatile;仅读取指针值自身的 # load(alloca → 指针值)不带(那是指针变量而非所指物)。 vol_sub_rd: int = self.Gen.VarGen.var_pointee_is_volatile(self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm.id)) # nonlocal 数组/指针:从 env 读共享堆地址(提升函数内不能 # lookup_var 外层 alloca——SSA 编号跨函数错乱崩溃) # 读路径:元素指针 load 出元素值 if GenApi.is_nonlocal_name(trans, nm.id) != 0: nl_ptr_r: llvmlite.Value* = self._nonlocal_subscript_ptr(builder, pool, trans, nm.id, idx_val) if nl_ptr_r is not None and nl_ptr_r.Ty is not None: nl_elem_ty: llvmlite.LLVMType* = nl_ptr_r.Ty.Pointee if nl_elem_ty is not None: return llvmlite.build_load(builder, nl_elem_ty, nl_ptr_r) return None alloca: llvmlite.Value* = self.Gen.VarGen.lookup_var(trans.SymTab, nm.id) if alloca is not None and alloca.Ty is not None: if self.is_ptr_type(alloca.Ty) != 0: pointee: llvmlite.LLVMType* = alloca.Ty.Pointee if pointee is not None: # 不调用 pointee.kind() 避免跨模块引用 LLVMType.kind 符号 # 用 match 检查 pointee 类型 match pointee: case llvmlite.LLVMType.Array(elem_ty, count): # 数组遍历: getelementptr [N x elem_ty], ... , i32 0, i32 %idx elem_ptr: llvmlite.Value* = llvmlite.build_gep_array(builder, pointee, elem_ty, alloca, self._zext_index_to_i32(builder, idx_val)) if elem_ptr is not None: return llvmlite.build_load(builder, elem_ty, elem_ptr) return None case llvmlite.LLVMType.Struct(_fs_v, _fc_v, lsn_v): # list[T] 值变量(无注解赋值 rhs 返回 list 值, # 如 parts = s1.split(','):split 的 define 返回 # %list[str] 结构体值,alloca 直接存 list 对象)。 # alloca 即 list*,直接走 list 内联 __getitem__ #(对齐 Ptr(Ptr(list)) 变量路径,修复 parts[0] 崩溃) if lsn_v is not None: if string.strstr(lsn_v, "list[") is not None: elem_addr_v: llvmlite.Value* = self.list_getitem_inline(builder, pool, alloca, idx_val, node) if elem_addr_v is not None: elem_ty_v: llvmlite.LLVMType* = self._list_elem_type_from_name(pool, lsn_v) if elem_ty_v is not None: elem_ptr_ty_v: llvmlite.LLVMType* = llvmlite.Ptr(pool, elem_ty_v) casted_v: llvmlite.Value* = \ llvmlite.build_bitcast(builder, elem_addr_v, elem_ptr_ty_v) if casted_v is not None: return llvmlite.build_load(builder, elem_ty_v, casted_v) return None case llvmlite.LLVMType.Ptr(inner_ty): # 检查 inner_ty 是否是 list[T] 类型(泛型类不注册 struct) # list 的 subscript 应该走 __getitem__ 内联路径,而非指针遍历 list_struct_name: str = None match inner_ty: case llvmlite.LLVMType.Struct(_, _, lsn): list_struct_name = lsn case _: pass if list_struct_name is not None: if string.strstr(list_struct_name, "list[") is not None: # list[T] 类型: 内联生成 __getitem__ 逻辑 ptr_val_list: llvmlite.Value* = llvmlite.build_load(builder, pointee, alloca) if ptr_val_list is not None: elem_addr_list: llvmlite.Value* = self.list_getitem_inline(builder, pool, ptr_val_list, idx_val, node) if elem_addr_list is not None: # 根据类型名提取元素类型,bitcast 后 load elem_ty_list: llvmlite.LLVMType* = self._list_elem_type_from_name(pool, list_struct_name) if elem_ty_list is not None: elem_ptr_ty_list: llvmlite.LLVMType* = llvmlite.Ptr(pool, elem_ty_list) casted_addr_list: llvmlite.Value* = llvmlite.build_bitcast(builder, elem_addr_list, elem_ptr_ty_list) if casted_addr_list is not None: return llvmlite.build_load(builder, elem_ty_list, casted_addr_list) return None # inner_ty 是 Ptr 说明 alloca.Ty 是三重指针 Ptr(Ptr(Ptr(...))), # 即 X|t.CPtr 当 X 本身是指针类型 (如 T=AST|t.CPtr, T|t.CPtr=AST**)。 # 此时 [i] 应该是指针解引用 (步长 sizeof(ptr)=8), 而非调用 # 结构体的 __getitem__ 方法 (会错误生成 AST.__getitem__ 调用)。 # 对比 HashTable|t.CPtr: alloca.Ty=HashTable**, inner_ty=Struct(HashTable) # (非 Ptr), 仍走下面的方法调用转发路径。 if self.is_ptr_type(inner_ty) != 0: ptr_val_pp: llvmlite.Value* = llvmlite.build_load(builder, pointee, alloca) if ptr_val_pp is not None: elem_ptr_pp: llvmlite.Value* = llvmlite.build_gep(builder, inner_ty, ptr_val_pp, idx_val) if elem_ptr_pp is not None: # volatile 指针指向物:解引用 load 带 volatile return llvmlite.build_load(builder, inner_ty, elem_ptr_pp, vol_sub_rd) return None # 自定义结构体 (如 HashTable|t.CPtr, JsonValue|t.CPtr): # 仅当类定义了 __getitem__(当前模块定义或跨模块 stub declare 注入) # 才转发方法调用;否则普通结构体指针按下标做 GEP 数组访问 # (对齐 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: str = pool.alloc(128) if gi_lookup_rd is not None: viperlib.snprintf(gi_lookup_rd, 128, "%s.__getitem__", cls_nm_rd_ptr) if self.Gen.CallGenBase.find_func_in_module(mod, gi_lookup_rd) is not None: obj_ptr_rd: llvmlite.Value* = llvmlite.build_load(builder, pointee, alloca) if not (obj_ptr_rd is None): arg_vals_rd_p: sizet* = pool.alloc(8) if not (arg_vals_rd_p is None): arg_vals_rd_p[0] = sizet(idx_val) ret_rd_p: llvmlite.Value* = self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, cls_nm_rd_ptr, "__getitem__", obj_ptr_rd, arg_vals_rd_p, 1, trans, sub) if not (ret_rd_p is None): return ret_rd_p # 无 __getitem__:结构体指针数组访问(GEP + load) ptr_val_rd_g: llvmlite.Value* = llvmlite.build_load(builder, pointee, alloca) if ptr_val_rd_g is not None: elem_rd_g: llvmlite.Value* = llvmlite.build_gep(builder, inner_ty, ptr_val_rd_g, idx_val) if elem_rd_g is not None: # volatile 指针指向物:解引用 load 带 volatile return llvmlite.build_load(builder, inner_ty, elem_rd_g, vol_sub_rd) return None # bytes|t.CPtr / str|t.CPtr: alloca 是 i8**, # 直接 GEP 按 i8* 步长(8 字节),load i8* # 仅当 inner_ty 不是自定义结构体时才走指针遍历 if trans is not None: ve_pe_ts: GenTypes.VarEntry* = \ self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm.id) if self.Gen.VarGen.var_is_ptr_element(ve_pe_ts) != 0: # bytes|t.CPtr / str|t.CPtr / T|t.CPtr:变量存指针值(i8*), # elem[i] 语义 = load [指针值 + i*8](8 字节指针元素)。 # 必须先 load alloca 得指针值,再 GEP i8*(步长 8)—— # 否则 GEP base 用 alloca(&elem_ptr)读到栈变量而非数据区, # list.get 返回"元素地址"而非"元素值"(dump 虚调用读错 vtable)。 ptr_val_pe_ts: llvmlite.Value* = llvmlite.build_load(builder, pointee, alloca) if ptr_val_pe_ts is not None: elem_ptr_ts: llvmlite.Value* = llvmlite.build_gep(builder, pointee, ptr_val_pe_ts, idx_val) if elem_ptr_ts is not None: # volatile 指针指向物:解引用 load 带 volatile return llvmlite.build_load(builder, pointee, elem_ptr_ts, vol_sub_rd) return None # 普通指针遍历: 先 load 指针值,再 GEP ptr_val: llvmlite.Value* = llvmlite.build_load(builder, pointee, alloca) if ptr_val is not None: elem_ptr2: llvmlite.Value* = llvmlite.build_gep(builder, inner_ty, ptr_val, idx_val) if elem_ptr2 is not None: # volatile 指针指向物:解引用 load 带 volatile return llvmlite.build_load(builder, inner_ty, elem_ptr2, vol_sub_rd) return None case _: # 联合类型变量(IsPtrElement=1,如 _list.vp 的 # elem_ptr: T | t.CPtr 退化为 i8*):pointee=i8 但 # 元素是 8 字节指针,须按 i8* 步长 GEP + load i8*—— # 否则 list.get 只读 1 字节,指针截断 inttoptr 崩溃。 if trans is not None: ve_pe_rd: GenTypes.VarEntry* = \ self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm.id) if self.Gen.VarGen.var_is_ptr_element(ve_pe_rd) != 0: match pointee: case llvmlite.LLVMType.Int(bits_rd): if bits_rd == 8: i8_ptr_rd: llvmlite.LLVMType* = llvmlite.Ptr(pool, llvmlite.Int8(pool)) elem_ptr_rd: llvmlite.Value* = llvmlite.build_gep(builder, i8_ptr_rd, alloca, idx_val) if elem_ptr_rd is not None: return llvmlite.build_load(builder, i8_ptr_rd, elem_ptr_rd) case _: pass # 自定义类(结构体类型): 仅当类定义了 __getitem__ # (当前模块定义或跨模块 stub declare 注入)才转发方法调用; # 否则普通结构体指针按下标做 GEP 数组访问 cls_nm_sub: str = self.Gen.StructGen.get_class_name_by_type(pool, pointee) if not (cls_nm_sub is None): 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 self.Gen.CallGenBase.find_func_in_module(mod, gi_lookup_sub) is not None: obj_val_sub: llvmlite.Value* = llvmlite.build_load(builder, pointee, alloca) if not (obj_val_sub is None): arg_vals_sub: sizet* = pool.alloc(8) if not (arg_vals_sub is None): arg_vals_sub[0] = sizet(idx_val) ret_sub: llvmlite.Value* = self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, cls_nm_sub, "__getitem__", obj_val_sub, arg_vals_sub, 1, trans, sub) if not (ret_sub is None): return ret_sub # 无 __getitem__:结构体指针数组访问(GEP + load) ptr_val_sub_g: llvmlite.Value* = llvmlite.build_load(builder, pointee, alloca) if ptr_val_sub_g is not None: elem_sub_g: llvmlite.Value* = llvmlite.build_gep(builder, pointee, ptr_val_sub_g, idx_val) if elem_sub_g is not None: # volatile 指针指向物:解引用 load 带 volatile return llvmlite.build_load(builder, pointee, elem_sub_g, vol_sub_rd) return None pass # 通用路径:翻译 value 获取指针 ptr_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, sub.value, None, 0, trans) if ptr_val is None or ptr_val.Ty is None: return None # 检查是否是指针类型 if self.is_ptr_type(ptr_val.Ty) != 0: # 通用路径基址(如 self.ptr / 复杂表达式):仅当基址可解析到 # VarEntry/FieldEntry 且其为 rawptr[t.CVolatile|T] 时,元素 load 带 volatile; # 其余基址解析返回 0(明确不支持,见限制清单)。守卫为 0 时文本不变。 vol_sub_gen: int = self.Gen.ExprGenAttr.base_pointee_is_volatile(pool, trans, sub.value) elem_ty2: llvmlite.LLVMType* = ptr_val.Ty.Pointee if elem_ty2 is not None: # 数组类型: 双索引 GEP + load 元素 match elem_ty2: case llvmlite.LLVMType.Array(arr_elem_ty2, arr_count2): elem_ptr3: llvmlite.Value* = llvmlite.build_gep_array(builder, elem_ty2, arr_elem_ty2, ptr_val, self._zext_index_to_i32(builder, idx_val)) if elem_ptr3 is not None: return llvmlite.build_load(builder, arr_elem_ty2, elem_ptr3, vol_sub_gen) return None case _: pass # 64-bit scalar pointer fields (e.g. `sizet*`, `uint64*`, written as # `t.CUInt64T | t.CPtr`) keep the declared element type here: the slot is # a u64, so it is read as i64 -- same element type the write path uses # (see get_subscript_ptr). Loading it as i8* fabricated a pointer value # out of an integer slot and forced the caller through an implicit # ptrtoint / inttoptr, which the language forbids (it also made # `MemBuddy.free_lists[i]` mis-type its element). Sources that store or # read a pointer through such a slot must cast explicitly. # 自定义结构体 (如 self._ht[key]): 仅当类定义了 __getitem__ 才转发方法调用; # 否则普通结构体指针按下标做 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: str = pool.alloc(128) if gi_lookup_gen is not None: viperlib.snprintf(gi_lookup_gen, 128, "%s.__getitem__", cls_nm_rd_gen) if self.Gen.CallGenBase.find_func_in_module(mod, gi_lookup_gen) is not None: arg_vals_rd_g: sizet* = pool.alloc(8) if not (arg_vals_rd_g is None): arg_vals_rd_g[0] = sizet(idx_val) ret_rd_g: llvmlite.Value* = self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, cls_nm_rd_gen, "__getitem__", ptr_val, arg_vals_rd_g, 1, trans, sub) if not (ret_rd_g is None): return ret_rd_g # 无 __getitem__:结构体指针数组访问(GEP + load) elem_ptr_gen: llvmlite.Value* = llvmlite.build_gep(builder, elem_ty2, ptr_val, idx_val) if elem_ptr_gen is not None: return llvmlite.build_load(builder, elem_ty2, elem_ptr_gen, vol_sub_gen) return None # 指针类型: 单索引 GEP + load elem_ptr4: llvmlite.Value* = llvmlite.build_gep(builder, elem_ty2, ptr_val, idx_val) if elem_ptr4 is not None: return llvmlite.build_load(builder, elem_ty2, elem_ptr4, vol_sub_gen) return None # ============================================================ # 获取下标表达式的元素指针(不加载值,用于赋值) # ============================================================ def _annot_is_64bit_scalar(self, annot: str) -> int: """注解是否为 64 位标量 | t.CPtr 联合(AnnotClassName 为提取出的 非 CPtr 侧类型名,如 int64|t.CPtr → "CInt64T")。此类联合的 8 字节单元格存 i64 标量,下标元素类型应为 Int64 而非指针。""" if annot is None: return 0 if string.strstr(annot, "CInt64T") is not None: return 1 if string.strstr(annot, "CUInt64T") is not None: return 1 if string.strstr(annot, "CSizeT") is not None: return 1 return 0 # ============================================================ # subscript_base_store_kind - 下标基座的**存储形态**(只读,不生成 IR) # # 用于区分「数组槽」与「指针所指对象」,只有前者才允许"整对象赋值": # 1 = 数组存储:t.CArray[T,N] / 内建 Array 形态。元素槽按 sizeof(T) 布局, # `v[i] = <指向 T 的指针>`(如构造函数返回的临时对象地址)是合法的 # 整对象复制,不拦。 # 0 = 指针存储:rawptr[T] 形态(基座元素类型是 Ptr(T),T 为对象)。 # 元素即所指对象,`p[i] = <指向 T 的指针>` 会静默整对象拷贝 # (写 sizeof(T) 字节而非 8 字节指针)——可能写穿按 8 字节排布的 # 缓冲/空闲链表,由调用方 fail-fast。 # -1 = 无法判定(基座不是可静态定型的 Name / 单层 Attribute):不作为判据, # 调用方保持既有行为(不误伤,也不新增静默降级)。 # 分派与 get_subscript_ptr 同源:Name 取变量/全局存储的元素类型, # Attribute 取字段类型。 # ============================================================ def subscript_base_store_kind(self, pool: memhub.MemBuddy*, trans: HT.Translator*, node: ast.AST*) -> int: """下标基座存储形态:1=数组 / 0=指针 / -1=无法判定""" if node is None or trans is None: return -1 sub_bk: ast.Subscript* = ast.Subscript*(node) if sub_bk is None or sub_bk.value is None: return -1 base_ty_bk: llvmlite.LLVMType* = None if sub_bk.value.kind() == ast.ASTKind.Name: nm_bk: ast.Name* = ast.Name*(sub_bk.value) if nm_bk.id is None: return -1 alloca_bk: llvmlite.Value* = self.Gen.VarGen.lookup_var(trans.SymTab, nm_bk.id) if alloca_bk is None: alloca_bk = self.Gen.VarGen.lookup_module_var(trans.SymTab, nm_bk.id) if alloca_bk is None or alloca_bk.Ty is None: return -1 if self.is_ptr_type(alloca_bk.Ty) == 0: return -1 base_ty_bk = alloca_bk.Ty.Pointee elif sub_bk.value.kind() == ast.ASTKind.Attribute: # 单层 obj.field(如 self.arr):非 fatal 只读解析字段类型 fe_bk: GenTypes.FieldEntry* = self.Gen.ExprGenAttr._resolve_attr_field_entry(pool, trans, sub_bk.value) if fe_bk is None or fe_bk.Ty is None: return -1 base_ty_bk = fe_bk.Ty else: return -1 if base_ty_bk is None: return -1 # 基座自身是数组值 → 数组存储 if self.is_array_type(base_ty_bk) != 0: return 1 if self.is_ptr_type(base_ty_bk) != 0: inner_bk: llvmlite.LLVMType* = base_ty_bk.Pointee if inner_bk is None: return -1 # Ptr(Array) → t.CArray[T,N] 局部/字段(数组存储) if self.is_array_type(inner_bk) != 0: return 1 # Ptr(Struct) → rawptr[T](指针存储) if inner_bk.kind() == llvmlite.LLVMType.Struct: return 0 return -1 def get_subscript_ptr(self, builder: llvmlite.IRBuilder*, pool: memhub.MemBuddy*, mod: llvmlite.LLVMModule*, node: ast.AST*, trans: HT.Translator* = None) -> llvmlite.Value*: """获取下标表达式的元素指针(用于赋值 lhs)""" if node is None or builder is None: return None sub: ast.Subscript* = ast.Subscript*(node) if sub is None: return None # 翻译索引 idx_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, sub.slice, None, 0, trans) if idx_val is None: return None # 嵌套下标: a[i][j] = v —— 递归解析内层下标指针后 GEP # (如 gfx.vp Mat4.m: t.CArray[t.CArray[float, 4], 4] 的 m.m[0][0] = 1; # 外层 Subscript 的 value 是内层 Subscript,通用路径 translate_value # 会把内层元素加载为值(Array 类型)→ is_ptr_type 失败 → 返回 None → # "subscript ptr is None" fail-fast。递归取内层指针再 GEP 根治。) if sub.value is not None and sub.value.kind() == ast.ASTKind.Subscript: inner_ptr: llvmlite.Value* = self.get_subscript_ptr(builder, pool, mod, sub.value, trans) if inner_ptr is None or inner_ptr.Ty is None: return None inner_elem: llvmlite.LLVMType* = inner_ptr.Ty.Pointee if inner_elem is None: return None match inner_elem: case llvmlite.LLVMType.Array(arr_ie, _): return llvmlite.build_gep_array(builder, inner_elem, arr_ie, inner_ptr, self._zext_index_to_i32(builder, idx_val)) case _: return llvmlite.build_gep(builder, inner_elem, inner_ptr, idx_val) # 如果 value 是 Name,尝试从 alloca 类型推断 if sub.value is not None and sub.value.kind() == ast.ASTKind.Name: nm: ast.Name* = ast.Name*(sub.value) if nm.id is not None and trans is not None: # nonlocal 数组/指针:从 env 读共享堆地址(提升函数内不能 # lookup_var 外层 alloca——SSA 编号跨函数错乱崩溃) if GenApi.is_nonlocal_name(trans, nm.id) != 0: return self._nonlocal_subscript_ptr(builder, pool, trans, nm.id, idx_val) alloca: llvmlite.Value* = self.Gen.VarGen.lookup_var(trans.SymTab, nm.id) if alloca is not None and alloca.Ty is not None: if self.is_ptr_type(alloca.Ty) != 0: pointee: llvmlite.LLVMType* = alloca.Ty.Pointee if pointee is not None: # 用 match 检查 pointee 类型 match pointee: case llvmlite.LLVMType.Array(elem_ty, count): # 数组遍历 return llvmlite.build_gep_array(builder, pointee, elem_ty, alloca, self._zext_index_to_i32(builder, idx_val)) case llvmlite.LLVMType.Ptr(inner_ty): # inner_ty 是 Ptr 说明 alloca.Ty 是三重指针, # 即 X|t.CPtr 当 X 本身是指针类型 (如 T=AST|t.CPtr, T|t.CPtr=AST**)。 # 此时 [i]=val 应该是指针解引用赋值, 而非调用 __setitem__。 if self.is_ptr_type(inner_ty) != 0: ptr_val_gsp: llvmlite.Value* = llvmlite.build_load(builder, pointee, alloca) if ptr_val_gsp is not None: return llvmlite.build_gep(builder, inner_ty, ptr_val_gsp, idx_val) return None # 自定义结构体 (如 HashTable|t.CPtr, JsonValue|t.CPtr): # 仅当类定义了 __setitem__(当前模块定义或跨模块 stub declare 注入) # 才返回 None 触发 __setitem__ 重载;否则普通结构体指针按下标 # 做 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: str = pool.alloc(128) if si_lookup_gsp is not None: viperlib.snprintf(si_lookup_gsp, 128, "%s.__setitem__", cls_nm_ptr_chk) if self.Gen.CallGenBase.find_func_in_module(mod, si_lookup_gsp) is not None: return None # bytes|t.CPtr / str|t.CPtr: alloca 是 i8**, # 直接 GEP 按 i8* 步长(8 字节),不 load # 仅当 inner_ty 不是自定义结构体时才走指针遍历 if trans is not None: ve_pe: GenTypes.VarEntry* = \ self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm.id) if self.Gen.VarGen.var_is_ptr_element(ve_pe) != 0: # bytes|t.CPtr / str|t.CPtr / T|t.CPtr:变量存指针值, # 下标语义 = [指针值 + i*8](8 字节指针元素)。必须先 load # alloca 得指针值,再 GEP——否则 GEP base 用 alloca(&elem_ptr) # 读到栈变量而非数据区,赋值写不进 list 数据 # (data 全 0xbaadf00d,dump 虚调用读错 vtable 崩溃)。 ptr_val_pe: llvmlite.Value* = llvmlite.build_load(builder, pointee, alloca) if ptr_val_pe is not None: # [FIX 2026-08-30] 64 位标量联合(int64|t.CPtr / # uint64|t.CPtr / sizet|t.CPtr):8 字节单元格存 # i64 标量(viperlib %n 的 np[0]=write_count 是解引用写入, # 语义 *np=(i64)x)。GEP 元素必须用 Int64(标量)而非指针, # 否则元素类型为指针 → i64 存储触发整数隐式转指针 # fail-fast(把解引用写入误判为 int→ptr)。 pe_annot: str = self.Gen.VarGen.var_annot_class_name(ve_pe) if pe_annot is not None and self._annot_is_64bit_scalar(pe_annot) != 0: return llvmlite.build_gep(builder, llvmlite.Int64(pool), ptr_val_pe, idx_val) match pointee: case llvmlite.LLVMType.Int(bits_pe): if bits_pe == 8: i8_ptr_pe: llvmlite.LLVMType* = llvmlite.Ptr(pool, llvmlite.Int8(pool)) return llvmlite.build_gep(builder, i8_ptr_pe, ptr_val_pe, idx_val) case _: pass return llvmlite.build_gep(builder, pointee, ptr_val_pe, idx_val) return None # 普通指针遍历: 先 load 指针值,再 GEP ptr_val: llvmlite.Value* = llvmlite.build_load(builder, pointee, alloca) if ptr_val is None: return None gep_r: llvmlite.Value* = llvmlite.build_gep(builder, inner_ty, ptr_val, idx_val) return gep_r case _: # pointee 是普通标量类型 (如 i64, i32, i8): # alloca 是 Ptr(标量), 直接 GEP 获取第 idx 个元素指针 # 支持 arg_vals[i] = val 这类参数数组下标赋值 # 联合类型变量(IsPtrElement=1,如 _list.vp 的 # elem_ptr: T | t.CPtr 退化为 i8*):pointee=i8 但 # 元素是 8 字节指针,须按 i8* 步长 GEP(防只写 1 字节截断) if trans is not None: ve_pe_cs: GenTypes.VarEntry* = \ self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm.id) if self.Gen.VarGen.var_is_ptr_element(ve_pe_cs) != 0: # T|t.CPtr(退化为 i8*,如 _list.vp 的 elem_ptr)变量 # 存数据区指针,元素为 8 字节指针:必须先 load alloca # 得指针值,再按 i8* 步长 GEP——否则 GEP base 用 alloca # (&elem_ptr)算到栈地址,赋值写不进 list 数据区 # (append 只增 count、data 全 0xbaadf00d)。 ptr_val_cs: llvmlite.Value* = llvmlite.build_load(builder, pointee, alloca) if ptr_val_cs is not None: match pointee: case llvmlite.LLVMType.Int(bits_cs): if bits_cs == 8: i8_ptr_cs: llvmlite.LLVMType* = llvmlite.Ptr(pool, llvmlite.Int8(pool)) return llvmlite.build_gep(builder, i8_ptr_cs, ptr_val_cs, idx_val) case _: pass return llvmlite.build_gep(builder, pointee, ptr_val_cs, idx_val) return None return llvmlite.build_gep(builder, pointee, alloca, idx_val) # 通用路径 ptr_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, sub.value, None, 0, trans) if ptr_val is None or ptr_val.Ty is None: return None if self.is_ptr_type(ptr_val.Ty) != 0: elem_ty2: llvmlite.LLVMType* = ptr_val.Ty.Pointee if elem_ty2 is not None: # 数组类型: 双索引 GEP (getelementptr [N x ty], ptr, i32 0, i32 idx) match elem_ty2: case llvmlite.LLVMType.Array(arr_elem_ty, arr_count): return llvmlite.build_gep_array(builder, elem_ty2, arr_elem_ty, ptr_val, self._zext_index_to_i32(builder, idx_val)) case _: pass # 自定义结构体 (如 self._ht[key]): 仅当类定义了 __setitem__ # 才返回 None 触发 HandlesAssign 的 __setitem__ 重载; # 否则普通结构体指针按下标做 GEP 数组访问 cls_nm_gen: str = self._get_custom_struct_cls_nm(pool, elem_ty2) if not (cls_nm_gen is None): 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 self.Gen.CallGenBase.find_func_in_module(mod, si_lookup_gen) is not None: return None # 指针类型: 单索引 GEP (getelementptr ty, ptr, idx) return llvmlite.build_gep(builder, elem_ty2, ptr_val, idx_val) return None