删除 lib/includes/t.py、c.py,类型模型迁入 lib/core/TypeSystem.py;移除 IsTModule/_T_MODULE_NAMES 等名称判据,语法糖与内部标记统一为裸名;builtins 的 sizet/intN/uintN/fast/least/uchar/short/long 等改为编译器内建短名。
5598 lines
331 KiB
Python
5598 lines
331 KiB
Python
from __future__ import annotations
|
||
from typing import TYPE_CHECKING
|
||
if TYPE_CHECKING:
|
||
from lib.core.translator import Translator
|
||
from lib.core.Translator.LlvmGenerator import LlvmGeneratorMixin
|
||
import vast as ast
|
||
import os
|
||
import re
|
||
import llvmlite.ir as ir
|
||
from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo, FuncMeta
|
||
from lib.core.VLogger import get_logger as _vlog
|
||
from lib.constants.config import mode as _config_mode
|
||
from lib.core import TypeSystem
|
||
from lib.core.TypeSystem import CTypeRegistry
|
||
from lib.core.SymbolUtils import (
|
||
ExtractTypeNameFromBinOp, IsPtrSubscriptNode, DesugarPtrSubscriptToUnion,
|
||
ResolveTypeArgStr, GenericArgRawName,
|
||
ClassHasFuncLevelCVTable, IsVtableSlotMethod)
|
||
from lib.core.Handles.HandlesExpr import DefineUseWidthFromLLVMType
|
||
from lib.vast.ExprParser import NEW_SRC_MEMGR
|
||
|
||
|
||
# len() 参数形态不支持时的共享提示语(与 ViperC App/lib/core/Gen/Call/
|
||
# CallGenDispatch.vp 的 len() 分支同口径,措辞逐字一致,便于用户对照两侧报文)。
|
||
_LEN_SUPPORTED_HINT: str = (
|
||
"len() 只支持定长数组/数组指针(CArray[T, N])、i8*(str/bytes)或带 __len__ 的结构体;"
|
||
"非 i8 裸指针/标量指针没有长度语义:字符串请用 str/bytes,需要元素个数请自行记录长度,"
|
||
"或改用 CPtr[元素] 并显式维护元素计数"
|
||
)
|
||
|
||
# PROF 热点:_EmitLLVMIRInstruction 对每条 IR 模板都要做多次 re.match / re.split,
|
||
# 未预编译的模块级入口每次都要「模式串哈希 → re 缓存查找 → 未命中就重新编译」,
|
||
# 512 条缓存被打穿后开销巨大。这些模式全是字面量 → 提升为模块级预编译常量。
|
||
# 模式串与调用点处的字面量逐字一致,语义不变。
|
||
# _EmitLLVMIRInstruction 用:剥离 IR 模板前置的结果赋值 `%__OPn__ = `
|
||
_RE_OP_ASSIGN: re.Pattern[str] = re.compile(r'%__OP(\d+)__\s*=\s*(.+)')
|
||
# _EmitLLVMIRInstruction 用:整数比较指令 icmp
|
||
_RE_ICMP: re.Pattern[str] = re.compile(r'icmp\s+(\w+)\s+(\w+)\s+%__OP(\d+)__,\s*%__OP(\d+)__')
|
||
# _EmitLLVMIRInstruction 用:浮点比较指令 fcmp
|
||
_RE_FCMP: re.Pattern[str] = re.compile(r'fcmp\s+([\w\s]+?)\s+(\w+)\s+%__OP(\d+)__,\s*%__OP(\d+)__')
|
||
# _EmitLLVMIRInstruction 用:select 指令
|
||
_RE_SELECT: re.Pattern[str] = re.compile(r'select\s+i1\s+%__OP(\d+)__,\s*(\w+)\s+%__OP(\d+)__,\s*(\w+)\s+%__OP(\d+)__')
|
||
# _EmitLLVMIRInstruction 用:Load 指令
|
||
_RE_LOAD: re.Pattern[str] = re.compile(r'Load\s+(\w+),\s*(\w+)\s+%__OP(\d+)__')
|
||
# _EmitLLVMIRInstruction 用:store 指令
|
||
_RE_STORE: re.Pattern[str] = re.compile(r'store\s+(\w+)\s+%__OP(\d+)__,\s*(\w+)\s+%__OP(\d+)__')
|
||
# _EmitLLVMIRInstruction 用:getelementptr 指令
|
||
_RE_GEP: re.Pattern[str] = re.compile(r'getelementptr\s+(?:inbounds\s+)?(\w+),\s*(\w+)\s+%__OP(\d+)__,\s*(.+)')
|
||
# _EmitLLVMIRInstruction 用:单个 %__OPn__ 操作数占位引用
|
||
_RE_OP_REF: re.Pattern[str] = re.compile(r'%__OP(\d+)__')
|
||
# _EmitLLVMIRInstruction 用:取负形式 sub 指令
|
||
_RE_NEG: re.Pattern[str] = re.compile(r'sub\s+(\w+)\s+(\d+),\s*%__OP(\d+)__')
|
||
# _EmitLLVMIRInstruction 用:按位取反形式 xor 指令
|
||
_RE_NOT: re.Pattern[str] = re.compile(r'xor\s+(\w+)\s+(-1|\d+),\s*%__OP(\d+)__')
|
||
# _EmitLLVMIRInstruction 用:call 指令
|
||
_RE_CALL: re.Pattern[str] = re.compile(r'call\s+(\w+)\s+@([\w.]+)\((.+)\)')
|
||
# _EmitLLVMIRInstruction 用:调用参数中的「类型 %__OPn__」片段
|
||
_RE_TYPED_OP: re.Pattern[str] = re.compile(r'(\w+\*?)\s+%__OP(\d+)__')
|
||
# _EmitLLVMIRInstruction 用:调用参数中的「类型 常量」片段
|
||
_RE_CONST: re.Pattern[str] = re.compile(r'(\w+)\s+(-?\d+)')
|
||
# _EmitLLVMIRInstruction 用:以逗号切分操作数列表(逗号 + 任意空白)
|
||
_RE_COMMA_WS: re.Pattern[str] = re.compile(r',\s*')
|
||
|
||
|
||
def _safe_ptr_type(ty: ir.Type) -> ir.Type:
|
||
"""LLVM IR 中不允许 void* 指针,Ptr(VoidType) 统一替换为 i8*(对应 C 的 void* 语义)"""
|
||
if isinstance(ty, ir.PointerType):
|
||
cur: ir.Type = ty
|
||
while isinstance(cur, ir.PointerType):
|
||
if isinstance(cur.pointee, ir.VoidType):
|
||
return ir.IntType(8).as_pointer()
|
||
cur = cur.pointee
|
||
return ty
|
||
|
||
|
||
def _BinOpContainsCPtr(node: ast.AST) -> bool:
|
||
"""递归检查 BinOp(BitOr) 联合类型中是否含 CPtr(指针标记)"""
|
||
if isinstance(node, ast.Name):
|
||
return node.id == 'CPtr'
|
||
if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
|
||
return _BinOpContainsCPtr(node.left) or _BinOpContainsCPtr(node.right)
|
||
return False
|
||
|
||
|
||
class ExprCallHandle(BaseHandle):
|
||
# vtable on-demand 缓存(类级,跨 worker 任务共享,进程内单线程无竞争)。
|
||
# 原实现 pyi_cache 是 _try_register_vtable_ondemand 函数局部变量,每次调用都
|
||
# 重建 → 437 次调用 = 437 次 open+ast.parse 同一批 pyi(prof 38.5s)。
|
||
# vpi 以 sha1 命名、单次编译内只增不减,路径不变则内容不可变,进程内缓存安全。
|
||
# _vtable_pyi_cache:pyi 文件绝对路径 → {类名: ClassDef 节点}
|
||
# _vtable_methods_cache:(sha1, class_name) → (methods, is_cvtable, is_novtable, parent_name)
|
||
_vtable_pyi_cache: dict[str, dict[str, ast.ClassDef]] = {}
|
||
_vtable_methods_cache: dict[tuple[str, str], tuple[list[str], bool, bool, str | None]] = {}
|
||
def _append_eh_msg_out_arg(self, CallArgs: list[ir.Value], func: ir.Function | None, Gen: LlvmGeneratorMixin) -> None:
|
||
if not func:
|
||
return
|
||
func_args: list[ir.Type] = func.function_type.args
|
||
n_user_args: int = len(CallArgs)
|
||
has_eh_msg: bool = False
|
||
has_eh_code: bool = False
|
||
if len(func_args) > n_user_args:
|
||
last_type: ir.Type = func_args[-1]
|
||
if (isinstance(last_type, ir.PointerType)
|
||
and isinstance(last_type.pointee, ir.IntType)
|
||
and last_type.pointee.width == 32):
|
||
has_eh_code = True
|
||
if len(func_args) > n_user_args + (1 if has_eh_code else 0):
|
||
check_idx: int = len(func_args) - 1 - (1 if has_eh_code else 0)
|
||
check_type: ir.Type = func_args[check_idx]
|
||
if (isinstance(check_type, ir.PointerType)
|
||
and isinstance(check_type.pointee, ir.PointerType)
|
||
and isinstance(check_type.pointee.pointee, ir.IntType)
|
||
and check_type.pointee.pointee.width == 8):
|
||
has_eh_msg = True
|
||
if not has_eh_msg:
|
||
return
|
||
eh_msg_ptr: ir.Value | None = None
|
||
eh_code_ptr: ir.Value | None = None
|
||
if Gen.eh_except_block_stack:
|
||
_, _, exception_code, eh_message = Gen.eh_except_block_stack[-1]
|
||
if eh_message is not None:
|
||
eh_msg_ptr = eh_message
|
||
if exception_code is not None:
|
||
eh_code_ptr = exception_code
|
||
if eh_msg_ptr is None and Gen.func and len(Gen.func.args) > 0:
|
||
for arg in Gen.func.args:
|
||
if arg.name == '__eh_msg_out__' and eh_msg_ptr is None:
|
||
eh_msg_ptr = arg
|
||
elif arg.name == '__eh_code_out__' and eh_code_ptr is None:
|
||
eh_code_ptr = arg
|
||
if eh_msg_ptr is None:
|
||
eh_msg_ptr = Gen._allocaEntry(ir.PointerType(ir.IntType(8)), name="eh_msg_out_null")
|
||
if eh_code_ptr is None:
|
||
eh_code_ptr = Gen._allocaEntry(ir.IntType(32), name="eh_code_out_null")
|
||
Gen._store(ir.Constant(ir.PointerType(ir.IntType(8)), None), eh_msg_ptr)
|
||
Gen._store(ir.Constant(ir.IntType(32), 0), eh_code_ptr)
|
||
CallArgs.append(eh_msg_ptr)
|
||
if has_eh_code:
|
||
CallArgs.append(eh_code_ptr)
|
||
|
||
def _check_eh_return(self, result: ir.Value, func_name: str, Gen: LlvmGeneratorMixin, called_func: ir.Function | None = None) -> ir.Value:
|
||
has_eh_msg_out: bool = False
|
||
has_eh_code_out: bool = False
|
||
if called_func and hasattr(called_func, 'args') and len(called_func.args) > 0:
|
||
for arg in called_func.args:
|
||
if arg.name == '__eh_msg_out__':
|
||
has_eh_msg_out = True
|
||
elif arg.name == '__eh_code_out__':
|
||
has_eh_code_out = True
|
||
if not has_eh_msg_out:
|
||
return result
|
||
eh_msg_ptr: ir.Value | None = None
|
||
eh_code_ptr: ir.Value | None = None
|
||
if Gen.eh_except_block_stack:
|
||
_, _, exception_code, eh_message = Gen.eh_except_block_stack[-1]
|
||
if eh_message is not None:
|
||
eh_msg_ptr = eh_message
|
||
if exception_code is not None:
|
||
eh_code_ptr = exception_code
|
||
if eh_msg_ptr is None and Gen.func and len(Gen.func.args) > 0:
|
||
for arg in Gen.func.args:
|
||
if arg.name == '__eh_msg_out__' and eh_msg_ptr is None:
|
||
eh_msg_ptr = arg
|
||
elif arg.name == '__eh_code_out__' and eh_code_ptr is None:
|
||
eh_code_ptr = arg
|
||
if eh_msg_ptr is not None:
|
||
eh_msg_val: ir.Value = Gen._load(eh_msg_ptr, name=f"Load_eh_msg_{func_name}")
|
||
null_ptr: ir.Constant = ir.Constant(ir.PointerType(ir.IntType(8)), None)
|
||
is_error: ir.Value = Gen.builder.icmp_signed('!=', eh_msg_val, null_ptr, name=f"check_eh_msg_{func_name}")
|
||
OkBB: ir.Block = Gen.func.append_basic_block(name=f"ok_after_{func_name}")
|
||
ErrorBB: ir.Block = Gen.func.append_basic_block(name=f"error_after_{func_name}")
|
||
Gen.builder.cbranch(is_error, ErrorBB, OkBB)
|
||
Gen.builder.position_at_start(ErrorBB)
|
||
ret_type: ir.Type | None = getattr(Gen.func, 'ftype', None) and Gen.func.ftype.return_type if getattr(Gen, 'func', None) else None
|
||
error_ret_val: ir.Constant | None = None
|
||
if isinstance(ret_type, ir.IdentifiedStructType):
|
||
if ret_type.elements:
|
||
error_ret_val = ir.Constant(ret_type, [
|
||
ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType))
|
||
else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType))
|
||
else ir.Constant(et, ir.Undefined) for et in ret_type.elements])
|
||
else:
|
||
error_ret_val = ir.Constant(ret_type, None)
|
||
elif isinstance(ret_type, ir.PointerType):
|
||
error_ret_val = ir.Constant(ret_type, None)
|
||
elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)):
|
||
error_ret_val = ir.Constant(ret_type, 0.0)
|
||
elif isinstance(ret_type, ir.IntType):
|
||
error_ret_val = ir.Constant(ret_type, 1)
|
||
elif isinstance(ret_type, ir.VoidType):
|
||
pass
|
||
else:
|
||
error_ret_val = ir.Constant(ir.IntType(32), 1)
|
||
if Gen.eh_except_block_stack:
|
||
ExceptBB, _, exception_code, _ = Gen.eh_except_block_stack[-1]
|
||
if ExceptBB is not None:
|
||
if has_eh_code_out and eh_code_ptr is not None:
|
||
eh_code_val = Gen._load(eh_code_ptr, name=f"Load_eh_code_{func_name}")
|
||
Gen._store(eh_code_val, exception_code)
|
||
else:
|
||
Gen._store(ir.Constant(ir.IntType(32), 1), exception_code)
|
||
Gen.builder.branch(ExceptBB)
|
||
else:
|
||
if isinstance(ret_type, ir.VoidType):
|
||
Gen.builder.ret_void()
|
||
else:
|
||
Gen.builder.ret(error_ret_val)
|
||
else:
|
||
if isinstance(ret_type, ir.VoidType):
|
||
Gen.builder.ret_void()
|
||
else:
|
||
Gen.builder.ret(error_ret_val)
|
||
Gen.builder.position_at_start(OkBB)
|
||
|
||
def _fill_default_args(self, CallArgs: list[ir.Value], func: ir.Function | None, func_name: str | None = None) -> None:
|
||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||
global_defaults: dict = self.Trans._global_function_default_args
|
||
func_defaults: list | None = None
|
||
if func_name:
|
||
func_defaults = global_defaults.get(func_name)
|
||
if not func_defaults and func:
|
||
func_defaults = global_defaults.get(func.name)
|
||
if not func_defaults and func_name:
|
||
for gk, gv in global_defaults.items():
|
||
if func_name in gk or gk.endswith(func_name) or gk.endswith('.' + func_name):
|
||
func_defaults = gv
|
||
break
|
||
if func and len(CallArgs) < len(func.args):
|
||
total_params: int = len(func.args)
|
||
if func_defaults:
|
||
num_defaults: int = len(func_defaults)
|
||
default_start: int = total_params - num_defaults
|
||
else:
|
||
num_defaults = 0
|
||
default_start = total_params
|
||
while len(CallArgs) < total_params:
|
||
arg_idx: int = len(CallArgs)
|
||
arg = func.args[arg_idx]
|
||
param_type: ir.Type = arg.type if hasattr(arg, 'type') else arg
|
||
if func_defaults and arg_idx >= default_start:
|
||
def_idx: int = arg_idx - default_start
|
||
if def_idx < num_defaults and func_defaults[def_idx] is not None:
|
||
default_val = func_defaults[def_idx]
|
||
if isinstance(param_type, ir.IntType):
|
||
max_val: int = (1 << param_type.width) - 1
|
||
if isinstance(default_val, bool):
|
||
default_val = 1 if default_val else 0
|
||
if isinstance(default_val, int) and default_val > max_val:
|
||
default_val = default_val & max_val
|
||
if isinstance(default_val, int) and default_val < 0:
|
||
default_val = default_val & max_val
|
||
CallArgs.append(ir.Constant(param_type, default_val))
|
||
elif isinstance(param_type, ir.PointerType):
|
||
CallArgs.append(ir.Constant(param_type, None))
|
||
else:
|
||
try:
|
||
_zv = Gen._zero_value_for_type(param_type)
|
||
CallArgs.append(_zv if _zv is not None else ir.Constant(ir.IntType(32), 0))
|
||
except (AssertionError, TypeError):
|
||
CallArgs.append(ir.Constant(ir.IntType(32), 0))
|
||
else:
|
||
if isinstance(param_type, ir.PointerType):
|
||
CallArgs.append(ir.Constant(param_type, None))
|
||
elif isinstance(param_type, ir.IntType):
|
||
CallArgs.append(ir.Constant(param_type, 0))
|
||
else:
|
||
try:
|
||
_zv = Gen._zero_value_for_type(param_type)
|
||
CallArgs.append(_zv if _zv is not None else ir.Constant(ir.IntType(32), 0))
|
||
except (AssertionError, TypeError):
|
||
CallArgs.append(ir.Constant(ir.IntType(32), 0))
|
||
else:
|
||
if isinstance(param_type, ir.PointerType):
|
||
CallArgs.append(ir.Constant(param_type, None))
|
||
elif isinstance(param_type, ir.IntType):
|
||
CallArgs.append(ir.Constant(param_type, 0))
|
||
else:
|
||
try:
|
||
_zv = Gen._zero_value_for_type(param_type)
|
||
CallArgs.append(_zv if _zv is not None else ir.Constant(ir.IntType(32), 0))
|
||
except (AssertionError, TypeError):
|
||
CallArgs.append(ir.Constant(ir.IntType(32), 0))
|
||
|
||
def _LookupGlobalDefaults(self, func_name: str | None) -> list | None:
|
||
"""按函数名查询全局默认参数表(跨模块调用点用)。
|
||
|
||
查找顺序:精确键 → 去 mangled 前缀后的裸名 → 以 '.<裸名>' 结尾的键
|
||
(如 {sha1}.name)。精确键优先,避免"同名不同模块"的默认值互相乱配。
|
||
"""
|
||
if not func_name:
|
||
return None
|
||
table: dict = getattr(self.Trans, '_global_function_default_args', None) or {}
|
||
if not table:
|
||
return None
|
||
hit = table.get(func_name)
|
||
if hit:
|
||
return hit
|
||
base: str = func_name.split('.')[-1]
|
||
if base != func_name:
|
||
hit = table.get(base)
|
||
if hit:
|
||
return hit
|
||
for key, value in table.items():
|
||
if key.endswith('.' + base):
|
||
return value
|
||
return None
|
||
|
||
def _LookupGlobalParamNames(self, func_name: str | None) -> list | None:
|
||
"""按函数名查询全局参数名表;查找顺序同 _LookupGlobalDefaults。"""
|
||
if not func_name:
|
||
return None
|
||
table: dict = getattr(self.Trans, '_global_function_param_names', None) or {}
|
||
if not table:
|
||
return None
|
||
hit = table.get(func_name)
|
||
if hit:
|
||
return hit
|
||
base: str = func_name.split('.')[-1]
|
||
if base != func_name:
|
||
hit = table.get(base)
|
||
if hit:
|
||
return hit
|
||
for key, value in table.items():
|
||
if key.endswith('.' + base):
|
||
return value
|
||
return None
|
||
|
||
@staticmethod
|
||
def _ConstantToIrValue(raw: object, param_type: ir.Type, Gen: LlvmGeneratorMixin) -> ir.Value | None:
|
||
"""把全局默认参数表里的 Python 常量转成形参类型的 IR 常量。
|
||
|
||
只处理整数/布尔(跨模块默认值里最常见,如 cap: CSizeT = 4096)。字符串等
|
||
常量需要在调用点引用定义模块的全局对象,无法安全重建 → 返回 None,调用点
|
||
退回原有零值填充(与修复前行为一致)。
|
||
"""
|
||
if isinstance(param_type, ir.IntType):
|
||
if isinstance(raw, bool):
|
||
raw = 1 if raw else 0
|
||
if isinstance(raw, int):
|
||
max_val: int = (1 << param_type.width) - 1
|
||
if raw > max_val or raw < 0:
|
||
raw = raw & max_val
|
||
return ir.Constant(param_type, raw)
|
||
return ir.Constant(param_type, 0)
|
||
if isinstance(param_type, ir.PointerType):
|
||
return ir.Constant(param_type, None)
|
||
return None
|
||
|
||
def _ApplyKeywordArgs(self, Node: ast.Call, CallArgs: list[ir.Value], func: ir.Function | None, func_name: str | None, self_offset: int = 1) -> None:
|
||
"""在 _fill_default_args 之后调用:用 keyword args 按 param_names 覆盖 CallArgs 对应位置。
|
||
self_offset=1 表示 CallArgs[0] 是 self,参数从 CallArgs[1] 开始(__init__/__new__/__call__/method)。
|
||
self_offset=0 表示无 self,参数从 CallArgs[0] 开始(普通函数)。
|
||
"""
|
||
if not Node.keywords:
|
||
return
|
||
global_param_names: dict = self.Trans._global_function_param_names
|
||
param_names: list[str] | None = None
|
||
if func_name:
|
||
param_names = global_param_names.get(func_name)
|
||
if not param_names and func is not None:
|
||
param_names = global_param_names.get(func.name)
|
||
if not param_names and func is not None and hasattr(func, 'args'):
|
||
llvm_names: list[str] = [a.name for a in func.args] if func.args else []
|
||
if llvm_names and not all(n.isdigit() for n in llvm_names):
|
||
param_names = llvm_names
|
||
if not param_names:
|
||
# 无法获取参数名,回退:按顺序追加(保持旧行为,避免静默丢弃)
|
||
for kw in Node.keywords:
|
||
if kw.arg is None:
|
||
continue
|
||
ArgVal = self.HandleExprLlvm(kw.value)
|
||
if ArgVal:
|
||
CallArgs.append(ArgVal)
|
||
return
|
||
for kw in Node.keywords:
|
||
if kw.arg is None:
|
||
continue
|
||
ArgVal = self.HandleExprLlvm(kw.value)
|
||
if not ArgVal:
|
||
continue
|
||
if kw.arg in param_names:
|
||
idx: int = param_names.index(kw.arg)
|
||
target_idx: int = idx - self_offset
|
||
if 0 <= target_idx < len(CallArgs) - self_offset:
|
||
CallArgs[self_offset + target_idx] = ArgVal
|
||
|
||
def _CheckFuncPtrArity(self, Node: ast.Call, FnPtr: ir.Value, Args: list[ir.Value],
|
||
FuncName: str, Gen: LlvmGeneratorMixin) -> None:
|
||
"""函数指针间接调用前的 arity 校验(fail-fast,紧邻 builder.call 之前)。
|
||
|
||
期望形参个数取自 FnPtr 的静态 LLVM 函数类型的形参表:来源是函数指针槽
|
||
(模块级/局部 Callable[...] 注解)的 CTypeInfo.FuncPtrParams →
|
||
CTypeInfo.ToLLVM/_ctype_to_llvm → ir.FunctionType(ret, params);变参位由
|
||
FunctionType.var_arg 承载。不校验时,实参个数少于形参个数会让 llvmlite
|
||
CallInstr 按形参个数索引 args[i] 抛裸 `IndexError: list index out of range`
|
||
(无函数名、无源位置,栈顶落在被调函数 docstring 行,无法定位真因)。
|
||
|
||
变参函数(var_arg=True,如 C printf 形态)只要求实参不少于固定形参个数:
|
||
多出的实参按变参传递,不报错;仅 len(Args) < 固定形参个数 时报错。
|
||
"""
|
||
FnType: ir.Type = FnPtr.type.pointee if isinstance(FnPtr.type, ir.PointerType) else FnPtr.type
|
||
if not isinstance(FnType, ir.FunctionType):
|
||
return
|
||
Expected: int = len(FnType.args)
|
||
Actual: int = len(Args)
|
||
IsVariadic: bool = bool(getattr(FnType, 'var_arg', False))
|
||
if IsVariadic:
|
||
if Actual >= Expected:
|
||
return
|
||
elif Actual == Expected:
|
||
return
|
||
# 源位置:按本文件既有写法取 Node 自身的 lineno/col_offset(不用
|
||
# _current_node_info/_current_lineno —— 二者可能停留在上一条语句),
|
||
# 源文件取 Gen._current_source_file,源码行取 Gen._get_source_line。
|
||
Lineno: int = getattr(Node, 'lineno', 0) or 0
|
||
# 注入行偏移还原:AST 行号含 _inject_auto_imports 在文件头注入的 N 行,
|
||
# 先按精确偏移减回磁盘真实行号(N 由 Phase2Translator 计算并挂到 translator);
|
||
# 报文行号与源码行必须同用还原后的 Lineno,二者一致(否则会显示下一行源码)。
|
||
_line_offset: int = int(getattr(self.Trans, '_line_offset', 0) or 0)
|
||
if _line_offset > 0 and Lineno > _line_offset:
|
||
Lineno -= _line_offset
|
||
Col: int = getattr(Node, 'col_offset', -1)
|
||
SrcFile: str = getattr(Gen, '_current_source_file', '') or 'unknown'
|
||
Loc: str = f"{SrcFile}:{Lineno}"
|
||
if Col >= 0:
|
||
Loc += f":{Col}"
|
||
SourceLine: str = ''
|
||
if Lineno > 0 and hasattr(Gen, '_get_source_line'):
|
||
SourceLine = (Gen._get_source_line(Lineno) or '').strip()
|
||
ExpectText: str = (f"至少 {Expected} 个形参(变参函数,仅固定形参)"
|
||
if IsVariadic else f" {Expected} 个形参")
|
||
raise Exception(
|
||
f"[TransPyC] 函数指针调用实参个数不匹配: '{FuncName}' 期望{ExpectText},"
|
||
f"实际传入 {Actual} 个实参;请检查该函数指针(Callable[...] 注解槽)的"
|
||
f"形参表是否与调用处实参个数一致。位置 {Loc}"
|
||
f"{(',源码: ' + SourceLine) if SourceLine else ''}"
|
||
)
|
||
|
||
def _RequireArgValue(self, ArgVal: ir.Value | None, Callee: str, ArgIndex: int,
|
||
ArgNode: ast.AST, CallNode: ast.Call) -> ir.Value:
|
||
"""fail-fast:调用实参编译期求值为空(`HandleExprLlvm` 返回 None)时终止装配。
|
||
|
||
调用装配处原写作 `ArgVal = self.HandleExprLlvm(arg); if ArgVal: 追加(ArgVal)`:
|
||
实参求值为 None 时它被**静默整条丢弃**,导致后续实参整体前移一格,最终由
|
||
`FuncGen._adjust_args` 报出误导性的"指针类型不能隐式转换为整数参数"(真因是
|
||
"少了一个实参")。实例:`ast.OpKind.BitOr` 因枚举成员未登记而求值 None ⇒
|
||
`ast.BinOp(...)` 的 4 个实参退化为 3 个 ⇒ `AST*` 落到 `op: i32`(见
|
||
`Debugger/rawptr-migration-and-fastfail.md` §27、`Debugger/enum-semantics.md`
|
||
的「逗号分组成员被静默丢弃」一节)。
|
||
|
||
`HandleExprLlvm` 返回 None 只有一种语义——该表达式编译期**求值失败**
|
||
(名称/属性链/枚举成员未登记、跨模块符号查找失败、类构造在声明期结构体不完整等);
|
||
"按类型本无值"的形态(以返回 void 的调用收尾)返回的是 CallInstr 对象而非 None,
|
||
故不存在需要跳过的合法实参。此处改为当场终止,报文含被调者、实参序号与源表达式、
|
||
根因提示与源码位置;**不丢弃该实参**。
|
||
"""
|
||
if ArgVal is not None:
|
||
return ArgVal
|
||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||
expr_text: str = self._ExprText(ArgNode)
|
||
ArgKind: str = type(ArgNode).__name__
|
||
raw_lineno: int = getattr(ArgNode, 'lineno', 0) or getattr(CallNode, 'lineno', 0) or 0
|
||
lineno: int = raw_lineno
|
||
# 行号还原:`_inject_auto_imports` 会在解析前往文件头注入 import 行,AST 行号
|
||
# 比磁盘真实行号大 N;与 HandlesBase._RaiseUnresolvedExpr 同口径。
|
||
_line_offset: int = int(getattr(self.Trans, '_line_offset', 0) or 0)
|
||
if _line_offset > 0 and lineno > _line_offset:
|
||
lineno -= _line_offset
|
||
col: int = getattr(ArgNode, 'col_offset', -1)
|
||
src_file: str = getattr(Gen, '_current_source_file', '') or 'unknown'
|
||
code_line: str = ''
|
||
if lineno > 0 and hasattr(Gen, '_get_source_line'):
|
||
try:
|
||
code_line = (Gen._get_source_line(lineno) or '').strip()
|
||
except Exception:
|
||
code_line = ''
|
||
loc: str = f"{src_file}:{lineno}"
|
||
if col >= 0:
|
||
loc += f":{col}"
|
||
# 实参是属性读时补同一份基址事实(与 HandlesBase._RaiseUnresolvedExpr 共用
|
||
# `_DescribeAttrBase`):属性读取值失败的两类根因(类名登记退化 / 键不同源)
|
||
# 必须一眼可见,不再从"求值失败"反推。
|
||
_base_facts: str = ''
|
||
if isinstance(ArgNode, ast.Attribute):
|
||
try:
|
||
_base_facts = self._DescribeAttrBase(Gen, ArgNode)
|
||
except Exception: # noqa: BLE001
|
||
_base_facts = ''
|
||
raise Exception(
|
||
f"[TransPyC] 调用实参编译期求值为空: 被调者 '{Callee}' 的第 {ArgIndex} 个实参 "
|
||
f"'{expr_text}'({ArgKind} 形态)求值失败;已终止编译,不丢弃该实参"
|
||
f"(丢弃会使后续实参前移一格,报出与真因无关的类型不匹配)。"
|
||
f"常见根因:枚举成员/名称未登记、跨模块符号查找失败、类定义在声明期结构体不完整。"
|
||
f"位置 {loc}"
|
||
f"{(',源码: ' + code_line) if code_line else ''}"
|
||
f"{chr(10) + '│ 基址诊断: ' + _base_facts if _base_facts else ''}"
|
||
)
|
||
|
||
def _HandleCallLlvm(self, Node: ast.Call) -> ir.Value:
|
||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||
# 协程:coro.coro_run(帧) 内联翻译为 resume 循环
|
||
if isinstance(Node.func, ast.Attribute) and Node.func.attr == 'coro_run':
|
||
if isinstance(Node.func.value, ast.Name) and self.Trans.AsyncHandler._IsCoroModule(Node.func.value.id):
|
||
return self.Trans.AsyncHandler._HandleCoroRunLlvm(Node, Gen)
|
||
# 协程:coro.coro_destroy(帧) 内联翻译为 free
|
||
if isinstance(Node.func, ast.Attribute) and Node.func.attr == 'coro_destroy':
|
||
if isinstance(Node.func.value, ast.Name) and self.Trans.AsyncHandler._IsCoroModule(Node.func.value.id):
|
||
return self.Trans.AsyncHandler._HandleCoroDestroyLlvm(Node, Gen)
|
||
# 协程:coro.coro_exception(帧) 内联翻译为帧 exc 槽读取
|
||
if isinstance(Node.func, ast.Attribute) and Node.func.attr == 'coro_exception':
|
||
if isinstance(Node.func.value, ast.Name) and self.Trans.AsyncHandler._IsCoroModule(Node.func.value.id):
|
||
return self.Trans.AsyncHandler._HandleCoroExceptionLlvm(Node, Gen)
|
||
# 协程:coro.coro_exception_msg(帧) 内联翻译为帧 msg 槽读取
|
||
if isinstance(Node.func, ast.Attribute) and Node.func.attr == 'coro_exception_msg':
|
||
if isinstance(Node.func.value, ast.Name) and self.Trans.AsyncHandler._IsCoroModule(Node.func.value.id):
|
||
return self.Trans.AsyncHandler._HandleCoroExceptionMsgLlvm(Node, Gen)
|
||
# 协程:coro.coro_gather(帧...) 内联翻译为并发推进循环
|
||
if isinstance(Node.func, ast.Attribute) and Node.func.attr == 'coro_gather':
|
||
if isinstance(Node.func.value, ast.Name) and self.Trans.AsyncHandler._IsCoroModule(Node.func.value.id):
|
||
return self.Trans.AsyncHandler._HandleCoroGatherLlvm(Node, Gen)
|
||
FuncAttr: str | None = None
|
||
ModulePath: str | None = None
|
||
if isinstance(Node.func, ast.Name):
|
||
FuncName = Node.func.id
|
||
# __asm__(...) 语法糖:等价 Asm(...)(裸名调用,无需 import c)
|
||
if FuncName == '__asm__':
|
||
return self.Trans.ExprAsmHandle._HandleAsmLlvm(Node)
|
||
# __llvmir__(...) 语法糖:等价 LLVMIR(...)
|
||
if FuncName == '__llvmir__':
|
||
return self._HandleLLVMIRLlvm(Node)
|
||
# irinp/irout 等价 LInp/LOut(仅作模板占位符,独立调用返回 0)
|
||
if FuncName in ('irinp', 'irout'):
|
||
return ir.Constant(ir.IntType(32), 0)
|
||
# 内建语法糖调用(裸名):Asm / Addr / Deref / DerefAs / Set / Load /
|
||
# PtrToInt / CError / AsmInp / AsmOut / LLVMIR / LInp / LOut /
|
||
# CPragma / CUndef 不是普通函数,优先于符号查找。
|
||
if FuncName == 'Asm':
|
||
return self.Trans.ExprAsmHandle._HandleAsmLlvm(Node)
|
||
if FuncName == 'Addr':
|
||
return self.Trans.CSpecialCallHandle._HandleCAddrLlvm(Node)
|
||
if FuncName == 'Set':
|
||
return self.Trans.CSpecialCallHandle._HandleCSetLlvm(Node)
|
||
if FuncName == 'Load':
|
||
return self.Trans.CSpecialCallHandle._HandleCLoadLlvm(Node)
|
||
if FuncName == 'Deref':
|
||
return self.Trans.CSpecialCallHandle._HandleCDerefLlvm(Node)
|
||
if FuncName == 'DerefAs':
|
||
return self._HandleCDerefAsLlvm(Node)
|
||
if FuncName == 'PtrToInt':
|
||
return self.Trans.CSpecialCallHandle._HandleCPtrToIntLlvm(Node)
|
||
if FuncName in ('AsmInp', 'AsmOut', 'LInp', 'LOut'):
|
||
return ir.Constant(ir.IntType(32), 0)
|
||
if FuncName == 'LLVMIR':
|
||
return self._HandleLLVMIRLlvm(Node)
|
||
if FuncName in ('CPragma', 'CUndef'):
|
||
return ir.Constant(ir.IntType(1), 1)
|
||
if FuncName == 'CError':
|
||
msg = "compile-time error"
|
||
if Node.args:
|
||
arg = Node.args[0]
|
||
if isinstance(arg, ast.Constant) and isinstance(arg.value, str):
|
||
msg = arg.value
|
||
lineno = getattr(Node, 'lineno', 0)
|
||
# 注入行偏移还原:AST 行号含 _inject_auto_imports 注入的 N 行
|
||
_line_offset: int = int(getattr(self.Trans, '_line_offset', 0) or 0)
|
||
if _line_offset > 0 and lineno > _line_offset:
|
||
lineno -= _line_offset
|
||
raise Exception(f"#error: {msg} (line {lineno})")
|
||
# M1 协程:普通函数调用 async 函数 → create_<name>()(返回帧指针)
|
||
if hasattr(self.Trans, 'AsyncHandler') and self.Trans.AsyncHandler._IsAsyncFunc(FuncName):
|
||
return self.Trans.AsyncHandler._HandleAsyncCreateCallLlvm(Node, FuncName)
|
||
if hasattr(self.Trans.FunctionHandler, '_generic_templates') and FuncName in self.Trans.FunctionHandler._generic_templates:
|
||
return self._HandleGenericCallLlvm(Node, FuncName)
|
||
result = self.Trans.ExprBuiltinHandle._HandleBuiltinCallLlvm(Node)
|
||
if result is not None:
|
||
return result
|
||
if Gen._has_function(FuncName):
|
||
return self._HandleClosureCallLlvm(Node, FuncName)
|
||
SymInfo = self.Trans.SymbolTable.lookup(FuncName)
|
||
if SymInfo:
|
||
# 名字冲突处理:类名可能与 CEnum 成员名冲突(如 ASTKind.Name 枚举成员与 Name 类同名)
|
||
# 若该名字同时是类(在 Gen.structs 中或存在 __before_init__),优先作为类构造函数处理
|
||
IsAlsoClass: bool = (FuncName in Gen.structs) or Gen._has_function(f'{FuncName}.__before_init__')
|
||
if SymInfo.IsEnum and not (IsAlsoClass and getattr(SymInfo, 'IsEnumMember', False)):
|
||
# 枚举类型转换 `EnumName(v)`:结果宽度 = 该枚举的存储宽度
|
||
# (最宽成员类型),与成员常量宽度同点(ABI 一致)。
|
||
_enum_ty: ir.IntType = Gen._enum_int_type(FuncName, SymInfo)
|
||
if Node.args:
|
||
arg_val = self.HandleExprLlvm(Node.args[0])
|
||
if arg_val:
|
||
if isinstance(arg_val.type, ir.IntType) and arg_val.type.width != _enum_ty.width:
|
||
if arg_val.type.width < _enum_ty.width:
|
||
arg_val = Gen.builder.zext(arg_val, _enum_ty, name="zext_enum_arg")
|
||
else:
|
||
arg_val = Gen.builder.trunc(arg_val, _enum_ty, name="trunc_enum_arg")
|
||
return arg_val
|
||
return ir.Constant(_enum_ty, 0)
|
||
if SymInfo.IsTypedef:
|
||
return self._HandleTypedefCastLlvm(Node, FuncName)
|
||
NewFuncName = f'{FuncName}.__before_init__'
|
||
InitFuncName = f'{FuncName}.__init__'
|
||
if Gen._has_function(NewFuncName):
|
||
return self._HandleClassNewLlvm(Node, FuncName)
|
||
if Gen._has_function(InitFuncName) and FuncName in Gen.structs:
|
||
return self._HandleClassNewLlvm(Node, FuncName)
|
||
if FuncName in Gen.structs:
|
||
return self._HandleClassNewLlvm(Node, FuncName)
|
||
if hasattr(self.Trans.ClassHandler, '_generic_class_templates') and FuncName in self.Trans.ClassHandler._generic_class_templates:
|
||
return self._HandleClassNewLlvm(Node, FuncName)
|
||
if self.Trans.FunctionDefCache.get(FuncName):
|
||
return self._HandleClosureCallLlvm(Node, FuncName)
|
||
if FuncName in self._C_LIB_FUNCS:
|
||
return self._HandleClosureCallLlvm(Node, FuncName)
|
||
ClassName = Gen.var_struct_class.get(FuncName)
|
||
if ClassName and Gen._has_function(f'{ClassName}.__call__'):
|
||
return self._HandleInstanceCallLlvm(Node, FuncName, ClassName)
|
||
t_c_imported = getattr(self.Trans, '_from_import_aliases', {})
|
||
if FuncName in t_c_imported:
|
||
src_module, src_name = t_c_imported[FuncName]
|
||
virtual_node = self._make_virtual_attr_call(Node, src_module, src_name)
|
||
return self._HandleCallLlvm(virtual_node)
|
||
# 检查是否是全局变量中的函数指针(Callable 类型在模块级定义)
|
||
if FuncName not in Gen.variables and FuncName in Gen.global_vars:
|
||
Gen._Load_var(FuncName)
|
||
if FuncName not in Gen.variables and FuncName in Gen.module.globals:
|
||
GVar = Gen.module.globals[FuncName]
|
||
if not isinstance(GVar, ir.Function):
|
||
StoredType = GVar.type.pointee if isinstance(GVar.type, ir.PointerType) else GVar.type
|
||
if isinstance(StoredType, ir.PointerType) and isinstance(StoredType.pointee, ir.FunctionType):
|
||
Gen.variables[FuncName] = GVar
|
||
# 检查是否是闭包变量(lambda 赋值给变量后调用)
|
||
if FuncName in Gen.variables and Gen.variables[FuncName] is not None:
|
||
VarPtr = Gen.variables[FuncName]
|
||
# 检查是否是函数指针变量(Callable 类型),直接加载并调用
|
||
if isinstance(VarPtr, ir.GlobalVariable) and isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, ir.PointerType) and isinstance(VarPtr.type.pointee.pointee, ir.FunctionType):
|
||
fn_ptr = Gen._load(VarPtr, name=f"Load_fn_{FuncName}")
|
||
args = []
|
||
for arg in Node.args:
|
||
ArgVal = self.HandleExprLlvm(arg)
|
||
if ArgVal:
|
||
args.append(ArgVal)
|
||
self._CheckFuncPtrArity(Node, fn_ptr, args, FuncName, Gen)
|
||
return Gen.builder.call(fn_ptr, args, name=f"call_{FuncName}")
|
||
closure_ptr = Gen._load(VarPtr, name=f"Load_closure_{FuncName}")
|
||
if isinstance(closure_ptr.type, ir.PointerType) and isinstance(closure_ptr.type.pointee, ir.FunctionType):
|
||
fn_ptr = closure_ptr
|
||
args = []
|
||
for arg in Node.args:
|
||
ArgVal = self.HandleExprLlvm(arg)
|
||
if ArgVal:
|
||
args.append(ArgVal)
|
||
self._CheckFuncPtrArity(Node, fn_ptr, args, FuncName, Gen)
|
||
return Gen.builder.call(fn_ptr, args, name=f"call_{FuncName}")
|
||
# 处理 CPtr (i8*) 函数指针调用
|
||
# 当函数被赋值给 CPtr 变量时,原始函数类型退化为 i8*
|
||
# 检查是否是闭包变量(通过 _closure_var_types 追踪)
|
||
if isinstance(closure_ptr.type, ir.PointerType) and isinstance(closure_ptr.type.pointee, ir.IntType) and closure_ptr.type.pointee.width == 8:
|
||
ClosureInfo: tuple[ir.Type, list[ir.Type]] | None = Gen._closure_var_types.get(FuncName)
|
||
if ClosureInfo is not None:
|
||
# 闭包结构体解包:{i8* env, i8* fn} -> 加载 env 和 fn,构造正确函数签名
|
||
FnRetType: ir.Type = ClosureInfo[0]
|
||
NonlocalArgTypes: list[ir.Type] = [_safe_ptr_type(t) for t in ClosureInfo[1]]
|
||
I8PtrType: ir.PointerType = ir.IntType(8).as_pointer()
|
||
ClosureStructType: ir.LiteralStructType = ir.LiteralStructType([I8PtrType, I8PtrType])
|
||
ClosureStructPtr: ir.Value = Gen.builder.bitcast(closure_ptr, ir.PointerType(ClosureStructType), name=f"cast_closure_{FuncName}")
|
||
# 加载 env(field 0)和 fn(field 1)
|
||
EnvGep: ir.Value = Gen.builder.gep(ClosureStructPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"env_gep_{FuncName}")
|
||
EnvVal: ir.Value = Gen._load(EnvGep, name=f"env_{FuncName}")
|
||
FnGep: ir.Value = Gen.builder.gep(ClosureStructPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 1)], name=f"fn_gep_{FuncName}")
|
||
FnVal: ir.Value = Gen._load(FnGep, name=f"fn_{FuncName}")
|
||
# 收集用户调用参数
|
||
UserArgTypes: list[ir.Type] = []
|
||
UserCallArgs: list[ir.Value] = []
|
||
for arg in Node.args:
|
||
ArgVal = self.HandleExprLlvm(arg)
|
||
if ArgVal:
|
||
UserCallArgs.append(ArgVal)
|
||
UserArgTypes.append(ArgVal.type)
|
||
# 构造完整函数类型:[nonlocal_types..., user_arg_types...]
|
||
FullArgTypes: list[ir.Type] = list(NonlocalArgTypes) + UserArgTypes
|
||
FullFnType: ir.FunctionType = ir.FunctionType(FnRetType, FullArgTypes)
|
||
FullFnPtr: ir.Value = Gen.builder.bitcast(FnVal, ir.PointerType(FullFnType), name=f"cast_fn_{FuncName}")
|
||
# 调用参数:env 对应 nonlocal 参数,bitcast 到正确类型(需 _safe_ptr_type 兜底避免 void*)
|
||
CallArgs: list[ir.Value] = []
|
||
if NonlocalArgTypes:
|
||
CallArgs.append(Gen.builder.bitcast(EnvVal, _safe_ptr_type(NonlocalArgTypes[0]), name=f"cast_env_{FuncName}"))
|
||
CallArgs.extend(UserCallArgs)
|
||
return Gen.builder.call(FullFnPtr, CallArgs, name=f"call_{FuncName}")
|
||
# 普通函数指针调用(无闭包):从调用参数构造函数类型,默认返回 i32
|
||
cptr_arg_types: list[ir.Type] = []
|
||
cptr_call_args: list[ir.Value] = []
|
||
for arg in Node.args:
|
||
ArgVal = self.HandleExprLlvm(arg)
|
||
if ArgVal:
|
||
cptr_call_args.append(ArgVal)
|
||
cptr_arg_types.append(ArgVal.type)
|
||
cptr_fn_type = ir.FunctionType(ir.IntType(32), cptr_arg_types)
|
||
cptr_fn_ptr = Gen.builder.bitcast(closure_ptr, ir.PointerType(cptr_fn_type), name=f"cast_fn_{FuncName}")
|
||
return Gen.builder.call(cptr_fn_ptr, cptr_call_args, name=f"call_{FuncName}")
|
||
if isinstance(closure_ptr.type, ir.PointerType) and isinstance(closure_ptr.type.pointee, ir.LiteralStructType):
|
||
st = closure_ptr.type.pointee
|
||
if len(st.elements) == 2 and isinstance(st.elements[1], ir.PointerType) and isinstance(st.elements[1].pointee, ir.FunctionType):
|
||
fn_ptr_type = st.elements[1]
|
||
fn_ptr = Gen.builder.gep(closure_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 1)], name=f"fn_ptr_{FuncName}")
|
||
fn_val = Gen._load(fn_ptr, name=f"fn_{FuncName}")
|
||
args = []
|
||
for arg in Node.args:
|
||
ArgVal = self.HandleExprLlvm(arg)
|
||
if ArgVal:
|
||
args.append(ArgVal)
|
||
env_ptr = Gen.builder.gep(closure_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"env_ptr_{FuncName}")
|
||
env_val = Gen._load(env_ptr, name=f"env_{FuncName}")
|
||
call_args = [env_val] + args
|
||
expected_fn_type = fn_ptr_type.pointee
|
||
if len(call_args) < len(expected_fn_type.args):
|
||
while len(call_args) < len(expected_fn_type.args):
|
||
call_args.append(ir.Constant(expected_fn_type.args[len(call_args)], 0))
|
||
# 如果函数期望的 env 类型与闭包中存储的 i8* 不同,做 bitcast(避免 void*)
|
||
if len(expected_fn_type.args) > 0 and call_args[0].type != expected_fn_type.args[0]:
|
||
safe_env_type: ir.Type = _safe_ptr_type(expected_fn_type.args[0])
|
||
call_args[0] = Gen.builder.bitcast(call_args[0], safe_env_type, name=f"cast_env_{FuncName}")
|
||
return Gen.builder.call(fn_val, call_args, name=f"call_{FuncName}")
|
||
# 编译器内置裸指针强转 rawptr(x):rawptr 是 TPC/VPC 双端**语法保留字**
|
||
# (无 SymbolTable typedef 条目、无泛型模板;builtins.vp 已不再声明它,
|
||
# 见 TypeAnnotationResolver._BUILTIN_ROWPTR_NAME 与 VPC 同口径内置分支
|
||
# TypeGenResolve.vp:921)。落到下方 typedef 表判据必然 miss ⇒ 误报
|
||
# "Undefined function: 'rawptr'"(ViperC/App/lib/core/Gen/
|
||
# StructGenMixin.vp `vt_ptr: rawptr = rawptr(*(uint64*)(default_val))` 根因)。
|
||
# 单独 rawptr 等价 CPtr(void* → i8*):目标类型取内置 rawptr 的权威
|
||
# CTypeInfo(_builtin_rawptr_info,与注解侧同源),转换复用 (rawptr[X])(x)
|
||
# / (CPtr)(x) 的 _emit_rawptr_cast——不新造第二套 rawptr 表示。
|
||
# 不照抄 uchar 的做法(往 builtins.vp 加 `uchar: CTypedef = ...`):
|
||
# rawptr 不是普通 typedef 名而是内置语法,VPC register_ctypedef 显式拒绝
|
||
# 重定义(TypeGenCType.vp:157-160)、TPC builtins_typedef_value 亦硬编码
|
||
# 返回内置值(TypeAnnotationResolver.py:313-314)⇒ 该声明不生效。
|
||
# 本分支置于下方 try 之外:解析/转换异常必须外抛,不得被吞成
|
||
# "Undefined function: 'rawptr'" 的误导报文。
|
||
from lib.core.TypeAnnotationResolver import TypeAnnotationResolver as _TAR_RP
|
||
if FuncName == _TAR_RP._BUILTIN_ROWPTR_NAME:
|
||
_rawptr_target: ir.Type = Gen._ctype_to_llvm(_TAR_RP._builtin_rawptr_info())
|
||
return self._emit_rawptr_cast(Node, Gen, _rawptr_target)
|
||
# builtins 隐式 CTypedef 作为类型转换调用(uint64(x)/int64(x)/size_t(x) 等,
|
||
# builtins.vp 声明、无需 import,不注册进 SymbolTable):常规 miss 后在此
|
||
# 尝试 typedef cast(uint64(buf) = CUInt64T(buf)),否则报
|
||
# "Undefined function: 'uint64'"(includes/ast/base.vp bootstrap 根因)。
|
||
_td_diag: str = ''
|
||
try:
|
||
from lib.core.TypeAnnotationResolver import TypeAnnotationResolver as _TAR_TD
|
||
_td_table: dict = _TAR_TD._scan_builtins()['typedefs']
|
||
if FuncName not in _td_table:
|
||
# 典型成因:includes/builtins.vp 未定位到(PROJECT_INCLUDE_DIRS 尚未
|
||
# 装配)、或声明写法未被文本扫描识别 ⇒ 整表为空/缺项。
|
||
_td_diag = (f"(builtins typedef 表 {len(_td_table)} 项,无 '{FuncName}';"
|
||
f"includes 目录={_TAR_TD._builtins_include_dirs()})")
|
||
if FuncName in _td_table:
|
||
# from_type_name 对裸 typedef 名(uint64 等)解析不出真实类型类
|
||
# (BuiltinTypeMap 无此键,CreateFromTypeName 落空成空 CType),
|
||
# 因此改走权威 typedef 值:'CUInt64T' → CTypeRegistry.NameToLLVM
|
||
# → 'i64'(与 DeclarationGenerator 的 stub 兜底同机制)。
|
||
_bv_td: str | None = _TAR_TD.builtins_typedef_value(FuncName)
|
||
_lls_td: str | None = None
|
||
if _bv_td:
|
||
_nm_td: str = _bv_td
|
||
from lib.core.TypeSystem import CTypeRegistry as _CR_TD
|
||
_lls_td = _CR_TD.NameToLLVM(_nm_td)
|
||
if not _lls_td:
|
||
# 声明值本身也是短别名(新语法:`typedef short = int16`、
|
||
# `typedef longlong = int64`)⇒ 单步 NameToLLVM(不认短别名)
|
||
# 落空。改走权威链式解析(builtins.vp 声明 → 逐级展开到 C* 类型),
|
||
# 与注解位置 LLVMTypeMapper._resolve_name 同一来源。
|
||
_td_info = _TAR_TD._lookup_builtins_typedef(FuncName, self.Trans.SymbolTable)
|
||
if _td_info is not None and _td_info.BaseType:
|
||
_tg_td2: ir.Type = Gen._ctype_to_llvm(_td_info)
|
||
if isinstance(_tg_td2, (ir.IntType, ir.FloatType, ir.DoubleType, ir.PointerType)):
|
||
if len(Node.args) >= 2:
|
||
_p2b: ast.AST = Node.args[1]
|
||
_p2b_cptr: bool = (
|
||
isinstance(_p2b, ast.Name) and _p2b.id == 'CPtr'
|
||
)
|
||
if _p2b_cptr:
|
||
if isinstance(_tg_td2, ir.PointerType):
|
||
return self._emit_rawptr_cast(Node, Gen, _tg_td2)
|
||
return self._emit_rawptr_cast(Node, Gen, ir.PointerType(_tg_td2))
|
||
return self._emit_rawptr_cast(Node, Gen, _tg_td2)
|
||
if _lls_td:
|
||
_tg_td: ir.Type = Gen._ctype_to_llvm(_lls_td)
|
||
if isinstance(_tg_td, (ir.IntType, ir.FloatType, ir.DoubleType, ir.PointerType)):
|
||
# 双参数形式 uint8(s, CPtr) / int64(v, CPtr):第二参是
|
||
# CPtr 标记 → 指针包装(等价旧写法 CUInt8T(s, CPtr),
|
||
# 对齐 CXXX(v, CPtr) 的 IsPtr_cast 语义)。
|
||
# 单参形式 uint64(buf) 才是标量转换。忽略第二参会把
|
||
# hashlib/__sha1.vp 的 data 编译成标量 → 运行时 sha1
|
||
# transform 读越界崩溃。
|
||
if len(Node.args) >= 2:
|
||
_p2_td: ast.AST = Node.args[1]
|
||
_p2_cptr: bool = (
|
||
isinstance(_p2_td, ast.Name) and _p2_td.id == 'CPtr'
|
||
)
|
||
if _p2_cptr:
|
||
if isinstance(_tg_td, ir.PointerType):
|
||
return self._emit_rawptr_cast(Node, Gen, _tg_td)
|
||
_tg_ptr_td: ir.Type = ir.PointerType(_tg_td)
|
||
return self._emit_rawptr_cast(Node, Gen, _tg_ptr_td)
|
||
return self._emit_rawptr_cast(Node, Gen, _tg_td)
|
||
except Exception as _e_td:
|
||
# 不再静默:兜底链任何一步抛错都要带出来(此前 pass 让真正的根因
|
||
# 只剩一句误导性的 "Undefined function")。
|
||
_td_diag = _td_diag + f"(typedef cast 求值异常: {type(_e_td).__name__}: {_e_td})"
|
||
raise Exception(f"Undefined function: '{FuncName}'{_td_diag}")
|
||
if isinstance(Node.func, ast.Subscript):
|
||
# Handle list[int](mb) syntax — generic class constructor with explicit type args
|
||
# Handle xxx[T](x) syntax — generic function call with explicit type args
|
||
sub: ast.Subscript = Node.func
|
||
# (rawptr[X])(expr) / (CPtr[X])(expr):内建裸指针转换(无泛型模板)。
|
||
# 不拦截 → 泛型模板查不到 → 落 L850 "Unsupported call expression"
|
||
# (StubMergerCollect.vp L271 bootstrap 根因)。
|
||
_sub_nm: str | None = None
|
||
if isinstance(sub.value, ast.Name):
|
||
_sub_nm = sub.value.id
|
||
if _sub_nm in ('rawptr', 'CPtr'):
|
||
return self._HandleSubscriptPtrCastLlvm(Node, sub)
|
||
if isinstance(sub.value, ast.Name):
|
||
FuncName: str = sub.value.id
|
||
# 优先检查泛型类模板
|
||
if hasattr(self.Trans.ClassHandler, '_generic_class_templates') and FuncName in self.Trans.ClassHandler._generic_class_templates:
|
||
return self._HandleGenericClassNewLlvm(Node, FuncName, explicit_slice=sub.slice)
|
||
# 检查泛型函数模板(如 xxx[T](x))
|
||
if hasattr(self.Trans.FunctionHandler, '_generic_templates') and FuncName in self.Trans.FunctionHandler._generic_templates:
|
||
return self._HandleGenericCallExplicitLlvm(Node, FuncName, explicit_slice=sub.slice)
|
||
if isinstance(Node.func, ast.Attribute):
|
||
if Node.func.attr in ('update', 'final', 'transform'):
|
||
pass
|
||
if Node.func.attr == '__sizeof__':
|
||
if isinstance(Node.func.value, ast.Subscript):
|
||
spec_name = self._ResolveGenericSlice(Node.func.value)
|
||
if spec_name:
|
||
return self._HandleSizeofLlvm(ast.Name(id=spec_name, ctx=ast.Load()))
|
||
# 对于 BinOp/BitOr 联合类型(如 AST | CPtr),
|
||
# sizeof 应返回指针大小 8,而非结构体大小
|
||
# 必须在 HandleExprLlvm 之前检查,避免对类型名求值产生副作用
|
||
if isinstance(Node.func.value, ast.BinOp) and isinstance(Node.func.value.op, ast.BitOr):
|
||
if self._AnnotationContainsCPtr(Node.func.value):
|
||
return ir.Constant(ir.IntType(64), 8)
|
||
# 对于 ast.Attribute(如 ast.ClassDef.__sizeof__() / CInt.__sizeof__()),
|
||
# 直接调用 _HandleSizeofLlvm,不走 HandleExprLlvm
|
||
# 因为 ast.Attribute 在 sizeof 上下文中一定是类型名,不是变量
|
||
if isinstance(Node.func.value, ast.Attribute):
|
||
type_name = Node.func.value.attr
|
||
SizeofNode = ast.Name(id=type_name, ctx=ast.Load())
|
||
_r = self._HandleSizeofLlvm(SizeofNode)
|
||
return _r
|
||
# 对于 ast.Name,需要区分变量和类型名:
|
||
# - 如果是已知变量(Gen.variables/_reg_values/_direct_values/self),
|
||
# 走 HandleExprLlvm 路径(如 myvar.__sizeof__())
|
||
# - 否则视为类型名,直接调用 _HandleSizeofLlvm
|
||
# 这避免了 HandleExprLlvm 对类型名求值产生副作用
|
||
# (如修改 builder 状态、污染 variables 缓存等),
|
||
# 这些副作用会导致泛型特化后 then 块为空
|
||
if isinstance(Node.func.value, ast.Name):
|
||
nm: str = Node.func.value.id
|
||
is_variable: bool = (
|
||
nm == 'self'
|
||
or nm in Gen.variables
|
||
or nm in getattr(Gen, '_reg_values', {})
|
||
or nm in getattr(Gen, '_direct_values', {})
|
||
)
|
||
if not is_variable:
|
||
SizeofNode = ast.Name(id=nm, ctx=ast.Load())
|
||
_r = self._HandleSizeofLlvm(SizeofNode)
|
||
return _r
|
||
# 变量/实例的 sizeof: 通过 HandleExprLlvm 获取值
|
||
ObjVal = self.HandleExprLlvm(Node.func.value)
|
||
if ObjVal and isinstance(ObjVal.type, ir.PointerType):
|
||
pointee = ObjVal.type.pointee
|
||
if isinstance(pointee, ir.ArrayType):
|
||
# 元素尺寸统一走 Gen._get_struct_size(含字段对齐/填充,与 __sizeof__ /
|
||
# memhub alloc 同源):_get_struct_size(ArrayType) = 元素尺寸 × 元素数。
|
||
# 原实现手写「字段宽度直接相加 + 未知类型兜底 8」,会漏算 struct 的填充
|
||
# ({i8,i64} 算成 9 而非 16),sizeof 偏小 → 调用方按过小尺寸 alloc →
|
||
# 越界写坏邻居块头(与 1 GiB 主池漏满同一根因链)。
|
||
return ir.Constant(ir.IntType(64), Gen._get_struct_size(pointee))
|
||
elif isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
|
||
# 结构体实例: 直接计算大小
|
||
self._resolve_opaque_struct_members(pointee, Gen)
|
||
size = Gen._get_struct_size(pointee)
|
||
if size > 0:
|
||
return ir.Constant(ir.IntType(64), size)
|
||
# 回退: 尝试作为类型名处理
|
||
if isinstance(Node.func.value, ast.Name):
|
||
type_name = Node.func.value.id
|
||
SizeofNode = ast.Name(id=type_name, ctx=ast.Load())
|
||
return self._HandleSizeofLlvm(SizeofNode)
|
||
ModulePath = self._get_ModulePath(Node.func.value)
|
||
if ModulePath:
|
||
first_part = ModulePath.split('.')[0]
|
||
resolved_first = self.Trans.SymbolTable.resolve_alias(first_part)
|
||
if resolved_first != first_part:
|
||
ModulePath = resolved_first + ModulePath[len(first_part):]
|
||
# 统一获取模块 SHA1,用于跨模块类型引用(确保用源模块的 SHA1 而非当前模块)
|
||
# 放在 ModulePath 和 alias 解析之后,供所有 _HandleClassNewLlvm/_ensure_struct_declared 调用点使用
|
||
_ctor_module_sha1: str | None = None
|
||
if ModulePath:
|
||
_ctor_sha1_map: dict[str, str] = getattr(Gen, 'ModuleSha1Map', {})
|
||
_ctor_module_sha1 = _ctor_sha1_map.get(ModulePath)
|
||
if not _ctor_module_sha1 and '.' in ModulePath:
|
||
_ctor_module_sha1 = _ctor_sha1_map.get(ModulePath.split('.')[-1])
|
||
if ModulePath:
|
||
is_instance_var = isinstance(Node.func.value, ast.Name) and (
|
||
Node.func.value.id in Gen.var_struct_class
|
||
or Node.func.value.id in Gen.variables
|
||
or Node.func.value.id in Gen.global_vars
|
||
) and (
|
||
Node.func.value.id not in Gen.ModuleSha1Map
|
||
or Node.func.value.id in Gen.var_struct_class
|
||
or Node.func.value.id in Gen.variables
|
||
or Node.func.value.id in Gen.global_vars
|
||
)
|
||
is_class_name = isinstance(Node.func.value, ast.Name) and (Node.func.value.id in Gen.structs or self.Trans.SymbolTable.is_struct(Node.func.value.id))
|
||
# 链式方法调用:如 self.__mbuddy__.alloc() 或 trans.ImportsH.HandleImport(child)
|
||
# Node.func.value 是 ast.Attribute,基础是实例变量(如 self/trans)
|
||
_is_chained_instance: bool = False
|
||
if isinstance(Node.func.value, ast.Attribute):
|
||
_base_node: ast.AST = Node.func.value
|
||
while isinstance(_base_node, ast.Attribute):
|
||
_base_node = _base_node.value
|
||
if isinstance(_base_node, ast.Name):
|
||
_base_name: str = _base_node.id
|
||
# 检查基名是否为已知变量(self、局部变量、全局变量、已知 struct 变量)
|
||
# 且不在 ModuleSha1Map 中(避免把模块名误判为变量)
|
||
if _base_name == 'self' or (
|
||
(_base_name in Gen.var_struct_class
|
||
or _base_name in Gen.variables
|
||
or _base_name in Gen.global_vars)
|
||
and (_base_name not in Gen.ModuleSha1Map
|
||
or _base_name in Gen.var_struct_class
|
||
or _base_name in Gen.variables
|
||
or _base_name in Gen.global_vars)
|
||
):
|
||
_is_chained_instance = True
|
||
elif self._IsModuleQualifiedGlobalChain(_base_name, Node.func.value):
|
||
# 模块限定全局变量链:`Module.Global.field.method(...)`
|
||
# (如 GenApi._g_gen.ClassGenBase._collect_parents(...))。
|
||
# 链根是模块别名、次段是该模块的全局变量 ⇒ 接收者是对象,
|
||
# 与 self/局部变量/全局变量同一条"实例链"判据(详见
|
||
# _IsModuleQualifiedGlobalChain 的说明)。
|
||
_is_chained_instance = True
|
||
if (is_instance_var or _is_chained_instance) and not is_class_name:
|
||
return self._HandleMethodCallLlvm(Node)
|
||
FuncAttr = Node.func.attr
|
||
# 语法糖调用一律使用裸内建名;t./c. 前缀在调用点直接报错。
|
||
if ModulePath in ('t', 'c'):
|
||
raise TypeError(
|
||
f"[TPC] 类型注解/调用不再接受 '{ModulePath}.' 前缀;"
|
||
f"请直接写裸内建名,如 {FuncAttr}(...)")
|
||
# stdarg 模块的变参糖:stdarg.arg / stdarg.va_arg / stdarg.va_start /
|
||
# stdarg.va_end 命中与裸名同名内建**完全相同**的处理(stdarg 是编译器
|
||
# 拦截的糖模块,不是真符号,与内建语法糖同一口径)。仅当
|
||
# ModulePath 恰为 'stdarg' 时进入,不会抢掉其它模块/用户模块的调用。
|
||
if ModulePath == 'stdarg':
|
||
if FuncAttr == 'arg':
|
||
return self.Trans.ExprBuiltinHandle._HandleArgLlvm(Node.args)
|
||
elif FuncAttr == 'va_arg':
|
||
return self.Trans.ExprBuiltinHandle._HandleVaArgLlvm(Node.args)
|
||
elif FuncAttr == 'va_start':
|
||
return self.Trans.ExprBuiltinHandle._HandleVaStartLlvm(Node.args)
|
||
elif FuncAttr == 'va_end':
|
||
return self.Trans.ExprBuiltinHandle._HandleVaEndLlvm(Node.args)
|
||
if FuncAttr in Gen.structs:
|
||
result = self._HandleClassNewLlvm(Node, FuncAttr, module_sha1=_ctor_module_sha1)
|
||
if result is not None:
|
||
return result
|
||
if hasattr(self.Trans.ClassHandler, '_generic_class_templates') and FuncAttr in self.Trans.ClassHandler._generic_class_templates:
|
||
return self._HandleGenericClassNewLlvm(Node, FuncAttr)
|
||
# 跨模块 REnum 变体构造:ClassName.Variant(args)
|
||
# 直接检查 Node.func.value 是否是 REnum 类名(不依赖变体短名注册)
|
||
if isinstance(Node.func.value, ast.Name):
|
||
RenumClassName: str = Node.func.value.id
|
||
if self.Trans.SymbolTable.has(RenumClassName):
|
||
RenumInfo = self.Trans.SymbolTable[RenumClassName]
|
||
if RenumInfo.IsRenum and hasattr(RenumInfo, 'RenumVariants') and RenumInfo.RenumVariants:
|
||
if FuncAttr in RenumInfo.RenumVariants:
|
||
TagValue: int = RenumInfo.RenumVariants.index(FuncAttr)
|
||
result = self._HandleREnumConstructLlvm(Node, RenumClassName, FuncAttr, TagValue)
|
||
if result is not None:
|
||
return result
|
||
# 跨模块 REnum 变体构造(**点号类名**写法):`mod.ClassName.Variant(args)`
|
||
# 现场:`llvmlite.LLVMType.Struct(fields, fcount, name)` —— Node.func.value
|
||
# 是 Attribute(llvmlite.LLVMType)而不是 Name,上一条判据(L903 的
|
||
# isinstance(Node.func.value, ast.Name))漏掉 ⇒ 落到"模块函数 Struct"路径:
|
||
# 返回类型被当成普通函数返回值(实为 boxed 变体构造指针),且实参少一个
|
||
# pool(arity 也不对)。此处与裸名写法同口径补齐,覆盖点号写法。
|
||
if isinstance(Node.func.value, ast.Attribute):
|
||
_rc_attr: str = getattr(Node.func.value, 'attr', '') or ''
|
||
_rc_sym: Any = None
|
||
for _rc_key in (f"{ModulePath}.{_rc_attr}", _rc_attr):
|
||
if _rc_key and self.Trans.SymbolTable.has(_rc_key):
|
||
_rc_sym = self.Trans.SymbolTable[_rc_key]
|
||
break
|
||
if _rc_sym is not None and getattr(_rc_sym, 'IsRenum', False):
|
||
_rc_vars: Any = getattr(_rc_sym, 'RenumVariants', None)
|
||
if _rc_vars and FuncAttr in _rc_vars:
|
||
_rc_tag: int = _rc_vars.index(FuncAttr)
|
||
result = self._HandleREnumConstructLlvm(Node, _rc_attr, FuncAttr, _rc_tag)
|
||
if result is not None:
|
||
return result
|
||
if self.Trans.SymbolTable.has(FuncAttr):
|
||
SymInfo = self.Trans.SymbolTable[FuncAttr]
|
||
if SymInfo.IsStruct:
|
||
if FuncAttr not in Gen.structs:
|
||
self._ensure_struct_declared(FuncAttr, module_sha1=_ctor_module_sha1)
|
||
if FuncAttr in Gen.structs:
|
||
result = self._HandleClassNewLlvm(Node, FuncAttr, module_sha1=_ctor_module_sha1)
|
||
if result is not None:
|
||
return result
|
||
if SymInfo.IsEnumMember and SymInfo.EnumName:
|
||
# When called as module.func(args), check if module.func is a
|
||
# function/variable first. If so, skip REnum construction and
|
||
# let the function call path handle it. This fixes cases where
|
||
# a factory function shares a name with an REnum variant
|
||
# (e.g., llvmlite.Ptr vs LLVMType.Ptr).
|
||
_SkipRenum: bool = False
|
||
if ModulePath:
|
||
_FullKey = f"{ModulePath}.{FuncAttr}"
|
||
_FullSym = self.Trans.SymbolTable.lookup(_FullKey)
|
||
if _FullSym and (_FullSym.IsFunction or _FullSym.IsVariable):
|
||
_SkipRenum = True
|
||
if not _SkipRenum:
|
||
EnumName = SymInfo.EnumName
|
||
if self.Trans.SymbolTable.has(EnumName):
|
||
EnumInfo = self.Trans.SymbolTable[EnumName]
|
||
if EnumInfo.IsRenum:
|
||
result = self._HandleREnumConstructLlvm(Node, EnumName, FuncAttr, SymInfo.value)
|
||
if result is not None:
|
||
return result
|
||
FullAttrKey = f"{ModulePath}.{FuncAttr}"
|
||
if self.Trans.SymbolTable.has(FullAttrKey):
|
||
SymInfo = self.Trans.SymbolTable[FullAttrKey]
|
||
if SymInfo.IsStruct:
|
||
if FuncAttr not in Gen.structs:
|
||
self._ensure_struct_declared(FuncAttr, module_sha1=_ctor_module_sha1)
|
||
if FuncAttr in Gen.structs:
|
||
result = self._HandleClassNewLlvm(Node, FuncAttr, module_sha1=_ctor_module_sha1)
|
||
if result is not None:
|
||
return result
|
||
# 跨模块 REnum 变体构造:FullName 查找(如 LLVMType.Int)
|
||
if SymInfo.IsEnumMember and SymInfo.EnumName:
|
||
EnumName = SymInfo.EnumName
|
||
if self.Trans.SymbolTable.has(EnumName):
|
||
EnumInfo = self.Trans.SymbolTable[EnumName]
|
||
if EnumInfo.IsRenum:
|
||
result = self._HandleREnumConstructLlvm(Node, EnumName, FuncAttr, SymInfo.value)
|
||
if result is not None:
|
||
return result
|
||
# 模块名与类名同名优先规则:`import lib.core.X as X` 且模块内
|
||
# 有同名 class X 时,`X.func()` 应解析为模块函数(mangle
|
||
# {sha1}.func,对应模块级 define)而非类静态方法(mangle
|
||
# {sha1}.X.func——模块函数没有带类名的 define,链接报 undefined
|
||
# symbol,如 CompilerFactory.get_perm_pool)。判断依据:SymbolTable
|
||
# 中 base 名是否注册了 IsModuleAlias(import 处理插入的别名标记)。
|
||
# 类构造调用(X.X(args))不受影响:FuncAttr==类名 时上方 591/639
|
||
# 行的 struct 路径已先行返回。
|
||
_is_mod_alias_base = False
|
||
if isinstance(Node.func.value, ast.Name):
|
||
_base_alias_sym = self.Trans.SymbolTable.lookup(Node.func.value.id)
|
||
if _base_alias_sym is not None and getattr(_base_alias_sym, 'IsModuleAlias', False):
|
||
_is_mod_alias_base = True
|
||
if is_class_name and not _is_mod_alias_base:
|
||
ClassName = Node.func.value.id
|
||
result = self._HandleStaticMethodCallLlvm(Node, ClassName, FuncAttr)
|
||
if result is not None:
|
||
return result
|
||
FullAttrKey = f"{ModulePath}.{FuncAttr}"
|
||
if self.Trans.SymbolTable.has(FullAttrKey):
|
||
SymInfo = self.Trans.SymbolTable[FullAttrKey]
|
||
if SymInfo.IsTypedef:
|
||
return ir.Constant(ir.IntType(32), 0)
|
||
if SymInfo.IsStruct:
|
||
if FuncAttr not in Gen.structs:
|
||
self._ensure_struct_declared(FuncAttr, module_sha1=_ctor_module_sha1)
|
||
if FuncAttr in Gen.structs:
|
||
result = self._HandleClassNewLlvm(Node, FuncAttr, module_sha1=_ctor_module_sha1)
|
||
if result is not None:
|
||
return result
|
||
if FuncAttr in Gen.structs:
|
||
result = self._HandleClassNewLlvm(Node, FuncAttr, module_sha1=_ctor_module_sha1)
|
||
if result is not None:
|
||
return result
|
||
if isinstance(Node.func.value, ast.Attribute):
|
||
inner_attr = Node.func.value.attr
|
||
if inner_attr in Gen.structs or self.Trans.SymbolTable.is_struct(inner_attr):
|
||
static_result = self._HandleStaticMethodCallLlvm(Node, inner_attr, FuncAttr)
|
||
if static_result is not None:
|
||
return static_result
|
||
MethodResult_attr = self._HandleMethodCallLlvm(Node)
|
||
is_zero_attr = isinstance(MethodResult_attr, ir.Constant) and isinstance(MethodResult_attr.type, ir.IntType) and MethodResult_attr.constant == 0
|
||
if MethodResult_attr is not None and not is_zero_attr:
|
||
return MethodResult_attr
|
||
result = self._HandleExternalCallLlvm(Node, FuncAttr, ModulePath)
|
||
if result is not None:
|
||
return result
|
||
MethodResult = self._HandleMethodCallLlvm(Node)
|
||
IsZeroResult = isinstance(MethodResult, ir.Constant) and isinstance(MethodResult.type, ir.IntType) and MethodResult.constant == 0
|
||
if IsZeroResult and FuncAttr is not None:
|
||
mangled_name = Gen._mangle_func_name(FuncAttr, ModulePath if ModulePath else None)
|
||
if Gen._has_function(mangled_name):
|
||
CallArgs = []
|
||
for ArgIdx, arg in enumerate(Node.args, start=1):
|
||
# 禁止静默丢弃求值为空的实参(会导致后续整体前移一格,
|
||
# 报出与真因无关的类型不匹配,见 _RequireArgValue 说明)
|
||
CallArgs.append(self._RequireArgValue(
|
||
self.HandleExprLlvm(arg), FuncAttr, ArgIdx, arg, Node))
|
||
return Gen.builder.call(Gen._get_function(mangled_name), CallArgs, name=f"call_{FuncAttr}")
|
||
if MethodResult is None or IsZeroResult:
|
||
imported = getattr(self.Trans, '_ImportedModules', set())
|
||
ModuleSha1Map = getattr(Gen, 'ModuleSha1Map', {})
|
||
IsKnown = (ModulePath in imported or ModulePath in self.Trans.SymbolTable.import_aliases or
|
||
ModulePath in ModuleSha1Map)
|
||
if not IsKnown and ModulePath and '.' in ModulePath:
|
||
LastPart = ModulePath.split('.')[-1]
|
||
IsKnown = (LastPart in imported or LastPart in self.Trans.SymbolTable.import_aliases or
|
||
LastPart in ModuleSha1Map)
|
||
# 最后尝试: 用 FuncAttr 直接查找 Gen.functions(_find_function 会遍历 SHA1 前缀)
|
||
if FuncAttr and ModulePath:
|
||
# _ctor_module_sha1 已在函数顶部统一获取,此处无需重复
|
||
# 先检查 FuncAttr 是否是函数/变量,如果是则跳过 struct 声明
|
||
_attr_sym = self.Trans.SymbolTable.lookup(FuncAttr)
|
||
_is_func_or_var = _attr_sym and (_attr_sym.IsFunction or _attr_sym.IsVariable)
|
||
if not _is_func_or_var and ModulePath:
|
||
_full_key = f"{ModulePath}.{FuncAttr}"
|
||
_full_sym = self.Trans.SymbolTable.lookup(_full_key)
|
||
if _full_sym and (_full_sym.IsFunction or _full_sym.IsVariable):
|
||
_is_func_or_var = True
|
||
# 优先检查 FuncAttr 是否为 struct/类构造器
|
||
if not _is_func_or_var and FuncAttr not in Gen.structs:
|
||
self._ensure_struct_declared(FuncAttr, module_sha1=_ctor_module_sha1)
|
||
if not _is_func_or_var and FuncAttr in Gen.structs:
|
||
result = self._HandleClassNewLlvm(Node, FuncAttr, module_sha1=_ctor_module_sha1)
|
||
if result is not None:
|
||
return result
|
||
# 检查 FullAttrKey 是否为 struct(如 hashlib.md5)
|
||
if ModulePath:
|
||
FullAttrKey = f"{ModulePath}.{FuncAttr}"
|
||
if self.Trans.SymbolTable.has(FullAttrKey):
|
||
FullSymInfo = self.Trans.SymbolTable[FullAttrKey]
|
||
if FullSymInfo.IsStruct or FullSymInfo.IsCpythonObject:
|
||
if FuncAttr not in Gen.structs:
|
||
self._ensure_struct_declared(FuncAttr, module_sha1=_ctor_module_sha1)
|
||
if FuncAttr in Gen.structs:
|
||
result = self._HandleClassNewLlvm(Node, FuncAttr, module_sha1=_ctor_module_sha1)
|
||
if result is not None:
|
||
return result
|
||
fallback_func = Gen._find_function(FuncAttr)
|
||
if fallback_func is not None:
|
||
CallArgs = []
|
||
for ArgIdx, arg in enumerate(Node.args, start=1):
|
||
# 同 1039:禁止静默丢弃(会导致后续前移一格)
|
||
CallArgs.append(self._RequireArgValue(
|
||
self.HandleExprLlvm(arg), FuncAttr, ArgIdx, arg, Node))
|
||
self._append_eh_msg_out_arg(CallArgs, fallback_func, Gen)
|
||
result = Gen.builder.call(fallback_func, CallArgs, name=f"call_{FuncAttr}")
|
||
return self._check_eh_return(result, FuncAttr, Gen, called_func=fallback_func)
|
||
# 尝试从 stub 按需加载函数声明
|
||
if ModulePath in ModuleSha1Map:
|
||
sha1 = ModuleSha1Map[ModulePath]
|
||
stub_mangled = f"{sha1}.{FuncAttr}"
|
||
try:
|
||
stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(stub_mangled, Gen)
|
||
except Exception:
|
||
stub_func_type = None
|
||
if not stub_func_type:
|
||
try:
|
||
stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(FuncAttr, Gen)
|
||
except Exception:
|
||
stub_func_type = None
|
||
if stub_func_type:
|
||
decl_name = stub_mangled if stub_mangled in getattr(self.Trans.ImportHandler, '_stub_func_cache', {}) else FuncAttr
|
||
func_decl = self.GetOrCreateStubFuncDecl(decl_name, stub_func_type, Gen, alias=FuncAttr)
|
||
CallArgs = []
|
||
for ArgIdx, arg in enumerate(Node.args, start=1):
|
||
# 同 1039:禁止静默丢弃(会导致后续前移一格)
|
||
CallArgs.append(self._RequireArgValue(
|
||
self.HandleExprLlvm(arg), FuncAttr, ArgIdx, arg, Node))
|
||
self._append_eh_msg_out_arg(CallArgs, func_decl, Gen)
|
||
result = Gen.builder.call(func_decl, CallArgs, name=f"call_{FuncAttr}")
|
||
return self._check_eh_return(result, FuncAttr, Gen, called_func=func_decl)
|
||
if ModulePath and IsKnown:
|
||
raise Exception(f"Undefined symbol: '{ModulePath}.{FuncAttr}'")
|
||
if ModulePath and not IsKnown:
|
||
raise Exception(f"Unknown module: '{ModulePath}' (undefined symbol: '{ModulePath}.{FuncAttr}')")
|
||
if not ModulePath and FuncAttr:
|
||
raise Exception(f"Undefined method: '{FuncAttr}'")
|
||
return MethodResult if MethodResult is not None else ir.Constant(ir.IntType(32), 0)
|
||
if isinstance(Node.func, ast.BinOp) and isinstance(Node.func.op, ast.BitOr):
|
||
return self._HandleTypeUnionCastLlvm(Node)
|
||
raise Exception(f"Unsupported call expression")
|
||
|
||
def _ensure_struct_declared(self, class_name: str, module_sha1: str | None = None) -> None:
|
||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||
# 如果名称是函数或变量,不应创建 struct
|
||
SymInfo = self.Trans.SymbolTable.lookup(class_name)
|
||
if SymInfo and (SymInfo.IsFunction or SymInfo.IsVariable):
|
||
return
|
||
# 跨模块类型引用:如果提供了 module_sha1,优先检查带 SHA1 前缀的完整名
|
||
full_key: str | None = f"{module_sha1}.{class_name}" if module_sha1 else None
|
||
if full_key and full_key in Gen.structs:
|
||
existing = Gen.structs[full_key]
|
||
if isinstance(existing, ir.IdentifiedStructType) and (existing.elements is None or len(existing.elements) == 0):
|
||
self.Trans.ImportHandler._TryLoadStructFromStub(class_name, Gen, source_sha1=module_sha1)
|
||
return
|
||
if class_name in Gen.structs:
|
||
existing = Gen.structs[class_name]
|
||
if isinstance(existing, ir.IdentifiedStructType) and (existing.elements is None or len(existing.elements) == 0):
|
||
self.Trans.ImportHandler._TryLoadStructFromStub(class_name, Gen, source_sha1=module_sha1)
|
||
existing = Gen.structs.get(class_name, existing)
|
||
if isinstance(existing, ir.IdentifiedStructType) and existing.elements is not None and len(existing.elements) > 0:
|
||
return
|
||
else:
|
||
# 短名已存在但 SHA1 可能不匹配:如果 module_sha1 与现有 struct 的 SHA1 不一致,
|
||
# 需要用正确的 SHA1 创建独立 struct
|
||
if module_sha1:
|
||
_existing_sha1: str = Gen._extract_struct_sha1(existing)
|
||
if _existing_sha1 and _existing_sha1 != module_sha1:
|
||
# SHA1 不匹配,用正确的 SHA1 创建
|
||
correct_st = Gen._get_or_create_struct(class_name, source_sha1=module_sha1)
|
||
self.Trans.ImportHandler._TryLoadStructFromStub(class_name, Gen, source_sha1=module_sha1)
|
||
return
|
||
SymInfo = self.Trans.SymbolTable.lookup(class_name)
|
||
if SymInfo and SymInfo.Members:
|
||
member_types = []
|
||
if isinstance(SymInfo.Members, dict):
|
||
for member_name, member_info in SymInfo.Members.items():
|
||
if isinstance(member_info, CTypeInfo):
|
||
mt = member_info.ToLLVM(Gen)
|
||
elif isinstance(member_info, str):
|
||
mt = Gen._CType2LLVM(member_info, '*' in member_info)
|
||
else:
|
||
mt = Gen._CType2LLVM(str(member_info) if member_info else 'int', False)
|
||
if isinstance(mt, ir.VoidType):
|
||
mt = ir.IntType(8)
|
||
member_types.append(mt)
|
||
else:
|
||
for item in SymInfo.Members:
|
||
if isinstance(item, (list, tuple)) and len(item) == 2:
|
||
member_name, member_type_str = item
|
||
mt = Gen._CType2LLVM(member_type_str, '*' in member_type_str)
|
||
if isinstance(mt, ir.VoidType):
|
||
mt = ir.IntType(8)
|
||
member_types.append(mt)
|
||
if member_types:
|
||
st = Gen._get_or_create_struct(class_name, source_sha1=module_sha1)
|
||
if isinstance(st, ir.IdentifiedStructType) and (st.elements is None or len(st.elements) == 0):
|
||
st.set_body(*member_types)
|
||
else:
|
||
Gen._get_or_create_struct(class_name, source_sha1=module_sha1)
|
||
else:
|
||
if class_name not in Gen.structs and not (full_key and full_key in Gen.structs):
|
||
self.Trans.ImportHandler._TryLoadStructFromStub(class_name, Gen, source_sha1=module_sha1)
|
||
Gen._get_or_create_struct(class_name, source_sha1=module_sha1)
|
||
|
||
def _HandleStaticMethodCallLlvm(self, Node: ast.Call, ClassName: str, MethodName: str) -> ir.Value | None:
|
||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||
struct_sha1_map = getattr(Gen, '_struct_sha1_map', {})
|
||
class_sha1 = struct_sha1_map.get(ClassName)
|
||
if class_sha1:
|
||
MangledName = f'{class_sha1}.{ClassName}.{MethodName}'
|
||
else:
|
||
MangledName = f'{ClassName}.{MethodName}'
|
||
func = Gen._find_function(MangledName)
|
||
if not func:
|
||
func = Gen._find_function(f'{MangledName}__')
|
||
if not func:
|
||
stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(MangledName, Gen)
|
||
if stub_func_type:
|
||
func = self.GetOrCreateStubFuncDecl(MangledName, stub_func_type, Gen)
|
||
if not func and class_sha1:
|
||
plain_name = f'{ClassName}.{MethodName}'
|
||
stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(plain_name, Gen)
|
||
if stub_func_type:
|
||
func = self.GetOrCreateStubFuncDecl(MangledName, stub_func_type, Gen)
|
||
if not func:
|
||
if ClassName not in Gen.structs:
|
||
self._ensure_struct_declared(ClassName)
|
||
SymInfo = self.LookupFunctionSymbol(MethodName, module_path=ClassName)
|
||
if SymInfo and SymInfo.IsFunction:
|
||
sig = self.BuildLLVMFuncTypeFromSig(SymInfo, Gen)
|
||
if sig is not None:
|
||
ret_type, llvm_param_types, _ = sig
|
||
is_static = FuncMeta.STATIC_METHOD in SymInfo.MetaList
|
||
if ClassName in Gen.structs and not is_static:
|
||
llvm_param_types.insert(0, ir.PointerType(Gen.structs[ClassName]))
|
||
func_type = ir.FunctionType(ret_type, llvm_param_types)
|
||
# 走唯一幂等入口:module.globals 已有同名函数(stub / 调用点先建)
|
||
# 时复用,避免 llvmlite DuplicatedNameError;类型不同则 fail-fast。
|
||
func = Gen._CreateOrReuseFuncDecl(MangledName, func_type)
|
||
# 方法实际定义类(多继承 this 调整用)
|
||
method_anc_st: str | None = None
|
||
# 若 MangledName 只有 stub 声明(无函数体),也走 MRO 回退找定义类方法
|
||
if not func or len(list(func.blocks)) == 0:
|
||
# 多继承:沿 MRO 祖先链查找(先声明父类优先)
|
||
for anc in Gen._get_mro_chain(ClassName)[1:]:
|
||
parent_mangled = Gen._mangle_name(f'{anc}.{MethodName}')
|
||
parent_func = Gen.functions.get(parent_mangled)
|
||
if parent_func:
|
||
func = parent_func
|
||
method_anc_st = anc
|
||
break
|
||
parent_func = Gen._find_function(f'{anc}.{MethodName}')
|
||
if parent_func:
|
||
func = parent_func
|
||
method_anc_st = anc
|
||
break
|
||
if not func:
|
||
return None
|
||
CallArgs = []
|
||
SymInfo = self.LookupFunctionSymbol(MethodName, module_path=ClassName)
|
||
is_static_call = SymInfo is not None and FuncMeta.STATIC_METHOD in SymInfo.MetaList
|
||
is_classmethod_call = SymInfo is not None and FuncMeta.CLASS_METHOD in SymInfo.MetaList
|
||
# @classmethod: 在参数列表前插入 cls(栈上分配的类实例指针)
|
||
if is_classmethod_call and ClassName in Gen.structs:
|
||
ClsPtr = Gen._alloca(Gen.structs[ClassName], name=f"cls_{ClassName}")
|
||
CallArgs.append(ClsPtr)
|
||
# 形参类型下传(窄通道):仅影响 CDefine 常量实参的物化宽度
|
||
# (更宽 ⇒ 升宽物化;更窄 ⇒ fail-fast);非常量实参走原路径。
|
||
_arg_off: int = len(CallArgs)
|
||
for _ai, arg in enumerate(Node.args):
|
||
_pt: ir.Type | None = None
|
||
if func is not None:
|
||
_ft_args: list[ir.Type] = func.function_type.args
|
||
if _ai + _arg_off < len(_ft_args):
|
||
_pt = _ft_args[_ai + _arg_off]
|
||
ArgVal = self.HandleExprLlvm(
|
||
arg, ConstWidthHint=DefineUseWidthFromLLVMType(_pt))
|
||
if ArgVal:
|
||
CallArgs.append(ArgVal)
|
||
if (ClassName not in Gen.class_vtable
|
||
and ClassName not in Gen._cross_module_vtable_classes
|
||
and class_sha1):
|
||
self._try_register_vtable_ondemand(ClassName, class_sha1, Gen)
|
||
# 跨模块多继承:确保 class_parents 可用(MRO 回退需要)。
|
||
# 如 HandlesType 委托调用 Generator 的方法——Generator 定义在
|
||
# 另一模块,class_parents 未随 import 填充,需从 vpi 按需加载。
|
||
self._EnsureClassParentsLoaded(ClassName, Gen)
|
||
if (ClassName in Gen.class_vtable or ClassName in Gen._cross_module_vtable_classes) and ClassName in Gen.class_methods and CallArgs and not is_static_call:
|
||
methods = Gen.class_methods[ClassName]
|
||
if class_sha1:
|
||
FullMethodName = f'{class_sha1}.{ClassName}.{MethodName}'
|
||
else:
|
||
FullMethodName = f'{ClassName}.{MethodName}'
|
||
method_idx = -1
|
||
for mi, mn in enumerate(methods):
|
||
if mn == FullMethodName or mn == MethodName or mn.endswith(f'.{MethodName}'):
|
||
method_idx = mi
|
||
break
|
||
if method_idx >= 0:
|
||
ObjVal = CallArgs[0]
|
||
if self._is_char_pointer(ObjVal):
|
||
if ClassName in Gen.structs:
|
||
ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}_static")
|
||
# 多继承 this 调整(仅调整 self 参数;vtable 槽位读取用原始 ObjVal,
|
||
# 因为 vptr 总在对象首字段,与 VPC _do_virtual_call 一致)
|
||
self_arg_st = self._adjust_this_for_inherited_method(Gen, ObjVal, ClassName, method_anc_st)
|
||
CallArgs[0] = self_arg_st
|
||
VtableSlotPtr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"vtable_slot_{ClassName}_static")
|
||
VtablePtr = Gen._load(VtableSlotPtr, name=f"vtable_ptr_{ClassName}_static")
|
||
VtableArrayType = ir.ArrayType(ir.PointerType(ir.IntType(8)), len(methods))
|
||
VtableTyped = Gen.builder.bitcast(VtablePtr, ir.PointerType(VtableArrayType), name=f"vtable_typed_{ClassName}_static")
|
||
MethodPtrAddr = Gen.builder.gep(VtableTyped, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), method_idx)], name=f"vmethod_ptr_addr_{MethodName}_static")
|
||
MethodPtrI8 = Gen._load(MethodPtrAddr, name=f"vmethod_ptr_{MethodName}_static")
|
||
FuncPtrType = ir.PointerType(func.function_type)
|
||
MethodPtrTyped = Gen.builder.bitcast(MethodPtrI8, FuncPtrType, name=f"vmethod_typed_{MethodName}_static")
|
||
self._fill_default_args(CallArgs, func, FullMethodName)
|
||
self._append_eh_msg_out_arg(CallArgs, func, Gen)
|
||
adjusted = Gen._adjust_args(CallArgs, func)
|
||
result = Gen.builder.call(MethodPtrTyped, adjusted, name=f"vcall_{FullMethodName}")
|
||
self._check_eh_return(result, FullMethodName, Gen, called_func=func)
|
||
return result
|
||
self._append_eh_msg_out_arg(CallArgs, func, Gen)
|
||
# 自动取址已收口到 Gen._adjust_args(唯一汇聚点,按 func.name 查表),
|
||
# 此处的显式取址已删除,避免 'always' 模式被重复应用(不幂等)。
|
||
adjusted = Gen._adjust_args(CallArgs, func)
|
||
result = Gen.builder.call(func, adjusted, name=f"call_{MangledName}")
|
||
self._check_eh_return(result, MangledName, Gen, called_func=func)
|
||
return result
|
||
|
||
def _HandleInstanceCallLlvm(self, Node: ast.Call, VarName: str, ClassName: str) -> ir.Value:
|
||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||
ObjVal = self.HandleExprLlvm(ast.Name(id=VarName, ctx=ast.Load()))
|
||
if not ObjVal:
|
||
raise Exception(f"Cannot evaluate object '{VarName}' for __call__")
|
||
if self._is_char_pointer(ObjVal):
|
||
if ClassName in Gen.structs:
|
||
ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
|
||
CallArgs = [ObjVal]
|
||
CallFuncName = f'{ClassName}.__call__'
|
||
struct_sha1_map = getattr(Gen, '_struct_sha1_map', {})
|
||
class_sha1 = struct_sha1_map.get(ClassName)
|
||
if class_sha1:
|
||
CallFuncName = f'{class_sha1}.{ClassName}.__call__'
|
||
# 形参类型下传(窄通道):仅影响 CDefine 常量实参的物化宽度。
|
||
# CallArgs[0] 为 self ⇒ 第 i 个用户实参对应形参 i+1。
|
||
_cfunc: ir.Function | None = (Gen._get_function(CallFuncName)
|
||
if Gen._has_function(CallFuncName) else None)
|
||
_ptypes: list[ir.Type] = _cfunc.function_type.args if _cfunc is not None else []
|
||
for _ai, arg in enumerate(Node.args):
|
||
_pt: ir.Type | None = _ptypes[_ai + 1] if _ai + 1 < len(_ptypes) else None
|
||
ArgVal = self.HandleExprLlvm(
|
||
arg, ConstWidthHint=DefineUseWidthFromLLVMType(_pt))
|
||
if ArgVal:
|
||
CallArgs.append(ArgVal)
|
||
if not Gen._has_function(CallFuncName):
|
||
raise Exception(f"Class '{ClassName}' has no __call__ method")
|
||
func = Gen._get_function(CallFuncName)
|
||
self._fill_default_args(CallArgs, func, CallFuncName)
|
||
self._ApplyKeywordArgs(Node, CallArgs, func, CallFuncName, self_offset=1)
|
||
self._append_eh_msg_out_arg(CallArgs, func, Gen)
|
||
adjusted = Gen._adjust_args(CallArgs, func)
|
||
result = Gen.builder.call(func, adjusted, name=f"call_{CallFuncName}")
|
||
self._check_eh_return(result, CallFuncName, Gen, called_func=func)
|
||
return result
|
||
|
||
def _make_virtual_attr_call(self, Node: ast.Call, module_name: str, attr_name: str) -> ast.Call:
|
||
virtual_func = ast.Attribute(
|
||
value=ast.Name(id=module_name, ctx=ast.Load()),
|
||
attr=attr_name,
|
||
ctx=ast.Load()
|
||
)
|
||
new_node = ast.Call(
|
||
func=virtual_func,
|
||
args=Node.args,
|
||
keywords=Node.keywords
|
||
)
|
||
ast.copy_location(new_node, Node)
|
||
return new_node
|
||
|
||
def _get_ModulePath(self, node: ast.AST) -> str | None:
|
||
parts = []
|
||
while isinstance(node, ast.Attribute):
|
||
parts.append(node.attr)
|
||
node = node.value
|
||
if isinstance(node, ast.Name):
|
||
parts.append(node.id)
|
||
parts.reverse()
|
||
return '.'.join(parts) if parts else None
|
||
|
||
def _IsModuleQualifiedGlobalChain(self, base_name: str, receiver: ast.AST) -> bool:
|
||
"""判定"模块限定全局变量"接收者链(链根=模块别名、次段=该模块全局变量)。
|
||
|
||
与调用点既有的"链根是已知变量(self / 局部变量 / 全局变量 / struct 变量)"
|
||
判据互补,补的是**模块限定全局变量**这一形态:
|
||
`import lib.core.Gen.GenApi as GenApi` 后写
|
||
`GenApi._g_gen.ClassGenBase._collect_parents(...)`——链根 `GenApi` 是模块
|
||
别名(不在 var_struct_class / variables / global_vars 中),次段 `_g_gen`
|
||
是该模块的全局变量。缺此判定时该接收者被当作"模块.类"引用,落到下方
|
||
`inner_attr in Gen.structs` 分支走 _HandleStaticMethodCallLlvm——该路径按
|
||
静态方法口径处理(**不前置接收者 self**),实参整体错位一格
|
||
(trans: Translator* 对上 max_parents: i32),触发 fail-fast
|
||
"指针类型 ... 不能隐式转换为整数参数 i32";不报错的同形调用(实参全为指针)
|
||
则静默生成缺 self 的错误调用。
|
||
|
||
判据只有两段:链根是模块(SymbolTable.import_aliases / IsModuleAlias 符号 /
|
||
ModuleSha1Map / _ImportedModules 任一命中),且**紧邻根名的那一段属性**不是
|
||
类型/函数类符号(类 / 枚举 / REnum / 枚举成员 / 函数 / CDefine / 异常类 /
|
||
模块别名)——即该段是"对象"(全局变量;跨模块全局在本符号表里登记为
|
||
IsTypedef 的空类型条目,故 IsTypedef 不在排除集内)。紧随段是类
|
||
(`Module.Class.static_method(...)`)时返回 False,静态方法口径保持不变。
|
||
"""
|
||
symbol_table: Any = self.Trans.SymbolTable
|
||
# 紧邻根名的那一段属性:GenApi._g_gen.ClassGenBase → '_g_gen'
|
||
first_attr: str | None = None
|
||
cursor: ast.AST = receiver
|
||
while isinstance(cursor, ast.Attribute):
|
||
first_attr = cursor.attr
|
||
cursor = cursor.value
|
||
if not first_attr or not isinstance(cursor, ast.Name):
|
||
return False
|
||
# 链根是不是模块:优先别名表(import ... as X 的 X → 模块全名),
|
||
# 其次符号表里的模块别名标记,最后模块表(其键含短名)兜底。
|
||
module_path: str = symbol_table.resolve_alias(base_name)
|
||
if module_path != base_name:
|
||
is_module: bool = True
|
||
else:
|
||
alias_entry: Any = symbol_table.lookup(base_name)
|
||
if alias_entry is not None and getattr(alias_entry, 'IsModuleAlias', False):
|
||
module_path = getattr(alias_entry, 'ResolvedModule', '') or ''
|
||
is_module = bool(module_path)
|
||
else:
|
||
is_module = (
|
||
base_name in getattr(self.Trans.LlvmGen, 'ModuleSha1Map', {})
|
||
or base_name in getattr(self.Trans, '_ImportedModules', set()))
|
||
if not is_module:
|
||
return False
|
||
segment: Any = symbol_table.lookup(f'{module_path}.{first_attr}') if module_path else None
|
||
if segment is None:
|
||
segment = symbol_table.lookup(first_attr)
|
||
if segment is None:
|
||
return False
|
||
# 该段是"类型/函数类"符号 ⇒ 属于 `Module.Class...` 引用,不按实例链处理
|
||
# (同名枚举成员/异常类在符号表里与类名冲突,一并排除,避免误判)。
|
||
for _type_flag in ('IsStruct', 'IsEnum', 'IsRenum', 'IsUnion', 'IsEnumMember',
|
||
'IsFunction', 'IsDefine', 'IsExceptionClass', 'IsModuleAlias'):
|
||
if getattr(segment, _type_flag, False):
|
||
return False
|
||
return True
|
||
|
||
def _HandleLLVMIRLlvm(self, Node: ast.Call) -> ir.Value:
|
||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||
if not Node.args:
|
||
return ir.Constant(ir.IntType(32), 0)
|
||
|
||
all_ops = []
|
||
input_ops = []
|
||
output_targets = []
|
||
operand_seq = 0
|
||
|
||
ret_type = ir.IntType(32)
|
||
if len(Node.args) >= 2:
|
||
ret_type_arg = Node.args[1]
|
||
inferred = self.Trans.ExprAsmHandle._infer_expr_llvm_type(ret_type_arg)
|
||
if inferred:
|
||
ret_type = inferred
|
||
|
||
ir_template = ""
|
||
first_arg = Node.args[0]
|
||
|
||
if isinstance(first_arg, ast.JoinedStr):
|
||
parts = []
|
||
for value in first_arg.values:
|
||
if isinstance(value, ast.Constant) and isinstance(value.value, str):
|
||
parts.append(value.value)
|
||
elif isinstance(value, ast.FormattedValue):
|
||
expr = value.value
|
||
# LInp/LOut 与裸名 irinp/irout 等价(见 _intrinsic_marker)
|
||
_marker: str | None = self.Trans.ExprAsmHandle._intrinsic_marker(expr)
|
||
if _marker == 'LInp':
|
||
if expr.args:
|
||
val = self.HandleExprLlvm(expr.args[0])
|
||
if val:
|
||
input_ops.append(val)
|
||
all_ops.append(('inp', len(input_ops) - 1))
|
||
parts.append(f'%__OP{operand_seq}__')
|
||
operand_seq += 1
|
||
elif _marker == 'LOut':
|
||
if expr.args:
|
||
target_ptr = self.Trans.ExprAsmHandle._get_var_ptr_for_asm(expr.args[0])
|
||
if target_ptr:
|
||
val = target_ptr
|
||
else:
|
||
val = self.HandleExprLlvm(expr.args[0])
|
||
if val:
|
||
output_targets.append(val)
|
||
all_ops.append(('out', len(output_targets) - 1))
|
||
parts.append(f'%__OP{operand_seq}__')
|
||
operand_seq += 1
|
||
else:
|
||
# 非标记表达式按普通输入操作数处理
|
||
fallback = self.HandleExprLlvm(expr)
|
||
if fallback:
|
||
input_ops.append(fallback)
|
||
all_ops.append(('inp', len(input_ops) - 1))
|
||
parts.append(f'%__OP{operand_seq}__')
|
||
operand_seq += 1
|
||
ir_template = ''.join(parts)
|
||
elif isinstance(first_arg, ast.Constant) and isinstance(first_arg.value, str):
|
||
ir_template = first_arg.value
|
||
|
||
return self._EmitLLVMIRInstruction(Gen, ir_template, input_ops, output_targets, all_ops, ret_type)
|
||
|
||
def _EmitLLVMIRInstruction(self, Gen: LlvmGeneratorMixin, ir_template: str, input_ops: list[ir.Value], output_targets: list[ir.Value], all_ops: list[tuple], ret_type: ir.Type) -> ir.Value:
|
||
template = ir_template.strip()
|
||
|
||
def resolve_op(idx):
|
||
if idx < len(all_ops):
|
||
kind, local_idx = all_ops[idx]
|
||
if kind == 'inp' and local_idx < len(input_ops):
|
||
return input_ops[local_idx]
|
||
elif kind == 'out' and local_idx < len(output_targets):
|
||
return output_targets[local_idx]
|
||
return None
|
||
|
||
assign_match = _RE_OP_ASSIGN.match(template)
|
||
if assign_match:
|
||
template = assign_match.group(2).strip()
|
||
|
||
binop_map = {
|
||
'add': 'add', 'fadd': 'fadd', 'sub': 'sub', 'fsub': 'fsub',
|
||
'mul': 'mul', 'fmul': 'fmul', 'udiv': 'udiv', 'sdiv': 'sdiv',
|
||
'fdiv': 'fdiv', 'urem': 'urem', 'srem': 'srem', 'frem': 'frem',
|
||
'shl': 'shl', 'lshr': 'lshr', 'ashr': 'ashr',
|
||
'and': 'and_', 'or': 'or_', 'xor': 'xor_',
|
||
}
|
||
|
||
icmp_match = _RE_ICMP.match(template)
|
||
if icmp_match:
|
||
pred: str = icmp_match.group(1)
|
||
op1 = resolve_op(int(icmp_match.group(3)))
|
||
op2 = resolve_op(int(icmp_match.group(4)))
|
||
if op1 and op2:
|
||
# LLVM IR 谓词(eq/ne/sgt/sge/slt/sle/ugt/uge/ult/ule)映射到 llvmlite
|
||
# llvmlite 的 icmp_signed/icmp_unsigned 只接受 '=='/'!='/'<'/'<='/'>'/>='
|
||
_ICMP_PRED_MAP: dict[str, tuple[str, str]] = {
|
||
'eq': ('==', 'signed'), 'ne': ('!=', 'signed'),
|
||
'sgt': ('>', 'signed'), 'sge': ('>=', 'signed'),
|
||
'slt': ('<', 'signed'), 'sle': ('<=', 'signed'),
|
||
'ugt': ('>', 'unsigned'), 'uge': ('>=', 'unsigned'),
|
||
'ult': ('<', 'unsigned'), 'ule': ('<=', 'unsigned'),
|
||
}
|
||
pred_info: tuple[str, str] | None = _ICMP_PRED_MAP.get(pred)
|
||
if pred_info:
|
||
llvmlite_pred: str
|
||
cmp_kind: str
|
||
llvmlite_pred, cmp_kind = pred_info
|
||
icmp_method: Any = Gen.builder.icmp_signed if cmp_kind == 'signed' else Gen.builder.icmp_unsigned
|
||
result = icmp_method(llvmlite_pred, op1, op2, name="llvmir_result")
|
||
return self._StoreLLVMIROutputs(Gen, result, output_targets)
|
||
|
||
fcmp_match = _RE_FCMP.match(template)
|
||
if fcmp_match:
|
||
pred_raw: str = fcmp_match.group(1).strip()
|
||
# 分离 fast 修饰符(可能是 "oeq fast" 或 "fast oeq")
|
||
is_fast: bool = 'fast' in pred_raw
|
||
pred: str = pred_raw.replace('fast', '').strip()
|
||
op1 = resolve_op(int(fcmp_match.group(3)))
|
||
op2 = resolve_op(int(fcmp_match.group(4)))
|
||
if op1 and op2:
|
||
# LLVM IR fcmp 谓词(oeq/ogt/olt/ord/uno/ueq 等)映射到 llvmlite
|
||
_FCMP_PRED_MAP: dict[str, tuple[str, str]] = {
|
||
'oeq': ('==', 'ordered'), 'ogt': ('>', 'ordered'),
|
||
'oge': ('>=', 'ordered'), 'olt': ('<', 'ordered'),
|
||
'ole': ('<=', 'ordered'), 'one': ('!=', 'ordered'),
|
||
'ord': ('ord', 'ordered'), 'uno': ('uno', 'unordered'),
|
||
'ueq': ('==', 'unordered'), 'ugt': ('>', 'unordered'),
|
||
'uge': ('>=', 'unordered'), 'ult': ('<', 'unordered'),
|
||
'ule': ('<=', 'unordered'), 'une': ('!=', 'unordered'),
|
||
}
|
||
fcmp_info: tuple[str, str] | None = _FCMP_PRED_MAP.get(pred)
|
||
if fcmp_info:
|
||
llvmlite_pred: str
|
||
cmp_kind: str
|
||
llvmlite_pred, cmp_kind = fcmp_info
|
||
fcmp_method: Any = Gen.builder.fcmp_ordered if cmp_kind == 'ordered' else Gen.builder.fcmp_unordered
|
||
result = fcmp_method(llvmlite_pred, op1, op2, name="llvmir_result")
|
||
return self._StoreLLVMIROutputs(Gen, result, output_targets)
|
||
|
||
for op_name, method_name in binop_map.items():
|
||
pattern = re.compile(
|
||
rf'{op_name}\s+(\w+)\s+%__OP(\d+)__,\s*%__OP(\d+)__',
|
||
re.IGNORECASE if op_name in ('and', 'or', 'xor') else 0
|
||
)
|
||
m = pattern.match(template)
|
||
if m:
|
||
op1 = resolve_op(int(m.group(2)))
|
||
op2 = resolve_op(int(m.group(3)))
|
||
if op1 and op2:
|
||
method = getattr(Gen.builder, method_name, None)
|
||
if method:
|
||
result = method(op1, op2, name="llvmir_result")
|
||
return self._StoreLLVMIROutputs(Gen, result, output_targets)
|
||
|
||
select_match = _RE_SELECT.match(template)
|
||
if select_match:
|
||
cond = resolve_op(int(select_match.group(1)))
|
||
true_val = resolve_op(int(select_match.group(3)))
|
||
false_val = resolve_op(int(select_match.group(5)))
|
||
if cond and true_val and false_val:
|
||
result = Gen.builder.select(cond, true_val, false_val, name="llvmir_result")
|
||
return self._StoreLLVMIROutputs(Gen, result, output_targets)
|
||
|
||
cast_map = {
|
||
'zext': 'zext', 'sext': 'sext', 'trunc': 'trunc',
|
||
'bitcast': 'bitcast', 'inttoptr': 'inttoptr', 'ptrtoint': 'ptrtoint',
|
||
'uitofp': 'uitofp', 'sitofp': 'sitofp', 'fptoui': 'fptoui', 'fptosi': 'fptosi',
|
||
'fpext': 'fpext', 'fptrunc': 'fptrunc',
|
||
}
|
||
for op_name, method_name in cast_map.items():
|
||
pattern = re.compile(rf'{op_name}\s+(\w+)\s+%__OP(\d+)__\s+to\s+(\w+)')
|
||
m = pattern.match(template)
|
||
if m:
|
||
src_val = resolve_op(int(m.group(2)))
|
||
dest_type_str = m.group(3)
|
||
dest_type = self._ParseLLVMType(Gen, dest_type_str)
|
||
if src_val and dest_type:
|
||
method = getattr(Gen.builder, method_name, None)
|
||
if method:
|
||
result = method(src_val, dest_type, name="llvmir_result")
|
||
return self._StoreLLVMIROutputs(Gen, result, output_targets)
|
||
|
||
Load_match = _RE_LOAD.match(template)
|
||
if Load_match:
|
||
ptr_val = resolve_op(int(Load_match.group(3)))
|
||
if ptr_val:
|
||
result = Gen.builder.load(ptr_val, name="llvmir_result")
|
||
return self._StoreLLVMIROutputs(Gen, result, output_targets)
|
||
|
||
store_match = _RE_STORE.match(template)
|
||
if store_match:
|
||
val = resolve_op(int(store_match.group(2)))
|
||
ptr = resolve_op(int(store_match.group(4)))
|
||
if val and ptr:
|
||
Gen.builder.store(val, ptr)
|
||
return ir.Constant(ir.IntType(32), 0)
|
||
|
||
gep_match = _RE_GEP.match(template)
|
||
if gep_match:
|
||
ptr_val = resolve_op(int(gep_match.group(3)))
|
||
indices_str = gep_match.group(4)
|
||
if ptr_val:
|
||
indices = []
|
||
for idx_part in _RE_COMMA_WS.split(indices_str):
|
||
idx_part = idx_part.strip()
|
||
idx_m = _RE_OP_REF.match(idx_part)
|
||
if idx_m:
|
||
idx_op = resolve_op(int(idx_m.group(1)))
|
||
if idx_op:
|
||
indices.append(idx_op)
|
||
else:
|
||
try:
|
||
indices.append(ir.Constant(ir.IntType(32), int(idx_part)))
|
||
except ValueError:
|
||
break
|
||
if indices:
|
||
result = Gen.builder.gep(ptr_val, indices, name="llvmir_result")
|
||
return self._StoreLLVMIROutputs(Gen, result, output_targets)
|
||
|
||
neg_match = _RE_NEG.match(template)
|
||
if neg_match:
|
||
op = resolve_op(int(neg_match.group(3)))
|
||
if op:
|
||
zero = ir.Constant(op.type, int(neg_match.group(2)))
|
||
result = Gen.builder.sub(zero, op, name="llvmir_result")
|
||
return self._StoreLLVMIROutputs(Gen, result, output_targets)
|
||
|
||
not_match = _RE_NOT.match(template)
|
||
if not_match:
|
||
op = resolve_op(int(not_match.group(3)))
|
||
if op:
|
||
mask = ir.Constant(op.type, int(not_match.group(2)))
|
||
result = Gen.builder.xor_(op, mask, name="llvmir_result")
|
||
return self._StoreLLVMIROutputs(Gen, result, output_targets)
|
||
|
||
call_match = _RE_CALL.match(template)
|
||
if call_match:
|
||
call_ret_str = call_match.group(1)
|
||
func_name = call_match.group(2)
|
||
args_str = call_match.group(3)
|
||
call_args = []
|
||
for arg_part in _RE_COMMA_WS.split(args_str):
|
||
arg_part = arg_part.strip()
|
||
typed_op = _RE_TYPED_OP.match(arg_part)
|
||
if typed_op:
|
||
expected_type_str = typed_op.group(1)
|
||
op_idx = int(typed_op.group(2))
|
||
val = resolve_op(op_idx)
|
||
if val:
|
||
val = self._ConvertLLVMIRType(Gen, val, expected_type_str)
|
||
if val:
|
||
call_args.append(val)
|
||
else:
|
||
const_m = _RE_CONST.match(arg_part)
|
||
if const_m:
|
||
const_type = self._ParseLLVMType(Gen, const_m.group(1))
|
||
if const_type:
|
||
call_args.append(ir.Constant(const_type, int(const_m.group(2))))
|
||
if call_args:
|
||
call_ret_type = self._ParseLLVMType(Gen, call_ret_str) or ir.VoidType()
|
||
func_type = ir.FunctionType(call_ret_type, [a.type for a in call_args])
|
||
if func_name.startswith('llvm.'):
|
||
existing = Gen.module.globals.get(func_name)
|
||
if existing:
|
||
func = existing
|
||
else:
|
||
try:
|
||
func = Gen.module.declare_intrinsic(func_name, [a.type for a in call_args])
|
||
except Exception:
|
||
func = Gen._CreateOrReuseFuncDecl(func_name, func_type)
|
||
else:
|
||
existing = Gen.module.globals.get(func_name)
|
||
if existing:
|
||
func = existing
|
||
else:
|
||
func = Gen._CreateOrReuseFuncDecl(func_name, func_type)
|
||
result = Gen.builder.call(func, call_args, name="llvmir_result")
|
||
if output_targets:
|
||
return self._StoreLLVMIROutputs(Gen, result, output_targets)
|
||
if isinstance(call_ret_type, ir.VoidType):
|
||
return ir.Constant(ir.IntType(32), 0)
|
||
return result
|
||
|
||
if output_targets:
|
||
for i, target in enumerate(output_targets):
|
||
if isinstance(target, ir.AllocaInstr):
|
||
Gen.builder.store(ir.Constant(target.type.pointee, 0), target)
|
||
return ir.Constant(ir.IntType(32), 0)
|
||
|
||
return ir.Constant(ret_type, 0)
|
||
|
||
def _StoreLLVMIROutputs(self, Gen: LlvmGeneratorMixin, result: ir.Value, output_targets: list[ir.Value]) -> ir.Value:
|
||
for target in output_targets:
|
||
if isinstance(target, ir.AllocaInstr):
|
||
if target.type.pointee == result.type:
|
||
Gen.builder.store(result, target)
|
||
else:
|
||
i64t = ir.IntType(64)
|
||
if isinstance(result.type, ir.IntType) and result.type.width == 64 and isinstance(target.type.pointee, ir.PointerType):
|
||
ptr_val = Gen.builder.inttoptr(result, target.type.pointee)
|
||
Gen.builder.store(ptr_val, target)
|
||
elif isinstance(result.type, ir.PointerType) and isinstance(target.type.pointee, ir.IntType) and target.type.pointee.width == 64:
|
||
int_val = Gen.builder.ptrtoint(result, i64t)
|
||
Gen.builder.store(int_val, target)
|
||
else:
|
||
try:
|
||
cast_val = Gen.builder.bitcast(result, target.type.pointee)
|
||
Gen.builder.store(cast_val, target)
|
||
except Exception:
|
||
Gen.builder.store(result, target)
|
||
elif isinstance(target, (ir.GlobalVariable, ir.GEPInstr)):
|
||
if isinstance(target.type, ir.PointerType):
|
||
if target.type.pointee == result.type:
|
||
Gen.builder.store(result, target)
|
||
else:
|
||
try:
|
||
cast_val = Gen.builder.bitcast(result, target.type.pointee)
|
||
Gen.builder.store(cast_val, target)
|
||
except Exception:
|
||
Gen.builder.store(result, target)
|
||
return result
|
||
|
||
def _ParseLLVMType(self, Gen: LlvmGeneratorMixin, type_str: str) -> ir.Type | None:
|
||
type_map = {
|
||
'i1': ir.IntType(1), 'i8': ir.IntType(8), 'i16': ir.IntType(16),
|
||
'i32': ir.IntType(32), 'i64': ir.IntType(64), 'i128': ir.IntType(128),
|
||
'float': ir.FloatType(), 'double': ir.DoubleType(),
|
||
'void': ir.VoidType(),
|
||
}
|
||
if type_str in type_map:
|
||
return type_map[type_str]
|
||
if type_str.endswith('*'):
|
||
pointee = self._ParseLLVMType(Gen, type_str[:-1])
|
||
if pointee:
|
||
return ir.PointerType(pointee)
|
||
return None
|
||
|
||
def _ConvertLLVMIRType(self, Gen: LlvmGeneratorMixin, val: ir.Value, expected_type_str: str) -> ir.Value | None:
|
||
expected_type = self._ParseLLVMType(Gen, expected_type_str.rstrip('*'))
|
||
if not expected_type:
|
||
return val
|
||
IsPtr = expected_type_str.endswith('*')
|
||
if IsPtr:
|
||
expected_ptr_type = ir.PointerType(expected_type)
|
||
if isinstance(val.type, ir.PointerType) and val.type != expected_ptr_type:
|
||
try:
|
||
return Gen.builder.bitcast(val, expected_ptr_type)
|
||
except Exception:
|
||
return val
|
||
elif isinstance(val.type, ir.IntType) and val.type.width == 64:
|
||
try:
|
||
return Gen.builder.inttoptr(val, expected_ptr_type)
|
||
except Exception:
|
||
return val
|
||
return val
|
||
if val.type == expected_type:
|
||
return val
|
||
if isinstance(val.type, ir.IntType) and isinstance(expected_type, ir.IntType):
|
||
if expected_type.width < val.type.width:
|
||
return Gen.builder.trunc(val, expected_type)
|
||
else:
|
||
# 整型加宽必须**保符号**(i32/i64 按有符号语义):此前一律 zext,会把负值
|
||
# 当无符号处理。现场:`int64(-1)` 里 `-1` 的 i32 位型被 zext 成 4294967295
|
||
# ⇒ `x ^ int64(-1)` 变号 ⇒ IntWidthTest Test 5 第三条(循环不收敛)FAIL。
|
||
return Gen.builder.sext(val, expected_type)
|
||
if isinstance(val.type, ir.PointerType) and isinstance(expected_type, ir.IntType):
|
||
if expected_type.width == 64:
|
||
return Gen.builder.ptrtoint(val, expected_type)
|
||
if isinstance(val.type, ir.IntType) and isinstance(expected_type, ir.PointerType):
|
||
if val.type.width == 64:
|
||
return Gen.builder.inttoptr(val, expected_type)
|
||
return val
|
||
|
||
def _HandleExternalCallLlvm(self, Node: ast.Call, func_name: str, ModulePath: str | None) -> ir.Value | None:
|
||
Gen = self.Trans.LlvmGen
|
||
|
||
# 解析 import 别名: 如 window -> vpsdk.window
|
||
if ModulePath:
|
||
ModulePath = self.Trans.SymbolTable.resolve_alias(ModulePath)
|
||
|
||
is_user_module = (ModulePath and
|
||
(ModulePath in Gen.ModuleSha1Map or
|
||
ModulePath in getattr(self.Trans, '_ImportedModules', set()) or
|
||
ModulePath in self.Trans.SymbolTable.import_aliases))
|
||
if ModulePath and not is_user_module:
|
||
is_user_module = (ModulePath in Gen.ModuleSha1Map or
|
||
ModulePath.split('.')[-1] in Gen.ModuleSha1Map or
|
||
ModulePath.split('.')[-1] in getattr(self.Trans, '_ImportedModules', set()))
|
||
if is_user_module and ModulePath not in Gen.ModuleSha1Map and ModulePath not in getattr(self.Trans, '_ImportedModules', set()):
|
||
ModulePath = ModulePath.split('.')[-1]
|
||
|
||
# 模块别名识别:`import lib.core.X as X`(模块内有同名类时,类名会
|
||
# 注册进 SymbolTable 遮蔽模块判定——如 CompilerFactory 模块 + 同名类)。
|
||
# import 处理(HandlesImports._EmitImportDeclarationsLlvm)在 SymbolTable
|
||
# 插入了 IsModuleAlias 的 AliasInfo,据此识别并补全完整路径,使
|
||
# `X.get_perm_pool()` 正确解析为模块函数({sha1}.get_perm_pool)而非
|
||
# 类方法({sha1}.X.get_perm_pool,链接 undefined symbol)。
|
||
if ModulePath and not is_user_module:
|
||
_al_last = ModulePath.split('.')[-1]
|
||
_al_sym = self.Trans.SymbolTable.lookup(_al_last)
|
||
if _al_sym and getattr(_al_sym, 'IsModuleAlias', False):
|
||
is_user_module = True
|
||
if ModulePath in self.Trans.SymbolTable.import_aliases:
|
||
ModulePath = self.Trans.SymbolTable.import_aliases[ModulePath]
|
||
# 未命中模块别名时不截断:保持 is_user_module=False 走下方裸名回退
|
||
|
||
if is_user_module:
|
||
mangled_name = Gen._mangle_func_name(func_name, ModulePath)
|
||
sym_info = self.LookupFunctionSymbol(func_name, module_path=ModulePath)
|
||
is_inline = sym_info and (sym_info.IsInline or isinstance(sym_info.Storage, TypeSystem.CInline))
|
||
if is_inline and sym_info.InlineBody:
|
||
self._HandleInlineExpandLlvm(Node, sym_info)
|
||
return ir.Constant(ir.IntType(32), 1)
|
||
sym_info_exact = self.Trans.SymbolTable.lookup(f'{ModulePath}.{func_name}')
|
||
if sym_info_exact:
|
||
exact_params = sym_info_exact.FuncPtrParams
|
||
exact_param_names = [pn for pn, _ in exact_params]
|
||
# stub/LLVM 侧形参名多为 arg0/arg1 占位(SymbolTable._InsertFuncSymbol),
|
||
# 用它们无法把命名实参 `f(cap = 8, x = 1)` 绑到正确位置,会误报"缺少必需
|
||
# 参数"。优先替换为源码/vpi 扫描得到的语义参数名(长度一致才替换,
|
||
# 避免 shape 不符时错配)。
|
||
semantic_names = (self._LookupGlobalParamNames(mangled_name)
|
||
or self._LookupGlobalParamNames(func_name))
|
||
if semantic_names and len(semantic_names) == len(exact_param_names):
|
||
exact_param_names = semantic_names
|
||
if exact_param_names:
|
||
provided = len(Node.args)
|
||
kw_provided = set()
|
||
for kw in Node.keywords:
|
||
if kw.arg and kw.arg in exact_param_names:
|
||
kw_provided.add(exact_param_names.index(kw.arg))
|
||
# 获取默认参数信息,计算必需参数数量(与 _fill_default_args 一致的查找逻辑)
|
||
func_defaults: list | None = self._LookupGlobalDefaults(mangled_name)
|
||
if func_defaults is None:
|
||
func_defaults = self._LookupGlobalDefaults(func_name)
|
||
total_params: int = len(exact_param_names)
|
||
if func_defaults is None:
|
||
# 默认参数信息缺失(跨模块 stub 加载:vpi/stub 只含参数
|
||
# 类型不含默认值;或并行编译时序导致定义模块的默认参数
|
||
# 尚未注册到共享表)→ 无法准确计算必需参数数量,
|
||
# 跳过严格检查避免误报(如 HandlesType.fatal_error 的
|
||
# err_type/col_start/col_end 默认值未同步时误报"缺 arg3")。
|
||
# 同文件函数的参数检查由 FunctionDef 路径(L1983)覆盖。
|
||
pass
|
||
elif len(func_defaults) > total_params:
|
||
# 表里的条目与当前函数长度不符(同名不同模块)→ 不做严格检查
|
||
pass
|
||
else:
|
||
num_defaults: int = len(func_defaults)
|
||
min_args: int = total_params - num_defaults
|
||
# 只检查必需参数(有默认值的参数允许缺失)
|
||
for i in range(min_args):
|
||
if i >= provided and i not in kw_provided:
|
||
raise Exception(f"调用 {ModulePath}.{func_name}() 缺少必需参数 '{exact_param_names[i]}',该参数没有默认值")
|
||
elif ModulePath in Gen.ModuleSha1Map and len(Node.args) == 0:
|
||
func = Gen.functions.get(mangled_name)
|
||
if func and len(func.function_type.args) > 0:
|
||
raise Exception(f"调用 {ModulePath}.{func_name}() 缺少必需参数,函数需要 {len(func.function_type.args)} 个参数但未传入任何参数")
|
||
if Gen._has_function(mangled_name):
|
||
return self._HandleClosureCallLlvm(Node, mangled_name)
|
||
try:
|
||
stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(mangled_name, Gen)
|
||
except Exception:
|
||
stub_func_type = None
|
||
if not stub_func_type and mangled_name != func_name:
|
||
try:
|
||
stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(func_name, Gen)
|
||
except Exception:
|
||
stub_func_type = None
|
||
if stub_func_type:
|
||
if is_user_module:
|
||
decl_name = mangled_name
|
||
else:
|
||
decl_name = mangled_name if mangled_name in self.Trans.ImportHandler._stub_func_cache else func_name
|
||
self.GetOrCreateStubFuncDecl(decl_name, stub_func_type, Gen, alias=func_name)
|
||
return self._HandleClosureCallLlvm(Node, decl_name)
|
||
sym_info = self.LookupFunctionSymbol(func_name, module_path=ModulePath)
|
||
if sym_info:
|
||
sig = self.BuildLLVMFuncTypeFromSig(sym_info, Gen, mangled_name=mangled_name, use_infer_fallback=True)
|
||
if sig is not None:
|
||
ret_type, llvm_param_types, sym_is_variadic = sig
|
||
self.GetOrCreateFuncDecl(mangled_name, ret_type, llvm_param_types, Gen,
|
||
is_variadic=sym_is_variadic, replace_name=func_name)
|
||
return self._HandleClosureCallLlvm(Node, mangled_name)
|
||
# 回退: 直接用 func_name 查找(_find_function 会遍历 SHA1 前缀)
|
||
fallback_func = Gen._find_function(func_name)
|
||
if fallback_func is not None:
|
||
return self._HandleClosureCallLlvm(Node, func_name)
|
||
return None
|
||
|
||
win32_apis = {
|
||
'SetConsoleOutputCP': (ir.IntType(32), [ir.IntType(32)]),
|
||
'SetConsoleCP': (ir.IntType(32), [ir.IntType(32)]),
|
||
'GetConsoleOutputCP': (ir.IntType(32), []),
|
||
'GetConsoleCP': (ir.IntType(32), []),
|
||
}
|
||
if ModulePath and 'win32console' in ModulePath and func_name in win32_apis:
|
||
ret_type, param_types = win32_apis[func_name]
|
||
if func_name not in Gen.functions:
|
||
# module.globals 已有同名声明(其它路径/依赖 stub 先建)→ 直接登记复用,
|
||
# 不重建(llvmlite NameScope 按名字去重,重建必抛 DuplicatedNameError)
|
||
g_ex_w32: Any = Gen.module.globals.get(func_name)
|
||
if g_ex_w32 is not None:
|
||
Gen.functions[func_name] = g_ex_w32
|
||
else:
|
||
func_type = ir.FunctionType(ret_type, param_types)
|
||
func_decl = Gen._CreateOrReuseFuncDecl(func_name, func_type)
|
||
func_decl.linkage = 'external'
|
||
Gen.functions[func_name] = func_decl
|
||
call_args = []
|
||
if Node.args:
|
||
arg_val = self.HandleExprLlvm(Node.args[0])
|
||
if arg_val:
|
||
target_type = param_types[0] if param_types else ir.IntType(32)
|
||
if isinstance(arg_val.type, ir.IntType) and arg_val.type.width < target_type.width:
|
||
arg_val = Gen.builder.zext(arg_val, target_type, name="zext_win32_arg")
|
||
elif isinstance(arg_val.type, ir.IntType) and arg_val.type.width > target_type.width:
|
||
arg_val = Gen.builder.trunc(arg_val, target_type, name="trunc_win32_arg")
|
||
call_args.append(arg_val)
|
||
return Gen.builder.call(Gen.functions[func_name], call_args, name=f"call_{func_name}")
|
||
|
||
if Gen._has_function(func_name):
|
||
return self._HandleClosureCallLlvm(Node, func_name)
|
||
|
||
if func_name in self.Trans.FunctionDefCache:
|
||
return self._HandleClosureCallLlvm(Node, func_name)
|
||
|
||
if func_name in self._C_LIB_FUNCS:
|
||
return self._HandleClosureCallLlvm(Node, func_name)
|
||
|
||
mangled_name = Gen._mangle_func_name(func_name, ModulePath)
|
||
try:
|
||
stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(mangled_name, Gen)
|
||
except Exception:
|
||
stub_func_type = None
|
||
if not stub_func_type and mangled_name != func_name:
|
||
try:
|
||
stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(func_name, Gen)
|
||
except Exception:
|
||
stub_func_type = None
|
||
if stub_func_type:
|
||
decl_name = mangled_name if mangled_name in self.Trans.ImportHandler._stub_func_cache else func_name
|
||
self.GetOrCreateStubFuncDecl(decl_name, stub_func_type, Gen, alias=func_name, check_existing=False)
|
||
return self._HandleClosureCallLlvm(Node, decl_name)
|
||
|
||
sym_info = self.LookupFunctionSymbol(func_name, module_path=ModulePath or None)
|
||
if sym_info:
|
||
sig = self.BuildLLVMFuncTypeFromSig(sym_info, Gen)
|
||
if sig is not None:
|
||
ret_type, llvm_param_types, sym_is_variadic = sig
|
||
mangled_name = Gen._mangle_func_name(func_name, ModulePath)
|
||
self.GetOrCreateFuncDecl(mangled_name, ret_type, llvm_param_types, Gen,
|
||
is_variadic=sym_is_variadic, replace_name=func_name)
|
||
return self._HandleClosureCallLlvm(Node, mangled_name)
|
||
|
||
return None
|
||
|
||
def _HandleTypeUnionCastLlvm(self, Node: ast.Call) -> ir.Value | None:
|
||
Gen = self.Trans.LlvmGen
|
||
if not Node.args:
|
||
return None
|
||
type_info = None
|
||
MergeException = None
|
||
try:
|
||
type_info = getattr(self.Trans, 'TypeMergeHandler', None) and self.Trans.TypeMergeHandler.MergeTypes(Node.func)
|
||
except Exception as _e:
|
||
MergeException = _e
|
||
if _config_mode == "strict":
|
||
raise
|
||
_vlog().warning(f"解析类型失败: {_e}", "Exception")
|
||
if isinstance(type_info, CTypeInfo):
|
||
# 主路径:MergeTypes 成功返回 CTypeInfo,沿用原有逻辑生成类型字符串
|
||
target_type_str = type_info.ToString()
|
||
IsPtr = type_info.IsPtr
|
||
if IsPtr and target_type_str and '*' not in target_type_str:
|
||
target_type_str += ' *'
|
||
if not target_type_str:
|
||
# Fallback:ToString 返回空字符串时,尝试手动从 BinOp 提取类型字符串
|
||
_vlog().warning(
|
||
f"_HandleTypeUnionCastLlvm: ToString 返回空字符串,启用 fallback 手动解析 "
|
||
f"(type_info={type_info!r})"
|
||
)
|
||
target_type_str = self._ExtractTypeStrFromUnionBinOp(Node.func)
|
||
if target_type_str and type_info.IsPtr and not IsPtr:
|
||
if '*' not in target_type_str:
|
||
target_type_str += ' *'
|
||
if isinstance(type_info.Storage, TypeSystem.CExport) or isinstance(type_info.Storage, TypeSystem.CExtern):
|
||
pass
|
||
if type_info.IsState:
|
||
Gen._export_funcs.add('_type_union_cast')
|
||
else:
|
||
# Fallback 路径:MergeTypes 失败(返回 None 或抛异常)时,手动从 BinOp 提取类型信息
|
||
# 处理 (BaseType | CPtr) 这种模式,手动解析为 "{BaseType} *"
|
||
_vlog().warning(
|
||
f"_HandleTypeUnionCastLlvm: MergeTypes 未返回 CTypeInfo "
|
||
f"(type_info={type_info!r}, exception={MergeException!r}),启用 fallback 手动解析"
|
||
)
|
||
target_type_str = self._ExtractTypeStrFromUnionBinOp(Node.func)
|
||
if not target_type_str:
|
||
# fail-fast(原为 _vlog().warning + return None):
|
||
# `(T | CPtr)(x)` 只可能来自指针强转——parser 把 `(T*)x` / `(T*)(x)` /
|
||
# `T*(x)`(含 `**`)统一产成 func = `T | CPtr` 的 Call(见
|
||
# vast/ExprParser._ConsumePtrSuffixCall、vast_c.c ConsumePtrSuffixCall)。
|
||
# 该形态必须有值产出;返回 None 会让调用方把整条表达式当"编译期求值为空"
|
||
# 丢掉(现场:ViperC ExprGenBase.vp:360 `v = (ast.Expr*(node)).value`
|
||
# → TPC 报"赋值表达式 'value'(Attribute 形态)编译期求值为空",而同函数
|
||
# 前三条 `(ast.Assign/AnnAssign/AugAssign*(node)).value` 同款写法正常)。
|
||
# 故把"哪一步没解析出目标类型"逐项摊开,而不是静默丢弃整条表达式。
|
||
from lib.core.LLVMCG.FuncGen import FailFastError
|
||
raise FailFastError(self._DescribeUnionCastFailure(
|
||
Node, Gen, type_info, MergeException, target_type_str))
|
||
return self._HandleTypeCastLlvm(Node.args[0], target_type_str)
|
||
|
||
def _DescribeUnionCastFailure(self, Node: ast.Call, Gen: Any, TypeInfo: Any,
|
||
MergeException: Any, TargetStr: Any) -> str:
|
||
"""联合类型强转目标类型解析失败时的判定依据(逐项列出,供 fail-fast 报文)。
|
||
|
||
只做取证,不做类型解析:把 MergeTypes / _ExtractTypeStrFromUnionBinOp 的
|
||
返回值、异常,以及联合中每个操作数在符号表与类登记表(Gen.structs /
|
||
_struct_sha1_map / class_sha1_map)里的命中情况全部列出,使"是基座类名
|
||
没被当成类"还是"CPtr 标记侧解析失败"一眼可分。
|
||
"""
|
||
_Flat: list = []
|
||
|
||
def _Collect(n: ast.AST) -> None:
|
||
if isinstance(n, ast.BinOp) and isinstance(n.op, ast.BitOr):
|
||
_Collect(n.left)
|
||
_Collect(n.right)
|
||
else:
|
||
_Flat.append(n)
|
||
|
||
_Collect(Node.func)
|
||
_Operands: list[str] = []
|
||
for _op in _Flat:
|
||
_short: str = ''
|
||
_full: str = ''
|
||
if isinstance(_op, ast.Attribute):
|
||
_short = _op.attr
|
||
_cur: ast.AST = _op.value
|
||
while isinstance(_cur, ast.Attribute):
|
||
_cur = _cur.value
|
||
_full = f"{_cur.id}.{_short}" if isinstance(_cur, ast.Name) else _short
|
||
elif isinstance(_op, ast.Name):
|
||
_short = _op.id
|
||
_full = _short
|
||
else:
|
||
_Operands.append(f"<{type(_op).__name__}>(非类型名形态)")
|
||
continue
|
||
_sym: Any = None
|
||
try:
|
||
_sym = self.Trans.SymbolTable.lookup(_short)
|
||
except Exception:
|
||
_sym = None
|
||
_verdict: str = '符号表未命中'
|
||
if _sym is not None:
|
||
_verdict = (f"IsStruct={getattr(_sym, 'IsStruct', None)}"
|
||
f" IsRenum={getattr(_sym, 'IsRenum', None)}"
|
||
f" IsEnum={getattr(_sym, 'IsEnum', None)}"
|
||
f" IsEnumMember={getattr(_sym, 'IsEnumMember', None)}"
|
||
f" IsTypedef={getattr(_sym, 'IsTypedef', None)}"
|
||
f" Name={getattr(_sym, 'Name', None)!r}")
|
||
_Operands.append(
|
||
f"{_full}({_verdict};in structs={_short in Gen.structs}"
|
||
f";structs 同短名键={[k for k in Gen.structs if k.split('.')[-1] == _short][:4]}"
|
||
f";_struct_sha1_map={getattr(Gen, '_struct_sha1_map', {}).get(_short)!r}"
|
||
f";class_sha1_map={getattr(Gen, 'class_sha1_map', {}).get(_short)!r})")
|
||
|
||
_ToStr: str = '<非 CTypeInfo>'
|
||
try:
|
||
if isinstance(TypeInfo, CTypeInfo):
|
||
_ToStr = repr(TypeInfo.ToString())
|
||
elif TypeInfo is None:
|
||
_ToStr = 'None'
|
||
except Exception as _E:
|
||
_ToStr = f"<ToString 异常 {type(_E).__name__}: {_E}>"
|
||
return (f"联合类型强转 '({ast.unparse(Node.func)})(...)' 无法确定目标类型,"
|
||
f"拒绝静默返回 None(会让整条表达式被判为『编译期求值为空』而丢弃):"
|
||
f"MergeTypes 返回={type(TypeInfo).__name__}(ToString()={_ToStr});"
|
||
f"_ExtractTypeStrFromUnionBinOp={TargetStr!r};"
|
||
f"MergeTypes 异常={MergeException!r};操作数判据:" + ";".join(_Operands))
|
||
|
||
def _ExtractTypeStrFromUnionBinOp(self, NodeFunc: ast.AST) -> str | None:
|
||
"""Fallback:从类型联合 BinOp 手动提取类型字符串。
|
||
|
||
处理 (BaseType | CPtr) 这种模式,手动解析为 "{BaseType} *"。
|
||
支持嵌套的 | 操作(如 (CInt | CPtr) | CStatic)。
|
||
|
||
策略:
|
||
- 递归展平所有 | 操作数
|
||
- CPtr 视为指针修饰符(生成 "{BaseType} *" 格式)
|
||
- 其他 CType 子类作为基础类型(取第一个)
|
||
- 跳过存储类/限定符修饰符(CExport/CExtern/CStatic/CConst/CVolatile/CInline 等)
|
||
"""
|
||
if not isinstance(NodeFunc, ast.BinOp) or not isinstance(NodeFunc.op, ast.BitOr):
|
||
return None
|
||
|
||
# 存储类/限定符/修饰符类型名集合:这些类型在类型联合中只起修饰作用,
|
||
# 不是基础类型,应跳过(参考 HandlesTypeMerge._GetCTypeInfoInternal 的分类逻辑)
|
||
StorageQualifierNames = {
|
||
'CArrayPtr', 'CConst', 'CVolatile', 'CInline',
|
||
'CStatic', 'CExtern', 'CExport', 'CAuto', 'CRegister',
|
||
'CDefine', 'CPass', 'CTypeDefault', 'State',
|
||
'BigEndian', 'LittleEndian',
|
||
}
|
||
|
||
# 递归展平所有 | 操作数
|
||
Operands = []
|
||
|
||
def CollectOperands(node: ast.AST) -> None:
|
||
if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
|
||
CollectOperands(node.left)
|
||
CollectOperands(node.right)
|
||
else:
|
||
Operands.append(node)
|
||
|
||
CollectOperands(NodeFunc)
|
||
|
||
HasCPtr = False # 是否包含 CPtr(指针修饰符)
|
||
BaseTypeName = None # 基础类型名(如 "CInt"、"CChar")
|
||
|
||
for Operand in Operands:
|
||
AttrName = None
|
||
if isinstance(Operand, ast.Attribute):
|
||
AttrName = Operand.attr
|
||
elif isinstance(Operand, ast.Name):
|
||
AttrName = Operand.id
|
||
else:
|
||
continue
|
||
|
||
# CPtr 是指针修饰符,单独处理(增加一层 *)
|
||
if AttrName == 'CPtr':
|
||
HasCPtr = True
|
||
continue
|
||
|
||
# 跳过存储类/限定符/修饰符类型,它们不是基础类型
|
||
if AttrName in StorageQualifierNames:
|
||
continue
|
||
|
||
# 通过 TypeSystem 获取类型类,验证是否为 CType 子类
|
||
TypeClass = getattr(TypeSystem, AttrName, None)
|
||
if not (isinstance(TypeClass, type) and issubclass(TypeClass, TypeSystem.CType)):
|
||
# 非 CType 类,跳过
|
||
continue
|
||
|
||
# 记录第一个非 CPtr 基础类型
|
||
if BaseTypeName is None:
|
||
BaseTypeName = AttrName
|
||
|
||
if not BaseTypeName:
|
||
return None
|
||
|
||
# 包含 CPtr 时,生成 "{BaseType} *" 格式
|
||
# _CType2LLVM 已验证能解析 "CInt *" → i32*(ir.PointerType(ir.IntType(32)))
|
||
if HasCPtr:
|
||
return f"{BaseTypeName} *"
|
||
return BaseTypeName
|
||
|
||
def _HandleTypeCastLlvm(self, expr_node: ast.AST, target_type_str: str) -> ir.Value | None:
|
||
Gen = self.Trans.LlvmGen
|
||
val = self.HandleExprLlvm(expr_node)
|
||
if val is None:
|
||
return Gen.emit_constant(0, target_type_str)
|
||
target_type = Gen._CType2LLVM(target_type_str)
|
||
if not target_type:
|
||
return val
|
||
if val.type == target_type:
|
||
if Gen._is_type_unsigned(target_type_str):
|
||
Gen._unsigned_results[id(val)] = True
|
||
return val
|
||
src_is_float = isinstance(val.type, (ir.FloatType, ir.DoubleType))
|
||
dst_is_float = isinstance(target_type, (ir.FloatType, ir.DoubleType))
|
||
src_is_int = isinstance(val.type, ir.IntType)
|
||
dst_is_int = isinstance(target_type, ir.IntType)
|
||
src_IsPtr = isinstance(val.type, ir.PointerType)
|
||
dst_IsPtr = isinstance(target_type, ir.PointerType)
|
||
if src_is_int and dst_is_float:
|
||
is_unsigned = Gen._check_node_unsigned(expr_node)
|
||
if is_unsigned:
|
||
return Gen.builder.uitofp(val, target_type, name="uint2float")
|
||
return Gen.builder.sitofp(val, target_type, name="int2float")
|
||
if src_is_float and dst_is_int:
|
||
return Gen.builder.fptosi(val, target_type, name="float2int")
|
||
if src_is_int and dst_is_int:
|
||
is_dst_unsigned = Gen._is_type_unsigned(target_type_str)
|
||
if val.type.width < target_type.width:
|
||
if val.type.width == 1:
|
||
# i1 是布尔值(来自 icmp/fcmp/__contains__),无符号语义,必须 zext
|
||
result = Gen.builder.zext(val, target_type, name="zext_bool_cast")
|
||
else:
|
||
is_unsigned = Gen._check_node_unsigned(expr_node)
|
||
if is_unsigned or is_dst_unsigned:
|
||
result = Gen.builder.zext(val, target_type, name="zext_cast")
|
||
else:
|
||
result = Gen.builder.sext(val, target_type, name="sext_cast")
|
||
if is_dst_unsigned:
|
||
Gen._unsigned_results[id(result)] = True
|
||
return result
|
||
if val.type.width > target_type.width:
|
||
# 目标 i1:真值归一化 `x != 0`(与 bool(x) 内建 / if 条件 / 落存储
|
||
# 同一判据),不是 trunc 取最低位(运行时值 2 会得 false)
|
||
if target_type.width == 1:
|
||
result = Gen._CoerceIntToI1(val, name="bool_norm_cast")
|
||
else:
|
||
result = Gen.builder.trunc(val, target_type, name="trunc_cast")
|
||
if is_dst_unsigned:
|
||
Gen._unsigned_results[id(result)] = True
|
||
return result
|
||
if is_dst_unsigned:
|
||
Gen._unsigned_results[id(val)] = True
|
||
return val
|
||
if src_is_float and dst_is_float:
|
||
if isinstance(val.type, ir.FloatType) and isinstance(target_type, ir.DoubleType):
|
||
return Gen.builder.fpext(val, target_type, name="fpext_cast")
|
||
if isinstance(val.type, ir.DoubleType) and isinstance(target_type, ir.FloatType):
|
||
return Gen.builder.fptrunc(val, target_type, name="fptrunc_cast")
|
||
return val
|
||
if src_IsPtr and dst_is_int:
|
||
if target_type.width < 64:
|
||
ptr_to_i64 = Gen.builder.ptrtoint(val, ir.IntType(64), name="ptr2i64")
|
||
return Gen.builder.trunc(ptr_to_i64, target_type, name="ptr2int_cast")
|
||
return Gen.builder.ptrtoint(val, target_type, name="ptr2int_cast")
|
||
if src_is_int and dst_IsPtr:
|
||
return Gen.builder.inttoptr(val, target_type, name="int2ptr_cast")
|
||
if src_IsPtr and dst_IsPtr:
|
||
if isinstance(val.type.pointee, ir.PointerType) and isinstance(target_type.pointee, ir.IntType):
|
||
Loaded = Gen._load(val, name="load_ptr")
|
||
return Loaded
|
||
return Gen.builder.bitcast(val, target_type, name="ptrcast")
|
||
try:
|
||
return Gen.builder.bitcast(val, target_type, name="cast")
|
||
except Exception: # 回退:bitcast 失败时返回原值
|
||
return val
|
||
|
||
def _HandleREnumConstructLlvm(self, Node: ast.Call, RenumName: str, VariantName: str, TagValue: int) -> ir.Value | None:
|
||
Gen = self.Trans.LlvmGen
|
||
if RenumName not in Gen.structs:
|
||
self.Trans.ImportHandler._TryLoadStructFromStub(RenumName, Gen)
|
||
if RenumName not in Gen.structs:
|
||
return None
|
||
RenumType = Gen.structs[RenumName]
|
||
# `new memgr(x) Qual.Variant(args)`:_HandleNewExprLlvm 已取好池存储 → 复用;
|
||
# 裸 `Qual.Variant(args)`(无 new)时 NewStorageOverride 为 None → 帧内 alloca。
|
||
if Gen.NewStorageOverride is not None:
|
||
result = Gen.NewStorageOverride
|
||
else:
|
||
result = Gen._allocaEntry(RenumType, name=f"{RenumName}_{VariantName}")
|
||
tag_ptr = Gen.builder.gep(result, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="renum_tag_ptr")
|
||
Gen._store(ir.Constant(ir.IntType(32), TagValue), tag_ptr)
|
||
NestedStructName = f"{RenumName}_{VariantName}"
|
||
if Node.args:
|
||
# 变体嵌套结构体按需补发:导入模块侧 stub 只声明主 REnum,不含
|
||
# `<REnum>_<Variant>` 声明(见 BaseHandle._EnsureRenumVariantStruct)。
|
||
# 缺它时历史行为是**静默丢弃全部载荷实参**(只写 tag)—— 属静默错码,
|
||
# 故此处补齐;补不上则响亮失败,绝不产出"只有 tag 没有载荷"的值。
|
||
self._EnsureRenumVariantStruct(Gen, RenumName, VariantName)
|
||
if NestedStructName not in Gen.structs or not Gen.class_members.get(NestedStructName):
|
||
from lib.core.LLVMCG.FuncGen import FailFastError
|
||
raise FailFastError(
|
||
f"REnum 变体 '{RenumName}.{VariantName}' 的嵌套结构体/载荷成员缺失,"
|
||
f"无法写入 {len(Node.args)} 个载荷实参(拒绝静默丢弃):"
|
||
f"structs 命中={'有' if NestedStructName in Gen.structs else '无'} "
|
||
f"class_members={len(Gen.class_members.get(NestedStructName, []))} 项;"
|
||
f"同前缀 structs 键="
|
||
f"{[k for k in Gen.structs if k.startswith(RenumName + '_')][:8]}"
|
||
)
|
||
if NestedStructName in Gen.structs and Node.args:
|
||
NestedStructType = Gen.structs[NestedStructName]
|
||
NestedStructPtrType = ir.PointerType(NestedStructType)
|
||
variant_ptr = Gen.builder.bitcast(result, NestedStructPtrType, name=f"cast_{NestedStructName}")
|
||
members = Gen.class_members.get(NestedStructName, [])
|
||
payLoad_members = [(n, t) for n, t in members if n != '__tag']
|
||
for i, arg in enumerate(Node.args):
|
||
if i < len(payLoad_members):
|
||
member_name, member_type = payLoad_members[i]
|
||
ArgVal = self.HandleExprLlvm(arg)
|
||
if ArgVal:
|
||
Coerced = Gen._coerce_value(ArgVal, member_type)
|
||
if Coerced is not None:
|
||
ArgVal = Coerced
|
||
elem_ptr = Gen.builder.gep(variant_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), i + 1)], name=f"{VariantName}_{member_name}")
|
||
# REnum 嵌套结构体共享 max_variant_struct 布局,成员类型可能与
|
||
# 结构体字段类型不一致(如 Bits:i32 与 Ret:LLVMType* 重叠)。
|
||
# 需 bitcast elem_ptr 到成员类型,避免 _store 按 struct 字段类型做错误转换。
|
||
if isinstance(elem_ptr.type, ir.PointerType) and elem_ptr.type.pointee != member_type:
|
||
elem_ptr = Gen.builder.bitcast(elem_ptr, ir.PointerType(member_type), name=f"{VariantName}_{member_name}_cast")
|
||
Gen._store(ArgVal, elem_ptr)
|
||
return result
|
||
|
||
def _HandleTypedefCastLlvm(self, Node: ast.Call, TypedefName: str) -> ir.Value:
|
||
Gen = self.Trans.LlvmGen
|
||
SymInfo = self.Trans.SymbolTable.lookup(TypedefName)
|
||
if not SymInfo or not SymInfo.IsTypedef:
|
||
return ir.Constant(ir.IntType(32), 0)
|
||
# 确保 Name 已设置,以便 _resolve_typedef_ctype 能正确解析
|
||
if not SymInfo.Name:
|
||
SymInfo.Name = TypedefName
|
||
TargetType = Gen._ctype_to_llvm(SymInfo)
|
||
if not Node.args:
|
||
if isinstance(TargetType, ir.IntType):
|
||
return ir.Constant(TargetType, 0)
|
||
elif isinstance(TargetType, ir.PointerType):
|
||
return ir.Constant(TargetType, None)
|
||
return ir.Constant(ir.IntType(32), 0)
|
||
ArgVal = self.HandleExprLlvm(Node.args[0])
|
||
if not ArgVal:
|
||
if isinstance(TargetType, ir.IntType):
|
||
return ir.Constant(TargetType, 0)
|
||
return ir.Constant(ir.IntType(32), 0)
|
||
if ArgVal.type == TargetType:
|
||
return ArgVal
|
||
if isinstance(TargetType, ir.IntType) and isinstance(ArgVal.type, ir.IntType):
|
||
if ArgVal.type.width < TargetType.width:
|
||
# **显式**强转的加宽必须保符号:此前手写 zext,负值/负数常量会被零扩展
|
||
# (现场:`int64(-1)` 变 4294967295;IntWidthTest Test 5)。
|
||
return Gen.builder.sext(ArgVal, TargetType, name=f"sext_{TypedefName}_cast")
|
||
elif ArgVal.type.width > TargetType.width:
|
||
# 显式窄化 = 截断(“隐式窄化禁止”只针对**隐式**路径,不拦显式转换)
|
||
return Gen.builder.trunc(ArgVal, TargetType, name=f"trunc_{TypedefName}_cast")
|
||
if isinstance(TargetType, ir.PointerType):
|
||
if isinstance(ArgVal.type, ir.PointerType):
|
||
return Gen.builder.bitcast(ArgVal, TargetType, name=f"bitcast_{TypedefName}_cast")
|
||
if isinstance(ArgVal.type, ir.IntType):
|
||
return Gen.builder.inttoptr(ArgVal, TargetType, name=f"inttoptr_{TypedefName}_cast")
|
||
# 如果参数是结构体值,需要 alloca 并返回指针
|
||
if isinstance(ArgVal.type, ir.BaseStructType):
|
||
alloca = Gen.builder.alloca(ArgVal.type, name=f"struct_alloca_{TypedefName}")
|
||
Gen.builder.store(ArgVal, alloca, align=8)
|
||
return Gen.builder.bitcast(alloca, TargetType, name=f"bitcast_struct_{TypedefName}")
|
||
if isinstance(TargetType, ir.IntType) and isinstance(ArgVal.type, ir.PointerType):
|
||
return Gen.builder.ptrtoint(ArgVal, TargetType, name=f"ptrtoint_{TypedefName}_cast")
|
||
if isinstance(TargetType, (ir.FloatType, ir.DoubleType)) and isinstance(ArgVal.type, ir.IntType):
|
||
return Gen.builder.sitofp(ArgVal, TargetType, name=f"sitofp_{TypedefName}_cast")
|
||
if isinstance(TargetType, ir.IntType) and isinstance(ArgVal.type, (ir.FloatType, ir.DoubleType)):
|
||
return Gen.builder.fptosi(ArgVal, TargetType, name=f"fptosi_{TypedefName}_cast")
|
||
return ArgVal
|
||
|
||
def _HandleSubscriptPtrCastLlvm(self, Node: ast.Call, sub: ast.Subscript) -> ir.Value:
|
||
"""(rawptr[X])(expr) / (CPtr[X])(expr) 内建指针转换:expr → X*
|
||
|
||
rawptr 是编译器内建裸指针语法(无 SymbolTable typedef 条目、无泛型模板),
|
||
此前 Subscript 调用仅查泛型模板 → 落空后报 "Unsupported call expression"
|
||
(StubMergerCollect.vp `(rawptr[FileEntry])(CVoid(...))` bootstrap 根因)。
|
||
目标类型经 TypeMergeHandler.GetCTypeInfo 解析 Subscript 类型节点获得。
|
||
"""
|
||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||
TargetType: ir.Type | None = None
|
||
try:
|
||
ti_cast: Any = self.Trans.TypeMergeHandler.GetCTypeInfo(sub)
|
||
if ti_cast is not None:
|
||
TargetType = Gen._ctype_to_llvm(ti_cast)
|
||
except Exception:
|
||
TargetType = None
|
||
if TargetType is None or isinstance(TargetType, ir.VoidType):
|
||
# 回退:rawptr[X] 语义 = X*(X 为已注册 struct/类,可能模块限定名)
|
||
s_name: str | None = None
|
||
_sl = getattr(sub, 'slice', None)
|
||
if isinstance(_sl, ast.Attribute):
|
||
s_name = _sl.attr
|
||
elif isinstance(_sl, ast.Name):
|
||
s_name = _sl.id
|
||
if s_name and s_name in Gen.structs:
|
||
TargetType = ir.PointerType(Gen.structs[s_name])
|
||
else:
|
||
TargetType = ir.PointerType(ir.IntType(8))
|
||
return self._emit_rawptr_cast(Node, Gen, TargetType)
|
||
|
||
def _emit_rawptr_cast(self, Node: ast.Call, Gen: LlvmGeneratorMixin, TargetType: ir.Type) -> ir.Value:
|
||
"""按 _HandleTypedefCastLlvm 的指针语义执行 bitcast/inttoptr 转换"""
|
||
if not Node.args:
|
||
if isinstance(TargetType, ir.PointerType):
|
||
return ir.Constant(TargetType, None)
|
||
return ir.Constant(ir.IntType(32), 0)
|
||
ArgVal: Any = self.HandleExprLlvm(Node.args[0])
|
||
if not ArgVal:
|
||
return ir.Constant(ir.IntType(32), 0)
|
||
if ArgVal.type == TargetType:
|
||
return ArgVal
|
||
if isinstance(TargetType, ir.IntType) and isinstance(ArgVal.type, ir.IntType):
|
||
# builtins typedef 数值转换(int64(bool) / uint64(i32) 等):加宽保符号(sext),
|
||
# 窄化=截断(显式转换不受“隐式窄化禁止”约束)。
|
||
# 此前加宽用 zext,`int64(-1)` 会变成 4294967295(IntWidthTest Test 5)。
|
||
if ArgVal.type.width < TargetType.width:
|
||
return Gen.builder.sext(ArgVal, TargetType, name="sext_typedef_cast")
|
||
elif ArgVal.type.width > TargetType.width:
|
||
return Gen.builder.trunc(ArgVal, TargetType, name="trunc_typedef_cast")
|
||
return ArgVal
|
||
if isinstance(TargetType, ir.PointerType):
|
||
if isinstance(ArgVal.type, ir.PointerType):
|
||
return Gen.builder.bitcast(ArgVal, TargetType, name="bitcast_rawptr_cast")
|
||
if isinstance(ArgVal.type, ir.IntType):
|
||
return Gen.builder.inttoptr(ArgVal, TargetType, name="inttoptr_rawptr_cast")
|
||
if isinstance(ArgVal.type, ir.BaseStructType):
|
||
alloca = Gen.builder.alloca(ArgVal.type, name="struct_alloca_rawptr")
|
||
Gen.builder.store(ArgVal, alloca, align=8)
|
||
return Gen.builder.bitcast(alloca, TargetType, name="bitcast_struct_rawptr")
|
||
if isinstance(TargetType, ir.IntType) and isinstance(ArgVal.type, ir.PointerType):
|
||
return Gen.builder.ptrtoint(ArgVal, TargetType, name="ptrtoint_rawptr_cast")
|
||
return ArgVal
|
||
|
||
def _HandleInlineExpandLlvm(self, Node: ast.Call, sym_info: CTypeInfo) -> None:
|
||
Gen = self.Trans.LlvmGen
|
||
inline_body = sym_info.InlineBody
|
||
inline_params = sym_info.InlineParams or []
|
||
call_args = []
|
||
for arg in Node.args:
|
||
call_args.append(self.Trans.ExprHandler.HandleExprLlvm(arg))
|
||
saved_vars = {}
|
||
for i, param_name in enumerate(inline_params):
|
||
if i < len(call_args):
|
||
saved_vars[param_name] = call_args[i]
|
||
old_var_scopes = list(self.Trans.VarScopes)
|
||
for param_name, val in saved_vars.items():
|
||
if val is not None:
|
||
alloca = Gen._allocaEntry(val.type, name=f"inline_arg_{param_name}")
|
||
Gen._store(val, alloca)
|
||
self.Trans.VarScopes.append((param_name, alloca))
|
||
self.Trans.BodyHandler.HandleBodyLlvm(inline_body)
|
||
for param_name, _ in saved_vars.items():
|
||
if self.Trans.VarScopes and self.Trans.VarScopes[-1][0] == param_name:
|
||
self.Trans.VarScopes.pop()
|
||
self.Trans.VarScopes = old_var_scopes
|
||
return None
|
||
|
||
def _HandleClosureCallLlvm(self, Node: ast.Call, FuncName: str) -> ir.Value:
|
||
Gen = self.Trans.LlvmGen
|
||
func = Gen.functions.get(FuncName)
|
||
if not func:
|
||
if FuncName in self.Trans.FunctionDefCache:
|
||
FuncDef = self.Trans.FunctionDefCache[FuncName]
|
||
self.Trans.FunctionHandler._EmitFunctionForwardDeclLlvm(FuncDef, Gen)
|
||
func = Gen.functions.get(FuncName)
|
||
if not func:
|
||
func = self._try_declare_c_lib_func(FuncName, Gen)
|
||
if not func:
|
||
raise Exception(f"Undefined function: '{FuncName}'")
|
||
|
||
FuncDef = self.Trans.FunctionDefCache.get(FuncName)
|
||
param_names = []
|
||
FuncDef_args = getattr(FuncDef, 'args', None) if FuncDef else None
|
||
if FuncDef_args:
|
||
param_names = [arg.arg for arg in FuncDef.args.args]
|
||
# 回退到全局参数名表(支持跨模块 include 函数)
|
||
if not param_names:
|
||
global_param_names = getattr(self.Trans, '_global_function_param_names', {})
|
||
param_names = global_param_names.get(FuncName) or []
|
||
|
||
num_params = len(func.function_type.args)
|
||
nonlocal_param_count = len(Gen.nonlocal_params.get(FuncName, []))
|
||
eh_msg_out_count = 0
|
||
if num_params > 0 and func.args:
|
||
for arg in func.args:
|
||
if arg.name in ('__eh_msg_out__', '__eh_code_out__'):
|
||
eh_msg_out_count += 1
|
||
regular_param_count = num_params - nonlocal_param_count - eh_msg_out_count
|
||
is_variadic = False
|
||
func_ft = getattr(func, 'function_type', None)
|
||
is_variadic = getattr(func_ft, 'var_arg', False) if func_ft else False
|
||
|
||
if not is_variadic and len(Node.args) > regular_param_count:
|
||
raise Exception(f"调用 {FuncName}() 传入了 {len(Node.args)} 个参数,但函数只需要 {regular_param_count} 个参数")
|
||
|
||
# 变参函数:固定形参(含带默认值的)之外才是可变部分。被省略的固定形参
|
||
# 也必须补进调用实参,否则实参个数少于固定形参 → 被调函数读到寄存器/栈
|
||
# 垃圾(VET json.write 缺省 cap 读成指针量级 → pool.alloc 巨量 → OOM 的形态)。
|
||
max_args = max(regular_param_count, len(Node.args)) if is_variadic else regular_param_count
|
||
resolved = [None] * max_args
|
||
|
||
for i, arg in enumerate(Node.args):
|
||
if i < max_args:
|
||
arg_var_type = None
|
||
if i < num_params:
|
||
arg_var_type = func.function_type.args[i]
|
||
ArgVal = self.HandleExprLlvm(arg, VarType=arg_var_type)
|
||
if ArgVal:
|
||
resolved[i] = ArgVal
|
||
|
||
for kw in Node.keywords:
|
||
if kw.arg is None:
|
||
if isinstance(kw.value, ast.Dict):
|
||
pass
|
||
elif isinstance(kw.value, ast.Call):
|
||
pass
|
||
continue
|
||
ArgVal = self.HandleExprLlvm(kw.value)
|
||
if not ArgVal:
|
||
continue
|
||
kw_name = kw.arg
|
||
if kw_name in param_names:
|
||
idx = param_names.index(kw_name)
|
||
if idx < regular_param_count:
|
||
resolved[idx] = ArgVal
|
||
|
||
FuncDef_args_defaults = getattr(getattr(FuncDef, 'args', None), 'defaults', []) if FuncDef else []
|
||
# 跨模块调用(被调函数不在本模块 FunctionDefCache:其它 App 模块 / includes
|
||
# 模块 / .vpi 声明)时 FuncDef 为 None,本模块没有被调方 AST,AST 默认值不可用。
|
||
# 此时从全局默认参数表(Phase2 预扫描 App 与 includes 源码得到)取值,按
|
||
# "尾部默认参数"语义补齐被省略的实参;缺失该表时保持原有零值填充。
|
||
Global_defaults_vals: list | None = None
|
||
if not FuncDef_args_defaults:
|
||
Global_defaults_vals = self._LookupGlobalDefaults(FuncName)
|
||
if Global_defaults_vals is None and func is not None:
|
||
Global_defaults_vals = self._LookupGlobalDefaults(getattr(func, 'name', None))
|
||
Num_defaults: int = len(FuncDef_args_defaults) if FuncDef_args_defaults else (
|
||
len(Global_defaults_vals) if Global_defaults_vals else 0)
|
||
if Num_defaults > 0:
|
||
Min_args: int = regular_param_count - Num_defaults
|
||
for i in range(regular_param_count):
|
||
if resolved[i] is not None or i < Min_args:
|
||
continue
|
||
default_idx = i - Min_args
|
||
if default_idx >= Num_defaults:
|
||
continue
|
||
if FuncDef_args_defaults:
|
||
default_val = self.HandleExprLlvm(FuncDef_args_defaults[default_idx])
|
||
else:
|
||
default_val = self._ConstantToIrValue(Global_defaults_vals[default_idx],
|
||
func.function_type.args[i], Gen)
|
||
if default_val:
|
||
param_type = func.function_type.args[i]
|
||
if default_val.type != param_type:
|
||
if isinstance(param_type, ir.IntType) and isinstance(default_val.type, ir.IntType):
|
||
if default_val.type.width < param_type.width:
|
||
default_val = Gen.builder.zext(default_val, param_type, name=f"zext_default_{i}")
|
||
elif default_val.type.width > param_type.width:
|
||
default_val = Gen.builder.trunc(default_val, param_type, name=f"trunc_default_{i}")
|
||
elif isinstance(param_type, ir.PointerType) and isinstance(default_val.type, ir.IntType):
|
||
default_val = Gen.builder.inttoptr(default_val, param_type, name=f"inttoptr_default_{i}")
|
||
resolved[i] = default_val
|
||
|
||
if FuncDef and param_names:
|
||
min_args = regular_param_count - Num_defaults
|
||
provided = len(Node.args)
|
||
kw_provided = set()
|
||
for kw in Node.keywords:
|
||
if kw.arg and kw.arg in param_names:
|
||
kw_provided.add(param_names.index(kw.arg))
|
||
for i in range(min(min_args, len(param_names))):
|
||
if i >= provided and i not in kw_provided:
|
||
raise Exception(f"调用 {FuncName}() 缺少必需参数 '{param_names[i]}',该参数没有默认值")
|
||
|
||
CallArgs = []
|
||
for i in range(max_args):
|
||
if resolved[i] is not None:
|
||
CallArgs.append(resolved[i])
|
||
elif i < regular_param_count:
|
||
arg_type = func.function_type.args[i]
|
||
if isinstance(arg_type, ir.PointerType):
|
||
CallArgs.append(ir.Constant(arg_type, None))
|
||
elif isinstance(arg_type, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
||
zero_val = Gen._zero_value_for_type(arg_type)
|
||
if zero_val is not None:
|
||
CallArgs.append(zero_val)
|
||
else:
|
||
CallArgs.append(ir.Constant(ir.PointerType(arg_type), None))
|
||
elif isinstance(arg_type, ir.ArrayType):
|
||
zero_val = Gen._zero_value_for_type(arg_type)
|
||
if zero_val is not None:
|
||
CallArgs.append(zero_val)
|
||
else:
|
||
CallArgs.append(ir.Constant(arg_type, 0))
|
||
else:
|
||
CallArgs.append(ir.Constant(arg_type, 0))
|
||
|
||
if FuncName in Gen.nonlocal_params:
|
||
for var_name, ptr_type in Gen.nonlocal_params[FuncName]:
|
||
if var_name in Gen.variables and Gen.variables[var_name] is not None:
|
||
CallArgs.append(Gen.variables[var_name])
|
||
elif var_name in Gen._reg_values:
|
||
OldVal = Gen._reg_values[var_name]
|
||
var = Gen._allocaEntry(OldVal.type, name=var_name)
|
||
Gen._store(OldVal, var)
|
||
Gen.variables[var_name] = var
|
||
del Gen._reg_values[var_name]
|
||
CallArgs.append(var)
|
||
|
||
self._append_eh_msg_out_arg(CallArgs, func, Gen)
|
||
|
||
if is_variadic:
|
||
# 对于可变参数函数,需要手动处理参数类型转换
|
||
adjusted = []
|
||
for i, arg in enumerate(CallArgs):
|
||
if i < num_params:
|
||
# 固定参数:尝试类型转换
|
||
param_type = func.function_type.args[i]
|
||
if arg.type != param_type:
|
||
try:
|
||
if isinstance(arg.type, ir.IntType) and isinstance(param_type, ir.PointerType):
|
||
adjusted.append(self.builder.inttoptr(arg, param_type))
|
||
elif isinstance(arg.type, ir.PointerType) and isinstance(param_type, ir.IntType):
|
||
adjusted.append(Gen.builder.ptrtoint(arg, param_type))
|
||
elif isinstance(arg.type, ir.IntType) and arg.type.width < param_type.width:
|
||
adjusted.append(Gen.builder.zext(arg, param_type))
|
||
elif isinstance(arg.type, ir.PointerType) and isinstance(param_type, ir.PointerType):
|
||
adjusted.append(Gen.builder.bitcast(arg, param_type, name=f"cast_arg_{i}"))
|
||
else:
|
||
adjusted.append(arg)
|
||
except Exception: # 回退:参数类型调整失败时使用原值
|
||
if isinstance(arg.type, ir.PointerType) and isinstance(param_type, ir.PointerType):
|
||
try:
|
||
adjusted.append(Gen.builder.bitcast(arg, param_type, name=f"cast_arg_{i}"))
|
||
except Exception:
|
||
adjusted.append(arg)
|
||
else:
|
||
adjusted.append(arg)
|
||
else:
|
||
adjusted.append(arg)
|
||
else:
|
||
# 可变参数:应用默认参数提升(float -> double, i32 -> i64)
|
||
if isinstance(arg.type, ir.FloatType):
|
||
arg = Gen.builder.fpext(arg, ir.DoubleType(), name=f"fpext_vararg_{FuncName}")
|
||
elif isinstance(arg.type, ir.IntType) and arg.type.width < 64:
|
||
# i1 是布尔值(来自 icmp/fcmp/__contains__),无符号语义,必须 zext
|
||
if arg.type.width == 1:
|
||
arg = Gen.builder.zext(arg, ir.IntType(64), name=f"zext_bool_vararg_{FuncName}")
|
||
else:
|
||
# 有符号整数用 sext,无符号整数用 zext
|
||
is_signed = True
|
||
arg_node = Node.args[i] if i < len(Node.args) else None
|
||
if arg_node is not None:
|
||
is_u = Gen._check_node_unsigned(arg_node)
|
||
if is_u:
|
||
is_signed = False
|
||
if is_signed:
|
||
arg = Gen.builder.sext(arg, ir.IntType(64), name=f"sext_vararg_{FuncName}")
|
||
else:
|
||
arg = Gen.builder.zext(arg, ir.IntType(64), name=f"zext_vararg_{FuncName}")
|
||
elif isinstance(arg.type, (ir.LiteralStructType, ir.IdentifiedStructType)):
|
||
# 治本修复:变参函数(如 printf)不支持 struct by value 传递。
|
||
# 当 self 等 struct 值被错误地 load 为值(而非指针)传入变参时,
|
||
# ABI 不匹配会导致崩溃。修复:将 struct 值通过 alloca + bitcast
|
||
# 转换为 i8* 指针传递,确保与 %p / %s 等格式说明符兼容。
|
||
try:
|
||
alloca_tmp = Gen.builder.alloca(arg.type, name=f"vararg_struct_{FuncName}_{i}")
|
||
Gen.builder.store(arg, alloca_tmp)
|
||
arg = Gen.builder.bitcast(alloca_tmp, ir.IntType(8).as_pointer(), name=f"vararg_struct_ptr_{FuncName}_{i}")
|
||
except Exception:
|
||
# 回退:alloca/store 失败时,尝试 ptrtoint 为 i64
|
||
try:
|
||
arg = Gen.builder.ptrtoint(arg, ir.IntType(64), name=f"vararg_struct_i64_{FuncName}_{i}")
|
||
except Exception:
|
||
pass # 最终回退:保留原值(可能仍会导致崩溃,但至少不阻塞编译)
|
||
adjusted.append(arg)
|
||
result = Gen.builder.call(func, adjusted, name=f"call_{FuncName}")
|
||
else:
|
||
# 自动取址已收口到 Gen._adjust_args(唯一汇聚点,按 func.name 查表)。
|
||
adjusted = Gen._adjust_args(CallArgs, func)
|
||
# 兜底:确保所有指针类型参数与函数签名匹配(如 struct* -> i8*)
|
||
for i, (arg, param) in enumerate(zip(adjusted, func.args)):
|
||
if arg.type != param.type:
|
||
if isinstance(arg.type, ir.PointerType) and isinstance(param.type, ir.PointerType):
|
||
adjusted[i] = Gen.builder.bitcast(arg, param.type, name=f"cast_arg_{i}")
|
||
result = Gen.builder.call(func, adjusted, name=f"call_{FuncName}")
|
||
self._check_eh_return(result, FuncName, Gen, called_func=func)
|
||
return result
|
||
|
||
@staticmethod
|
||
def _has_cvtable_decorator(node: ast.ClassDef) -> bool:
|
||
"""检查 ClassDef 是否有 @CVTable 装饰器(或 @CVTable)"""
|
||
for decorator in node.decorator_list:
|
||
if isinstance(decorator, ast.Call):
|
||
inner = decorator.func
|
||
if isinstance(inner, ast.Name) and inner.id == 'CVTable':
|
||
return True
|
||
if isinstance(decorator, ast.Name) and decorator.id == 'CVTable':
|
||
return True
|
||
return False
|
||
|
||
@staticmethod
|
||
def _has_novtable_decorator(node: ast.ClassDef) -> bool:
|
||
"""检查 ClassDef 是否有 @NoVTable 装饰器"""
|
||
for decorator in node.decorator_list:
|
||
if isinstance(decorator, ast.Name) and decorator.id == 'NoVTable':
|
||
return True
|
||
return False
|
||
|
||
def _try_register_vtable_ondemand(self, ClassName: str, class_sha1: str, Gen: "LlvmGeneratorMixin") -> None:
|
||
"""按需 vtable 注册:从 .pyi stub 检查 @CVTable 并注册到 vtable 集合。
|
||
|
||
沿继承链递归收集方法,保证 vtable 布局与 prescan 的 _EmitClassLlvm 一致:
|
||
- 基类方法在前(固定索引,保证多态分派正确)
|
||
- 子类新增方法在后
|
||
- 子类覆盖的方法放在父类的位置(用子类实现)
|
||
|
||
与 prescan 的 _resolve_class_flags 逻辑一致:
|
||
- 类自身有 @CVTable → 注册
|
||
- 类自身有 @NoVTable → 不注册
|
||
- 类继承 @CVTable 基类(且无 @NoVTable)→ 注册(自动启用 CVTable)
|
||
"""
|
||
try:
|
||
import_handler = self.Trans.ImportHandler
|
||
project_root = import_handler._find_project_root()
|
||
struct_sha1_map = getattr(Gen, '_struct_sha1_map', {})
|
||
|
||
# 类级缓存已读取的 .pyi 文件(绝对路径 -> class_map),跨 worker 任务共享。
|
||
# 原实现为函数局部缓存,每次调用重建 → 437 次 open+ast.parse 同一批 pyi。
|
||
def load_pyi(sha1: str) -> dict[str, ast.ClassDef] | None:
|
||
pyi_path = os.path.join(project_root, 'temp', f'{sha1}.vpi')
|
||
if not os.path.isfile(pyi_path):
|
||
# 回退读取旧缓存 .pyi
|
||
pyi_path = os.path.join(project_root, 'temp', f'{sha1}.pyi')
|
||
if not os.path.isfile(pyi_path):
|
||
return None
|
||
abs_pyi = os.path.abspath(pyi_path)
|
||
cmap = self._vtable_pyi_cache.get(abs_pyi)
|
||
if cmap is not None:
|
||
return cmap
|
||
with open(pyi_path, 'r', encoding='utf-8') as f:
|
||
pyi_code = f.read()
|
||
tree = ast.parse(pyi_code, pyi_path)
|
||
cmap: dict[str, ast.ClassDef] = {}
|
||
for node in ast.iter_child_nodes(tree):
|
||
if isinstance(node, ast.ClassDef):
|
||
cmap[node.name] = node
|
||
self._vtable_pyi_cache[abs_pyi] = cmap
|
||
return cmap
|
||
|
||
def collect_class_methods(class_name: str, sha1: str, visited: set[str]) -> tuple[list[str], bool, bool, str | None]:
|
||
"""递归收集类的方法列表(基类方法在前,子类方法在后)。
|
||
|
||
Returns:
|
||
(methods, is_cvtable, is_novtable, parent_name)
|
||
"""
|
||
# 结果缓存(类级,键 (sha1, class_name)):同一类的 vtable 方法收集
|
||
# 跨 worker 任务重复调用时直接复用(原 437 次顶层调用 + 递归每次都重走)。
|
||
key = (sha1, class_name)
|
||
cached = self._vtable_methods_cache.get(key)
|
||
if cached is not None:
|
||
# 返回新 list:避免调用方(Gen.class_methods)后续修改污染缓存
|
||
return (list(cached[0]), cached[1], cached[2], cached[3])
|
||
if class_name in visited:
|
||
return ([], False, False, None)
|
||
visited.add(class_name)
|
||
|
||
class_map = load_pyi(sha1)
|
||
if class_map is None:
|
||
return ([], False, False, None)
|
||
|
||
target_node = class_map.get(class_name)
|
||
if target_node is None:
|
||
return ([], False, False, None)
|
||
|
||
is_cvtable = self._has_cvtable_decorator(target_node)
|
||
is_novtable = self._has_novtable_decorator(target_node)
|
||
|
||
# 收集自身方法(方法级修饰符的槽位过滤放在父类状态确定之后:
|
||
# 判据 SymbolUtils.IsVtableSlotMethod 需要 VtableByClassLevel)
|
||
self_method_pairs: list[tuple] = []
|
||
for item in target_node.body:
|
||
if isinstance(item, ast.FunctionDef):
|
||
method_name = item.name
|
||
if method_name in ('__new__', '__init__', '__before_init__'):
|
||
continue
|
||
if method_name == '__call__':
|
||
self_method_pairs.append((item, f"{class_name}.__call__"))
|
||
else:
|
||
self_method_pairs.append((item, f"{class_name}.{method_name}"))
|
||
|
||
# 收集基类方法(多继承:遍历所有父类,声明顺序,短名去重,先声明父类优先)
|
||
parent_methods: list[str] = []
|
||
parent_name: str | None = None
|
||
parent_names: list[str] = []
|
||
parent_method_names_seen: set[str] = set()
|
||
# 第一个真实父类的 vtable 状态(None=无父类/未知)
|
||
first_parent_vtable: bool | None = None
|
||
for base in target_node.bases:
|
||
base_name: str | None = None
|
||
if hasattr(base, 'id'):
|
||
base_name = base.id
|
||
elif hasattr(base, 'attr'):
|
||
base_name = base.attr
|
||
if not base_name or base_name in ('Object', 'CVTable', 'NoVTable', 'CStruct', 'CUnion', 'CEnum', 'REnum', 'Exception', 'Enum'):
|
||
continue
|
||
parent_names.append(base_name)
|
||
if parent_name is None:
|
||
parent_name = base_name
|
||
|
||
# 检查同文件内的基类
|
||
base_node = class_map.get(base_name)
|
||
if base_node is not None:
|
||
base_methods, base_cvtable, base_novtable, _ = collect_class_methods(base_name, sha1, visited)
|
||
# 仅第一个真实父类决定 vtable 继承状态(与 _resolve_class_flags 一致)
|
||
if parent_name == base_name:
|
||
first_parent_vtable = (base_cvtable and not base_novtable)
|
||
for bm in base_methods:
|
||
bmn = bm.split('.')[-1] if '.' in bm else bm
|
||
if bmn not in parent_method_names_seen:
|
||
parent_method_names_seen.add(bmn)
|
||
parent_methods.append(bm)
|
||
else:
|
||
# 跨模块基类 — 查找基类的 sha1
|
||
base_sha1 = struct_sha1_map.get(base_name)
|
||
if base_sha1:
|
||
base_methods, base_cvtable, base_novtable, _ = collect_class_methods(base_name, base_sha1, visited)
|
||
if parent_name == base_name:
|
||
first_parent_vtable = (base_cvtable and not base_novtable)
|
||
for bm in base_methods:
|
||
bmn = bm.split('.')[-1] if '.' in bm else bm
|
||
if bmn not in parent_method_names_seen:
|
||
parent_method_names_seen.add(bmn)
|
||
parent_methods.append(bm)
|
||
else:
|
||
# 无法找到基类的 sha1 → 父类信息未知,保守启用 vtable
|
||
if parent_name == base_name and first_parent_vtable is None:
|
||
first_parent_vtable = True
|
||
if base_name in Gen._cross_module_novtable:
|
||
pass # 父类是 NoVTable,不继承 vtable
|
||
|
||
# 继承链统一 vtable(与 _resolve_class_flags 一致):
|
||
# 类自身无 @CVTable 时,第一个父类有 vtable → 子类启用;
|
||
# 父类无 vtable → 子类静态;父类信息未知 → 保守启用。
|
||
if not is_cvtable and not is_novtable and first_parent_vtable is not None:
|
||
if first_parent_vtable:
|
||
is_cvtable = True
|
||
|
||
# VtableByClassLevel:**忽略方法级 CVTable 标记**算出的 vtable 状态
|
||
# (= 类级 CVTable / 继承链判定)——供槽位筛选与"方法级触发"共用。
|
||
_VtByClassLevel: bool = is_cvtable
|
||
# 方法级修饰符筛选:`novirtual def`(⇒ @NoVTable)不进槽;
|
||
# `virtual def`(⇒ @CVTable)进槽。判据唯一源 = IsVtableSlotMethod
|
||
# (与定义端 HandlesClassDef / VPC _should_method_be_virtual 同口径),
|
||
# 故跨模块虚表槽序与定义模块逐槽一致。
|
||
self_methods: list[str] = []
|
||
for _nd, _full in self_method_pairs:
|
||
if (not is_cvtable) or IsVtableSlotMethod(_nd, _VtByClassLevel):
|
||
self_methods.append(_full)
|
||
# 方法级 virtual 触发类级 vtable(与 HandlesClassDef._resolve_class_flags /
|
||
# VPC _detect_vtable_status 的 `_has_any_func_cvtable` 分支对齐:
|
||
# 类级 NoVTable / 无真实父类这两种可判定形态;父类 vtable 已在上面处理)
|
||
if not is_cvtable and ClassHasFuncLevelCVTable(target_node):
|
||
if is_novtable or parent_name is None:
|
||
is_cvtable = True
|
||
|
||
# 合并方法列表:基类方法在前,子类方法在后
|
||
# 子类覆盖的方法放在父类的位置;
|
||
# 父类独有方法直接用父类方法原名(实际定义类.方法,与 VPC 一致)
|
||
child_method_map: dict[str, str] = {}
|
||
for m in self_methods:
|
||
mn = m.split('.')[-1] if '.' in m else m
|
||
child_method_map[mn] = m
|
||
|
||
merged: list[str] = []
|
||
covered_names: set[str] = set()
|
||
for pm in parent_methods:
|
||
mn = pm.split('.')[-1] if '.' in pm else pm
|
||
if mn in child_method_map:
|
||
merged.append(child_method_map[mn])
|
||
covered_names.add(mn)
|
||
else:
|
||
# 父类独有方法 — 用父类方法原名(虚分派时函数查找沿 MRO 回退)
|
||
merged.append(pm)
|
||
|
||
for m in self_methods:
|
||
mn = m.split('.')[-1] if '.' in m else m
|
||
if mn not in covered_names:
|
||
merged.append(m)
|
||
|
||
result = (merged, is_cvtable, is_novtable, parent_name)
|
||
self._vtable_methods_cache[key] = result
|
||
return result
|
||
|
||
methods, is_cvtable, is_novtable, parent_name = collect_class_methods(ClassName, class_sha1, set())
|
||
|
||
if is_novtable:
|
||
return
|
||
if not is_cvtable:
|
||
return
|
||
|
||
# 注册到 vtable 集合(共享集合)
|
||
Gen._cross_module_vtable_classes.add(ClassName)
|
||
Gen.class_vtable.add(ClassName)
|
||
# 设置方法列表(与 prescan 逻辑一致:基类方法在前)
|
||
Gen.class_methods[ClassName] = methods
|
||
# 根本修复:注册 vtable 元数据后同步具化 struct body,从源头消除
|
||
# "元数据已注册、本体仍 opaque" 的撕裂状态(配合 _HandleMethodCallLlvm
|
||
# 中 _EnsureReceiverStructConcrete 的使用前校验,双保险)。
|
||
import_handler._TryLoadStructFromStub(ClassName, Gen, source_sha1=class_sha1)
|
||
# 设置 class_parent / class_parents(用于虚分派时的函数查找回退与 MRO)
|
||
if parent_name and ClassName not in Gen.class_parent:
|
||
Gen.class_parent[ClassName] = parent_name
|
||
parent_names_map = getattr(Gen, 'class_parents', None)
|
||
if parent_names_map is None:
|
||
parent_names_map = {}
|
||
Gen.class_parents = parent_names_map
|
||
if parent_name and ClassName not in parent_names_map:
|
||
parent_names_map[ClassName] = [parent_name]
|
||
except Exception:
|
||
pass
|
||
|
||
def _try_complete_generic_specialization(self, ClassName: str, MethodName: str, Gen: LlvmGeneratorMixin) -> None:
|
||
"""泛型特化类方法按需完整特化。
|
||
|
||
当 ClassName 是泛型特化名(如 ndarray[double])且缓存中只有
|
||
declare_only 版本时,补发方法体。这样方法调用能找到 define,
|
||
避免链接时 undefined reference。
|
||
|
||
触发场景:numpy 模块内部函数(如 np_sum)调用 a.sum(),
|
||
其中 a 的类型注解 ndarray[CDouble] | CPtr 在类型解析时
|
||
只触发了 declare_only=True 特化(创建 struct + __before_init__),
|
||
方法体(fill/delete/dot/sum/...)未被编译。
|
||
"""
|
||
# 仅对特化名(含 '[' 且以 ']' 结尾)触发
|
||
if '[' not in ClassName or not ClassName.endswith(']'):
|
||
return
|
||
# 反推模板类名(如 ndarray[double] → ndarray)
|
||
base_name: str = ClassName.split('[')[0]
|
||
# 检查是否是已注册的泛型模板
|
||
if not (hasattr(self.Trans.ClassHandler, '_generic_class_templates') and base_name in self.Trans.ClassHandler._generic_class_templates):
|
||
return
|
||
# 构造 spec_key(与 _specialize_generic_class 一致:ClassName<arg1,arg2,...>)
|
||
spec_key: str = base_name + '<' + ','.join(ClassName[len(base_name) + 1:-1].split('][')) + '>'
|
||
spec_cache = getattr(Gen, '_generic_class_specializations', {})
|
||
cached = spec_cache.get(spec_key)
|
||
if not isinstance(cached, tuple) or len(cached) < 2:
|
||
return
|
||
cached_name: str = cached[0]
|
||
was_declare_only: bool = cached[1]
|
||
# 仅当缓存是 declare_only 版本时才需要补发
|
||
if not was_declare_only:
|
||
return
|
||
# 检查方法是否已有 define(blocks 非空表示已编译方法体)
|
||
struct_sha1_map = getattr(Gen, '_struct_sha1_map', {})
|
||
class_sha1 = struct_sha1_map.get(cached_name)
|
||
full_method_name: str = f'{class_sha1}.{cached_name}.{MethodName}' if class_sha1 else f'{cached_name}.{MethodName}'
|
||
existing_func = Gen._find_function(full_method_name)
|
||
if existing_func is not None:
|
||
existing_blocks = getattr(existing_func, 'blocks', [])
|
||
if existing_blocks:
|
||
return # 方法体已编译
|
||
# 从缓存获取 type_args/type_names
|
||
type_info = getattr(Gen, '_generic_class_spec_type_info', {}).get(spec_key)
|
||
if type_info is None:
|
||
return
|
||
cached_type_args, cached_type_names = type_info
|
||
# 不预先标记:_specialize_generic_class 内部缓存逻辑会检测
|
||
# cached_declare_only=True 且 declare_only=False,自动补发方法体
|
||
# 并更新缓存为 (spec_name, False)。预注册机制(L117)防止递归。
|
||
#
|
||
# 上下文快照:本函数**吞掉**特化异常、让外层方法继续编译,故必须在失败时把
|
||
# 编译器上下文复位——`_EmitFunctionLlvm` 的类名/构建器恢复只在**成功路径**
|
||
# 执行(失败路径直接 re-raise),异常穿过多层后 `Gen.builder/func` 与
|
||
# `_CurrentCpythonObjectClass` 会停在内层特化方法的中间状态:外层方法随后
|
||
# 的 `self.X` 被按内层类解析(ExprGenFstr.vp 的 `self.Gen` 被按
|
||
# `list[cfc4ca8da95a30e1.AST*]` 解析 → "属性 'Gen' 在类中找不到"的连带错误),
|
||
# 且后续指令会误插进内层函数的块。
|
||
_saved_builder: object = Gen.builder
|
||
_saved_func: object = Gen.func
|
||
_saved_cpython_class: str | None = getattr(self.Trans, '_CurrentCpythonObjectClass', None)
|
||
_saved_class_name: object = getattr(Gen, '_current_class_name', None)
|
||
try:
|
||
self.Trans.ClassHandler._specialize_generic_class(
|
||
base_name, cached_type_args, Gen,
|
||
type_names=cached_type_names, declare_only=False
|
||
)
|
||
except Exception:
|
||
# 失败时恢复 declare_only 标记,避免后续调用跳过补发
|
||
Gen._generic_class_specializations[spec_key] = (cached_name, True)
|
||
Gen.builder = _saved_builder
|
||
Gen.func = _saved_func
|
||
self.Trans._CurrentCpythonObjectClass = _saved_cpython_class
|
||
Gen._current_class_name = _saved_class_name
|
||
|
||
def _compute_field_byte_offset(self, Gen: LlvmGeneratorMixin, ClassName: str, field_name: str) -> int | None:
|
||
"""计算字段在 struct 中的字节偏移(按 LLVM 布局含对齐)。
|
||
|
||
遍历 struct elements 带对齐累加(与 _get_struct_size/_get_align 一致)。
|
||
有 vtable 的类 struct 首元素为 vtable 指针(i8*),class_members 不含它。
|
||
返回 None 表示无法计算(struct 未定义 / 字段不存在)。
|
||
"""
|
||
# class_members 的 key 是裸类名,而 ClassName 可能带 sha1 前缀
|
||
# (跨模块 ObjVal 类型带前缀,如 "e1ea7eaf63a9c3d1.Generator")。
|
||
# 不剥离则 members 为空 → 找不到字段 → this_adjust 被跳过 → 继承方法
|
||
# self 不调整 → 运行时错位崩溃(register_reexport 写 0x3f 越界即此)。
|
||
lookup_cls: str = ClassName
|
||
if len(ClassName) > 17 and ClassName[16] == '.':
|
||
lookup_cls = ClassName[17:]
|
||
st = Gen.structs.get(ClassName)
|
||
# 注意:不能用 `not st` 做真值判断——IdentifiedStructType 定义 __len__,
|
||
# opaque(elements is None)时 bool(st) 触发 __len__ 的 assert(AssertionError)。
|
||
# 必须用 `st is None` 身份比较。
|
||
if (st is None or not isinstance(st, ir.IdentifiedStructType) or st.elements is None) \
|
||
and lookup_cls != ClassName:
|
||
st = Gen.structs.get(lookup_cls)
|
||
if st is None or not isinstance(st, ir.IdentifiedStructType) or st.elements is None:
|
||
return None
|
||
members: list = Gen.class_members.get(lookup_cls, [])
|
||
# base(vtable 占位槽数)统一走 Gen._member_base(唯一真源),
|
||
# 不再直查 class_vtable/_cross_module_vtable_classes(会漏掉跨模块 AST 节点类)。
|
||
base: int = Gen._member_base(ClassName)
|
||
idx: int | None = None
|
||
for i, (name, _) in enumerate(members):
|
||
if name == field_name:
|
||
idx = base + i
|
||
break
|
||
if idx is None or idx >= len(st.elements):
|
||
return None
|
||
# ============================================================
|
||
# diff_elems 修正(2026-08-13):class_members 与 struct.elements 数量
|
||
# 不一致时对齐(前提:遗漏字段位于目标字段之前)。
|
||
# ============================================================
|
||
diff_elems: int = len(st.elements) - len(members)
|
||
if diff_elems > 0:
|
||
idx += diff_elems
|
||
if idx >= len(st.elements):
|
||
return None
|
||
# 临时诊断(2026-08-18,确定后移除):捕获 this_adjust 计算输入,
|
||
# 定位 TPC 并行 worker 间 class_members/struct 不一致导致的偏移抖动。
|
||
if lookup_cls in ('Generator',):
|
||
try:
|
||
with open(r'd:\Users\TermiNexus\Desktop\TransPyC\_diag_offset.log', 'a', encoding='utf-8') as _f:
|
||
_f.write(f"{lookup_cls}|{field_name}|members={len(members)}|struct={len(st.elements)}"
|
||
f"|base={base}|idx={idx}|diff={diff_elems}\n")
|
||
except Exception:
|
||
pass
|
||
offset: int = 0
|
||
for i in range(idx):
|
||
et = st.elements[i]
|
||
align: int = Gen._get_align(et)
|
||
size: int = Gen._get_struct_size(et)
|
||
if align > 1:
|
||
offset = ((offset + align - 1) // align) * align
|
||
offset += size
|
||
align = Gen._get_align(st.elements[idx])
|
||
if align > 1:
|
||
offset = ((offset + align - 1) // align) * align
|
||
return offset
|
||
|
||
def _adjust_this_for_inherited_method(self, Gen: LlvmGeneratorMixin, ObjVal: ir.Value,
|
||
ClassName: str, method_anc: str | None) -> ir.Value:
|
||
"""多继承 this 调整(与 VPC _translate_method_call 一致):
|
||
|
||
继承方法体按"定义类自身布局"读 self 字段(如 B.get_b 内
|
||
GEP(self_B, [0, 1]),字节偏移为 B 布局中 b 的 offset 8)。父类字段区
|
||
在子类中的**字节偏移**可能不同(如 AB={i8*,a@8,b@12} 中 b 偏移 12),
|
||
self 需按字节差前移,使父类方法内二次 GEP 恰好落到子类字段。
|
||
|
||
修复(2026-08-10):字段索引法在"父类与子类元素大小不同"时错位
|
||
(GEP 索引按元素个数计,非字节等价)。改用字节偏移:
|
||
delta = 字段在子类中字节偏移 − 字段在父类自身布局中字节偏移
|
||
delta==0(第一父类,字段区前缀对齐)无需调整;delta>0 时按字节
|
||
GEP 到父类字段区在子类中的等效基址,再 bitcast 成父类指针。
|
||
"""
|
||
if method_anc is None or method_anc == ClassName:
|
||
return ObjVal
|
||
anc_lookup: str = method_anc
|
||
if len(method_anc) > 17 and method_anc[16] == '.':
|
||
anc_lookup = method_anc[17:]
|
||
anc_members: list = Gen.class_members.get(anc_lookup, [])
|
||
if not anc_members:
|
||
return ObjVal
|
||
first_field_name: str | None = None
|
||
for _fn, _ft in anc_members:
|
||
if _fn == '__vtable__':
|
||
continue
|
||
first_field_name = _fn
|
||
break
|
||
if first_field_name is None:
|
||
return ObjVal
|
||
sub_off: int | None = self._compute_field_byte_offset(Gen, ClassName, first_field_name)
|
||
if sub_off is None:
|
||
# 兄弟 Mixin 场景:调用类(ClassName)不含定义类字段——定义类在
|
||
# 组合类 MRO 中位于调用类之前(如 Combined(BaseA, BaseB),BaseB 内
|
||
# self.helper() 调 BaseA.helper)。此时 BaseB.this 指向组合类中
|
||
# BaseB 字段区起点,BaseA 区在它前面,this 前移 sizeof(定义类 struct)。
|
||
anc_st: Any = Gen.structs.get(method_anc)
|
||
if anc_st is None:
|
||
anc_st = Gen.structs.get(anc_lookup)
|
||
if anc_st is None or not isinstance(anc_st, ir.IdentifiedStructType) or anc_st.elements is None:
|
||
return ObjVal
|
||
sibling_delta: int = -Gen._get_struct_size(anc_st)
|
||
if sibling_delta >= 0:
|
||
return ObjVal
|
||
obj_i8_s: ir.Value = Gen.builder.bitcast(
|
||
ObjVal, ir.PointerType(ir.IntType(8)), name=f"this_sibling_i8_{anc_lookup}")
|
||
adj_s: ir.Value = Gen.builder.gep(
|
||
obj_i8_s, [ir.Constant(ir.IntType(64), sibling_delta)],
|
||
name=f"this_sibling_{anc_lookup}")
|
||
return Gen.builder.bitcast(adj_s, ir.PointerType(anc_st),
|
||
name=f"this_sibling_cast_{anc_lookup}")
|
||
anc_off: int | None = self._compute_field_byte_offset(Gen, method_anc, first_field_name)
|
||
if anc_off is None:
|
||
return ObjVal
|
||
delta: int = sub_off - anc_off
|
||
if delta <= 0:
|
||
return ObjVal
|
||
if method_anc not in Gen.structs:
|
||
return ObjVal
|
||
obj_i8: ir.Value = Gen.builder.bitcast(ObjVal, ir.PointerType(ir.IntType(8)),
|
||
name=f"this_adjust_i8_{method_anc}")
|
||
adj: ir.Value = Gen.builder.gep(obj_i8, [ir.Constant(ir.IntType(64), delta)],
|
||
name=f"this_adjust_{method_anc}")
|
||
return Gen.builder.bitcast(adj, ir.PointerType(Gen.structs[method_anc]),
|
||
name=f"this_adjust_cast_{method_anc}")
|
||
|
||
def _EnsureClassParentsLoaded(self, ClassName: str, Gen: LlvmGeneratorMixin) -> None:
|
||
"""跨模块多继承:class_parents 缺失时从 vpi 按需加载继承信息。
|
||
|
||
调用方(如 HandlesType 委托)引用的类定义在另一模块,其父类
|
||
信息未随 import 填充。_TryLoadClassMembersFromPyi 读取 .vpi 中
|
||
的 ClassDef 并经 _EmitExternalClassDeclLlvm 填充 class_parents,
|
||
使 _get_mro_chain 能沿 MRO 回退到定义类(如 TypeGenMixin)。
|
||
"""
|
||
if not ClassName:
|
||
return
|
||
if Gen.class_parents.get(ClassName):
|
||
return
|
||
# 归一化:ClassName 可能带 sha1 前缀(如 "c9b44d17cd621a75.CallGenLib",
|
||
# 跨模块 structs 表键),而 class_parents / ModuleSha1Map / _struct_sha1_map
|
||
# 的键是裸类名。不剥离则查不到父类 → 继承方法 MRO 回退失效 → fail-fast
|
||
# "Undefined method 'find_func_in_module' in class '...CallGenLib'"。
|
||
lookup_cls: str = ClassName
|
||
if len(ClassName) > 17 and ClassName[16] == '.':
|
||
lookup_cls = ClassName[17:]
|
||
if Gen.class_parents.get(lookup_cls):
|
||
return
|
||
sha1_cls = Gen.ModuleSha1Map.get(lookup_cls)
|
||
if not sha1_cls:
|
||
sha1_cls = getattr(Gen, '_struct_sha1_map', {}).get(lookup_cls)
|
||
if not sha1_cls:
|
||
return
|
||
try:
|
||
self.Trans.ImportHandler._TryLoadClassMembersFromPyi(lookup_cls, f"{sha1_cls}.stub.ll", Gen)
|
||
except Exception:
|
||
pass
|
||
|
||
def _HandleMethodCallLlvm(self, Node: ast.Call) -> ir.Value:
|
||
Gen = self.Trans.LlvmGen
|
||
MethodName = Node.func.attr
|
||
# 检查是否为 @staticmethod 或 @classmethod,如果是则走特殊路径
|
||
if isinstance(Node.func.value, ast.Name):
|
||
VarName = Node.func.value.id
|
||
ClassName = Gen.var_struct_class.get(VarName)
|
||
if ClassName:
|
||
SymKey = f'{ClassName}.{MethodName}'
|
||
SymInfo = self.Trans.SymbolTable.lookup(SymKey)
|
||
if SymInfo and SymInfo.MetaList:
|
||
if FuncMeta.STATIC_METHOD in SymInfo.MetaList:
|
||
return self._HandleStaticMethodCallLlvm(Node, ClassName, MethodName)
|
||
if FuncMeta.CLASS_METHOD in SymInfo.MetaList:
|
||
return self._HandleStaticMethodCallLlvm(Node, ClassName, MethodName)
|
||
if isinstance(Node.func.value, ast.Name) :
|
||
result = self.Trans.TSpecialCallHandle._HandleTSpecialCallLlvm(Node)
|
||
if result is not None:
|
||
return result
|
||
ctype_cls = CTypeRegistry.GetClassByName(MethodName)
|
||
if ctype_cls is not None:
|
||
try:
|
||
ctype_inst = ctype_cls()
|
||
except Exception:
|
||
ctype_inst = None
|
||
target_bits = getattr(ctype_inst, 'Size', None) if ctype_inst else None
|
||
if target_bits is None:
|
||
target_bits = 0
|
||
is_float = getattr(ctype_inst, 'IsSigned', False) is None and target_bits > 0 if ctype_inst else False
|
||
IsPtr_cast = len(Node.args) >= 2 and (
|
||
isinstance(Node.args[1], ast.Name) and Node.args[1].id == 'CPtr'
|
||
)
|
||
if Node.args:
|
||
ArgNode = Node.args[0]
|
||
if isinstance(ArgNode, ast.Subscript):
|
||
SubscriptPtr = self._HandleSubscriptPtrLlvm(ArgNode)
|
||
if SubscriptPtr:
|
||
if MethodName == 'CPtr' or IsPtr_cast:
|
||
return SubscriptPtr
|
||
if isinstance(SubscriptPtr.type, ir.PointerType):
|
||
val = Gen._load(SubscriptPtr, name="Load_subscript_val")
|
||
else:
|
||
val = SubscriptPtr
|
||
if target_bits > 0 and isinstance(val.type, ir.IntType) and not is_float:
|
||
if val.type.width < target_bits:
|
||
val = Gen.builder.zext(val, ir.IntType(target_bits), name="zext_cast")
|
||
elif val.type.width > target_bits:
|
||
val = Gen.builder.trunc(val, ir.IntType(target_bits), name="trunc_cast")
|
||
return val
|
||
val = self.HandleExprLlvm(ArgNode)
|
||
if IsPtr_cast:
|
||
if target_bits > 0 and not is_float:
|
||
target_ptr_type = ir.PointerType(ir.IntType(target_bits))
|
||
elif is_float and target_bits == 32:
|
||
target_ptr_type = ir.PointerType(ir.FloatType())
|
||
elif is_float and target_bits == 64:
|
||
target_ptr_type = ir.PointerType(ir.DoubleType())
|
||
else:
|
||
target_ptr_type = ir.PointerType(ir.IntType(8))
|
||
if isinstance(val.type, ir.PointerType):
|
||
if val.type != target_ptr_type:
|
||
val = Gen.builder.bitcast(val, target_ptr_type, name="ptr_cast")
|
||
elif isinstance(val.type, ir.IntType):
|
||
if val.type.width < 64:
|
||
val = Gen.builder.zext(val, ir.IntType(64), name="zext_ptr_cast")
|
||
val = Gen.builder.inttoptr(val, target_ptr_type, name="int_to_ptr_cast")
|
||
return val
|
||
if val and target_bits > 0 and not is_float:
|
||
if isinstance(val.type, ir.IntType):
|
||
if val.type.width < target_bits:
|
||
val = Gen.builder.zext(val, ir.IntType(target_bits), name="zext_cast")
|
||
elif val.type.width > target_bits:
|
||
val = Gen.builder.trunc(val, ir.IntType(target_bits), name="trunc_cast")
|
||
elif isinstance(val.type, ir.PointerType):
|
||
val = Gen.builder.ptrtoint(val, ir.IntType(target_bits), name="ptrtoint_cast")
|
||
return val
|
||
if is_float:
|
||
return ir.Constant(ir.FloatType() if target_bits == 32 else ir.DoubleType(), 0.0)
|
||
return ir.Constant(ir.IntType(target_bits) if target_bits > 0 else ir.IntType(32), 0)
|
||
if self.Trans.SymbolTable.has(MethodName):
|
||
SymInfo = self.Trans.SymbolTable[MethodName]
|
||
if SymInfo.IsTypedef:
|
||
return self._HandleTypedefCastLlvm(Node, MethodName)
|
||
ObjVal = self.HandleExprLlvm(Node.func.value)
|
||
if not ObjVal:
|
||
return None
|
||
if isinstance(ObjVal.type, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
||
if isinstance(Node.func.value, ast.Name):
|
||
var_name = Node.func.value.id
|
||
if var_name in Gen.variables:
|
||
var_ptr = Gen.variables[var_name]
|
||
if isinstance(var_ptr.type, ir.PointerType) and isinstance(var_ptr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
||
ObjVal = var_ptr
|
||
else:
|
||
tmp = Gen._allocaEntry(ObjVal.type, name="chain_method_tmp")
|
||
Gen._store(ObjVal, tmp)
|
||
ObjVal = tmp
|
||
else:
|
||
tmp = Gen._allocaEntry(ObjVal.type, name="chain_method_tmp")
|
||
Gen._store(ObjVal, tmp)
|
||
ObjVal = tmp
|
||
else:
|
||
tmp = Gen._allocaEntry(ObjVal.type, name="chain_method_tmp")
|
||
Gen._store(ObjVal, tmp)
|
||
ObjVal = tmp
|
||
if isinstance(Node.func.value, ast.Name):
|
||
ModuleName = Node.func.value.id
|
||
imported = getattr(self.Trans, '_ImportedModules', set())
|
||
actual_module = self.Trans.SymbolTable.resolve_alias(ModuleName)
|
||
if (ModuleName in imported or actual_module in imported) and ModuleName not in Gen.var_struct_class:
|
||
mangled_name = Gen._mangle_func_name(MethodName, actual_module)
|
||
if Gen._has_function(mangled_name):
|
||
func = Gen._get_function(mangled_name)
|
||
CallArgs = []
|
||
# 形参类型下传(窄通道):仅影响 CDefine 常量实参的物化宽度。
|
||
_ptypes: list[ir.Type] = func.function_type.args if func is not None else []
|
||
for _ai, arg in enumerate(Node.args):
|
||
_pt: ir.Type | None = _ptypes[_ai] if _ai < len(_ptypes) else None
|
||
# 不再 `if ArgVal: append`(实参求值为空会被静默丢弃 ⇒ 后续整体
|
||
# 前移一格 ⇒ 由 _adjust_args 报出与真因无关的类型不匹配,见
|
||
# _RequireArgValue 的说明)。
|
||
CallArgs.append(self._RequireArgValue(
|
||
self.HandleExprLlvm(
|
||
arg, ConstWidthHint=DefineUseWidthFromLLVMType(_pt)),
|
||
mangled_name, _ai + 1, arg, Node))
|
||
self._fill_default_args(CallArgs, func, MethodName)
|
||
func_ft = getattr(func, 'function_type', None)
|
||
is_variadic = getattr(func_ft, 'var_arg', False) if func_ft else False
|
||
num_fixed_params = len(func_ft.args) if func_ft else 0
|
||
if is_variadic:
|
||
adjusted = []
|
||
for i, arg in enumerate(CallArgs):
|
||
if i < num_fixed_params:
|
||
param_type = func_ft.args[i]
|
||
if arg.type != param_type:
|
||
try:
|
||
if isinstance(arg.type, ir.IntType) and isinstance(param_type, ir.PointerType):
|
||
adjusted.append(self.builder.inttoptr(arg, param_type))
|
||
elif isinstance(arg.type, ir.PointerType) and isinstance(param_type, ir.IntType):
|
||
adjusted.append(Gen.builder.ptrtoint(arg, param_type))
|
||
elif isinstance(arg.type, ir.IntType) and arg.type.width < param_type.width:
|
||
adjusted.append(Gen.builder.zext(arg, param_type))
|
||
else:
|
||
adjusted.append(arg)
|
||
except Exception: # 回退:参数类型调整失败时使用原值
|
||
adjusted.append(arg)
|
||
else:
|
||
adjusted.append(arg)
|
||
else:
|
||
if isinstance(arg.type, ir.FloatType):
|
||
arg = Gen.builder.fpext(arg, ir.DoubleType(), name=f"fpext_vararg_{MethodName}")
|
||
elif isinstance(arg.type, ir.IntType) and arg.type.width < 64:
|
||
if arg.type.width == 1:
|
||
arg = Gen.builder.zext(arg, ir.IntType(64), name=f"zext_bool_vararg_{MethodName}")
|
||
else:
|
||
is_signed = True
|
||
arg_node = Node.args[i] if i < len(Node.args) else None
|
||
if arg_node is not None:
|
||
is_u = Gen._check_node_unsigned(arg_node)
|
||
if is_u:
|
||
is_signed = False
|
||
if is_signed:
|
||
arg = Gen.builder.sext(arg, ir.IntType(64), name=f"sext_vararg_{MethodName}")
|
||
else:
|
||
arg = Gen.builder.zext(arg, ir.IntType(64), name=f"zext_vararg_{MethodName}")
|
||
adjusted.append(arg)
|
||
result = Gen.builder.call(func, adjusted, name=f"call_{MethodName}")
|
||
else:
|
||
# 自动取址已收口到 Gen._adjust_args(唯一汇聚点,按 func.name 查表)。
|
||
adjusted = Gen._adjust_args(CallArgs, func)
|
||
result = Gen.builder.call(func, adjusted, name=f"call_{MethodName}")
|
||
return result
|
||
if Gen._has_function(MethodName):
|
||
_mf = Gen._get_function(MethodName)
|
||
if '.' not in _mf.name:
|
||
CallArgs = []
|
||
# 形参类型下传(窄通道):仅影响 CDefine 常量实参的物化宽度。
|
||
_ptypes: list[ir.Type] = _mf.function_type.args
|
||
for _ai, arg in enumerate(Node.args):
|
||
_pt: ir.Type | None = _ptypes[_ai] if _ai < len(_ptypes) else None
|
||
# 同 3357:禁止静默丢弃求值为空的实参(会导致后续前移一格)
|
||
CallArgs.append(self._RequireArgValue(
|
||
self.HandleExprLlvm(
|
||
arg, ConstWidthHint=DefineUseWidthFromLLVMType(_pt)),
|
||
MethodName, _ai + 1, arg, Node))
|
||
func = _mf
|
||
self._fill_default_args(CallArgs, func, MethodName)
|
||
func_ft = getattr(func, 'function_type', None)
|
||
is_variadic = getattr(func_ft, 'var_arg', False) if func_ft else False
|
||
num_fixed_params = len(func_ft.args) if func_ft else 0
|
||
if is_variadic:
|
||
adjusted = []
|
||
for i, arg in enumerate(CallArgs):
|
||
if i < num_fixed_params:
|
||
param_type = func_ft.args[i]
|
||
if arg.type != param_type:
|
||
try:
|
||
if isinstance(arg.type, ir.IntType) and isinstance(param_type, ir.PointerType):
|
||
adjusted.append(self.builder.inttoptr(arg, param_type))
|
||
elif isinstance(arg.type, ir.PointerType) and isinstance(param_type, ir.IntType):
|
||
adjusted.append(Gen.builder.ptrtoint(arg, param_type))
|
||
elif isinstance(arg.type, ir.IntType) and arg.type.width < param_type.width:
|
||
adjusted.append(Gen.builder.zext(arg, param_type))
|
||
else:
|
||
adjusted.append(arg)
|
||
except Exception: # 回退:参数类型调整失败时使用原值
|
||
adjusted.append(arg)
|
||
else:
|
||
adjusted.append(arg)
|
||
else:
|
||
if isinstance(arg.type, ir.FloatType):
|
||
arg = Gen.builder.fpext(arg, ir.DoubleType(), name=f"fpext_vararg_{MethodName}")
|
||
elif isinstance(arg.type, ir.IntType) and arg.type.width < 64:
|
||
if arg.type.width == 1:
|
||
arg = Gen.builder.zext(arg, ir.IntType(64), name=f"zext_bool_vararg_{MethodName}")
|
||
else:
|
||
is_signed = True
|
||
arg_node = Node.args[i] if i < len(Node.args) else None
|
||
if arg_node is not None:
|
||
is_u = Gen._check_node_unsigned(arg_node)
|
||
if is_u:
|
||
is_signed = False
|
||
if is_signed:
|
||
arg = Gen.builder.sext(arg, ir.IntType(64), name=f"sext_vararg_{MethodName}")
|
||
else:
|
||
arg = Gen.builder.zext(arg, ir.IntType(64), name=f"zext_vararg_{MethodName}")
|
||
adjusted.append(arg)
|
||
result = Gen.builder.call(func, adjusted, name=f"call_{MethodName}")
|
||
else:
|
||
# 自动取址已收口到 Gen._adjust_args(唯一汇聚点,按 func.name 查表)。
|
||
adjusted = Gen._adjust_args(CallArgs, func)
|
||
result = Gen.builder.call(func, adjusted, name=f"call_{MethodName}")
|
||
return result
|
||
stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(mangled_name, Gen)
|
||
if not stub_func_type:
|
||
stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(MethodName, Gen)
|
||
if not stub_func_type and mangled_name != MethodName:
|
||
for sha1 in getattr(Gen, 'ModuleSha1Map', {}).values():
|
||
alt_name = f"{sha1}.{MethodName}"
|
||
stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(alt_name, Gen)
|
||
if stub_func_type:
|
||
mangled_name = alt_name
|
||
break
|
||
if stub_func_type:
|
||
func = self.GetOrCreateStubFuncDecl(mangled_name, stub_func_type, Gen)
|
||
CallArgs = []
|
||
# 形参类型下传(窄通道):仅影响 CDefine 常量实参的物化宽度。
|
||
_ptypes: list[ir.Type] = func.function_type.args if func is not None else []
|
||
for _ai, arg in enumerate(Node.args):
|
||
_pt: ir.Type | None = _ptypes[_ai] if _ai < len(_ptypes) else None
|
||
# 同 3357:禁止静默丢弃求值为空的实参(会导致后续前移一格)
|
||
CallArgs.append(self._RequireArgValue(
|
||
self.HandleExprLlvm(
|
||
arg, ConstWidthHint=DefineUseWidthFromLLVMType(_pt)),
|
||
mangled_name, _ai + 1, arg, Node))
|
||
self._fill_default_args(CallArgs, func, mangled_name)
|
||
self._append_eh_msg_out_arg(CallArgs, func, Gen)
|
||
# 自动取址已收口到 Gen._adjust_args(唯一汇聚点,按 func.name 查表)。
|
||
adjusted = Gen._adjust_args(CallArgs, func)
|
||
result = Gen.builder.call(func, adjusted, name=f"call_{MethodName}")
|
||
self._check_eh_return(result, mangled_name, Gen, called_func=func)
|
||
return result
|
||
return ir.Constant(ir.IntType(32), 0)
|
||
CallArgs = []
|
||
for _ai, arg in enumerate(Node.args):
|
||
# 同 3357:禁止静默丢弃求值为空的实参(会导致后续整体前移一格)
|
||
CallArgs.append(self._RequireArgValue(
|
||
self.HandleExprLlvm(arg), self._ExprText(Node.func), _ai + 1, arg, Node))
|
||
ClassName = None
|
||
if isinstance(Node.func.value, ast.Name):
|
||
ClassName = Gen.var_struct_class.get(Node.func.value.id)
|
||
if not ClassName and isinstance(Node.func.value, ast.Attribute):
|
||
# 链式属性访问(如 func.Params.append):通过 _get_var_class 推导泛型特化类名
|
||
ClassName = self.Trans.ExprHandler._get_var_class(Node.func.value, Gen)
|
||
if not ClassName:
|
||
for CN, ST in Gen.structs.items():
|
||
if isinstance(ObjVal.type, ir.PointerType) and ObjVal.type.pointee == ST:
|
||
ClassName = CN
|
||
break
|
||
if not ClassName and self._is_char_pointer(ObjVal):
|
||
MethodName = Node.func.attr
|
||
# FakeDuck: 检查是否有影子结构体 a__meta__ (per-instance 字段存储)
|
||
meta_ptr: ir.Value | None = None
|
||
if isinstance(Node.func.value, ast.Name):
|
||
meta_name = f"{Node.func.value.id}__meta__"
|
||
if meta_name in Gen.variables:
|
||
meta_ptr = Gen.variables[meta_name]
|
||
for CN, ST in Gen.structs.items():
|
||
method_key = f'{CN}.{MethodName}'
|
||
if not Gen._has_function(method_key):
|
||
continue
|
||
# FakeDuck: 不跳过空结构体 (扩展类可能没有数据成员只有方法)
|
||
try:
|
||
# 如果有影子结构体且该类有字段, 使用影子结构体作为 self (而非 bitcast char*)
|
||
if meta_ptr is not None and hasattr(ST, 'elements') and len(ST.elements) > 0:
|
||
ObjVal = meta_ptr
|
||
elif CN == '_str' and hasattr(ST, 'elements') and len(ST.elements) > 0:
|
||
# FakeDuck: 字符串字面量/匿名 str 表达式调用 _str 方法时,
|
||
# 创建临时影子结构体 (栈上), 设置 __data__ 和 __mbuddy__ 字段。
|
||
# bitcast i8* → _str* 会导致读取垃圾指针 → ACCESS_VIOLATION
|
||
tmp_meta: ir.AllocaInstr = Gen._allocaEntry(ST, name="tmp_str_meta")
|
||
_data_off = Gen._get_member_offset('__data__', '_str')
|
||
if _data_off is not None:
|
||
_data_ptr = Gen.builder.gep(tmp_meta, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), _data_off)], name="tmp_str_data")
|
||
Gen._store(ObjVal, _data_ptr)
|
||
_mpool_off = Gen._get_member_offset('__mbuddy__', '_str')
|
||
if _mpool_off is not None:
|
||
_mpool_ptr = Gen.builder.gep(tmp_meta, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), _mpool_off)], name="tmp_str_mbuddy")
|
||
Gen._store(ir.Constant(ir.PointerType(ir.IntType(8)), None), _mpool_ptr)
|
||
# 从 with 上下文自动注入 requires 字段 (如 __mbuddy__)
|
||
self._InjectRequiresFields(tmp_meta, '_str', Gen)
|
||
ObjVal = tmp_meta
|
||
else:
|
||
casted = Gen.builder.bitcast(ObjVal, ir.PointerType(ST), name=f"cast_{CN}")
|
||
ObjVal = casted
|
||
ClassName = CN
|
||
break
|
||
except Exception: # 回退:bitcast 失败时尝试下一个类
|
||
continue
|
||
if not ClassName and isinstance(Node.func.value, ast.Call):
|
||
if isinstance(Node.func.value.func, ast.Attribute):
|
||
InnerAttrName = Node.func.value.func.attr
|
||
for CN in Gen.structs:
|
||
if CN.endswith(f'__{InnerAttrName}') or f'__{InnerAttrName}' in CN:
|
||
continue
|
||
method_name = f'{CN}__{InnerAttrName}'
|
||
if Gen._has_function(method_name):
|
||
func = Gen._get_function(method_name)
|
||
ret_type = func.fnty.return_type
|
||
if isinstance(ret_type, ir.PointerType):
|
||
for CN2, ST in Gen.structs.items():
|
||
if ret_type.pointee == ST:
|
||
ClassName = CN2
|
||
break
|
||
elif isinstance(ret_type, ir.IdentifiedStructType):
|
||
for CN2, ST in Gen.structs.items():
|
||
if ret_type == ST:
|
||
ClassName = CN2
|
||
break
|
||
if ClassName:
|
||
break
|
||
if not ClassName:
|
||
return ir.Constant(ir.IntType(32), 0)
|
||
# REnum.kind() 编译期转 __tag 读取(位置 0,i32):
|
||
# REnum 无 kind 方法(源码无、编译器不生成),此前 .kind() 被"兄弟 Mixin
|
||
# 兜底"(L3203-3240)误绑到 AST.kind(this 前移 sizeof=-48,语义错误)。
|
||
# 此处把 kind() 直接翻译为 bitcast 到 i32* + load —— 零函数调用,
|
||
# 返回变体 tag,与 match 读 __tag 语义一致。
|
||
if MethodName == 'kind':
|
||
_renum_nm: str = ClassName[17:] if (len(ClassName) > 17 and ClassName[16] == '.') else ClassName
|
||
if '.' in _renum_nm: # 模块限定名 "llvmlite.LLVMType" → 裸名
|
||
_renum_nm = _renum_nm.rsplit('.', 1)[1]
|
||
_renum_info: Any = self.Trans.SymbolTable.lookup(_renum_nm) if _renum_nm else None
|
||
if _renum_info is not None and getattr(_renum_info, 'IsRenum', False):
|
||
if isinstance(ObjVal.type, ir.PointerType):
|
||
_kind_ptr: ir.Value = Gen.builder.bitcast(
|
||
ObjVal, ir.PointerType(ir.IntType(32)), name="renum_kind_ptr")
|
||
return Gen._load(_kind_ptr, name="renum_kind")
|
||
# 泛型特化定位:当 ClassName 是 opaque 基础名(如 'ndarray'/'list',不含 '[')
|
||
# 时,按【接收者 LLVM 值类型】反查唯一的具体特化,而不再遍历 Gen.structs 按
|
||
# 迭代顺序任选一个 'ClassName[' 开头的特化——任选会命中 list[int] 之类元素
|
||
# 类型错误的特化,方法返回 i32 被 inttoptr 当指针 → 运行期崩溃。
|
||
if '[' not in ClassName:
|
||
SpecClass: str | None = None
|
||
# 1) 以接收者 LLVM 值类型的 pointee 结构体反查真实类名(唯一解)。
|
||
_recv_found: tuple[str, ir.IdentifiedStructType] | None = None
|
||
_recv_type: Any = getattr(ObjVal, 'type', None)
|
||
if isinstance(_recv_type, ir.PointerType):
|
||
_recv_found = Gen.find_struct_by_pointee(_recv_type.pointee)
|
||
if _recv_found is not None and '[' in _recv_found[0]:
|
||
SpecClass = _recv_found[0]
|
||
# 2) 接收者实型无法唯一确定具体特化(裸泛型基类 / 反查不到结构体):
|
||
# 仅当「基名匹配 + 该类型下存在目标方法」的特化唯一时才采用;存在
|
||
# 多个候选 ⇒ fail-fast(禁止按 Gen.structs 顺序任选)。0 个候选表示
|
||
# 该基名下没有任何带此方法的特化(普通非泛型类方法调用路径),保持
|
||
# ClassName 不变、交由后续常规分派。
|
||
if SpecClass is None:
|
||
_base_src: str = _recv_found[0] if _recv_found is not None else ClassName
|
||
_base_short: str = Gen._extract_short_name(_base_src)
|
||
_cands: list[str] = []
|
||
for CN in Gen.structs.keys():
|
||
if '[' not in CN or CN.split('.')[-1].split('[')[0] != _base_short:
|
||
continue
|
||
struct_sha1_tmp = getattr(Gen, '_struct_sha1_map', {}).get(CN)
|
||
if struct_sha1_tmp and Gen._has_function(f'{struct_sha1_tmp}.{CN}.{MethodName}'):
|
||
_cands.append(CN)
|
||
elif Gen._has_function(f'{CN}.{MethodName}'):
|
||
_cands.append(CN)
|
||
if len(_cands) == 1:
|
||
SpecClass = _cands[0]
|
||
elif len(_cands) > 1:
|
||
raise Exception(
|
||
f"方法调用 '{MethodName}' 的接收者无法唯一确定泛型特化:"
|
||
f"基名 '{_base_short}' 下存在多个带该方法的结构体 {_cands},"
|
||
f"禁止按 Gen.structs 顺序任选(会分派到错误元素类型)。")
|
||
if SpecClass:
|
||
ClassName = SpecClass
|
||
struct_sha1_map = getattr(Gen, '_struct_sha1_map', {})
|
||
# 归一化:ClassName 可能带 sha1 前缀(跨模块 structs 表键,如
|
||
# "940e5294667daf5a.ExprGenAttr"),其前 16 位即模块 sha1,直接用作
|
||
# class_sha1 并免拼接(否则 struct_sha1_map.get(带前缀名)=None → class_sha1
|
||
# 为空 → 下方 stub 查找路径被跳过 → fail-fast "Undefined method
|
||
# 'get_attribute_ptr' in class '...ExprGenAttr'")。裸类名则从映射表取 sha1。
|
||
cls_has_prefix: bool = len(ClassName) > 17 and ClassName[16] == '.'
|
||
if cls_has_prefix:
|
||
class_sha1 = ClassName[:16]
|
||
FullMethodName = f'{ClassName}.{MethodName}'
|
||
else:
|
||
class_sha1 = struct_sha1_map.get(ClassName)
|
||
if class_sha1:
|
||
FullMethodName = f'{class_sha1}.{ClassName}.{MethodName}'
|
||
else:
|
||
FullMethodName = f'{ClassName}.{MethodName}'
|
||
|
||
# 泛型特化类方法按需完整特化:当 ClassName 是特化名(如 ndarray[double])
|
||
# 且缓存中只有 declare_only 版本时,补发方法体。否则方法调用会查找
|
||
# stub declare(无 define),链接时报 undefined reference。
|
||
self._try_complete_generic_specialization(ClassName, MethodName, Gen)
|
||
|
||
# 提前查找函数以获取参数信息
|
||
func_for_kw = Gen._find_function(FullMethodName)
|
||
if not func_for_kw:
|
||
func_for_kw = Gen._find_function(f'{FullMethodName}__')
|
||
if not func_for_kw and class_sha1:
|
||
func_for_kw = Gen._find_function(f'{ClassName}.{MethodName}')
|
||
|
||
# 处理关键字参数: 先用 _fill_default_args 填充默认值,再用 keyword args 覆盖
|
||
if Node.keywords and func_for_kw:
|
||
# 优先从全局参数名表获取 Python 参数名(支持跨模块 include 函数)
|
||
global_param_names = getattr(self.Trans, '_global_function_param_names', {})
|
||
param_names = global_param_names.get(FullMethodName)
|
||
if not param_names:
|
||
param_names = global_param_names.get(f'{ClassName}.{MethodName}')
|
||
if not param_names:
|
||
# 回退到 LLVM 函数参数名(仅当参数名不是自动生成的数字名时有效)
|
||
llvm_names = [arg.name for arg in func_for_kw.args] if func_for_kw.args else []
|
||
# 检测是否为 LLVM 自动生成的数字名(如 "0", "1", "2")
|
||
if llvm_names and not all(n.isdigit() for n in llvm_names):
|
||
param_names = llvm_names
|
||
if param_names:
|
||
# 构造临时 call_args (含 self) 调用 _fill_default_args 填充默认值
|
||
temp_call_args = [ObjVal] + list(CallArgs)
|
||
self._fill_default_args(temp_call_args, func_for_kw, FullMethodName)
|
||
# 提取回非 self 参数 (现在已填充默认值)
|
||
CallArgs.clear()
|
||
CallArgs.extend(temp_call_args[1:])
|
||
# 用 keyword args 覆盖对应位置
|
||
for kw in Node.keywords:
|
||
if kw.arg is None:
|
||
continue
|
||
ArgVal = self.HandleExprLlvm(kw.value)
|
||
if not ArgVal:
|
||
continue
|
||
kw_name = kw.arg
|
||
if kw_name in param_names:
|
||
idx = param_names.index(kw_name)
|
||
# idx 0 是 self, 所以 CallArgs 中的偏移是 idx-1
|
||
target_idx = idx - 1
|
||
if 0 <= target_idx < len(CallArgs):
|
||
CallArgs[target_idx] = ArgVal
|
||
|
||
# 按需 vtable 注册:当 ClassName 不在 vtable 集合中但有 class_sha1 时,
|
||
# 从 .pyi stub 检查 @CVTable 装饰器并注册。
|
||
# 修复场景:list[str].__new__ 中 pool.alloc(48) 编译时,
|
||
# MemManager 可能因导入时序问题未注册到当前 Gen 的 vtable 集合,
|
||
# 导致生成 call_(直接调用)而非 vcall_(虚分派),运行时段错误。
|
||
if (ClassName not in Gen.class_vtable
|
||
and ClassName not in Gen._cross_module_vtable_classes
|
||
and class_sha1):
|
||
self._try_register_vtable_ondemand(ClassName, class_sha1, Gen)
|
||
# 跨模块多继承:确保 class_parents 可用(MRO 回退需要),
|
||
# 如 HandlesType 委托调用 Generator 的方法(定义类在 TypeGenMixin)。
|
||
self._EnsureClassParentsLoaded(ClassName, Gen)
|
||
|
||
if (ClassName in Gen.class_vtable or ClassName in Gen._cross_module_vtable_classes) and ClassName in Gen.class_methods:
|
||
# 根本修复:vtable 分派要求接收者 struct 已具化。元数据(vtable 集合 /
|
||
# class_methods)与 struct body 可能因并行 include 翻译时序撕裂——
|
||
# _try_register_vtable_ondemand 只注册元数据不具化 body,若此时 struct
|
||
# 仍 opaque,下方 GEP [0,0] 取 vtable 指针会抛 llvmlite 裸 TypeError
|
||
# (典型:list[AST|CPtr].append 中 self.__pool__.alloc(...),
|
||
# __pool__ 类型 memhub.MemManager|CPtr,MemManager 已进 vtable 集合
|
||
# 但 struct body 未从 stub 具化)。
|
||
# 此处先主动具化(stub + class_members 双路径),仍失败则 fail-fast
|
||
# 暴露上游 stub 加载时序问题,而非静默崩溃。
|
||
ObjVal = self._EnsureReceiverStructConcrete(ClassName, class_sha1, ObjVal, Gen)
|
||
methods = Gen.class_methods[ClassName]
|
||
method_idx = -1
|
||
for mi, mn in enumerate(methods):
|
||
if mn == FullMethodName or mn == MethodName or mn.endswith(f'.{MethodName}'):
|
||
method_idx = mi
|
||
break
|
||
if method_idx >= 0:
|
||
func = Gen._find_function(FullMethodName)
|
||
# 方法实际定义类(多继承 this 调整用,None=本类或未知)
|
||
method_anc: str | None = None
|
||
# 仅当无函数或只有 stub 声明(无函数体)时,沿 MRO 祖先链回退,
|
||
# 否则 stub 会挡住回退导致 this 调整失效(与直接调用路径一致)
|
||
if not func or len(list(func.blocks)) == 0:
|
||
func = Gen._find_function(f'{FullMethodName}__')
|
||
if not func or len(list(func.blocks)) == 0:
|
||
# 多继承:沿 MRO 祖先链查找定义类方法(先声明父类优先)
|
||
for anc in Gen._get_mro_chain(ClassName)[1:]:
|
||
parent_full = f'{anc}.{MethodName}'
|
||
func = Gen._find_function(parent_full)
|
||
if not func:
|
||
func = Gen._find_function(f'{parent_full}__')
|
||
if func:
|
||
method_anc = anc
|
||
break
|
||
# 修复:vtable 分派需要 func 的函数类型。当 func=None 时(如 __new__
|
||
# 编译较早,MemManager.alloc 的 declare 尚未加入 Gen.functions),
|
||
# 从 stub 获取函数类型并创建 declare,确保 vtable 分派不被跳过
|
||
# 回退到直接调用(直接调用基类 MemManager.alloc 返回 NULL → 段错误)。
|
||
if not func and class_sha1:
|
||
stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(FullMethodName, Gen)
|
||
if stub_func_type:
|
||
func = self.GetOrCreateStubFuncDecl(FullMethodName, stub_func_type, Gen)
|
||
if not func and class_sha1:
|
||
plain_name = f'{ClassName}.{MethodName}'
|
||
stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(plain_name, Gen)
|
||
if stub_func_type:
|
||
func = self.GetOrCreateStubFuncDecl(FullMethodName, stub_func_type, Gen)
|
||
if not func:
|
||
plain_name = f'{ClassName}.{MethodName}'
|
||
func = Gen._find_function(plain_name)
|
||
if func:
|
||
# 多继承 this 调整:继承方法定义在无 vtable 父类且字段区偏移 > 0 时,
|
||
# 把 self 定位到父类第一个用户字段在子类中的位置并 bitcast 成父类指针。
|
||
# receiver 为 i8*/泛型指针(CVTable 抽象基类如 ast.AST 无独立
|
||
# struct 类型、联合字段存储为 i8*)时 vtable 槽恒在对象偏移 0:
|
||
# bitcast 到 ClassName 的 struct(无则建 opaque 占位)再 GEP,
|
||
# 否则 gep(i8) 报 "'IntType' object has no attribute 'gep'"。
|
||
if (isinstance(ObjVal.type, ir.PointerType)
|
||
and not isinstance(ObjVal.type.pointee,
|
||
(ir.IdentifiedStructType, ir.LiteralStructType))):
|
||
_vt_st_rc: ir.Type = Gen.structs.get(ClassName)
|
||
if _vt_st_rc is None:
|
||
_vt_st_rc = Gen._get_or_create_struct(ClassName)
|
||
ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(_vt_st_rc),
|
||
name=f"vt_cast_{ClassName}")
|
||
self_arg = self._adjust_this_for_inherited_method(Gen, ObjVal, ClassName, method_anc)
|
||
VtableSlotPtr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"vtable_slot_{ClassName}")
|
||
VtablePtr = Gen._load(VtableSlotPtr, name=f"vtable_ptr_{ClassName}")
|
||
VtableArrayType = ir.ArrayType(ir.PointerType(ir.IntType(8)), len(methods))
|
||
VtableTyped = Gen.builder.bitcast(VtablePtr, ir.PointerType(VtableArrayType), name=f"vtable_typed_{ClassName}")
|
||
MethodPtrAddr = Gen.builder.gep(VtableTyped, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), method_idx)], name=f"vmethod_ptr_addr_{MethodName}")
|
||
MethodPtrI8 = Gen._load(MethodPtrAddr, name=f"vmethod_ptr_{MethodName}")
|
||
FuncPtrType = ir.PointerType(func.function_type)
|
||
MethodPtrTyped = Gen.builder.bitcast(MethodPtrI8, FuncPtrType, name=f"vmethod_typed_{MethodName}")
|
||
call_args = [self_arg] + CallArgs
|
||
self._fill_default_args(call_args, func, FullMethodName)
|
||
self._append_eh_msg_out_arg(call_args, func, Gen)
|
||
adjusted = Gen._adjust_args(call_args, func)
|
||
result = Gen.builder.call(MethodPtrTyped, adjusted, name=f"vcall_{FullMethodName}")
|
||
self._check_eh_return(result, FullMethodName, Gen, called_func=func)
|
||
return result
|
||
func = Gen._find_function(FullMethodName)
|
||
# 方法实际定义类(多继承 this 调整用,None=本类或未知)
|
||
method_anc: str | None = None
|
||
if not func:
|
||
func = Gen._find_function(f'{FullMethodName}__')
|
||
if not func and class_sha1:
|
||
stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(FullMethodName, Gen)
|
||
if stub_func_type:
|
||
func = self.GetOrCreateStubFuncDecl(FullMethodName, stub_func_type, Gen)
|
||
if not func and class_sha1:
|
||
plain_name = f'{ClassName}.{MethodName}'
|
||
stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(plain_name, Gen)
|
||
if stub_func_type:
|
||
func = self.GetOrCreateStubFuncDecl(FullMethodName, stub_func_type, Gen)
|
||
# 最终回退:尝试无 sha1 前缀的函数名(与 func_for_kw 的双路径回退一致)
|
||
if not func:
|
||
plain_name = f'{ClassName}.{MethodName}'
|
||
func = Gen._find_function(plain_name)
|
||
# 若 FullMethodName 只有 stub 声明(无函数体),也走 MRO 回退找定义类方法
|
||
if not func or len(list(func.blocks)) == 0:
|
||
# 多继承:沿 MRO 祖先链查找定义类方法(先声明父类优先),
|
||
# 继承方法用"定义类.方法"(如 B.get_b)直接调用,不再依赖子类包装器。
|
||
for anc in Gen._get_mro_chain(ClassName)[1:]:
|
||
anc_full = f'{anc}.{MethodName}'
|
||
func = Gen._find_function(anc_full)
|
||
if not func:
|
||
func = Gen._find_function(f'{anc_full}__')
|
||
if func:
|
||
method_anc = anc
|
||
break
|
||
if not func or len(list(func.blocks)) == 0:
|
||
# 兄弟 Mixin 兜底:仅当"调用类自身未声明该方法"时启用。
|
||
# 判断依据 class_methods[ClassName]:
|
||
# * BaseB.caller 调 self.helper()——BaseB 无 helper(源码未定义)
|
||
# → 跨 Mixin → 在其它注册类中找定义类(BaseA.helper)✓
|
||
# * JsonValue.__getitem__ 源码定义存在但 stub 未命中(如 VPC 自身
|
||
# 编译 Config.vp 时跨模块 stub 注册/时序问题)→ 不兜底,
|
||
# fail-fast(Undefined method)暴露上游 stub 问题——避免误绑
|
||
# 无关类 HashTable.__getitem__(this 前移 sizeof(HashTable)=-48
|
||
# → Load_project_config 读 -1 崩溃,1.LOG 根因;3fd875d 只
|
||
# 过滤 list 特化,普通类仍被误绑)。
|
||
# 注:不能用 MRO/组合类判断(Combined 定义在 BaseB 之后,BaseB.caller
|
||
# 翻译时组合类未注册,MRO 查询不可靠——780cd4a 引入 NoVTable 回归)。
|
||
_self_has_method: bool = False
|
||
_cm_map = getattr(Gen, 'class_methods', None)
|
||
if isinstance(_cm_map, dict):
|
||
_self_methods = _cm_map.get(ClassName)
|
||
if _self_methods:
|
||
for _sm in _self_methods:
|
||
if _sm == MethodName or _sm.endswith(f'.{MethodName}'):
|
||
_self_has_method = True
|
||
break
|
||
if not _self_has_method:
|
||
for _cand_cls, _cand_methods in list(Gen.class_methods.items()):
|
||
if _cand_cls == ClassName:
|
||
continue
|
||
if '[' in _cand_cls:
|
||
continue
|
||
if not any(_cm.endswith(f'.{MethodName}') or _cm == MethodName for _cm in _cand_methods):
|
||
continue
|
||
_cand_full = f'{_cand_cls}.{MethodName}'
|
||
_cand_func = Gen._find_function(_cand_full)
|
||
if not _cand_func:
|
||
_cand_func = Gen._find_function(f'{_cand_full}__')
|
||
if _cand_func:
|
||
func = _cand_func
|
||
method_anc = _cand_cls
|
||
break
|
||
if func:
|
||
# 多继承 this 调整:继承方法定义在无 vtable 父类且字段区偏移 > 0 时,
|
||
# 把 self 定位到父类第一个用户字段在子类中的位置并 bitcast 成父类指针。
|
||
self_arg = self._adjust_this_for_inherited_method(Gen, ObjVal, ClassName, method_anc)
|
||
call_args = [self_arg] + CallArgs
|
||
self._fill_default_args(call_args, func, FullMethodName)
|
||
self._append_eh_msg_out_arg(call_args, func, Gen)
|
||
# 自动取址已收口到 Gen._adjust_args(唯一汇聚点,按 func.name 查表)。
|
||
adjusted = Gen._adjust_args(call_args, func)
|
||
result = Gen.builder.call(func, adjusted, name=f"call_{FullMethodName}")
|
||
self._check_eh_return(result, FullMethodName, Gen, called_func=func)
|
||
return result
|
||
i8ptr = ir.PointerType(ir.IntType(8))
|
||
member_idx = -1
|
||
if ClassName in Gen.class_members:
|
||
for mi, (mn, mt) in enumerate(Gen.class_members[ClassName]):
|
||
if mn == MethodName:
|
||
member_idx = mi
|
||
break
|
||
if member_idx >= 0 and isinstance(ObjVal.type, ir.PointerType):
|
||
# base(vtable 占位槽数)统一走 Gen._member_base(唯一真源)。
|
||
base = Gen._member_base(ClassName)
|
||
member_ptr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), base + member_idx)], name=f"funcptr_{MethodName}_ptr")
|
||
raw_ptr = Gen._load(member_ptr, name=f"funcptr_{MethodName}_raw")
|
||
func_ptr_type = ir.PointerType(ir.FunctionType(ir.IntType(32), [i8ptr] + [a.type for a in CallArgs]))
|
||
typed_ptr = Gen.builder.bitcast(raw_ptr, func_ptr_type, name=f"funcptr_{MethodName}_typed")
|
||
obj_as_i8 = Gen.builder.bitcast(ObjVal, i8ptr, name=f"funcptr_self_{ClassName}")
|
||
call_args = [obj_as_i8] + CallArgs
|
||
result = Gen.builder.call(typed_ptr, call_args, name=f"call_funcptr_{ClassName}.{MethodName}")
|
||
return result
|
||
if class_sha1 and ClassName in Gen.structs:
|
||
struct_type = Gen.structs[ClassName]
|
||
self_ptr_type = ir.PointerType(struct_type)
|
||
# 修复 Bug 4: 从符号表获取完整参数列表(含默认参数)和正确返回类型,
|
||
# 而非仅使用 CallArgs(漏掉默认参数)和硬编码 i32 返回类型。
|
||
# 这避免了 main.py 中 declare Logger.info(...,i8*) (2参数)
|
||
# 与 VLogger 中 define Logger.info(...,i8*,i8*) (3参数)的签名冲突。
|
||
ret_type: Any = ir.IntType(32)
|
||
param_types: list[Any] = [self_ptr_type] + [a.type for a in CallArgs]
|
||
SymInfoFallback = self.LookupFunctionSymbol(MethodName, module_path=ClassName)
|
||
if SymInfoFallback and SymInfoFallback.IsFunction:
|
||
sig = self.BuildLLVMFuncTypeFromSig(SymInfoFallback, Gen)
|
||
if sig is not None:
|
||
sig_ret, sig_params, _ = sig
|
||
ret_type = sig_ret
|
||
is_static_fb = FuncMeta.STATIC_METHOD in SymInfoFallback.MetaList
|
||
if not is_static_fb:
|
||
sig_params = [self_ptr_type] + sig_params
|
||
param_types = sig_params
|
||
func_type = ir.FunctionType(ret_type, param_types)
|
||
# 复用已存在的声明(vpi 合并/LoadDepVpiIntoModule 可能已注册同名 declare),
|
||
# 避免 llvmlite DuplicatedNameError(如 gen.__init__ / ImportsHandle.HandleImport)
|
||
func = Gen._find_function(FullMethodName)
|
||
if func is None:
|
||
# 走唯一幂等入口(module.globals 同名函数复用 / 类型冲突 fail-fast),
|
||
# 不再裸建 ir.Function —— Guard 只看 Gen.functions 时漏掉
|
||
# module.globals 已有声明会抛 llvmlite DuplicatedNameError。
|
||
func = Gen._CreateOrReuseFuncDecl(FullMethodName, func_type)
|
||
if isinstance(ObjVal.type, ir.PointerType) and ObjVal.type.pointee == struct_type:
|
||
call_self = ObjVal
|
||
else:
|
||
call_self = Gen.builder.bitcast(ObjVal, self_ptr_type, name=f"method_self_{ClassName}")
|
||
call_args_fb = [call_self] + CallArgs
|
||
self._fill_default_args(call_args_fb, func, FullMethodName)
|
||
self._append_eh_msg_out_arg(call_args_fb, func, Gen)
|
||
adjusted = Gen._adjust_args(call_args_fb, func)
|
||
result = Gen.builder.call(func, adjusted, name=f"call_{FullMethodName}")
|
||
return result
|
||
raise Exception(f"Undefined method '{MethodName}' in class '{ClassName}' (no function declaration found for '{FullMethodName}')")
|
||
|
||
def _EnsureReceiverStructConcrete(self, ClassName: str, class_sha1: str | None, ObjVal: Any, Gen: "LlvmGeneratorMixin") -> Any:
|
||
"""根本修复:vtable 分派前保证接收者 struct 已具化(非 opaque)。
|
||
|
||
背景:跨模块类的 vtable 元数据(class_vtable / _cross_module_vtable_classes /
|
||
class_methods)由 _precollect_vtable_state 预扫描或 _try_register_vtable_ondemand
|
||
按需注册,而 struct body 依赖 _TryLoadStructFromStub 从 stub.ll 加载。
|
||
二者时序可能撕裂:body 仍 opaque 就对 struct 做 GEP [0,0] 取 vtable 指针,
|
||
llvmlite 在 types.py 的 elements[i] 处抛裸 TypeError('NoneType' object is
|
||
not subscriptable)。
|
||
|
||
本方法:
|
||
1. 先走 stub.ll 补 body(source_sha1 精确匹配优先)
|
||
2. 再补 class_members(供 _generate_structs 用成员构造 body 的备选路径)
|
||
3. 若 Gen.structs 中已具化版本与 ObjVal 指向的 opaque 占位对象不同,
|
||
bitcast 替换 ObjVal 到具体版本
|
||
4. 仍 opaque → fail-fast 报带源码上下文的编译错误(遵循"不兜底"原则,
|
||
暴露上游 stub 加载/时序问题而非让 llvmlite 裸崩)
|
||
|
||
Returns:
|
||
ObjVal 本身或 bitcast 到具体 struct 版本后的新值。
|
||
"""
|
||
if not isinstance(ObjVal.type, ir.PointerType):
|
||
return ObjVal
|
||
pointee: ir.Type = ObjVal.type.pointee
|
||
if not isinstance(pointee, ir.IdentifiedStructType) or not pointee.is_opaque:
|
||
return ObjVal
|
||
|
||
import_handler: Any = self.Trans.ImportHandler
|
||
# 1) stub.ll 补 body(source_sha1 精确匹配优先)
|
||
if class_sha1:
|
||
import_handler._TryLoadStructFromStub(ClassName, Gen, source_sha1=class_sha1)
|
||
else:
|
||
import_handler._TryLoadStructFromStub(ClassName, Gen)
|
||
# 2) 补 class_members(备选具化路径)
|
||
stub_basename: str = f'{class_sha1}.stub.ll' if class_sha1 else f'{ClassName}.stub.ll'
|
||
import_handler._TryLoadClassMembersFromPyi(ClassName, stub_basename, Gen)
|
||
|
||
# 3) 从 Gen.structs 找已具化版本(短名优先,再按 sha1 全名)
|
||
concrete_st: ir.IdentifiedStructType | None = None
|
||
_st_short: Any = Gen.structs.get(ClassName)
|
||
if isinstance(_st_short, ir.IdentifiedStructType) and not _st_short.is_opaque:
|
||
concrete_st = _st_short
|
||
if concrete_st is None and class_sha1:
|
||
_st_full: Any = Gen.structs.get(f'{class_sha1}.{ClassName}')
|
||
if isinstance(_st_full, ir.IdentifiedStructType) and not _st_full.is_opaque:
|
||
concrete_st = _st_full
|
||
if concrete_st is None:
|
||
# 4) 仍 opaque → fail-fast(暴露上游 stub 加载/时序问题)
|
||
raise Exception(
|
||
f"vtable 分派失败: 类 '{ClassName}' 已注册虚表(class_vtable/class_methods)"
|
||
f"但 struct 类型无法从 stub 具化(仍为 opaque){Gen._get_node_info()}"
|
||
)
|
||
if concrete_st is pointee:
|
||
return ObjVal
|
||
# ObjVal 指向旧 opaque 占位对象:bitcast 到具体版本
|
||
return Gen.builder.bitcast(ObjVal, ir.PointerType(concrete_st), name=f"concrete_self_{ClassName}")
|
||
|
||
_C_LIB_FUNCS = {
|
||
'malloc': lambda: (ir.PointerType(ir.IntType(8)), [ir.IntType(64)]),
|
||
'calloc': lambda: (ir.PointerType(ir.IntType(8)), [ir.IntType(64), ir.IntType(64)]),
|
||
'realloc': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.IntType(64)]),
|
||
'free': lambda: (ir.VoidType(), [ir.PointerType(ir.IntType(8))]),
|
||
'strlen': lambda: (ir.IntType(64), [ir.PointerType(ir.IntType(8))]),
|
||
'strlength': lambda: (ir.IntType(64), [ir.PointerType(ir.IntType(8))]),
|
||
'memset': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.IntType(32), ir.IntType(64)]),
|
||
'memcpy': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64)]),
|
||
'memmove': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64)]),
|
||
'memcmp': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64)]),
|
||
'strcmp': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8))]),
|
||
'strncmp': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64)]),
|
||
'strcpy': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8))]),
|
||
'strncpy': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64)]),
|
||
'strcat': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8))]),
|
||
'puts': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8))]),
|
||
'atoi': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8))]),
|
||
'atol': lambda: (ir.IntType(64), [ir.PointerType(ir.IntType(8))]),
|
||
'abs': lambda: (ir.IntType(32), [ir.IntType(32)]),
|
||
'labs': lambda: (ir.IntType(64), [ir.IntType(64)]),
|
||
'system': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8))]),
|
||
}
|
||
|
||
def _try_declare_c_lib_func(self, func_name: str, Gen: LlvmGeneratorMixin) -> ir.Function | None:
|
||
if func_name not in self._C_LIB_FUNCS:
|
||
return None
|
||
ret_type, param_types = self._C_LIB_FUNCS[func_name]()
|
||
func_type = ir.FunctionType(ret_type, param_types)
|
||
# C 库声明名固定(malloc/strlen/...),同一模块内多次调用必须复用同一符号:
|
||
# 裸建会在第二次抛 llvmlite DuplicatedNameError。
|
||
return Gen._CreateOrReuseFuncDecl(func_name, func_type)
|
||
|
||
def _FailFastLenUnsupported(self, arg_node: ast.AST, Gen: LlvmGeneratorMixin,
|
||
val: ir.Value | None, reason: str) -> None:
|
||
"""len(x) 参数形态不支持时的编译期 fail-fast 出口(TPC 与 ViperC 同口径)。
|
||
|
||
规则(对齐 ViperC App/lib/core/Gen/Call/CallGenDispatch.vp 的 len() 分支):
|
||
定长数组/数组指针 → 常量 N;i8*(str/bytes)→ strlen;
|
||
带 __len__ 的结构体 → 调用 __len__;其余一律编译期报错。
|
||
非 i8 裸指针(如 `[]T` 形参实为 `T*`)与标量指针**没有长度语义**,旧实现会
|
||
静默返回常量 0(或回落 strlen)从而掩盖错误,这里改为响亮失败。
|
||
报文含 行:列 + 源码片段 + 期望形态 + 正确做法提示。
|
||
"""
|
||
raw_lineno: int = getattr(arg_node, 'lineno', 0) or 0
|
||
lineno: int = raw_lineno or getattr(Gen, '_current_lineno', 0) or 0
|
||
col: int = getattr(arg_node, 'col_offset', -1)
|
||
src_file: str = getattr(Gen, '_current_source_file', '') or ''
|
||
_line_offset: int = int(getattr(self.Trans, '_line_offset', 0) or 0)
|
||
if _line_offset > 0 and lineno > _line_offset:
|
||
lineno -= _line_offset
|
||
code_line: str = ''
|
||
if lineno > 0 and hasattr(Gen, '_get_source_line'):
|
||
try:
|
||
code_line = (Gen._get_source_line(lineno) or '').strip()
|
||
except Exception:
|
||
code_line = ''
|
||
loc: str = src_file
|
||
if lineno > 0:
|
||
loc += f":{lineno}"
|
||
if col >= 0:
|
||
loc += f":{col}"
|
||
actual: str = str(val.type) if val is not None else '<未知>'
|
||
msg: str = (f"[fast-fail] {reason}。{_LEN_SUPPORTED_HINT}。"
|
||
f"实际类型 '{actual}'。位置 {loc}"
|
||
+ (f",源码: {code_line}" if code_line else ''))
|
||
raise TypeError(msg)
|
||
|
||
def _HandleLenLlvm(self, arg_node: ast.AST) -> ir.Value | None:
|
||
Gen = self.Trans.LlvmGen
|
||
if isinstance(arg_node, ast.Attribute) and isinstance(arg_node.value, ast.Name) and arg_node.value.id == 'self':
|
||
attr_name = arg_node.attr
|
||
len_member = f'{attr_name}__len'
|
||
current_class = self.Trans._CurrentCpythonObjectClass
|
||
# 关键:_CurrentCpythonObjectClass 可能带 sha1 前缀(如
|
||
# 'a351387236c6ce1c.TypeGenCType'),而 class_members /
|
||
# class_member_element_class 的 key 全部是裸类名。必须先把前缀剥离
|
||
# 再做 `in Gen.class_members` 检查——否则带前缀时 gate 直接 miss,
|
||
# 整个 self.attr 分支(含 list.__len__ 修复)被跳过,fall through
|
||
# 到 strlen(stdint.vp 0xC0000005 崩溃根因)。
|
||
bare_cls: str | None = current_class
|
||
if bare_cls and len(bare_cls) > 17 and bare_cls[16] == '.':
|
||
bare_cls = bare_cls[17:]
|
||
if bare_cls and bare_cls in Gen.class_members:
|
||
for m_name, m_type in Gen.class_members[bare_cls]:
|
||
if m_name == len_member:
|
||
self_val = Gen._get_var_ptr('self')
|
||
if self_val:
|
||
self_ptr = Gen._load(self_val, name="self_for_len")
|
||
offset = Gen._get_member_offset(len_member, bare_cls)
|
||
len_ptr = Gen.builder.gep(self_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=f"self_{len_member}_ptr")
|
||
return Gen._load(len_ptr, name=f"self_{len_member}")
|
||
# 修复 stdint.vp 崩溃(0xC0000005)根因:`list[X] | CPtr` 联合字段
|
||
# 的 LLVM 类型退化为 i8*,_HandleLenLlvm 无法识别为 list,fall through
|
||
# 到 strlen 分支 → 对 list 对象指针执行 strlen → 垃圾长度 → 越界 get
|
||
# → 垃圾指针 → strcmp 崩。此处按字段静态类型(class_member_element_class
|
||
# 记录的特化名,如 'list[str]',沿 MRO 链查找含父类)分派到 list.__len__。
|
||
field_cls: str | None = None
|
||
_elem_map: dict = getattr(Gen, 'class_member_element_class', {})
|
||
for _mro_cls in Gen._get_mro_chain(bare_cls):
|
||
# class_member_element_class 的 key 是裸类名(如 'TypeGenBase'),
|
||
# _get_mro_chain 在输入裸名时也返回裸名链;再保险剥一次前缀。
|
||
_mro_key: str = _mro_cls
|
||
if len(_mro_cls) > 17 and _mro_cls[16] == '.':
|
||
_mro_key = _mro_cls[17:]
|
||
_sub: dict = _elem_map.get(_mro_key, {})
|
||
if attr_name in _sub:
|
||
field_cls = _sub[attr_name]
|
||
break
|
||
if field_cls and (field_cls == 'list' or field_cls.startswith('list[')):
|
||
self_val = Gen._get_var_ptr('self')
|
||
if self_val:
|
||
self_ptr = Gen._load(self_val, name="self_for_len")
|
||
offset = Gen._get_member_offset(attr_name, bare_cls)
|
||
if offset is not None:
|
||
list_ptr = Gen.builder.gep(self_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=f"self_{attr_name}_ptr")
|
||
list_val = Gen._load(list_ptr, name=f"self_{attr_name}")
|
||
result = self.Trans.ExprUtils._try_operator_overLoad(field_cls, '__len__', list_val, Gen)
|
||
if result is not None:
|
||
return result
|
||
val = self.HandleExprLlvm(arg_node)
|
||
if not val:
|
||
return None
|
||
if isinstance(val.type, ir.PointerType):
|
||
pointee = val.type.pointee
|
||
if isinstance(pointee, ir.PointerType):
|
||
val = Gen._load(val, name="len_deref")
|
||
pointee = val.type.pointee
|
||
if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
||
# struct(或任何非基本类型)→ 仍先走既有 __len__ 分派(保持不变);
|
||
# 没有 __len__ 时由旧实现的「回落 strlen」改为 fail-fast(与 VPC 同口径)。
|
||
_matched_cn: str | None = None
|
||
for CN, ST in Gen.structs.items():
|
||
if pointee == ST:
|
||
_matched_cn = CN
|
||
break
|
||
if _matched_cn is not None:
|
||
result = self.Trans.ExprUtils._try_operator_overLoad(_matched_cn, '__len__', val, Gen)
|
||
if result is not None:
|
||
return result
|
||
self._FailFastLenUnsupported(arg_node, Gen, val, f"len() 参数类型 '{_matched_cn}' 没有 __len__ 方法")
|
||
else:
|
||
# 未在 Gen.structs 登记的 struct(opaque/匿名)→ fail-fast。
|
||
self._FailFastLenUnsupported(arg_node, Gen, val, "len() 参数类型不支持(非字符串/数组/对象)")
|
||
if isinstance(pointee, ir.ArrayType):
|
||
return ir.Constant(ir.IntType(64), pointee.count)
|
||
# i8*(含 str/bytes 指针形态)→ strlen(保持不变)。
|
||
if isinstance(pointee, ir.IntType) and pointee.width == 8:
|
||
if val.type != ir.PointerType(ir.IntType(8)):
|
||
val = Gen.builder.bitcast(val, ir.PointerType(ir.IntType(8)), name="str_ptr_cast")
|
||
correct_strlen_type = ir.FunctionType(ir.IntType(64), [ir.PointerType(ir.IntType(8))])
|
||
strlen_func = None
|
||
if 'strlen' in Gen.functions:
|
||
existing = Gen.functions['strlen']
|
||
if existing.ftype == correct_strlen_type:
|
||
strlen_func = existing
|
||
if not strlen_func:
|
||
try:
|
||
strlen_func = Gen._CreateOrReuseFuncDecl('strlen', correct_strlen_type)
|
||
Gen.functions['strlen'] = strlen_func
|
||
except Exception as _e:
|
||
from lib.core.LLVMCG.FuncGen import FailFastError as _FFE
|
||
if isinstance(_e, _FFE):
|
||
raise
|
||
if _config_mode == "strict":
|
||
self.Trans.LogWarning(f"异常被忽略: {_e}")
|
||
if strlen_func:
|
||
result = Gen.builder.call(strlen_func, [val], name="strlen_call")
|
||
return result
|
||
return None
|
||
# 非 i8 裸指针 / 标量指针(i32*/i64*/float*/double*)→ fail-fast
|
||
# (旧实现静默返回常量 0 或回落 strlen,与 VPC 口径不符)。
|
||
self._FailFastLenUnsupported(arg_node, Gen, val, "len() 参数类型不支持(非字符串/数组/对象)")
|
||
elif isinstance(val.type, ir.ArrayType):
|
||
return ir.Constant(ir.IntType(64), val.type.count)
|
||
# 其它不支持形态(标量值 / 结构体值等)→ fail-fast(旧实现静默返回常量 0)。
|
||
self._FailFastLenUnsupported(arg_node, Gen, val, "len() 参数类型不支持(非字符串/数组/对象)")
|
||
|
||
def _resolve_opaque_struct_members(self, struct_type: ir.Type, Gen: LlvmGeneratorMixin, _visited: set | None = None) -> None:
|
||
"""Recursively resolve opaque struct members by loading from stub files."""
|
||
if _visited is None:
|
||
_visited = set()
|
||
if not isinstance(struct_type, ir.IdentifiedStructType):
|
||
return
|
||
# 防止循环引用导致无限递归
|
||
try:
|
||
st_id = id(struct_type)
|
||
except Exception:
|
||
st_id = struct_type
|
||
if st_id in _visited:
|
||
return
|
||
_visited.add(st_id)
|
||
if struct_type.elements is None or len(struct_type.elements) == 0:
|
||
# Find the class name for this opaque struct and try to resolve
|
||
for cn, st in Gen.structs.items():
|
||
try:
|
||
if st == struct_type or (hasattr(st, 'name') and hasattr(struct_type, 'name') and st.name == struct_type.name):
|
||
self.Trans.ImportHandler._TryLoadStructFromStub(cn, Gen)
|
||
break
|
||
except (AssertionError, RuntimeError):
|
||
pass
|
||
# Re-get the struct in case it was resolved
|
||
if struct_type.elements:
|
||
for elem in struct_type.elements:
|
||
if isinstance(elem, ir.IdentifiedStructType):
|
||
self._resolve_opaque_struct_members(elem, Gen, _visited)
|
||
elif isinstance(elem, ir.PointerType):
|
||
pointee = elem.pointee
|
||
if isinstance(pointee, ir.IdentifiedStructType):
|
||
self._resolve_opaque_struct_members(pointee, Gen, _visited)
|
||
|
||
def _resolve_type_arg_str(self, node: ast.AST) -> str:
|
||
"""将类型参数 AST 节点解析为规范化的类型字符串(用于泛型特化的 mangling)。
|
||
|
||
规则本体在 SymbolUtils.ResolveTypeArgStr(定义端/声明端唯一规则源,
|
||
声明端 DeclarationGenerator 的泛型分支亦调用同一函数),此处仅注入
|
||
翻译器上下文:
|
||
- t/c 导入别名表(from t import CInt as myint → 'CInt')
|
||
- 跨模块结构体 SHA1 表(ast.Name/Attribute 命中 → '{sha1}.{名}',与普通签名一致)
|
||
"""
|
||
Gen = self.Trans.LlvmGen
|
||
StructSha1Map: dict[str, str] = getattr(Gen, '_struct_sha1_map', {}) if Gen is not None else {}
|
||
return ResolveTypeArgStr(
|
||
node,
|
||
TCAliasMap=getattr(self.Trans, '_from_import_aliases', {}),
|
||
StructSha1Map=StructSha1Map)
|
||
|
||
def _get_raw_type_name(self, node: ast.AST) -> str:
|
||
"""获取类型节点的原始名称(不带模块前缀),用于泛型 T 替换。
|
||
|
||
ast.Name → sn.id (如 'AST', 'CInt')
|
||
ast.Attribute → sn.attr (如 CInt → 'CInt')
|
||
ast.BinOp → 左侧的原始名称 (如 AST | CPtr → 'AST')
|
||
"""
|
||
if isinstance(node, ast.Name):
|
||
return node.id
|
||
if isinstance(node, ast.Attribute):
|
||
return node.attr
|
||
if isinstance(node, ast.BinOp):
|
||
return self._get_raw_type_name(node.left)
|
||
return ast.unparse(node)
|
||
|
||
def _resolve_generic_slice_type(self, sn: ast.AST) -> tuple[str, str] | None:
|
||
"""解析泛型 slice 中的单个类型参数节点,返回 (type_arg, type_name) 或 None。
|
||
|
||
type_arg: 用于 mangling,走**唯一规则源** _resolve_type_arg_str
|
||
(内层与参数注解同解析:'AST | CPtr' / 'rawptr[AST]' →
|
||
'{sha1}.AST*'、裸类名 'AST' → '{sha1}.AST'、标量按
|
||
NormalizeGenericArgName 归一)
|
||
type_name: 用于替换泛型类型参数 T(原始源码名,如 'AST' / 'CInt',
|
||
_specialize_generic_class 会自动给类名加 | CPtr)
|
||
指针下标 rawptr[T] 先折叠成等价的 `T | CPtr` 再解析,
|
||
与源码联合写法得到同一 (type_arg, type_name):否则 list[rawptr[ast.AST]]
|
||
会拼出 'rawptr[ast.AST]' 实参串(内层未混淆)→ 与 list[ast.AST | CPtr]
|
||
的 '<sha1>.AST*' 分裂成两个特化名(结构体/方法声明/调用点三端不一致)。
|
||
"""
|
||
if IsPtrSubscriptNode(sn, self.Trans.SymbolTable):
|
||
sn = DesugarPtrSubscriptToUnion(sn, self.Trans.SymbolTable)
|
||
if isinstance(sn, ast.Name):
|
||
# type_arg 走唯一规则源(命中注册类加 SHA1 前缀,裸名与
|
||
# `list[X]`/`rawptr[X]` 内层收敛到同一名字);
|
||
# type_name 保留源码名供 T 替换与内建/类类型判定(两张表收拢在 SymbolUtils)
|
||
return (self._resolve_type_arg_str(sn), GenericArgRawName(sn.id))
|
||
# BinOp (如 AST | CPtr) 或 Attribute (如 mod.CInt)
|
||
type_str: str = self._resolve_type_arg_str(sn)
|
||
# type_name 保留源码名(如 'CUnsignedChar'),避免 T(0) 替换为
|
||
# CUnsignedChar(0) 后因 CUnsignedChar 不在顶层作用域而报
|
||
# "Undefined function: 'CUnsignedChar'"。
|
||
# CPtr 同样保留 'CPtr':作为 type_map['T'] 替换进模板(item: T →
|
||
# item: CPtr)时需要可解析;指针参数识别由 _BUILTIN_TYPE_NAMES 的
|
||
# tn_bare 检测('CPtr'→'CPtr')。
|
||
if isinstance(sn, ast.Attribute) and isinstance(sn.value, ast.Name):
|
||
raw_name: str = f'{sn.value.id}.{sn.attr}'
|
||
else:
|
||
raw_name: str = self._get_raw_type_name(sn)
|
||
return (type_str, raw_name)
|
||
|
||
@staticmethod
|
||
def _IsCPtrMark(Node: ast.AST) -> bool:
|
||
"""判断节点是否为 `CPtr` 标记(裸名)。"""
|
||
if isinstance(Node, ast.Name):
|
||
return Node.id == 'CPtr'
|
||
return False
|
||
|
||
def _CallReturnClass(self, Node: ast.Call, Gen: LlvmGeneratorMixin) -> str | None:
|
||
"""调用结果的**被指类名**:从被调者的返回注解恢复。
|
||
|
||
背景:`list[str]*` ≡ `list[str] | CPtr`(只读探针已确认二者 AST 逐字同形,
|
||
都是 `BinOp(BitOr, Subscript(...), Attribute(CPtr))`)这类返回注解在 LLVM 层
|
||
被映射成通用指针 `i8*`,类名随之丢失 ⇒ 调用点只能按通用指针处理
|
||
(`parts = s1.split(',')` 之后 `parts[0]` 退化成按字节索引、得到整数,赋给
|
||
`str` 时报"整数隐式转指针已禁止",真因在 4 行之前)。
|
||
本方法把类名从**注解**取回;判据与 HandlesAnnAssign 的同类恢复
|
||
(:644-684 `rawptr[X]`、:1012-1034 联合注解构特化名)同源。
|
||
取不到返回 None —— 调用方据此不改动既有行为。
|
||
"""
|
||
_fn: ast.AST = Node.func
|
||
_cands: list[str] = []
|
||
if isinstance(_fn, ast.Name):
|
||
_cands.append(_fn.id)
|
||
elif isinstance(_fn, ast.Attribute):
|
||
_m: str = _fn.attr
|
||
_recv_cls: str | None = None
|
||
if isinstance(_fn.value, ast.Name):
|
||
_recv_cls = (Gen.var_struct_class.get(_fn.value.id)
|
||
or (getattr(Gen, 'global_struct_class', {}) or {}).get(_fn.value.id))
|
||
# FakeDuck 影子类(str→_str / bytes→_bytes)与接收者真实类名两条线都试;
|
||
# FuncDefCache 的方法键在仓库里既有 'cls.method' 也有裸 'method' 两种形态。
|
||
for _c in ([_recv_cls] if _recv_cls else []) + ['_str', '_bytes']:
|
||
_cands.append(f'{_c}.{_m}')
|
||
_cands.append(_m)
|
||
for _nm in _cands:
|
||
_fd: ast.FunctionDef | None = self.Trans.FunctionDefCache.get(_nm)
|
||
if _fd is not None and _fd.returns is not None:
|
||
_cls: str | None = self._ClassFromAnnotation(_fd.returns, Gen)
|
||
if _cls:
|
||
return _cls
|
||
return None
|
||
|
||
def _ClassFromAnnotation(self, Ann: ast.AST, Gen: LlvmGeneratorMixin) -> str | None:
|
||
"""从注解恢复"类名(含泛型特化名)":剔除 `| CPtr` 侧与指针层后取核类型。
|
||
|
||
- `list[str] | CPtr` / `list[str]*` → `list[str]`(泛型特化名,与
|
||
HandlesAnnAssign:1012-1034 的构名方式一致);
|
||
- `Foo | CPtr` / `Foo*` → `Foo`;
|
||
- 核类型名必须能在 `Gen.structs` / `Gen.class_members` 命中(含 sha1 前缀
|
||
全名的短名归一),否则返回 None(类型信息不完整时不硬塞名字)。
|
||
"""
|
||
_core: ast.AST = Ann
|
||
if isinstance(_core, ast.BinOp) and isinstance(_core.op, ast.BitOr):
|
||
_l: ast.AST = _core.left
|
||
_r: ast.AST = _core.right
|
||
if self._IsCPtrMark(_r):
|
||
_core = _l
|
||
elif self._IsCPtrMark(_l):
|
||
_core = _r
|
||
else:
|
||
return None
|
||
if isinstance(_core, ast.Subscript):
|
||
_base: ast.expr = _core.value
|
||
_bn: str | None = None
|
||
if isinstance(_base, ast.Name):
|
||
_bn = _base.id
|
||
elif isinstance(_base, ast.Attribute):
|
||
_bn = _base.attr
|
||
if not _bn:
|
||
return None
|
||
_sl: ast.AST = _core.slice
|
||
if hasattr(ast, 'Index') and isinstance(_sl, ast.Index):
|
||
_sl = _sl.value
|
||
_r2: tuple[str, str] | None = self._resolve_generic_slice_type(_sl)
|
||
if not _r2:
|
||
return None
|
||
_spec: str = f'{_bn}[{_r2[0]}]'
|
||
if _spec in Gen.structs or _spec in Gen.class_members:
|
||
return _spec
|
||
# 端键归一:特化键可能是 sha1 前缀全名
|
||
for _k in Gen.structs:
|
||
if _k.split('.')[-1] == _spec:
|
||
return _k
|
||
return _spec
|
||
if isinstance(_core, ast.Name):
|
||
if _core.id in Gen.structs or _core.id in Gen.class_members:
|
||
return _core.id
|
||
for _k in Gen.structs:
|
||
if _k.split('.')[-1] == _core.id:
|
||
return _k
|
||
return None
|
||
if isinstance(_core, ast.Attribute):
|
||
if _core.attr in Gen.structs or _core.attr in Gen.class_members:
|
||
return _core.attr
|
||
for _k in Gen.structs:
|
||
if _k.split('.')[-1] == _core.attr:
|
||
return _k
|
||
return None
|
||
return None
|
||
|
||
def _ResolveGenericSlice(self, Sub: ast.Subscript) -> str | None:
|
||
"""从泛型 Subscript (如 Stack[int]) 解析特化名,确保特化类型已生成。"""
|
||
if not isinstance(Sub.value, ast.Name):
|
||
return None
|
||
ClassName: str = Sub.value.id
|
||
if not (hasattr(self.Trans.ClassHandler, '_generic_class_templates') and ClassName in self.Trans.ClassHandler._generic_class_templates):
|
||
return None
|
||
Gen = self.Trans.LlvmGen
|
||
# 共享符号表构建阶段(_build_shared_symbol_data / ParsePythonFile)LlvmGen 为 None,
|
||
# 此时不应发射特化 IR;调用方(GetCTypeInfo)已用 mangled 名设置符号表信息
|
||
if Gen is None:
|
||
return None
|
||
template: dict = self.Trans.ClassHandler._generic_class_templates[ClassName]
|
||
type_param_names: list[str] = template['type_params']
|
||
type_args: list[str] = []
|
||
type_names: list[str] = []
|
||
slice_nodes: list[ast.AST] = []
|
||
if isinstance(Sub.slice, ast.Tuple):
|
||
slice_nodes = list(Sub.slice.elts)
|
||
else:
|
||
slice_nodes = [Sub.slice]
|
||
for sn in slice_nodes:
|
||
result = self._resolve_generic_slice_type(sn)
|
||
if result is not None:
|
||
type_args.append(result[0])
|
||
type_names.append(result[1])
|
||
if len(type_args) < len(type_param_names):
|
||
raise Exception(
|
||
f"泛型类注解 '{ast.unparse(Sub)}' 无法解析全部类型实参:"
|
||
f"需要 {len(type_param_names)} 个,仅解析出 {len(type_args)} 个;"
|
||
f"禁止按 int 兜底。")
|
||
# 类型注解解析(如 Float64Array: CTypedef = ndarray[CDouble])
|
||
# 只需 struct 定义,不需方法体;使用 declare_only=True 避免过早触发
|
||
# 完整特化(此时被引用的函数如 printf 可能尚未由 from X import Y 注册,
|
||
# 导致 "Undefined function" 错误)。完整特化由后续类实例化
|
||
# (_HandleClassNewLlvm → _specialize_generic_class(declare_only=False))
|
||
# 触发,缓存机制会补发方法体。
|
||
return self.Trans.ClassHandler._specialize_generic_class(ClassName, type_args, Gen, type_names=type_names, declare_only=True)
|
||
|
||
@staticmethod
|
||
def _AnnotationContainsCPtr(Node: ast.AST) -> bool:
|
||
"""检查类型注解 AST 是否包含 CPtr(即是否为指针类型)"""
|
||
if isinstance(Node, ast.Name):
|
||
if Node.id == 'CPtr':
|
||
return True
|
||
if isinstance(Node, ast.BinOp) and isinstance(Node.op, ast.BitOr):
|
||
return (ExprCallHandle._AnnotationContainsCPtr(Node.left)
|
||
or ExprCallHandle._AnnotationContainsCPtr(Node.right))
|
||
return False
|
||
|
||
@staticmethod
|
||
def _is_sizeof_type_name(name: str, Gen: "LlvmGeneratorMixin") -> bool:
|
||
"""检查名称是否是已知的类型名(用于 __sizeof__ 上下文)。
|
||
检查顺序: Gen.structs → SHA1 前缀 → 内建类型 → CTypeRegistry
|
||
"""
|
||
if not name:
|
||
return False
|
||
# 1. 直接在 Gen.structs 中查找
|
||
if name in Gen.structs:
|
||
return True
|
||
# 2. 带 SHA1 前缀查找(如 ClassDef → 657e182b27c2a022.ClassDef)
|
||
struct_sha1_map = getattr(Gen, '_struct_sha1_map', {})
|
||
if name in struct_sha1_map:
|
||
return True
|
||
# 遍历所有 SHA1 前缀
|
||
for sha1 in struct_sha1_map.values():
|
||
prefixed = f"{sha1}.{name}"
|
||
if prefixed in Gen.structs:
|
||
return True
|
||
# 3. 内建类型名
|
||
if name in ('str', 'bytes', 'int', 'double', 'float', 'char', 'bool',
|
||
'void', 'i8', 'i16', 'i32', 'i64', 'half', 'fp128'):
|
||
return True
|
||
# 4. CTypeRegistry 中的类型
|
||
if CTypeRegistry.GetClassByName(name) is not None:
|
||
return True
|
||
if CTypeRegistry.ResolveName(name):
|
||
return True
|
||
return False
|
||
|
||
def _HandleSizeofLlvm(self, Node: ast.AST) -> ir.Constant:
|
||
Gen = self.Trans.LlvmGen
|
||
if isinstance(Node, ast.Name):
|
||
type_name = Node.id
|
||
elif isinstance(Node, ast.Attribute):
|
||
type_name = Node.attr
|
||
elif isinstance(Node, ast.BinOp) and isinstance(Node.op, ast.BitOr):
|
||
# 联合类型(如 X | CPtr):VPC 注解中 | = and,带 CPtr 的联合
|
||
# 是指针类型(X* 或 i8*),sizeof = 8(指针大小)。
|
||
# list[T].__init__ 的 T.__sizeof__() 特化后 T 被还原为 'X | CPtr'
|
||
# (_make_replacement_node),此前落到 else 返回 0 → elem_size=0 →
|
||
# 所有元素存取同槽(get(0)==get(1),list[对象] join 误报根因)。
|
||
if _BinOpContainsCPtr(Node):
|
||
return ir.Constant(ir.IntType(64), 8)
|
||
# 不带 CPtr 的联合(A | B)无法确定尺寸:曾静默返回 0 →
|
||
# 下游 elem_size=0 → alloc(0) 返回 NULL / 所有元素存取同槽。fail-fast。
|
||
raise ValueError(
|
||
f"[FATAL][__sizeof__] 联合类型 '{ast.unparse(Node)}' 不含 CPtr,"
|
||
f"无法确定尺寸,拒绝静默返回 0(会导致 alloc(0)/元素同槽)"
|
||
)
|
||
else:
|
||
# 非 名称/属性/联合 的 sizeof 目标(如表达式、调用):曾静默返回 0。fail-fast。
|
||
raise ValueError(
|
||
f"[FATAL][__sizeof__] 不支持的 sizeof 目标 {type(Node).__name__}"
|
||
f"({ast.unparse(Node)}),"
|
||
f"拒绝静默返回 0(会导致 alloc(0))"
|
||
)
|
||
|
||
if type_name not in Gen.structs:
|
||
# SHA1 前缀查找:如 ClassDef → 657e182b27c2a022.ClassDef
|
||
struct_sha1_map = getattr(Gen, '_struct_sha1_map', {})
|
||
resolved_name: str | None = None
|
||
if type_name in struct_sha1_map:
|
||
resolved_name = f"{struct_sha1_map[type_name]}.{type_name}"
|
||
else:
|
||
for sha1 in struct_sha1_map.values():
|
||
prefixed = f"{sha1}.{type_name}"
|
||
if prefixed in Gen.structs:
|
||
resolved_name = prefixed
|
||
break
|
||
if resolved_name is not None and resolved_name in Gen.structs:
|
||
type_name = resolved_name
|
||
if type_name not in Gen.structs:
|
||
# str/bytes 是指针类型 (char*/void*),sizeof = 指针大小
|
||
if type_name in ('str', 'bytes'):
|
||
return ir.Constant(ir.IntType(64), 8)
|
||
ctype_cls = CTypeRegistry.GetClassByName(type_name)
|
||
if ctype_cls is not None:
|
||
try:
|
||
ctype_inst = ctype_cls()
|
||
size_bits = getattr(ctype_inst, 'Size', 0) or 0
|
||
size_bytes = size_bits // 8
|
||
# POINTER 类型(CPtr 等)Size 为 None/0 → 指针大小 8。
|
||
# 根因:CPtr.__sizeof__() 返回 0 → list[CPtr]
|
||
# elem_size=0 → append 全写同槽/alloc(0) → 崩溃。
|
||
if getattr(ctype_inst, 'HasPosition', None) \
|
||
and ctype_inst.HasPosition(TypeSystem.CType.POINTER) \
|
||
and size_bytes == 0:
|
||
size_bytes = 8
|
||
return ir.Constant(ir.IntType(64), size_bytes)
|
||
except Exception as _e:
|
||
if _config_mode == "strict":
|
||
raise
|
||
_vlog().warning(f"解析类型失败: {_e}", "Exception")
|
||
resolved = CTypeRegistry.ResolveName(type_name)
|
||
if resolved:
|
||
ctype_cls, ptr_level = resolved
|
||
try:
|
||
ctype_inst = ctype_cls()
|
||
size_bits = getattr(ctype_inst, 'Size', 0) or 0
|
||
size_bytes = size_bits // 8
|
||
if ptr_level > 0:
|
||
size_bytes = 8
|
||
return ir.Constant(ir.IntType(64), size_bytes)
|
||
except Exception as _e:
|
||
if _config_mode == "strict":
|
||
raise
|
||
_vlog().warning(f"解析类型失败: {_e}", "Exception")
|
||
# 所有查找策略均失败(不在 Gen.structs、SHA1 前缀查找失败、CTypeRegistry 也找不到):
|
||
# 报错终止,拒绝静默返回 0(会导致 malloc(0)/alloc(0) 堆溢出)
|
||
raise ValueError(
|
||
f"[FATAL][__sizeof__] 类型 '{type_name}' 无法解析"
|
||
f"(不在 Gen.structs、SHA1 前缀查找失败、CTypeRegistry 也找不到),"
|
||
f"拒绝静默返回 0"
|
||
)
|
||
|
||
struct_type = Gen.structs[type_name]
|
||
if isinstance(struct_type, ir.PointerType):
|
||
struct_type = struct_type.pointee
|
||
# 保存 builder 状态:_TryLoadStructFromStub / _resolve_opaque_struct_members
|
||
# 可能触发重入编译(编译其他模块的函数),这会改变 Gen.func/Gen.builder,
|
||
# 导致当前函数的指令被写到错误函数的 block 中(then 块为空的根因)
|
||
_saved_func = Gen.func
|
||
_saved_builder = Gen.builder
|
||
_saved_block = Gen.builder.block if (Gen.builder and Gen.builder.block) else None
|
||
_saved_variables = dict(Gen.variables) if Gen.variables else {}
|
||
_saved_reg_values = dict(getattr(Gen, '_reg_values', {}))
|
||
_saved_direct_values = dict(getattr(Gen, '_direct_values', {}))
|
||
_saved_var_type_info = dict(getattr(Gen, 'var_type_info', {}))
|
||
_saved_var_signedness = dict(getattr(Gen, 'var_signedness', {}))
|
||
_saved_global_vars = set(getattr(Gen, 'global_vars', set()))
|
||
_saved_var_scopes = [dict(s) for s in getattr(self.Trans, 'VarScopes', [])]
|
||
try:
|
||
if isinstance(struct_type, ir.IdentifiedStructType) and (struct_type.elements is None or len(struct_type.elements) == 0):
|
||
self.Trans.ImportHandler._TryLoadStructFromStub(type_name, Gen)
|
||
struct_type = Gen.structs.get(type_name, struct_type)
|
||
# Recursively resolve opaque struct members
|
||
self._resolve_opaque_struct_members(struct_type, Gen)
|
||
finally:
|
||
Gen.func = _saved_func
|
||
Gen.builder = _saved_builder
|
||
if _saved_block is not None and Gen.builder is not None:
|
||
Gen.builder.position_at_end(_saved_block)
|
||
Gen.variables = _saved_variables
|
||
Gen._reg_values = _saved_reg_values
|
||
Gen._direct_values = _saved_direct_values
|
||
Gen.var_type_info = _saved_var_type_info
|
||
Gen.var_signedness = _saved_var_signedness
|
||
Gen.global_vars = _saved_global_vars
|
||
self.Trans.VarScopes = _saved_var_scopes
|
||
# _get_struct_size 已在尺寸不可得时 fail-fast(不返回 0),此处直接采用。
|
||
return ir.Constant(ir.IntType(64), Gen._get_struct_size(struct_type))
|
||
|
||
def _HandleAbsLlvm(self, arg_node: ast.AST) -> ir.Value | None:
|
||
Gen = self.Trans.LlvmGen
|
||
val = self.HandleExprLlvm(arg_node)
|
||
if not val:
|
||
return None
|
||
if isinstance(val.type, ir.PointerType):
|
||
pointee = val.type.pointee
|
||
if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
||
for CN, ST in Gen.structs.items():
|
||
if pointee == ST:
|
||
result = self.Trans.ExprUtils._try_operator_overLoad(CN, '__abs__', val, Gen)
|
||
if result is not None:
|
||
return result
|
||
break
|
||
if isinstance(val.type, ir.IntType):
|
||
neg_val = Gen.builder.neg(val, name="abs_neg")
|
||
is_neg = Gen.builder.icmp_signed('<', val, ir.Constant(val.type, 0), name="is_neg")
|
||
return Gen.builder.select(is_neg, neg_val, val, name="abs_result")
|
||
elif isinstance(val.type, (ir.FloatType, ir.DoubleType)):
|
||
zero = ir.Constant(val.type, 0.0)
|
||
neg_val = Gen.builder.fneg(val, name="fabs_neg")
|
||
is_neg = Gen.builder.fcmp_ordered('<', val, zero, name="f_is_neg")
|
||
return Gen.builder.select(is_neg, neg_val, val, name="fabs_result")
|
||
return None
|
||
|
||
def _HandleDirLlvm(self, Node: ast.Call) -> ir.Constant:
|
||
Gen = self.Trans.LlvmGen
|
||
return ir.Constant(ir.IntType(8).as_pointer(), None)
|
||
|
||
def _HandleTypeLlvm(self, Node: ast.Call) -> ir.Value:
|
||
Gen = self.Trans.LlvmGen
|
||
if not Node.args:
|
||
type_str = "<class 'unknown' size=0 signed=false, ptr=false>"
|
||
else:
|
||
arg = Node.args[0]
|
||
enum_type_name = None
|
||
|
||
def _get_attr_path(node):
|
||
if isinstance(node, ast.Name):
|
||
return node.id
|
||
elif isinstance(node, ast.Attribute):
|
||
return f"{_get_attr_path(node.value)}.{node.attr}"
|
||
return None
|
||
|
||
if isinstance(arg, ast.Name):
|
||
arg_name = arg.id
|
||
Gen = self.Trans.LlvmGen
|
||
if arg_name in Gen.var_type_info:
|
||
type_info = Gen.var_type_info[arg_name]
|
||
if isinstance(type_info, dict) and type_info.get('type') == 'enum':
|
||
enum_type_name = type_info.get('name')
|
||
if not enum_type_name:
|
||
TypeInfo = self.Trans.SymbolTable.lookup(arg_name)
|
||
if TypeInfo and TypeInfo.IsEnum:
|
||
enum_type_name = arg_name
|
||
elif isinstance(arg, ast.Attribute):
|
||
LastPart = None
|
||
enum_class_name = None
|
||
if isinstance(arg.value, ast.Name):
|
||
LastPart = arg.attr
|
||
AttrInfo = self.Trans.SymbolTable.lookup(LastPart)
|
||
if AttrInfo and AttrInfo.IsEnumMember and AttrInfo.EnumName:
|
||
enum_type_name = AttrInfo.EnumName
|
||
elif isinstance(arg.value, ast.Attribute):
|
||
attr_path = _get_attr_path(arg)
|
||
if attr_path:
|
||
parts = attr_path.split('.')
|
||
if len(parts) >= 2:
|
||
enum_class_name = parts[-2]
|
||
LastPart = parts[-1]
|
||
qualified_name_dot = f"{enum_class_name}.{LastPart}"
|
||
qualified_name_under = f"{enum_class_name}_{LastPart}"
|
||
enum_member_found = None
|
||
for qname in (qualified_name_dot, qualified_name_under):
|
||
info = self.Trans.SymbolTable.lookup(qname)
|
||
if info and info.IsEnumMember and info.EnumName == enum_class_name:
|
||
enum_member_found = info
|
||
break
|
||
if not enum_member_found:
|
||
for key in self.Trans.SymbolTable:
|
||
if key == LastPart:
|
||
info = self.Trans.SymbolTable[key]
|
||
if info.IsEnumMember and info.EnumName == enum_class_name:
|
||
enum_member_found = info
|
||
break
|
||
if enum_member_found:
|
||
enum_type_name = enum_class_name
|
||
if enum_type_name:
|
||
_enum_bits: int = self.Trans.LlvmGen._enum_int_type(enum_type_name).width
|
||
type_str = f"<enum '{enum_type_name}' size={_enum_bits // 8} signed=true, ptr=false>"
|
||
else:
|
||
llvm_type = self.Trans.ExprUtils._infer_expr_llvm_type_full(arg)
|
||
if isinstance(llvm_type, ir.PointerType):
|
||
pointee = llvm_type.pointee
|
||
if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
|
||
llvm_type = pointee
|
||
type_info = self.Trans.ExprUtils._llvm_type_to_detailed_string(llvm_type)
|
||
type_str = f"<class '{type_info['name']}' size={type_info['size']} signed={str(type_info['signed']).lower()}, ptr={str(type_info['ptr']).lower()}>"
|
||
return Gen.emit_constant(type_str, 'string')
|
||
|
||
def _HandleInputLlvm(self, Node: ast.Call) -> ir.Value:
|
||
Gen = self.Trans.LlvmGen
|
||
if Node.args and isinstance(Node.args[0], ast.Constant) and isinstance(Node.args[0].value, str):
|
||
prompt = Node.args[0].value
|
||
prompt_ptr = Gen.emit_constant(prompt, 'string')
|
||
printf_func = Gen.get_or_declare_c_func('printf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True))
|
||
Gen.builder.call(printf_func, [prompt_ptr])
|
||
scanf_func = Gen.get_or_declare_c_func('scanf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True))
|
||
input_buffer = Gen._alloca(ir.ArrayType(ir.IntType(8), 256), name="input_buffer")
|
||
result = Gen.builder.call(scanf_func, [Gen.emit_constant("%255s", 'string'), input_buffer])
|
||
return Gen.builder.gep(input_buffer, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="input_result")
|
||
|
||
def _HandleAtoiLlvm(self, str_ptr: ir.Value) -> ir.Value:
|
||
Gen = self.Trans.LlvmGen
|
||
atoi_func = Gen.get_or_declare_c_func('atoi', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))]))
|
||
return Gen.builder.call(atoi_func, [str_ptr], name="atoi_result")
|
||
|
||
def _HandleOrdLlvm(self, expr_node: ast.AST) -> ir.Value:
|
||
Gen = self.Trans.LlvmGen
|
||
val = self.HandleExprLlvm(expr_node)
|
||
if val and self._is_char_pointer(val):
|
||
return Gen._load(val, name="ord_result")
|
||
return ir.Constant(ir.IntType(32), 0)
|
||
|
||
def _HandleChrLlvm(self, expr_node: ast.AST) -> ir.Value:
|
||
Gen = self.Trans.LlvmGen
|
||
val = self.HandleExprLlvm(expr_node)
|
||
if val:
|
||
char_ptr = Gen._alloca(ir.IntType(8), name="chr_char")
|
||
Gen.builder.store(Gen.builder.trunc(val, ir.IntType(8), name="trunc_chr"), char_ptr)
|
||
return Gen.builder.gep(char_ptr, [ir.Constant(ir.IntType(32), 0)], name="chr_result")
|
||
return ir.Constant(ir.IntType(8).as_pointer(), None)
|
||
|
||
def _HandleMallocLlvm(self, args: list[ast.AST]) -> ir.Value:
|
||
Gen = self.Trans.LlvmGen
|
||
malloc_type = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.IntType(64)])
|
||
malloc_func = Gen._get_or_declare_func('malloc', malloc_type)
|
||
param_type = malloc_func.type.pointee.args[0]
|
||
size_val = None
|
||
if args:
|
||
size_val = self.HandleExprLlvm(args[0])
|
||
if size_val and isinstance(size_val.type, ir.IntType):
|
||
if isinstance(param_type, ir.IntType) and size_val.type.width != param_type.width:
|
||
if size_val.type.width < param_type.width:
|
||
size_val = Gen.builder.zext(size_val, param_type, name="zext_malloc_size")
|
||
else:
|
||
size_val = Gen.builder.trunc(size_val, param_type, name="trunc_malloc_size")
|
||
if not size_val:
|
||
size_val = ir.Constant(param_type, 1)
|
||
result = Gen.builder.call(malloc_func, [size_val], name="malloc_result")
|
||
return Gen.builder.bitcast(result, ir.IntType(8).as_pointer(), name="malloc_cast")
|
||
|
||
def _HandleReallocLlvm(self, args: list[ast.AST]) -> ir.Value:
|
||
Gen = self.Trans.LlvmGen
|
||
realloc_type = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.IntType(64)])
|
||
realloc_func = Gen._get_or_declare_func('realloc', realloc_type)
|
||
size_param_type = realloc_func.type.pointee.args[1]
|
||
ptr_val = None
|
||
size_val = None
|
||
if len(args) >= 2:
|
||
ptr_val = self.HandleExprLlvm(args[0])
|
||
size_val = self.HandleExprLlvm(args[1])
|
||
elif len(args) == 1:
|
||
size_val = self.HandleExprLlvm(args[0])
|
||
if not ptr_val:
|
||
ptr_val = ir.Constant(ir.PointerType(ir.IntType(8)), None)
|
||
if isinstance(ptr_val.type, ir.PointerType) and not self._is_char_pointer(ptr_val):
|
||
ptr_val = Gen.builder.bitcast(ptr_val, ir.PointerType(ir.IntType(8)), name="realloc_cast_ptr")
|
||
if size_val and isinstance(size_val.type, ir.IntType):
|
||
if isinstance(size_param_type, ir.IntType) and size_val.type.width != size_param_type.width:
|
||
if size_val.type.width < size_param_type.width:
|
||
size_val = Gen.builder.zext(size_val, size_param_type, name="zext_realloc_size")
|
||
else:
|
||
size_val = Gen.builder.trunc(size_val, size_param_type, name="trunc_realloc_size")
|
||
if not size_val:
|
||
size_val = ir.Constant(size_param_type, 0)
|
||
result = Gen.builder.call(realloc_func, [ptr_val, size_val], name="realloc_result")
|
||
return Gen.builder.bitcast(result, ir.IntType(8).as_pointer(), name="realloc_cast")
|
||
|
||
def _HandleFreeLlvm(self, args: list[ast.AST]) -> ir.Constant:
|
||
Gen = self.Trans.LlvmGen
|
||
free_type = ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))])
|
||
free_func = Gen._get_or_declare_func('free', free_type)
|
||
if args:
|
||
var_name = None
|
||
if isinstance(args[0], ast.Name):
|
||
var_name = args[0].id
|
||
ptr_val = self.HandleExprLlvm(args[0])
|
||
if ptr_val:
|
||
if var_name and hasattr(Gen, '_var_to_heap_ptr') and var_name in Gen._var_to_heap_ptr:
|
||
registered_val = Gen._var_to_heap_ptr[var_name]
|
||
Gen._unregister_local_heap_ptr(registered_val)
|
||
del Gen._var_to_heap_ptr[var_name]
|
||
if isinstance(ptr_val.type, ir.PointerType) and not self._is_char_pointer(ptr_val):
|
||
ptr_val = Gen.builder.bitcast(ptr_val, ir.PointerType(ir.IntType(8)), name="free_cast_ptr")
|
||
Gen.builder.call(free_func, [ptr_val], name="free_call")
|
||
return ir.Constant(ir.IntType(32), 0)
|
||
|
||
def _HandleMemcpyLlvm(self, args: list[ast.AST]) -> None:
|
||
Gen = self.Trans.LlvmGen
|
||
if 'llvm.memcpy' not in Gen.functions:
|
||
memcpy_type = ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64), ir.IntType(1)])
|
||
Gen.functions['llvm.memcpy'] = Gen._CreateOrReuseFuncDecl('llvm.memcpy', memcpy_type)
|
||
if len(args) >= 3:
|
||
dst = self.HandleExprLlvm(args[0])
|
||
src = self.HandleExprLlvm(args[1])
|
||
size = self.HandleExprLlvm(args[2])
|
||
if dst and src and size:
|
||
i8ptr = ir.PointerType(ir.IntType(8))
|
||
if isinstance(dst.type, ir.PointerType) and dst.type != i8ptr:
|
||
dst = Gen.builder.bitcast(dst, i8ptr, name="memcpy_dst_cast")
|
||
elif isinstance(dst.type, ir.IntType):
|
||
if dst.type.width < 64:
|
||
dst = Gen.builder.zext(dst, ir.IntType(64), name="zext_dst_ptr")
|
||
dst = Gen.builder.inttoptr(dst, i8ptr, name="dst_int2ptr")
|
||
if isinstance(src.type, ir.PointerType) and src.type != i8ptr:
|
||
src = Gen.builder.bitcast(src, i8ptr, name="memcpy_src_cast")
|
||
elif isinstance(src.type, ir.IntType):
|
||
if src.type.width < 64:
|
||
src = Gen.builder.zext(src, ir.IntType(64), name="zext_src_ptr")
|
||
src = Gen.builder.inttoptr(src, i8ptr, name="src_int2ptr")
|
||
if isinstance(size.type, ir.IntType) and size.type.width < 64:
|
||
size = Gen.builder.zext(size, ir.IntType(64), name="zext_memcpy_size")
|
||
isvolatile = ir.Constant(ir.IntType(1), 0)
|
||
Gen.builder.call(Gen.functions['llvm.memcpy'], [dst, src, size, isvolatile], name="memcpy_call")
|
||
return None
|
||
|
||
def _HandleMemsetLlvm(self, args: list[ast.AST]) -> None:
|
||
Gen = self.Trans.LlvmGen
|
||
memset_func = Gen.get_or_declare_c_func('memset', ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.IntType(32), ir.IntType(64)]))
|
||
if len(args) >= 3:
|
||
dst = self.HandleExprLlvm(args[0])
|
||
val = self.HandleExprLlvm(args[1])
|
||
size = self.HandleExprLlvm(args[2])
|
||
if dst and val is not None and size:
|
||
if isinstance(dst.type, ir.PointerType) and not self._is_char_pointer(dst):
|
||
dst = Gen.builder.bitcast(dst, ir.PointerType(ir.IntType(8)), name="memset_dst_cast")
|
||
if isinstance(val.type, ir.IntType) and val.type.width != 32:
|
||
if val.type.width < 32:
|
||
val = Gen.builder.zext(val, ir.IntType(32), name="zext_memset_val")
|
||
else:
|
||
val = Gen.builder.trunc(val, ir.IntType(32), name="trunc_memset_val")
|
||
if isinstance(size.type, ir.IntType) and size.type.width < 64:
|
||
size = Gen.builder.zext(size, ir.IntType(64), name="zext_memset_size")
|
||
elif isinstance(size.type, ir.IntType) and size.type.width > 64:
|
||
size = Gen.builder.trunc(size, ir.IntType(64), name="trunc_memset_size")
|
||
Gen.builder.call(memset_func, [dst, val, size], name="memset_call")
|
||
return None
|
||
|
||
def _HandleVaStartLlvm(self, args: list[ast.AST]) -> None:
|
||
Gen = self.Trans.LlvmGen
|
||
return None
|
||
|
||
def _HandleVaEndLlvm(self, args: list[ast.AST]) -> None:
|
||
Gen = self.Trans.LlvmGen
|
||
return None
|
||
|
||
def _HandleVaArgLlvm(self, args: list[ast.AST]) -> ir.Constant:
|
||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||
return ir.Constant(ir.IntType(32), 0)
|
||
|
||
def _HandleCDerefAsLlvm(self, Node: ast.Call) -> ir.Value | None:
|
||
"""DerefAs(p, v):bitcast **指针** p 到 typeof(v)* 后按值存 v(`*(T*(p)) = v`)。
|
||
|
||
与 ViperC CallGenCBuiltin.translate_c_derefas 逐字同口径:
|
||
- 单参形式(len<2)是**解引用读取**(等同 Deref(p));
|
||
- 双参:p、v 均为指针且 p 的 pointee 是结构体且与 v 的 pointee **同一**时,
|
||
按整对象拷贝(load v 指向的对象 + bitcast p + store);否则 bitcast p 到
|
||
typeof(v)* 后按值 store v。
|
||
此前实现把**值** bitcast 成指针大小整数再写(`*(intptr_t*(p)) = (intptr_t)v`),
|
||
与语义不符(R5 混淆了"bitcast 指针"与"bitcast 值")。
|
||
"""
|
||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||
if Node.args is None or len(Node.args) < 1:
|
||
return ir.Constant(ir.IntType(32), 0)
|
||
if len(Node.args) < 2:
|
||
# 单参:解引用读取(与 VPC translate_c_derefas 的转发口径一致)
|
||
return self.Trans.CSpecialCallHandle._HandleCDerefLlvm(Node)
|
||
ptr_val: ir.Value | None = self.HandleExprLlvm(Node.args[0])
|
||
val_val: ir.Value | None = self.HandleExprLlvm(Node.args[1])
|
||
if ptr_val is None or val_val is None:
|
||
return ir.Constant(ir.IntType(32), 0)
|
||
if not isinstance(ptr_val.type, ir.PointerType):
|
||
return val_val
|
||
# 整对象拷贝:p 的 pointee 是结构体且与 v 的 pointee 同一(REnum 变体 tag 才不会丢)
|
||
if isinstance(val_val.type, ir.PointerType):
|
||
p_pointee: ir.Type = ptr_val.type.pointee
|
||
v_pointee: ir.Type = val_val.type.pointee
|
||
if (isinstance(p_pointee, (ir.IdentifiedStructType, ir.LiteralStructType))
|
||
and p_pointee == v_pointee):
|
||
loaded_s: ir.Value = Gen._load(val_val, name="deref_as_struct_load")
|
||
store_ptr: ir.Value = ptr_val
|
||
if store_ptr.type != val_val.type:
|
||
store_ptr = Gen.builder.bitcast(ptr_val, val_val.type, name="deref_as_ptr_align")
|
||
Gen._store(loaded_s, store_ptr)
|
||
return val_val
|
||
# 常规:bitcast p 到 typeof(v)* 后按值存 v(`*(T*(p)) = v`)
|
||
if ptr_val.type.pointee != val_val.type:
|
||
ptr_val = Gen.builder.bitcast(ptr_val, ir.PointerType(val_val.type), name="deref_as_cast")
|
||
Gen._store(val_val, ptr_val)
|
||
return val_val
|
||
|
||
def _InjectRequiresFields(self, result: ir.Value, ClassName: str, Gen: LlvmGeneratorMixin) -> None:
|
||
"""在 __new__ 后、__init__ 前自动注入 __requires__/__require_must__ 字段。
|
||
|
||
- 编译期:对 __require_must__ 做纯静态可达性检查(遍历 _with_provides_stack)
|
||
- 运行时:对每个 requires 字段调用 _find_provider,非 NULL 则 bitcast 写入
|
||
"""
|
||
requires_all: list[str] = []
|
||
requires_all.extend(Gen.class_requires.get(ClassName, []))
|
||
requires_all.extend(Gen.class_require_must.get(ClassName, []))
|
||
if not requires_all:
|
||
return
|
||
# 编译期 __require_must__ 静态检查
|
||
must_fields: list[str] = Gen.class_require_must.get(ClassName, [])
|
||
if must_fields:
|
||
# 跳过类自身方法内的检查(类的实现内部不需要 with 上下文)
|
||
current_class = getattr(Gen, '_current_class_name', None)
|
||
if current_class != ClassName:
|
||
available: set[str] = set()
|
||
for provides_list in Gen._with_provides_stack:
|
||
available.update(provides_list)
|
||
for field in must_fields:
|
||
if field not in available:
|
||
raise SyntaxError(
|
||
f"[TransPyC] Class '{ClassName}' __require_must__ field '{field}' "
|
||
f"not provided by any enclosing 'with' context"
|
||
)
|
||
# 运行时注入
|
||
find_func = Gen.functions.get('_find_provider')
|
||
if not find_func:
|
||
return
|
||
members = Gen.class_members.get(ClassName, [])
|
||
# base(vtable 占位槽数)统一走 Gen._member_base(唯一真源)。
|
||
base = Gen._member_base(ClassName)
|
||
field_map: dict[str, tuple[int, ir.Type]] = {}
|
||
for i, (mname, mtype) in enumerate(members):
|
||
if mname in requires_all:
|
||
field_map[mname] = (base + i, mtype)
|
||
for field_name in requires_all:
|
||
if field_name not in field_map:
|
||
continue
|
||
field_idx, field_type = field_map[field_name]
|
||
field_str = Gen._create_string_global(field_name)
|
||
ptr_val = Gen.builder.call(find_func, [field_str], name=f"find_{field_name}")
|
||
null_ptr = ir.Constant(ptr_val.type, None)
|
||
is_null = Gen.builder.icmp_unsigned('==', ptr_val, null_ptr, name=f"is_null_{field_name}")
|
||
skip_bb = Gen.func.append_basic_block(f"skip_inject_{field_name}")
|
||
inject_bb = Gen.func.append_basic_block(f"inject_{field_name}")
|
||
Gen.builder.cbranch(is_null, skip_bb, inject_bb)
|
||
Gen.builder.position_at_end(inject_bb)
|
||
if isinstance(field_type, ir.PointerType):
|
||
casted = Gen.builder.bitcast(ptr_val, field_type, name=f"cast_{field_name}")
|
||
elif isinstance(field_type, ir.IntType):
|
||
casted = Gen.builder.ptrtoint(ptr_val, field_type, name=f"cast_{field_name}")
|
||
else:
|
||
casted = Gen.builder.bitcast(ptr_val, ir.PointerType(ir.IntType(8)), name=f"cast_{field_name}")
|
||
elem_ptr = Gen.builder.gep(result, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), field_idx)], name=f"field_{field_name}_ptr")
|
||
Gen._store(casted, elem_ptr)
|
||
Gen.builder.branch(skip_bb)
|
||
Gen.builder.position_at_end(skip_bb)
|
||
|
||
# _HandleNewExprLlvm - Viper `new [描述符...] T(args)`(vast ExprParser 产出 ast.New)。
|
||
# - memgr(x):按 sizeof(T) 从 x.alloc 取存储(T*),置 Gen.NewStorageOverride 供
|
||
# _HandleClassNewLlvm / _HandleREnumConstructLlvm 复用(否则它们各自 alloca);
|
||
# - 其余(stack/heap/hlife/slife/缺省):与旧 _ExpandNewExprs 容忍层同语义 —— 等价
|
||
# 裸构造 T(args)(TPC 的类/REnum 构造自带存储策略)。
|
||
def _HandleNewExprLlvm(self, Node: ast.New) -> ir.Value | None:
|
||
"""`new [描述符...] T(args)`:取存储 + 构造;返回 T*(失败响亮失败)"""
|
||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||
# 合成裸构造 Call(VPC New 节点不携带 keywords)
|
||
ArgList: list = Node.args if Node.args is not None else []
|
||
cl: ast.Call = ast.Call(func=Node.func, args=list(ArgList), keywords=[])
|
||
cl.lineno = getattr(Node, 'lineno', 0)
|
||
cl.col_offset = getattr(Node, 'col_offset', 0)
|
||
cl.end_lineno = getattr(Node, 'end_lineno', 0)
|
||
cl.end_col_offset = getattr(Node, 'end_col_offset', 0)
|
||
if Node.Source != NEW_SRC_MEMGR or Node.memgr is None:
|
||
return self.HandleExprLlvm(cl)
|
||
# ---- memgr(x):池分配 ----
|
||
StructType: ir.Type | None = self._ResolveNewMemgrType(Node)
|
||
if StructType is None:
|
||
from lib.core.LLVMCG.FuncGen import FailFastError
|
||
raise FailFastError(
|
||
f"`new memgr(x) T(args)`:被构造类型 T 既不是已注册类/REnum 变体,也不是"
|
||
f"可解析的标量/数组(memgr 路径需要具体布局算尺寸){Gen._get_node_info()}")
|
||
size_bytes: int = Gen._get_struct_size(StructType)
|
||
# raw = <memgr>.alloc(sizeof(T)) —— 复用既有方法调用通道(mlirlite._new_type 同款)
|
||
SizeNode: ast.Constant = ast.Constant(value=size_bytes, kind=None)
|
||
SizeNode.lineno = cl.lineno
|
||
SizeNode.col_offset = cl.col_offset
|
||
AllocAttr: ast.Attribute = ast.Attribute(value=Node.memgr, attr='alloc', ctx=ast.Load())
|
||
AllocAttr.lineno = cl.lineno
|
||
AllocAttr.col_offset = cl.col_offset
|
||
AllocCall: ast.Call = ast.Call(func=AllocAttr, args=[SizeNode], keywords=[])
|
||
AllocCall.lineno = cl.lineno
|
||
AllocCall.col_offset = cl.col_offset
|
||
Raw: ir.Value | None = self.HandleExprLlvm(AllocCall)
|
||
if Raw is None:
|
||
from lib.core.LLVMCG.FuncGen import FailFastError
|
||
raise FailFastError(
|
||
f"`new memgr(x)`:x.alloc({size_bytes}) 求值失败(x 需为可 alloc 的内存管理器)"
|
||
f"{Gen._get_node_info()}")
|
||
TargetPtrType: ir.Type = ir.PointerType(StructType)
|
||
Storage: ir.Value
|
||
if isinstance(Raw.type, ir.PointerType) and Raw.type != TargetPtrType:
|
||
Storage = Gen.builder.bitcast(Raw, TargetPtrType, name="new_memgr_ptr_cast")
|
||
elif isinstance(Raw.type, ir.IntType):
|
||
Storage = Gen.builder.inttoptr(Raw, TargetPtrType, name="new_memgr_int2ptr")
|
||
else:
|
||
Storage = Raw
|
||
Prev: object = Gen.NewStorageOverride
|
||
Gen.NewStorageOverride = Storage
|
||
try:
|
||
return self.HandleExprLlvm(cl)
|
||
finally:
|
||
Gen.NewStorageOverride = Prev
|
||
|
||
def _ResolveNewMemgrType(self, Node: ast.New) -> ir.Type | None:
|
||
"""`new memgr(x) T(args)` 的 T 的 LLVM 结构类型(REnum 变体 / 普通类);
|
||
非类/REnum(标量/数组等)返回 None(由调用方响亮失败)。"""
|
||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||
fn: ast.AST | None = Node.func
|
||
if fn is None:
|
||
return None
|
||
# REnum 变体:Qual.Variant / mod.Qual.Variant(Qual 为已注册 REnum 类)
|
||
if isinstance(fn, ast.Attribute):
|
||
Qual: str | None = None
|
||
Base: ast.AST | None = fn.value
|
||
if isinstance(Base, ast.Name):
|
||
Qual = Base.id
|
||
elif isinstance(Base, ast.Attribute):
|
||
Qual = Base.attr
|
||
if Qual is not None:
|
||
QSym = self.Trans.SymbolTable.lookup(Qual)
|
||
if QSym is not None and getattr(QSym, 'IsRenum', False):
|
||
if Qual not in Gen.structs:
|
||
self.Trans.ImportHandler._TryLoadStructFromStub(Qual, Gen)
|
||
return Gen.structs.get(Qual)
|
||
# 普通类构造:ClassName(...) / mod.ClassName(...)
|
||
ClsName: str | None = None
|
||
if isinstance(fn, ast.Name):
|
||
ClsName = fn.id
|
||
elif isinstance(fn, ast.Attribute):
|
||
ClsName = fn.attr
|
||
if ClsName is not None:
|
||
if ClsName not in Gen.structs:
|
||
self.Trans.ImportHandler._TryLoadStructFromStub(ClsName, Gen)
|
||
return Gen.structs.get(ClsName)
|
||
return None
|
||
|
||
def _HandleClassNewLlvm(self, Node: ast.Call, ClassName: str, module_sha1: str | None = None) -> ir.Value:
|
||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||
# DEBUG: 追踪 Asm 类的构造
|
||
if ClassName == 'Asm':
|
||
import sys as _dbg_sys
|
||
print(f"[DEBUG_CLASSNEW] _HandleClassNewLlvm called for Asm, module_sha1={module_sha1}", file=_dbg_sys.stderr)
|
||
# 跨模块类型引用:优先用 {module_sha1}.{ClassName} 查找 struct
|
||
_struct_full_key: str | None = f"{module_sha1}.{ClassName}" if module_sha1 else None
|
||
if hasattr(self.Trans.ClassHandler, '_generic_class_templates') and ClassName in self.Trans.ClassHandler._generic_class_templates:
|
||
return self._HandleGenericClassNewLlvm(Node, ClassName)
|
||
NewFuncName = f'{ClassName}.__before_init__'
|
||
InitFuncName = f'{ClassName}.__init__'
|
||
NewMethodFuncName = f'{ClassName}.__new__'
|
||
has_new_method = Gen._find_function(NewMethodFuncName) is not None
|
||
|
||
# 【self 的类型必须与 callee 同源(2026-09-30)】
|
||
# `Gen.structs` 的键有"裸短名 / sha1 全名 / import 别名"三种:定义端恒以**短名**
|
||
# 作键(StructGen._generate_structs),别名注册只是**浅拷贝**(HandlesImports 对
|
||
# `Gen.structs[asname] = Gen.structs[name]`)。因此"两个模块各定义同名类"时,
|
||
# `ClassName` 无论是别名(`from .astaux import Keyword as KwNode` ⇒ 'KwNode')、
|
||
# 还是被别的模块先占用的短名('Keyword' 被 .tokens 占用),按名字查都可能拿到
|
||
# **另一份实例**。唯一无歧义的判据是 **callee 自己**:构造函数
|
||
# (__new__/__before_init__/__init__)第 0 个形参(self)的 pointee 就是编译器
|
||
# 写下的期望类型,也正是 `_adjust_args` 用来比较的对象(llvmlite 的类型相等按
|
||
# **IR 名字**判定,实测同名不同对象 `==` 为真,故取 callee 形参的 pointee 即与之
|
||
# 逐字同名;按短名另取一份只会继续 fail-fast)。
|
||
# 现场:includes/ast/parser.vp:1774 `kw: rawptr[AST] = KwNode(ps.pool, None, val)`
|
||
# —— callee 是 astaux 的 `8312ce86a2fd82c0.Keyword.__new__`,self 实参却按
|
||
# 短名/别名叫到了 tokens 的 `fef783da4d24330d.Keyword` ⇒
|
||
# "指针隐式转换已禁止(非基本类型(结构体/类/联合))"。
|
||
def _CalleeSelfType() -> ir.Type | None:
|
||
"""callee 第 0 个形参 self 的 pointee(未具化时按 IR 名补已具化的同类型)。
|
||
|
||
按 __new__ → __before_init__ → __init__ 顺序取第一个可用的:三者都是 self
|
||
的接收者,且同名类的多份实例只可能因"查名"分歧而不同源,取 callee 侧即可
|
||
消除分歧。取不到(无形参 / 非具名结构体)时返回 None,调用方退回按名字查。
|
||
未具化的实例不能用于 `_allocaEntry`(算不出尺寸),故按 **IR 名**换已具化的
|
||
同类型对象 —— IR 里类型的身份就是名字,同名即同类型(判据同
|
||
`BaseGen._FindStructByIrName` 的文档)。
|
||
"""
|
||
for _fn_name in (NewMethodFuncName, NewFuncName, InitFuncName):
|
||
_Fn: Any = Gen._find_function(_fn_name)
|
||
_Args: Any = getattr(getattr(_Fn, 'function_type', None), 'args', None)
|
||
if not _Args:
|
||
continue
|
||
_P0: Any = _Args[0]
|
||
if not isinstance(_P0, ir.PointerType):
|
||
continue
|
||
_PT: Any = _P0.pointee
|
||
if not isinstance(_PT, ir.IdentifiedStructType):
|
||
continue
|
||
if _PT.elements is not None:
|
||
return _PT
|
||
_Twin: Any = Gen._FindStructByIrName(getattr(_PT, 'name', '') or '')
|
||
if isinstance(_Twin, ir.IdentifiedStructType) and _Twin.elements is not None:
|
||
return _Twin
|
||
return None
|
||
|
||
def _get_struct_type(name: str) -> ir.Type | None:
|
||
"""self 用的 struct:callee 形参(无歧义)→ sha1 全名键 → 名字键"""
|
||
_SelfTy: ir.Type | None = _CalleeSelfType()
|
||
if _SelfTy is not None:
|
||
return _SelfTy
|
||
if _struct_full_key and _struct_full_key in Gen.structs:
|
||
return Gen.structs[_struct_full_key]
|
||
return Gen.structs.get(name)
|
||
|
||
if ClassName == 'Asm':
|
||
import sys as _dbg_sys
|
||
print(f"[DEBUG_CLASSNEW] Asm: has_before_init={Gen._has_function(NewFuncName)}, has_new={has_new_method}, struct_in_gen={ClassName in Gen.structs}", file=_dbg_sys.stderr)
|
||
if Gen._has_function(NewFuncName):
|
||
NewFunc = Gen._get_function(NewFuncName)
|
||
StructType = _get_struct_type(ClassName)
|
||
if StructType:
|
||
# `new memgr(x) ClassName(args)`:_HandleNewExprLlvm 已取好池存储 → 复用;
|
||
# 裸 `ClassName(args)` / 非 memgr 描述符时 NewStorageOverride 为 None → alloca。
|
||
if Gen.NewStorageOverride is not None:
|
||
result = Gen.NewStorageOverride
|
||
else:
|
||
result = Gen._allocaEntry(StructType, name=f"{ClassName}_alloca")
|
||
else:
|
||
return ir.Constant(ir.IntType(32), 0)
|
||
Gen.builder.call(NewFunc, [result], name=f"before_init_{ClassName}")
|
||
if has_new_method:
|
||
NewMethodFunc = Gen._find_function(NewMethodFuncName)
|
||
if NewMethodFunc:
|
||
NewMethodArgs = [result]
|
||
for ArgIdx, arg in enumerate(Node.args, start=1):
|
||
ArgVal = self._RequireArgValue(self.HandleExprLlvm(arg), f"{ClassName}.__new__", ArgIdx, arg, Node)
|
||
NewMethodArgs.append(ArgVal)
|
||
self._fill_default_args(NewMethodArgs, NewMethodFunc, NewMethodFuncName)
|
||
self._ApplyKeywordArgs(Node, NewMethodArgs, NewMethodFunc, NewMethodFuncName, self_offset=1)
|
||
# 自动取址已收口到 Gen._adjust_args(唯一汇聚点,按 func.name 查表)。
|
||
adjusted_new = Gen._adjust_args(NewMethodArgs, NewMethodFunc)
|
||
heap_ptr = Gen.builder.call(NewMethodFunc, adjusted_new, name=f"new_{ClassName}")
|
||
if heap_ptr:
|
||
target_ptr_type = ir.PointerType(StructType) if StructType else None
|
||
if isinstance(heap_ptr.type, ir.PointerType):
|
||
# Bitcast the returned pointer to the struct pointer type if needed
|
||
if target_ptr_type and heap_ptr.type != target_ptr_type:
|
||
result = Gen.builder.bitcast(heap_ptr, target_ptr_type, name=f"new_{ClassName}_cast")
|
||
else:
|
||
result = heap_ptr
|
||
elif isinstance(heap_ptr.type, ir.IntType) and target_ptr_type:
|
||
# __new__ returned an integer (pointer as int), convert back to pointer
|
||
if heap_ptr.type.width < 64:
|
||
i64_val = Gen.builder.zext(heap_ptr, ir.IntType(64), name=f"new_{ClassName}_i64")
|
||
result = Gen.builder.inttoptr(i64_val, target_ptr_type, name=f"new_{ClassName}_ptr")
|
||
else:
|
||
result = Gen.builder.inttoptr(heap_ptr, target_ptr_type, name=f"new_{ClassName}_ptr")
|
||
# __new__ 后:对堆指针重新调用 __before_init__ 初始化默认值(alloca 的默认值已随 alloca 丢弃)
|
||
if has_new_method:
|
||
Gen.builder.call(NewFunc, [result], name=f"before_init_{ClassName}_heap")
|
||
# __new__ 后、__init__ 前:自动注入 requires 字段
|
||
self._InjectRequiresFields(result, ClassName, Gen)
|
||
if Gen._has_function(InitFuncName):
|
||
InitFunc = Gen._get_function(InitFuncName)
|
||
InitArgs = [result]
|
||
for ArgIdx, arg in enumerate(Node.args, start=1):
|
||
ArgVal = self._RequireArgValue(self.HandleExprLlvm(arg), f"{ClassName}.__init__", ArgIdx, arg, Node)
|
||
InitArgs.append(ArgVal)
|
||
self._fill_default_args(InitArgs, InitFunc, InitFuncName)
|
||
self._ApplyKeywordArgs(Node, InitArgs, InitFunc, InitFuncName, self_offset=1)
|
||
self._append_eh_msg_out_arg(InitArgs, InitFunc, Gen)
|
||
# 自动取址已收口到 Gen._adjust_args(唯一汇聚点,按 func.name 查表)。
|
||
adjusted_init = Gen._adjust_args(InitArgs, InitFunc)
|
||
Gen.builder.call(InitFunc, adjusted_init, name=f"init_{ClassName}")
|
||
return result
|
||
# 【两支合并(2026-09-30)】原实现的"sha1 全名键命中"那一支只解析 StructType、
|
||
# **不产出 alloca / 构造调用**,控制流随后落到函数末尾 `return i32 0` —— 即跨模块
|
||
# 同名类的构造会**静默不构造**("名字键命中"那一支才是完整实现)。`_get_struct_type`
|
||
# 现已统一「callee 形参 → sha1 全名键 → 名字键」的解析顺序,故两支可合并为一条
|
||
# 条件;行为差异只剩"不再静默返回 i32 0"。
|
||
if (_struct_full_key and _struct_full_key in Gen.structs) or ClassName in Gen.structs:
|
||
StructType = _get_struct_type(ClassName)
|
||
if isinstance(StructType, ir.PointerType):
|
||
StructType = StructType.pointee
|
||
is_opaque = isinstance(StructType, ir.IdentifiedStructType) and (StructType.elements is None or len(StructType.elements) == 0)
|
||
if is_opaque:
|
||
self._ensure_struct_declared(ClassName, module_sha1=module_sha1)
|
||
StructType = Gen.structs.get(ClassName, StructType)
|
||
if isinstance(StructType, ir.PointerType):
|
||
StructType = StructType.pointee
|
||
is_opaque = isinstance(StructType, ir.IdentifiedStructType) and (StructType.elements is None or len(StructType.elements) == 0)
|
||
if is_opaque:
|
||
return None
|
||
result = Gen._allocaEntry(StructType, name=f"{ClassName}_alloca")
|
||
# Call __new__ method if it exists (may replace self with heap pointer)
|
||
if has_new_method:
|
||
NewMethodFunc = Gen._find_function(NewMethodFuncName)
|
||
if NewMethodFunc:
|
||
NewMethodArgs = [result]
|
||
for ArgIdx, arg in enumerate(Node.args, start=1):
|
||
ArgVal = self._RequireArgValue(self.HandleExprLlvm(arg), f"{ClassName}.__new__", ArgIdx, arg, Node)
|
||
NewMethodArgs.append(ArgVal)
|
||
self._fill_default_args(NewMethodArgs, NewMethodFunc, NewMethodFuncName)
|
||
self._ApplyKeywordArgs(Node, NewMethodArgs, NewMethodFunc, NewMethodFuncName, self_offset=1)
|
||
# 自动取址已收口到 Gen._adjust_args(唯一汇聚点,按 func.name 查表)。
|
||
adjusted_new = Gen._adjust_args(NewMethodArgs, NewMethodFunc)
|
||
heap_ptr = Gen.builder.call(NewMethodFunc, adjusted_new, name=f"new_{ClassName}")
|
||
if heap_ptr:
|
||
target_ptr_type = ir.PointerType(StructType) if StructType else None
|
||
if isinstance(heap_ptr.type, ir.PointerType):
|
||
# Bitcast the returned pointer to the struct pointer type if needed
|
||
if target_ptr_type and heap_ptr.type != target_ptr_type:
|
||
result = Gen.builder.bitcast(heap_ptr, target_ptr_type, name=f"new_{ClassName}_cast")
|
||
else:
|
||
result = heap_ptr
|
||
elif isinstance(heap_ptr.type, ir.IntType) and target_ptr_type:
|
||
# __new__ returned an integer (pointer as int), convert back to pointer
|
||
if heap_ptr.type.width < 64:
|
||
i64_val = Gen.builder.zext(heap_ptr, ir.IntType(64), name=f"new_{ClassName}_i64")
|
||
result = Gen.builder.inttoptr(i64_val, target_ptr_type, name=f"new_{ClassName}_ptr")
|
||
else:
|
||
result = Gen.builder.inttoptr(heap_ptr, target_ptr_type, name=f"new_{ClassName}_ptr")
|
||
# __new__ 后:对堆指针调用 __before_init__ 初始化默认值
|
||
if has_new_method and Gen._has_function(NewFuncName):
|
||
NewFunc = Gen._get_function(NewFuncName)
|
||
Gen.builder.call(NewFunc, [result], name=f"before_init_{ClassName}_heap")
|
||
# __new__ 后、__init__ 前:自动注入 requires 字段
|
||
self._InjectRequiresFields(result, ClassName, Gen)
|
||
InitFunc = Gen.functions.get(InitFuncName)
|
||
if not InitFunc:
|
||
g = Gen.module.globals.get(InitFuncName)
|
||
if g and isinstance(g, ir.Function):
|
||
Gen.functions[InitFuncName] = g
|
||
InitFunc = g
|
||
if InitFunc:
|
||
InitArgs = [result]
|
||
init_param_types = InitFunc.function_type.args if hasattr(InitFunc, 'function_type') else []
|
||
for i, arg in enumerate(Node.args):
|
||
arg_var_type = init_param_types[i + 1] if i + 1 < len(init_param_types) else None
|
||
ArgVal = self._RequireArgValue(self.HandleExprLlvm(arg, VarType=arg_var_type), f"{ClassName}.__init__", i + 1, arg, Node)
|
||
InitArgs.append(ArgVal)
|
||
self._fill_default_args(InitArgs, InitFunc, InitFuncName)
|
||
self._ApplyKeywordArgs(Node, InitArgs, InitFunc, InitFuncName, self_offset=1)
|
||
self._append_eh_msg_out_arg(InitArgs, InitFunc, Gen)
|
||
# 自动取址已收口到 Gen._adjust_args(唯一汇聚点,按 func.name 查表)。
|
||
adjusted_init = Gen._adjust_args(InitArgs, InitFunc)
|
||
Gen.builder.call(InitFunc, adjusted_init, name=f"init_{ClassName}")
|
||
elif Node.args or Node.keywords:
|
||
self._InitStructDefaults(result, ClassName, StructType)
|
||
self._InitStructFromArgs(result, Node, ClassName, StructType)
|
||
else:
|
||
self._InitStructDefaults(result, ClassName, StructType)
|
||
return result
|
||
return ir.Constant(ir.IntType(32), 0)
|
||
|
||
def _ZeroInitStruct(self, struct_ptr: ir.Value, StructType: ir.Type) -> None:
|
||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||
if isinstance(StructType, ir.IdentifiedStructType) and StructType.elements:
|
||
for i, elem_type in enumerate(StructType.elements):
|
||
elem_ptr = Gen.builder.gep(struct_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), i)], name=f"zero_elem_{i}")
|
||
zero_val = self._GetZeroValue(elem_type)
|
||
if zero_val is not None:
|
||
Gen._store(zero_val, elem_ptr)
|
||
elif isinstance(StructType, ir.IntType):
|
||
Gen._store(ir.Constant(StructType, 0), struct_ptr)
|
||
elif isinstance(StructType, ir.ArrayType) and isinstance(StructType.pointee, ir.IntType):
|
||
zero_arr = ir.Constant(StructType, None)
|
||
Gen._store(zero_arr, struct_ptr)
|
||
|
||
def _GetZeroValue(self, typ: ir.Type) -> ir.Constant | None:
|
||
if isinstance(typ, ir.IntType):
|
||
return ir.Constant(typ, 0)
|
||
elif isinstance(typ, ir.PointerType):
|
||
return ir.Constant(typ, None)
|
||
elif isinstance(typ, (ir.FloatType, ir.DoubleType)):
|
||
return ir.Constant(typ, 0.0)
|
||
elif isinstance(typ, ir.ArrayType):
|
||
return ir.Constant(typ, None)
|
||
return None
|
||
|
||
def _InitStructDefaults(self, struct_ptr: ir.Value, ClassName: str, StructType: ir.Type) -> None:
|
||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||
defaults: dict = Gen.class_member_defaults.get(ClassName, {})
|
||
members: list[tuple] = Gen.class_members.get(ClassName, [])
|
||
if not defaults or not members:
|
||
return
|
||
if not isinstance(StructType, ir.IdentifiedStructType):
|
||
return
|
||
# base(vtable 占位槽数)统一走 Gen._member_base(唯一真源)。
|
||
base = Gen._member_base(ClassName)
|
||
for i, (member_name, member_type) in enumerate(members):
|
||
if member_name in defaults:
|
||
default_val = defaults[member_name]
|
||
if isinstance(default_val, ir.Constant):
|
||
elem_ptr = Gen.builder.gep(struct_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), base + i)], name=f"default_{ClassName}_{member_name}")
|
||
Gen._store(default_val, elem_ptr)
|
||
|
||
def _InitStructFromArgs(self, struct_ptr: ir.Value, Node: ast.Call, ClassName: str, StructType: ir.Type) -> None:
|
||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||
if not isinstance(StructType, ir.IdentifiedStructType):
|
||
return
|
||
members = Gen.class_members.get(ClassName, [])
|
||
# base(vtable 占位槽数)统一走 Gen._member_base(唯一真源)。
|
||
base = Gen._member_base(ClassName)
|
||
for i, arg in enumerate(Node.args):
|
||
if i >= len(members):
|
||
break
|
||
val = self.HandleExprLlvm(arg)
|
||
if not val:
|
||
continue
|
||
member_name, member_type = members[i]
|
||
elem_idx = base + i
|
||
if StructType.elements is None or elem_idx >= len(StructType.elements):
|
||
break
|
||
elem_type = StructType.elements[elem_idx]
|
||
if isinstance(elem_type, ir.IntType) and isinstance(val.type, ir.IntType):
|
||
if val.type.width < elem_type.width:
|
||
val = Gen.builder.zext(val, elem_type, name=f"zext_init_{ClassName}_{i}")
|
||
elif val.type.width > elem_type.width:
|
||
val = Gen.builder.trunc(val, elem_type, name=f"trunc_init_{ClassName}_{i}")
|
||
elif isinstance(elem_type, ir.PointerType) and isinstance(val.type, ir.PointerType):
|
||
if val.type.pointee != elem_type.pointee:
|
||
val = Gen.builder.bitcast(val, elem_type, name=f"bitcast_init_{ClassName}_{i}")
|
||
elem_ptr = Gen.builder.gep(struct_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), elem_idx)], name=f"init_elem_{ClassName}_{member_name}")
|
||
Gen._store(val, elem_ptr)
|
||
if Node.keywords:
|
||
member_map = {name: (base + i) for i, (name, _) in enumerate(members)}
|
||
for kw in Node.keywords:
|
||
if kw.arg in member_map:
|
||
val = self.HandleExprLlvm(kw.value)
|
||
if not val:
|
||
continue
|
||
elem_idx = member_map[kw.arg]
|
||
if StructType.elements is None or elem_idx >= len(StructType.elements):
|
||
continue
|
||
elem_type = StructType.elements[elem_idx]
|
||
if isinstance(elem_type, ir.IntType) and isinstance(val.type, ir.IntType):
|
||
if val.type.width < elem_type.width:
|
||
val = Gen.builder.zext(val, elem_type, name=f"zext_init_{ClassName}_{kw.arg}")
|
||
elif val.type.width > elem_type.width:
|
||
val = Gen.builder.trunc(val, elem_type, name=f"trunc_init_{ClassName}_{kw.arg}")
|
||
elif isinstance(elem_type, ir.PointerType) and isinstance(val.type, ir.PointerType):
|
||
if val.type.pointee != elem_type.pointee:
|
||
val = Gen.builder.bitcast(val, elem_type, name=f"bitcast_init_{ClassName}_{kw.arg}")
|
||
elem_ptr = Gen.builder.gep(struct_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), elem_idx)], name=f"init_elem_{ClassName}_{kw.arg}")
|
||
Gen._store(val, elem_ptr)
|
||
|
||
def _HandleSubscriptPtrLlvm(self, Node: ast.Subscript) -> ir.Value | None:
|
||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||
# pointee-volatile 基址名后缀(同 HandlesExprAttr._HandleSubscriptLlvm);空后缀
|
||
# ⇒ 下标 GEP 名仍是 "subscript",既有代码 IR 逐字节不变。
|
||
_PVSuffix: str = Gen._SubscriptSuffix(Node.value)
|
||
ClassName: str | None = self.Trans.ExprHandler._get_var_class(Node.value, Gen)
|
||
if ClassName and ClassName in Gen.structs and Gen._has_function(f'{ClassName}.__getitem__'):
|
||
obj_val = self.HandleExprLlvm(Node.value)
|
||
idx_val = self.HandleExprLlvm(Node.slice)
|
||
if obj_val and idx_val:
|
||
# 处理 obj_val 为 i8(整数)的情况:联合类型 | CPtr 降级后可能被 load 为 i8
|
||
if isinstance(obj_val.type, ir.IntType) and obj_val.type.width == 8:
|
||
obj_val = Gen.builder.inttoptr(obj_val, ir.PointerType(ir.IntType(8)), name=f"i8_to_ptr_{ClassName}")
|
||
if self._is_char_pointer(obj_val):
|
||
obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
|
||
if isinstance(idx_val.type, ir.IntType) and idx_val.type.width < 64:
|
||
idx_val = Gen.builder.zext(idx_val, ir.IntType(64), name="zext_idx")
|
||
result = Gen.builder.call(Gen._get_function(f'{ClassName}.__getitem__'), [obj_val, idx_val], name=f"call_{ClassName}.__getitem__")
|
||
return result
|
||
ValueVal = self.HandleExprLlvm(Node.value)
|
||
if not ValueVal:
|
||
return None
|
||
IndexVal = self.HandleExprLlvm(Node.slice)
|
||
if not IndexVal:
|
||
return None
|
||
if isinstance(ValueVal.type, ir.IntType):
|
||
var_ptr = self._get_int_ptr(Node.value)
|
||
if var_ptr:
|
||
i8_ptr = Gen.builder.bitcast(var_ptr, ir.PointerType(ir.IntType(8)), name="int_to_i8ptr")
|
||
if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64:
|
||
IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_int_index")
|
||
ptr = Gen.builder.gep(i8_ptr, [IndexVal], name="int_subscript_ptr")
|
||
return ptr
|
||
return None
|
||
if isinstance(ValueVal.type, ir.PointerType) and isinstance(ValueVal.type.pointee, ir.PointerType):
|
||
LoadedValueVal = Gen._load(ValueVal, name="Load_subscript")
|
||
if isinstance(LoadedValueVal.type, ir.PointerType):
|
||
ElemPtr = Gen.builder.gep(LoadedValueVal, [IndexVal], name=f"subscript{_PVSuffix}")
|
||
return ElemPtr
|
||
if isinstance(ValueVal.type, ir.PointerType):
|
||
pointee = ValueVal.type.pointee
|
||
if isinstance(pointee, ir.ArrayType):
|
||
zero = ir.Constant(ir.IntType(32), 0)
|
||
if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32:
|
||
if IndexVal.type.width < 32:
|
||
IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index")
|
||
else:
|
||
IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index")
|
||
ElemPtr = Gen.builder.gep(ValueVal, [zero, IndexVal], name=f"subscript{_PVSuffix}")
|
||
return Gen._load(ElemPtr, name="arr_subscript_val")
|
||
else:
|
||
if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64:
|
||
IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_ptr_index")
|
||
ElemPtr = Gen.builder.gep(ValueVal, [IndexVal], name=f"subscript{_PVSuffix}")
|
||
if isinstance(pointee, ir.IntType):
|
||
return Gen._load(ElemPtr, name="subscript_val")
|
||
return ElemPtr
|
||
elif isinstance(ValueVal.type, ir.ArrayType):
|
||
zero = ir.Constant(ir.IntType(32), 0)
|
||
if isinstance(Node.value, ast.Name):
|
||
VarName = Node.value.id
|
||
if VarName in Gen.variables and Gen.variables[VarName] is not None:
|
||
VarPtr = Gen.variables[VarName]
|
||
if isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, ir.ArrayType):
|
||
if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32:
|
||
if IndexVal.type.width < 32:
|
||
IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index")
|
||
else:
|
||
IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index")
|
||
ElemPtr = Gen.builder.gep(VarPtr, [zero, IndexVal], name=f"subscript{_PVSuffix}")
|
||
return ElemPtr
|
||
arr_alloc = Gen._allocaEntry(ValueVal.type, name="arr_subscript_tmp")
|
||
Gen._store(ValueVal, arr_alloc)
|
||
ElemPtr = Gen.builder.gep(arr_alloc, [zero, IndexVal], name=f"subscript{_PVSuffix}")
|
||
return ElemPtr
|
||
return None
|
||
|
||
def _HandleGenericCallExplicitLlvm(self, Node: ast.Call, FuncName: str, explicit_slice: ast.AST) -> ir.Value | None:
|
||
"""处理泛型函数手动传类型参数的调用 xxx[T](x)。
|
||
|
||
与自动推导的 _HandleGenericCallLlvm 不同,这里从 explicit_slice
|
||
提取类型参数,而不是从参数值推导。
|
||
"""
|
||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||
template: dict = self.Trans.FunctionHandler._generic_templates[FuncName]
|
||
type_param_names: list[str] = template['type_params']
|
||
# 从 slice 提取类型参数
|
||
type_args: list[str] = []
|
||
slice_nodes: list[ast.AST] = []
|
||
if isinstance(explicit_slice, ast.Tuple):
|
||
slice_nodes = list(explicit_slice.elts)
|
||
else:
|
||
slice_nodes = [explicit_slice]
|
||
for sn in slice_nodes:
|
||
result = self._resolve_generic_slice_type(sn)
|
||
if result is not None:
|
||
type_args.append(result[0])
|
||
# 无法解析全部类型实参时禁止按 int 兜底(否则会特化出错误元素类型的函数)
|
||
if len(type_args) < len(type_param_names):
|
||
raise Exception(
|
||
f"泛型函数 '{FuncName}' 的显式类型实参无法全部解析:"
|
||
f"需要 {len(type_param_names)} 个,仅解析出 {len(type_args)} 个;"
|
||
f"禁止按 int 兜底。")
|
||
type_args = type_args[:len(type_param_names)]
|
||
# 特化
|
||
spec_name = self.Trans.FunctionHandler._specialize_generic_function(FuncName, type_args, Gen)
|
||
if spec_name is None:
|
||
return None
|
||
mangled_spec = Gen._mangle_func_name(spec_name)
|
||
func = None
|
||
if mangled_spec in Gen.functions:
|
||
func = Gen.functions[mangled_spec]
|
||
elif spec_name in Gen.functions:
|
||
func = Gen.functions[spec_name]
|
||
else:
|
||
for fname, fobj in Gen.functions.items():
|
||
if spec_name in fname or fname.endswith(spec_name):
|
||
func = fobj
|
||
break
|
||
if func is None:
|
||
return None
|
||
# 处理调用参数
|
||
CallArgs: list[ir.Value] = []
|
||
for arg_node in Node.args:
|
||
arg_val = self.HandleExprLlvm(arg_node)
|
||
if arg_val:
|
||
CallArgs.append(arg_val)
|
||
if not CallArgs:
|
||
CallArgs = [ir.Constant(ir.IntType(32), 0) for _ in func.args]
|
||
# 自动取址已收口到 Gen._adjust_args(唯一汇聚点,按 func.name 查表)。
|
||
adjusted = Gen._adjust_args(CallArgs, func)
|
||
return Gen.builder.call(func, adjusted, name=f"call_{spec_name}")
|
||
|
||
def _HandleGenericCallLlvm(self, Node: ast.Call, FuncName: str) -> ir.Value | None:
|
||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||
template: dict = self.Trans.FunctionHandler._generic_templates[FuncName]
|
||
type_param_names: list[str] = template['type_params']
|
||
type_args: list[str] = []
|
||
CallArgs: list[ir.Value] = []
|
||
for i, arg_node in enumerate(Node.args):
|
||
arg_val = self.HandleExprLlvm(arg_node)
|
||
if arg_val:
|
||
CallArgs.append(arg_val)
|
||
type_str = self.Trans.FunctionHandler._infer_type_arg_from_value(arg_val, Gen)
|
||
type_args.append(type_str)
|
||
else:
|
||
# 实参未产生 LLVM 值 ⇒ 无法推导其类型实参,禁止按 int 兜底
|
||
raise Exception(
|
||
f"泛型函数 '{FuncName}' 调用无法从第 {i + 1} 个实参推导类型实参;"
|
||
f"禁止按 int 兜底。")
|
||
if len(type_args) < len(type_param_names):
|
||
raise Exception(
|
||
f"泛型函数 '{FuncName}' 调用无法推导全部类型实参:"
|
||
f"需要 {len(type_param_names)} 个,仅推导出 {len(type_args)} 个;"
|
||
f"禁止按 int 兜底。")
|
||
type_args = type_args[:len(type_param_names)]
|
||
spec_name = self.Trans.FunctionHandler._specialize_generic_function(FuncName, type_args, Gen)
|
||
if spec_name is None:
|
||
return None
|
||
mangled_spec = Gen._mangle_func_name(spec_name)
|
||
func = None
|
||
if mangled_spec in Gen.functions:
|
||
func = Gen.functions[mangled_spec]
|
||
elif spec_name in Gen.functions:
|
||
func = Gen.functions[spec_name]
|
||
else:
|
||
for fname, fobj in Gen.functions.items():
|
||
if spec_name in fname or fname.endswith(spec_name):
|
||
func = fobj
|
||
break
|
||
if func is None:
|
||
return None
|
||
if not CallArgs:
|
||
CallArgs = [ir.Constant(ir.IntType(32), 0) for _ in func.args]
|
||
# 自动取址已收口到 Gen._adjust_args(唯一汇聚点,按 func.name 查表)。
|
||
adjusted = Gen._adjust_args(CallArgs, func)
|
||
return Gen.builder.call(func, adjusted, name=f"call_{spec_name}")
|
||
|
||
def _HandleGenericClassNewLlvm(self, Node: ast.Call, ClassName: str, explicit_slice: ast.AST | None = None) -> ir.Value:
|
||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||
template: dict = self.Trans.ClassHandler._generic_class_templates[ClassName]
|
||
type_param_names: list[str] = template['type_params']
|
||
type_args: list[str] = []
|
||
type_names: list[str] = []
|
||
# 如果有显式类型参数 (如 list[int](mb)),直接从 slice 提取
|
||
if explicit_slice is not None:
|
||
slice_nodes: list[ast.AST] = []
|
||
if isinstance(explicit_slice, ast.Tuple):
|
||
slice_nodes = list(explicit_slice.elts)
|
||
else:
|
||
slice_nodes = [explicit_slice]
|
||
for sn in slice_nodes:
|
||
result = self._resolve_generic_slice_type(sn)
|
||
if result is not None:
|
||
type_args.append(result[0])
|
||
type_names.append(result[1])
|
||
# 无法解析全部类型实参时禁止按 int 兜底(否则特化出错误元素类型的类)
|
||
if len(type_args) < len(type_param_names):
|
||
raise Exception(
|
||
f"泛型类 '{ClassName}' 的显式类型实参无法全部解析:"
|
||
f"需要 {len(type_param_names)} 个,仅解析出 {len(type_args)} 个;"
|
||
f"禁止按 int 兜底。")
|
||
spec_name = self.Trans.ClassHandler._specialize_generic_class(ClassName, type_args, Gen, type_names=type_names)
|
||
if spec_name is None:
|
||
return ir.Constant(ir.IntType(32), 0)
|
||
return self._HandleClassNewLlvm(Node, spec_name)
|
||
all_inferred: list[tuple[str, str]] = []
|
||
for i, arg_node in enumerate(Node.args):
|
||
type_str = 'int'
|
||
type_name = 'CInt'
|
||
if isinstance(arg_node, ast.Constant):
|
||
if isinstance(arg_node.value, float):
|
||
type_str = 'double'
|
||
type_name = 'CDouble'
|
||
elif isinstance(arg_node.value, int):
|
||
type_str = 'int'
|
||
type_name = 'CInt'
|
||
elif isinstance(arg_node.value, bool):
|
||
type_str = 'i8'
|
||
type_name = 'CBool'
|
||
elif isinstance(arg_node, ast.Call):
|
||
if isinstance(arg_node.func, ast.Name):
|
||
func_id = arg_node.func.id
|
||
if func_id == 'float':
|
||
type_str = 'double'
|
||
type_name = 'CDouble'
|
||
elif func_id == 'int':
|
||
type_str = 'int'
|
||
type_name = 'CInt'
|
||
elif func_id == 'char':
|
||
# char() 内建 i8 强转(与 float()/double() 并列)
|
||
type_str = 'i8'
|
||
type_name = 'CChar'
|
||
else:
|
||
float_types = {'CDouble', 'CFloat', 'CFloat64T', 'CFloat32T'}
|
||
int_types = {'CInt', 'CUInt', 'CInt32T', 'CUInt32T', 'CInt64T', 'CUInt64T', 'CInt16T', 'CUInt16T', 'CInt8T', 'CUInt8T', 'CShort', 'CLong'}
|
||
if func_id in float_types:
|
||
type_str = 'double'
|
||
type_name = func_id
|
||
elif func_id == 'CChar':
|
||
type_str = 'i8'
|
||
type_name = func_id
|
||
elif func_id in int_types:
|
||
type_str = 'int'
|
||
type_name = func_id
|
||
elif isinstance(arg_node.func, ast.Attribute):
|
||
attr_name = arg_node.func.attr
|
||
float_types = {'CDouble', 'CFloat', 'CFloat64T', 'CFloat32T'}
|
||
int_types = {'CInt', 'CUInt', 'CInt32T', 'CUInt32T', 'CInt64T', 'CUInt64T', 'CInt16T', 'CUInt16T', 'CInt8T', 'CUInt8T', 'CShort', 'CLong'}
|
||
if attr_name in float_types:
|
||
type_str = 'double'
|
||
type_name = attr_name
|
||
elif attr_name == 'CChar':
|
||
type_str = 'i8'
|
||
type_name = attr_name
|
||
elif attr_name in int_types:
|
||
type_str = 'int'
|
||
type_name = attr_name
|
||
elif isinstance(arg_node, ast.Name):
|
||
var_info = self.Trans.SymbolTable.lookup(arg_node.id)
|
||
if var_info and isinstance(var_info, dict):
|
||
var_type = var_info.get('type', '')
|
||
if var_type in ('double', 'float'):
|
||
type_str = 'double'
|
||
type_name = 'CDouble'
|
||
elif var_type in ('char', 'i8', 'CChar'):
|
||
type_str = 'i8'
|
||
type_name = 'CChar'
|
||
all_inferred.append((type_str, type_name))
|
||
hint_types = [(ts, tn) for ts, tn in all_inferred if tn != 'CInt' or ts != 'int']
|
||
for i in range(len(type_param_names)):
|
||
if i < len(hint_types):
|
||
type_args.append(hint_types[i][0])
|
||
type_names.append(hint_types[i][1])
|
||
elif i < len(all_inferred):
|
||
type_args.append(all_inferred[i][0])
|
||
type_names.append(all_inferred[i][1])
|
||
else:
|
||
# 第 i 个类型参数既无对应实参也无法推断 ⇒ 禁止按 int 兜底
|
||
raise Exception(
|
||
f"泛型类 '{ClassName}' 构造调用无法为第 {i + 1} 个类型参数推导实参;"
|
||
f"禁止按 int 兜底。")
|
||
spec_name = self.Trans.ClassHandler._specialize_generic_class(ClassName, type_args, Gen, type_names=type_names)
|
||
if spec_name is None:
|
||
return ir.Constant(ir.IntType(32), 0)
|
||
return self._HandleClassNewLlvm(Node, spec_name)
|
||
|