feat: 支持 t.Callable 函数指针类型注解、赋值与间接调用(含返回类型签名缓存)

This commit is contained in:
TermiNexus committed 2026-08-08 01:12:40 +08:00
1 parent 3197152d4e
commit 09833a80eb
3 files changed
+212 -10

No files matched your search

+162 -4
View File
@@ -5394,11 +5394,16 @@ def translate_call(pool: memhub.MemBuddy | t.CPtr,
else:
call_ret_ty = _infer_external_func_ret_ty(pool, func_name)
# 如果模块中找不到函数,检查是否是变量(闭包调用)
# 如果模块中找不到函数,检查是否是变量(函数指针 / 闭包调用)
if found_func is None:
closure_ptr: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, func_name)
if closure_ptr is not None:
return translate_closure_call(pool, builder, mod, closure_ptr,
fp_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, func_name)
if fp_alloca is not None:
# 函数指针变量(t.Callable 注解 → i8** alloca):按实参构造签名间接调用
if _is_func_ptr_alloca(fp_alloca) != 0:
return _translate_func_ptr_call(pool, builder, mod, fp_alloca,
func_name, cargs, can, trans)
# 闭包变量(i8* alloca):走闭包调用路径
return translate_closure_call(pool, builder, mod, fp_alloca,
cargs, can)
# 翻译参数并链接
@@ -5756,6 +5761,159 @@ def translate_closure_call(pool: memhub.MemBuddy | t.CPtr,
env_ptr.Next = None
return llvmlite.build_call_indirect(builder, fn_typed, env_ptr, 1, i32_ty)
# ============================================================
# _is_func_ptr_alloca - 判断变量 alloca 是否为函数指针变量
#
# 函数指针变量(t.Callable 注解 → i8*)的 alloca 类型是 Ptr(Ptr(i8)) = i8**;
# 闭包变量 alloca 是 i8*(Ptr(i8))。通过类型层级区分。
# ============================================================
def _is_func_ptr_alloca(alloca: llvmlite.Value | t.CPtr) -> int:
"""判断 alloca 是否为函数指针变量(类型 Ptr(Ptr(i8))),1=是 / 0=否"""
if alloca is None or alloca.Ty is None:
return 0
if HandlesExpr.is_ptr_type(alloca.Ty) == 0:
return 0
pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee
if pointee is None or HandlesExpr.is_ptr_type(pointee) == 0:
return 0
inner: llvmlite.LLVMType | t.CPtr = pointee.Pointee
if inner is None or HandlesExpr.is_ptr_type(inner) != 0:
return 0
return 1
# ============================================================
# 函数指针变量签名表(变量名 → 返回类型)
#
# AnnAssign 处理 t.Callable 注解时注册,函数指针间接调用时
# 按注册的返回类型构造签名(而非默认 i32)。
# ============================================================
MAX_FUNC_PTR_SIGS: t.CDefine = 64
_g_funcptr_names: t.CChar | t.CPtr = None
_g_funcptr_rets: t.CUInt64T | t.CPtr = None
_g_funcptr_count: int = 0
def _ensure_funcptr_sigs() -> int:
"""确保函数指针签名表已分配(stdlib.malloc,懒初始化)"""
global _g_funcptr_names, _g_funcptr_rets
if _g_funcptr_names is not None:
return 1
_g_funcptr_names = stdlib.malloc(64 * MAX_FUNC_PTR_SIGS)
_g_funcptr_rets = stdlib.malloc(8 * MAX_FUNC_PTR_SIGS)
if _g_funcptr_names is None or _g_funcptr_rets is None:
return 0
string.memset(_g_funcptr_names, 0, 64 * MAX_FUNC_PTR_SIGS)
return 1
def register_func_ptr_sig(name: str,
ret_ty: llvmlite.LLVMType | t.CPtr) -> int:
"""注册函数指针变量的返回类型签名,0 成功"""
global _g_funcptr_count
if name is None or ret_ty is None:
return 1
if _ensure_funcptr_sigs() == 0:
return 1
if _g_funcptr_count >= MAX_FUNC_PTR_SIGS:
return 1
idx: t.CSizeT = t.CSizeT(_g_funcptr_count) * 64
string.strcpy(_g_funcptr_names + idx, name)
_g_funcptr_rets[_g_funcptr_count] = t.CUInt64T(ret_ty)
_g_funcptr_count += 1
return 0
def lookup_func_ptr_ret(name: str) -> llvmlite.LLVMType | t.CPtr:
"""查函数指针变量的返回类型,None=未注册(调用时默认 i32)"""
if name is None or _g_funcptr_names is None:
return None
for i in range(_g_funcptr_count):
idx: t.CSizeT = t.CSizeT(i) * 64
if string.strcmp(_g_funcptr_names + idx, name) == 0:
return (llvmlite.LLVMType | t.CPtr)(
t.CVoid(_g_funcptr_rets[i], t.CPtr))
return None
# ============================================================
# _translate_func_ptr_call - 函数指针变量间接调用
#
# func_p: t.Callable[[A, B], Ret] 后调用 func_p(a, b):
# 1. load 函数地址 (i8*)
# 2. 翻译实参并链接为 Value 链表
# 3. 按实参类型 + 注册的返回类型构造签名(未注册时默认 i32)
# 4. bitcast i8* → 函数指针类型,间接调用
# ============================================================
def _translate_func_ptr_call(pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
fp_alloca: llvmlite.Value | t.CPtr,
func_name: str,
cargs: list[ast.AST | t.CPtr] | t.CPtr,
can: t.CSizeT,
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
"""函数指针变量间接调用,返回结果 Value"""
if builder is None or fp_alloca is None:
return None
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
# 1. load 函数地址 (i8*)
fn_i8: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, fp_alloca)
if fn_i8 is None:
return None
# 2. 翻译实参并链接为 Value 链表
head: llvmlite.Value | t.CPtr = None
tail: llvmlite.Value | t.CPtr = None
arg_count: int = 0
ai: t.CSizeT
for ai in range(can):
arg: ast.AST | t.CPtr = cargs.get(ai)
if arg is not None:
arg_val: llvmlite.Value | t.CPtr = HandlesExpr.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. 按实参类型 + 注册的返回类型构造签名(未注册返回类型时默认 i32)
ret_ty: llvmlite.LLVMType | t.CPtr = lookup_func_ptr_ret(func_name)
if ret_ty is None:
ret_ty = i32_ty
fp_first: llvmlite.ParamNode | t.CPtr = None
fp_prev: llvmlite.ParamNode | t.CPtr = None
cur_v: llvmlite.Value | t.CPtr = head
for pi in range(arg_count):
if cur_v is None:
break
cur_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(cur_v)
pn2: llvmlite.ParamNode | t.CPtr = 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 | t.CPtr = llvmlite.Func(pool, ret_ty, fp_first, arg_count)
if func_ty is None:
return None
func_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, func_ty)
# 4. bitcast i8* → 函数指针类型,间接调用
fn_typed: llvmlite.Value | t.CPtr = 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)
# ============================================================
# 翻译 printf 调用 — 模块级版本
# ============================================================