Files
ViperC/App/lib/core/Gen/AssignGenMixin.vp
T
TermiNexus 6677da99f7 refactor(gen): P6 方法化 - StmtGen/AssignGen/VarGen/ImportsGen/TranslatorGen Mixin
5 个新 Mixin(92 方法)承接 HandlesBody/If/While/For/Return/Nonlocal/Match/Enum/AnnAssign/AugAssign/Var/Imports/Translator/Main 的无状态函数与 _g_ 全局;15 个 Handles 模块改为一行委托(调用方零改动);Generator 组合扩展至 12 Mixin,__init__ 初始化 8 个新字段;BuildPipeline/main 注入 14 个模块 set_global_gen;修复 ImportsGenMixin 与 TypeGenMixin 的 CurrentFile 重复字段冲突(改 HandlesType 委托,延迟 import 规避循环依赖)。
2026-08-10 18:42:07 +08:00

519 lines
24 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import t, c
from stdint import *
import ast
import llvmlite
import memhub
import string
import stdio
import stdlib
import viperlib
import w32.fileio as fileio
import lib.core.VLogger as VLogger
import lib.core.Handles.HandlesTranslator as HT
import lib.core.Handles.HandlesType as HandlesType
import lib.core.Handles.HandlesExpr as HandlesExpr
# ============================================================
# AssignGenMixin - 赋值翻译 Mixin(P6 方法化)
#
# 从 HandlesAssign/HandlesAnnAssign/HandlesAugAssign 迁移:
# 模块级无状态函数(trans/pool 首参)→ 类方法;全局状态
# (HandlesAnnAssign._g_recover_found)→ 本类字段 RecoverFound。
#
# 迁移原则(与 P1-P5 一致,行为零变化):
# 1. 方法保留原函数签名(含 trans/pool 首参),仅函数体内的
# 本模块函数调用改为 self.xxx(...)
# 2. 外部模块调用(HandlesType.xxx/HandlesExpr.xxx 等)保留模块前缀
# 3. 原 Handles 模块函数保留为"委托":本地模块级单例 _g_gen
# (BuildPipeline/main 注入)cast 成 Generator 类型
#
# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。
# ============================================================
@t.NoVTable
class AssignGenMixin:
"""赋值翻译 Mixin(P6 方法化)"""
# --- 原 HandlesAnnAssign._g_recover_found 模块级全局(迁移为实例字段) ---
RecoverFound: int
# ============================================================
# is_cdefine_annotation - 检测注解是否为 t.CDefine(模块级函数)
#
# 支持两种形式:
# 1. Attribute(Name('t'), 'CDefine')
# 2. BinOp(... | Attribute(Name('t'), 'CDefine'))(联合注解)
# ============================================================
def is_cdefine_annotation(self, annot: ast.AST | t.CPtr) -> int:
"""检测注解是否为 t.CDefine,返回 1 表示是,0 表示否"""
if annot is None:
return 0
k: int = annot.kind()
if k == ast.ASTKind.Attribute:
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(annot)
if at.attr is not None and string.strcmp(at.attr, "CDefine") == 0:
return 1
return 0
if k == ast.ASTKind.BinOp:
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(annot)
if self.is_cdefine_annotation(bop.left) != 0:
return 1
if self.is_cdefine_annotation(bop.right) != 0:
return 1
return 0
# ============================================================
# extract_cdefine_int_value - 从 AnnAssign.value 提取整数常量(模块级函数)
#
# 支持的表达式形式:
# 1. Constant(INT) — 如 0x0002, 42
# 2. BinOp(BitOr/BitAnd) — 如 FOREGROUND_RED | FOREGROUND_GREEN
# 3. Name — 引用已注册的 CDefine 常量
# 4. Call — 如 t.CUnsignedLong(-11) → 取第一个参数
# 5. UnaryOp(USub/UAdd/Invert) — 如 -11
# ============================================================
def extract_cdefine_int_value(self, val_node: ast.AST | t.CPtr) -> int:
"""从值节点提取整数常量(支持 Constant/BinOp/Name/Call/UnaryOp)"""
if val_node is None:
return 0
k: int = val_node.kind()
# Case 1: Constant(INT) — 如 0x0002
if k == ast.ASTKind.Constant:
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(val_node)
if cn.const_kind != ast.CONST_INT:
return 0
return cn.int_val
# Case 2: BinOp — 如 FOREGROUND_RED | FOREGROUND_GREEN
if k == ast.ASTKind.BinOp:
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(val_node)
left_val: int = self.extract_cdefine_int_value(bop.left)
right_val: int = self.extract_cdefine_int_value(bop.right)
if bop.op == ast.OpKind.BitOr:
return left_val | right_val
if bop.op == ast.OpKind.BitAnd:
return left_val & right_val
if bop.op == ast.OpKind.Add:
return left_val + right_val
if bop.op == ast.OpKind.Sub:
return left_val - right_val
return 0
# Case 3: Name — 引用已注册的 CDefine 常量
if k == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(val_node)
if nm.id is not None:
looked_up: int = HandlesType.lookup_cdefine_constant(nm.id)
if HandlesType.is_cdefine_found() != 0:
return looked_up
return 0
# Case 4: Call — 如 t.CUnsignedLong(-11)
if k == ast.ASTKind.Call:
cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(val_node)
# 必须先把属性赋给显式类型为 list[...] | t.CPtr 的局部变量再调用 __len__(),
# 否则编译器无法识别属性返回的 list 类型,GEP base 会变成 i32 0 导致 llc 报错
cl_args_list: list[ast.AST | t.CPtr] | t.CPtr = cl.args
if cl_args_list is not None and cl_args_list.__len__() > 0:
first_arg: ast.AST | t.CPtr = cl_args_list.get(0)
arg_val: int = self.extract_cdefine_int_value(first_arg)
return arg_val
return 0
# Case 5: UnaryOp — 如 -11
if k == ast.ASTKind.UnaryOp:
uop: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(val_node)
operand_val: int = self.extract_cdefine_int_value(uop.operand)
if uop.op == ast.OpKind.USub:
return -operand_val
if uop.op == ast.OpKind.UAdd:
return operand_val
if uop.op == ast.OpKind.Invert:
return ~operand_val
return 0
return 0
# ============================================================
# _register_cdefine_from_value - 注册 CDefine 常量(浮点/整数自动识别)
#
# 浮点字面量(如 vipermath 的 U_M_PI: t.CDefine = 3.14159...)走
# register_cdefine_double,否则 translate_value 查表得 0 生成
# ret i32 0(llc 报错 "value doesn't match function result type")。
# ============================================================
def _register_cdefine_from_value(self, pool: memhub.MemBuddy | t.CPtr,
name: str, val_node: ast.AST | t.CPtr) -> None:
"""注册 CDefine 常量(浮点字面量 → register_cdefine_double,否则整数)"""
if pool is None or name is None:
return
if val_node is not None and val_node.kind() == ast.ASTKind.Constant:
cn_fp: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(val_node)
if cn_fp.const_kind == ast.CONST_FLOAT:
# 源文件重读恢复(最可靠:AST 节点 float_val 可能被 pool 操作覆写,
# 源文件文本不受影响;用输出参数绕开跨模块 double 返回值传递 bug)
use_val: double = cn_fp.float_val
rec_d: t.CDouble = 0.0
if self._recover_cdefine_float(name, t.CPtr(c.Addr(rec_d))) != 0:
use_val = rec_d
# CDEF-DBG: 打印 float_val 读取(定位浮点 CDefine 值错误)
fb_cd: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_cd is not None:
# 位模式拆解:把 float_val / rec_d 的 8 字节拷贝到 u64,再拆高低 32 位
# 用于确认"哪一半被覆写 + 被谁覆写"(若与 int_val/const_kind 位模式重叠即锁布局 bug)
fv_bits: t.CUInt64T = 0
string.memcpy(t.CVoid(t.CUInt64T(c.Addr(fv_bits)), t.CPtr),
t.CVoid(t.CUInt64T(c.Addr(cn_fp.float_val)), t.CPtr), 8)
rec_bits: t.CUInt64T = 0
string.memcpy(t.CVoid(t.CUInt64T(c.Addr(rec_bits)), t.CPtr),
t.CVoid(t.CUInt64T(c.Addr(rec_d)), t.CPtr), 8)
stdio.snprintf(fb_cd, 1024,
"REG-SRC: %s kind=%d const_kind=%d ptr=%p\n"
" fv=%.17g %a hi=%08llx lo=%08llx\n"
" int_val=%lld bits=%016llx const_kind_hex=%x str_val=%p\n"
" rec=%.17g %a hi=%08llx lo=%08llx use=%.17g",
name, val_node.kind(), cn_fp.const_kind, t.CSizeT(cn_fp),
cn_fp.float_val, cn_fp.float_val,
t.CUInt64T(fv_bits >> 32), t.CUInt64T(fv_bits & 0xFFFFFFFF),
cn_fp.int_val, t.CUInt64T(cn_fp.int_val), cn_fp.const_kind,
t.CSizeT(cn_fp.str_val),
rec_d, rec_d,
t.CUInt64T(rec_bits >> 32), t.CUInt64T(rec_bits & 0xFFFFFFFF),
use_val)
VLogger.info(fb_cd, "CDEF-DBG")
HandlesType.register_cdefine_double(pool, name, use_val)
return
val_fp: int = self.extract_cdefine_int_value(val_node)
HandlesType.register_cdefine_constant(pool, name, val_fp)
# ============================================================
# 源文件重读恢复 CDefine 浮点值
#
# 背景:AST 节点的 float_val/str_val 字段可能被 pool 分配操作覆写
# (MemBuddy 内存冲突),导致注册的浮点 CDefine 值错误(llc ret i32 0)。
# 本函数直接读源文件找 "NAME: t.CDefine = value" 行,atof 解析 value——
# 源文件文本不受 pool 影响,是最可靠的恢复路径。
#
# 原模块级 _g_recover_found 全局已迁移为实例字段 self.RecoverFound。
# ============================================================
def _recover_found(self) -> int:
"""检查最近一次 _recover_cdefine_float 是否成功"""
return self.RecoverFound
def _recover_cdefine_float(self, name: str, out: t.CDouble | t.CPtr) -> int:
"""从当前模块源文件恢复浮点 CDefine 值,写入 out[0],成功返回 1
用输出参数传递 double,避免 TPV 跨模块 double 返回值传递 bug。
"""
self.RecoverFound = 0
fp: str = HandlesType.get_current_file()
if fp is None or name is None or out is None:
return 0
f: fileio.File | t.CPtr = fileio.File(fp, fileio.MODE.R)
if f.closed:
return 0
BUF_SZ: t.CSizeT = 1048576
buf: bytes = stdlib.malloc(BUF_SZ)
if buf is None:
f.close()
return 0
nrd: LONG = f.read_all(buf, BUF_SZ)
f.close()
if nrd <= 0:
stdlib.free(buf)
return 0
if nrd < BUF_SZ:
buf[nrd] = 0
else:
buf[BUF_SZ - 1] = 0
name_len: t.CSizeT = string.strlen(name)
total_len: t.CSizeT = string.strlen(buf)
pos: t.CSizeT = 0
while pos < total_len:
line_start: t.CSizeT = pos
while pos < total_len and buf[pos] != '\n':
pos += 1
line_len: t.CSizeT = pos - line_start
if pos < total_len:
pos += 1
# 匹配 "name:"
if line_len < name_len + 1:
continue
match_ok: int = 1
ki: t.CSizeT
for ki in range(name_len):
if buf[line_start + ki] != name[ki]:
match_ok = 0
break
if match_ok == 0:
continue
if buf[line_start + name_len] != ':':
continue
# 行内包含 "t.CDefine"
has_cd: int = 0
ci: t.CSizeT = line_start + name_len + 1
while ci + 8 <= line_start + line_len:
if (buf[ci] == 't' and buf[ci + 1] == '.' and buf[ci + 2] == 'C' and
buf[ci + 3] == 'D' and buf[ci + 4] == 'e' and buf[ci + 5] == 'f' and
buf[ci + 6] == 'i' and buf[ci + 7] == 'n' and buf[ci + 8] == 'e'):
has_cd = 1
break
ci += 1
if has_cd == 0:
continue
# 找 '='
eq: t.CSizeT = line_start
while eq < line_start + line_len and buf[eq] != '=':
eq += 1
if eq >= line_start + line_len:
continue
eq += 1
while eq < line_start + line_len and buf[eq] == ' ':
eq += 1
val_start: t.CSizeT = eq
while eq < line_start + line_len and buf[eq] != ' ' and buf[eq] != '\t' \
and buf[eq] != '#' and buf[eq] != '\r' and buf[eq] != '\n':
eq += 1
if eq == val_start:
continue
val_txt: str = stdlib.malloc(eq - val_start + 1)
if val_txt is None:
stdlib.free(buf)
return 0
vi: t.CSizeT
for vi in range(eq - val_start):
val_txt[vi] = buf[val_start + vi]
val_txt[eq - val_start] = 0
stdlib.free(buf)
# 用 atof_out(输出参数)绕开跨模块 double 返回值传递 bug
if string.atof_out(val_txt, out) != 0:
self.RecoverFound = 1
return 1
return 0
stdlib.free(buf)
return 0
# ============================================================
# _annotation_contains_name - 递归检查注解中是否包含指定名称
#
# 支持 BinOp(BitOr) 递归,同时检查 Attribute.attr 和 Name.id。
# ============================================================
def _annotation_contains_name(self, annot: ast.AST | t.CPtr, name: str) -> int:
"""递归检查注解中是否包含指定名称,返回 1=包含 / 0=不包含"""
if annot is None or name is None:
return 0
k: int = annot.kind()
if k == ast.ASTKind.Attribute:
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(annot)
if at.attr is not None and string.strcmp(at.attr, name) == 0:
return 1
return 0
if k == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(annot)
if nm.id is not None and string.strcmp(nm.id, name) == 0:
return 1
return 0
if k == ast.ASTKind.BinOp:
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(annot)
if self._annotation_contains_name(bop.left, name) != 0:
return 1
if self._annotation_contains_name(bop.right, name) != 0:
return 1
return 0
# ============================================================
# _is_ptr_element_annotation - 检查注解是否为 bytes|t.CPtr 或 str|t.CPtr
#
# 返回 1=是(下标按 8 字节步长, i8** 语义), 0=否(下标按 1 字节步长, i8* 语义)
#
# 规则:
# bytes|t.CPtr / str|t.CPtr → i8**(8 字节步长)→ 返回 1
# t.CChar|t.CPtr / t.CInt8T|t.CPtr → i8*(1 字节步长)→ 返回 0
# 纯 bytes / str → i8*(1 字节步长)→ 返回 0
#
# 注: 注解中的 "|" 是"和"的意思(组合类型),非右值中的位或运算
# ============================================================
def _is_ptr_element_annotation(self, annot: ast.AST | t.CPtr) -> int:
"""检查注解是否为 bytes|t.CPtr 或 str|t.CPtr 形式"""
if annot is None:
return 0
k: int = annot.kind()
if k != ast.ASTKind.BinOp:
return 0
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(annot)
if bop.op != ast.OpKind.BitOr:
return 0
if self._annotation_contains_name(annot, "str") != 0:
return 1
if self._annotation_contains_name(annot, "bytes") != 0:
return 1
return 0
# ============================================================
# _init_global_array_from_list — 从列表字面量初始化全局数组
#
# 为每个元素生成 GEP + store 指令,将值存入全局数组的对应位置。
# 适用于模块级 t.CArray[elem_ty, count] = [v0, v1, ...] 的初始化。
#
# Args:
# builder: IRBuilder
# pool: 编译器内存池
# mod: LLVMModule
# array_alloca: 全局数组变量的 Value 引用(类型为 [N x elem_ty]*)
# list_node: ast.List 节点
# trans: Translator 对象
#
# Returns:
# 0 成功,1 失败
# ============================================================
def _init_global_array_from_list(self, builder: llvmlite.IRBuilder | t.CPtr,
pool: memhub.MemBuddy | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
array_alloca: llvmlite.Value | t.CPtr,
list_node: ast.AST | t.CPtr,
trans: HT.Translator | t.CPtr) -> int:
"""从列表字面量初始化全局数组,为每个元素生成 GEP + store"""
if builder is None or array_alloca is None or list_node is None:
return 1
# 获取数组类型(Pointee of [N x elem_ty]*)
arr_ty: llvmlite.LLVMType | t.CPtr = None
if array_alloca.Ty is not None:
arr_ty = array_alloca.Ty.Pointee
if arr_ty is None:
return 1
# 匹配数组类型获取元素类型
elem_ty: llvmlite.LLVMType | t.CPtr = None
match arr_ty:
case llvmlite.LLVMType.Array(et, _):
elem_ty = et
if elem_ty is None:
return 1
# 获取列表元素
lst: ast.List | t.CPtr = (ast.List | t.CPtr)(list_node)
if lst is None or lst.elts is None:
return 1
elts: list[ast.AST | t.CPtr] | t.CPtr = lst.elts
elts_count: t.CSizeT = elts.__len__()
# 为每个元素生成 GEP + store
i: t.CSizeT = 0
while i < elts_count:
elem_node: ast.AST | t.CPtr = elts.get(i)
elem_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, elem_node, None, 0, trans)
if elem_val is not None:
idx_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, i)
elem_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_array(
builder, arr_ty, elem_ty, array_alloca, idx_val)
if elem_ptr is not None:
# 类型转换(如 i32 → i8 截断)
store_val: llvmlite.Value | t.CPtr = elem_val
if elem_ptr.Ty is not None and elem_ptr.Ty.Pointee is not None:
store_val = HandlesExpr.coerce_to_type(
builder, elem_val, elem_ptr.Ty.Pointee, elem_node)
llvmlite.build_store(builder, store_val, elem_ptr)
i += 1
return 0
# ============================================================
# _apply_aug_op - 应用增强赋值的二元运算
#
# 支持浮点运算、指针算术: ptr += int / ptr -= int
# 整数运算自动类型提升
# ============================================================
def _apply_aug_op(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
op: int,
lhs: llvmlite.Value | t.CPtr,
rhs: llvmlite.Value | t.CPtr,
node: ast.AST | t.CPtr = None,
trans: HT.Translator | t.CPtr = None,
lhs_node: ast.AST | t.CPtr = None) -> llvmlite.Value | t.CPtr:
"""应用增强赋值的二元运算(浮点 + 指针算术 + 整数运算)"""
lhs_bits: int = HandlesExpr.get_llvm_type_bits(lhs.Ty)
rhs_bits: int = HandlesExpr.get_llvm_type_bits(rhs.Ty)
lhs_fbits: int = HandlesExpr.get_llvm_float_bits(lhs.Ty)
rhs_fbits: int = HandlesExpr.get_llvm_float_bits(rhs.Ty)
# 浮点运算: 任一操作数为浮点时,使用浮点指令(必须在指针算术之前检查,
# 因为 float 的 int bits 为 0,会被误认为指针)
if lhs_fbits != 0 or rhs_fbits != 0:
# 确定目标浮点类型(使用较大的位宽)
target_fbits: int = lhs_fbits
if rhs_fbits > target_fbits:
target_fbits = rhs_fbits
target_float_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool)
if target_fbits == 32:
target_float_ty = llvmlite.Float(pool)
# 将两个操作数转换为目标浮点类型(int→float via si2fp, float→float via fpext/fptrunc)
lhs = HandlesExpr.coerce_to_type(builder, lhs, target_float_ty, node)
rhs = HandlesExpr.coerce_to_type(builder, rhs, target_float_ty, node)
if op == ast.OpKind.Add:
return llvmlite.build_fadd(builder, lhs, rhs)
if op == ast.OpKind.Sub:
return llvmlite.build_fsub(builder, lhs, rhs)
if op == ast.OpKind.Mult:
return llvmlite.build_fmul(builder, lhs, rhs)
if op == ast.OpKind.Div:
return llvmlite.build_fdiv(builder, lhs, rhs)
if op == ast.OpKind.Mod:
return llvmlite.build_frem(builder, lhs, rhs)
return None
# 指针算术: ptr += int / ptr -= int → getelementptr(按元素大小缩放)
# 对齐 TPC HandlesAugAssign.py L140-149 / L170-180
if lhs_bits == 0 and rhs_bits != 0:
if op == ast.OpKind.Add or op == ast.OpKind.Sub:
return HandlesExpr.translate_ptr_arith(pool, builder, lhs, rhs, op)
return None
# 整数运算:类型提升
if lhs_bits > rhs_bits and rhs_bits > 0:
rhs = HandlesExpr.coerce_to_type(builder, rhs, lhs.Ty, node)
elif rhs_bits > lhs_bits and lhs_bits > 0:
lhs = HandlesExpr.coerce_to_type(builder, lhs, rhs.Ty, node)
if op == ast.OpKind.Add:
return llvmlite.build_add(builder, lhs, rhs)
elif op == ast.OpKind.Sub:
return llvmlite.build_sub(builder, lhs, rhs)
elif op == ast.OpKind.Mult:
return llvmlite.build_mul(builder, lhs, rhs)
elif op == ast.OpKind.Div:
return llvmlite.build_sdiv(builder, lhs, rhs)
elif op == ast.OpKind.FloorDiv:
return llvmlite.build_sdiv(builder, lhs, rhs)
elif op == ast.OpKind.Mod:
return llvmlite.build_srem(builder, lhs, rhs)
elif op == ast.OpKind.BitAnd:
return llvmlite.build_and(builder, lhs, rhs)
elif op == ast.OpKind.BitOr:
return llvmlite.build_or(builder, lhs, rhs)
elif op == ast.OpKind.BitXor:
return llvmlite.build_xor(builder, lhs, rhs)
elif op == ast.OpKind.LShift:
return llvmlite.build_shl(builder, lhs, rhs)
elif op == ast.OpKind.RShift:
# 无符号 >> → lshr(逻辑右移),有符号 >> → ashr(算术右移)
# 对齐 TPC ExprGen.emit_binary_op:i8/i16 默认无符号;其余查操作数无符号性
if lhs_bits == 8 or lhs_bits == 16:
return llvmlite.build_lshr(builder, lhs, rhs)
if lhs_node is not None and trans is not None:
if HandlesExpr._node_type_unsigned(pool, lhs_node, trans) != 0:
return llvmlite.build_lshr(builder, lhs, rhs)
return llvmlite.build_ashr(builder, lhs, rhs)
return None