Files
TransPyC/lib/core/Handles/HandlesExprUtils.py
T
TermiNexus f19d25782f refactor(tpc): 退役 t/c 模块并将定宽类型升级为内建
删除 lib/includes/t.py、c.py,类型模型迁入 lib/core/TypeSystem.py;移除 IsTModule/_T_MODULE_NAMES 等名称判据,语法糖与内部标记统一为裸名;builtins 的 sizet/intN/uintN/fast/least/uchar/short/long 等改为编译器内建短名。
2026-10-18 13:00:58 +08:00

437 lines
23 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from __future__ import annotations
from typing import TYPE_CHECKING, Any
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
import vast as ast
import llvmlite.ir as ir
class ExprUtils:
def __init__(self, translator: "Translator") -> None:
self.Trans: Translator = translator
def GetOpSymbol(self, Op: ast.cmpop | ast.operator | ast.unaryoperator) -> str | None:
OpMap: dict[type, str] = {
ast.Add: '+', ast.Sub: '-', ast.Mult: '*', ast.Div: '/',
ast.FloorDiv: '//', ast.Mod: '%', ast.Pow: '**', ast.BitAnd: '&',
ast.BitOr: '|', ast.BitXor: '^', ast.LShift: '<<', ast.RShift: '>>',
ast.MatMult: '@',
}
return OpMap.get(type(Op), None)
def GetUnaryOpSymbol(self, Op: ast.unaryoperator) -> str | None:
OpMap: dict[type, str] = {
ast.Invert: '~', ast.Not: 'not', ast.UAdd: '+', ast.USub: '-',
ast.Deref: '*', ast.AddrOf: '&',
}
return OpMap.get(type(Op), None)
def GetComparatorSymbol(self, Op: ast.cmpop) -> str | None:
OpMap: dict[type, str] = {
ast.Eq: '==', ast.NotEq: '!=', ast.Lt: '<', ast.LtE: '<=',
ast.Gt: '>', ast.GtE: '>=', ast.Is: 'is', ast.IsNot: 'is not',
ast.In: 'in', ast.NotIn: 'not in',
}
return OpMap.get(type(Op), None)
def _get_var_class(self, node: ast.AST, Gen: LlvmCodeGenerator) -> str | None:
if isinstance(node, ast.Name):
VarName: str = node.id
return Gen.var_struct_class.get(VarName)
if isinstance(node, ast.Attribute):
AttrName: str = node.attr
# 从父对象的类成员类型推导(如 self._ht → ParsedArgs._ht → HashTable)
# 必须先查 BaseClass,避免字段名和变量名冲突导致错误分派
# (如 old_args.args 匹配到函数参数 args 的 var_struct_class='AST')
BaseClass: str | None = self._get_var_class(node.value, Gen)
if not BaseClass and isinstance(node.value, ast.Name) and node.value.id == 'self':
BaseClass = getattr(self.Trans, '_CurrentCpythonObjectClass', None)
if not BaseClass:
# 【模块别名 + 模块级变量】`Mod.Var` 形态(如 CompilerFactory.factory):
# var_struct_class 只登记**当前模块**变量,跨模块量不在其中 → 递归到此
# 返回 None → 整条链 `Mod.Var.Field` 解析为空 → 赋值/调用 fail-fast
# ("属性访问未能解析出目标类型/成员",StructGenMixin.vp:139 根因)。
BaseClass = self._resolve_module_var_class(Gen, node.value, AttrName)
if BaseClass:
# 对齐 _HandleLenLlvm L3445-3454:class_member_element_class /
# class_members 的键是裸类名,而 var_struct_class 可能带 sha1 前缀
# (如 'd81b22c853de40a2.Call')。直查会 miss → 容器字段
# (list[...] / rawptr[list[...]],如 ast.Call.args)方法分派失败
# → "Undefined method 'get' in class 'rawptr'"。剥前缀 + MRO 链查
# element_class(list 特化名,如 list[...ASTptr])优先。
_bare: str = BaseClass
if len(_bare) > 17 and _bare[16] == '.':
_bare = _bare[17:]
element_class_map = getattr(Gen, 'class_member_element_class', {})
try:
_mro_chain: list = Gen._get_mro_chain(_bare)
except Exception:
_mro_chain = [_bare]
for _mro_cls in _mro_chain:
_mk: str = _mro_cls
if len(_mk) > 17 and _mk[16] == '.':
_mk = _mk[17:]
_sub = element_class_map.get(_mk)
if _sub and AttrName in _sub:
return _sub[AttrName]
if _bare in Gen.class_members:
for m_name, m_type in Gen.class_members[_bare]:
if m_name == AttrName:
if isinstance(m_type, ir.PointerType) and isinstance(m_type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
found = Gen.find_struct_by_pointee(m_type.pointee)
if found:
return found[0]
break
# Fallback: 直接查找 var_struct_class(放在 BaseClass 查找之后,
# 避免字段名和变量名冲突导致错误分派)
cls: str | None = Gen.var_struct_class.get(AttrName)
if cls:
return cls
return None
return None
def _resolve_module_var_class(self, Gen: LlvmCodeGenerator, ModNode: ast.AST,
AttrName: str) -> str | None:
"""`模块别名.模块级变量` 的类名解析(如 CompilerFactory.factory)
背景:`CompilerFactory.factory.PermPool` 这类链的第一跳既不在
`var_struct_class`(只含当前模块变量)也不在 `global_struct_class`
(只含按变量名登记的项),于是 `_get_var_class` 递归到底返回 None →
整条链解析为空 → 赋值/调用 fail-fast("属性访问未能解析出目标类型/成员")。
这里按模块别名把 `Mod.Var` 落到其 LLVM 全局量,再从全局量类型反推结构体
类名;候选键形态对齐 `_lookup_module_global`(裸名 / {mod}.{var} /
{sha1}.{var})。仅当 ModNode 确为 import 模块(含别名)时生效。
"""
if not isinstance(ModNode, ast.Name):
return None
Mod: str = ModNode.id
imported: Any = getattr(self.Trans, '_ImportedModules', None) or []
sha1_map: Any = getattr(Gen, 'ModuleSha1Map', {}) or {}
try:
resolved_mod: str = self.Trans.SymbolTable.resolve_alias(Mod)
except Exception:
resolved_mod = Mod
aliases: Any = getattr(self.Trans.SymbolTable, 'import_aliases', {}) or {}
_is_mod: bool = (Mod in imported or resolved_mod in imported
or Mod in sha1_map or resolved_mod in sha1_map
or Mod in aliases or resolved_mod in aliases)
if not _is_mod:
# 兜底:ModuleSha1Map 的键多为全路径(lib.core.CompilerFactory),
# 用后缀扫描判定「Mod 是否确实是某个已导入模块(含别名)」。
for _k in sha1_map:
if _k == Mod or _k.endswith(f'.{Mod}'):
_is_mod = True
break
if not _is_mod:
return None
# 1) 变量名侧已有登记(stub 解析时跨模块量常以**裸变量名**登记)
gsc: Any = getattr(Gen, 'global_struct_class', {}) or {}
vsc: Any = getattr(Gen, 'var_struct_class', {}) or {}
for key in (f"{Mod}.{AttrName}", f"{resolved_mod}.{AttrName}", AttrName):
if key in gsc:
return gsc[key]
if key in vsc:
return vsc[key]
# 2) 借属性侧既有解析器(覆盖 module.globals/variables 与前缀形态)
try:
_via_attr: str | None = self.Trans.ExprAttrHandle._resolve_var_classname(Gen, AttrName)
except Exception:
_via_attr = None
if _via_attr:
return _via_attr
# 3) 从 LLVM 全局量类型反推结构体类名
cands: list[str] = [f"{Mod}.{AttrName}", AttrName]
for m in imported:
if m == Mod or m.endswith(f".{Mod}"):
k: str = f"{m}.{AttrName}"
if k not in cands:
cands.append(k)
for cand in (Mod, resolved_mod):
sha1: str | None = sha1_map.get(cand)
if sha1:
k2: str = f"{sha1}.{AttrName}"
if k2 not in cands:
cands.append(k2)
globals_map: Any = getattr(getattr(Gen, 'module', None), 'globals', {}) or {}
# 3b) 后缀扫描:全局量键常为 "{sha1}.{var}",sha1 不一定能从 Mod 反查到
for _gk in globals_map:
if _gk.endswith(f".{AttrName}") and _gk not in cands:
cands.append(_gk)
for key in cands:
gv: Any = globals_map.get(key)
if gv is None:
continue
ty: Any = getattr(gv, 'type', None)
if not isinstance(ty, ir.PointerType):
continue
pointee: Any = ty.pointee
# 全局量本身是指针变量(值类型 X*,LLVM 全局类型 X**)→ 再剥一层
if isinstance(pointee, ir.PointerType):
pointee = pointee.pointee
if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
found: Any = Gen.find_struct_by_pointee(pointee)
if found:
return found[0]
return None
def _try_operator_overLoad(self, ClassName: str, op_name: str, obj_val: ir.Value, Gen: LlvmCodeGenerator, other_val: ir.Value | None = None) -> ir.Value | None:
FullMethodName: str = f'{ClassName}.{op_name}'
if not Gen._has_function(FullMethodName):
FullMethodName = f'{ClassName}.{op_name}__'
if not Gen._has_function(FullMethodName):
# 多继承:沿 MRO 祖先链查找 dunder 方法(先声明父类优先,与 VPC 一致)
for anc in Gen._get_mro_chain(ClassName)[1:]:
anc_method: str = f'{anc}.{op_name}'
if Gen._has_function(anc_method):
FullMethodName = anc_method
break
anc_method_ss = f'{anc}.{op_name}__'
if Gen._has_function(anc_method_ss):
FullMethodName = anc_method_ss
break
if not Gen._has_function(FullMethodName):
# 泛型特化 fallback:当 ClassName 是 opaque 基础名(如 'ndarray')且
# 无直接匹配方法时,遍历 Gen.structs 查找以 'ClassName[' 开头的特化版本
# (如 'ndarray[double]')。注解 'numpy.ndarray | CPtr' 未指定类型参数时,
# var_struct_class 仅记录裸模板名,但方法只在特化版本中定义。
# 选择策略:优先选 obj_val.type.pointee 实际匹配的特化;否则选第一个有方法的特化。
if '[' not in ClassName:
SpecClass: str | None = None
# 先收集所有候选特化(有方法 declare 或 define 的)
best_candidates: list[str] = []
for CN in Gen.structs.keys():
if CN.startswith(f'{ClassName}[') and (Gen._has_function(f'{CN}.{op_name}') or Gen._has_function(f'{CN}.{op_name}__')):
best_candidates.append(CN)
# 优先选已编译方法体(define)的特化:dict 插入序选第一个会命中
# 只有 declare 无 define 的错误特化(如 list[AST]),生成 undefined
# symbol(ld.lld undefined symbol: list[AST].__len__ 根因)。
for CN in best_candidates:
_fn: str = f'{CN}.{op_name}' if Gen._has_function(f'{CN}.{op_name}') else f'{CN}.{op_name}__'
_f: Any = Gen._get_function(_fn)
if _f is not None and getattr(_f, 'blocks', []):
SpecClass = CN
break
if SpecClass is None and best_candidates:
# 全部只有 declare:按需补发方法体(幂等,_specialize_generic_class
# 缓存机制会从 declare_only 升级为完整特化),补发后重新检查
try:
self.Trans.ExprCallHandle._try_complete_generic_specialization(best_candidates[0], op_name, Gen)
except Exception:
pass
_fn2: str = f'{best_candidates[0]}.{op_name}' if Gen._has_function(f'{best_candidates[0]}.{op_name}') else f'{best_candidates[0]}.{op_name}__'
_f2: Any = Gen._get_function(_fn2)
if _f2 is not None and getattr(_f2, 'blocks', []):
SpecClass = best_candidates[0]
if SpecClass:
FullMethodName = f'{SpecClass}.{op_name}'
if not Gen._has_function(FullMethodName):
FullMethodName = f'{SpecClass}.{op_name}__'
if Gen._has_function(FullMethodName):
func: Any = Gen._get_function(FullMethodName)
# 多继承 this 调整:运算符重载方法定义在"无 vtable 父类"且字段区偏移 > 0 时,
# 把 self 定位到父类第一个用户字段在子类中的位置并 bitcast 成父类指针。
method_anc: str | None = None
_fm_short: str = FullMethodName.split('.')[-1] if '.' in FullMethodName else FullMethodName
if '.' in FullMethodName:
_fm_cls: str = FullMethodName.split('.')[0]
if _fm_cls != ClassName:
method_anc = _fm_cls
_call_self: Any = self.Trans.ExprCallHandle._adjust_this_for_inherited_method(Gen, obj_val, ClassName, method_anc)
call_args: list[Any] = [_call_self]
if other_val is not None:
call_args.append(other_val)
if len(func.ftype.args) == len(call_args):
for i, (expected_type, actual_val) in enumerate(zip(func.ftype.args, call_args)):
if isinstance(expected_type, ir.PointerType) and isinstance(actual_val.type, ir.PointerType):
if expected_type != actual_val.type:
if isinstance(expected_type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
call_args[i] = Gen.builder.bitcast(actual_val, expected_type, name=f"bitcast_arg_{i}")
result: Any = Gen.builder.call(func, call_args, name=f"call_{FullMethodName}")
return result
return None
def _llvm_type_to_detailed_string(self, llvm_type: ir.Type, var_name: str = "") -> dict[str, Any]:
info: dict[str, Any] = {
'name': "unknown",
'size': 0,
'signed': False,
'ptr': False
}
if isinstance(llvm_type, ir.IntType):
info['size'] = llvm_type.width // 8
info['signed'] = True
if llvm_type.width == 8:
info['name'] = "char"
elif llvm_type.width == 16:
info['name'] = "short"
elif llvm_type.width == 32:
info['name'] = "int"
elif llvm_type.width == 64:
info['name'] = "long long"
else:
info['name'] = f"int{llvm_type.width}"
elif isinstance(llvm_type, ir.DoubleType):
info['size'] = 8
info['signed'] = True
info['name'] = "double"
elif isinstance(llvm_type, ir.FloatType):
info['size'] = 4
info['signed'] = True
info['name'] = "float"
elif isinstance(llvm_type, ir.PointerType):
info['size'] = 8
info['signed'] = False
info['ptr'] = True
pointee_info: dict[str, Any] = self._llvm_type_to_detailed_string(llvm_type.pointee)
info['name'] = f"{pointee_info['name']}*"
elif isinstance(llvm_type, (ir.LiteralStructType, ir.IdentifiedStructType)):
size: int = 0
for elem in llvm_type.elements:
elem_info: dict[str, Any] = self._llvm_type_to_detailed_string(elem)
size += elem_info['size']
info['size'] = size
info['signed'] = False
if isinstance(llvm_type, ir.IdentifiedStructType):
info['name'] = llvm_type.name
else:
info['name'] = "struct"
elif isinstance(llvm_type, ir.ArrayType):
elem_info = self._llvm_type_to_detailed_string(llvm_type.element)
info['size'] = elem_info['size'] * llvm_type.count
info['signed'] = elem_info['signed']
info['name'] = f"{elem_info['name']}[]"
elif isinstance(llvm_type, ir.VoidType):
info['size'] = 0
info['signed'] = False
info['name'] = "void"
else:
info['size'] = 0
info['signed'] = False
info['name'] = str(llvm_type)
return info
def _infer_expr_llvm_type_full(self, node: ast.AST) -> ir.Type:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
if isinstance(node, ast.Constant):
if isinstance(node.value, bool):
return ir.IntType(32)
elif isinstance(node.value, int):
return ir.IntType(32)
elif isinstance(node.value, float):
return ir.DoubleType()
elif isinstance(node.value, str):
if getattr(node, 'kind', None) == 'u':
return ir.PointerType(ir.IntType(16))
return ir.PointerType(ir.IntType(8))
return ir.IntType(32)
elif isinstance(node, ast.Name):
if node.id in Gen.variables:
var_ptr: Any = Gen.variables[node.id]
if isinstance(var_ptr.type, ir.PointerType):
return var_ptr.type.pointee
return var_ptr.type
if node.id in Gen._reg_values:
return Gen._reg_values[node.id].type
return ir.IntType(32)
elif isinstance(node, ast.Attribute):
attr_name: str = node.attr
AttrInfo: Any = self.Trans.SymbolTable.lookup(attr_name)
if AttrInfo and getattr(AttrInfo, 'IsEnumMember', None):
# 枚举成员表达式的 LLVM 类型 = 该枚举的存储宽度(最宽成员类型)
return self.Trans.LlvmGen._enum_int_type(
getattr(AttrInfo, 'EnumName', None), AttrInfo)
return ir.IntType(32)
elif isinstance(node, ast.BinOp):
left_type: ir.Type = self._infer_expr_llvm_type_full(node.left)
right_type: ir.Type = self._infer_expr_llvm_type_full(node.right)
if isinstance(left_type, (ir.FloatType, ir.DoubleType)) or isinstance(right_type, (ir.FloatType, ir.DoubleType)):
return ir.DoubleType()
if isinstance(left_type, ir.PointerType) or isinstance(right_type, ir.PointerType):
return ir.PointerType(ir.IntType(8))
return ir.IntType(32)
elif isinstance(node, ast.UnaryOp):
op_inner: ir.Type = self._infer_expr_llvm_type_full(node.operand)
if isinstance(node.op, ast.Deref):
# *p → pointee 类型
if isinstance(op_inner, ir.PointerType):
return op_inner.pointee
return op_inner
if isinstance(node.op, ast.AddrOf):
# &x → T*(取地址即指针)
return ir.PointerType(op_inner)
return op_inner
elif isinstance(node, ast.Subscript):
val_type: ir.Type = self._infer_expr_llvm_type_full(node.value)
if isinstance(val_type, ir.PointerType):
if isinstance(val_type.pointee, ir.IntType) and val_type.pointee.width == 8:
return ir.IntType(8)
if isinstance(val_type.pointee, ir.ArrayType):
return ir.PointerType(val_type.pointee.element)
return val_type.pointee
if isinstance(val_type, ir.ArrayType):
return val_type.element
if isinstance(val_type, ir.IntType):
return ir.IntType(8)
return ir.IntType(32)
elif isinstance(node, ast.Call):
if isinstance(node.func, ast.Name):
func_name: str = node.func.id
if Gen._has_function(func_name):
fn: Any = Gen._get_function(func_name)
return fn.function_type.return_type
if func_name == 'len':
return ir.IntType(32)
if func_name == 'sizeof':
return ir.IntType(32)
if func_name == 'ord':
return ir.IntType(32)
if func_name == 'chr':
return ir.IntType(8)
if func_name == 'int':
return ir.IntType(32)
if func_name == 'float' or func_name == 'double':
return ir.DoubleType()
if func_name == 'Deref':
return ir.IntType(64)
if func_name == 'CChar':
return ir.PointerType(ir.IntType(8))
return ir.IntType(32)
elif isinstance(node, ast.Compare):
return ir.IntType(1)
elif isinstance(node, ast.BoolOp):
return ir.IntType(1)
elif isinstance(node, ast.IfExp):
return self._infer_expr_llvm_type_full(node.body)
elif isinstance(node, ast.Attribute):
return ir.PointerType(ir.IntType(8))
return ir.IntType(32)
def _collect_names(self, node: ast.AST, bound: set[str], free: set[str] | None = None) -> None:
"""收集 AST 节点中的绑定变量和自由变量
Args:
node: AST 节点
bound: 集合,收集绑定变量(ast.Store 上下文)
free: 集合,收集自由变量(ast.Load 上下文),可为 None
"""
if free is None:
free = set()
if isinstance(node, ast.Name):
if isinstance(node.ctx, ast.Store):
bound.add(node.id)
elif isinstance(node.ctx, ast.Load):
free.add(node.id)
elif isinstance(node, (ast.Lambda, ast.FunctionDef, ast.AsyncFunctionDef)):
# 这些节点有自己的作用域,不递归进入
# 但需要收集参数名作为 bound
if hasattr(node, 'args') and node.args:
for arg in node.args.args:
bound.add(arg.arg)
elif getattr(node, '_fields', None):
for field in node._fields:
value: Any = getattr(node, field, None)
if isinstance(value, list):
for item in value:
if isinstance(item, (ast.stmt, ast.expr)):
self._collect_names(item, bound, free)
elif isinstance(value, (ast.stmt, ast.expr)):
self._collect_names(value, bound, free)