refactor(gen): CallGenMixin 阶段 B 拆出 6 组(Ctor/Call/Prop/Fd/Vt/Va),顶层剩 translate_call 中枢

This commit is contained in:
TermiNexus committed 2026-08-17 06:34:33 +08:00
1 parent 8d9ff96f61
commit 1718738a19
9 files changed
+4123 -3818

No files matched your search

File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+437
View File
@@ -0,0 +1,437 @@
import t, c
from stdint import *
import ast
import llvmlite
import memhub
import string
import stdio
import stdlib
import sys
import viperlib
import w32.fileio as fileio
import lib.core.VLogger as VLogger
import lib.core.Handles.HandlesBase as HandlesBase
import lib.core.Handles.HandlesTranslator as HT
import lib.core.Handles.HandlesExpr as HandlesExpr
import lib.core.Handles.HandlesVar as HandlesVar
import lib.core.Handles.HandlesType as HandlesType
import lib.core.Handles.HandlesNonlocal as HandlesNonlocal
import lib.core.Handles.HandlesStruct as HandlesStruct
import lib.core.Handles.HandlesImports as HandlesImports
import lib.core.Handles.HandlesClassDef as HandlesClassDef
import lib.core.Handles.HandlesFunctions as HandlesFunctions
import lib.core.StubMerger as StubMerger
import lib.core.Handles.HandlesExprCall as HandlesExprCall
import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign
import lib.core.CompilerFactory as CompilerFactory
import lib.core.Gen.CallGenBase as CallGenBase
# ============================================================
# CallGenFd - CallGenMixin 拆分(阶段 B):FakeDuck / requires 字段注入 / provider 栈
#
# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。
# 跨 Mixin 调用统一走 HandlesExprCall 委托(经 _g_gen)。
# @t.NoVTable:静态绑定。
# ============================================================
@t.NoVTable
class CallGenFd(CallGenBase.CallGenBase):
"""FakeDuck / requires 字段注入 / provider 栈"""
# ============================================================
# _translate_fakeduck_call - FakeDuck: str 变量方法调用 → 扩展类 _Type/_str
#
# 对齐 TPC HandlesExprCall.py L2841-2880:
# ClassName 常规解析失败且对象是 char*(i8*)时,遍历扩展类查找
# {CN}.{method} 函数。对象是 Name 变量且有影子({var}__meta__,fd2
# 创建)时 self=影子;否则(字符串字面量/匿名 str)在入口创建临时
# 影子,写 __data__=obj 值、__mbuddy__=NULL 后作 self,避免
# bitcast i8* → _str* 读取垃圾指针导致 ACCESS_VIOLATION。
# ============================================================
# ============================================================
# _translate_fakeduck_call - FakeDuck: str 变量方法调用 → 扩展类 _Type/_str
#
# 对齐 TPC HandlesExprCall.py L2841-2880:
# ClassName 常规解析失败且对象是 char*(i8*)时,遍历扩展类查找
# {CN}.{method} 函数。对象是 Name 变量且有影子({var}__meta__,fd2
# 创建)时 self=影子;否则(字符串字面量/匿名 str)在入口创建临时
# 影子,写 __data__=obj 值、__mbuddy__=NULL 后作 self,避免
# bitcast i8* → _str* 读取垃圾指针导致 ACCESS_VIOLATION。
# ============================================================
def _translate_fakeduck_call(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
cls_name: str,
method_name: str,
cl: ast.Call | t.CPtr,
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
"""FakeDuck: str 变量方法调用解析到扩展类 _Type/_str,返回 call 结果或 None"""
if pool is None or builder is None or cl is None or trans is None:
return None
if method_name is None:
return None
# 仅对 str 类型触发(AnnotClassName == "str",对象是 char*);
# cls_name 为 None(表达式接收者解析失败)时也尝试
if cls_name is not None and string.strcmp(cls_name, "str") != 0:
return None
if cl.func is None or cl.func.kind() != ast.ASTKind.Attribute:
return None
fd_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
if fd_at is None or fd_at.value is None or fd_at.attr is None:
return None
if string.strcmp(fd_at.attr, method_name) != 0:
return None
# 候选扩展类:先 _Type(a.type_id())后 _str(a.upper() 等)
fd_func: llvmlite.Function | t.CPtr = None
fd_cls: str = None
fd_key: str = pool.alloc(160)
if fd_key is not None:
for fd_ci in range(2):
fd_cn: str = "_Type"
if fd_ci == 1:
fd_cn = "_str"
viperlib.snprintf(fd_key, 160, "%s.%s", fd_cn, method_name)
fd_func = self.find_func_in_module(mod, fd_key)
if fd_func is not None:
fd_cls = fd_cn
break
if fd_func is None or fd_cls is None:
return None
# 扩展类结构体必须已注册(GEP/临时影子需要类型)
fd_sty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(fd_cls)
if fd_sty is None:
return None
# 扩展类字段数:有字段(_str)时 self 用影子结构体指针;
# 无字段(_Type)时 self 用对象值 bitcast 到扩展类指针(对齐 TPC L2856-2876)
fd_entry_fd: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(fd_sty)
fd_has_fields: int = 0
if fd_entry_fd is not None and fd_entry_fd.FieldCount > 0:
fd_has_fields = 1
# self 参数:优先使用已有影子 {var}__meta__(fd2 创建,仅当扩展类有字段时)
fd_self: llvmlite.Value | t.CPtr = None
if fd_at.value.kind() == ast.ASTKind.Name:
fd_onm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(fd_at.value)
if fd_onm.id is not None:
# pool 持久缓冲(f-string 栈缓冲在函数返回后失效)
fd_mn: str = pool.alloc(256)
if fd_mn is not None:
viperlib.snprintf(fd_mn, 256, "%s__meta__", fd_onm.id)
fd_meta: llvmlite.Value | t.CPtr = HandlesVar.lookup_current(
trans.SymTab, fd_mn)
if fd_meta is not None and fd_has_fields != 0:
fd_self = fd_meta
if fd_self is None:
if fd_has_fields != 0:
# 有字段扩展类且无影子(字符串字面量等):入口创建临时影子并初始化
# 先确保 _str 完整定义(跨模块结构体默认 opaque,alloca 报 unsized)
HandlesStruct.ensure_struct_def_in_module(pool, mod, fd_sty)
fd_self = HandlesVar._alloca_at_entry(builder, fd_sty)
if fd_self is None:
return None
fd_obj_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, fd_at.value, None, 0, trans)
if fd_obj_val is not None:
fd_dfe: HandlesStruct.FieldEntry | t.CPtr = \
HandlesStruct.lookup_field(fd_sty, "__data__")
if fd_dfe is not None and fd_dfe.Ty is not None:
fd_dp: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
builder, fd_sty, fd_dfe.Ty, fd_self, fd_dfe.Index)
if fd_dp is not None:
llvmlite.build_store(builder, fd_obj_val, fd_dp)
fd_bfe: HandlesStruct.FieldEntry | t.CPtr = \
HandlesStruct.lookup_field(fd_sty, "__mbuddy__")
if fd_bfe is not None and fd_bfe.Ty is not None:
fd_bp: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
builder, fd_sty, fd_bfe.Ty, fd_self, fd_bfe.Index)
fd_null: llvmlite.Value | t.CPtr = llvmlite.ConstNull(
pool, fd_bfe.Ty, "null")
if fd_bp is not None and fd_null is not None:
llvmlite.build_store(builder, fd_null, fd_bp)
# FakeDuck: with 上下文自动注入 requires 字段(如 __mbuddy__)
self._inject_requires_fields(
trans, pool, builder, mod, fd_self, fd_cls)
else:
# 无字段扩展类(_Type):对象值 bitcast 到扩展类指针
fd_obj_v: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, fd_at.value, None, 0, trans)
if fd_obj_v is None:
return None
fd_self = llvmlite.build_bitcast(
builder, fd_obj_v, llvmlite.Ptr(pool, fd_sty))
if fd_self is None:
return None
# 构建参数链表: self → 其余参数
llvmlite.value_set_next(fd_self, None)
fd_head: llvmlite.Value | t.CPtr = fd_self
fd_tail: llvmlite.Value | t.CPtr = fd_self
fd_args: list[ast.AST | t.CPtr] | t.CPtr = cl.args
fd_can: int = 0
if fd_args is not None:
fd_can = len(fd_args)
for fd_ai in range(fd_can):
fd_arg: ast.AST | t.CPtr = fd_args.get(fd_ai)
if fd_arg is not None:
fd_av: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, fd_arg, None, 0, trans)
# char 常量参数 → 单字符字符串(char 隐式转 str,
# 如 s1.split(','):',' 是 i32 值 44,传给 str 参数须先字符串化,
# 否则运行时 strlen/strncmp 解引用 44 崩溃)
if fd_arg.kind() == ast.ASTKind.Constant:
fd_ac: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(fd_arg)
if fd_ac.const_kind == ast.CONST_CHAR:
ch_buf: str = pool.alloc(2)
if ch_buf is not None:
ch_buf[0] = t.CChar(fd_ac.int_val)
ch_buf[1] = '\0'
fd_av = HandlesExpr.create_global_string(
builder, pool, mod, ch_buf, trans)
if fd_av is not None:
llvmlite.value_set_next(fd_av, None)
llvmlite.value_set_next(fd_tail, fd_av)
fd_tail = fd_av
# 返回类型与调用名(来自 find_func_in_module 命中的函数定义)
fd_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(fd_func)
if fd_ret_ty is None:
fd_ret_ty = llvmlite.Int32(pool)
fd_fname: str = llvmlite.function_get_name(fd_func)
if fd_fname is None:
return None
# 返回类型精确化:跨模块 declare 的 list[T] 特化返回类型可能被简化
# 为 Ptr(i8),调用方变量 alloca 类型随之退化 → parts[0] 走字符下标
# 路径而非 list 内联 __getitem__(printf %s 解引用字符值崩溃)。
# 从定义模块 text.ll 读取精确返回类型(对齐普通方法调用 _translate_method_call)。
fd_sha1: str = pool.alloc(17)
if fd_sha1 is not None:
string.strncpy(fd_sha1, fd_fname, 16)
fd_sha1[16] = '\0'
fd_exact: llvmlite.LLVMType | t.CPtr = self._LookupMethodRetTyFromTextLL(
pool, fd_sha1, fd_cls, method_name)
if fd_exact is not None:
fd_ret_ty = fd_exact
fd_total: int = 1 + fd_can
return llvmlite.build_call(builder, fd_fname, fd_head, fd_total, fd_ret_ty, 0)
# ============================================================
# _inject_requires_fields - FakeDuck: with 上下文注入 requires 字段
#
# 对齐 TPC HandlesExprCall.py L4021-4079:
# 对类 __requires__ 元数据(fd1 注册)中的每个字段,运行时调用
# _find_provider(field) 查找 with 上下文提供的指针;非 NULL 时
# bitcast 到字段类型写入 meta_ptr 对应槽位(条件注入,避免覆盖
# 用户已手动设置的值)。_find_provider 未注册(未 import
# _withcontent)时跳过注入,不影响非 with 场景。
# ============================================================
# ============================================================
# _inject_requires_fields - FakeDuck: with 上下文注入 requires 字段
#
# 对齐 TPC HandlesExprCall.py L4021-4079:
# 对类 __requires__ 元数据(fd1 注册)中的每个字段,运行时调用
# _find_provider(field) 查找 with 上下文提供的指针;非 NULL 时
# bitcast 到字段类型写入 meta_ptr 对应槽位(条件注入,避免覆盖
# 用户已手动设置的值)。_find_provider 未注册(未 import
# _withcontent)时跳过注入,不影响非 with 场景。
# ============================================================
def _inject_requires_fields(self, trans: HT.Translator | t.CPtr,
pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
meta_ptr: llvmlite.Value | t.CPtr,
class_name: str) -> int:
"""在 with 上下文注入 requires 字段,返回注入字段数"""
if trans is None or pool is None or builder is None or mod is None:
return 0
if meta_ptr is None or class_name is None:
return 0
# _withcontent._find_provider(跨模块):仅当本模块可见(_withcontent
# 被 import,vpi stub declare 已注入)时才注入。对齐 TPC L4048-4050
# (Gen.functions.get('_find_provider') 不存在则跳过)——否则非 with
# 项目(如 HashTableTest 未 import _withcontent)也会为每个 _str(...)
# 构造发射 {sha1}._find_provider 调用 → ld.lld undefined symbol。
fd_fn_probe: llvmlite.Function | t.CPtr = self.find_func_in_module(
mod, "_find_provider")
if fd_fn_probe is None:
return 0
fd_fname: str = llvmlite.function_get_name(fd_fn_probe)
if fd_fname is None:
return 0
cnt: int = HandlesType.class_meta_count(
HandlesType.CLASS_META_REQUIRES, class_name)
if cnt <= 0:
return 0
sty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(class_name)
if sty is None:
return 0
i8_ty_j: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
if i8_ty_j is None:
return 0
i8_ptr_ty_j: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_j)
if i8_ptr_ty_j is None:
return 0
cur_func: llvmlite.Function | t.CPtr = trans._cur_func
if cur_func is None:
return 0
injected: int = 0
for ji in range(cnt):
fname: str = HandlesType.class_meta_field_at(
HandlesType.CLASS_META_REQUIRES, class_name, ji)
if fname is None:
continue
fe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field(
sty, fname)
if fe is None or fe.Ty is None:
continue
# 参数:字段名字符串(i8*)
fd_fstr: llvmlite.Value | t.CPtr = HandlesExpr.create_global_string(
builder, pool, mod, fname, trans)
if fd_fstr is None:
continue
llvmlite.value_set_next(fd_fstr, None)
self._ensure_method_declare(
pool, mod, fd_fname, i8_ptr_ty_j, fd_fstr, 1)
fd_ptr: llvmlite.Value | t.CPtr = llvmlite.build_call(
builder, fd_fname, fd_fstr, 1, i8_ptr_ty_j, 0)
if fd_ptr is None:
continue
# 条件注入:ptr != NULL 才写入(保留用户手动设置的值)
fd_null: llvmlite.Value | t.CPtr = llvmlite.ConstNull(
pool, i8_ptr_ty_j, "null")
if fd_null is None:
continue
fd_cmp: llvmlite.Value | t.CPtr = llvmlite.build_icmp(
builder, llvmlite.ICMP_NE, fd_ptr, fd_null)
if fd_cmp is None:
continue
# 块名唯一化(create_block 不自动编号,同名 label 在文本 IR 中
# 冲突 → llc "Terminator found in the middle of a basic block")
vtc2: int = trans._label_counter
trans._label_counter = vtc2 + 1
fd_bb_buf2: str = pool.alloc(64)
if fd_bb_buf2 is None:
continue
viperlib.snprintf(fd_bb_buf2, 64, "fd.skip.%d", vtc2)
fd_skip_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(
pool, cur_func, fd_bb_buf2)
viperlib.snprintf(fd_bb_buf2, 64, "fd.inject.%d", vtc2)
fd_inject_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(
pool, cur_func, fd_bb_buf2)
if fd_skip_bb is None or fd_inject_bb is None:
continue
llvmlite.build_cond_br(builder, fd_cmp, fd_inject_bb, fd_skip_bb)
# inject 块:bitcast + GEP + store,跳回 skip
llvmlite.position_at_end(builder, fd_inject_bb)
fd_cast: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
builder, fd_ptr, fe.Ty)
if fd_cast is not None:
fd_fp: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
builder, sty, fe.Ty, meta_ptr, fe.Index)
if fd_fp is not None:
llvmlite.build_store(builder, fd_cast, fd_fp)
llvmlite.build_br(builder, fd_skip_bb)
# skip 块:恢复 CurBlock,继续后续代码生成
llvmlite.position_at_end(builder, fd_skip_bb)
injected += 1
return injected
# ============================================================
# _emit_provider_push / _emit_provider_pop - FakeDuck: with 上下文
# provider push/pop(__provides__ 元数据,fd1 注册)
#
# 对齐 TPC HandlesWith.py L138-174:
# with 进入时对每个提供字段生成 _push_provider(field_str, ctx_i8);
# 退出时生成等量 _pop_provider()。运行时 _withcontent 模块负责
# 维护 TLS provider 栈,供 _inject_requires_fields 查找。
# ============================================================
# ============================================================
# _emit_provider_push / _emit_provider_pop - FakeDuck: with 上下文
# provider push/pop(__provides__ 元数据,fd1 注册)
#
# 对齐 TPC HandlesWith.py L138-174:
# with 进入时对每个提供字段生成 _push_provider(field_str, ctx_i8);
# 退出时生成等量 _pop_provider()。运行时 _withcontent 模块负责
# 维护 TLS provider 栈,供 _inject_requires_fields 查找。
# ============================================================
def _emit_provider_push(self, trans: HT.Translator | t.CPtr,
pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
cls_name: str,
ctx_val: llvmlite.Value | t.CPtr) -> int:
"""生成 _push_provider(field, ctx_i8) 调用(每提供字段一次),返回字段数"""
if trans is None or pool is None or builder is None or mod is None:
return 0
if cls_name is None or ctx_val is None:
return 0
fd_pc: int = HandlesType.class_meta_count(
HandlesType.CLASS_META_PROVIDES, cls_name)
if fd_pc <= 0:
return 0
# _withcontent._push_provider(跨模块,同 _find_provider 的可见性守卫:
# 本模块未 import _withcontent 时跳过,避免 undefined symbol)
fd_pfn_probe: llvmlite.Function | t.CPtr = self.find_func_in_module(
mod, "_push_provider")
if fd_pfn_probe is None:
return 0
fd_pfn: str = llvmlite.function_get_name(fd_pfn_probe)
if fd_pfn is None:
return 0
i8_ty_p: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
if i8_ty_p is None:
return 0
i8_ptr_ty_p: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_p)
if i8_ptr_ty_p is None:
return 0
ret_i32_p: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
if ret_i32_p is None:
return 0
# ctx 值 bitcast 到 i8*(provider 栈存 void*)
fd_ctx_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
builder, ctx_val, i8_ptr_ty_p)
if fd_ctx_i8 is None:
return 0
for pi in range(fd_pc):
fname: str = HandlesType.class_meta_field_at(
HandlesType.CLASS_META_PROVIDES, cls_name, pi)
if fname is None:
continue
fd_fstr: llvmlite.Value | t.CPtr = HandlesExpr.create_global_string(
builder, pool, mod, fname, trans)
if fd_fstr is None:
continue
llvmlite.value_set_next(fd_fstr, fd_ctx_i8)
llvmlite.value_set_next(fd_ctx_i8, None)
self._ensure_method_declare(
pool, mod, fd_pfn, ret_i32_p, fd_fstr, 2)
llvmlite.build_call(builder, fd_pfn, fd_fstr, 2, ret_i32_p, 0)
return fd_pc
def _emit_provider_pop(self, trans: HT.Translator | t.CPtr,
pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
cls_name: str) -> int:
"""生成 _pop_provider() 调用(每提供字段一次),返回字段数"""
if trans is None or pool is None or builder is None or mod is None:
return 0
if cls_name is None:
return 0
fd_pc: int = HandlesType.class_meta_count(
HandlesType.CLASS_META_PROVIDES, cls_name)
if fd_pc <= 0:
return 0
# _withcontent._pop_provider(跨模块,同 _find_provider 的可见性守卫:
# 本模块未 import _withcontent 时跳过,避免 undefined symbol)
fd_pon_probe: llvmlite.Function | t.CPtr = self.find_func_in_module(
mod, "_pop_provider")
if fd_pon_probe is None:
return 0
fd_pon: str = llvmlite.function_get_name(fd_pon_probe)
if fd_pon is None:
return 0
ret_i32_q: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
if ret_i32_q is None:
return 0
self._ensure_method_declare(pool, mod, fd_pon, ret_i32_q, None, 0)
for _pi in range(fd_pc):
llvmlite.build_call(builder, fd_pon, None, 0, ret_i32_q, 0)
return fd_pc
File diff suppressed because it is too large. Load diff
+455
View File
@@ -0,0 +1,455 @@
import t, c
from stdint import *
import ast
import llvmlite
import memhub
import string
import stdio
import stdlib
import sys
import viperlib
import w32.fileio as fileio
import lib.core.VLogger as VLogger
import lib.core.Handles.HandlesBase as HandlesBase
import lib.core.Handles.HandlesTranslator as HT
import lib.core.Handles.HandlesExpr as HandlesExpr
import lib.core.Handles.HandlesVar as HandlesVar
import lib.core.Handles.HandlesType as HandlesType
import lib.core.Handles.HandlesNonlocal as HandlesNonlocal
import lib.core.Handles.HandlesStruct as HandlesStruct
import lib.core.Handles.HandlesImports as HandlesImports
import lib.core.Handles.HandlesClassDef as HandlesClassDef
import lib.core.Handles.HandlesFunctions as HandlesFunctions
import lib.core.StubMerger as StubMerger
import lib.core.Handles.HandlesExprCall as HandlesExprCall
import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign
import lib.core.CompilerFactory as CompilerFactory
import lib.core.Gen.CallGenBase as CallGenBase
# ============================================================
# CallGenProp - CallGenMixin 拆分(阶段 B):属性访问(getter/setter/deleter / 静态类调用 / list 内置方法)
#
# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。
# 跨 Mixin 调用统一走 HandlesExprCall 委托(经 _g_gen)。
# @t.NoVTable:静态绑定。
# ============================================================
@t.NoVTable
class CallGenProp(CallGenBase.CallGenBase):
"""属性访问(getter/setter/deleter / 静态类调用 / list 内置方法)"""
# ============================================================
# _ensure_method_declare - 为跨模块方法调用创建 declare 声明
#
# 当 found_func 为 None(stub 未注入或跨模块调用)时,
# 在当前模块中创建函数声明,避免 llc 报 undefined value。
# ============================================================
# ============================================================
# 属性方法(@property/@x.setter/@x.deleter)与静态/类方法调用辅助
#
# 元数据表由 HandlesClassDef 在类翻译/预注册阶段填充,
# 这里负责把 obj.prop / obj.prop=v / del obj.prop / Class.method()
# 翻译为对应的 {sha1}.ClassName.prop 系列函数调用。
# ============================================================
# ============================================================
# _translate_property_call — 翻译属性方法调用
#
# 与 _translate_method_call 的调用名/返回类型解析逻辑一致:
# 1. 优先用模块中已有的函数(精确/后缀匹配,来自 stub 注入)
# 2. 否则用类所属模块的 SHA1 构造 "{sha1}.ClassName.method" 调用名
# 3. 返回类型:函数实类型 → text.ll 查找 → 按方法名推断(默认 i32)
#
# call_head/call_count: 已构建好的参数链表(如 getter 只有 obj 一个参数)
# ============================================================
def _translate_property_call(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
class_name: str,
method_name: str,
call_head: llvmlite.Value | t.CPtr,
call_count: int,
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
"""翻译属性/静态方法调用,返回 call 结果 Value"""
if pool is None or builder is None or class_name is None or method_name is None:
return None
# 构造查找名: ClassName.method_name
lookup_name: str = pool.alloc(128)
if lookup_name is None:
return None
viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, method_name)
# 查找函数(精确/后缀匹配)
found_func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, lookup_name)
# 确定调用名
call_name: str = lookup_name
if found_func is not None:
found_name: str = llvmlite.function_get_name(found_func)
if found_name is not None:
call_name = found_name
else:
# 未找到:用类所属模块的 SHA1 构造调用名
cls_sha1_pc: str = HandlesStruct.get_struct_sha1(class_name)
if cls_sha1_pc is not None:
mlen_pc: t.CSizeT = string.strlen(cls_sha1_pc) + string.strlen(lookup_name) + 2
mangled_pc: str = pool.alloc(mlen_pc)
if mangled_pc is not None:
viperlib.snprintf(mangled_pc, mlen_pc, "%s.%s", cls_sha1_pc, lookup_name)
call_name = mangled_pc
# 确定返回类型
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
call_ret_ty: llvmlite.LLVMType | t.CPtr = i32_ty
if found_func is not None:
frt: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(found_func)
if frt is not None:
call_ret_ty = frt
else:
sp_ty1: llvmlite.LLVMType | t.CPtr = self._special_method_ret_ty(pool, class_name, method_name)
if sp_ty1 is not None:
call_ret_ty = sp_ty1
else:
cls_sha1_rt: str = HandlesStruct.get_struct_sha1(class_name)
looked_up_ty: llvmlite.LLVMType | t.CPtr = self._LookupMethodRetTyFromTextLL(
pool, cls_sha1_rt, class_name, method_name)
if looked_up_ty is not None:
call_ret_ty = looked_up_ty
else:
# 精确查找:vpi stub 返回注解缓存(方法定义处,不硬编码白名单)
vpi_ret_ty: llvmlite.LLVMType | t.CPtr = self._lookup_method_ret_ty_via_vpi(
pool, cls_sha1_rt, class_name, method_name)
if vpi_ret_ty is not None:
call_ret_ty = vpi_ret_ty
else:
# Phase A 依赖未就绪(cls_sha1_rt None / 定义模块 text.ll 未生成):
# 标记 pending 下遍重译(对齐 _translate_method_call L4783-4790),
# 绝不 fail-fast 中断多遍收敛;真实错误由收敛检查兜底。
if cls_sha1_rt is None \
or self._dep_text_ll_exists(pool, cls_sha1_rt) == 0:
if trans is not None:
trans._deps_pending = 1
call_ret_ty = llvmlite.Void(pool)
else:
call_ret_ty = self._fail_method_ret_ty(method_name)
# 参数类型对齐:按目标函数声明的参数类型转换实参(与 _translate_method_call
# 一致)。例如 from_long(10) 的 i32 字面量 → i64 形参(v: t.CLong),
# 不转换则 call(i32) 与 declare(i64) 不匹配,llc 报参数类型错误。
# 目标函数优先用已找到的 found_func,否则按 mangled 调用名查模块 declare。
tgt_func_pc: llvmlite.Function | t.CPtr = found_func
if tgt_func_pc is None:
tgt_func_pc = self.find_func_in_module(mod, call_name)
if tgt_func_pc is not None:
prev_pc: llvmlite.Value | t.CPtr = None
cur_arg_pc: llvmlite.Value | t.CPtr = call_head
cur_param_pc: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(tgt_func_pc)
while cur_arg_pc is not None and cur_param_pc is not None:
param_ty_pc: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur_param_pc)
if param_ty_pc is not None and cur_arg_pc.Ty is not None:
coerced_pc: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(
builder, cur_arg_pc, param_ty_pc)
if coerced_pc is not None and coerced_pc != cur_arg_pc:
# 保持链表完整性:新 Value 继承原节点的 Next,前驱指向新节点
llvmlite.value_set_next(coerced_pc, cur_arg_pc.Next)
if prev_pc is None:
call_head = coerced_pc
else:
llvmlite.value_set_next(prev_pc, coerced_pc)
cur_arg_pc = coerced_pc
prev_pc = cur_arg_pc
cur_arg_pc = cur_arg_pc.Next
cur_param_pc = llvmlite.param_get_next(cur_param_pc)
# 确保 declare 存在,然后调用
self._ensure_method_declare(pool, mod, call_name, call_ret_ty, call_head, call_count)
return llvmlite.build_call(builder, call_name, call_head, call_count, call_ret_ty, 0)
# ============================================================
# _resolve_obj_class_name — 解析对象表达式的类名(短名)
#
# 优先从变量注解(AnnotClassName)解析(如 "memhub.MemBuddy" → "MemBuddy"),
# 失败时从 LLVM 类型解析(Ptr(Struct) → 类名)。
# 供属性访问/赋值/删除识别 property 时使用。
# ============================================================
# ============================================================
# _resolve_obj_class_name — 解析对象表达式的类名(短名)
#
# 优先从变量注解(AnnotClassName)解析(如 "memhub.MemBuddy" → "MemBuddy"),
# 失败时从 LLVM 类型解析(Ptr(Struct) → 类名)。
# 供属性访问/赋值/删除识别 property 时使用。
# ============================================================
def _resolve_obj_class_name(self, pool: memhub.MemBuddy | t.CPtr,
trans: HT.Translator | t.CPtr,
obj_node: ast.AST | t.CPtr) -> str:
"""解析对象表达式的类名(短名),失败返回 None"""
if pool is None or trans is None or obj_node is None:
return None
if obj_node.kind() == ast.ASTKind.Name:
obj_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(obj_node)
if obj_nm.id is not None:
var_entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry(
trans.SymTab, obj_nm.id)
if var_entry is not None and var_entry.AnnotClassName is not None:
annot_val: str = var_entry.AnnotClassName
dot_ptr: str = string.strrchr(annot_val, '.')
if dot_ptr is not None:
return dot_ptr + 1
return annot_val
return None
# ============================================================
# _try_property_getter_attr — 尝试将 obj.attr 翻译为 property getter 调用
#
# 检查 obj 的类是否有 @property/@x.getter 的 attr 方法;
# 若有则生成 call Class.attr(obj) 并返回调用结果 Value;否则返回 None。
# ============================================================
# ============================================================
# _try_property_getter_attr — 尝试将 obj.attr 翻译为 property getter 调用
#
# 检查 obj 的类是否有 @property/@x.getter 的 attr 方法;
# 若有则生成 call Class.attr(obj) 并返回调用结果 Value;否则返回 None。
# ============================================================
def _try_property_getter_attr(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
at_node: ast.Attribute | t.CPtr,
obj_ptr: llvmlite.Value | t.CPtr,
trans: HT.Translator | t.CPtr,
fallback_class_name: str = None) -> llvmlite.Value | t.CPtr:
"""尝试 property getter 属性访问,返回调用结果 Value;非 getter 返回 None
fallback_class_name: 对象表达式非 Name 时从 LLVM 类型解析出的类名兜底。
"""
if at_node is None or at_node.attr is None or obj_ptr is None or trans is None:
return None
class_name: str = self._resolve_obj_class_name(pool, trans, at_node.value)
if class_name is None:
class_name = fallback_class_name
if class_name is None:
return None
meta: int = HandlesClassDef.lookup_method_meta(class_name, at_node.attr)
if meta & HandlesClassDef.META_PROP_GETTER == 0:
return None
# 单参数调用: obj → getter
llvmlite.value_set_next(obj_ptr, None)
return self._translate_property_call(
pool, builder, mod, class_name, at_node.attr, obj_ptr, 1, trans)
# ============================================================
# _try_property_setter — 尝试将 obj.attr = v 翻译为 property setter 调用
#
# 检查 obj 的类是否有 @x.setter 的 attr 方法;
# 若有则生成 call Class.attr$set(obj, v),返回 1;否则返回 0。
# ============================================================
# ============================================================
# _try_property_setter — 尝试将 obj.attr = v 翻译为 property setter 调用
#
# 检查 obj 的类是否有 @x.setter 的 attr 方法;
# 若有则生成 call Class.attr$set(obj, v),返回 1;否则返回 0。
# ============================================================
def _try_property_setter(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
target_attr: ast.Attribute | t.CPtr,
rhs_val: llvmlite.Value | t.CPtr,
trans: HT.Translator | t.CPtr) -> int:
"""尝试 property setter 赋值,返回 1=已处理(生成调用)"""
if pool is None or builder is None or mod is None or trans is None:
return 0
if target_attr is None or target_attr.attr is None or rhs_val is None:
return 0
class_name: str = self._resolve_obj_class_name(pool, trans, target_attr.value)
if class_name is None:
return 0
meta: int = HandlesClassDef.lookup_method_meta(class_name, target_attr.attr)
if meta & HandlesClassDef.META_PROP_SETTER == 0:
return 0
# 翻译对象值(self 参数)
obj_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, target_attr.value, None, 0, trans)
if obj_val is None:
return 0
# 构建参数链表: obj → rhs
llvmlite.value_set_next(obj_val, None)
llvmlite.value_set_next(rhs_val, None)
llvmlite.value_set_next(obj_val, rhs_val)
# setter 函数名带 $set 后缀
setter_name_buf: str = pool.alloc(128)
if setter_name_buf is None:
return 0
viperlib.snprintf(setter_name_buf, 128, "%s$set", target_attr.attr)
self._translate_property_call(pool, builder, mod, class_name,
setter_name_buf, obj_val, 2, trans)
return 1
# ============================================================
# _try_property_deleter — 尝试将 del obj.attr 翻译为 property deleter 调用
#
# 检查 obj 的类是否有 @x.deleter 的 attr 方法;
# 若有则生成 call Class.attr$del(obj),返回 1;否则返回 0。
# ============================================================
# ============================================================
# _try_property_deleter — 尝试将 del obj.attr 翻译为 property deleter 调用
#
# 检查 obj 的类是否有 @x.deleter 的 attr 方法;
# 若有则生成 call Class.attr$del(obj),返回 1;否则返回 0。
# ============================================================
def _try_property_deleter(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
target_attr: ast.Attribute | t.CPtr,
trans: HT.Translator | t.CPtr) -> int:
"""尝试 property deleter 删除,返回 1=已处理(生成调用)"""
if pool is None or builder is None or mod is None or trans is None:
return 0
if target_attr is None or target_attr.attr is None:
return 0
class_name: str = self._resolve_obj_class_name(pool, trans, target_attr.value)
if class_name is None:
return 0
meta: int = HandlesClassDef.lookup_method_meta(class_name, target_attr.attr)
if meta & HandlesClassDef.META_PROP_DELETER == 0:
return 0
# 翻译对象值(self 参数)
obj_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, target_attr.value, None, 0, trans)
if obj_val is None:
return 0
llvmlite.value_set_next(obj_val, None)
# deleter 函数名带 $del 后缀
del_name_buf: str = pool.alloc(128)
if del_name_buf is None:
return 0
viperlib.snprintf(del_name_buf, 128, "%s$del", target_attr.attr)
self._translate_property_call(pool, builder, mod, class_name,
del_name_buf, obj_val, 1, trans)
return 1
# ============================================================
# _translate_static_class_call — 翻译 ClassName.method(args) 静态/类方法调用
#
# @staticmethod: 直接 call Class.method(args...),无 self
# @classmethod: 在参数前插入栈上分配的类实例指针(与 TPC 一致)
# ============================================================
# ============================================================
# _translate_static_class_call — 翻译 ClassName.method(args) 静态/类方法调用
#
# @staticmethod: 直接 call Class.method(args...),无 self
# @classmethod: 在参数前插入栈上分配的类实例指针(与 TPC 一致)
# ============================================================
def _translate_static_class_call(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
class_name: str,
method_name: str,
cl: ast.Call | t.CPtr,
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
"""翻译类名静态/类方法调用,返回 call 结果 Value;非静态/类方法返回 None"""
if pool is None or builder is None or mod is None or trans is None:
return None
if class_name is None or method_name is None or cl is None:
return None
meta: int = HandlesClassDef.lookup_method_meta(class_name, method_name)
is_static: int = 0
is_class: int = 0
if meta & HandlesClassDef.META_STATIC != 0:
is_static = 1
if meta & HandlesClassDef.META_CLASS != 0:
is_class = 1
if is_static == 0 and is_class == 0:
return None
# 构建参数链表
head: llvmlite.Value | t.CPtr = None
total_count: int = 0
# @classmethod: 插入栈上分配的类实例指针作为 cls 参数
if is_class != 0:
struct_ty_cc: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(class_name)
if struct_ty_cc is None:
return None
cls_ptr: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty_cc)
if cls_ptr is None:
return None
llvmlite.value_set_next(cls_ptr, None)
head = cls_ptr
total_count = 1
# 翻译调用参数
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
can: t.CSizeT = 0
if cargs is not None:
can = len(cargs)
tail: llvmlite.Value | t.CPtr = head
for ai in range(can):
arg_node: ast.AST | t.CPtr = cargs.get(ai)
if arg_node is None:
continue
arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, arg_node, None, 0, trans)
if arg_val is None:
continue
llvmlite.value_set_next(arg_val, None)
if head is None:
head = arg_val
tail = arg_val
else:
llvmlite.value_set_next(tail, arg_val)
tail = arg_val
total_count += 1
# 零参 @staticmethod(如 PyListObj.new()):head 保持 None 是合法的
# 无参调用,照常走 _translate_property_call(SHA1 前缀名 + 精确返回类型)。
# 若此处 return None,调用方回退通用路径把方法名当裸函数解析,生成
# call i32 @new() → 链接 undefined reference(CPythonTest 根因)。
# @classmethod 恒有 cls_ptr(head 非 None),不受影响。
return self._translate_property_call(pool, builder, mod, class_name,
method_name, head, total_count, trans)
# ============================================================
# _is_list_builtin_method - 判断是否是 list 泛型内置容器方法
#
# list[T] 是内置泛型容器(_list.vp),其方法(append/get/set/pop/clear/
# __iter__/__len__/__getitem__/__setitem__)由 translate_call 的 list
# 内置分支内联 GEP 处理,不注册为方法函数。若 obj.method() 检测把
# list 特化 struct(如 list[AST | CPtr])误当普通结构体走
# _translate_method_call,会查不到 append 返回类型 → fail-fast
# (NewAstTest body.append 根因)。此判断用于跳过 method_call 路径。
#
# 返回: 1=list 内置方法(应落到 list 内置分支),0=普通方法
# ============================================================
# ============================================================
# _is_list_builtin_method - 判断是否是 list 泛型内置容器方法
#
# list[T] 是内置泛型容器(_list.vp),其方法(append/get/set/pop/clear/
# __iter__/__len__/__getitem__/__setitem__)由 translate_call 的 list
# 内置分支内联 GEP 处理,不注册为方法函数。若 obj.method() 检测把
# list 特化 struct(如 list[AST | CPtr])误当普通结构体走
# _translate_method_call,会查不到 append 返回类型 → fail-fast
# (NewAstTest body.append 根因)。此判断用于跳过 method_call 路径。
#
# 返回: 1=list 内置方法(应落到 list 内置分支),0=普通方法
# ============================================================
def _is_list_builtin_method(self, class_name: str,
method_name: str) -> int:
"""判断 (class_name, method_name) 是否是 list 泛型内置方法"""
if class_name is None or method_name is None:
return 0
# 类名必须以 "list" 开头(list / list[AST | CPtr] 特化名)
if string.strncmp(class_name, "list", 4) != 0:
return 0
# 方法名必须是 list 内置方法集合
if string.strcmp(method_name, "append") == 0: return 1
if string.strcmp(method_name, "get") == 0: return 1
if string.strcmp(method_name, "set") == 0: return 1
if string.strcmp(method_name, "pop") == 0: return 1
if string.strcmp(method_name, "clear") == 0: return 1
if string.strcmp(method_name, "__iter__") == 0: return 1
if string.strcmp(method_name, "__len__") == 0: return 1
if string.strcmp(method_name, "__getitem__") == 0: return 1
if string.strcmp(method_name, "__setitem__") == 0: return 1
return 0
+334
View File
@@ -0,0 +1,334 @@
import t, c
from stdint import *
import ast
import llvmlite
import memhub
import string
import stdio
import stdlib
import sys
import viperlib
import w32.fileio as fileio
import lib.core.VLogger as VLogger
import lib.core.Handles.HandlesBase as HandlesBase
import lib.core.Handles.HandlesTranslator as HT
import lib.core.Handles.HandlesExpr as HandlesExpr
import lib.core.Handles.HandlesVar as HandlesVar
import lib.core.Handles.HandlesType as HandlesType
import lib.core.Handles.HandlesNonlocal as HandlesNonlocal
import lib.core.Handles.HandlesStruct as HandlesStruct
import lib.core.Handles.HandlesImports as HandlesImports
import lib.core.Handles.HandlesClassDef as HandlesClassDef
import lib.core.Handles.HandlesFunctions as HandlesFunctions
import lib.core.StubMerger as StubMerger
import lib.core.Handles.HandlesExprCall as HandlesExprCall
import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign
import lib.core.CompilerFactory as CompilerFactory
import lib.core.Gen.CallGenBase as CallGenBase
# ============================================================
# CallGenVa - CallGenMixin 拆分(阶段 B):va_arg 变长参数(start/arg/end / 变长调用提升)
#
# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。
# 跨 Mixin 调用统一走 HandlesExprCall 委托(经 _g_gen)。
# @t.NoVTable:静态绑定。
# ============================================================
@t.NoVTable
class CallGenVa(CallGenBase.CallGenBase):
"""va_arg 变长参数(start/arg/end / 变长调用提升)"""
# ============================================================
# _func_has_eh_params - 被调函数签名是否含 try-except EH 输出参数
#
# EH 参数(%__eh_msg_out__/__eh_code_out__)由 translate_function_def/
# _translate_method 在含 raise 的函数签名末尾注入(main 除外)。
# ============================================================
def _va_arg_get_alloca_ptr(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
arg_node: ast.AST | t.CPtr,
funcs_ptr: t.CPtr,
func_count: int,
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
"""获取 va_list 变量的 alloca 指针(不 load)
va_arg/va_start/va_end 需要的是 va_list 对象的地址(alloca 指针),
而非 va_list 的值。若 arg_node 是 Name,查符号表获取 alloca;
否则用 translate_value 翻译(调用者负责确保传入的是指针)。
"""
if arg_node is None:
return None
# Name 节点:直接查符号表获取 alloca 指针(不 load)
if arg_node.kind() == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(arg_node)
if nm.id is not None:
alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id)
if alloca is not None:
return alloca
# 回退:translate_value(可能返回 load 后的值,仅适用于已是指针的情况)
return HandlesExpr.translate_value(builder, pool, mod, arg_node, funcs_ptr, func_count, trans)
def _resolve_va_arg_type(self, pool: memhub.MemBuddy | t.CPtr,
type_node: ast.AST | t.CPtr,
trans: HT.Translator | t.CPtr) -> llvmlite.LLVMType | t.CPtr:
"""解析 va_arg/arg 的类型参数为 LLVMType
支持的类型表达式:
t.CInt / t.CInt32T → i32
t.CInt64T → i64
t.CDouble → double
t.CPtr / str → i8*
str / bytes → i8*
无类型参数时默认 i32(vsnprintf 中 va_arg(ap) 常用于读取 i32)
"""
if type_node is None:
return llvmlite.Int32(pool)
# 使用 HandlesType.resolve_annotation_type 解析类型表达式
resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
pool, type_node, trans._imported_modules, trans._from_imports, trans)
if resolved is not None:
return resolved
# 类型节点存在但解析失败:fail-fast,绝不回退 i32(会按错宽度读变参槽位)
HandlesType.fatal_error(type_node, "va_arg 类型解析失败", "TypeError")
return llvmlite.Int32(pool)
def _translate_va_arg_sugar(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
cl: ast.Call | t.CPtr,
cargs: list[ast.AST | t.CPtr] | t.CPtr,
can: t.CSizeT,
funcs_ptr: t.CPtr,
func_count: int,
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
"""va_arg(ap, type) / va_arg(ap) → %N = va_arg <ap_ty> <ap>, <type>
生成 LLVM va_arg 指令,从 va_list 读取下一个变长参数。
"""
if can == 0 or cargs is None:
return llvmlite.const_int32(pool, 0)
# 第一个参数:va_list(求值为 i8* 地址值,对齐 TPC _HandleVaArgLlvm)
# 当前函数 *args:translate_value 经 vararg 名映射直接返回 va_list 缓冲区地址;
# 转发场景(sprintf → vsnprintf 的 ap 参数):translate_value load 参数得到地址值。
ap_node: ast.AST | t.CPtr = cargs.get(0)
ap_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, ap_node, None, 0, trans)
if ap_val is None:
return llvmlite.const_int32(pool, 0)
ap_ptr: llvmlite.Value | t.CPtr = ap_val
# 第二个参数:目标类型(可选,默认 i32)
arg_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
if can >= 2:
type_node: ast.AST | t.CPtr = cargs.get(1)
arg_ty = self._resolve_va_arg_type(pool, type_node, trans)
# Win64 变参槽位为 8 字节:<64 位整数按 i64 读取(对齐 TPC emit_va_arg L72-73)
read_ty: llvmlite.LLVMType | t.CPtr = arg_ty
abits_va: int = HandlesExpr.get_llvm_type_bits(arg_ty)
if abits_va != 0 and abits_va < 64:
read_ty = llvmlite.Int64(pool)
# 生成 va_arg 指令
return llvmlite.build_va_arg(builder, ap_ptr, read_ty)
def _translate_arg_sugar(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
cl: ast.Call | t.CPtr,
cargs: list[ast.AST | t.CPtr] | t.CPtr,
can: t.CSizeT,
funcs_ptr: t.CPtr,
func_count: int,
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
"""arg(type) → %N = va_arg <va_list_ty> <trans._va_list_ptr>, <type>
使用当前函数的隐式 va_list(trans._va_list_ptr),
简化 *args 函数体内的 va_arg 调用。
"""
if trans._va_list_ptr is None:
return llvmlite.const_int32(pool, 0)
# 第一个参数:目标类型(可选,默认 i32)
arg_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
if can >= 1 and cargs is not None:
type_node: ast.AST | t.CPtr = cargs.get(0)
arg_ty = self._resolve_va_arg_type(pool, type_node, trans)
# Win64 变参槽位为 8 字节:<64 位整数按 i64 读取(与 _translate_va_arg_sugar 一致)
read_ty: llvmlite.LLVMType | t.CPtr = arg_ty
abits_arg: int = HandlesExpr.get_llvm_type_bits(arg_ty)
if abits_arg != 0 and abits_arg < 64:
read_ty = llvmlite.Int64(pool)
# 生成 va_arg 指令(使用 trans._va_list_ptr 作为 va_list 地址)
return llvmlite.build_va_arg(builder, trans._va_list_ptr, read_ty)
def _translate_va_start_sugar(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
cargs: list[ast.AST | t.CPtr] | t.CPtr,
can: t.CSizeT,
funcs_ptr: t.CPtr,
func_count: int,
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
"""va_start(ap, last_arg) → call void @llvm.va_start(i8* %ap)
初始化 va_list。第二个参数 last_arg 在 LLVM intrinsic 中不使用(C 宏兼容)。
"""
if can == 0 or cargs is None:
return llvmlite.const_int32(pool, 0)
# 第一个参数:va_list 指针(获取 alloca,不 load)
ap_node: ast.AST | t.CPtr = cargs.get(0)
ap_ptr: llvmlite.Value | t.CPtr = self._va_arg_get_alloca_ptr(
pool, builder, mod, ap_node, funcs_ptr, func_count, trans)
if ap_ptr is None:
return llvmlite.const_int32(pool, 0)
# bitcast 到 i8*(@llvm.va_start 接受 i8*)
i8_ty_vs: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
i8_ptr_ty_vs: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_vs)
ap_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, ap_ptr, i8_ptr_ty_vs)
if ap_i8 is None:
return llvmlite.const_int32(pool, 0)
void_ty_vs: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool)
llvmlite.build_call(builder, "llvm.va_start", ap_i8, 1, void_ty_vs, 0)
return llvmlite.const_int32(pool, 0)
def _translate_va_end_sugar(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
cargs: list[ast.AST | t.CPtr] | t.CPtr,
can: t.CSizeT,
funcs_ptr: t.CPtr,
func_count: int,
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
"""va_end(ap) → call void @llvm.va_end(i8* %ap)
清理 va_list。在大多数平台上是 no-op,但调用它是良好的 C ABI 习惯。
"""
if can == 0 or cargs is None:
return llvmlite.const_int32(pool, 0)
# 第一个参数:va_list 指针(获取 alloca,不 load)
ap_node: ast.AST | t.CPtr = cargs.get(0)
ap_ptr: llvmlite.Value | t.CPtr = self._va_arg_get_alloca_ptr(
pool, builder, mod, ap_node, funcs_ptr, func_count, trans)
if ap_ptr is None:
return llvmlite.const_int32(pool, 0)
# bitcast 到 i8*(@llvm.va_end 接受 i8*)
i8_ty_ve: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
i8_ptr_ty_ve: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_ve)
ap_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, ap_ptr, i8_ptr_ty_ve)
if ap_i8 is None:
return llvmlite.const_int32(pool, 0)
void_ty_ve: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool)
llvmlite.build_call(builder, "llvm.va_end", ap_i8, 1, void_ty_ve, 0)
return llvmlite.const_int32(pool, 0)
def _get_func_fixed_param_count(self, func: llvmlite.Function | t.CPtr) -> int:
"""获取函数的固定参数数量(遍历 Params 链表)"""
if func is None:
return 0
count: int = 0
param: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(func)
while param is not None:
count += 1
param = llvmlite.param_get_next(param)
return count
def _check_and_promote_variadic_call(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
call_name: str,
head: llvmlite.Value | t.CPtr,
can: t.CSizeT,
arg_nodes: list[ast.AST | t.CPtr] | t.CPtr = None,
self_offset: int = 0,
trans: HT.Translator | t.CPtr = None) -> int:
"""检查被调用函数是否为变长函数,若是则对变长参数进行 C ABI 提升
返回: is_variadic (1=变长调用, 0=普通调用)
副作用: 修改 head 链表中超过固定参数数量的节点(C ABI 提升)
arg_nodes: 实参 AST 链表(不含 self),用于 i8/i16 提升的无符号性判断
self_offset: Value 链中 self 占用的偏移(方法调用=1,普通函数=0)
trans: 供 _node_type_unsigned 查询变量注解
"""
if mod is None or call_name is None or head is None:
return 0
# 查找函数对象
func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, call_name)
if func is None:
return 0
if func.IsVarArg != 1:
return 0
# 获取固定参数数量
fixed_count: int = self._get_func_fixed_param_count(func)
# 无变长参数(实参数量 <= 固定参数数量),仍需 is_variadic=1
if can <= fixed_count:
return 1
# 遍历到第 fixed_count 个节点(固定参数的最后一个)
cur: llvmlite.Value | t.CPtr = head
prev: llvmlite.Value | t.CPtr = None
idx: int = 0
while cur is not None and idx < fixed_count:
prev = cur
cur = cur.Next
idx += 1
# cur 指向第 fixed_count+1 个节点(第一个变长参数)
# 对变长参数进行 C ABI 提升
i32_ty_promote: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
double_ty_promote: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool)
v_idx: int = fixed_count
while cur is not None:
next_node: llvmlite.Value | t.CPtr = cur.Next
promoted: llvmlite.Value | t.CPtr = cur
# C ABI integer promotion: i8/i16 → i32
arg_bits: int = HandlesExpr.get_llvm_type_bits(cur.Ty)
if arg_bits != 0 and arg_bits < 32:
# 无符号整型(t.CUInt8T/CUInt16T 等)→ zext;有符号/未知 → sext。
# 修复: printf("%02x", buf[i]) 中 buf[i] 是 CUInt8T,sext 得
# 0xFFFFFFF3 打印 fffffff3(哈希摘要输出垃圾),应 zext 得 0xF3。
is_u_va: int = 0
if arg_nodes is not None and trans is not None:
ast_idx_va: int = v_idx - self_offset
if ast_idx_va >= 0 and ast_idx_va < len(arg_nodes):
an_va: ast.AST | t.CPtr = arg_nodes.get(ast_idx_va)
if an_va is not None:
if HandlesExpr._node_type_unsigned(pool, an_va, trans) != 0:
is_u_va = 1
if is_u_va != 0:
promoted = llvmlite.build_zext(builder, cur, i32_ty_promote)
else:
# is_u_va 判断失败(arg_nodes/trans 缺失或变量注解查不到)时,
# i8 按系统编程惯例默认 zext(对齐 should_zext_widen 的
# "i8 → zext(系统编程中 i8 几乎总是无符号字节)"策略),
# 否则 printf("%02x", buf[i]) 中 uint8 字节被 sext 成
# 0xFFFFFFF3,哈希摘要输出 ffffffXX 垃圾。
if HandlesExpr.get_llvm_type_bits(cur.Ty) == 8:
promoted = llvmlite.build_zext(builder, cur, i32_ty_promote)
else:
promoted = HandlesExpr.coerce_to_type(builder, cur, i32_ty_promote, None)
if promoted is not None:
promoted.Next = next_node
if prev is not None:
prev.Next = promoted
# C ABI float promotion: float → double
arg_fbits: int = HandlesExpr.get_llvm_float_bits(promoted.Ty)
if arg_fbits != 0 and arg_fbits < 64:
promoted = HandlesExpr.coerce_to_type(builder, promoted, double_ty_promote, None)
if promoted is not None:
promoted.Next = next_node
if prev is not None:
prev.Next = promoted
prev = promoted
cur = next_node
v_idx += 1
return 1
+251
View File
@@ -0,0 +1,251 @@
import t, c
from stdint import *
import ast
import llvmlite
import memhub
import string
import stdio
import stdlib
import sys
import viperlib
import w32.fileio as fileio
import lib.core.VLogger as VLogger
import lib.core.Handles.HandlesBase as HandlesBase
import lib.core.Handles.HandlesTranslator as HT
import lib.core.Handles.HandlesExpr as HandlesExpr
import lib.core.Handles.HandlesVar as HandlesVar
import lib.core.Handles.HandlesType as HandlesType
import lib.core.Handles.HandlesNonlocal as HandlesNonlocal
import lib.core.Handles.HandlesStruct as HandlesStruct
import lib.core.Handles.HandlesImports as HandlesImports
import lib.core.Handles.HandlesClassDef as HandlesClassDef
import lib.core.Handles.HandlesFunctions as HandlesFunctions
import lib.core.StubMerger as StubMerger
import lib.core.Handles.HandlesExprCall as HandlesExprCall
import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign
import lib.core.CompilerFactory as CompilerFactory
import lib.core.Gen.CallGenBase as CallGenBase
# ============================================================
# CallGenVt - CallGenMixin 拆分(阶段 B):vtable 槽位写入
#
# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。
# 跨 Mixin 调用统一走 HandlesExprCall 委托(经 _g_gen)。
# @t.NoVTable:静态绑定。
# ============================================================
@t.NoVTable
class CallGenVt(CallGenBase.CallGenBase):
"""vtable 槽位写入"""
# ============================================================
# _write_vtable_slot / _write_vtable_attr — vtable 方法槽位直接写入
#
# serial0_file.open = serial0_open(devfs 驱动注册模式):把模块级函数
# 指针写入对象 vtable 的方法槽位。vtable 方法不是数据字段(FieldEntry),
# get_attribute_ptr 查不到 → 此前 fatal_error "属性写入失败"。
# 对齐 TPC HandlesAssign.py L905-949 的写时复制:
# 对象 vtable 仍指向类默认 vtable 时,先复制一份(internal 全局 +
# llvm.memcpy)并让对象指向副本,再 GEP method_index 槽位 store
# 函数指针(i8*)。多次写入互不覆盖(第二次起 vtable 已非默认,
# 跳过复制直接写槽位)。
# ============================================================
# ============================================================
# _write_vtable_slot / _write_vtable_attr — vtable 方法槽位直接写入
#
# serial0_file.open = serial0_open(devfs 驱动注册模式):把模块级函数
# 指针写入对象 vtable 的方法槽位。vtable 方法不是数据字段(FieldEntry),
# get_attribute_ptr 查不到 → 此前 fatal_error "属性写入失败"。
# 对齐 TPC HandlesAssign.py L905-949 的写时复制:
# 对象 vtable 仍指向类默认 vtable 时,先复制一份(internal 全局 +
# llvm.memcpy)并让对象指向副本,再 GEP method_index 槽位 store
# 函数指针(i8*)。多次写入互不覆盖(第二次起 vtable 已非默认,
# 跳过复制直接写槽位)。
# ============================================================
def _write_vtable_slot(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
obj_ptr: llvmlite.Value | t.CPtr,
class_name: str,
method_index: int,
func_val: llvmlite.Value | t.CPtr,
trans: HT.Translator | t.CPtr) -> int:
"""生成 vtable 槽位写入(写时复制),成功返回 1"""
if pool is None or builder is None or mod is None or trans is None:
return 0
if obj_ptr is None or class_name is None or func_val is None:
return 0
if method_index < 0 or trans._cur_func is None:
return 0
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
if i8_ty is None:
return 0
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
if i8_ptr_ty is None:
return 0
i8_ptr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty)
if i8_ptr_ptr_ty is None:
return 0
method_count: int = HandlesStruct.get_vtable_method_count(class_name)
if method_count <= 0:
return 0
# 构造 vtable 类型 { i8*, i8*, ... }
vt_first: llvmlite.ParamNode | t.CPtr = None
vt_prev: llvmlite.ParamNode | t.CPtr = None
for vi in range(method_count):
pn: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, i8_ptr_ty)
if pn is None:
continue
if vt_first is None:
vt_first = pn
if vt_prev is not None:
llvmlite.paramnode_set_next(vt_prev, pn)
vt_prev = pn
vtable_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, vt_first, method_count, None)
if vtable_ty is None:
return 0
# 对象 vtable 槽位(对象头 → i8**,vtable 指针总是第一个字段)
vtable_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
builder, obj_ptr, i8_ptr_ptr_ty)
if vtable_slot is None:
return 0
vtable_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(
builder, i8_ptr_ty, vtable_slot)
if vtable_ptr is None:
return 0
# 类默认 vtable 地址(比较用)
class_vt: llvmlite.Value | t.CPtr = HandlesExprCall._make_vtable_ref_i8(
pool, builder, mod, class_name, trans)
if class_vt is None:
return 0
cmp_vt: llvmlite.Value | t.CPtr = llvmlite.build_icmp(
builder, llvmlite.ICMP_EQ, vtable_ptr, class_vt)
if cmp_vt is None:
return 0
# 块名唯一化(create_block 不自动编号;同函数多次 vtable 写入(如
# devfs open/close/read/write 连续赋值)同名 label 冲突)
vtc3: int = trans._label_counter
trans._label_counter = vtc3 + 1
vt_bb_buf3: str = pool.alloc(64)
if vt_bb_buf3 is None:
return 0
viperlib.snprintf(vt_bb_buf3, 64, "vt.copy.%d", vtc3)
vt_copy_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(
pool, trans._cur_func, vt_bb_buf3)
viperlib.snprintf(vt_bb_buf3, 64, "vt.skip.%d", vtc3)
vt_skip_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(
pool, trans._cur_func, vt_bb_buf3)
if vt_copy_bb is None or vt_skip_bb is None:
return 0
llvmlite.build_cond_br(builder, cmp_vt, vt_copy_bb, vt_skip_bb)
# copy 块:创建 internal 副本全局(zeroinit)+ memcpy + 对象指向副本
llvmlite.position_at_end(builder, vt_copy_bb)
vtc: int = trans._label_counter
trans._label_counter = vtc + 1
vcopy_buf: str = pool.alloc(256)
if vcopy_buf is not None:
viperlib.snprintf(vcopy_buf, 256, "%s.vtable.copy.%d", class_name, vtc)
vcopy_gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(
pool, vcopy_buf, vtable_ty)
if vcopy_gv is not None:
llvmlite.module_add_global(mod, vcopy_gv)
vcopy_gv.Linkage = None
vcopy_gv.Initializer = "zeroinitializer"
vcopy_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue(
pool, llvmlite.Ptr(pool, vtable_ty), vcopy_buf)
if vcopy_ref is not None:
vcopy_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
builder, vcopy_ref, i8_ptr_ty)
if vcopy_i8 is not None:
vt_size: llvmlite.Value | t.CPtr = llvmlite.ConstInt(
pool, llvmlite.Int64(pool), method_count * 8, "vtsz")
if vt_size is not None:
HandlesExprCall._emit_llvm_memcpy_intrinsic(
pool, builder, mod, vcopy_i8, class_vt, vt_size)
llvmlite.build_store(builder, vcopy_i8, vtable_slot)
llvmlite.build_br(builder, vt_skip_bb)
# skip 块:reload vtable → GEP 槽位 → store 函数指针(i8*)
llvmlite.position_at_end(builder, vt_skip_bb)
vt_ptr2: llvmlite.Value | t.CPtr = llvmlite.build_load(
builder, i8_ptr_ty, vtable_slot)
if vt_ptr2 is None:
return 0
vt_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
builder, vt_ptr2, llvmlite.Ptr(pool, vtable_ty))
if vt_typed is None:
return 0
vt_slotp: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
builder, vtable_ty, i8_ptr_ty, vt_typed, method_index)
if vt_slotp is None:
return 0
fptr_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
builder, func_val, i8_ptr_ty)
if fptr_i8 is not None:
llvmlite.build_store(builder, fptr_i8, vt_slotp)
return 1
def _write_vtable_attr(self, builder: llvmlite.IRBuilder | t.CPtr,
pool: memhub.MemBuddy | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
node: ast.AST | t.CPtr,
rhs_val: llvmlite.Value | t.CPtr,
trans: HT.Translator | t.CPtr) -> int:
"""属性写入 obj.method = func:检测 vtable 方法并生成槽位写入(成功返回 1)"""
if node is None or builder is None or pool is None or mod is None:
return 0
if rhs_val is None or trans is None:
return 0
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node)
if at is None or at.value is None or at.attr is None:
return 0
# 解析类名(AnnotClassName;去模块前缀)
class_nm_v: str = None
if at.value.kind() == ast.ASTKind.Name:
nm_v: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
if nm_v.id is not None:
ve_v: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry(
trans.SymTab, nm_v.id)
if ve_v is not None:
class_nm_v = ve_v.AnnotClassName
elif at.value.kind() == ast.ASTKind.Attribute:
# 跨 Mixin:_resolve_attr_field_class 定义在 ExprGenMixin,经 gen 单例调用
import lib.core.Gen.Generator as Generator
g_vta: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(
t.CVoid(HandlesExpr._g_gen, t.CPtr))
if g_vta is not None:
class_nm_v = g_vta._resolve_attr_field_class(pool, trans, at.value)
if class_nm_v is None:
return 0
fd_dot_v: str = string.strrchr(class_nm_v, '.')
if fd_dot_v is not None:
class_nm_v = fd_dot_v + 1
if HandlesStruct.get_struct_type(class_nm_v) is None:
return 0
vm_idx_v: int = HandlesStruct.get_vtable_method_index(class_nm_v, at.attr)
if vm_idx_v < 0:
return 0
# 解析 obj_ptr(对齐 get_attribute_ptr 前半段:Name 直接查 alloca)
obj_ptr_v: llvmlite.Value | t.CPtr = None
if at.value.kind() == ast.ASTKind.Name:
obj_ptr_v = HandlesVar.lookup_var(
trans.SymTab, ((ast.Name | t.CPtr)(at.value)).id)
else:
obj_ptr_v = HandlesExpr.translate_value(
builder, pool, mod, at.value, None, 0, trans)
if obj_ptr_v is None or obj_ptr_v.Ty is None:
return 0
# X|t.CPtr 变量(Ptr(Ptr))load 解引用取对象指针
match obj_ptr_v.Ty:
case llvmlite.LLVMType.Ptr(inner_v):
match inner_v:
case llvmlite.LLVMType.Ptr(_):
obj_ptr_v = llvmlite.build_load(builder, inner_v, obj_ptr_v)
case _:
pass
case _:
pass
if obj_ptr_v is None:
return 0
return self._write_vtable_slot(
pool, builder, mod, obj_ptr_v, class_nm_v, vm_idx_v, rhs_val, trans)
+9
View File
@@ -10,6 +10,12 @@ import lib.core.Gen.CallGenMixin as CallGenMixin
import lib.core.Gen.CallGenBase as CallGenBase
import lib.core.Gen.CallGenLeafKit as CallGenLeafKit
import lib.core.Gen.CallGenCBuiltin as CallGenCBuiltin
import lib.core.Gen.CallGenCtor as CallGenCtor
import lib.core.Gen.CallGenCall as CallGenCall
import lib.core.Gen.CallGenProp as CallGenProp
import lib.core.Gen.CallGenFd as CallGenFd
import lib.core.Gen.CallGenVt as CallGenVt
import lib.core.Gen.CallGenVa as CallGenVa
import lib.core.Gen.FuncGenMixin as FuncGenMixin
import lib.core.Gen.ClassGenMixin as ClassGenMixin
import lib.core.Gen.ImportsGenMixin as ImportsGenMixin
@@ -38,6 +44,9 @@ class Generator(BaseGenMixin.BaseGenMixin, TypeGenMixin.TypeGenMixin,
StructGenMixin.StructGenMixin, ExprGenMixin.ExprGenMixin,
CallGenMixin.CallGenMixin, CallGenBase.CallGenBase,
CallGenLeafKit.CallGenLeafKit, CallGenCBuiltin.CallGenCBuiltin,
CallGenCtor.CallGenCtor, CallGenCall.CallGenCall,
CallGenProp.CallGenProp, CallGenFd.CallGenFd,
CallGenVt.CallGenVt, CallGenVa.CallGenVa,
FuncGenMixin.FuncGenMixin,
ClassGenMixin.ClassGenMixin, ImportsGenMixin.ImportsGenMixin,
StmtGenMixin.StmtGenMixin, AssignGenMixin.AssignGenMixin,
+51
View File
@@ -1816,3 +1816,54 @@ def _translate_isinstance(pool: memhub.MemBuddy | t.CPtr,
if g is not None:
return g._translate_isinstance(pool, builder, mod, obj_node, cls_node, trans)
return None
# ============================================================
# _is_sha1_mangled_call / _is_list_builtin_method / _translate_fakeduck_call /
# _translate_super_call(阶段 B:CallGenMixin 拆分后顶层经委托调用这些方法)
# ============================================================
def _is_sha1_mangled_call(call_name: str) -> int:
"""判断 call_name 是否为跨模块 Viper 函数(委托到 gen._is_sha1_mangled_call)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g._is_sha1_mangled_call(call_name)
return 0
def _is_list_builtin_method(class_name: str, method_name: str) -> int:
"""判断 (class_name, method_name) 是否是 list 泛型内置方法(委托到 gen._is_list_builtin_method)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g._is_list_builtin_method(class_name, method_name)
return 0
def _translate_fakeduck_call(pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
cls_name: str,
method_name: str,
cl: ast.Call | t.CPtr,
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
"""FakeDuck: str 变量方法调用(委托到 gen._translate_fakeduck_call)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g._translate_fakeduck_call(pool, builder, mod, cls_name, method_name, cl, trans)
return None
def _translate_super_call(pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
cl: ast.Call | t.CPtr,
method_name: str,
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
"""super().method(args) → 父类方法静态调用(委托到 gen._translate_super_call)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g._translate_super_call(pool, builder, mod, cl, method_name, trans)
return None