Files
ViperC/App/lib/core/Gen/Call/CallGenLeafKit.vp
T
TermiNexus 1ad7abf33d refactor(TransPyV): 统一自举写法(novirtual / define / rawptr→* / 去续行反斜杠)
- @t.NoVTable class X → novirtual class X
- t.CDefine = N → define N
- rawptr[X]、X | t.CPtr → X*
- t.CPtr → rawptr(裸指针标记)
- t.Callable[...] → callable[...]
- 去掉 if/elif 条件的行续反斜杠(改单行写法)
- w32.win32file.X → win32file.X(已 import as)
- core/__init__.vp 去掉未使用的 import t, c / from stdint import *

涉及:CompilerFactory、IncludesScanner、Repl、core/__init__、
Gen/Call/{CallGenBase,CallGenCBuiltin,CallGenCall,CallGenDispatch,CallGenLeafKit}、
Gen/Class/ClassGenGeneric。
2026-10-02 02:16:37 +08:00

1546 lines
80 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import lib.core.Gen.GenTypes as GenTypes
import t, c
from stdint import *
import ast
import llvmlite
import memhub
import string
import stdlib
import viperlib
import lib.core.VLogger as VLogger
import lib.core.Gen.GenApi as GenApi
import lib.core.Gen.Translator as HT
import lib.core.CompilerFactory as CompilerFactory
import lib.core.Gen.Type.TypeSpec as TSpec
from . import CallGenCBuiltin
from . import CallGenBase
# ============================================================
# CallGenLeafKit - CallGenMixin 拆分 3/9:EH/isinstance/闭包/print/函数表
# ============================================================
# ============================================================
# 常量
# ============================================================
define _CEXPORT_MAX = 256
define ASM_MAX_OPERANDS = 16
define ASM_TEXT_BUF_SIZE = 2048
define ASM_CONST_BUF_SIZE = 512
define ASM_ARGS_BUF_SIZE = 512
define ASM_LINE_BUF_SIZE = 4096
define LLVMIR_MAX_OPS = 16
define LLVMIR_TEMPLATE_BUF = 512
# ============================================================
# 全局函数表名索引(名 → 槽下标,开放寻址 | 线性探测)
#
# 槽数 = 2 * CallGenBase.GLOBAL_FUNC_MAX(2 的幂,负载 < 0.5,线性探测必然终止)。
# 值写成字面量 16384:模块级 t.CDefine 初始化式不能引用跨模块常量
# (跨模块 t.CDefine 只能在函数体内读),故与 CallGenBase.GLOBAL_FUNC_MAX 手工保持 2 倍关系。
# 槽存槽下标 + 1(0=空槽)。GlobalFuncs 在 PermPool 定长分配、只追加不重排、
# 从不 reset ⇒ 槽下标稳定;Built == GlobalFuncCount 才可信。
# ============================================================
define GLOBAL_FUNC_IDX_CAP = 16384
# 索引哈希常量(32 位 FNV-1a,与 StructGenMixin 范式一致)
define GFN_FNV_OFFSET = 2166136261
define GFN_FNV_PRIME = 16777619
define GFN_FNV_MASK = 4294967295
def _gfn_hash(name: str) -> uint64:
"""函数名 → 64 位哈希(32 位 FNV-1a,逐字节到 NUL 结束)"""
h: uint64 = uint64(GFN_FNV_OFFSET)
if name is None: return h
i: sizet = 0
while name[i] != '\0':
h = (h ^ uint64(int(name[i]))) * uint64(GFN_FNV_PRIME)
h = h & uint64(GFN_FNV_MASK)
i += 1
return h
def _gfn_idx_slot(idx_base: sizet*, si: sizet) -> sizet*:
"""取索引第 si 个槽(8 字节,存槽下标+1;0=空槽)"""
return (sizet*)(uint64(idx_base) + uint64(si) * 8)
def _gfn_idx_find(funcs: GenTypes.FuncEntry*,
idx_base: sizet*, cap: int, name: str) -> int:
"""在全局函数表名索引中探测 name,返回命中槽下标(>=0);未命中/不可用返回 -1"""
if funcs is None or idx_base is None or cap <= 0 or name is None:
return -1
h: uint64 = _gfn_hash(name)
mask: sizet = sizet(cap - 1)
si: sizet = sizet(h) & mask
entry_size: sizet = GenTypes.FuncEntry.__sizeof__()
i: int = 0
while i < cap:
slot: sizet* = _gfn_idx_slot(idx_base, si)
sv: sizet = slot[0]
if sv == 0: return -1
se: int = int(sv) - 1
entry_addr: uint64 = uint64(funcs) + se * entry_size
entry: GenTypes.FuncEntry* = GenTypes.FuncEntry*(entry_addr)
if entry is not None and entry.Name is not None:
if string.strcmp(entry.Name, name) == 0: return se
si = (si + 1) & mask
i += 1
return -1
def _gfn_idx_insert(idx_base: sizet*, cap: int, slot_index: int, name: str) -> int:
"""把 (name → slot_index) 记入索引;0=成功 / 1=失败"""
if idx_base is None or cap <= 0 or name is None:
return 1
h: uint64 = _gfn_hash(name)
mask: sizet = sizet(cap - 1)
si: sizet = sizet(h) & mask
i: int = 0
while i < cap:
slot: sizet* = _gfn_idx_slot(idx_base, si)
if slot[0] == 0:
slot[0] = sizet(slot_index + 1)
return 0
si = (si + 1) & mask
i += 1
return 1
# ============================================================
# CallGenLeafKit - EH/isinstance/闭包/print/函数表
# ============================================================
novirtual class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
"""EH 防护 + isinstance + 闭包 + print + 全局函数表(继承 CBuiltin)"""
# ============================================================
# _func_has_eh_params - 被调函数签名是否含 try-except EH 输出参数
#
# EH 参数(%__eh_msg_out__/__eh_code_out__)由 translate_function_def/
# _translate_method 在含 raise 的函数签名末尾注入(main 除外)。
# ============================================================
def _func_has_eh_params(self, func: llvmlite.Function*) -> int:
"""返回 1=函数带 EH 输出参数 / 0=不带"""
if func is None:
return 0
cur_p: llvmlite.Param* = llvmlite.function_get_param_head(func)
while cur_p is not None:
pn: str = llvmlite.param_get_name(cur_p)
if pn is not None and string.strcmp(pn, "%__eh_msg_out__") == 0:
return 1
cur_p = llvmlite.param_get_next(cur_p)
return 0
# ============================================================
# _emit_eh_guarded_call - 调用侧 try-except EH 检测(对齐 TPC
# HandlesExprCall._append_eh_msg_out_arg + _check_eh_return)
#
# 被调函数带 EH 输出参数时:
# 1. 确定 msg/code 输出指针:
# - 当前在 try(trans._eh_dispatch_bb 非空):复用 try 的
# eh_message/exception_code alloca——被调函数直接写入,检查
# 路径读同一 alloca 即得异常,无需搬运
# - 当前函数有 EH 输出参数:复用本函数 out 参数(异常直接写进
# 本函数输出,检查命中后仅返回,由调用方接管传播)
# - 两者皆无:局部 null alloca(异常被吞)
# 2. 调用前清零输出指针(复用 alloca 必须复位,防上次残留误判)
# 3. 追加 msg/code 两个实参(count+2)
# 4. 调用后检查 msg != null:命中 → err 块(try 内分支 DispatchBB;
# 否则仅返回默认值);未命中 → ok 块继续
# ============================================================
# ============================================================
def _emit_eh_guarded_call(self, builder: llvmlite.IRBuilder*,
pool: memhub.MemBuddy*,
mod: llvmlite.LLVMModule*,
trans: HT.Translator*,
func: llvmlite.Function*,
call_name: str,
head: llvmlite.Value*,
count: int,
ret_ty: llvmlite.LLVMType*,
is_variadic: int) -> llvmlite.Value*:
"""带 try-except EH 检测的函数调用,返回 call 结果(检查后位于 ok 块)"""
if trans is None or self._func_has_eh_params(func) == 0:
return llvmlite.build_call(builder, call_name, head, count, ret_ty, is_variadic)
# ---- 1. 确定输出指针 ----
i8_ty_g: llvmlite.LLVMType* = llvmlite.Int8(pool)
i8_ptr_ty_g: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty_g)
i32_ty_g: llvmlite.LLVMType* = llvmlite.Int32(pool)
if i8_ty_g is None or i8_ptr_ty_g is None or i32_ty_g is None:
return llvmlite.build_call(builder, call_name, head, count, ret_ty, is_variadic)
msg_ptr: llvmlite.Value* = None
code_ptr: llvmlite.Value* = None
if trans._eh_msg_ptr is not None and trans._eh_code_ptr is not None:
msg_ptr = trans._eh_msg_ptr
code_ptr = trans._eh_code_ptr
elif trans._cur_func_has_eh != 0 and trans._eh_msg_out_param is not None and trans._eh_code_out_param is not None:
msg_ptr = trans._eh_msg_out_param
code_ptr = trans._eh_code_out_param
if msg_ptr is None:
msg_ptr = self.Gen.VarGen._alloca_at_entry(builder, i8_ptr_ty_g)
code_ptr = self.Gen.VarGen._alloca_at_entry(builder, i32_ty_g)
# ---- 2. 调用前清零 ----
null_msg_g: llvmlite.Value* = llvmlite.ConstNull(pool, i8_ptr_ty_g, "null")
zero_code_g: llvmlite.Value* = llvmlite.const_int32(pool, 0)
if null_msg_g is not None:
llvmlite.build_store(builder, null_msg_g, msg_ptr)
if zero_code_g is not None:
llvmlite.build_store(builder, zero_code_g, code_ptr)
# ---- 3. 追加实参(链表末尾 + count+2)----
msg_ptr.Next = code_ptr
code_ptr.Next = None
if head is None:
head = msg_ptr
else:
tail_g: llvmlite.Value* = head
while tail_g.Next is not None:
tail_g = tail_g.Next
tail_g.Next = msg_ptr
count = count + 2
# ---- 4. 调用 + 检查 ----
result: llvmlite.Value* = llvmlite.build_call(builder, call_name, head, count, ret_ty, is_variadic)
cur_func_g: llvmlite.Function* = trans._cur_func
if cur_func_g is None or null_msg_g is None: return result
msg_val_g: llvmlite.Value* = llvmlite.build_load(builder, i8_ptr_ty_g, msg_ptr)
if msg_val_g is None: return result
is_err_g: llvmlite.Value* = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, msg_val_g, null_msg_g)
if is_err_g is None: return result
lc_g: int = trans._label_counter
trans._label_counter = lc_g + 1
bb_buf_g: str = pool.alloc(64)
if bb_buf_g is None: return result
viperlib.snprintf(bb_buf_g, 64, "eh.err.%d", lc_g)
err_bb_g: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, cur_func_g, bb_buf_g)
viperlib.snprintf(bb_buf_g, 64, "eh.ok.%d", lc_g)
ok_bb_g: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, cur_func_g, bb_buf_g)
if err_bb_g is None or ok_bb_g is None: return result
llvmlite.build_cond_br(builder, is_err_g, err_bb_g, ok_bb_g)
# err 块
llvmlite.position_at_end(builder, err_bb_g)
if trans._eh_dispatch_bb is not None:
# try 内:异常已写入 try 的 alloca(code_ptr 即 try 的 alloca),
# 分支 DispatchBB 交给 except 链
llvmlite.build_br(builder, trans._eh_dispatch_bb)
else:
# 非 try:异常已写入本函数 out 参数(复用)或局部 alloca(吞掉),
# 仅返回默认值,由调用方检测本函数 out 参数
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
ret_ty_g2: llvmlite.LLVMType* = llvmlite.function_get_ret_ty(cur_func_g)
if ret_ty_g2 is not None:
match ret_ty_g2:
case llvmlite.LLVMType.Void():
llvmlite.build_ret_void(builder)
case llvmlite.LLVMType.Ptr(_pg):
nv_g: llvmlite.Value* = llvmlite.ConstNull(pool, ret_ty_g2, "null")
if nv_g is not None:
llvmlite.build_ret(builder, nv_g)
case llvmlite.LLVMType.Float(_fg):
zf_g: llvmlite.Value* = llvmlite.ConstFloat(pool, ret_ty_g2, 0.0)
if zf_g is not None:
llvmlite.build_ret(builder, zf_g)
case _:
zv_g: llvmlite.Value* = llvmlite.ConstZero(pool, ret_ty_g2)
if zv_g is not None:
llvmlite.build_ret(builder, zv_g)
# ok 块:继续
llvmlite.position_at_end(builder, ok_bb_g)
return result
# ============================================================
# isinstance - 运行时 vtable 子类集合比较(2026-08-10)
#
# CVTable 对象头部 vtable 指针唯一标识对象实际类。isinstance(obj, Cls)
# 语义 = Cls 是实际类的祖先(实际类 == Cls 或继承自 Cls)。运行时只能
# 拿到实际类 vtable 地址,无法向上推导祖先链,因此在编译期沿
# StructEntry.ParentNames 反向 BFS 枚举 Cls 的全部已知子类(含自身),
# 运行时比较 obj->vtable ∈ {Cls 子类 vtable 地址集合}。
# NoVTable / 未知类回退编译时静态判断(obj 静态类型 MRO 判断)。
# ============================================================
def _translate_isinstance(self, pool: memhub.MemBuddy*,
builder: llvmlite.IRBuilder*,
mod: llvmlite.LLVMModule*,
obj_node: ast.AST*,
cls_node: ast.AST*,
trans: HT.Translator* = None) -> llvmlite.Value*:
"""isinstance(obj, Cls):运行时 vtable 子类集合比较,返回 i1"""
if obj_node is None or cls_node is None:
# 参数缺失即调用错误:fail-fast,绝不返回 True 掩盖
self.Gen.TypeGenErr.fatal_error(cls_node, "isinstance() 参数类型推断失败", "TypeError")
obj_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, obj_node, None, 0, trans)
if obj_val is None or obj_val.Ty is None:
# obj 类型推断失败:fail-fast,绝不返回 True 掩盖
self.Gen.TypeGenErr.fatal_error(cls_node, "isinstance() 参数类型推断失败", "TypeError")
# 对象指针规整:二级指针(变量 alloca / 联合 Class|t.CPtr)先 load
obj_ptr: llvmlite.Value* = obj_val
match obj_val.Ty:
case llvmlite.LLVMType.Ptr(inner_ty):
match inner_ty:
case llvmlite.LLVMType.Ptr(_):
loaded: llvmlite.Value* = llvmlite.build_load(builder, inner_ty, obj_val)
if loaded is not None:
obj_ptr = loaded
case _:
pass
obj_is_ptr: int = self.Gen.ExprGenBase.is_ptr_type(obj_ptr.Ty)
i8_ty: llvmlite.LLVMType* = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty)
i8_ptr_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ptr_ty)
# 对象 vtable 指针惰性读取(首个 CVTable 类比较时执行一次)
vtable_ptr: llvmlite.Value* = None
vtable_ready: int = 0
res: llvmlite.Value* = None
cls_names: sizet* = self._extract_isinstance_class_names(pool, cls_node)
if cls_names is None:
# 类名提取失败:fail-fast,绝不返回 True 掩盖
self.Gen.TypeGenErr.fatal_error(cls_node, "isinstance() 参数类型推断失败", "TypeError")
ci: int = 0
while cls_names[ci] != 0:
cn: str = rawptr(cls_names[ci])
if cn is not None:
if self.Gen.StructGen.is_novtable_by_name(cn) != 0 \
or self.Gen.StructGen.has_vtable_by_name(cn) == 0:
# NoVTable / 未知类 → 编译时静态判断(obj 静态类型 MRO)
st: int = self._isinstance_compile_time(pool, obj_ptr, cn)
c1: llvmlite.Value* = llvmlite.const_int(pool, 1, 1 if st > 0 else 0)
if res is None:
res = c1
else:
res = llvmlite.build_or(builder, res, c1)
elif obj_is_ptr != 0:
# CVTable → 运行时 vtable 比较(读对象头部 vtable 指针)
if vtable_ready == 0:
vtable_slot: llvmlite.Value* = llvmlite.build_bitcast(builder, obj_ptr, i8_ptr_ptr_ty)
if vtable_slot is not None:
vtable_ptr = llvmlite.build_load(builder, i8_ptr_ty, vtable_slot)
vtable_ready = 1
if vtable_ptr is not None:
subs: sizet* = self._collect_subclass_vtable_classes(pool, cn)
if subs is not None:
k: int = 0
while subs[k] != 0:
scn: str = rawptr(subs[k])
if scn is not None:
sub_i8: llvmlite.Value* = self._make_vtable_ref_i8(pool, builder, mod, scn, trans)
if sub_i8 is not None:
cmp: llvmlite.Value* = llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, vtable_ptr, sub_i8)
if cmp is not None:
if res is None:
res = cmp
else:
res = llvmlite.build_or(builder, res, cmp)
k += 1
ci += 1
if res is None:
# 未产生任何比较结果(obj 非指针且类全部为 CVTable):推断失败,fail-fast
self.Gen.TypeGenErr.fatal_error(cls_node, "isinstance() 参数类型推断失败", "TypeError")
return res
def _extract_isinstance_class_names(self, pool: memhub.MemBuddy*,
node: ast.AST*) -> sizet*:
"""从 isinstance 第二参数提取类名数组(Name→id / Attribute→attr / Tuple→遍历)"""
arr: sizet* = pool.alloc(8 * 16)
if arr is None:
return None
# 全数组清零:pool 分配内存非零时,未初始化槽位会被 while cls_names[ci]!=0
# 误当类名指针解引用 → 段错误
string.memset(arr, 0, 8 * 16)
arr[0] = 0
if node is None:
return arr
count: int = 0
k: int = node.kind()
if k == ast.ASTKind.Name:
nm: ast.Name* = ast.Name*(node)
if nm.id is not None:
arr[0] = sizet(nm.id)
elif k == ast.ASTKind.Attribute:
at: ast.Attribute* = ast.Attribute*(node)
if at.attr is not None:
arr[0] = sizet(at.attr)
elif k == ast.ASTKind.Tuple:
tp: ast.Tuple* = ast.Tuple*(node)
elts: list[ast.AST*]* = tp.elts
if elts is not None:
n: sizet = len(elts)
for i in range(n):
if count >= 15:
break
elt: ast.AST* = elts.get(i)
if elt is None:
continue
ek: int = elt.kind()
if ek == ast.ASTKind.Name:
enm: ast.Name* = ast.Name*(elt)
if enm.id is not None:
arr[count] = sizet(enm.id)
count += 1
elif ek == ast.ASTKind.Attribute:
eat: ast.Attribute* = ast.Attribute*(elt)
if eat.attr is not None:
arr[count] = sizet(eat.attr)
count += 1
arr[count] = 0
return arr
def _collect_subclass_vtable_classes(self, pool: memhub.MemBuddy*,
class_name: str) -> sizet*:
"""反向 BFS 收集目标类及全部子类(含自身,仅 HasVTable==1),返回 0 结尾数组"""
if class_name is None:
return None
names: sizet* = pool.alloc(8 * (CallGenBase.ISINSTANCE_CLASS_MAX + 1))
queue: sizet* = pool.alloc(8 * CallGenBase.ISINSTANCE_CLASS_MAX)
visited: sizet* = pool.alloc(8 * CallGenBase.ISINSTANCE_CLASS_MAX)
if names is None or queue is None or visited is None:
return None
string.memset(names, 0, 8 * (CallGenBase.ISINSTANCE_CLASS_MAX + 1))
string.memset(queue, 0, 8 * CallGenBase.ISINSTANCE_CLASS_MAX)
string.memset(visited, 0, 8 * CallGenBase.ISINSTANCE_CLASS_MAX)
qcount: int = 1
outcount: int = 0
vcount: int = 0
queue[0] = sizet(class_name) # 存疑
while qcount > 0:
qcount -= 1
cur_addr: sizet = queue[qcount]
cur: str = rawptr(cur_addr)
if cur is None:
continue
dup: int = 0
for vi in range(vcount):
va: sizet = visited[vi]
if va != 0:
vn: str = rawptr(va)
if vn is not None and string.strcmp(vn, cur) == 0:
dup = 1
break
if dup != 0:
continue
if vcount < CallGenBase.ISINSTANCE_CLASS_MAX:
visited[vcount] = sizet(cur)
vcount += 1
centry: GenTypes.StructEntry* = self.Gen.StructGen.find_struct(cur)
if centry is not None and centry.HasVTable != 0:
if outcount < CallGenBase.ISINSTANCE_CLASS_MAX:
names[outcount] = sizet(cur)
outcount += 1
# 子类入队:遍历全部已注册 struct,ParentNames 含 cur 者
# 【守卫】这是按序号(0..StructCount-1)的全量遍历,非按名查找,
# 不走 StructNameIdx 索引:需枚举每个条目的 ParentNames | 按序号
# 取条目,语义等价于"扫描全表收集子类",不可改为 find_struct。
scnt: int = self.Gen.StructGen.get_struct_count()
for i in range(scnt):
e2: GenTypes.StructEntry* = self.Gen.StructGen._get_struct_entry(i)
if e2 is None or e2.Name is None:
continue
if e2.ParentCount > 0 and e2.ParentNames is not None:
parr: sizet* = (sizet*)(e2.ParentNames)
for j in range(e2.ParentCount):
pa: sizet = parr[j]
if pa != 0:
pn: str = rawptr(pa)
if pn is not None and string.strcmp(pn, cur) == 0:
if qcount < CallGenBase.ISINSTANCE_CLASS_MAX:
queue[qcount] = sizet(e2.Name)
qcount += 1
break
names[outcount] = 0
return names
def _make_vtable_ref_i8(self, pool: memhub.MemBuddy*,
builder: llvmlite.IRBuilder*,
mod: llvmlite.LLVMModule*,
class_name: str,
trans: HT.Translator* = None) -> llvmlite.Value*:
"""构造类 vtable 地址引用(i8*):本模块已定义直接引用,跨模块声明 external"""
if class_name is None:
return None
i8_ty: llvmlite.LLVMType* = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty)
buf: str = pool.alloc(256)
if buf is None:
return None
viperlib.snprintf(buf, 256, "%s.vtable", class_name)
vn: str = rawptr(buf)
sha1: str = self.Gen.StructGen.get_struct_sha1(class_name)
if sha1 is None:
if trans is None:
return None
sha1 = trans.ModuleSha1
if sha1 is None:
return None
mangled: str = self.Gen.FuncGenBase._mangle_name_with_sha1(sha1, vn)
ref_name: str = pool.alloc(256)
if ref_name is None:
return None
# vtable 名含 sha1 点号前缀,一律 @"..." 引号形式
viperlib.snprintf(ref_name, 256, "@\"%s\"", mangled)
gv: llvmlite.GlobalVariable* = self.Gen.ExprGenAttr.find_global_in_module(mod, mangled)
ref_ty: llvmlite.LLVMType* = None
if gv is not None:
# 本模块已定义 vtable(constant {i8* x N})→ 引用类型 Ptr(struct)
ref_ty = llvmlite.Ptr(pool, gv.Ty)
else:
# 跨模块:声明 @mangled = external global i8*,引用类型 i8**
gv2: llvmlite.GlobalVariable* = llvmlite.new_global_variable(pool, mangled, i8_ptr_ty)
if gv2 is None:
return None
llvmlite.module_add_global(mod, gv2)
ref_ty = llvmlite.Ptr(pool, i8_ptr_ty)
ref: llvmlite.Value* = llvmlite.SSAValue(pool, ref_ty, ref_name)
if ref is None:
return None
return llvmlite.build_bitcast(builder, ref, i8_ptr_ty)
def _isinstance_compile_time(self, pool: memhub.MemBuddy*,
obj_ptr: llvmlite.Value*,
class_name: str) -> int:
"""编译时静态判断:obj 静态类型 == class_name 或 class_name 在其 MRO 中"""
if obj_ptr is None or obj_ptr.Ty is None or class_name is None:
return 0
match obj_ptr.Ty:
case llvmlite.LLVMType.Ptr(obj_struct_ty):
sname: str = self.Gen.StructGen.get_class_name_by_type(pool, obj_struct_ty)
if sname is not None:
if string.strcmp(sname, class_name) == 0:
return 1
mro: sizet* = self.Gen.StructGen.get_mro_chain(pool, sname)
if mro is not None:
k: int = 0
while mro[k] != 0:
mn: str = rawptr(mro[k])
if mn is not None and string.strcmp(mn, class_name) == 0:
return 1
k += 1
case _:
pass
return 0
# ============================================================
# P4 簇 5+6 迁移方法(函数体来自 HandlesExprCall.vp:
# 闭包调用/函数指针/printf/print/stdarg 糖/变长参数提升/函数表/全局注册表)
# 本模块函数调用改 self.,外部模块调用保留模块前缀,全局变量改 self 字段
# ============================================================
def translate_closure_call(self, pool: memhub.MemBuddy*,
builder: llvmlite.IRBuilder*,
mod: llvmlite.LLVMModule*,
closure_alloca: llvmlite.Value*,
cargs: list[ast.AST*]*,
can: sizet,
trans: HT.Translator* = None) -> llvmlite.Value*:
"""通过闭包指针间接调用(支持带参 lambda:i32(i8*, args...))"""
if builder is None or closure_alloca is None:
return None
i8_ty: llvmlite.LLVMType* = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty)
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
# 1. 加载闭包指针 (i8*)
closure_ptr: llvmlite.Value* = llvmlite.build_load(builder, i8_ptr_ty, closure_alloca)
if closure_ptr is None:
return None
# 2. 加载 fn_ptr (offset 0): bitcast to i8**, load i8*
fn_ptr_addr: llvmlite.Value* = llvmlite.build_bitcast(builder, closure_ptr, llvmlite.Ptr(pool, i8_ptr_ty))
if fn_ptr_addr is None:
return None
fn_raw: llvmlite.Value* = llvmlite.build_load(builder, i8_ptr_ty, fn_ptr_addr)
if fn_raw is None:
return None
# 3. 加载 env_ptr (offset 8): GEP i8, closure, 8; load i8*
eight_val: llvmlite.Value* = llvmlite.const_int32(pool, 8)
env_addr: llvmlite.Value* = llvmlite.build_gep(builder, i8_ty, closure_ptr, eight_val)
if env_addr is None:
return None
env_ptr: llvmlite.Value* = llvmlite.build_load(builder, i8_ptr_ty, env_addr)
if env_ptr is None:
return None
# 4. 构建参数:env 头 + 实参尾(带参 lambda 时翻译实参)
total_args: int = 1
arg_head: llvmlite.Value* = env_ptr
arg_tail: llvmlite.Value* = env_ptr
param_node: llvmlite.ParamNode* = llvmlite.new_param_node(pool, i8_ptr_ty)
pn_tail: llvmlite.ParamNode* = param_node
if can > 0 and cargs is not None and trans is not None:
for ai in range(can):
arg: ast.AST* = cargs.get(ai)
if arg is None: continue
arg_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, arg, None, 0, trans)
if arg_val is None or arg_val.Ty is None: continue
arg_val.Next = None
if arg_tail is not None:
arg_tail.Next = arg_val
arg_tail = arg_val
pn_new: llvmlite.ParamNode* = llvmlite.new_param_node(pool, arg_val.Ty)
if pn_new is not None:
pn_tail.Next = pn_new
pn_tail = pn_new
total_args += 1
if total_args == 1:
env_ptr.Next = None
# 5. bitcast fn_raw 到函数指针类型 i32(i8*, [args...])*
func_ty: llvmlite.LLVMType* = llvmlite.Func(pool, i32_ty, param_node, total_args)
func_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, func_ty)
fn_typed: llvmlite.Value* = llvmlite.build_bitcast(builder, fn_raw, func_ptr_ty)
if fn_typed is None:
return None
# 6. 间接调用: call i32 %fn_typed(env, args...)
return llvmlite.build_call_indirect(builder, fn_typed, arg_head, total_args, i32_ty)
def _is_func_ptr_alloca(self, alloca: llvmlite.Value*) -> int:
"""判断 alloca 是否为函数指针变量(类型 Ptr(Ptr(i8))),1=是 / 0=否"""
if alloca is None or alloca.Ty is None:
return 0
if self.Gen.ExprGenBase.is_ptr_type(alloca.Ty) == 0:
return 0
pointee: llvmlite.LLVMType* = alloca.Ty.Pointee
if pointee is None or self.Gen.ExprGenBase.is_ptr_type(pointee) == 0:
return 0
inner: llvmlite.LLVMType* = pointee.Pointee
if inner is None or self.Gen.ExprGenBase.is_ptr_type(inner) != 0:
return 0
return 1
def _ensure_closure_names(self) -> int:
"""确保闭包名表已分配,0 失败"""
if self.ClosureNames is not None: return 1
self.ClosureNames = CompilerFactory.factory.PermPool.alloc(64 * CallGenBase.MAX_CLOSURE_NAMES)
if self.ClosureNames is None: return 0
string.memset(self.ClosureNames, 0, 64 * CallGenBase.MAX_CLOSURE_NAMES)
return 1
def register_closure_name(self, name: str) -> int:
"""注册嵌套函数(闭包变量)名,0 成功"""
if name is None: return 1
if self._ensure_closure_names() == 0: return 1
if self.ClosureCount >= CallGenBase.MAX_CLOSURE_NAMES: return 1
idx: sizet = sizet(self.ClosureCount) * 64
string.strncpy(self.ClosureNames + idx, name, 63)
self.ClosureCount += 1
return 0
def is_closure_name(self, name: str) -> int:
"""检查 name 是否已注册为闭包变量名,1=是 / 0=否"""
if name is None or self.ClosureNames is None:
return 0
i: sizet
for i in range(self.ClosureCount):
if string.strcmp(self.ClosureNames + i * 64, name) == 0:
return 1
return 0
def _ensure_funcptr_sigs(self) -> int:
"""确保函数指针签名表已分配(stdlib.malloc,懒初始化)"""
if self.FuncptrNames is not None:
return 1
self.FuncptrNames = CompilerFactory.factory.PermPool.alloc(64 * CallGenBase.MAX_FUNC_PTR_SIGS)
self.FuncptrRets = CompilerFactory.factory.PermPool.alloc(8 * CallGenBase.MAX_FUNC_PTR_SIGS)
if self.FuncptrNames is None or self.FuncptrRets is None:
return 0
string.memset(self.FuncptrNames, 0, 64 * CallGenBase.MAX_FUNC_PTR_SIGS)
return 1
def _func_ptr_sig_fatal(self, pool: memhub.MemBuddy*,
node: ast.AST*, name: str,
ret_ty: llvmlite.LLVMType*,
reason: str) -> None:
"""函数指针签名登记失败 → 编译期报错(文案含变量名/返回类型/上限/处置建议)
原实现满表时静默 return 1:登记被丢弃后,调用点才以
"函数指针变量 'X' 的返回类型未注册(t.Callable 注解缺失)"
(下方 _translate_func_ptr_call:843-850)报错,定位到调用行而非登记处,
掩盖真因(表满/重名冲突)。此处统一在登记点 fail-fast。
fatal_error 终止编译、不返回,故调用方的返回值分支仅为防御性写法。
"""
cap: int = CallGenBase.MAX_FUNC_PTR_SIGS
ret_str: str = "?"
if ret_ty is not None:
typed_buf: str = pool.alloc(96)
if typed_buf is not None:
llvmlite.TypePrint(typed_buf, 96, ret_ty, pool)
if typed_buf[0] != '\0':
ret_str = typed_buf
msg_buf: str = pool.alloc(1024)
if msg_buf is not None:
viperlib.snprintf(
msg_buf, 1024,
"函数指针签名表登记失败:变量 '%s'(返回类型 %s)——%s。"
"当前上限 MAX_FUNC_PTR_SIGS=%d,已登记 %d 条。"
"同名同返回类型的重复登记已做原地命中、不占新槽位;"
"若确实需要更多函数指针变量,请上调 CallGenBase.vp 的 "
"MAX_FUNC_PTR_SIGS(全仓唯一来源,改此一处即全仓生效)",
name, ret_str, reason, cap, self.FuncptrCount)
self.Gen.TypeGenErr.fatal_error(node, msg_buf, "TypeError")
return
self.Gen.TypeGenErr.fatal_error(node, "函数指针签名表登记失败(签名表已满或变量名冲突)", "TypeError")
def register_func_ptr_sig(self, pool: memhub.MemBuddy*, name: str,
ret_ty: llvmlite.LLVMType*,
node: ast.AST* = None) -> int:
"""注册函数指针变量的返回类型签名,0=成功(含幂等命中)/ 1=失败(已报错终止)
表按**裸变量名**全局共享(PermPool,跨文件/跨阶段存活),同一变量可能被
多轮登记(模块级:Translator.vp:568-575 的预注册遍与 translate_children
TranslatorGenMixin.vp:130-136 各见同一 AnnAssign 一次):
* 同名同返回类型 → 原地命中、不新增槽位(否则重复登记把表撑爆);
* 同名不同返回类型 → 报错。既不能静默丢弃(查找返回先登记值:先翻译
模块已按旧值生成间接调用,后登记模块却按新值,同一名字两种 ABI),
也不能静默覆盖(先翻译模块的调用点已按旧值生成)——两者都是无声误编译;
* 满表 → 报错(原实现静默丢弃)。
"""
if name is None or ret_ty is None:
return 1
if self._ensure_funcptr_sigs() == 0:
self._func_ptr_sig_fatal(pool, node, name, ret_ty,
"签名表分配失败(PermPool 内存不足)")
return 1
# 幂等/冲突检查:线性扫已登记裸名(FuncptrCount 上限 64,代价可忽略)
i: sizet
for i in range(self.FuncptrCount):
idx_hit: sizet = sizet(i) * 64
if string.strcmp(self.FuncptrNames + idx_hit, name) == 0:
prev_ret: llvmlite.LLVMType* = (llvmlite.LLVMType*)(self.FuncptrRets[i])
if prev_ret is not None and self.Gen.AssignGen._stg_ty_equal(pool, prev_ret, ret_ty) != 0:
return 0
self._func_ptr_sig_fatal(pool, node, name, ret_ty, "该名字已按另一种返回类型登记过")
return 1
if self.FuncptrCount >= CallGenBase.MAX_FUNC_PTR_SIGS:
self._func_ptr_sig_fatal(pool, node, name, ret_ty, "签名表已满")
return 1
idx: sizet = sizet(self.FuncptrCount) * 64
# 槽位定长 64 字节,与 register_closure_name 一致用 strncpy 钳制防越界
string.strncpy(self.FuncptrNames + idx, name, 63)
# ret_ty 是调用方 pool 分配的裸 LLVMType,1a 每文件 reset 后悬空;
# 深拷贝到 perm_pool(lookup_func_ptr_ret 跨文件读取)
ret_copy_fp: llvmlite.LLVMType* = llvmlite.DeepCopyType(CompilerFactory.factory.PermPool, ret_ty)
if ret_copy_fp is not None:
self.FuncptrRets[self.FuncptrCount] = uint64(ret_copy_fp)
else:
self.FuncptrRets[self.FuncptrCount] = uint64(ret_ty)
self.FuncptrCount += 1
return 0
def lookup_func_ptr_ret(self, name: str) -> llvmlite.LLVMType*:
"""查函数指针变量的返回类型,None=未注册(调用时默认 i32)"""
if name is None or self.FuncptrNames is None:
return None
for i in range(self.FuncptrCount):
idx: sizet = sizet(i) * 64
if string.strcmp(self.FuncptrNames + idx, name) == 0:
return (llvmlite.LLVMType*)(self.FuncptrRets[i])
return None
def _translate_func_ptr_call(self, pool: memhub.MemBuddy*,
builder: llvmlite.IRBuilder*,
mod: llvmlite.LLVMModule*,
fp_alloca: llvmlite.Value*,
func_name: str,
cargs: list[ast.AST*]*,
can: sizet,
trans: HT.Translator*) -> llvmlite.Value*:
"""函数指针变量间接调用,返回结果 Value"""
if builder is None or fp_alloca is None:
return None
i8_ty: llvmlite.LLVMType* = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty)
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
# 1. load 函数地址 (i8*)
fn_i8: llvmlite.Value* = llvmlite.build_load(builder, i8_ptr_ty, fp_alloca)
if fn_i8 is None: return None
# 2. 翻译实参并链接为 Value 链表
head: llvmlite.Value* = None
tail: llvmlite.Value* = None
arg_count: int = 0
ai: sizet
for ai in range(can):
arg: ast.AST* = cargs.get(ai)
if arg is not None:
arg_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, arg, None, 0, trans)
if arg_val is not None:
arg_val.Next = None
if head is None:
head = arg_val
else:
tail.Next = arg_val
tail = arg_val
arg_count += 1
# 3. 按实参类型 + 注册的返回类型构造签名(未注册即 t.Callable 注解缺失,fail-fast)
ret_ty: llvmlite.LLVMType* = self.lookup_func_ptr_ret(func_name)
if ret_ty is None:
self.Gen.TypeGenErr.fatal_error(None, f"函数指针变量 '{func_name}' 的返回类型未注册(t.Callable 注解缺失)", "TypeError")
ret_ty = i32_ty
fp_first: llvmlite.ParamNode* = None
fp_prev: llvmlite.ParamNode* = None
cur_v: llvmlite.Value* = head
for pi in range(arg_count):
if cur_v is None:
break
cur_ty: llvmlite.LLVMType* = llvmlite.value_get_ty(cur_v)
pn2: llvmlite.ParamNode* = llvmlite.new_param_node(pool, cur_ty)
if pn2 is not None:
if fp_first is None:
fp_first = pn2
if fp_prev is not None:
llvmlite.paramnode_set_next(fp_prev, pn2)
fp_prev = pn2
cur_v = llvmlite.value_get_next(cur_v)
func_ty: llvmlite.LLVMType* = llvmlite.Func(pool, ret_ty, fp_first, arg_count)
if func_ty is None:
return None
func_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, func_ty)
# 4. bitcast i8* → 函数指针类型,间接调用
fn_typed: llvmlite.Value* = llvmlite.build_bitcast(builder, fn_i8, func_ptr_ty)
if fn_typed is None:
return None
return llvmlite.build_call_indirect(builder, fn_typed, head, arg_count, ret_ty)
def translate_printf_call(self, pool: memhub.MemBuddy*,
builder: llvmlite.IRBuilder*,
mod: llvmlite.LLVMModule*,
cl: ast.Call*,
trans: HT.Translator* = None) -> None:
"""翻译 printf 调用(特殊处理格式字符串)"""
cargs: list[ast.AST*]* = cl.args
if cargs is None: return
can: sizet = len(cargs)
if can == 0: return
arg0: ast.AST* = cargs.get(0)
if arg0 is None: return
fmt_str: str = None
arg0_kind: int = arg0.kind()
if arg0_kind == ast.ASTKind.Constant:
cn: ast.Constant* = ast.Constant*(arg0)
if cn.const_kind == ast.CONST_STR:
fmt_str = cn.str_val
if fmt_str is None: return
fmt_ptr: llvmlite.Value* = self.Gen.ExprGenConst.create_global_string(builder, pool, mod, fmt_str, trans)
if fmt_ptr is None: return
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
# 翻译额外参数并链接
prev: llvmlite.Value* = fmt_ptr
for ai in range(1, can):
arg: ast.AST* = cargs.get(ai)
if arg is not None:
arg_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, arg, None, 0, trans)
if arg_val is not None:
# C ABI integer promotion: i8/i16 → i32(printf 变参函数要求)
arg_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(arg_val.Ty)
if arg_bits != 0 and arg_bits < 32:
arg_val = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val, i32_ty, arg)
# C ABI float promotion: float → double(printf 变参函数要求)
arg_fbits: int = self.Gen.ExprGenBase.get_llvm_float_bits(arg_val.Ty)
if arg_fbits != 0 and arg_fbits < 64:
double_ty: llvmlite.LLVMType* = llvmlite.Double(pool)
arg_val = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val, double_ty, arg)
arg_val.Next = None
prev.Next = arg_val
prev = arg_val
prev.Next = None
# is_variadic=1: 生成带显式函数类型签名的 call(如 call i32 (i8*, ...) @printf),
# 让 llc 识别为 variadic 调用,生成正确的 Win64 ABI 代码(浮点参数同时传 XMM 和整数寄存器)
llvmlite.build_call(builder, "printf", fmt_ptr, can, i32_ty, 1)
def translate_print_call(self, pool: memhub.MemBuddy*,
builder: llvmlite.IRBuilder*,
mod: llvmlite.LLVMModule*,
cl: ast.Call*,
trans: HT.Translator* = None) -> None:
"""翻译 print 调用(类型感知格式化 + 默认换行)"""
cargs: list[ast.AST*]* = cl.args
if cargs is None:
return
FMT_BUF_SIZE: sizet = 256
fmt_buf: bytes = stdlib.malloc(FMT_BUF_SIZE)
if fmt_buf is None:
return
fmt_buf[0] = '\0'
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
i64_ty: llvmlite.LLVMType* = llvmlite.Int64(pool)
dbl_ty: llvmlite.LLVMType* = llvmlite.Double(pool)
can: sizet = len(cargs)
arg_head: llvmlite.Value* = None
arg_tail: llvmlite.Value* = None
arg_count: int = 1 # 格式串本身是第 1 个 printf 参数
for ai in range(can):
arg: ast.AST* = cargs.get(ai)
if arg is None: continue
arg_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, arg, None, 0, trans)
if arg_val is None or arg_val.Ty is None:
# fail-fast:print 参数翻译失败必须终止编译,绝不在格式串写
# 误导为数据问题而非编译器 bug。
VLogger.error(f"print 参数翻译失败(表达式返回 None): [arg={ai}]", "PRINT")
self.Gen.TypeGenErr.fatal_error(arg, "print 参数翻译失败(表达式返回 None)", "TypeError")
return
# 数组名(如 print(l),l: t.CArray[char, N]):
# translate_value 会 load 出数组值([N x T]),print 无法格式化;
# 按数组退化语义取数组 alloca 地址——字符数组 → %s(打印字符串内容),
# 其他元素类型 → 0x%llx(打印数组地址)。
array_ptr: llvmlite.Value* = None
array_elem_bits: int = 0
if arg.kind() == ast.ASTKind.Name and trans is not None:
anm: ast.Name* = ast.Name*(arg)
if anm.id is not None:
arr_alloca: llvmlite.Value* = self.Gen.VarGen.lookup_var(trans.SymTab, anm.id)
if arr_alloca is not None and arr_alloca.Ty is not None and self.Gen.ExprGenBase.is_ptr_type(arr_alloca.Ty) != 0:
arr_pointee: llvmlite.LLVMType* = arr_alloca.Ty.Pointee
if arr_pointee is not None:
match arr_pointee:
case llvmlite.LLVMType.Array(arr_et, arr_n):
array_ptr = arr_alloca
array_elem_bits = self.Gen.ExprGenBase.get_llvm_type_bits(arr_et)
case _:
pass
token: str = None
chain_arg: int = 1 # 1=该 token 消耗一个参数,0=纯文本
arg_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(arg_val.Ty)
arg_fbits: int = self.Gen.ExprGenBase.get_llvm_float_bits(arg_val.Ty)
if array_ptr is not None:
# 数组退化:字符数组 → %s(bitcast [N x i8]* 到 i8*);其他 → 0x%llx
if array_elem_bits == 8:
i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, llvmlite.Int8(pool))
token = "%s"
arg_val = llvmlite.build_bitcast(builder, array_ptr, i8_ptr_ty)
else:
token = "0x%llx"
arg_val = llvmlite.build_ptrtoint(builder, array_ptr, i64_ty)
elif self.Gen.ExprGenBase.is_ptr_type(arg_val.Ty) != 0:
# i8*(str/bytes)→ %s;其他指针 → 0x%llx
pointee: llvmlite.LLVMType* = arg_val.Ty.Pointee
if pointee is not None and self.Gen.ExprGenBase.get_llvm_type_bits(pointee) == 8:
token = "%s"
else:
token = "0x%llx"
arg_val = llvmlite.build_ptrtoint(builder, arg_val, i64_ty)
elif arg_bits != 0:
if arg_bits == 1:
token = "%d"
arg_val = llvmlite.build_zext(builder, arg_val, i32_ty)
elif arg_bits == 8:
token = "%d"
arg_val = llvmlite.build_sext(builder, arg_val, i32_ty)
elif arg_bits == 16:
token = "%d"
arg_val = llvmlite.build_sext(builder, arg_val, i32_ty)
elif arg_bits == 32:
token = "%d"
else:
token = "%lld"
elif arg_fbits != 0:
token = "%f"
if arg_fbits < 64:
arg_val = llvmlite.build_fpext(builder, arg_val, dbl_ty)
else:
# 结构体值/数组/函数等 → "(unknown)",不传参
token = "(unknown)"
chain_arg = 0
# 追加格式 token
if string.strlen(fmt_buf) < FMT_BUF_SIZE - 16:
viperlib.snprintf(fmt_buf + string.strlen(fmt_buf), 16, "%s", token)
# 链接参数
if chain_arg != 0:
arg_val.Next = None
if arg_tail is None:
arg_head = arg_val
else:
arg_tail.Next = arg_val
arg_tail = arg_val
arg_count += 1
# 追加默认换行(Python print 默认 end="\n")
if string.strlen(fmt_buf) < FMT_BUF_SIZE - 2:
viperlib.snprintf(fmt_buf + string.strlen(fmt_buf), 2, "\n")
fmt_ptr: llvmlite.Value* = self.Gen.ExprGenConst.create_global_string(builder, pool, mod, fmt_buf, trans)
stdlib.free(fmt_buf)
if fmt_ptr is None: return
fmt_ptr.Next = arg_head
# is_variadic=1: 带显式函数类型签名(C ABI 变参调用)
llvmlite.build_call(builder, "printf", fmt_ptr, arg_count, i32_ty, 1)
def init_func_table(self, pool: memhub.MemBuddy*, max_count: int) -> GenTypes.FuncEntry*:
"""分配并清零函数表数组"""
size: sizet = max_count * GenTypes.FuncEntry.__sizeof__()
funcs_ptr: GenTypes.FuncEntry* = pool.alloc(size)
if funcs_ptr is not None:
string.memset(funcs_ptr, 0, size)
return funcs_ptr
def find_func_in_table(self, funcs: GenTypes.FuncEntry*,
func_count: int,
name: str,
owner_sha1: str = None) -> llvmlite.Function*:
"""在函数表中按名称查找,返回 Function 指针或 None
owner_sha1: 当前模块 SHA1。非 None 时"本模块函数优先"——表里同名条目
可能同时含本模块函数与依赖 stub 注入的外来函数(LoadDepVpiIntoModule
在 forward_declare_functions 之前把依赖模块同名函数以裸名注册进本文件
_funcs,槽位在前;本模块条目注册在后)。本模块函数 mangled 名为
"{owner_sha1}.{name}",按其 16 位前缀优先返回;无本模块条目
(纯 from-import/外部 stub)时回落首个同名条目(旧语义)。
"""
if name is None or funcs is None:
return None
entry_size: sizet = GenTypes.FuncEntry.__sizeof__()
# 全局函数表 + 无 owner(find_func_global / _register_global_func 去重路径):
# owner 分支不激活 ⇒ 等价于"首个同名条目的 Func"(含 Func 为 None → None),
# 走名索引快速路径。funcs 非全局表(逐文件 _funcs)或带 owner 时保持下方
# 线性扫描(owner 优先需按同组顺序遍历,索引不适用)。
gfuncs_match: int = 0
if owner_sha1 is None and self.GlobalFuncs is not None:
if uint64(funcs) == uint64(self.GlobalFuncs) and func_count == self.GlobalFuncCount:
gfuncs_match = 1
if gfuncs_match != 0 and self.GlobalFuncNameIdxBuilt == self.GlobalFuncCount \
and self.GlobalFuncNameIdx is not None and self.GlobalFuncNameIdxCap > 0:
fi_t: int = _gfn_idx_find(self.GlobalFuncs, self.GlobalFuncNameIdx,
self.GlobalFuncNameIdxCap, name)
if fi_t >= 0:
fe_t: GenTypes.FuncEntry* = GenTypes.FuncEntry*((uint64(self.GlobalFuncs) + fi_t * entry_size))
if fe_t is not None:
return fe_t.Func
# 索引可信(Built==GlobalFuncCount | 查询名非空)⇒ 未命中即"确无同名条目":
# 全局表只经 _register_global_func 追加(每次追加即同步索引,失败则置
# Built=-1),名注册后不再改写 ⇒ owner_sha1 为 None 时原线性扫描等价于
# "首个同名条目的 Func",未命中必为 None。索引不可信时回退下方线性扫描。
return None
# 单遍扫描(合并原 owner 优先遍 + 通用遍,语义完全一致但省一半遍历):扫描中同时记录"首个同裸名条目"作通用兜底;一旦发现本模块条目(mangled 名以 "{owner_sha1}." 开头,16 位前缀 + '.')立即返回
fallback_entry: GenTypes.FuncEntry* = None
for i in range(func_count):
entry_addr: uint64 = uint64(funcs) + i * entry_size
entry: GenTypes.FuncEntry* = GenTypes.FuncEntry*(entry_addr)
if entry is not None and entry.Name is not None:
# 快速路径:同名要求首字符相等(strcmp 判等蕴含首字符相等),
# 首字符不同者直接跳过 strcmp,避免全表每槽一次函数调用。
if entry.Name[0] == name[0] and string.strcmp(entry.Name, name) == 0:
if fallback_entry is None:
fallback_entry = entry
if entry.Func is not None and owner_sha1 is not None:
fn_nm_o: str = llvmlite.function_get_name(entry.Func)
if fn_nm_o is not None:
if string.strncmp(fn_nm_o, owner_sha1, 16) == 0 and fn_nm_o[16] == '.':
return entry.Func
if fallback_entry is not None:
return fallback_entry.Func
return None
def add_func_to_table(self, funcs: GenTypes.FuncEntry*,
func_count: int,
name: str,
func: llvmlite.Function*,
max_count: int,
defaults: t.CPtr = None,
default_count: int = 0,
param_count: int = 0,
pool: memhub.MemBuddy* = None,
def_sha1: str = None) -> int:
"""添加函数到函数表,返回 0 成功
Args:
defaults: ast.Arguments.defaults 列表节点指针,None=无默认值
default_count: 默认值数量(len(defaults))
param_count: 形参数量(不含 self,len(args.args))
pool: 内存池(保留兼容参数;Spec 由 arena/PermPool 分配)
"""
if name is None or func is None or funcs is None:
return 1
if func_count >= max_count:
return 1
entry_size: sizet = GenTypes.FuncEntry.__sizeof__()
entry_addr: uint64 = uint64(funcs) + func_count * entry_size
entry: GenTypes.FuncEntry* = GenTypes.FuncEntry*(entry_addr)
entry.Name = name
entry.Func = func
entry.Defaults = defaults
entry.DefaultCount = default_count
entry.ParamCount = param_count
# [S3 条目双写] Spec 在形参 add_param 完成后由 update_global_func_spec 填
entry.Spec = None
# 同时注册到全局函数表(供跨模块 vtable 初始化查找)
self._register_global_func(name, func, pool)
# 同时注册到全局默认参数表(供跨模块调用时填充默认值)
if default_count > 0:
self._register_global_defaults(name, defaults, default_count, param_count, def_sha1)
return 0
def _init_global_func_table(self) -> int:
"""初始化全局函数表(用 stdlib.malloc 分配,生命周期=整个程序)"""
if self.GlobalFuncs is not None:
return 1
size: sizet = CallGenBase.GLOBAL_FUNC_MAX * GenTypes.FuncEntry.__sizeof__()
self.GlobalFuncs = CompilerFactory.factory.PermPool.alloc(size)
if self.GlobalFuncs is None:
return 0
string.memset(self.GlobalFuncs, 0, size)
self.GlobalFuncCount = 0
# 名索引(PermPool,与表同生命周期)。分配失败 → 保持不可信(Built=-1),
# 查找/去重一律回退线性扫描(语义完全一致,不因此使初始化失败)。
idx_bytes: sizet = sizet(GLOBAL_FUNC_IDX_CAP) * 8
idx_buf: sizet* = CompilerFactory.factory.PermPool.alloc(idx_bytes)
if idx_buf is None:
self.GlobalFuncNameIdx = None
self.GlobalFuncNameIdxCap = 0
self.GlobalFuncNameIdxBuilt = -1
else:
string.memset(idx_buf, 0, idx_bytes)
self.GlobalFuncNameIdx = idx_buf
self.GlobalFuncNameIdxCap = GLOBAL_FUNC_IDX_CAP
self.GlobalFuncNameIdxBuilt = 0
return 1
def _register_global_func(self, name: str, func: llvmlite.Function*,
pool: memhub.MemBuddy* = None) -> int:
"""注册函数到全局表(已存在则跳过),返回 0 成功
直接操作全局表,不调用 add_func_to_table,避免递归。
"""
if name is None or func is None:
return 1
if self._init_global_func_table() == 0:
return 1
# 已存在则跳过(避免重复)
if self.find_func_in_table(self.GlobalFuncs, self.GlobalFuncCount, name) is not None:
return 0
if self.GlobalFuncCount >= CallGenBase.GLOBAL_FUNC_MAX:
return 1
# 直接写入全局表(不调用 add_func_to_table,避免递归)
entry_size: sizet = GenTypes.FuncEntry.__sizeof__()
entry_addr: uint64 = uint64(self.GlobalFuncs) + self.GlobalFuncCount * entry_size
entry: GenTypes.FuncEntry* = GenTypes.FuncEntry*(entry_addr)
# Name 深拷贝到 stdlib 区:全局表跨文件永久存活,pool 内名字会被 1b 每文件
# reset_to(mark1) 回收导致悬空(vtable 生成 find_func_global 后 strcmp 崩溃)
name_len: sizet = string.strlen(name)
name_copy: str = CompilerFactory.factory.PermPool.alloc(name_len + 1)
if name_copy is None:
return 1
string.strcpy(name_copy, name)
entry.Name = name_copy
entry.Func = func
# [S3 条目双写] Spec 待 update_global_func_spec 填(形参未 add 完)
entry.Spec = None
# Spec 不在此生成:函数参数在 add_func_to_table 之后才添加,
# 需由调用方在参数添加完成后调用 update_global_func_spec 补全。
self.GlobalFuncCount += 1
# 同步名索引(槽下标 = 新条目下标):仅当插入前可信(Built==Count-1)
# 且插入成功;否则标记不可信(查找回退线性扫描)。
if self.GlobalFuncNameIdxBuilt == self.GlobalFuncCount - 1 \
and _gfn_idx_insert(self.GlobalFuncNameIdx, self.GlobalFuncNameIdxCap,
self.GlobalFuncCount - 1, name_copy) == 0:
self.GlobalFuncNameIdxBuilt = self.GlobalFuncCount
else:
self.GlobalFuncNameIdxBuilt = -1
return 0
def update_global_func_spec(self, name: str,
func: llvmlite.Function*) -> int:
"""更新全局函数表的 Spec(在函数参数全部添加完成后调用)
调用时机:add_func_to_table 注册后、llvmlite.add_param 全部执行完。
用 NewTypeFunc 构造整签名 Spec(PermPool 驻留,跨 1b reset 安全),
供 vtable 生成在 func 被 1b reset 后经 SpecToLLVMText 派生类型文本。
"""
if name is None or func is None:
return 1
entry: GenTypes.FuncEntry* = self.find_func_entry_global(name)
if entry is None:
return 1
entry.Spec = self._build_func_spec(func)
return 0
# _build_func_spec:由函数对象构造整签名 TypeSpec(S3 条目双写)——Kind=TS_FUNC,含 Ret + 形参 Spec 数组 + ParamCount + IsVarArg,必须在形参全部 add_param 完成后调用。参数沿 function_get_param_head 的 Param 链表两遍遍历(先计数再填充,llvmlite 无按下标取参且无法预知长度)。与 TSpec.SpecFromLLVMType 的 Func 分支不同:后者不含变参信息(恒置 IsVarArg=0),故此处直接用 NewTypeFunc(..., func.IsVarArg)。失败返回 None,调用方保留 None 不造伪 spec
def _build_func_spec(self, func: llvmlite.Function*) -> TSpec.TypeSpec*:
"""由函数对象构造整签名 TypeSpec,失败返回 None"""
if func is None: return None
arena: TSpec.TypeSpecArena* = self.Gen.TypeGenBase.ensure_spec_arena()
if arena is None: return None
ret_s: TSpec.TypeSpec* = TSpec.SpecFromLLVMType(arena, llvmlite.function_get_ret_ty(func))
if ret_s is None: return None
# 第一遍:计数
cnt: int = 0
cur: llvmlite.Param* = llvmlite.function_get_param_head(func)
while cur is not None and cnt < 256:
cnt += 1
cur = llvmlite.param_get_next(cur)
# 第二遍:逐个构造并写入连续参数数组
params_arr: sizet* = None
if cnt > 0:
params_arr = CompilerFactory.factory.PermPool.alloc(8 * cnt)
if params_arr is None: return None
cur = llvmlite.function_get_param_head(func)
i: int = 0
while cur is not None and i < cnt:
ps: TSpec.TypeSpec* = TSpec.SpecFromLLVMType(arena, llvmlite.param_get_ty(cur))
if ps is None: return None
slot: sizet* = (sizet*)(uint64(params_arr) + uint64(i * 8))
if slot is None: return None
slot[0] = sizet(ps)
cur = llvmlite.param_get_next(cur)
i += 1
return TSpec.NewTypeFunc(arena, ret_s, params_arr, cnt, func.IsVarArg)
def find_func_global(self, name: str) -> llvmlite.Function*:
"""在全局函数表中按名称查找,返回 Function 指针或 None"""
if name is None or self.GlobalFuncs is None: return None
return self.find_func_in_table(self.GlobalFuncs, self.GlobalFuncCount, name)
def find_func_entry_global(self, name: str) -> GenTypes.FuncEntry*:
"""在全局函数表中按名称查找,返回完整 FuncEntry(含 Spec)或 None"""
if name is None or self.GlobalFuncs is None: return None
entry_size: sizet = GenTypes.FuncEntry.__sizeof__()
# 名索引快速路径:可信(Built==Count)时一次探测返回首个同名条目
# (= 原线性扫描首个命中);可信且查询名非空时未命中即"确无同名条目"
# (全局表只经 _register_global_func 追加并同步索引,名注册后不再改写),
# 直接返回 None;索引不可信 → 回退下方原线性扫描。
if self.GlobalFuncNameIdxBuilt == self.GlobalFuncCount and self.GlobalFuncNameIdx is not None and self.GlobalFuncNameIdxCap > 0:
gi: int = _gfn_idx_find(self.GlobalFuncs, self.GlobalFuncNameIdx, self.GlobalFuncNameIdxCap, name)
if gi >= 0:
entry_g: GenTypes.FuncEntry* = GenTypes.FuncEntry*(uint64(self.GlobalFuncs) + gi * entry_size)
return entry_g
return None
for i in range(self.GlobalFuncCount):
entry_addr: uint64 = uint64(self.GlobalFuncs) + i * entry_size
entry: GenTypes.FuncEntry* = GenTypes.FuncEntry*(entry_addr)
if entry.Name is not None:
# 快速路径:同名要求首字符相等(strcmp 判等蕴含首字符相等),
# 首字符不同者直接跳过 strcmp。
if entry.Name[0] == name[0] and string.strcmp(entry.Name, name) == 0:
return entry
return None
def _init_global_defaults_table(self) -> int:
"""初始化全局默认参数表"""
if self.GlobalDefaults is not None: return 1
size: sizet = CallGenBase.GLOBAL_DEFAULTS_MAX * GenTypes.FuncDefaultsEntry.__sizeof__()
self.GlobalDefaults = CompilerFactory.factory.PermPool.alloc(size)
if self.GlobalDefaults is None: return 0
string.memset(self.GlobalDefaults, 0, size)
self.GlobalDefaultsCount = 0
return 1
def _register_global_defaults(self, name: str,
defaults: t.CPtr,
default_count: int,
param_count: int,
def_sha1: str = None) -> int:
"""注册函数默认参数到全局表,返回 0 成功
注册时提取每个默认值 Constant 的常量快照到 stdlib(ConstKinds/ConstInts/ConstStrs),
跨模块调用时优先用快照重建常量 IR,避免读取被 reset 回收的 pool 内 AST。
def_sha1:**定义该函数的模块 SHA1**。依赖注入路径(VpiReader)必须显式传入,
否则会退回 CurrentModuleSha1 —— 注入期它是**导入方**,会把被依赖模块函数的
默认值挂到导入方名下(如 mm.init 的 2 个默认值挂到 usb)→ usb 的
`uhci.init(io_base)` 经 find_func_defaults("init", usb_sha) 命中该错账条目
而被补 2 个 i32 0(N17 真因;模块函数表的"按定义模块限定查找"救不了这条
全局表路径,因为该处 found_func 仍为 None、交叉校验被整体跳过)。
"""
if name is None or defaults is None: return 1
if self._init_global_defaults_table() == 0: return 1
# 限定键 = **定义该函数的模块 SHA1**:同一函数名在不同模块各存一条,查询时
# 按「名 + 定义模块」精确匹配,消除跨模块同名串味。def_sha1 由依赖注入
# 路径显式传入被依赖模块自身 sha1;非注入路径(本模块真实定义)取
# CurrentModuleSha1(此时它就是定义模块)。
cur_sha: str = def_sha1
if cur_sha is None and self.Gen is not None and self.Gen.TypeGenBase is not None:
cur_sha = self.Gen.TypeGenBase.CurrentModuleSha1
# 同模块同名已存在则跳过
if self.find_func_defaults(name, cur_sha) is not None: return 0
if self.GlobalDefaultsCount >= CallGenBase.GLOBAL_DEFAULTS_MAX: return 1
entry_size: sizet = GenTypes.FuncDefaultsEntry.__sizeof__()
entry_addr: uint64 = uint64(self.GlobalDefaults) + self.GlobalDefaultsCount * entry_size
entry: GenTypes.FuncDefaultsEntry* = GenTypes.FuncDefaultsEntry*(entry_addr)
# Name 深拷贝到 stdlib(全局表跨文件永久存活)
nm_len: sizet = string.strlen(name)
nm_copy: str = CompilerFactory.factory.PermPool.alloc(nm_len + 1)
if nm_copy is None: return 1
string.strcpy(nm_copy, name)
entry.Name = nm_copy
entry.ModuleSha1 = None
if cur_sha is not None:
sh_len: sizet = string.strlen(cur_sha)
sh_copy: str = CompilerFactory.factory.PermPool.alloc(sh_len + 1)
if sh_copy is not None:
string.strcpy(sh_copy, cur_sha)
entry.ModuleSha1 = sh_copy
entry.Defaults = defaults
entry.DefaultCount = default_count
entry.ParamCount = param_count
# 范围防御:default_count 异常(vpi tree 损坏时 len 垃圾大数)时放弃
# 提取快照(调用方哨兵已拦截,此为第二道),避免 alloc(垃圾) + 数组
# 越界写 perm_pool 覆盖当前模块 AST/表(SlotsBugTest 崩溃根因候选)。
if default_count > 128:
entry.Defaults = None
entry.DefaultCount = 0
return 0
# 提取常量快照到 stdlib
if default_count > 0:
kinds: int | t.CPtr = CompilerFactory.factory.PermPool.alloc(default_count * 4)
ints: int64 | t.CPtr = CompilerFactory.factory.PermPool.alloc(default_count * 8)
strs: sizet* = CompilerFactory.factory.PermPool.alloc(default_count * 8)
if kinds is not None and ints is not None and strs is not None:
string.memset(kinds, 0, default_count * 4)
string.memset(ints, 0, default_count * 8)
string.memset(strs, 0, default_count * 8)
dl: list[ast.AST*]* = (list[ast.AST*] | t.CPtr)(uint64(defaults))
di: int
for di in range(default_count):
dnode: ast.AST* = dl.get(di)
if dnode is not None and dnode.kind() == ast.ASTKind.Constant:
dcn: ast.Constant* = ast.Constant*(dnode)
kinds[di] = dcn.const_kind
ints[di] = dcn.int_val
if dcn.const_kind == ast.CONST_STR and dcn.str_val is not None:
slen: sizet = string.strlen(dcn.str_val)
scopy: str = CompilerFactory.factory.PermPool.alloc(slen + 1)
if scopy is not None:
string.strcpy(scopy, dcn.str_val)
strs[di] = sizet(scopy)
elif dnode is not None and dnode.kind() == ast.ASTKind.Name:
# CDefine Name 引用默认值(如 share: ULONG = SHARE_READ):
# 注册时求值 CDefine 存快照——否则跨模块重建时快照为空
# → "跨模块默认参数无法重建"(FileIoTest File.__init__ 根因)。
# 仅支持已注册的整型 CDefine;未注册保持 kinds=0(重建时
# 仍 fail-fast,绝不静默回退)。
dnm: ast.Name* = ast.Name*(dnode)
if dnm.id is not None:
cdef_v: int = self.Gen.TypeGenCDef.lookup_cdefine_constant(dnm.id)
if self.Gen.TypeGenCDef.is_cdefine_found() != 0:
kinds[di] = ast.CONST_INT
ints[di] = cdef_v
elif dnode is not None and dnode.kind() == ast.ASTKind.UnaryOp:
# 一元字面量默认值(如 ex3: int = -1):AST 是
# UnaryOp(USub, Constant(1)),不是 Constant —— 此前无此分支
# → kinds[di] 保持 0 → 快照重建失败 → "跨模块默认参数无法
# 重建(快照缺失,默认值需为简单常量)"(AppGui.top_index
# 的 ex3 = -1 根因)。只对"操作数是整型 Constant"求值,
# 其它(浮点取负 / 取负变量)保持 kinds=0 → 重建时 fail-fast。
du: ast.UnaryOp* = ast.UnaryOp*(dnode)
if du.operand is not None and du.operand.kind() == ast.ASTKind.Constant:
doc: ast.Constant* = ast.Constant*(du.operand)
if doc.const_kind == ast.CONST_INT:
if du.op == ast.OpKind.USub:
kinds[di] = ast.CONST_INT
ints[di] = -doc.int_val
elif du.op == ast.OpKind.UAdd:
kinds[di] = ast.CONST_INT
ints[di] = doc.int_val
elif du.op == ast.OpKind.Invert:
kinds[di] = ast.CONST_INT
ints[di] = ~doc.int_val
entry.ConstKinds = kinds
entry.ConstInts = ints
entry.ConstStrs = strs
self.GlobalDefaultsCount += 1
return 0
def find_func_defaults(self, name: str,
module_sha1: str = None) -> GenTypes.FuncDefaultsEntry*:
"""按函数名(可选按定义模块 SHA1)查找默认参数信息,返回 FuncDefaultsEntry 或 None
module_sha1 非 None 时要求条目定义模块完全一致(限定名匹配,消除跨模块同名串味);
为 None 时退化为按名匹配(兼容旧调用点)。
"""
if name is None or self.GlobalDefaults is None:
return None
entry_size: sizet = GenTypes.FuncDefaultsEntry.__sizeof__()
for i in range(self.GlobalDefaultsCount):
entry_addr: uint64 = uint64(self.GlobalDefaults) + i * entry_size
entry: GenTypes.FuncDefaultsEntry* = GenTypes.FuncDefaultsEntry*(entry_addr)
if entry.Name is None:
continue
if string.strcmp(entry.Name, name) != 0:
continue
if module_sha1 is not None:
if entry.ModuleSha1 is None:
continue
if string.strcmp(entry.ModuleSha1, module_sha1) != 0:
continue
return entry
return None
def _build_const_from_snapshot(self, pool: memhub.MemBuddy*,
mod: llvmlite.LLVMModule*,
gd_entry: GenTypes.FuncDefaultsEntry*,
di: int,
trans: HT.Translator*,
builder: llvmlite.IRBuilder*) -> llvmlite.Value*:
"""从快照重建第 di 个默认值常量 IR"""
if gd_entry is None or gd_entry.ConstKinds is None or gd_entry.ConstInts is None:
return None
if di < 0 or di >= gd_entry.DefaultCount:
return None
kind: int = gd_entry.ConstKinds[di]
ival: int64 = gd_entry.ConstInts[di]
if kind == ast.CONST_INT:
if ival > 2147483647 or ival < -2147483648:
return llvmlite.const_int64(pool, ival)
return llvmlite.const_int32(pool, ival)
elif kind == ast.CONST_BOOL:
if ival != 0:
return llvmlite.const_int32(pool, 1)
return llvmlite.const_int32(pool, 0)
elif kind == ast.CONST_NONE:
i8_ty: llvmlite.LLVMType* = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty)
return llvmlite.ConstNull(pool, i8_ptr_ty, "null")
elif kind == ast.CONST_STR:
if gd_entry.ConstStrs is not None and gd_entry.ConstStrs[di] != 0:
sv: str = rawptr(gd_entry.ConstStrs[di])
return self.Gen.ExprGenConst.create_global_string(builder, pool, mod, sv, trans)
# 无法重建的(如 CONST_FLOAT/复杂表达式)返回 None,调用方回退到 AST
return None
def find_func_entry_in_table(self, funcs: GenTypes.FuncEntry*,
func_count: int,
name: str) -> GenTypes.FuncEntry*:
"""在函数表中按名称查找,返回完整 FuncEntry 或 None"""
if name is None or funcs is None:
return None
entry_size: sizet = GenTypes.FuncEntry.__sizeof__()
for i in range(func_count):
entry_addr: uint64 = uint64(funcs) + i * entry_size
entry: GenTypes.FuncEntry* = GenTypes.FuncEntry*(entry_addr)
if entry.Name is not None:
# 快速路径:strcmp 判等蕴含首字符相等,首字符不同者跳过 strcmp
if entry.Name[0] == name[0] and string.strcmp(entry.Name, name) == 0:
return entry
return None
def find_func_entry_in_table_owned(self, funcs: GenTypes.FuncEntry*,
func_count: int,
name: str,
owner_sha1: str) -> GenTypes.FuncEntry*:
"""按「裸名 + 定义模块 SHA1」查找函数表条目,返回 FuncEntry 或 None
函数表以**裸名**登记,且 LoadDepVpiIntoModule 会把依赖模块的同名函数
(同样裸名)注入到本模块表 —— 裸名首命中会跨模块串味:usb.vp 的
`uhci.init(io_base)`(1 形参)会命中先注入的 `mm.init`(5 形参/2 默认值)
→ 调用点被补 2 个 `i32 0` → call 3 实参 vs declare/define 1 形参(N17)。
故以 `entry.Func` 的 mangled 名("{定义模块 sha1}.{name}")前缀限定定义
模块;owner_sha1 为 None(模块名不可解)时退化为裸名首命中(旧语义,
避免丢失合法的默认参数填充)。
"""
if name is None or funcs is None:
return None
entry_size: sizet = GenTypes.FuncEntry.__sizeof__()
for i in range(func_count):
entry_addr: uint64 = uint64(funcs) + i * entry_size
entry: GenTypes.FuncEntry* = GenTypes.FuncEntry*(entry_addr)
if entry is None or entry.Name is None:
continue
# 快速路径:strcmp 判等要求首字符相等,首字符不同者跳过 strcmp
# (热点:本函数对函数表逐条按裸名 + 定义模块 SHA1 比对)。
if entry.Name[0] != name[0] or string.strcmp(entry.Name, name) != 0:
continue
if owner_sha1 is None:
return entry
if entry.Func is not None:
fn_nm_o: str = llvmlite.function_get_name(entry.Func)
if fn_nm_o is not None:
if string.strncmp(fn_nm_o, owner_sha1, 16) == 0 and fn_nm_o[16] == '.':
return entry
return None
def NewExprCallHandle(self, pool: memhub.MemBuddy*, trans: HT.Translator*) -> ExprCallHandle*:
h: ExprCallHandle* = pool.alloc(ExprCallHandle.__sizeof__())
if h is None: return None
string.memset(h, 0, ExprCallHandle.__sizeof__())
h.Trans = trans
return h
# ============================================================
# ExprCallHandle - 函数调用处理器(自 HandlesExprCall 迁入)
#
# HandleCall / HandlePrintfCall / HandlePrintCall 提供 trans 接口,
# 内部委托 GenApi.translate_call 等。
# ============================================================
novirtual class ExprCallHandle(HT.Mixin):
"""函数调用处理器:继承 Mixin 获得 Trans 回指针"""
def __init__(self, trans: HT.Translator*):
self.Trans = trans
# ============================================================
# HandleCall - 翻译函数调用,返回 call 结果 Value
# ============================================================
def HandleCall(self, node: ast.AST*) -> llvmlite.Value*:
"""翻译函数调用,从 self.Trans 获取共享状态"""
return GenApi.translate_call(self.Trans.Pool, self.Trans._cur_builder, self.Trans.Module, node, self.Trans._funcs, self.Trans._func_count, self.Trans)
# ============================================================
# HandlePrintfCall - 翻译 printf 调用
# ============================================================
def HandlePrintfCall(self, cl: ast.Call*):
"""翻译 printf 调用,从 self.Trans 获取共享状态"""
GenApi.translate_printf_call(self.Trans.Pool, self.Trans._cur_builder, self.Trans.Module, cl, self.Trans)
# ============================================================
# HandlePrintCall - 翻译 print 调用
# ============================================================
def HandlePrintCall(self, cl: ast.Call*):
"""翻译 print 调用(类型感知格式化 + 默认换行)"""
GenApi.translate_print_call(self.Trans.Pool, self.Trans._cur_builder, self.Trans.Module, cl, self.Trans)