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 规避循环依赖)。
This commit is contained in:
TermiNexus committed 2026-08-10 18:42:07 +08:00
1 parent 451be82b32
commit 6677da99f7
22 files changed
+4123 -2234

No files matched your search

+27
View File
@@ -20,6 +20,18 @@ import lib.core.Handles.HandlesExprCall as HandlesExprCall
import lib.core.Handles.HandlesFunctions as HandlesFunctions
import lib.core.Handles.HandlesClassDef as HandlesClassDef
import lib.core.Handles.HandlesImports as HandlesImports
import lib.core.Handles.HandlesBody as HandlesBody
import lib.core.Handles.HandlesIf as HandlesIf
import lib.core.Handles.HandlesWhile as HandlesWhile
import lib.core.Handles.HandlesFor as HandlesFor
import lib.core.Handles.HandlesReturn as HandlesReturn
import lib.core.Handles.HandlesNonlocal as HandlesNonlocal
import lib.core.Handles.HandlesMatch as HandlesMatch
import lib.core.Handles.HandlesEnum as HandlesEnum
import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign
import lib.core.Handles.HandlesAugAssign as HandlesAugAssign
import lib.core.Handles.HandlesVar as HandlesVar
import lib.core.Handles.HandlesMain as HandlesMain
import lib.core.StubMerger as StubMerger
import lib.StubGen.Converter as StubConverter
import lib.Projectrans.Config as Config
@@ -156,6 +168,21 @@ def TranslateFileGetTrans(mb: memhub.MemBuddy | t.CPtr, file_path: str,
HandlesExprCall.set_global_gen(gen)
HandlesFunctions.set_global_gen(gen)
HandlesClassDef.set_global_gen(gen)
# P6: 注入语句/赋值/变量/导入/翻译驱动模块的单例
HandlesImports.set_global_gen(gen)
HandlesBody.set_global_gen(gen)
HandlesIf.set_global_gen(gen)
HandlesWhile.set_global_gen(gen)
HandlesFor.set_global_gen(gen)
HandlesReturn.set_global_gen(gen)
HandlesNonlocal.set_global_gen(gen)
HandlesMatch.set_global_gen(gen)
HandlesEnum.set_global_gen(gen)
HandlesAnnAssign.set_global_gen(gen)
HandlesAugAssign.set_global_gen(gen)
HandlesVar.set_global_gen(gen)
HandlesTranslator.set_global_gen(gen)
HandlesMain.set_global_gen(gen)
# 设置当前文件名(供报错使用)
HandlesType.set_current_file(file_path)
# 同步到 HandlesImports(import 时 SHA1 检查报错需要当前文件名,循环依赖无法直接读 HandlesType)
+518
View File
@@ -0,0 +1,518 @@
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
+19 -1
View File
@@ -9,6 +9,11 @@ import lib.core.Gen.ExprGenMixin as ExprGenMixin
import lib.core.Gen.CallGenMixin as CallGenMixin
import lib.core.Gen.FuncGenMixin as FuncGenMixin
import lib.core.Gen.ClassGenMixin as ClassGenMixin
import lib.core.Gen.ImportsGenMixin as ImportsGenMixin
import lib.core.Gen.StmtGenMixin as StmtGenMixin
import lib.core.Gen.AssignGenMixin as AssignGenMixin
import lib.core.Gen.VarGenMixin as VarGenMixin
import lib.core.Gen.TranslatorGenMixin as TranslatorGenMixin
import lib.core.Handles.HandlesVar as HandlesVar
import lib.core.Handles.HandlesExprCall as HandlesExprCall
@@ -29,7 +34,9 @@ import lib.core.Handles.HandlesExprCall as HandlesExprCall
class Generator(BaseGenMixin.BaseGenMixin, TypeGenMixin.TypeGenMixin,
StructGenMixin.StructGenMixin, ExprGenMixin.ExprGenMixin,
CallGenMixin.CallGenMixin, FuncGenMixin.FuncGenMixin,
ClassGenMixin.ClassGenMixin):
ClassGenMixin.ClassGenMixin, ImportsGenMixin.ImportsGenMixin,
StmtGenMixin.StmtGenMixin, AssignGenMixin.AssignGenMixin,
VarGenMixin.VarGenMixin, TranslatorGenMixin.TranslatorGenMixin):
"""生成器:多继承 Mixin 组合(对象化迁移宿主)"""
def __init__(self, pool: memhub.MemBuddy | t.CPtr):
@@ -112,6 +119,17 @@ class Generator(BaseGenMixin.BaseGenMixin, TypeGenMixin.TypeGenMixin,
self.VtMethodNames = None
self.VtParentSha1s = None
self.VtMethodCount = 0
# ---- ImportsGenMixin 字段 ----
self.ReexportSha1s = None
self.ReexportFuncs = None
self.ReexportSrcs = None
self.ReexportCount = 0
# ---- StmtGenMixin 字段 ----
self.CifEvalOk = 0
self.EnumTable = None
self.EnumCount = 0
# ---- AssignGenMixin 字段 ----
self.RecoverFound = 0
# ============================================================
+622
View File
@@ -0,0 +1,622 @@
import t, c
from stdint import *
import ast
import memhub
import string
import stdlib
import viperlib
import stdio
import sys
import w32.fileio as fileio
import lib.core.StubMerger as StubMerger
# ============================================================
# ImportsGenMixin - 导入处理 Mixin(对象化 P6-D,wiki/14-oo-refactor.md)
#
# 从 HandlesImports.vp 迁移:
# 全局状态(_g_reexport_sha1s/_g_reexport_funcs/_g_reexport_srcs/
# _g_reexport_count/_g_current_file)→ 本类字段
# 模块级函数(add_imported_module/is_module_imported/...)→ 本类方法
#
# 迁移原则(与 P1-P5 Mixin 一致,行为零变化):
# 1. 方法保留原函数签名(含 pool 首参),仅函数体内的全局变量改为 self.字段
# 2. 本模块内部函数调用改为 self.方法;跨模块调用(StubMerger 等)保留模块前缀
# 3. HandlesImports.vp 原函数保留为"委托":本地模块级单例 _g_gen
# (BuildPipeline/main 注入)cast 成 Generator 类型后调本类方法
#
# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整,无 vtable 开销)。
# ============================================================
# ============================================================
# 常量(与 HandlesImports 保持一致)
# ============================================================
MAX_REEXPORT: t.CDefine = 512
# ============================================================
# ImportsGenMixin - 导入处理
# ============================================================
@t.NoVTable
class ImportsGenMixin:
"""导入处理 Mixin(P6 方法化)"""
# --- 全局 re-export 映射表(原 _g_reexport_sha1s/_g_reexport_funcs/
# _g_reexport_srcs/_g_reexport_count) ---
ReexportSha1s: bytes
ReexportFuncs: bytes
ReexportSrcs: bytes
ReexportCount: int
# 注意:不声明 CurrentFile 字段——TypeGenMixin 已声明(Generator 展平块
# 只有一份,跨父类不去重规则下重复声明会导致字段错位)。本 Mixin 的
# set_current_file 与 CurrentFile 读取统一经 HandlesType 委托(延迟 import
# 规避 HandlesType↔HandlesImports 循环依赖)。
# ============================================================
# 添加已导入模块名
# ============================================================
def add_imported_module(self, pool: memhub.MemBuddy | t.CPtr,
imported_modules: str,
name: str) -> str:
"""记录已导入的模块名,返回新的 imported_modules 字符串指针"""
if name is None:
return imported_modules
if imported_modules is None:
nlen: t.CSizeT = string.strlen(name)
buf: t.CChar | t.CPtr = pool.alloc(nlen + 1)
if buf is not None:
string.strcpy(buf, name)
return buf
return None
else:
old_len: t.CSizeT = string.strlen(imported_modules)
name_len: t.CSizeT = string.strlen(name)
new_len: t.CSizeT = old_len + 1 + name_len
buf2: t.CChar | t.CPtr = pool.alloc(new_len + 1)
if buf2 is not None:
string.strcpy(buf2, imported_modules)
buf2[old_len] = ' '
string.strcpy(buf2 + old_len + 1, name)
return buf2
return imported_modules
# ============================================================
# 检查模块是否已导入
# ============================================================
def is_module_imported(self, imported_modules: str, name: str) -> int:
"""检查模块是否已导入(词边界精确匹配,避免子串误匹配)"""
if name is None or imported_modules is None:
return 0
name_len: t.CSizeT = string.strlen(name)
cur: t.CChar | t.CPtr = imported_modules
total_len: t.CSizeT = string.strlen(imported_modules)
ci: t.CSizeT = 0
while ci < total_len:
while ci < total_len and cur[ci] == ' ':
ci += 1
if ci >= total_len:
break
word_start: t.CSizeT = ci
while ci < total_len and cur[ci] != ' ':
ci += 1
word_len: t.CSizeT = ci - word_start
if word_len == name_len:
match: int = 1
for ei in range(name_len):
if cur[word_start + ei] != name[ei]:
match = 0
break
if match == 1:
return 1
return 0
# ============================================================
# 添加 from-import 名称映射
# ============================================================
def add_from_import(self, pool: memhub.MemBuddy | t.CPtr,
from_imports: str,
local_name: str,
module_name: str,
original_name: str = None) -> str:
"""添加 from-import 映射,返回新的 from_imports 字符串
格式:
无别名: "local_name:module_name"
有别名: "local_name:module_name:original_name"
(original_name 为源模块中的真实函数名,用于跨模块 SHA1 修饰)
"""
if local_name is None or module_name is None:
return from_imports
entry: t.CChar | t.CPtr = pool.alloc(256)
if entry is None:
return from_imports
if original_name is not None and string.strcmp(original_name, local_name) != 0:
viperlib.snprintf(entry, 256, "%s:%s:%s", local_name, module_name, original_name)
else:
viperlib.snprintf(entry, 256, "%s:%s", local_name, module_name)
if from_imports is None:
return entry
else:
old_len: t.CSizeT = string.strlen(from_imports)
entry_len: t.CSizeT = string.strlen(entry)
new_len: t.CSizeT = old_len + 1 + entry_len
buf: t.CChar | t.CPtr = pool.alloc(new_len + 1)
if buf is not None:
string.strcpy(buf, from_imports)
buf[old_len] = ' '
string.strcpy(buf + old_len + 1, entry)
return buf
return from_imports
# ============================================================
# 查找 from-import 名称 → 返回原始函数名(别名场景)
#
# 对于 from X import Y as Z,返回 Y(源模块中的真实函数名)。
# 无别名时返回 None(local_name 即为原始名)。
# ============================================================
def lookup_from_import_original(self, from_imports: str,
local_name: str) -> str:
"""查找 from-import 别名对应的原始函数名,返回 None=无别名或未找到"""
if local_name is None or from_imports is None:
return None
name_len: t.CSizeT = string.strlen(local_name)
cur: t.CChar | t.CPtr = from_imports
ci: t.CSizeT = 0
total_len: t.CSizeT = string.strlen(from_imports)
while ci < total_len:
# 跳过前导空格
while ci < total_len and cur[ci] == ' ':
ci += 1
if ci >= total_len:
break
# 找到第一个 ':' 的位置
colon1: t.CSizeT = ci
while colon1 < total_len and cur[colon1] != ':' and cur[colon1] != ' ':
colon1 += 1
if colon1 >= total_len or cur[colon1] != ':':
break
entry_name_len: t.CSizeT = colon1 - ci
# 跳过 star import
if entry_name_len == 1 and cur[ci] == '*':
ci = colon1
while ci < total_len and cur[ci] != ' ':
ci += 1
continue
# 比较名称
if entry_name_len == name_len:
match: int = 1
ei: t.CSizeT = 0
while ei < name_len:
if cur[ci + ei] != local_name[ei]:
match = 0
break
ei += 1
if match == 1:
# 找到匹配,检查是否有第三个字段(原始名)
pos: t.CSizeT = colon1 + 1
# 跳过模块名
while pos < total_len and cur[pos] != ':' and cur[pos] != ' ' and cur[pos] != '\0':
pos += 1
if pos < total_len and cur[pos] == ':':
# 有第三个字段: original_name
orig_start: t.CSizeT = pos + 1
orig_end: t.CSizeT = orig_start
while orig_end < total_len and cur[orig_end] != ' ' and cur[orig_end] != '\0':
orig_end += 1
orig_len: t.CSizeT = orig_end - orig_start
if orig_len > 0:
orig_buf: str = cur + orig_start
# 返回指向内部的指针(调用方需在使用期内保持 from_imports 有效)
return orig_buf
return None
return None
# 跳到下一个条目
ci = colon1
while ci < total_len and cur[ci] != ' ':
ci += 1
return None
# ============================================================
# 查找 from-import 名称 → 返回模块名或 None
#
# allow_star_fallback: 是否允许 star import 回退(默认 1=允许)。
# 当查询明确模块名(如 "BuildPipeline")时,应传 0 禁用回退,
# 避免被 star import 模块名误导(如 from stdint import * 后
# 查询 "BuildPipeline" 错误回退到 "stdint")。
# ============================================================
def lookup_from_import(self, from_imports: str, name: str,
allow_star_fallback: int = 1) -> str:
"""查找 from-import 名称,返回模块名或 None
支持 star import: 如果 from_imports 中有 "*:module" 条目,
且未找到精确名称匹配,且 allow_star_fallback != 0,则返回 star import 的模块名。
"""
if name is None or from_imports is None:
return None
name_len: t.CSizeT = string.strlen(name)
cur: t.CChar | t.CPtr = from_imports
ci: t.CSizeT = 0
total_len: t.CSizeT = string.strlen(from_imports)
star_mod: str = None
while ci < total_len:
# 跳过前导空格
while ci < total_len and cur[ci] == ' ':
ci += 1
if ci >= total_len:
break
# 找到 ':' 的位置
colon_pos: t.CSizeT = ci
while colon_pos < total_len and cur[colon_pos] != ':' and cur[colon_pos] != ' ':
colon_pos += 1
if colon_pos >= total_len or cur[colon_pos] != ':':
break
entry_name_len: t.CSizeT = colon_pos - ci
# 检测 star import ("*:module")
if entry_name_len == 1 and cur[ci] == '*':
mod_start: t.CSizeT = colon_pos + 1
mod_end: t.CSizeT = mod_start
while mod_end < total_len and cur[mod_end] != ' ' and cur[mod_end] != '\0' and cur[mod_end] != ':':
mod_end += 1
star_mod = cur + mod_start
# 比较名称
elif entry_name_len == name_len:
match: int = 1
ei: t.CSizeT = 0
while ei < name_len:
if cur[ci + ei] != name[ei]:
match = 0
break
ei += 1
if match == 1:
mod_start2: t.CSizeT = colon_pos + 1
mod_end2: t.CSizeT = mod_start2
# 模块名结束于: 空格、null、或第二个':'(别名格式的分隔符)
while mod_end2 < total_len and cur[mod_end2] != ' ' and cur[mod_end2] != '\0' and cur[mod_end2] != ':':
mod_end2 += 1
return cur + mod_start2
# 跳到下一个条目
ci = colon_pos
while ci < total_len and cur[ci] != ' ':
ci += 1
# 未找到精确匹配,仅在允许时回退到 star import
if allow_star_fallback == 0:
return None
return star_mod
# ============================================================
# register_reexport - 注册 re-export 映射
#
# 在 HandleImportFromNames 中调用:当处理 from .X import Y 时,
# 记录当前模块(通过 ModuleSha1)re-export 了函数 Y,源模块为 X。
#
# 幂等:重复注册相同映射不会增加条目。
# 内存用 stdlib.malloc 分配(全局存储器,跨 Phase 持久化)。
# ============================================================
def register_reexport(self, mod_sha1: str, func_name: str, source_module: str) -> int:
"""注册 re-export 映射(幂等),返回 0 成功,-1 失败"""
if mod_sha1 is None or func_name is None or source_module is None:
return -1
# 懒初始化
if self.ReexportSha1s is None:
self.ReexportSha1s = stdlib.malloc(MAX_REEXPORT * 17)
self.ReexportFuncs = stdlib.malloc(MAX_REEXPORT * 64)
self.ReexportSrcs = stdlib.malloc(MAX_REEXPORT * 64)
if self.ReexportSha1s is None or self.ReexportFuncs is None or self.ReexportSrcs is None:
return -1
string.memset(self.ReexportSha1s, 0, MAX_REEXPORT * 17)
string.memset(self.ReexportFuncs, 0, MAX_REEXPORT * 64)
string.memset(self.ReexportSrcs, 0, MAX_REEXPORT * 64)
if self.ReexportCount >= MAX_REEXPORT:
return -1
# 幂等检查:查找是否已存在相同映射
for i in range(self.ReexportCount):
sidx: t.CSizeT = t.CSizeT(i) * 17
fidx: t.CSizeT = t.CSizeT(i) * 64
if string.strcmp(self.ReexportSha1s + sidx, mod_sha1) == 0:
if string.strcmp(self.ReexportFuncs + fidx, func_name) == 0:
# 已存在,更新 source_module(以防变化;64 字节槽,strncpy 钳制)
string.strncpy(self.ReexportSrcs + fidx, source_module, 63)
self.ReexportSrcs[fidx + 63] = '\0'
return 0
# 添加新条目(槽位定长 17/64 字节,strcpy 无界会越界写相邻槽,全部 strncpy 钳制)
idx2: t.CSizeT = t.CSizeT(self.ReexportCount) * 17
fidx2: t.CSizeT = t.CSizeT(self.ReexportCount) * 64
string.strncpy(self.ReexportSha1s + idx2, mod_sha1, 16)
self.ReexportSha1s[idx2 + 16] = '\0'
string.strncpy(self.ReexportFuncs + fidx2, func_name, 63)
self.ReexportFuncs[fidx2 + 63] = '\0'
string.strncpy(self.ReexportSrcs + fidx2, source_module, 63)
self.ReexportSrcs[fidx2 + 63] = '\0'
self.ReexportCount += 1
return 0
# ============================================================
# lookup_reexport - 查找 re-export 映射
#
# 给定模块 SHA1 和函数名,返回源模块名(如 "ast.lexer")或 None。
# 调用方通过 _lookup_module_sha1(source_module) 获取源模块的 SHA1。
# ============================================================
def lookup_reexport(self, mod_sha1: str, func_name: str) -> str:
"""查找 re-export 映射,返回源模块名或 None"""
if mod_sha1 is None or func_name is None:
return None
if self.ReexportSha1s is None or self.ReexportCount <= 0:
return None
for i in range(self.ReexportCount):
sidx: t.CSizeT = t.CSizeT(i) * 17
fidx: t.CSizeT = t.CSizeT(i) * 64
if string.strcmp(self.ReexportSha1s + sidx, mod_sha1) == 0:
if string.strcmp(self.ReexportFuncs + fidx, func_name) == 0:
return self.ReexportSrcs + fidx
return None
# ============================================================
# _resolve_relative_module - 解析相对导入为完整模块名
#
# 对于 from .X import Y(level=1, module="X")在包 pkg 中:
# 解析为 "pkg.X"
# 对于 from . import Y(level=1, module=None)在包 pkg 中:
# 解析为 "pkg"
# 对于 from ..X import Y(level=2, module="X")在包 pkg.sub 中:
# 解析为 "pkg.X"(先从 pkg.sub 上溯一级到 pkg,再追加 .X)
#
# Args:
# pool: 内存池
# current_package: 当前文件所属包名(如 "llvmlite"),None 表示无包
# level: 相对导入级别(0=绝对,1=., 2=..)
# module: ImportFrom 的 module 字段(可能为 None)
#
# Returns:
# 解析后的完整模块名;绝对导入(level<=0)直接返回 module;
# 无法解析时返回 module(回退到原始值)
# ============================================================
def _resolve_relative_module(self, pool: memhub.MemBuddy | t.CPtr,
current_package: str,
level: t.CInt,
module: str) -> str:
"""解析相对导入为完整模块名"""
if level <= 0:
return module
if current_package is None:
return module
# 从 current_package 开始,上溯 (level-1) 级
pkg: str = current_package
up: t.CInt = level - 1
while up > 0:
pkg_len: t.CSizeT = string.strlen(pkg)
last_dot: t.CSizeT = 0
found: int = 0
i: t.CSizeT = 0
while i < pkg_len:
if pkg[i] == '.':
last_dot = i
found = 1
i += 1
if found == 0:
# 无更多父级,包变为空
pkg = None
break
# 截断到最后一个 '.' 处
new_pkg: str = pool.alloc(last_dot + 1)
if new_pkg is None:
return module
string.strncpy(new_pkg, pkg, last_dot)
new_pkg[last_dot] = '\0'
pkg = new_pkg
up -= 1
if module is None:
# from . import Y → 模块就是包本身
return pkg
if pkg is None:
# 包已上溯到空,直接用 module
return module
# 拼接 pkg + "." + module
pkg_len2: t.CSizeT = string.strlen(pkg)
mod_len: t.CSizeT = string.strlen(module)
buf: str = pool.alloc(pkg_len2 + 1 + mod_len + 1)
if buf is None:
return module
string.strcpy(buf, pkg)
buf[pkg_len2] = '.'
string.strcpy(buf + pkg_len2 + 1, module)
return buf
# ============================================================
# compute_package_from_relpath - 从相对路径计算包名
#
# 包名 = 文件所在目录路径,将 / 和 \ 替换为 .
# 对于顶级文件(无目录分隔符),返回 None
#
# 示例:
# "llvmlite/__init__.vp" → "llvmlite"
# "llvmlite/__types.vp" → "llvmlite"
# "ast/parser.vp" → "ast"
# "ast.vp" → None(顶级文件)
# ============================================================
def compute_package_from_relpath(self, pool: memhub.MemBuddy | t.CPtr,
rel_path: str) -> str:
"""从相对路径计算包名(目录部分,分隔符替换为 .)"""
if rel_path is None:
return None
rlen: t.CSizeT = string.strlen(rel_path)
# 找最后一个 / 或 \
last_sep: t.CSizeT = 0
found: int = 0
i: t.CSizeT = 0
while i < rlen:
ch: t.CChar = rel_path[i]
if ch == '/' or ch == '\\':
last_sep = i
found = 1
i += 1
if found == 0:
# 无目录分隔符 → 顶级文件,无包
return None
# 复制目录部分,将 / 和 \ 替换为 .
dir_len: t.CSizeT = last_sep
buf: str = pool.alloc(dir_len + 1)
if buf is None:
return None
j: t.CSizeT = 0
while j < dir_len:
ch2: t.CChar = rel_path[j]
if ch2 == '/' or ch2 == '\\':
buf[j] = '.'
else:
buf[j] = ch2
j += 1
buf[dir_len] = '\0'
return buf
# ============================================================
# set_current_file - 设置当前编译的文件名
#
# 与 TypeGenMixin.set_current_file 行为一致(写 CurrentFile 字段),
# BuildPipeline/Phase1 通过 HandlesImports.set_current_file 委托调用。
# 经 HandlesType 委托(延迟 import 规避循环依赖),字段由 TypeGenMixin 持有。
# ============================================================
def set_current_file(self, file_path: str) -> None:
"""设置当前正在编译的文件名(与 HandlesType.set_current_file 同步调用)"""
import lib.core.Handles.HandlesType as HandlesType
HandlesType.set_current_file(file_path)
# ============================================================
# _report_import_error - 本地实现 Python 风格报错(避免循环依赖)
#
# 无法访问 HandlesType.fatal_error(HandlesType import 了本模块,
# 若本模块再 import HandlesType 会形成循环依赖),这里用简化格式:
# Traceback (most recent call last):
# File "<当前文件>", line <N>
# ImportError: <msg>
# ============================================================
def _report_import_error(self, node: ast.AST | t.CPtr, msg: str) -> None:
"""以 Python 风格报错并退出(本地实现,避免循环依赖)"""
import lib.core.Handles.HandlesType as HandlesType
stdio.printf("Traceback (most recent call last):\n")
lineno: int = 0
if node is not None:
lineno = node.lineno
file_name: str = HandlesType.get_current_file()
if file_name is None:
file_name = "<unknown>"
stdio.printf(' File "%s", line %d\n', file_name, lineno)
# 显示行内内容(读源文件第 lineno 行的实际代码,便于快速定位)
if lineno > 0 and file_name is not None:
f_err: fileio.File | t.CPtr = fileio.File(file_name, fileio.MODE.R)
if not f_err.closed:
line_buf_err: bytes = stdlib.malloc(512)
if line_buf_err is not None:
cur_ln: int = 0
while cur_ln < lineno:
r_err: LONG = f_err.readline(line_buf_err, 511)
if r_err <= 0:
break
cur_ln += 1
if cur_ln == lineno:
ll_err: t.CSizeT = string.strlen(line_buf_err)
while ll_err > 0 and (line_buf_err[ll_err - 1] == '\n' or line_buf_err[ll_err - 1] == '\r'):
ll_err -= 1
line_buf_err[ll_err] = '\0'
stdio.printf(" %s\n", line_buf_err)
break
stdlib.free(line_buf_err)
f_err.close()
stdio.printf("ImportError: %s\n", msg)
sys.exit(1)
# ============================================================
# _is_local_module_file - 当前文件同目录存在 {mod_name}.vp/.py
#
# 多文件项目(如 Test/G4/App 的 caller1.vp import g4node)的兄弟模块
# 不在 includes 扫描存储器中(SHA1 在项目源文件列表),检查应豁免。
# ============================================================
def _is_local_module_file(self, mod_name: str) -> int:
"""当前文件同目录存在 {mod_name}.vp/.py → 项目内兄弟模块"""
import lib.core.Handles.HandlesType as HandlesType
cur: str = HandlesType.get_current_file()
if cur is None or mod_name is None:
return 0
cur_len: t.CSizeT = string.strlen(cur)
if cur_len == 0:
return 0
sep_pos: t.CSizeT = cur_len
while sep_pos > 0:
sep_pos -= 1
ch: t.CChar = cur[sep_pos]
if ch == '/' or ch == '\\':
sep_pos += 1
break
mod_len: t.CSizeT = string.strlen(mod_name)
path_len: t.CSizeT = sep_pos + mod_len + 5
path_buf: bytes = stdlib.malloc(path_len + 1)
if path_buf is None:
return 0
# .vp 文件
string.strncpy(path_buf, cur, sep_pos)
path_buf[sep_pos] = '\0'
string.strcat(path_buf, mod_name)
string.strcat(path_buf, ".vp")
fex: fileio.File | t.CPtr = fileio.File(path_buf, fileio.MODE.R)
if not fex.closed:
fex.close()
stdlib.free(path_buf)
return 1
# .py 文件(Python 模块可能无 .vp)
string.strncpy(path_buf, cur, sep_pos)
path_buf[sep_pos] = '\0'
string.strcat(path_buf, mod_name)
string.strcat(path_buf, ".py")
fex2: fileio.File | t.CPtr = fileio.File(path_buf, fileio.MODE.R)
if not fex2.closed:
fex2.close()
stdlib.free(path_buf)
return 1
stdlib.free(path_buf)
return 0
# ============================================================
# _check_import_sha1 - 导入时校验模块 SHA1 是否已注册(fast-fail)
#
# 背景:若 includes 路径配置错误(如 project.json 指向不存在的
# ./includes),includes 扫描结果为 0,模块不会注册 SHA1。此前
# 错误延迟到实际调用 module.func() 时才报误导性的
# "跨模块调用 'bd.alloc' 找不到模块 SHA1"。
# 现在在 import 语句处立即检测并报错,快速定位配置问题。
#
# t/c 是内部库,不参与 includes 扫描,豁免检查。
# ============================================================
def _check_import_sha1(self, node: ast.AST | t.CPtr, mod_name: str) -> int:
"""导入时校验模块 SHA1 是否已注册,未注册则立即报错退出
Args:
node: Import/ImportFrom AST 节点(提供行号)
mod_name: 导入的模块名(如 "memhub"、"w32.fileio")
Returns:
1=检查通过;模块未注册时直接报错退出(不会返回 0)
"""
if mod_name is None:
return 1
# t/c 是内部库,不参与 includes 扫描,豁免检查
if string.strcmp(mod_name, "t") == 0 or string.strcmp(mod_name, "c") == 0:
return 1
mod_sha1: str = StubMerger.LookupSha1ByModName(mod_name)
if mod_sha1 is None:
# App 兄弟模块豁免:当前文件同目录存在 {mod_name}.vp/.py
# (如 Test/G4/App/caller1.vp import g4node——同项目源文件,
# SHA1 在项目文件列表而非 includes 扫描存储器,不应报错)
if self._is_local_module_file(mod_name) != 0:
return 1
err_buf: t.CChar | t.CPtr = stdlib.malloc(256)
if err_buf is not None:
viperlib.snprintf(err_buf, 256,
"模块 '%s' 未注册 SHA1(includes 扫描未找到该模块,请检查 project.json 的 includes 路径配置)",
mod_name)
self._report_import_error(node, err_buf)
else:
self._report_import_error(node, "导入模块 SHA1 未注册(includes 扫描未找到该模块)")
return 1
+967
View File
@@ -0,0 +1,967 @@
import t, c
from stdint import *
import ast
import llvmlite
import memhub
import string
import viperlib
import lib.core.VLogger as VLogger
import lib.core.Handles.HandlesTranslator as HT
import lib.core.Handles.HandlesType as HandlesType
import lib.core.Handles.HandlesVar as HandlesVar
import lib.core.Handles.HandlesExpr as HandlesExpr
import lib.core.Handles.HandlesExprCall as HandlesExprCall
import lib.core.Handles.HandlesFunctions as HandlesFunctions
import lib.core.Handles.HandlesClassDef as HandlesClassDef
import lib.core.Handles.HandlesImports as HandlesImports
import lib.core.Handles.HandlesIf as HandlesIf
import lib.core.Handles.HandlesWhile as HandlesWhile
import lib.core.Handles.HandlesFor as HandlesFor
import lib.core.Handles.HandlesReturn as HandlesReturn
import lib.core.Handles.HandlesMatch as HandlesMatch
import lib.core.Handles.HandlesEnum as HandlesEnum
import lib.Projectrans.Config as Config
# ============================================================
# StmtGenMixin - 语句/流程翻译 Mixin(P6 对象化重构 A 组)
#
# 迁移自 HandlesBody/HandlesIf/HandlesWhile/HandlesFor/HandlesReturn/
# HandlesNonlocal/HandlesMatch/HandlesEnum 的模块级函数(trans 首参
# 或无状态纯函数 + NewXxxHandle 工厂)→ 类方法;全局状态
# (_g_cif_eval_ok/_enum_table/_enum_count)→ 本类字段。
#
# 迁移原则(与 P1-P5 一致,行为零变化):
# 1. 方法保留原函数签名(含 trans/pool 首参),仅函数体内的
# 本模块函数调用改为 self.xxx(...)
# 2. 外部模块调用(HandlesVar.xxx/HandlesExpr.xxx/HandlesType.xxx
# 等)保留模块前缀(对应模块保留委托层)
# 3. trans.XxxH.Handle(...) 子 Handle 分派保留(Handle 类不动,
# 由 HandlesTranslator._init_state 通过 NewXxxHandle 工厂创建)
# 4. 原 Handles 模块函数保留为"委托":本地模块级单例 _g_gen
# (BuildPipeline/main 注入)cast 成 Generator 类型调本类方法
# 5. HandlesIf._g_cif_eval_ok → self.CifEvalOk;HandlesEnum
# _enum_table/_enum_count → self.EnumTable/self.EnumCount
#
# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。
# ============================================================
# ============================================================
# 常量(与 HandlesEnum 保持一致,本地副本避免跨模块 CDefine 查找 bug)
# ============================================================
ENUM_MAX: t.CDefine = 64
ENUM_MEMBER_MAX: t.CDefine = 128
# ============================================================
# StmtGenMixin - 语句/流程翻译(P6 方法化)
# ============================================================
@t.NoVTable
class StmtGenMixin:
"""语句/流程翻译 Mixin(P6 方法化)
迁移自 HandlesBody/HandlesIf/HandlesWhile/HandlesFor/HandlesReturn/
HandlesNonlocal/HandlesMatch/HandlesEnum 的模块级函数
"""
# --- 编译期 CIf 求值状态(原 HandlesIf._g_cif_eval_ok) ---
CifEvalOk: int
# --- 枚举注册表(原 HandlesEnum._enum_table/_enum_count) ---
EnumTable: HandlesEnum.EnumEntry | t.CPtr
EnumCount: int
# ============================================================
# 簇 A:语句分派/流程语句(迁移自 HandlesBody.vp)
# ============================================================
def translate_stmt(self, trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""翻译单条语句,返回新增的变量数"""
if node is None:
return 0
k: int = node.kind()
if k == ast.ASTKind.Expr:
return self.translate_expr_stmt(trans, node)
elif k == ast.ASTKind.Assign:
return trans.AssignH.Handle(node)
elif k == ast.ASTKind.AnnAssign:
return trans.AnnAssignH.Handle(node)
elif k == ast.ASTKind.FunctionDef:
# 嵌套函数定义:提升为顶层函数 + 创建闭包
return HandlesFunctions.translate_nested_function_def(trans, node)
elif k == ast.ASTKind.Return:
return trans.ReturnH.Handle(node)
elif k == ast.ASTKind.If:
return trans.IfH.Handle(node)
elif k == ast.ASTKind.While:
return trans.WhileH.Handle(node)
elif k == ast.ASTKind.AugAssign:
return trans.AugAssignH.Handle(node)
elif k == ast.ASTKind.For:
return trans.ForH.Handle(node)
elif k == ast.ASTKind.ClassDef:
return HandlesClassDef.translate_class_def(trans, node)
elif k == ast.ASTKind.Import:
return trans.ImportsH.HandleImport(node)
elif k == ast.ASTKind.ImportFrom:
trans.ImportsH.HandleImportFromModule(node)
return trans.ImportsH.HandleImportFromNames(node)
elif k == ast.ASTKind.Global:
return self.translate_global(trans, node)
elif k == ast.ASTKind.Nonlocal:
return self.translate_nonlocal(trans, node)
elif k == ast.ASTKind.Pass:
return 0
elif k == ast.ASTKind.Break:
return self.translate_break(trans)
elif k == ast.ASTKind.Continue:
return self.translate_continue(trans)
elif k == ast.ASTKind.Match:
return trans.MatchH.Handle(node)
elif k == ast.ASTKind.Delete:
return self.translate_delete(trans, node)
return 0
def translate_delete(self, trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""翻译 del 语句,返回 0"""
if trans is None or node is None:
return 0
dnode: ast.Delete | t.CPtr = (ast.Delete | t.CPtr)(node)
if dnode is None or dnode.targets is None:
return 0
pool: memhub.MemBuddy | t.CPtr = trans.Pool
mod: llvmlite.LLVMModule | t.CPtr = trans.Module
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
if pool is None or mod is None or builder is None:
return 0
tn: t.CSizeT = dnode.targets.__len__()
for ti in range(tn):
tgt: ast.AST | t.CPtr = dnode.targets.get(ti)
if tgt is None:
continue
# del obj.attr → property deleter
if tgt.kind() == ast.ASTKind.Attribute:
del_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(tgt)
if del_at is not None:
HandlesExprCall._try_property_deleter(
pool, builder, mod, del_at, trans)
return 0
def translate_global(self, trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""翻译 global 语句:记录 global 变量名"""
gn: ast.Global | t.CPtr = (ast.Global | t.CPtr)(node)
if gn is None:
return 0
names: list[ast.AST | t.CPtr] | t.CPtr = gn.names
if names is None:
return 0
n: t.CSizeT = names.__len__()
for i in range(n):
nm_node: ast.AST | t.CPtr = names.get(i)
if nm_node is not None and nm_node.kind() == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(nm_node)
if nm.id is not None:
HT.add_global_name(trans, nm.id)
return 0
def translate_nonlocal(self, trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""翻译 nonlocal 语句:记录 nonlocal 变量名及其类型
类型信息通过查找父作用域的 alloca 获取(用于 env 指针数组方案的类型恢复)。
"""
nl: ast.Nonlocal | t.CPtr = (ast.Nonlocal | t.CPtr)(node)
if nl is None:
return 0
names: list[ast.AST | t.CPtr] | t.CPtr = nl.names
if names is None:
return 0
n: t.CSizeT = names.__len__()
for i in range(n):
nm_node: ast.AST | t.CPtr = names.get(i)
if nm_node is not None and nm_node.kind() == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(nm_node)
if nm.id is not None:
# 查找父作用域中的变量 alloca,获取类型信息
var_ty: llvmlite.LLVMType | t.CPtr = None
var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
trans.SymTab, nm.id)
if var_alloca is not None and var_alloca.Ty is not None:
var_ty = var_alloca.Ty.Pointee
# Void 类型视为无效(Pointee 访问异常时可能返回 Void),
# 设为 None 让 add_nonlocal_name 回退为 i32,避免生成
# "bitcast ... to void*" / "load void, void*" 非法 IR
if var_ty is not None:
match var_ty:
case llvmlite.LLVMType.Void():
var_ty = None
case _:
pass
HT.add_nonlocal_name(trans, nm.id, var_ty)
return 0
def translate_expr_stmt(self, trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""翻译表达式语句(printf 调用等)"""
ex: ast.Expr | t.CPtr = (ast.Expr | t.CPtr)(node)
if ex is None:
return 0
call_node: ast.AST | t.CPtr = ex.value
if call_node is None:
return 0
ck: int = call_node.kind()
if ck != ast.ASTKind.Call:
return 0
cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(call_node)
func_node: ast.AST | t.CPtr = cl.func
if func_node is None:
return 0
func_name: str = HandlesExpr.get_func_name(func_node)
if func_name is None:
return 0
# printf / print 走特殊路径(print 是类型感知格式化,不映射到 printf)
if string.strcmp(func_name, "printf") == 0:
trans.ExprCallH.HandlePrintfCall(cl)
elif string.strcmp(func_name, "print") == 0:
trans.ExprCallH.HandlePrintCall(cl)
else:
# 通用函数调用(返回值丢弃)
trans.ExprCallH.HandleCall(call_node)
return 0
def pre_scan_allocas(self, trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""预扫描语句中的 AnnAssign,提前创建 alloca
返回新增的变量数
"""
if node is None:
return 0
return trans.AnnAssignH.PreScan(node)
def pre_scan_scope_decls(self, trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""预扫描 Global/Nonlocal 声明,提前注册作用域名称"""
if node is None:
return 0
k: int = node.kind()
if k == ast.ASTKind.Global:
return self.translate_global(trans, node)
if k == ast.ASTKind.Nonlocal:
return self.translate_nonlocal(trans, node)
return 0
def translate_break(self, trans: HT.Translator | t.CPtr) -> int:
"""翻译 break 语句:跳转到循环 end 块"""
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
func: llvmlite.Function | t.CPtr = trans._cur_func
pool: memhub.MemBuddy | t.CPtr = trans.Pool
if builder is None or func is None:
return 0
# 发射 br 到 break 目标
if trans._break_bb is not None:
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
llvmlite.build_br(builder, trans._break_bb)
# 创建死代码 BB,用于后续语句(break 后面的代码不可达)
cnt: int = trans._label_counter
trans._label_counter = cnt + 1
name_buf: t.CChar | t.CPtr = pool.alloc(32)
viperlib.snprintf(name_buf, 32, "dead.%d", cnt)
dead_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
llvmlite.position_at_end(builder, dead_bb)
return 0
def translate_continue(self, trans: HT.Translator | t.CPtr) -> int:
"""翻译 continue 语句:跳转到循环 cond/incr 块"""
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
func: llvmlite.Function | t.CPtr = trans._cur_func
pool: memhub.MemBuddy | t.CPtr = trans.Pool
if builder is None or func is None:
return 0
# 发射 br 到 continue 目标
if trans._continue_bb is not None:
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
llvmlite.build_br(builder, trans._continue_bb)
# 创建死代码 BB,用于后续语句
cnt: int = trans._label_counter
trans._label_counter = cnt + 1
name_buf: t.CChar | t.CPtr = pool.alloc(32)
viperlib.snprintf(name_buf, 32, "dead.%d", cnt)
dead_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
llvmlite.position_at_end(builder, dead_bb)
return 0
def get_stmt_kind_name(self, node: ast.AST | t.CPtr) -> str:
"""获取语句类型名"""
if node is None:
return None
return node.type_name()
# ============================================================
# 簇 B:编译期 CIf 宏求值(迁移自 HandlesIf.vp 模块级函数)
# ============================================================
def _is_cif_attr(self, attr: str) -> int:
"""检查方法名是否为 CIf 系(CIf/CIfdef/CIfndef)"""
if attr is None:
return 0
if string.strcmp(attr, "CIf") == 0: return 1
if string.strcmp(attr, "CIfdef") == 0: return 1
if string.strcmp(attr, "CIfndef") == 0: return 1
return 0
def _is_cif_call(self, node: ast.AST | t.CPtr) -> int:
"""检查 test 是否为 c.CIf(...)/c.CIfdef(...)/c.CIfndef(...)(或裸 CIf 系)调用"""
if node is None or node.kind() != ast.ASTKind.Call:
return 0
cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node)
if cl.func is None:
return 0
fk: int = cl.func.kind()
if fk == ast.ASTKind.Attribute:
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
if at.attr is None:
return 0
if at.value is not None and at.value.kind() == ast.ASTKind.Name:
vn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
if vn.id is not None and string.strcmp(vn.id, "c") == 0:
return self._is_cif_attr(at.attr)
return 0
if fk == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cl.func)
if nm.id is not None and self._is_cif_attr(nm.id) != 0:
return 1
return 0
def _get_platform_macro_value(self, name: str) -> int:
"""平台内置宏值(从目标三元组推导,对齐 TPC HandlesIf._get_platform_macros)。
命中置 self.CifEvalOk=1;未命中置 0 返回 0。
"""
self.CifEvalOk = 0
if name is None:
return 0
triple: str = Config.TargetTriple
if triple is None:
triple = "x86_64-pc-windows-gnu"
is_win: int = 0
is_linux: int = 0
is_x64: int = 0
if string.strstr(triple, "windows") is not None \
or string.strstr(triple, "win32") is not None \
or string.strstr(triple, "mingw") is not None \
or string.strstr(triple, "msvc") is not None:
is_win = 1
if string.strstr(triple, "linux") is not None:
is_linux = 1
if string.strstr(triple, "x86_64") is not None:
is_x64 = 1
# 简化:本编译目标为 x86_64 Windows(_WIN64/WIN64 恒与 is_win 一致)
if string.strcmp(name, "_WIN32") == 0: self.CifEvalOk = is_win; return 1 if is_win else 0
if string.strcmp(name, "WIN32") == 0: self.CifEvalOk = is_win; return 1 if is_win else 0
if string.strcmp(name, "_WIN64") == 0: self.CifEvalOk = is_win; return 1 if is_win else 0
if string.strcmp(name, "WIN64") == 0: self.CifEvalOk = is_win; return 1 if is_win else 0
if string.strcmp(name, "__linux__") == 0: self.CifEvalOk = is_linux; return 1 if is_linux else 0
if string.strcmp(name, "__x86_64__") == 0: self.CifEvalOk = is_x64; return 1 if is_x64 else 0
if string.strcmp(name, "__x86_64") == 0: self.CifEvalOk = is_x64; return 1 if is_x64 else 0
if string.strcmp(name, "_M_X64") == 0: self.CifEvalOk = is_x64; return 1 if is_x64 else 0
if string.strcmp(name, "SIZEOF_VOID_P") == 0: self.CifEvalOk = 1; return 8 if is_x64 else 4
if string.strcmp(name, "__SIZEOF_POINTER__") == 0: self.CifEvalOk = 1; return 8 if is_x64 else 4
if string.strcmp(name, "NDEBUG") == 0: self.CifEvalOk = 1; return 0
return 0
def _cif_name_value(self, pool: memhub.MemBuddy | t.CPtr,
trans: HT.Translator | t.CPtr,
name: str) -> int:
"""查宏名值: 本地 CDefine → 跨模块 CDefine → 平台宏。
命中置 self.CifEvalOk=1(值 0 也算命中,如 DISABLED=0);未命中置 0。
"""
self.CifEvalOk = 0
if name is None or trans is None:
return 0
v: int = HandlesType.lookup_cdefine_constant(name)
if HandlesType.is_cdefine_found() != 0:
self.CifEvalOk = 1
return v
v2: int = HandlesExpr._lookup_cross_module_cdefine(
pool, name, trans._from_imports, trans._imported_modules)
if HandlesType.is_cdefine_found() != 0:
self.CifEvalOk = 1
return v2
pv: int = self._get_platform_macro_value(name)
if self.CifEvalOk != 0:
return pv
return 0
def _cif_attr_value(self, pool: memhub.MemBuddy | t.CPtr,
trans: HT.Translator | t.CPtr,
at: ast.Attribute | t.CPtr) -> int:
"""Attribute 宏值: platmacro.IS_WINDOWS → 本地 CDefine(attr) → 跨模块 CDefine。
命中置 self.CifEvalOk=1;未命中置 0。
"""
self.CifEvalOk = 0
if at is None or at.attr is None or at.value is None or trans is None:
return 0
if at.value.kind() != ast.ASTKind.Name:
return 0
vn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
if vn.id is None:
return 0
v: int = HandlesType.lookup_cdefine_constant(at.attr)
if HandlesType.is_cdefine_found() != 0:
self.CifEvalOk = 1
return v
# 跨模块: 确定真实模块名(解析 from_imports 别名)
real_mod: str = vn.id
if trans._from_imports is not None:
resolved: str = HandlesImports.lookup_from_import(
trans._from_imports, vn.id, 0)
if resolved is not None:
rm_len: t.CSizeT = 0
while resolved[rm_len] != ' ' and resolved[rm_len] != '\0' and resolved[rm_len] != ':':
rm_len += 1
rm_buf: str = pool.alloc(rm_len + 1)
if rm_buf is not None:
for rm_i in range(rm_len):
rm_buf[rm_i] = resolved[rm_i]
rm_buf[rm_len] = '\0'
real_mod = rm_buf
fi_len: t.CSizeT = string.strlen(at.attr) + string.strlen(real_mod) + 2
fi: str = pool.alloc(fi_len)
if fi is None:
return 0
viperlib.snprintf(fi, fi_len, "%s:%s", at.attr, real_mod)
v2: int = HandlesExpr._lookup_cross_module_cdefine(pool, at.attr, fi)
if HandlesType.is_cdefine_found() != 0:
self.CifEvalOk = 1
return v2
return 0
def _cif_eval_node(self, pool: memhub.MemBuddy | t.CPtr,
trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""递归常量求值 CIf 表达式。
支持: Constant(int) / Name(CDefine/跨模块/平台宏) / Attribute(跨模块 CDefine)
/ BinOp(+ - * // % & | ^ << >>) / Compare(== != < > <= >=)
/ BoolOp(and/or) / UnaryOp(not - + ~)。
成功置 self.CifEvalOk=1;失败(含运行时变量)置 0 返回 0。
"""
if node is None:
self.CifEvalOk = 0
return 0
k: int = node.kind()
if k == ast.ASTKind.Constant:
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node)
if cn.const_kind == ast.CONST_INT:
self.CifEvalOk = 1
return cn.int_val
self.CifEvalOk = 0
return 0
if k == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node)
if nm.id is None:
self.CifEvalOk = 0
return 0
return self._cif_name_value(pool, trans, nm.id)
if k == ast.ASTKind.Attribute:
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node)
return self._cif_attr_value(pool, trans, at)
if k == ast.ASTKind.UnaryOp:
uop: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node)
if uop.operand is None:
self.CifEvalOk = 0
return 0
ov: int = self._cif_eval_node(pool, trans, uop.operand)
if self.CifEvalOk == 0:
return 0
if uop.op == ast.OpKind.Not: return 1 if ov == 0 else 0
if uop.op == ast.OpKind.USub: return -ov
if uop.op == ast.OpKind.UAdd: return ov
if uop.op == ast.OpKind.Invert: return ~ov
self.CifEvalOk = 0
return 0
if k == ast.ASTKind.BoolOp:
bo: ast.BoolOp | t.CPtr = (ast.BoolOp | t.CPtr)(node)
vals: list[ast.AST | t.CPtr] | t.CPtr = bo.values
if vals is None:
self.CifEvalOk = 0
return 0
bn: t.CSizeT = vals.__len__()
if bo.op == ast.OpKind.And:
for bi in range(bn):
rv: int = self._cif_eval_node(pool, trans, vals.get(bi))
if self.CifEvalOk == 0:
return 0
if rv == 0:
return 0
return 1
if bo.op == ast.OpKind.Or:
for bi in range(bn):
rv: int = self._cif_eval_node(pool, trans, vals.get(bi))
if self.CifEvalOk == 0:
return 0
if rv != 0:
return 1
return 0
self.CifEvalOk = 0
return 0
if k == ast.ASTKind.Compare:
cmp: ast.Compare | t.CPtr = (ast.Compare | t.CPtr)(node)
lv: int = self._cif_eval_node(pool, trans, cmp.left)
if self.CifEvalOk == 0:
return 0
ops_list: list[t.CInt] | t.CPtr = (list[t.CInt] | t.CPtr)(cmp.ops)
comps: list[ast.AST | t.CPtr] | t.CPtr = cmp.comparators
if ops_list is None or comps is None:
self.CifEvalOk = 0
return 0
cc: t.CSizeT = comps.__len__()
ci: t.CSizeT
for ci in range(cc):
rv: int = self._cif_eval_node(pool, trans, comps.get(ci))
if self.CifEvalOk == 0:
return 0
op_id: int = ops_list.get(ci)
ok_cmp: int = 0
if op_id == ast.OpKind.Eq: ok_cmp = 1 if lv == rv else 0
elif op_id == ast.OpKind.Ne: ok_cmp = 1 if lv != rv else 0
elif op_id == ast.OpKind.Lt: ok_cmp = 1 if lv < rv else 0
elif op_id == ast.OpKind.Le: ok_cmp = 1 if lv <= rv else 0
elif op_id == ast.OpKind.Gt: ok_cmp = 1 if lv > rv else 0
elif op_id == ast.OpKind.Ge: ok_cmp = 1 if lv >= rv else 0
else:
self.CifEvalOk = 0
return 0
if ok_cmp == 0:
return 0
lv = rv
return 1
if k == ast.ASTKind.BinOp:
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node)
lv: int = self._cif_eval_node(pool, trans, bop.left)
if self.CifEvalOk == 0:
return 0
rv: int = self._cif_eval_node(pool, trans, bop.right)
if self.CifEvalOk == 0:
return 0
if bop.op == ast.OpKind.Add: return lv + rv
if bop.op == ast.OpKind.Sub: return lv - rv
if bop.op == ast.OpKind.Mult: return lv * rv
if bop.op == ast.OpKind.FloorDiv:
if rv == 0:
self.CifEvalOk = 0
return 0
return lv // rv
if bop.op == ast.OpKind.Mod:
if rv == 0:
self.CifEvalOk = 0
return 0
return lv % rv
if bop.op == ast.OpKind.BitAnd: return lv & rv
if bop.op == ast.OpKind.BitOr: return lv | rv
if bop.op == ast.OpKind.BitXor: return lv ^ rv
if bop.op == ast.OpKind.LShift: return lv << rv
if bop.op == ast.OpKind.RShift: return lv >> rv
self.CifEvalOk = 0
return 0
self.CifEvalOk = 0
return 0
def _evaluate_cif_test(self, pool: memhub.MemBuddy | t.CPtr,
trans: HT.Translator | t.CPtr,
test: ast.AST | t.CPtr) -> int:
"""求值 CIf 调用(test 必须是 c.CIf 系调用)。
成功: 置 self.CifEvalOk=1,返回条件值(0/1)
失败(运行时变量/未知结构): 置 self.CifEvalOk=0,返回 0
"""
self.CifEvalOk = 0
cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(test)
if cl is None or cl.func is None:
return 0
kind: str = None
fk: int = cl.func.kind()
if fk == ast.ASTKind.Attribute:
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
kind = at.attr
elif fk == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cl.func)
kind = nm.id
if kind is None:
return 0
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
if cargs is None or cargs.__len__() < 1:
return 0
arg0: ast.AST | t.CPtr = cargs.get(0)
if string.strcmp(kind, "CIf") == 0:
v: int = self._cif_eval_node(pool, trans, arg0)
if self.CifEvalOk == 0:
return 0
return 1 if v != 0 else 0
# CIfdef / CIfndef: 判定宏名是否已定义
defined: int = 0
if arg0 is not None and arg0.kind() == ast.ASTKind.Name:
nm0: ast.Name | t.CPtr = (ast.Name | t.CPtr)(arg0)
if nm0.id is None:
return 0
self._cif_name_value(pool, trans, nm0.id)
defined = self.CifEvalOk
elif arg0 is not None and arg0.kind() == ast.ASTKind.Constant:
cn0: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(arg0)
if cn0.const_kind == ast.CONST_STR and cn0.str_val is not None:
self._cif_name_value(pool, trans, cn0.str_val)
defined = self.CifEvalOk
else:
return 0
elif arg0 is not None and arg0.kind() == ast.ASTKind.Attribute:
at0: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(arg0)
self._cif_attr_value(pool, trans, at0)
defined = self.CifEvalOk
else:
return 0
# 定义判定本身成功(未定义名特判:不报错,defined=0 走 else)
self.CifEvalOk = 1
if string.strcmp(kind, "CIfdef") == 0:
return 1 if defined != 0 else 0
# CIfndef
return 0 if defined != 0 else 1
def NewIfHandle(self, pool: memhub.MemBuddy | t.CPtr,
trans: HT.Translator | t.CPtr) -> HandlesIf.IfHandle | t.CPtr:
"""创建 IfHandle 实例(迁移自 HandlesIf.NewIfHandle)"""
h: HandlesIf.IfHandle | t.CPtr = pool.alloc(HandlesIf.IfHandle.__sizeof__())
if h is None:
return None
string.memset(h, 0, HandlesIf.IfHandle.__sizeof__())
h.Trans = trans
return h
# ============================================================
# 簇 C:循环/return/match 子 Handle 工厂(迁移自
# HandlesWhile/HandlesFor/HandlesReturn/HandlesMatch)
# ============================================================
def NewWhileHandle(self, pool: memhub.MemBuddy | t.CPtr,
trans: HT.Translator | t.CPtr) -> HandlesWhile.WhileHandle | t.CPtr:
"""创建 WhileHandle 实例(迁移自 HandlesWhile.NewWhileHandle)"""
h: HandlesWhile.WhileHandle | t.CPtr = pool.alloc(HandlesWhile.WhileHandle.__sizeof__())
if h is None:
return None
string.memset(h, 0, HandlesWhile.WhileHandle.__sizeof__())
h.Trans = trans
return h
def NewForHandle(self, pool: memhub.MemBuddy | t.CPtr,
trans: HT.Translator | t.CPtr) -> HandlesFor.ForHandle | t.CPtr:
"""创建 ForHandle 实例(迁移自 HandlesFor.NewForHandle)"""
h: HandlesFor.ForHandle | t.CPtr = pool.alloc(HandlesFor.ForHandle.__sizeof__())
if h is None:
return None
string.memset(h, 0, HandlesFor.ForHandle.__sizeof__())
h.Trans = trans
return h
def NewReturnHandle(self, pool: memhub.MemBuddy | t.CPtr,
trans: HT.Translator | t.CPtr) -> HandlesReturn.ReturnHandle | t.CPtr:
"""创建 ReturnHandle 实例(迁移自 HandlesReturn.NewReturnHandle)"""
h: HandlesReturn.ReturnHandle | t.CPtr = pool.alloc(HandlesReturn.ReturnHandle.__sizeof__())
if h is None:
return None
string.memset(h, 0, HandlesReturn.ReturnHandle.__sizeof__())
h.Trans = trans
return h
def NewMatchHandle(self, pool: memhub.MemBuddy | t.CPtr,
trans: HT.Translator | t.CPtr) -> HandlesMatch.MatchHandle | t.CPtr:
"""创建 MatchHandle 实例(迁移自 HandlesMatch.NewMatchHandle)"""
h: HandlesMatch.MatchHandle | t.CPtr = pool.alloc(HandlesMatch.MatchHandle.__sizeof__())
if h is None:
return None
string.memset(h, 0, HandlesMatch.MatchHandle.__sizeof__())
h.Trans = trans
return h
# ============================================================
# 簇 D:nonlocal/闭包 env 访问(迁移自 HandlesNonlocal.vp)
# ============================================================
def _is_void_type(self, ty: llvmlite.LLVMType | t.CPtr) -> int:
"""判断是否为 Void 类型,是则返回 1,否则 0"""
if ty is None:
return 0
match ty:
case llvmlite.LLVMType.Void():
return 1
case _:
return 0
def get_env_ptr_var(self, trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
"""获取或创建 _env_ptr 变量(存储闭包 env 指针)"""
env_var: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
trans.SymTab, "_env_ptr")
if env_var is not None:
return env_var
# 创建 alloca 存储 env
pool: memhub.MemBuddy | t.CPtr = trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, i8_ptr_ty)
if alloca is None:
return None
HandlesVar.define_var(trans.SymTab, "_env_ptr", alloca)
return alloca
def _load_raw_var_ptr(self, trans: HT.Translator | t.CPtr,
name: str) -> llvmlite.Value | t.CPtr:
"""从闭包 env 加载 nonlocal 变量的原始指针(i8*)
返回 i8* 类型的 Value,调用方需 bitcast 为具体类型指针后 load/store。
"""
idx: int = HT.get_nonlocal_index(trans, name)
if idx < 0:
return None
pool: memhub.MemBuddy | t.CPtr = trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
i8_ptr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty)
# 1. 加载 env_ptr
env_alloca: llvmlite.Value | t.CPtr = self.get_env_ptr_var(trans)
if env_alloca is None:
return None
env_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, env_alloca)
if env_ptr is None:
return None
# 2. GEP to offset (idx * 8) — env 存储指针数组,每槽 8 字节
offset_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, idx * 8)
addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, env_ptr, offset_val)
if addr is None:
return None
# 3. Bitcast to i8** and load the raw pointer
ptr_addr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, addr, i8_ptr_ptr_ty)
if ptr_addr is None:
return None
return llvmlite.build_load(builder, i8_ptr_ty, ptr_addr)
def load_nonlocal_var(self, trans: HT.Translator | t.CPtr,
name: str) -> llvmlite.Value | t.CPtr:
"""从闭包 env 加载 nonlocal 变量值
通过 HT.get_nonlocal_type 获取变量类型,bitcast 原始指针后 load。
"""
raw_ptr: llvmlite.Value | t.CPtr = self._load_raw_var_ptr(trans, name)
if raw_ptr is None:
return None
pool: memhub.MemBuddy | t.CPtr = trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
# 获取变量类型(从注册时存储的类型信息)
var_ty: llvmlite.LLVMType | t.CPtr = HT.get_nonlocal_type(trans, name)
if var_ty is None or self._is_void_type(var_ty) != 0:
# Void 类型视为无效(会导致 "load void, void*" 非法 IR),回退为 i32
var_ty = llvmlite.Int32(pool)
# bitcast raw i8* to var_ty*
var_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, var_ty)
var_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, raw_ptr, var_ptr_ty)
if var_ptr is None:
return None
return llvmlite.build_load(builder, var_ty, var_ptr)
def get_nonlocal_var_ptr(self, trans: HT.Translator | t.CPtr,
name: str) -> llvmlite.Value | t.CPtr:
"""获取 nonlocal 变量的存储指针(var_ty*),用于 store 操作
返回的指针指向父函数的 alloca,store 操作对父函数可见。
"""
raw_ptr: llvmlite.Value | t.CPtr = self._load_raw_var_ptr(trans, name)
if raw_ptr is None:
return None
pool: memhub.MemBuddy | t.CPtr = trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
# 获取变量类型
var_ty: llvmlite.LLVMType | t.CPtr = HT.get_nonlocal_type(trans, name)
if var_ty is None or self._is_void_type(var_ty) != 0:
# Void 类型视为无效(会导致 "bitcast ... to void*" 非法 IR),回退为 i32
var_ty = llvmlite.Int32(pool)
# bitcast raw i8* to var_ty*
var_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, var_ty)
return llvmlite.build_bitcast(builder, raw_ptr, var_ptr_ty)
# ============================================================
# 簇 E:枚举注册表(迁移自 HandlesEnum.vp)
# ============================================================
def init_enum_table(self, pool: memhub.MemBuddy | t.CPtr) -> int:
"""初始化枚举注册表,返回 1 成功"""
if self.EnumTable is not None:
return 1
entry_size: t.CSizeT = HandlesEnum.EnumEntry.__sizeof__()
self.EnumTable = pool.alloc(entry_size * ENUM_MAX)
if self.EnumTable is None:
return 0
string.memset(self.EnumTable, 0, entry_size * ENUM_MAX)
self.EnumCount = 0
return 1
def _get_enum_entry(self, i: int) -> HandlesEnum.EnumEntry | t.CPtr:
"""获取第 i 个枚举条目"""
if self.EnumTable is None or i < 0 or i >= ENUM_MAX:
return None
entry_size: t.CSizeT = HandlesEnum.EnumEntry.__sizeof__()
addr: t.CUInt64T = t.CUInt64T(self.EnumTable) + i * entry_size
return (HandlesEnum.EnumEntry | t.CPtr)(t.CVoid(addr, t.CPtr))
def _get_enum_member(self, enum_entry: HandlesEnum.EnumEntry | t.CPtr,
i: int) -> HandlesEnum.EnumMember | t.CPtr:
"""获取枚举中第 i 个成员条目"""
if enum_entry is None or i < 0 or i >= ENUM_MEMBER_MAX:
return None
member_size: t.CSizeT = HandlesEnum.EnumMember.__sizeof__()
addr: t.CUInt64T = t.CUInt64T(enum_entry.Members) + i * member_size
return (HandlesEnum.EnumMember | t.CPtr)(t.CVoid(addr, t.CPtr))
def register_enum(self, pool: memhub.MemBuddy | t.CPtr,
name: str,
base_ty: llvmlite.LLVMType | t.CPtr) -> HandlesEnum.EnumEntry | t.CPtr:
"""注册枚举类型,返回 EnumEntry 指针"""
if self.init_enum_table(pool) == 0:
return None
# 检查是否已注册
existing: HandlesEnum.EnumEntry | t.CPtr = self.find_enum(name)
if existing is not None:
return existing
if self.EnumCount >= ENUM_MAX:
fb_et: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_et is not None:
viperlib.snprintf(fb_et, 1024, "table full, cannot register %s", name)
VLogger.error(fb_et, "ENUM")
return None
entry: HandlesEnum.EnumEntry | t.CPtr = self._get_enum_entry(self.EnumCount)
if entry is None:
return None
# 分配成员数组
member_size: t.CSizeT = HandlesEnum.EnumMember.__sizeof__()
entry.Members = pool.alloc(member_size * ENUM_MEMBER_MAX)
if entry.Members is None:
return None
string.memset(entry.Members, 0, member_size * ENUM_MEMBER_MAX)
# 复制类名
name_len: t.CSizeT = string.strlen(name)
name_buf: t.CChar | t.CPtr = pool.alloc(name_len + 1)
if name_buf is not None:
string.strcpy(name_buf, name)
entry.Name = name_buf
entry.BaseTy = base_ty
entry.MemberCount = 0
self.EnumCount += 1
return entry
def add_enum_member(self, pool: memhub.MemBuddy | t.CPtr,
enum_entry: HandlesEnum.EnumEntry | t.CPtr,
member_name: str,
member_val: t.CInt64T,
member_ty: llvmlite.LLVMType | t.CPtr) -> int:
"""向枚举添加成员,返回成员索引(-1 失败)"""
if enum_entry is None or member_name is None or member_ty is None:
return -1
if enum_entry.MemberCount >= ENUM_MEMBER_MAX:
fb_em: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_em is not None:
viperlib.snprintf(fb_em, 1024, "member table full for %s", enum_entry.Name)
VLogger.error(fb_em, "ENUM")
return -1
idx: int = enum_entry.MemberCount
me: HandlesEnum.EnumMember | t.CPtr = self._get_enum_member(enum_entry, idx)
if me is None:
return -1
# 复制成员名
name_len: t.CSizeT = string.strlen(member_name)
name_buf: t.CChar | t.CPtr = pool.alloc(name_len + 1)
if name_buf is not None:
string.strcpy(name_buf, member_name)
me.Name = name_buf
me.Value = member_val
me.Ty = member_ty
enum_entry.MemberCount = idx + 1
return idx
def find_enum(self, name: str) -> HandlesEnum.EnumEntry | t.CPtr:
"""按枚举类名查找,返回 EnumEntry 或 None"""
if name is None or self.EnumTable is None:
return None
for i in range(self.EnumCount):
entry: HandlesEnum.EnumEntry | t.CPtr = self._get_enum_entry(i)
if entry is not None and entry.Name is not None:
if string.strcmp(entry.Name, name) == 0:
return entry
return None
def lookup_enum_member(self, enum_name: str,
member_name: str) -> HandlesEnum.EnumMember | t.CPtr:
"""按枚举类名和成员名查找,返回 EnumMember 或 None"""
if enum_name is None or member_name is None:
return None
entry: HandlesEnum.EnumEntry | t.CPtr = self.find_enum(enum_name)
if entry is None:
return None
for mi in range(entry.MemberCount):
me: HandlesEnum.EnumMember | t.CPtr = self._get_enum_member(entry, mi)
if me is not None and me.Name is not None:
if string.strcmp(me.Name, member_name) == 0:
return me
return None
def is_enum_class(self, name: str) -> int:
"""检查类名是否为已注册枚举,返回 1=是 / 0=否"""
if name is None:
return 0
if self.find_enum(name) is not None:
return 1
return 0
def get_enum_base_type(self, enum_name: str) -> llvmlite.LLVMType | t.CPtr:
"""按枚举类名获取基准类型"""
entry: HandlesEnum.EnumEntry | t.CPtr = self.find_enum(enum_name)
if entry is not None:
return entry.BaseTy
return None
+695
View File
@@ -0,0 +1,695 @@
import t, c
from stdint import *
import ast
import llvmlite
import memhub
import string
import stdio
import stdlib
import viperlib
import lib.core.VLogger as VLogger
import lib.core.Handles.HandlesTranslator as HT
import lib.core.Handles.HandlesVar as HandlesVar
import lib.core.Handles.HandlesExprCall as HandlesExprCall
import lib.core.Handles.HandlesImports as HandlesImports
import lib.core.Handles.HandlesBody as HandlesBody
import lib.core.Handles.HandlesFunctions as HandlesFunctions
import lib.core.Handles.HandlesType as HandlesType
import lib.core.Handles.HandlesClassDef as HandlesClassDef
import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign
# ============================================================
# TranslatorGenMixin - 翻译驱动 Mixin(对象化 P6-E)
#
# 从 HandlesMain.vp / HandlesTranslator.vp 迁移:模块级纯函数
# (trans 首参)→ 类方法。包含:
# - 模块级翻译入口(translate_children/create_wrapper_main/
# handle_module_level_var 等,原 HandlesMain.vp)
# - global/nonlocal 名称管理辅助函数(原 HandlesTranslator.vp)
#
# 迁移原则(与 P2-P5 一致,行为零变化):
# 1. 方法保留原函数签名(含 trans/pool 首参),仅函数体内的
# 本模块函数调用改为 self.xxx(...)
# 2. 外部模块调用(HandlesType.xxx/HandlesVar.xxx 等)保留模块前缀
# 3. HandlesMain/HandlesTranslator 原函数保留为"委托":本地模块级
# 单例 _g_gen(BuildPipeline/main 注入)cast 成 Generator 类型
# 4. 嵌套函数保持嵌套
#
# 常量(MAX_VARS/MAX_FUNCS/MAX_GLOBAL_NAMES)与原模块保持一致。
# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。
# ============================================================
# ============================================================
# 常量(与 HandlesTranslator 保持一致)
# ============================================================
MAX_VARS: t.CDefine = 256
MAX_FUNCS: t.CDefine = 256
MAX_GLOBAL_NAMES: t.CDefine = 32
# ============================================================
# TranslatorGenMixin - 翻译驱动(模块级翻译入口 + 作用域名称管理)
# ============================================================
@t.NoVTable
class TranslatorGenMixin:
"""翻译驱动 Mixin(P6 方法化)"""
# ============================================================
# _register_cexport_from_funcdef - Phase 1a 预注册 CExport/State 函数
#
# 解决翻译顺序依赖问题:Phase 1b 按字母序翻译,后翻译的模块的
# CExport 函数无法被先翻译的模块正确识别为裸名调用。
# Phase 1a 预注册所有 CExport/State 函数名到全局表。
# ============================================================
def _register_cexport_from_funcdef(self, trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""预注册 CExport/State 函数到全局表(仅注册,不生成 IR)"""
fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(node)
if fd is None or fd.name is None:
return 0
if trans is None or trans.ModuleSha1 is None:
return 0
# 检查返回类型是否有 CExport 或 State 标记
has_export: int = 0
has_state: int = 0
if fd.returns is not None:
has_export = HandlesType.has_decorator_marker(fd.returns, "CExport")
has_state = HandlesType.has_decorator_marker(fd.returns, "State")
if has_export != 0 or has_state != 0:
HandlesExprCall.register_cexport_func(trans.ModuleSha1, fd.name)
return 0
# ============================================================
# translate_children - 遍历 AST 子节点并分派翻译
#
# 对应 TransPyC translator._translate_children()
# 共享状态从 trans 获取,imported_modules/from_imports 更新到 trans
# ============================================================
def translate_children(self, trans: HT.Translator | t.CPtr,
tree: ast.AST | t.CPtr) -> int:
"""遍历 tree.children 并翻译每个子节点
Args:
trans: 翻译器(含所有共享状态)
tree: AST 模块节点
Returns:
t.CInt: 新增的变量数
"""
ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children
if ch is None:
return 0
cn_count: t.CSizeT = ch.__len__()
added_total: int = 0
for ci in range(cn_count):
child: ast.AST | t.CPtr = ch.get(ci)
if child is None: continue
kd: int = child.kind()
# _declare_only == 0 时,_translate_module_level 已预处理导入语句,
# 此处跳过避免重复处理(from_imports 条目重复)
if trans._declare_only == 0 and (kd == ast.ASTKind.Import or kd == ast.ASTKind.ImportFrom):
continue
if kd == ast.ASTKind.Import:
trans.ImportsH.HandleImport(child)
elif kd == ast.ASTKind.ImportFrom:
trans.ImportsH.HandleImportFromModule(child)
trans.ImportsH.HandleImportFromNames(child)
elif kd == ast.ASTKind.FunctionDef:
# Phase 1a 声明模式:只注册 CExport/State 函数到全局表(解决翻译顺序依赖)
# Phase 1b 全量翻译:正常翻译函数体
if trans._declare_only == 0:
added: int = HandlesFunctions.translate_function_def(trans, child)
added_total += added
elif trans._declare_only == 1:
self._register_cexport_from_funcdef(trans, child)
# 预解析函数签名类型,触发泛型类特化(如 numpy 的 _empty_like
# 签名 ndarray[t.CDouble] → 特化结构体注册)。
# 1a 阶段在 mark1 之前,特化结构体的 Ty/Fields 分配在 mark1 前,
# 不被 1b 的 mark/reset 回收 → 避免 Phase2 翻译 App 文件时 UAF
# (Phase1 1b 才触发特化时,结构体 Ty/Fields 在 pool 被 reset 覆写)。
# 仅触发特化,不验证结果(1b 全量翻译时仍会重新解析)。
self._prescan_funcdef_signatures(trans, child)
elif kd == ast.ASTKind.ClassDef:
# ClassDef 在模块级直接处理(不需要 builder)
# _declare_only=2(import扫描模式)时跳过,只处理 import 依赖
if trans._declare_only != 2:
HandlesClassDef.translate_class_def(trans, child)
elif trans._declare_only == 0 and trans._cur_builder is not None:
# 有 builder → 委托 HandlesBody 分派
added = HandlesBody.translate_stmt(trans, child)
added_total += added
elif kd == ast.ASTKind.AnnAssign and trans._declare_only != 2:
# 模块级 AnnAssign
# _declare_only=2(import扫描模式)时跳过
# _declare_only=1(struct注册模式)时只处理 CDefine(在 handle_module_level_var 内部判断)
# _declare_only=0(全量翻译)时处理所有模块级 AnnAssign
added = self.handle_module_level_var(trans, child)
added_total += added
elif trans._declare_only == 0 and kd == ast.ASTKind.Assign:
# 无 builder 的模块级 Assign → 创建全局变量(仅全量翻译模式)
added = self.handle_module_level_var(trans, child)
added_total += added
return added_total
# ============================================================
# _prescan_funcdef_signatures - 1a 阶段预解析模块级函数签名
#
# 触发泛型类特化(如 numpy 的 _empty_like 签名 ndarray[t.CDouble]),
# 使特化结构体在 mark1 前注册(Ty/Fields 不被 1b 的 mark/reset 回收),
# 避免 Phase2 翻译 App 文件时访问悬空结构体(UAF)。
# 仅解析类型触发特化,不验证结果(1b 全量翻译时重新解析)。
# ============================================================
def _prescan_funcdef_signatures(self, trans: HT.Translator | t.CPtr,
fd: ast.FunctionDef | t.CPtr) -> None:
"""预解析模块级函数签名的返回/参数类型,触发泛型类特化"""
if trans is None or fd is None:
return
pool: memhub.MemBuddy | t.CPtr = trans.Pool
if pool is None:
return
imp: str = trans._imported_modules
fi: str = trans._from_imports
if fd.returns is not None:
HandlesType.resolve_annotation_type(pool, fd.returns, imp, fi, trans)
if fd.args is not None:
ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(fd.args)
if ags.args is not None:
al: list[ast.AST | t.CPtr] | t.CPtr = ags.args
an: t.CSizeT = al.__len__()
ai: t.CSizeT
for ai in range(an):
ag: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(al.get(ai))
if ag is not None and ag.annotation is not None:
HandlesType.resolve_annotation_type(pool, ag.annotation, imp, fi, trans)
# ============================================================
# _build_array_initializer_text - 从 AST List 生成 LLVM IR 数组初始化器
#
# 生成格式: [N x elem_ty] [elem_ty val0, elem_ty val1, ...]
# 用于模块级 t.CArray 列表字面量初始化(不依赖 builder,直接生成常量初始化器)
# ============================================================
def _build_array_initializer_text(self, pool: memhub.MemBuddy | t.CPtr,
var_ty: llvmlite.LLVMType | t.CPtr,
list_node: ast.List | t.CPtr) -> str:
"""从 AST List 节点生成 LLVM IR 数组初始化器文本,None 失败"""
if var_ty is None or list_node is None:
return None
# 重新进行类型转换,确保 TPV 编译器正确识别 ast.List 类型
# (避免 init_list_node 初始值为 None 时类型推断退化为 t.CPtr)
ln: ast.List | t.CPtr = (ast.List | t.CPtr)(list_node)
if ln is None:
return None
# 从 var_ty 提取数组元素类型和数量
elem_ty: llvmlite.LLVMType | t.CPtr = None
arr_count: t.CInt = 0
match var_ty:
case llvmlite.LLVMType.Array(et, cnt):
elem_ty = et
arr_count = cnt
if elem_ty is None or arr_count <= 0:
return None
# 确定元素类型的 IR 表示
elem_ir_ty: str = "i8"
match elem_ty:
case llvmlite.LLVMType.Int(bits):
if bits == 8:
elem_ir_ty = "i8"
elif bits == 16:
elem_ir_ty = "i16"
elif bits == 32:
elem_ir_ty = "i32"
elif bits == 64:
elem_ir_ty = "i64"
# 获取列表元素(通过 ln.elts 而非 list_node.elts,确保类型正确识别)
elts: list[ast.AST | t.CPtr] | t.CPtr = ln.elts
if elts is None:
return None
elts_count: t.CSizeT = elts.__len__()
# 计算缓冲区大小: 每个元素最多 "i32 -9223372036854775808, " 约 26 字符
buf_size: t.CSizeT = 64 + elts_count * 32
buf: t.CChar | t.CPtr = pool.alloc(buf_size)
if buf is None:
return None
# 写入前缀: "["(类型前缀由 _print_global 输出,初始化器只需元素列表)
written: t.CInt = viperlib.snprintf(buf, buf_size, "[")
pos: t.CSizeT = t.CSizeT(written)
# 逐个元素写入
i: t.CSizeT = 0
while i < elts_count:
elem_node: ast.AST | t.CPtr = elts.get(i)
# 直接从 Constant 节点提取 int_val(避免 extract_cdefine_int_value 的 t.CInt 截断)
elem_val: t.CInt64T = 0
if elem_node is not None:
ek: int = elem_node.kind()
if ek == ast.ASTKind.Constant:
ec: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(elem_node)
if ec is not None and ec.const_kind == ast.CONST_INT:
elem_val = ec.int_val
elif ek == ast.ASTKind.UnaryOp:
# 负数: UnaryOp(USub, Constant)
elem_val = HandlesAnnAssign.extract_cdefine_int_value(elem_node)
if i > 0:
written = viperlib.snprintf(buf + pos, buf_size - pos, ", ")
pos += t.CSizeT(written)
written = viperlib.snprintf(buf + pos, buf_size - pos, "%s %lld", elem_ir_ty, elem_val)
pos += t.CSizeT(written)
i += 1
# 写入后缀 "]"
viperlib.snprintf(buf + pos, buf_size - pos, "]")
return buf
# ============================================================
# _build_string_ptr_initializer - 为字符串字面量初始化指针类型全局变量
#
# 创建内部字符串常量全局 @.str.{var_name} = private constant [len+1 x i8] c"...\00"
# 返回 GEP 初始化器文本: getelementptr inbounds ([len+1 x i8], [len+1 x i8]* @.str.{var_name}, i32 0, i32 0)
# 用于 b64_tab: t.CArray[t.CChar, None] = "ABC..." 等字符串初始化指针类型
# ============================================================
def _build_string_ptr_initializer(self, pool: memhub.MemBuddy | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
var_name: str,
str_val: str) -> str:
"""为字符串字面量创建内部常量全局并返回 GEP 初始化器文本,None 失败"""
if str_val is None or var_name is None:
return None
# 构造内部字符串常量名称: .str.{var_name}
str_name_buf: t.CChar | t.CPtr = pool.alloc(64)
if str_name_buf is None:
return None
viperlib.snprintf(str_name_buf, 64, ".str.%s", var_name)
# 调用 llvmlite.create_global_string 创建字符串常量全局
str_gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.create_global_string(
pool, mod, str_name_buf, str_val)
if str_gv is None:
return None
# 生成 GEP 初始化器文本
str_len: t.CSizeT = string.strlen(str_val)
init_buf: t.CChar | t.CPtr = pool.alloc(128)
if init_buf is None:
return None
viperlib.snprintf(init_buf, 128,
"getelementptr inbounds ([%d x i8], [%d x i8]* @%s, i32 0, i32 0)",
str_len + 1, str_len + 1, str_name_buf)
return init_buf
# ============================================================
# handle_module_level_var - 模块级变量声明 → 创建 LLVM 全局变量
#
# 当用户已定义 main(无 wrapper main builder)时,模块级
# AnnAssign/Assign 创建全局变量 @var_name 并注册到 SymTab 模块作用域
# 支持整数、列表字面量、字符串字面量初始值
# ============================================================
def handle_module_level_var(self, trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""处理模块级变量声明,创建全局变量"""
pool: memhub.MemBuddy | t.CPtr = trans.Pool
mod: llvmlite.LLVMModule | t.CPtr = trans.Module
# CDefine 注解: 编译期常量,不创建全局变量
# 注册到全局 CDefine 表供 t.CArray[elem_ty, NAME] 解析
k: int = node.kind()
if k == ast.ASTKind.AnnAssign:
aa_cd: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node)
if aa_cd is not None and aa_cd.target is not None:
if aa_cd.target.kind() == ast.ASTKind.Name:
nm_cd: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa_cd.target)
if nm_cd.id is not None:
if HandlesAnnAssign.is_cdefine_annotation(aa_cd.annotation) != 0:
# 浮点/整数自动识别注册(浮点 CDefine 如 vipermath U_M_PI)
HandlesAnnAssign._register_cdefine_from_value(
pool, nm_cd.id, aa_cd.value)
return 0
# _declare_only=1(struct注册模式)时只处理 CDefine,不创建全局变量
# CDefine 已在上面处理并返回,到这里说明不是 CDefine,直接跳过
if trans._declare_only == 1:
return 0
var_name: str = None
var_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
init_val: t.CInt64T = 0
init_kind: int = 0 # 0=none, 1=int, 2=list, 3=str
init_str_val: str = None
init_list_node: ast.List | t.CPtr = None
if k == ast.ASTKind.AnnAssign:
aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node)
if aa is None or aa.target is None:
return 0
if aa.target.kind() != ast.ASTKind.Name:
return 0
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa.target)
var_name = nm.id
# 解析类型
if aa.annotation is not None:
resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
pool, aa.annotation, trans._imported_modules, trans._from_imports, trans)
if resolved is not None:
var_ty = resolved
# 解析初始值(支持整数、列表字面量、字符串字面量)
if aa.value is not None:
val_kind: int = aa.value.kind()
if val_kind == ast.ASTKind.Constant:
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(aa.value)
if cn.const_kind == ast.CONST_INT:
init_val = cn.int_val
init_kind = 1
elif cn.const_kind == ast.CONST_STR:
init_str_val = cn.str_val
init_kind = 3
elif val_kind == ast.ASTKind.List:
init_list_node = (ast.List | t.CPtr)(aa.value)
init_kind = 2
elif k == ast.ASTKind.Assign:
asgn: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(node)
if asgn is None or asgn.targets is None:
return 0
targets: list[ast.AST | t.CPtr] | t.CPtr = asgn.targets
if targets.__len__() < 1:
return 0
t0: ast.AST | t.CPtr = targets.get(0)
if t0 is None or t0.kind() != ast.ASTKind.Name:
return 0
nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(t0)
var_name = nm2.id
if asgn.value is not None:
val_kind2: int = asgn.value.kind()
if val_kind2 == ast.ASTKind.Constant:
cn2: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(asgn.value)
if cn2.const_kind == ast.CONST_INT:
init_val = cn2.int_val
init_kind = 1
elif cn2.const_kind == ast.CONST_STR:
init_str_val = cn2.str_val
init_kind = 3
elif val_kind2 == ast.ASTKind.List:
init_list_node = (ast.List | t.CPtr)(asgn.value)
init_kind = 2
if var_name is None:
return 0
# 检查是否已注册
existing: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var(
trans.SymTab, var_name)
if existing is not None:
return 0
# 创建全局变量 @var_name
# 先确保 var_ty 中的跨模块结构体类型在模块中有 opaque 声明
# 否则 @var_name = global %"sha1.ClassName"* zeroinitializer 会报
# "use of undefined type named 'sha1.ClassName'" 错误
# (如 _mbuddy: memhub.MemManager | t.CPtr → Ptr(Struct("aeb3...MemManager")))
llvmlite.module_ensure_opaque_for_type(mod, pool, var_ty)
gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, var_name, var_ty)
if gv is None:
return 0
llvmlite.module_add_global(mod, gv)
# 设置初始值(有初始值时清除 external linkage,因为 LLVM 22+ 不允许 external global 带初始值)
gv.Linkage = None
if init_kind == 1:
# 整数初始值
init_buf: t.CChar | t.CPtr = pool.alloc(48)
if init_buf is not None:
viperlib.snprintf(init_buf, 48, "%lld", init_val)
gv.Initializer = init_buf
elif init_kind == 2:
# 列表字面量 → 数组初始化器 [N x elem_ty] [elem_ty val0, ...]
arr_init: str = self._build_array_initializer_text(pool, var_ty, init_list_node)
if arr_init is not None:
gv.Initializer = arr_init
else:
gv.Initializer = "zeroinitializer"
elif init_kind == 3:
# 字符串字面量 → 创建字符串常量全局 + GEP 引用
str_init: str = self._build_string_ptr_initializer(pool, mod, var_name, init_str_val)
if str_init is not None:
gv.Initializer = str_init
else:
gv.Initializer = "zeroinitializer"
else:
# 使用 zeroinitializer 而非 "0":指针类型必须用 null/zeroinitializer,
# 整数/聚合类型也兼容 zeroinitializer,避免 "integer constant must have integer type"
gv.Initializer = "zeroinitializer"
# 创建 Value 引用(@var_name, 类型为 var_ty*)
var_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, var_ty)
ref_name: t.CChar | t.CPtr = pool.alloc(64)
if ref_name is not None:
viperlib.snprintf(ref_name, 64, "@%s", var_name)
gv_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, var_ptr_ty, ref_name)
# 注册到模块作用域
if HandlesVar.define_module_var(trans.SymTab, var_name, gv_ref) == 0:
# 设置 AnnotClassName(联合类型如 Logger|t.CPtr 简化为 Ptr(i8) 时,
# 属性访问需要通过 AnnotClassName 回退到类名查找结构体)
if k == ast.ASTKind.AnnAssign:
aa_ml: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node)
if aa_ml is not None and aa_ml.annotation is not None:
cls_nm_ml: str = HandlesType.extract_class_name_from_annotation(
aa_ml.annotation, trans._imported_modules)
if cls_nm_ml is not None:
HandlesVar.set_var_annot_class_name(
trans.SymTab, var_name, cls_nm_ml)
return 1
return 0
# ============================================================
# create_wrapper_main - 创建包装 main 函数
#
# 当用户未定义 main 函数时调用。
# 创建 main() -> i32 函数 → 设置 trans._cur_func/_cur_builder →
# 预扫描 alloca → 翻译子节点 → ret 0
# ============================================================
def create_wrapper_main(self, trans: HT.Translator | t.CPtr,
tree: ast.AST | t.CPtr,
i32_ty: llvmlite.LLVMType | t.CPtr) -> int:
"""创建包装 main 函数并翻译所有顶层语句
Args:
trans: 翻译器(含所有共享状态)
tree: AST 模块节点
i32_ty: i32 LLVMType
Returns:
t.CInt: 新增的变量数
"""
pool: memhub.MemBuddy | t.CPtr = trans.Pool
mod: llvmlite.LLVMModule | t.CPtr = trans.Module
main_func: llvmlite.Function | t.CPtr = llvmlite.create_function(
pool, mod, "main", i32_ty)
if main_func is None:
VLogger.error("CreateFunction main returned NULL", "TR")
return 0
entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(
pool, main_func, "entry")
if entry_blk is None:
VLogger.error("CreateBlock returned NULL", "TR")
return 0
builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, main_func)
if builder is None:
VLogger.error("NewBuilder returned NULL", "TR")
return 0
llvmlite.position_at_end(builder, entry_blk)
# 设置当前翻译上下文(供 Handle 通过 self.Trans._cur_builder 访问)
trans._cur_func = main_func
trans._cur_builder = builder
# 预处理模块级变量:为 AnnAssign/Assign 创建 LLVM 全局变量
# 必须在 pre_scan_allocas 之前执行,否则 PreScan 会创建局部 alloca,
# 导致其他函数通过 SSA 编号引用 wrapper main 的局部变量(无效 IR)
ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children
if ch is not None:
cn_count: t.CSizeT = ch.__len__()
for ci in range(cn_count):
child: ast.AST | t.CPtr = ch.get(ci)
if child is not None:
kd: int = child.kind()
if kd == ast.ASTKind.AnnAssign or kd == ast.ASTKind.Assign:
self.handle_module_level_var(trans, child)
# 预扫描顶层语句:为函数内 AnnAssign 提前创建 alloca
# (模块级变量已在上面注册到模块作用域,PreScan 的 lookup_current 会跳过它们)
if ch is not None:
for ci in range(cn_count):
child: ast.AST | t.CPtr = ch.get(ci)
if child is not None:
HandlesBody.pre_scan_allocas(trans, child)
# 翻译子节点
added_total: int = self.translate_children(trans, tree)
# 返回 0
zero_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0)
llvmlite.build_ret(builder, zero_val)
return added_total
# ============================================================
# global/nonlocal 名称管理(迁移自 HandlesTranslator.vp 模块级函数)
# ============================================================
def add_global_name(self, trans: HT.Translator | t.CPtr, name: str):
"""添加一个 global 变量名"""
if trans is None or name is None:
return
if trans._global_names is None:
return
# 检查是否已存在
if self.is_global_name(trans, name) != 0:
return
if trans._global_name_count >= MAX_GLOBAL_NAMES:
pool_err: memhub.MemBuddy | t.CPtr = trans.Pool
err_buf: str = None
if pool_err is not None:
err_buf = pool_err.alloc(256)
if err_buf is not None:
viperlib.snprintf(err_buf, 256, "global 变量数量超过上限 MAX_GLOBAL_NAMES=%d,请减少 global 声明或增大 MAX_GLOBAL_NAMES", MAX_GLOBAL_NAMES)
VLogger.error(err_buf, "ScopeDecl")
else:
VLogger.error("global 变量数量超过上限,请减少 global 声明或增大 MAX_GLOBAL_NAMES", "ScopeDecl")
return
entry_addr: t.CUInt64T = t.CUInt64T(trans._global_names) + trans._global_name_count * 8
slot_ptr: str | t.CPtr = (t.CVoid | t.CPtr)(entry_addr)
slot_ptr[0] = name
trans._global_name_count += 1
def is_global_name(self, trans: HT.Translator | t.CPtr, name: str) -> int:
"""检查 name 是否在当前函数的 global 集合中"""
if trans is None or name is None or trans._global_names is None:
return 0
for i in range(trans._global_name_count):
entry_addr: t.CUInt64T = t.CUInt64T(trans._global_names) + i * 8
slot_ptr: str | t.CPtr = (t.CVoid | t.CPtr)(entry_addr)
entry: str = slot_ptr[0]
if entry is not None:
if string.strcmp(entry, name) == 0:
return 1
return 0
def add_nonlocal_name(self, trans: HT.Translator | t.CPtr, name: str,
var_ty: llvmlite.LLVMType | t.CPtr = None):
"""添加一个 nonlocal 变量名
Args:
name: nonlocal 变量名
var_ty: 变量的 LLVM 类型(用于 env 指针数组方案的类型恢复,
None 时回退为 i32)
"""
if trans is None or name is None:
return
if trans._nonlocal_names is None:
return
if self.is_nonlocal_name(trans, name) != 0:
# 已存在:更新类型信息(可能在预扫描时类型未知,正式翻译时更新)
# _nonlocal_types 每槽 8 字节,存 LLVMType* 指针。
# 用 str|t.CPtr (i8**) 二级指针存取(与 _nonlocal_names 模式一致),
# [0] 解引用只拷贝 8 字节指针,避免值拷贝 24+ 字节 LLVMType 结构体溢出。
if var_ty is not None and trans._nonlocal_types is not None:
idx: int = self.get_nonlocal_index(trans, name)
if idx >= 0:
ty_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_types) + idx * 8
ty_slot: str | t.CPtr = (t.CVoid | t.CPtr)(ty_addr)
ty_slot[0] = var_ty
return
if trans._nonlocal_name_count >= MAX_GLOBAL_NAMES:
pool_err_nl: memhub.MemBuddy | t.CPtr = trans.Pool
err_buf_nl: str = None
if pool_err_nl is not None:
err_buf_nl = pool_err_nl.alloc(256)
if err_buf_nl is not None:
viperlib.snprintf(err_buf_nl, 256, "nonlocal 变量数量超过上限 MAX_GLOBAL_NAMES=%d,请减少 nonlocal 声明或增大 MAX_GLOBAL_NAMES", MAX_GLOBAL_NAMES)
VLogger.error(err_buf_nl, "ScopeDecl")
else:
VLogger.error("nonlocal 变量数量超过上限,请减少 nonlocal 声明或增大 MAX_GLOBAL_NAMES", "ScopeDecl")
return
entry_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_names) + trans._nonlocal_name_count * 8
slot_ptr: str | t.CPtr = (t.CVoid | t.CPtr)(entry_addr)
slot_ptr[0] = name
# 存储类型信息(用 str|t.CPtr = i8** 二级指针,与 _nonlocal_names 一致)
if trans._nonlocal_types is not None:
ty_addr2: t.CUInt64T = t.CUInt64T(trans._nonlocal_types) + trans._nonlocal_name_count * 8
ty_slot2: str | t.CPtr = (t.CVoid | t.CPtr)(ty_addr2)
# var_ty 为 None 时存入 i32 作为默认类型
stored_ty: llvmlite.LLVMType | t.CPtr = var_ty
if stored_ty is None:
pool: memhub.MemBuddy | t.CPtr = trans.Pool
if pool is not None:
stored_ty = llvmlite.Int32(pool)
ty_slot2[0] = stored_ty
trans._nonlocal_name_count += 1
trans._closure_env_count += 1
def get_nonlocal_type(self, trans: HT.Translator | t.CPtr,
name: str) -> llvmlite.LLVMType | t.CPtr:
"""获取 nonlocal 变量的 LLVM 类型
Returns: 找到的类型指针,找不到返回 None
"""
if trans is None or name is None or trans._nonlocal_types is None:
return None
idx: int = self.get_nonlocal_index(trans, name)
if idx < 0:
return None
ty_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_types) + idx * 8
ty_slot: str | t.CPtr = (t.CVoid | t.CPtr)(ty_addr)
return (llvmlite.LLVMType | t.CPtr)(ty_slot[0])
def is_nonlocal_name(self, trans: HT.Translator | t.CPtr, name: str) -> int:
"""检查 name 是否在当前函数的 nonlocal 集合中"""
if trans is None or name is None or trans._nonlocal_names is None:
return 0
for i in range(trans._nonlocal_name_count):
entry_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_names) + i * 8
slot_ptr: str | t.CPtr = (t.CVoid | t.CPtr)(entry_addr)
entry: str = slot_ptr[0]
if entry is not None:
if string.strcmp(entry, name) == 0:
return 1
return 0
def get_nonlocal_index(self, trans: HT.Translator | t.CPtr, name: str) -> int:
"""获取 nonlocal 变量在 env 中的索引(0-based),找不到返回 -1"""
if trans is None or name is None or trans._nonlocal_names is None:
return -1
for i in range(trans._nonlocal_name_count):
entry_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_names) + i * 8
slot_ptr: str | t.CPtr = (t.CVoid | t.CPtr)(entry_addr)
entry: str = slot_ptr[0]
if entry is not None:
if string.strcmp(entry, name) == 0:
return i
return -1
def clear_scope_names(self, trans: HT.Translator | t.CPtr):
"""清空当前函数的 global/nonlocal 名称集合(进入新函数时调用)"""
if trans is None:
return
trans._global_name_count = 0
trans._nonlocal_name_count = 0
trans._closure_env_count = 0
+392
View File
@@ -0,0 +1,392 @@
import t, c
from stdint import *
import llvmlite
import memhub
import string
import lib.core.Handles.HandlesVar as HandlesVar
# ============================================================
# VarGenMixin - 变量/作用域符号表 Mixin(P6 对象化,wiki/14-oo-refactor.md)
#
# 从 HandlesVar.vp 迁移:模块级函数(init_vars/find_var/find_var_entry/
# lookup_var_entry/set_var_annot_class_name/set_var_ptr_element/add_var/
# _alloca_at_entry/get_or_create_var/_create_scope/init_symbol_table/
# enter_scope/exit_scope/define_var/define_module_var/lookup_var/
# lookup_current/lookup_module_var/is_module_scope/get_or_create_sym)
# → 本类方法。
#
# 迁移原则(与 P1-P5 一致,行为零变化):
# 1. 方法保留原函数签名(含 symtab/vars_ptr 等指针首参——self 是宿主
# Generator,这些函数操作数据结构指针,self 可能少用,但为风格
# 统一仍方法化)
# 2. 函数体原样搬入,本模块内部函数调用改为 self.xxx(...);
# 跨模块调用保留模块前缀(本模块无跨模块调用)
# 3. HandlesVar.vp 原函数保留为"一行委托":本地模块级单例 _g_gen
# (BuildPipeline/main 注入)cast 成 Generator 类型后调本类方法
# 4. VarEntry/Scope/SymbolTable 数据结构类保留在 HandlesVar.vp
# (本类方法签名/函数体经 HandlesVar 前缀引用)
#
# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整,无 vtable 开销)。
# ============================================================
# ============================================================
# 常量(与 HandlesVar 保持一致)
# ============================================================
# 作用域类型常量
SCOPE_MODULE: t.CDefine = 0
SCOPE_FUNCTION: t.CDefine = 1
SCOPE_BLOCK: t.CDefine = 2
# 每个作用域最大变量数
MAX_VARS: t.CDefine = 256
# ============================================================
# VarGenMixin - 变量/作用域符号表 Mixin
# ============================================================
@t.NoVTable
class VarGenMixin:
"""变量/作用域 Mixin(P6 方法化)"""
# 迁移自 HandlesVar 的模块级函数
# ============================================================
# init_vars — 分配并清零 VarEntry 数组
# ============================================================
def init_vars(self, pool: memhub.MemBuddy | t.CPtr) -> HandlesVar.VarEntry | t.CPtr:
"""分配并清零变量表数组"""
size: t.CSizeT = MAX_VARS * HandlesVar.VarEntry.__sizeof__()
vars_ptr: HandlesVar.VarEntry | t.CPtr = pool.alloc(size)
if vars_ptr is not None:
string.memset(vars_ptr, 0, size)
return vars_ptr
# ============================================================
# find_var — 在变量表中按名称查找
# ============================================================
def find_var(self, vars_ptr: HandlesVar.VarEntry | t.CPtr,
var_count: int,
name: str) -> llvmlite.Value | t.CPtr:
"""在变量表中按名称查找"""
if name is None or vars_ptr is None:
return None
entry_size: t.CSizeT = HandlesVar.VarEntry.__sizeof__()
for i in range(var_count):
entry_addr: t.CUInt64T = t.CUInt64T(vars_ptr) + i * entry_size
entry: HandlesVar.VarEntry | t.CPtr = (HandlesVar.VarEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
if entry.Name is not None and entry.Used != 0:
if string.strcmp(entry.Name, name) == 0:
return entry.Alloca
return None
# ============================================================
# find_var_entry — 在变量表中按名称查找,返回 VarEntry(含 AnnotTy)
# ============================================================
def find_var_entry(self, vars_ptr: HandlesVar.VarEntry | t.CPtr,
var_count: int,
name: str) -> HandlesVar.VarEntry | t.CPtr:
"""在变量表中按名称查找,返回 VarEntry 或 None"""
if name is None or vars_ptr is None:
return None
entry_size: t.CSizeT = HandlesVar.VarEntry.__sizeof__()
for i in range(var_count):
entry_addr: t.CUInt64T = t.CUInt64T(vars_ptr) + i * entry_size
entry: HandlesVar.VarEntry | t.CPtr = (HandlesVar.VarEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
if entry.Name is not None and entry.Used != 0:
if string.strcmp(entry.Name, name) == 0:
return entry
return None
# ============================================================
# lookup_var_entry — 从当前作用域逐级向上查找变量,返回 VarEntry
# ============================================================
def lookup_var_entry(self, symtab: HandlesVar.SymbolTable | t.CPtr,
name: str) -> HandlesVar.VarEntry | t.CPtr:
"""从当前作用域逐级向上查找变量,返回 VarEntry 或 None"""
if symtab is None or name is None:
return None
scope: HandlesVar.Scope | t.CPtr = symtab.Current
while scope is not None:
result: HandlesVar.VarEntry | t.CPtr = self.find_var_entry(scope.Vars, scope.VarCount, name)
if result is not None:
return result
scope = scope.Parent
return None
# ============================================================
# set_var_annot_class_name — 设置变量的原始类型注解类名
#
# 在函数参数定义后调用,存储原始类型注解的类名。
# 方法调用检测时,当 alloca 类型是 Ptr(i8)(联合类型简化),
# 通过 AnnotClassName 查找实际结构体类型。
# ============================================================
def set_var_annot_class_name(self, symtab: HandlesVar.SymbolTable | t.CPtr,
name: str,
class_name: str) -> int:
"""设置变量的原始类型注解类名,返回 0=成功 / 1=失败"""
if symtab is None or name is None:
return 1
entry: HandlesVar.VarEntry | t.CPtr = self.lookup_var_entry(symtab, name)
if entry is None:
return 1
entry.AnnotClassName = class_name
return 0
# ============================================================
# set_var_ptr_element — 标记变量为"指针到 str/bytes"类型
#
# 注解为 bytes|t.CPtr 或 str|t.CPtr 的变量,其 alloca 类型是 i8*,
# 但下标访问应按 8 字节步长(i8** 语义),而非 1 字节步长(i8* 语义)。
# 此标志在 HandlesAnnAssign 中根据注解形式设置。
# ============================================================
def set_var_ptr_element(self, symtab: HandlesVar.SymbolTable | t.CPtr,
name: str) -> int:
"""标记变量为 ptr_element 类型,返回 0=成功 / 1=失败"""
if symtab is None or name is None:
return 1
entry: HandlesVar.VarEntry | t.CPtr = self.lookup_var_entry(symtab, name)
if entry is None:
return 1
entry.IsPtrElement = 1
return 0
# ============================================================
# add_var — 添加变量到变量表
# ============================================================
def add_var(self, vars_ptr: HandlesVar.VarEntry | t.CPtr,
var_count: int,
name: str,
alloca: llvmlite.Value | t.CPtr) -> int:
"""添加变量到变量表"""
if name is None or alloca is None or vars_ptr is None:
return 1
if var_count >= MAX_VARS:
return 1
entry_size: t.CSizeT = HandlesVar.VarEntry.__sizeof__()
entry_addr: t.CUInt64T = t.CUInt64T(vars_ptr) + var_count * entry_size
entry: HandlesVar.VarEntry | t.CPtr = (HandlesVar.VarEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
entry.Name = name
entry.Alloca = alloca
entry.Used = 1
return 0
# ============================================================
# _alloca_at_entry - 在函数入口块生成 alloca(确保支配性)
#
# LLVM IR 要求指令支配所有使用点。如果 alloca 在条件分支内生成,
# 但在其他分支使用,会违反支配性(Instruction does not dominate all uses)。
# 标准做法:所有 alloca 在函数入口块生成。
#
# 临时切换 builder.CurBlock 到入口块,生成 alloca,然后恢复。
# ============================================================
def _alloca_at_entry(self, builder: llvmlite.IRBuilder | t.CPtr,
ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr:
"""在函数入口块生成 alloca,返回 alloca 值
使用 llvmlite.build_alloca_at_entry 在入口块终止指令之前插入 alloca,
确保所有 alloca 在入口块,避免支配性违规。
"""
if builder is None or ty is None:
return None
return llvmlite.build_alloca_at_entry(builder, ty)
# ============================================================
# get_or_create_var — 查找或创建变量 alloca(旧版兼容)
# ============================================================
def get_or_create_var(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
vars_ptr: HandlesVar.VarEntry | t.CPtr,
var_count: int,
name: str,
ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr:
"""查找或创建变量 alloca"""
existing: llvmlite.Value | t.CPtr = self.find_var(vars_ptr, var_count, name)
if existing is not None:
return existing
alloca: llvmlite.Value | t.CPtr = self._alloca_at_entry(builder, ty)
if alloca is None:
return None
if self.add_var(vars_ptr, var_count, name, alloca) != 0:
return None
return alloca
# ============================================================
# _create_scope — 创建新作用域节点(内部辅助函数)
# ============================================================
def _create_scope(self, pool: memhub.MemBuddy | t.CPtr,
parent: HandlesVar.Scope | t.CPtr,
kind: int) -> HandlesVar.Scope | t.CPtr:
"""创建并初始化作用域节点"""
scope: HandlesVar.Scope | t.CPtr = pool.alloc(HandlesVar.Scope.__sizeof__())
if scope is None:
return None
string.memset(scope, 0, HandlesVar.Scope.__sizeof__())
scope.Parent = parent
scope.Vars = self.init_vars(pool)
scope.VarCount = 0
scope.Kind = kind
if scope.Vars is None:
return None
return scope
# ============================================================
# init_symbol_table — 创建符号表(含模块级根作用域)
# ============================================================
def init_symbol_table(self, pool: memhub.MemBuddy | t.CPtr) -> HandlesVar.SymbolTable | t.CPtr:
"""创建并初始化符号表,包含模块级根作用域"""
if pool is None:
return None
symtab: HandlesVar.SymbolTable | t.CPtr = pool.alloc(HandlesVar.SymbolTable.__sizeof__())
if symtab is None:
return None
string.memset(symtab, 0, HandlesVar.SymbolTable.__sizeof__())
symtab.Pool = pool
# 创建根作用域(模块级)
root: HandlesVar.Scope | t.CPtr = self._create_scope(pool, None, SCOPE_MODULE)
if root is None:
return None
symtab.Root = root
symtab.Current = root
return symtab
# ============================================================
# enter_scope — 进入新作用域
# ============================================================
def enter_scope(self, symtab: HandlesVar.SymbolTable | t.CPtr,
kind: int) -> HandlesVar.Scope | t.CPtr:
"""进入新作用域,返回新创建的作用域"""
if symtab is None:
return None
pool: memhub.MemBuddy | t.CPtr = symtab.Pool
scope: HandlesVar.Scope | t.CPtr = self._create_scope(pool, symtab.Current, kind)
if scope is None:
return None
symtab.Current = scope
return scope
# ============================================================
# exit_scope — 退出当前作用域
# ============================================================
def exit_scope(self, symtab: HandlesVar.SymbolTable | t.CPtr):
"""退出当前作用域,恢复到父作用域"""
if symtab is not None and symtab.Current is not None:
symtab.Current = symtab.Current.Parent
# ============================================================
# define_var — 在当前作用域定义变量
# ============================================================
def define_var(self, symtab: HandlesVar.SymbolTable | t.CPtr,
name: str,
alloca: llvmlite.Value | t.CPtr) -> int:
"""在当前作用域定义变量,返回 0 成功"""
if symtab is None or name is None or alloca is None:
return 1
scope: HandlesVar.Scope | t.CPtr = symtab.Current
if scope is None:
return 1
ret: int = self.add_var(scope.Vars, scope.VarCount, name, alloca)
if ret == 0:
scope.VarCount = scope.VarCount + 1
return ret
# ============================================================
# define_module_var — 在模块作用域定义变量
# ============================================================
def define_module_var(self, symtab: HandlesVar.SymbolTable | t.CPtr,
name: str,
alloca: llvmlite.Value | t.CPtr) -> int:
"""在模块作用域定义变量,返回 0 成功"""
if symtab is None or name is None or alloca is None:
return 1
scope: HandlesVar.Scope | t.CPtr = symtab.Root
if scope is None:
return 1
ret: int = self.add_var(scope.Vars, scope.VarCount, name, alloca)
if ret == 0:
scope.VarCount = scope.VarCount + 1
return ret
# ============================================================
# lookup_var — 从当前作用域逐级向上查找变量
# ============================================================
def lookup_var(self, symtab: HandlesVar.SymbolTable | t.CPtr,
name: str) -> llvmlite.Value | t.CPtr:
"""从当前作用域逐级向上查找变量,返回 alloca 或 None"""
if symtab is None or name is None:
return None
scope: HandlesVar.Scope | t.CPtr = symtab.Current
while scope is not None:
result: llvmlite.Value | t.CPtr = self.find_var(
scope.Vars, scope.VarCount, name)
if result is not None:
return result
scope = scope.Parent
return None
# ============================================================
# lookup_current — 仅在当前作用域查找变量
# ============================================================
def lookup_current(self, symtab: HandlesVar.SymbolTable | t.CPtr,
name: str) -> llvmlite.Value | t.CPtr:
"""仅在当前作用域查找变量"""
if symtab is None or name is None:
return None
scope: HandlesVar.Scope | t.CPtr = symtab.Current
if scope is None:
return None
return self.find_var(scope.Vars, scope.VarCount, name)
# ============================================================
# lookup_module_var — 在模块作用域查找变量
# ============================================================
def lookup_module_var(self, symtab: HandlesVar.SymbolTable | t.CPtr,
name: str) -> llvmlite.Value | t.CPtr:
"""在模块作用域查找变量"""
if symtab is None or name is None:
return None
scope: HandlesVar.Scope | t.CPtr = symtab.Root
if scope is None:
return None
return self.find_var(scope.Vars, scope.VarCount, name)
# ============================================================
# is_module_scope - 判断当前是否在模块级作用域
#
# 用于区分模块级代码和函数内代码:
# - 模块级代码:AnnAssign 应修改模块级变量(Python 语义)
# - 函数内代码:无 global 声明时 AnnAssign 应创建局部变量(Python 语义)
# ============================================================
def is_module_scope(self, symtab: HandlesVar.SymbolTable | t.CPtr) -> int:
"""判断当前作用域是否为模块级作用域(Current == Root)
Returns: 1=模块级作用域, 0=函数内作用域
"""
if symtab is None:
return 0
if symtab.Root is None or symtab.Current is None:
return 0
# 比较指针:Current 与 Root 相同则为模块级
if t.CUInt64T(symtab.Current) == t.CUInt64T(symtab.Root):
return 1
return 0
# ============================================================
# get_or_create_sym — 查找或创建变量(在当前作用域)
# ============================================================
def get_or_create_sym(self, symtab: HandlesVar.SymbolTable | t.CPtr,
pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
name: str,
ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr:
"""查找或创建变量 alloca(在当前作用域)"""
existing: llvmlite.Value | t.CPtr = self.lookup_current(symtab, name)
if existing is not None:
return existing
alloca: llvmlite.Value | t.CPtr = self._alloca_at_entry(builder, ty)
if alloca is None:
return None
self.define_var(symtab, name, alloca)
return alloca
+61 -290
View File
@@ -19,6 +19,25 @@ import lib.core.Handles.HandlesStruct as HandlesStruct
import lib.core.VLogger as VLogger
# ============================================================
# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式)
#
# 由 BuildPipeline/main 在 gen 创建后调用 set_global_gen 注入。
# P6 对象化重构:模块级无状态函数已迁移为 lib.core.Gen.AssignGenMixin
# 的方法(_g_recover_found 全局迁入 gen 字段 RecoverFound),本模块保留
# 同名模块级函数作为"一行委托":延迟 import Gen 取全局单例
# (BuildPipeline/main 创建后 set_global_gen 注册),再调用 gen 的
# 对应方法。签名与旧函数完全一致,调用方零改动。
# ============================================================
_g_gen: t.CVoid | t.CPtr = None
def set_global_gen(gen: t.CVoid | t.CPtr) -> None:
"""注入全局 gen 单例(BuildPipeline/main 调用)"""
global _g_gen
_g_gen = gen
# ============================================================
# HandlesAnnAssign - AnnAssign 语句处理(Mixin 继承模式)
# ============================================================
@@ -32,21 +51,11 @@ import lib.core.VLogger as VLogger
# 2. BinOp(... | Attribute(Name('t'), 'CDefine'))(联合注解)
# ============================================================
def is_cdefine_annotation(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 is_cdefine_annotation(bop.left) != 0:
return 1
if is_cdefine_annotation(bop.right) != 0:
return 1
"""检测注解是否为 t.CDefine,返回 1 表示是,0 表示否(委托到 gen.is_cdefine_annotation)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.is_cdefine_annotation(annot)
return 0
@@ -61,66 +70,11 @@ def is_cdefine_annotation(annot: ast.AST | t.CPtr) -> int:
# 5. UnaryOp(USub/UAdd/Invert) — 如 -11
# ============================================================
def extract_cdefine_int_value(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 = extract_cdefine_int_value(bop.left)
right_val: int = 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 = 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 = 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
"""从值节点提取整数常量(支持 Constant/BinOp/Name/Call/UnaryOp,委托到 gen.extract_cdefine_int_value)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.extract_cdefine_int_value(val_node)
return 0
@@ -133,47 +87,11 @@ def extract_cdefine_int_value(val_node: ast.AST | t.CPtr) -> int:
# ============================================================
def _register_cdefine_from_value(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 _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 = extract_cdefine_int_value(val_node)
HandlesType.register_cdefine_constant(pool, name, val_fp)
"""注册 CDefine 常量(浮点字面量 → register_cdefine_double,否则整数,委托到 gen._register_cdefine_from_value)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
g._register_cdefine_from_value(pool, name, val_node)
# ============================================================
@@ -183,113 +101,29 @@ def _register_cdefine_from_value(pool: memhub.MemBuddy | t.CPtr,
# (MemBuddy 内存冲突),导致注册的浮点 CDefine 值错误(llc ret i32 0)。
# 本函数直接读源文件找 "NAME: t.CDefine = value" 行,atof 解析 value——
# 源文件文本不受 pool 影响,是最可靠的恢复路径。
# 原模块级 _g_recover_found 全局已迁移为 gen 字段(RecoverFound)。
# ============================================================
_g_recover_found: int = 0
def _recover_found() -> int:
"""检查最近一次 _recover_cdefine_float 是否成功"""
return _g_recover_found
"""检查最近一次 _recover_cdefine_float 是否成功(委托到 gen._recover_found)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g._recover_found()
return 0
def _recover_cdefine_float(name: str, out: t.CDouble | t.CPtr) -> int:
"""从当前模块源文件恢复浮点 CDefine 值,写入 out[0],成功返回 1
用输出参数传递 double,避免 TPV 跨模块 double 返回值传递 bug。
(委托到 gen._recover_cdefine_float)
"""
global _g_recover_found
_g_recover_found = 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:
_g_recover_found = 1
return 1
return 0
stdlib.free(buf)
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g._recover_cdefine_float(name, out)
return 0
@@ -299,26 +133,11 @@ def _recover_cdefine_float(name: str, out: t.CDouble | t.CPtr) -> int:
# 支持 BinOp(BitOr) 递归,同时检查 Attribute.attr 和 Name.id。
# ============================================================
def _annotation_contains_name(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 _annotation_contains_name(bop.left, name) != 0:
return 1
if _annotation_contains_name(bop.right, name) != 0:
return 1
"""递归检查注解中是否包含指定名称,返回 1=包含 / 0=不包含(委托到 gen._annotation_contains_name)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g._annotation_contains_name(annot, name)
return 0
@@ -335,19 +154,11 @@ def _annotation_contains_name(annot: ast.AST | t.CPtr, name: str) -> int:
# 注: 注解中的 "|" 是"和"的意思(组合类型),非右值中的位或运算
# ============================================================
def _is_ptr_element_annotation(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 _annotation_contains_name(annot, "str") != 0:
return 1
if _annotation_contains_name(annot, "bytes") != 0:
return 1
"""检查注解是否为 bytes|t.CPtr 或 str|t.CPtr 形式(委托到 gen._is_ptr_element_annotation)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g._is_ptr_element_annotation(annot)
return 0
@@ -374,51 +185,11 @@ def _init_global_array_from_list(builder: llvmlite.IRBuilder | 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
"""从列表字面量初始化全局数组,为每个元素生成 GEP + store(委托到 gen._init_global_array_from_list)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g._init_global_array_from_list(builder, pool, mod, array_alloca, list_node, trans)
return 0
+23 -73
View File
@@ -14,6 +14,24 @@ import lib.core.Handles.HandlesExpr as HandlesExpr
import lib.core.Handles.HandlesNonlocal as HandlesNonlocal
# ============================================================
# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式)
#
# 由 BuildPipeline/main 在 gen 创建后调用 set_global_gen 注入。
# P6 对象化重构:模块级无状态函数已迁移为 lib.core.Gen.AssignGenMixin
# 的方法,本模块保留同名模块级函数作为"一行委托":延迟 import Gen
# 取全局单例(BuildPipeline/main 创建后 set_global_gen 注册),再调用
# gen 的对应方法。签名与旧函数完全一致,调用方零改动。
# ============================================================
_g_gen: t.CVoid | t.CPtr = None
def set_global_gen(gen: t.CVoid | t.CPtr) -> None:
"""注入全局 gen 单例(BuildPipeline/main 调用)"""
global _g_gen
_g_gen = gen
# ============================================================
# HandlesAugAssign - 增强赋值语句处理(Mixin 继承模式)
#
@@ -253,79 +271,11 @@ def _apply_aug_op(pool: memhub.MemBuddy | 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)
"""应用增强赋值的二元运算(浮点 + 指针算术 + 整数运算,委托到 gen._apply_aug_op)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g._apply_aug_op(pool, builder, op, lhs, rhs, node, trans, lhs_node)
return None
+74 -195
View File
@@ -15,63 +15,44 @@ import lib.core.Handles.HandlesVar as HandlesVar
# ============================================================
# HandlesBody - 语句分派(trans 单参模式,全方法调用)
# HandlesBody - 语句分派(P6 对象化后的委托层)
#
# 全部模块级函数已迁移为 lib.core.Gen.StmtGenMixin 的方法,本模块
# 保留同名模块级函数作为"一行委托":延迟 import Gen 取全局单例
# (BuildPipeline/main 创建后 set_global_gen 注册),再调用 gen 的
# 对应方法。签名与旧函数完全一致,调用方零改动。
#
# 所有语句类型通过 trans.XxxH.Handle(node) 分派到对应 Handle。
# 对应 TransPyC BodyHandle.HandleBodyLlvm 的 isinstance 分派。
# ============================================================
# ============================================================
# 全局 gen 单例(模块级镜像,同 HandlesStruct 模式)
#
# 由 BuildPipeline/main 在 gen 创建后调用 set_global_gen 注入。
# 委托函数用本地 _g_gen(cast 成 Generator 类型)调
# StmtGenMixin 方法,避免函数体 import 包模块与类/模块名歧义。
# ============================================================
_g_gen: t.CVoid | t.CPtr = None
def set_global_gen(gen: t.CVoid | t.CPtr) -> None:
"""注入全局 gen 单例(BuildPipeline/main 调用)"""
global _g_gen
_g_gen = gen
# ============================================================
# 语句翻译分派
# ============================================================
def translate_stmt(trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""翻译单条语句,返回新增的变量数"""
if node is None:
return 0
k: int = node.kind()
if k == ast.ASTKind.Expr:
return translate_expr_stmt(trans, node)
elif k == ast.ASTKind.Assign:
return trans.AssignH.Handle(node)
elif k == ast.ASTKind.AnnAssign:
return trans.AnnAssignH.Handle(node)
elif k == ast.ASTKind.FunctionDef:
# 嵌套函数定义:提升为顶层函数 + 创建闭包
return HandlesFunctions.translate_nested_function_def(trans, node)
elif k == ast.ASTKind.Return:
return trans.ReturnH.Handle(node)
elif k == ast.ASTKind.If:
return trans.IfH.Handle(node)
elif k == ast.ASTKind.While:
return trans.WhileH.Handle(node)
elif k == ast.ASTKind.AugAssign:
return trans.AugAssignH.Handle(node)
elif k == ast.ASTKind.For:
return trans.ForH.Handle(node)
elif k == ast.ASTKind.ClassDef:
return HandlesClassDef.translate_class_def(trans, node)
elif k == ast.ASTKind.Import:
return trans.ImportsH.HandleImport(node)
elif k == ast.ASTKind.ImportFrom:
trans.ImportsH.HandleImportFromModule(node)
return trans.ImportsH.HandleImportFromNames(node)
elif k == ast.ASTKind.Global:
return translate_global(trans, node)
elif k == ast.ASTKind.Nonlocal:
return translate_nonlocal(trans, node)
elif k == ast.ASTKind.Pass:
return 0
elif k == ast.ASTKind.Break:
return translate_break(trans)
elif k == ast.ASTKind.Continue:
return translate_continue(trans)
elif k == ast.ASTKind.Match:
return trans.MatchH.Handle(node)
elif k == ast.ASTKind.Delete:
return translate_delete(trans, node)
"""翻译单条语句,返回新增的变量数(委托到 gen.translate_stmt)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.translate_stmt(trans, node)
return 0
@@ -83,28 +64,11 @@ def translate_stmt(trans: HT.Translator | t.CPtr,
# ============================================================
def translate_delete(trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""翻译 del 语句,返回 0"""
if trans is None or node is None:
return 0
dnode: ast.Delete | t.CPtr = (ast.Delete | t.CPtr)(node)
if dnode is None or dnode.targets is None:
return 0
pool: memhub.MemBuddy | t.CPtr = trans.Pool
mod: llvmlite.LLVMModule | t.CPtr = trans.Module
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
if pool is None or mod is None or builder is None:
return 0
tn: t.CSizeT = dnode.targets.__len__()
for ti in range(tn):
tgt: ast.AST | t.CPtr = dnode.targets.get(ti)
if tgt is None:
continue
# del obj.attr → property deleter
if tgt.kind() == ast.ASTKind.Attribute:
del_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(tgt)
if del_at is not None:
HandlesExprCall._try_property_deleter(
pool, builder, mod, del_at, trans)
"""翻译 del 语句,返回 0(委托到 gen.translate_delete)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.translate_delete(trans, node)
return 0
@@ -115,20 +79,11 @@ def translate_delete(trans: HT.Translator | t.CPtr,
# ============================================================
def translate_global(trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""翻译 global 语句:记录 global 变量名"""
gn: ast.Global | t.CPtr = (ast.Global | t.CPtr)(node)
if gn is None:
return 0
names: list[ast.AST | t.CPtr] | t.CPtr = gn.names
if names is None:
return 0
n: t.CSizeT = names.__len__()
for i in range(n):
nm_node: ast.AST | t.CPtr = names.get(i)
if nm_node is not None and nm_node.kind() == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(nm_node)
if nm.id is not None:
HT.add_global_name(trans, nm.id)
"""翻译 global 语句:记录 global 变量名(委托到 gen.translate_global)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.translate_global(trans, node)
return 0
@@ -139,38 +94,14 @@ def translate_global(trans: HT.Translator | t.CPtr,
# ============================================================
def translate_nonlocal(trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""翻译 nonlocal 语句:记录 nonlocal 变量名及其类型
"""翻译 nonlocal 语句:记录 nonlocal 变量名及其类型(委托到 gen.translate_nonlocal)
类型信息通过查找父作用域的 alloca 获取(用于 env 指针数组方案的类型恢复)。
"""
nl: ast.Nonlocal | t.CPtr = (ast.Nonlocal | t.CPtr)(node)
if nl is None:
return 0
names: list[ast.AST | t.CPtr] | t.CPtr = nl.names
if names is None:
return 0
n: t.CSizeT = names.__len__()
for i in range(n):
nm_node: ast.AST | t.CPtr = names.get(i)
if nm_node is not None and nm_node.kind() == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(nm_node)
if nm.id is not None:
# 查找父作用域中的变量 alloca,获取类型信息
var_ty: llvmlite.LLVMType | t.CPtr = None
var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
trans.SymTab, nm.id)
if var_alloca is not None and var_alloca.Ty is not None:
var_ty = var_alloca.Ty.Pointee
# Void 类型视为无效(Pointee 访问异常时可能返回 Void),
# 设为 None 让 add_nonlocal_name 回退为 i32,避免生成
# "bitcast ... to void*" / "load void, void*" 非法 IR
if var_ty is not None:
match var_ty:
case llvmlite.LLVMType.Void():
var_ty = None
case _:
pass
HT.add_nonlocal_name(trans, nm.id, var_ty)
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.translate_nonlocal(trans, node)
return 0
@@ -179,34 +110,11 @@ def translate_nonlocal(trans: HT.Translator | t.CPtr,
# ============================================================
def translate_expr_stmt(trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""翻译表达式语句(printf 调用等)"""
ex: ast.Expr | t.CPtr = (ast.Expr | t.CPtr)(node)
if ex is None:
return 0
call_node: ast.AST | t.CPtr = ex.value
if call_node is None:
return 0
ck: int = call_node.kind()
if ck != ast.ASTKind.Call:
return 0
cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(call_node)
func_node: ast.AST | t.CPtr = cl.func
if func_node is None:
return 0
func_name: str = HandlesExpr.get_func_name(func_node)
if func_name is None:
return 0
# printf / print 走特殊路径(print 是类型感知格式化,不映射到 printf)
if string.strcmp(func_name, "printf") == 0:
trans.ExprCallH.HandlePrintfCall(cl)
elif string.strcmp(func_name, "print") == 0:
trans.ExprCallH.HandlePrintCall(cl)
else:
# 通用函数调用(返回值丢弃)
trans.ExprCallH.HandleCall(call_node)
"""翻译表达式语句(printf 调用等)(委托到 gen.translate_expr_stmt)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.translate_expr_stmt(trans, node)
return 0
@@ -215,13 +123,15 @@ def translate_expr_stmt(trans: HT.Translator | t.CPtr,
# ============================================================
def pre_scan_allocas(trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""预扫描语句中的 AnnAssign,提前创建 alloca
"""预扫描语句中的 AnnAssign,提前创建 alloca(委托到 gen.pre_scan_allocas)
返回新增的变量数
"""
if node is None:
return 0
return trans.AnnAssignH.PreScan(node)
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.pre_scan_allocas(trans, node)
return 0
# ============================================================
@@ -233,14 +143,11 @@ def pre_scan_allocas(trans: HT.Translator | t.CPtr,
# ============================================================
def pre_scan_scope_decls(trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""预扫描 Global/Nonlocal 声明,提前注册作用域名称"""
if node is None:
return 0
k: int = node.kind()
if k == ast.ASTKind.Global:
return translate_global(trans, node)
if k == ast.ASTKind.Nonlocal:
return translate_nonlocal(trans, node)
"""预扫描 Global/Nonlocal 声明,提前注册作用域名称(委托到 gen.pre_scan_scope_decls)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.pre_scan_scope_decls(trans, node)
return 0
@@ -248,26 +155,11 @@ def pre_scan_scope_decls(trans: HT.Translator | t.CPtr,
# 翻译 break 语句
# ============================================================
def translate_break(trans: HT.Translator | t.CPtr) -> int:
"""翻译 break 语句:跳转到循环 end 块"""
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
func: llvmlite.Function | t.CPtr = trans._cur_func
pool: memhub.MemBuddy | t.CPtr = trans.Pool
if builder is None or func is None:
return 0
# 发射 br 到 break 目标
if trans._break_bb is not None:
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
llvmlite.build_br(builder, trans._break_bb)
# 创建死代码 BB,用于后续语句(break 后面的代码不可达)
cnt: int = trans._label_counter
trans._label_counter = cnt + 1
name_buf: t.CChar | t.CPtr = pool.alloc(32)
viperlib.snprintf(name_buf, 32, "dead.%d", cnt)
dead_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
llvmlite.position_at_end(builder, dead_bb)
"""翻译 break 语句:跳转到循环 end 块(委托到 gen.translate_break)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.translate_break(trans)
return 0
@@ -275,26 +167,11 @@ def translate_break(trans: HT.Translator | t.CPtr) -> int:
# 翻译 continue 语句
# ============================================================
def translate_continue(trans: HT.Translator | t.CPtr) -> int:
"""翻译 continue 语句:跳转到循环 cond/incr 块"""
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
func: llvmlite.Function | t.CPtr = trans._cur_func
pool: memhub.MemBuddy | t.CPtr = trans.Pool
if builder is None or func is None:
return 0
# 发射 br 到 continue 目标
if trans._continue_bb is not None:
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
llvmlite.build_br(builder, trans._continue_bb)
# 创建死代码 BB,用于后续语句
cnt: int = trans._label_counter
trans._label_counter = cnt + 1
name_buf: t.CChar | t.CPtr = pool.alloc(32)
viperlib.snprintf(name_buf, 32, "dead.%d", cnt)
dead_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
llvmlite.position_at_end(builder, dead_bb)
"""翻译 continue 语句:跳转到循环 cond/incr 块(委托到 gen.translate_continue)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.translate_continue(trans)
return 0
@@ -302,7 +179,9 @@ def translate_continue(trans: HT.Translator | t.CPtr) -> int:
# 获取语句类型名(调试用)
# ============================================================
def get_stmt_kind_name(node: ast.AST | t.CPtr) -> str:
"""获取语句类型名"""
if node is None:
return None
return node.type_name()
"""获取语句类型名(委托到 gen.get_stmt_kind_name)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.get_stmt_kind_name(node)
return None
+71 -125
View File
@@ -9,8 +9,16 @@ import lib.core.VLogger as VLogger
# ============================================================
# HandlesEnum - 枚举类型注册和成员查找
# HandlesEnum - 枚举类型注册和成员查找(P6 对象化后的委托层)
#
# 全部模块级函数已迁移为 lib.core.Gen.StmtGenMixin 的方法
# (模块级全局 _enum_table/_enum_count → gen 实例字段
# EnumTable/EnumCount),本模块保留同名模块级函数作为"一行委托":
# 延迟 import Gen 取全局单例(BuildPipeline/main 创建后
# set_global_gen 注册),再调用 gen 的对应方法。签名与旧函数
# 完全一致,调用方零改动。
#
# EnumEntry/EnumMember 类型保留在本模块(gen 字段类型引用)。
# 管理 t.CEnum 派生类的成员信息:
# - 枚举名 → EnumEntry(基准类型 + 成员表)
# - 成员名 → EnumMember(值、类型)
@@ -44,53 +52,55 @@ class EnumEntry:
# ============================================================
# 全局注册表(静态分配)
# 全局 gen 单例(模块级镜像,同 HandlesStruct 模式)
#
# 由 BuildPipeline/main 在 gen 创建后调用 set_global_gen 注入。
# 委托函数用本地 _g_gen(cast 成 Generator 类型)调
# StmtGenMixin 方法,避免函数体 import 包模块与类/模块名歧义。
# ============================================================
_enum_table: EnumEntry | t.CPtr = None
_enum_count: int = 0
_g_gen: t.CVoid | t.CPtr = None
def set_global_gen(gen: t.CVoid | t.CPtr) -> None:
"""注入全局 gen 单例(BuildPipeline/main 调用)"""
global _g_gen
_g_gen = gen
# ============================================================
# init_enum_table — 初始化枚举注册表
# ============================================================
def init_enum_table(pool: memhub.MemBuddy | t.CPtr) -> int:
"""初始化枚举注册表,返回 1 成功"""
global _enum_table, _enum_count
if _enum_table is not None:
return 1
entry_size: t.CSizeT = EnumEntry.__sizeof__()
_enum_table = pool.alloc(entry_size * ENUM_MAX)
if _enum_table is None:
return 0
string.memset(_enum_table, 0, entry_size * ENUM_MAX)
_enum_count = 0
return 1
"""初始化枚举注册表,返回 1 成功(委托到 gen.init_enum_table)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.init_enum_table(pool)
return 0
# ============================================================
# _get_enum_entry — 获取第 i 个 EnumEntry 槽位
# ============================================================
def _get_enum_entry(i: int) -> EnumEntry | t.CPtr:
"""获取第 i 个枚举条目"""
if _enum_table is None or i < 0 or i >= ENUM_MAX:
return None
entry_size: t.CSizeT = EnumEntry.__sizeof__()
addr: t.CUInt64T = t.CUInt64T(_enum_table) + i * entry_size
return (EnumEntry | t.CPtr)(t.CVoid(addr, t.CPtr))
"""获取第 i 个枚举条目(委托到 gen._get_enum_entry)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g._get_enum_entry(i)
return None
# ============================================================
# _get_enum_member — 获取枚举中第 i 个 EnumMember 槽位
# ============================================================
def _get_enum_member(enum_entry: EnumEntry | t.CPtr, i: int) -> EnumMember | t.CPtr:
"""获取枚举中第 i 个成员条目"""
if enum_entry is None or i < 0 or i >= ENUM_MEMBER_MAX:
return None
member_size: t.CSizeT = EnumMember.__sizeof__()
addr: t.CUInt64T = t.CUInt64T(enum_entry.Members) + i * member_size
return (EnumMember | t.CPtr)(t.CVoid(addr, t.CPtr))
"""获取枚举中第 i 个成员条目(委托到 gen._get_enum_member)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g._get_enum_member(enum_entry, i)
return None
# ============================================================
@@ -101,46 +111,12 @@ def _get_enum_member(enum_entry: EnumEntry | t.CPtr, i: int) -> EnumMember | t.C
def register_enum(pool: memhub.MemBuddy | t.CPtr,
name: str,
base_ty: llvmlite.LLVMType | t.CPtr) -> EnumEntry | t.CPtr:
global _enum_count
"""注册枚举类型,返回 EnumEntry 指针"""
if init_enum_table(pool) == 0:
return None
# 检查是否已注册
existing: EnumEntry | t.CPtr = find_enum(name)
if existing is not None:
return existing
if _enum_count >= ENUM_MAX:
fb_et: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_et is not None:
viperlib.snprintf(fb_et, 1024, "table full, cannot register %s", name)
VLogger.error(fb_et, "ENUM")
return None
entry: EnumEntry | t.CPtr = _get_enum_entry(_enum_count)
if entry is None:
return None
# 分配成员数组
member_size: t.CSizeT = EnumMember.__sizeof__()
entry.Members = pool.alloc(member_size * ENUM_MEMBER_MAX)
if entry.Members is None:
return None
string.memset(entry.Members, 0, member_size * ENUM_MEMBER_MAX)
# 复制类名
name_len: t.CSizeT = string.strlen(name)
name_buf: t.CChar | t.CPtr = pool.alloc(name_len + 1)
if name_buf is not None:
string.strcpy(name_buf, name)
entry.Name = name_buf
entry.BaseTy = base_ty
entry.MemberCount = 0
_enum_count += 1
return entry
"""注册枚举类型,返回 EnumEntry 指针(委托到 gen.register_enum)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.register_enum(pool, name, base_ty)
return None
# ============================================================
@@ -151,48 +127,23 @@ def add_enum_member(pool: memhub.MemBuddy | t.CPtr,
member_name: str,
member_val: t.CInt64T,
member_ty: llvmlite.LLVMType | t.CPtr) -> int:
"""向枚举添加成员,返回成员索引(-1 失败)"""
if enum_entry is None or member_name is None or member_ty is None:
return -1
if enum_entry.MemberCount >= ENUM_MEMBER_MAX:
fb_em: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_em is not None:
viperlib.snprintf(fb_em, 1024, "member table full for %s", enum_entry.Name)
VLogger.error(fb_em, "ENUM")
return -1
idx: int = enum_entry.MemberCount
me: EnumMember | t.CPtr = _get_enum_member(enum_entry, idx)
if me is None:
return -1
# 复制成员名
name_len: t.CSizeT = string.strlen(member_name)
name_buf: t.CChar | t.CPtr = pool.alloc(name_len + 1)
if name_buf is not None:
string.strcpy(name_buf, member_name)
me.Name = name_buf
me.Value = member_val
me.Ty = member_ty
enum_entry.MemberCount = idx + 1
return idx
"""向枚举添加成员,返回成员索引(-1 失败,委托到 gen.add_enum_member)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.add_enum_member(pool, enum_entry, member_name, member_val, member_ty)
return 0
# ============================================================
# find_enum — 按枚举类名查找
# ============================================================
def find_enum(name: str) -> EnumEntry | t.CPtr:
"""按枚举类名查找,返回 EnumEntry 或 None"""
if name is None or _enum_table is None:
return None
for i in range(_enum_count):
entry: EnumEntry | t.CPtr = _get_enum_entry(i)
if entry is not None and entry.Name is not None:
if string.strcmp(entry.Name, name) == 0:
return entry
"""按枚举类名查找,返回 EnumEntry 或 None(委托到 gen.find_enum)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.find_enum(name)
return None
@@ -201,17 +152,11 @@ def find_enum(name: str) -> EnumEntry | t.CPtr:
# ============================================================
def lookup_enum_member(enum_name: str,
member_name: str) -> EnumMember | t.CPtr:
"""按枚举类名和成员名查找,返回 EnumMember 或 None"""
if enum_name is None or member_name is None:
return None
entry: EnumEntry | t.CPtr = find_enum(enum_name)
if entry is None:
return None
for mi in range(entry.MemberCount):
me: EnumMember | t.CPtr = _get_enum_member(entry, mi)
if me is not None and me.Name is not None:
if string.strcmp(me.Name, member_name) == 0:
return me
"""按枚举类名和成员名查找,返回 EnumMember 或 None(委托到 gen.lookup_enum_member)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.lookup_enum_member(enum_name, member_name)
return None
@@ -219,11 +164,11 @@ def lookup_enum_member(enum_name: str,
# is_enum_class — 检查类名是否为已注册枚举
# ============================================================
def is_enum_class(name: str) -> int:
"""检查类名是否为已注册枚举,返回 1=是 / 0=否"""
if name is None:
return 0
if find_enum(name) is not None:
return 1
"""检查类名是否为已注册枚举,返回 1=是 / 0=否(委托到 gen.is_enum_class)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.is_enum_class(name)
return 0
@@ -231,8 +176,9 @@ def is_enum_class(name: str) -> int:
# get_enum_base_type — 按枚举类名获取基准类型
# ============================================================
def get_enum_base_type(enum_name: str) -> llvmlite.LLVMType | t.CPtr:
"""按枚举类名获取基准类型"""
entry: EnumEntry | t.CPtr = find_enum(enum_name)
if entry is not None:
return entry.BaseTy
"""按枚举类名获取基准类型(委托到 gen.get_enum_base_type)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.get_enum_base_type(enum_name)
return None
+28 -8
View File
@@ -15,7 +15,11 @@ import lib.core.Handles.HandlesType as HandlesType
# ============================================================
# HandlesFor - for 循环语句处理(Mixin 继承模式)
# HandlesFor - for 循环语句处理(P6 对象化后的委托层)
#
# NewForHandle 工厂已迁移为 lib.core.Gen.StmtGenMixin 的方法
# (ForHandle 类保留:trans.ForH 的类型,由 HandlesTranslator.
# _init_state 经 NewForHandle 委托创建)。
#
# 支持 for i in range(start, stop, step) 模式:
# %i = alloca i32
@@ -37,6 +41,22 @@ import lib.core.Handles.HandlesType as HandlesType
# ============================================================
# ============================================================
# 全局 gen 单例(模块级镜像,同 HandlesStruct 模式)
#
# 由 BuildPipeline/main 在 gen 创建后调用 set_global_gen 注入。
# 委托函数用本地 _g_gen(cast 成 Generator 类型)调
# StmtGenMixin 方法,避免函数体 import 包模块与类/模块名歧义。
# ============================================================
_g_gen: t.CVoid | t.CPtr = None
def set_global_gen(gen: t.CVoid | t.CPtr) -> None:
"""注入全局 gen 单例(BuildPipeline/main 调用)"""
global _g_gen
_g_gen = gen
@t.NoVTable
class ForHandle(HandlesBase.Mixin):
"""for 循环语句处理器:继承 Mixin 获得 Trans 回指针"""
@@ -599,13 +619,13 @@ class ForHandle(HandlesBase.Mixin):
# ============================================================
# NewForHandle - 工厂函数
# NewForHandle - 工厂函数(委托到 gen.NewForHandle)
# ============================================================
def NewForHandle(pool: memhub.MemBuddy | t.CPtr,
trans: HT.Translator | t.CPtr) -> ForHandle | t.CPtr:
h: ForHandle | t.CPtr = pool.alloc(ForHandle.__sizeof__())
if h is None:
return None
string.memset(h, 0, ForHandle.__sizeof__())
h.Trans = trans
return h
"""创建 ForHandle 实例(委托到 gen.NewForHandle)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.NewForHandle(pool, trans)
return None
+80 -287
View File
@@ -16,6 +16,20 @@ import lib.Projectrans.Config as Config
# ============================================================
# HandlesIf - if/elif/else 语句处理(P6 对象化后的委托层)
#
# 编译期 CIf 求值的模块级函数(_is_cif_attr/_is_cif_call/
# _get_platform_macro_value/_cif_name_value/_cif_attr_value/
# _cif_eval_node/_evaluate_cif_test)已迁移为 lib.core.Gen.
# StmtGenMixin 的方法(_g_cif_eval_ok → gen 实例字段 CifEvalOk),
# 本模块保留同名模块级函数作为"一行委托";模块级 _g_cif_eval_ok
# 保留为镜像,委托后同步 gen.CifEvalOk(IfHandle.Handle 直接读它)。
#
# IfHandle 类(trans.IfH 的类型)保留:由 HandlesTranslator.
# _init_state 通过 NewIfHandle 工厂创建,Handle 方法内部经模块级
# 委托函数访问 gen。
# ============================================================
# 编译期宏条件: if c.CIf(...) / c.CIfdef(...) / c.CIfndef(...)
#
# 对齐 TPC HandlesIf.py:编译期求值命中分支并剪枝(不发射运行时 IR)。
@@ -26,81 +40,55 @@ import lib.Projectrans.Config as Config
# 求值失败(如运行时变量 val == 1)→ 回退运行时翻译
# (c.CIf 由 HandlesExprCall.translate_call 特判翻译成运行时真值,
# c.CIfdef/c.CIfndef 运行时恒真,对齐 TPC HandlesExprCall.py L2434-2446)。
# ============================================================
_g_cif_eval_ok: int = 0
# ============================================================
# 全局 gen 单例(模块级镜像,同 HandlesStruct 模式)
#
# 由 BuildPipeline/main 在 gen 创建后调用 set_global_gen 注入。
# 委托函数用本地 _g_gen(cast 成 Generator 类型)调
# StmtGenMixin 方法,避免函数体 import 包模块与类/模块名歧义。
# ============================================================
_g_gen: t.CVoid | t.CPtr = None
def set_global_gen(gen: t.CVoid | t.CPtr) -> None:
"""注入全局 gen 单例(BuildPipeline/main 调用)"""
global _g_gen
_g_gen = gen
def _is_cif_attr(attr: str) -> int:
"""检查方法名是否为 CIf 系(CIf/CIfdef/CIfndef)"""
if attr is None:
return 0
if string.strcmp(attr, "CIf") == 0: return 1
if string.strcmp(attr, "CIfdef") == 0: return 1
if string.strcmp(attr, "CIfndef") == 0: return 1
"""检查方法名是否为 CIf 系(CIf/CIfdef/CIfndef)(委托到 gen._is_cif_attr)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g._is_cif_attr(attr)
return 0
def _is_cif_call(node: ast.AST | t.CPtr) -> int:
"""检查 test 是否为 c.CIf(...)/c.CIfdef(...)/c.CIfndef(...)(或裸 CIf 系)调用"""
if node is None or node.kind() != ast.ASTKind.Call:
return 0
cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node)
if cl.func is None:
return 0
fk: int = cl.func.kind()
if fk == ast.ASTKind.Attribute:
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
if at.attr is None:
return 0
if at.value is not None and at.value.kind() == ast.ASTKind.Name:
vn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
if vn.id is not None and string.strcmp(vn.id, "c") == 0:
return _is_cif_attr(at.attr)
return 0
if fk == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cl.func)
if nm.id is not None and _is_cif_attr(nm.id) != 0:
return 1
"""检查 test 是否为 c.CIf(...)/c.CIfdef(...)/c.CIfndef(...)(或裸 CIf 系)调用(委托到 gen._is_cif_call)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g._is_cif_call(node)
return 0
def _get_platform_macro_value(name: str) -> int:
"""平台内置宏值(从目标三元组推导,对齐 TPC HandlesIf._get_platform_macros)。
命中置 _g_cif_eval_ok=1;未命中置 0 返回 0。
命中置 _g_cif_eval_ok=1;未命中置 0 返回 0(委托到 gen._get_platform_macro_value)。
"""
global _g_cif_eval_ok
_g_cif_eval_ok = 0
if name is None:
return 0
triple: str = Config.TargetTriple
if triple is None:
triple = "x86_64-pc-windows-gnu"
is_win: int = 0
is_linux: int = 0
is_x64: int = 0
if string.strstr(triple, "windows") is not None \
or string.strstr(triple, "win32") is not None \
or string.strstr(triple, "mingw") is not None \
or string.strstr(triple, "msvc") is not None:
is_win = 1
if string.strstr(triple, "linux") is not None:
is_linux = 1
if string.strstr(triple, "x86_64") is not None:
is_x64 = 1
# 简化:本编译目标为 x86_64 Windows(_WIN64/WIN64 恒与 is_win 一致)
if string.strcmp(name, "_WIN32") == 0: _g_cif_eval_ok = is_win; return 1 if is_win else 0
if string.strcmp(name, "WIN32") == 0: _g_cif_eval_ok = is_win; return 1 if is_win else 0
if string.strcmp(name, "_WIN64") == 0: _g_cif_eval_ok = is_win; return 1 if is_win else 0
if string.strcmp(name, "WIN64") == 0: _g_cif_eval_ok = is_win; return 1 if is_win else 0
if string.strcmp(name, "__linux__") == 0: _g_cif_eval_ok = is_linux; return 1 if is_linux else 0
if string.strcmp(name, "__x86_64__") == 0: _g_cif_eval_ok = is_x64; return 1 if is_x64 else 0
if string.strcmp(name, "__x86_64") == 0: _g_cif_eval_ok = is_x64; return 1 if is_x64 else 0
if string.strcmp(name, "_M_X64") == 0: _g_cif_eval_ok = is_x64; return 1 if is_x64 else 0
if string.strcmp(name, "SIZEOF_VOID_P") == 0: _g_cif_eval_ok = 1; return 8 if is_x64 else 4
if string.strcmp(name, "__SIZEOF_POINTER__") == 0: _g_cif_eval_ok = 1; return 8 if is_x64 else 4
if string.strcmp(name, "NDEBUG") == 0: _g_cif_eval_ok = 1; return 0
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
v: int = g._get_platform_macro_value(name)
_g_cif_eval_ok = g.CifEvalOk
return v
return 0
@@ -109,24 +97,15 @@ def _cif_name_value(pool: memhub.MemBuddy | t.CPtr,
name: str) -> int:
"""查宏名值: 本地 CDefine → 跨模块 CDefine → 平台宏。
命中置 _g_cif_eval_ok=1(值 0 也算命中,如 DISABLED=0);未命中置 0。
命中置 _g_cif_eval_ok=1(值 0 也算命中,如 DISABLED=0);未命中置 0(委托到 gen._cif_name_value)。
"""
global _g_cif_eval_ok
_g_cif_eval_ok = 0
if name is None or trans is None:
return 0
v: int = HandlesType.lookup_cdefine_constant(name)
if HandlesType.is_cdefine_found() != 0:
_g_cif_eval_ok = 1
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
v: int = g._cif_name_value(pool, trans, name)
_g_cif_eval_ok = g.CifEvalOk
return v
v2: int = HandlesExpr._lookup_cross_module_cdefine(
pool, name, trans._from_imports, trans._imported_modules)
if HandlesType.is_cdefine_found() != 0:
_g_cif_eval_ok = 1
return v2
pv: int = _get_platform_macro_value(name)
if _g_cif_eval_ok != 0:
return pv
return 0
@@ -135,45 +114,15 @@ def _cif_attr_value(pool: memhub.MemBuddy | t.CPtr,
at: ast.Attribute | t.CPtr) -> int:
"""Attribute 宏值: platmacro.IS_WINDOWS → 本地 CDefine(attr) → 跨模块 CDefine。
命中置 _g_cif_eval_ok=1;未命中置 0。
命中置 _g_cif_eval_ok=1;未命中置 0(委托到 gen._cif_attr_value)。
"""
global _g_cif_eval_ok
_g_cif_eval_ok = 0
if at is None or at.attr is None or at.value is None or trans is None:
return 0
if at.value.kind() != ast.ASTKind.Name:
return 0
vn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
if vn.id is None:
return 0
v: int = HandlesType.lookup_cdefine_constant(at.attr)
if HandlesType.is_cdefine_found() != 0:
_g_cif_eval_ok = 1
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
v: int = g._cif_attr_value(pool, trans, at)
_g_cif_eval_ok = g.CifEvalOk
return v
# 跨模块: 确定真实模块名(解析 from_imports 别名)
real_mod: str = vn.id
if trans._from_imports is not None:
resolved: str = HandlesImports.lookup_from_import(
trans._from_imports, vn.id, 0)
if resolved is not None:
rm_len: t.CSizeT = 0
while resolved[rm_len] != ' ' and resolved[rm_len] != '\0' and resolved[rm_len] != ':':
rm_len += 1
rm_buf: str = pool.alloc(rm_len + 1)
if rm_buf is not None:
for rm_i in range(rm_len):
rm_buf[rm_i] = resolved[rm_i]
rm_buf[rm_len] = '\0'
real_mod = rm_buf
fi_len: t.CSizeT = string.strlen(at.attr) + string.strlen(real_mod) + 2
fi: str = pool.alloc(fi_len)
if fi is None:
return 0
viperlib.snprintf(fi, fi_len, "%s:%s", at.attr, real_mod)
v2: int = HandlesExpr._lookup_cross_module_cdefine(pool, at.attr, fi)
if HandlesType.is_cdefine_found() != 0:
_g_cif_eval_ok = 1
return v2
return 0
@@ -185,128 +134,15 @@ def _cif_eval_node(pool: memhub.MemBuddy | t.CPtr,
支持: Constant(int) / Name(CDefine/跨模块/平台宏) / Attribute(跨模块 CDefine)
/ BinOp(+ - * // % & | ^ << >>) / Compare(== != < > <= >=)
/ BoolOp(and/or) / UnaryOp(not - + ~)。
成功置 _g_cif_eval_ok=1;失败(含运行时变量)置 0 返回 0。
成功置 _g_cif_eval_ok=1;失败(含运行时变量)置 0 返回 0(委托到 gen._cif_eval_node)。
"""
global _g_cif_eval_ok
if node is None:
_g_cif_eval_ok = 0
return 0
k: int = node.kind()
if k == ast.ASTKind.Constant:
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node)
if cn.const_kind == ast.CONST_INT:
_g_cif_eval_ok = 1
return cn.int_val
_g_cif_eval_ok = 0
return 0
if k == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node)
if nm.id is None:
_g_cif_eval_ok = 0
return 0
return _cif_name_value(pool, trans, nm.id)
if k == ast.ASTKind.Attribute:
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node)
return _cif_attr_value(pool, trans, at)
if k == ast.ASTKind.UnaryOp:
uop: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node)
if uop.operand is None:
_g_cif_eval_ok = 0
return 0
ov: int = _cif_eval_node(pool, trans, uop.operand)
if _g_cif_eval_ok == 0:
return 0
if uop.op == ast.OpKind.Not: return 1 if ov == 0 else 0
if uop.op == ast.OpKind.USub: return -ov
if uop.op == ast.OpKind.UAdd: return ov
if uop.op == ast.OpKind.Invert: return ~ov
_g_cif_eval_ok = 0
return 0
if k == ast.ASTKind.BoolOp:
bo: ast.BoolOp | t.CPtr = (ast.BoolOp | t.CPtr)(node)
vals: list[ast.AST | t.CPtr] | t.CPtr = bo.values
if vals is None:
_g_cif_eval_ok = 0
return 0
bn: t.CSizeT = vals.__len__()
if bo.op == ast.OpKind.And:
for bi in range(bn):
rv: int = _cif_eval_node(pool, trans, vals.get(bi))
if _g_cif_eval_ok == 0:
return 0
if rv == 0:
return 0
return 1
if bo.op == ast.OpKind.Or:
for bi in range(bn):
rv: int = _cif_eval_node(pool, trans, vals.get(bi))
if _g_cif_eval_ok == 0:
return 0
if rv != 0:
return 1
return 0
_g_cif_eval_ok = 0
return 0
if k == ast.ASTKind.Compare:
cmp: ast.Compare | t.CPtr = (ast.Compare | t.CPtr)(node)
lv: int = _cif_eval_node(pool, trans, cmp.left)
if _g_cif_eval_ok == 0:
return 0
ops_list: list[t.CInt] | t.CPtr = (list[t.CInt] | t.CPtr)(cmp.ops)
comps: list[ast.AST | t.CPtr] | t.CPtr = cmp.comparators
if ops_list is None or comps is None:
_g_cif_eval_ok = 0
return 0
cc: t.CSizeT = comps.__len__()
ci: t.CSizeT
for ci in range(cc):
rv: int = _cif_eval_node(pool, trans, comps.get(ci))
if _g_cif_eval_ok == 0:
return 0
op_id: int = ops_list.get(ci)
ok_cmp: int = 0
if op_id == ast.OpKind.Eq: ok_cmp = 1 if lv == rv else 0
elif op_id == ast.OpKind.Ne: ok_cmp = 1 if lv != rv else 0
elif op_id == ast.OpKind.Lt: ok_cmp = 1 if lv < rv else 0
elif op_id == ast.OpKind.Le: ok_cmp = 1 if lv <= rv else 0
elif op_id == ast.OpKind.Gt: ok_cmp = 1 if lv > rv else 0
elif op_id == ast.OpKind.Ge: ok_cmp = 1 if lv >= rv else 0
else:
_g_cif_eval_ok = 0
return 0
if ok_cmp == 0:
return 0
lv = rv
return 1
if k == ast.ASTKind.BinOp:
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node)
lv: int = _cif_eval_node(pool, trans, bop.left)
if _g_cif_eval_ok == 0:
return 0
rv: int = _cif_eval_node(pool, trans, bop.right)
if _g_cif_eval_ok == 0:
return 0
if bop.op == ast.OpKind.Add: return lv + rv
if bop.op == ast.OpKind.Sub: return lv - rv
if bop.op == ast.OpKind.Mult: return lv * rv
if bop.op == ast.OpKind.FloorDiv:
if rv == 0:
_g_cif_eval_ok = 0
return 0
return lv // rv
if bop.op == ast.OpKind.Mod:
if rv == 0:
_g_cif_eval_ok = 0
return 0
return lv % rv
if bop.op == ast.OpKind.BitAnd: return lv & rv
if bop.op == ast.OpKind.BitOr: return lv | rv
if bop.op == ast.OpKind.BitXor: return lv ^ rv
if bop.op == ast.OpKind.LShift: return lv << rv
if bop.op == ast.OpKind.RShift: return lv >> rv
_g_cif_eval_ok = 0
return 0
_g_cif_eval_ok = 0
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
v: int = g._cif_eval_node(pool, trans, node)
_g_cif_eval_ok = g.CifEvalOk
return v
return 0
@@ -316,59 +152,16 @@ def _evaluate_cif_test(pool: memhub.MemBuddy | t.CPtr,
"""求值 CIf 调用(test 必须是 c.CIf 系调用)。
成功: 置 _g_cif_eval_ok=1,返回条件值(0/1)
失败(运行时变量/未知结构): 置 _g_cif_eval_ok=0,返回 0
失败(运行时变量/未知结构): 置 _g_cif_eval_ok=0,返回 0(委托到 gen._evaluate_cif_test)。
"""
global _g_cif_eval_ok
_g_cif_eval_ok = 0
cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(test)
if cl is None or cl.func is None:
return 0
kind: str = None
fk: int = cl.func.kind()
if fk == ast.ASTKind.Attribute:
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
kind = at.attr
elif fk == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cl.func)
kind = nm.id
if kind is None:
return 0
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
if cargs is None or cargs.__len__() < 1:
return 0
arg0: ast.AST | t.CPtr = cargs.get(0)
if string.strcmp(kind, "CIf") == 0:
v: int = _cif_eval_node(pool, trans, arg0)
if _g_cif_eval_ok == 0:
return 0
return 1 if v != 0 else 0
# CIfdef / CIfndef: 判定宏名是否已定义
defined: int = 0
if arg0 is not None and arg0.kind() == ast.ASTKind.Name:
nm0: ast.Name | t.CPtr = (ast.Name | t.CPtr)(arg0)
if nm0.id is None:
return 0
_cif_name_value(pool, trans, nm0.id)
defined = _g_cif_eval_ok
elif arg0 is not None and arg0.kind() == ast.ASTKind.Constant:
cn0: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(arg0)
if cn0.const_kind == ast.CONST_STR and cn0.str_val is not None:
_cif_name_value(pool, trans, cn0.str_val)
defined = _g_cif_eval_ok
else:
return 0
elif arg0 is not None and arg0.kind() == ast.ASTKind.Attribute:
at0: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(arg0)
_cif_attr_value(pool, trans, at0)
defined = _g_cif_eval_ok
else:
return 0
# 定义判定本身成功(未定义名特判:不报错,defined=0 走 else)
_g_cif_eval_ok = 1
if string.strcmp(kind, "CIfdef") == 0:
return 1 if defined != 0 else 0
# CIfndef
return 0 if defined != 0 else 1
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
v: int = g._evaluate_cif_test(pool, trans, test)
_g_cif_eval_ok = g.CifEvalOk
return v
return 0
# ============================================================
@@ -526,13 +319,13 @@ class IfHandle(HandlesBase.Mixin):
# ============================================================
# NewIfHandle - 工厂函数
# NewIfHandle - 工厂函数(委托到 gen.NewIfHandle)
# ============================================================
def NewIfHandle(pool: memhub.MemBuddy | t.CPtr,
trans: HT.Translator | t.CPtr) -> IfHandle | t.CPtr:
h: IfHandle | t.CPtr = pool.alloc(IfHandle.__sizeof__())
if h is None:
return None
string.memset(h, 0, IfHandle.__sizeof__())
h.Trans = trans
return h
"""创建 IfHandle 实例(委托到 gen.NewIfHandle)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.NewIfHandle(pool, trans)
return None
+121 -445
View File
@@ -16,16 +16,46 @@ import lib.core.StubMerger as StubMerger
# ============================================================
# HandlesImports - 导入语句处理(Mixin 继承模式)
# HandlesImports - 导入语句处理(P6-D 对象化后的委托层)
#
# 管理 _imported_modules 和 _from_imports 字符串
# 注意:str = bytes = t.CChar | t.CPtr = i8*
#
# P6-D 对象化重构(wiki/14-oo-refactor.md):
# 全部模块级函数已迁移为 lib.core.Gen.ImportsGenMixin 的方法
# (全局状态 _g_reexport_* 与 _g_current_file 迁入 gen 字段),本模块
# 保留同名模块级函数作为"一行委托":延迟 import Gen 取全局单例
# (BuildPipeline/main 创建后 set_global_gen 注册),再调用 gen 的
# 对应方法。签名与旧函数完全一致,调用方零改动。
# ImportsHandle 类与 NewImportsHandle 工厂保留在本模块(对象工厂,
# 不依赖 gen 状态,与 HandlesExpr.NewExprHandle 模式一致)。
# ============================================================
MAX_REEXPORT: t.CDefine = 512
# ============================================================
# 模块级工具函数(保留供外部调用)
# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式)
#
# 由 BuildPipeline/main 在 gen 创建后调用 set_global_gen 注入。
# P6-D 委托函数用本地 _g_gen(cast 成 Generator 类型)调
# ImportsGenMixin 方法,避免函数体 import 包模块与 Generator
# 类/模块名歧义。
# ============================================================
_g_gen: t.CVoid | t.CPtr = None
def set_global_gen(gen: t.CVoid | t.CPtr) -> None:
"""注入全局 gen 单例(BuildPipeline/main 调用)"""
global _g_gen
_g_gen = gen
# ============================================================
# 委托函数:延迟 import Gen 取全局单例 → 调 gen 方法
# (gen 未注册时正常流程不会发生;有返回值函数返回默认值)
# ============================================================
# ============================================================
# 添加已导入模块名
@@ -33,57 +63,23 @@ import lib.core.StubMerger as StubMerger
def add_imported_module(pool: memhub.MemBuddy | t.CPtr,
imported_modules: str,
name: str) -> str:
"""记录已导入的模块名,返回新的 imported_modules 字符串指针"""
if name is None:
return imported_modules
if imported_modules is None:
nlen: t.CSizeT = string.strlen(name)
buf: t.CChar | t.CPtr = pool.alloc(nlen + 1)
if buf is not None:
string.strcpy(buf, name)
return buf
return None
else:
old_len: t.CSizeT = string.strlen(imported_modules)
name_len: t.CSizeT = string.strlen(name)
new_len: t.CSizeT = old_len + 1 + name_len
buf2: t.CChar | t.CPtr = pool.alloc(new_len + 1)
if buf2 is not None:
string.strcpy(buf2, imported_modules)
buf2[old_len] = ' '
string.strcpy(buf2 + old_len + 1, name)
return buf2
return imported_modules
"""记录已导入的模块名,返回新的 imported_modules 字符串指针(委托到 gen.add_imported_module)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.add_imported_module(pool, imported_modules, name)
return None
# ============================================================
# 检查模块是否已导入
# ============================================================
def is_module_imported(imported_modules: str, name: str) -> int:
"""检查模块是否已导入(词边界精确匹配,避免子串误匹配)"""
if name is None or imported_modules is None:
return 0
name_len: t.CSizeT = string.strlen(name)
cur: t.CChar | t.CPtr = imported_modules
total_len: t.CSizeT = string.strlen(imported_modules)
ci: t.CSizeT = 0
while ci < total_len:
while ci < total_len and cur[ci] == ' ':
ci += 1
if ci >= total_len:
break
word_start: t.CSizeT = ci
while ci < total_len and cur[ci] != ' ':
ci += 1
word_len: t.CSizeT = ci - word_start
if word_len == name_len:
match: int = 1
for ei in range(name_len):
if cur[word_start + ei] != name[ei]:
match = 0
break
if match == 1:
return 1
"""检查模块是否已导入(词边界精确匹配,避免子串误匹配,委托到 gen.is_module_imported)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.is_module_imported(imported_modules, name)
return 0
@@ -95,35 +91,18 @@ def add_from_import(pool: memhub.MemBuddy | t.CPtr,
local_name: str,
module_name: str,
original_name: str = None) -> str:
"""添加 from-import 映射,返回新的 from_imports 字符串
"""添加 from-import 映射,返回新的 from_imports 字符串(委托到 gen.add_from_import)
格式:
无别名: "local_name:module_name"
有别名: "local_name:module_name:original_name"
(original_name 为源模块中的真实函数名,用于跨模块 SHA1 修饰)
"""
if local_name is None or module_name is None:
return from_imports
entry: t.CChar | t.CPtr = pool.alloc(256)
if entry is None:
return from_imports
if original_name is not None and string.strcmp(original_name, local_name) != 0:
viperlib.snprintf(entry, 256, "%s:%s:%s", local_name, module_name, original_name)
else:
viperlib.snprintf(entry, 256, "%s:%s", local_name, module_name)
if from_imports is None:
return entry
else:
old_len: t.CSizeT = string.strlen(from_imports)
entry_len: t.CSizeT = string.strlen(entry)
new_len: t.CSizeT = old_len + 1 + entry_len
buf: t.CChar | t.CPtr = pool.alloc(new_len + 1)
if buf is not None:
string.strcpy(buf, from_imports)
buf[old_len] = ' '
string.strcpy(buf + old_len + 1, entry)
return buf
return from_imports
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.add_from_import(pool, from_imports, local_name, module_name, original_name)
return None
# ============================================================
@@ -134,64 +113,11 @@ def add_from_import(pool: memhub.MemBuddy | t.CPtr,
# ============================================================
def lookup_from_import_original(from_imports: str,
local_name: str) -> str:
"""查找 from-import 别名对应的原始函数名,返回 None=无别名或未找到"""
if local_name is None or from_imports is None:
return None
name_len: t.CSizeT = string.strlen(local_name)
cur: t.CChar | t.CPtr = from_imports
ci: t.CSizeT = 0
total_len: t.CSizeT = string.strlen(from_imports)
while ci < total_len:
# 跳过前导空格
while ci < total_len and cur[ci] == ' ':
ci += 1
if ci >= total_len:
break
# 找到第一个 ':' 的位置
colon1: t.CSizeT = ci
while colon1 < total_len and cur[colon1] != ':' and cur[colon1] != ' ':
colon1 += 1
if colon1 >= total_len or cur[colon1] != ':':
break
entry_name_len: t.CSizeT = colon1 - ci
# 跳过 star import
if entry_name_len == 1 and cur[ci] == '*':
ci = colon1
while ci < total_len and cur[ci] != ' ':
ci += 1
continue
# 比较名称
if entry_name_len == name_len:
match: int = 1
ei: t.CSizeT = 0
while ei < name_len:
if cur[ci + ei] != local_name[ei]:
match = 0
break
ei += 1
if match == 1:
# 找到匹配,检查是否有第三个字段(原始名)
pos: t.CSizeT = colon1 + 1
# 跳过模块名
while pos < total_len and cur[pos] != ':' and cur[pos] != ' ' and cur[pos] != '\0':
pos += 1
if pos < total_len and cur[pos] == ':':
# 有第三个字段: original_name
orig_start: t.CSizeT = pos + 1
orig_end: t.CSizeT = orig_start
while orig_end < total_len and cur[orig_end] != ' ' and cur[orig_end] != '\0':
orig_end += 1
orig_len: t.CSizeT = orig_end - orig_start
if orig_len > 0:
orig_buf: str = cur + orig_start
# 返回指向内部的指针(调用方需在使用期内保持 from_imports 有效)
return orig_buf
return None
return None
# 跳到下一个条目
ci = colon1
while ci < total_len and cur[ci] != ' ':
ci += 1
"""查找 from-import 别名对应的原始函数名,返回 None=无别名或未找到(委托到 gen.lookup_from_import_original)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.lookup_from_import_original(from_imports, local_name)
return None
@@ -205,83 +131,16 @@ def lookup_from_import_original(from_imports: str,
# ============================================================
def lookup_from_import(from_imports: str, name: str,
allow_star_fallback: int = 1) -> str:
"""查找 from-import 名称,返回模块名或 None
"""查找 from-import 名称,返回模块名或 None(委托到 gen.lookup_from_import)
支持 star import: 如果 from_imports 中有 "*:module" 条目,
且未找到精确名称匹配,且 allow_star_fallback != 0,则返回 star import 的模块名。
"""
if name is None or from_imports is None:
return None
name_len: t.CSizeT = string.strlen(name)
cur: t.CChar | t.CPtr = from_imports
ci: t.CSizeT = 0
total_len: t.CSizeT = string.strlen(from_imports)
star_mod: str = None
while ci < total_len:
# 跳过前导空格
while ci < total_len and cur[ci] == ' ':
ci += 1
if ci >= total_len:
break
# 找到 ':' 的位置
colon_pos: t.CSizeT = ci
while colon_pos < total_len and cur[colon_pos] != ':' and cur[colon_pos] != ' ':
colon_pos += 1
if colon_pos >= total_len or cur[colon_pos] != ':':
break
entry_name_len: t.CSizeT = colon_pos - ci
# 检测 star import ("*:module")
if entry_name_len == 1 and cur[ci] == '*':
mod_start: t.CSizeT = colon_pos + 1
mod_end: t.CSizeT = mod_start
while mod_end < total_len and cur[mod_end] != ' ' and cur[mod_end] != '\0' and cur[mod_end] != ':':
mod_end += 1
star_mod = cur + mod_start
# 比较名称
elif entry_name_len == name_len:
match: int = 1
ei: t.CSizeT = 0
while ei < name_len:
if cur[ci + ei] != name[ei]:
match = 0
break
ei += 1
if match == 1:
mod_start2: t.CSizeT = colon_pos + 1
mod_end2: t.CSizeT = mod_start2
# 模块名结束于: 空格、null、或第二个':'(别名格式的分隔符)
while mod_end2 < total_len and cur[mod_end2] != ' ' and cur[mod_end2] != '\0' and cur[mod_end2] != ':':
mod_end2 += 1
return cur + mod_start2
# 跳到下一个条目
ci = colon_pos
while ci < total_len and cur[ci] != ' ':
ci += 1
# 未找到精确匹配,仅在允许时回退到 star import
if allow_star_fallback == 0:
return None
return star_mod
# ============================================================
# 全局 re-export 映射表(module_sha1 + func_name → source_module)
#
# 当 ast/__init__.vp 中有 from .lexer import _lexer_init 时,
# _lexer_init 被 re-export 为 ast._lexer_init。
# 跨模块调用 ast._lexer_init(...) 需使用 ast.lexer 的 SHA1 混淆,
# 而非 ast 的 SHA1。
#
# 数据布局:
# _g_reexport_sha1s: 每条 17 字节(SHA1 16字符 + null)
# _g_reexport_funcs: 每条 64 字节(函数名 + null)
# _g_reexport_srcs: 每条 64 字节(源模块名 + null)
# ============================================================
MAX_REEXPORT: t.CDefine = 512
_g_reexport_sha1s: bytes = None
_g_reexport_funcs: bytes = None
_g_reexport_srcs: bytes = None
_g_reexport_count: int = 0
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.lookup_from_import(from_imports, name, allow_star_fallback)
return None
# ============================================================
@@ -294,42 +153,11 @@ _g_reexport_count: int = 0
# 内存用 stdlib.malloc 分配(全局存储器,跨 Phase 持久化)。
# ============================================================
def register_reexport(mod_sha1: str, func_name: str, source_module: str) -> int:
"""注册 re-export 映射(幂等),返回 0 成功,-1 失败"""
global _g_reexport_sha1s, _g_reexport_funcs, _g_reexport_srcs, _g_reexport_count
if mod_sha1 is None or func_name is None or source_module is None:
return -1
# 懒初始化
if _g_reexport_sha1s is None:
_g_reexport_sha1s = stdlib.malloc(MAX_REEXPORT * 17)
_g_reexport_funcs = stdlib.malloc(MAX_REEXPORT * 64)
_g_reexport_srcs = stdlib.malloc(MAX_REEXPORT * 64)
if _g_reexport_sha1s is None or _g_reexport_funcs is None or _g_reexport_srcs is None:
return -1
string.memset(_g_reexport_sha1s, 0, MAX_REEXPORT * 17)
string.memset(_g_reexport_funcs, 0, MAX_REEXPORT * 64)
string.memset(_g_reexport_srcs, 0, MAX_REEXPORT * 64)
if _g_reexport_count >= MAX_REEXPORT:
return -1
# 幂等检查:查找是否已存在相同映射
for i in range(_g_reexport_count):
sidx: t.CSizeT = t.CSizeT(i) * 17
fidx: t.CSizeT = t.CSizeT(i) * 64
if string.strcmp(_g_reexport_sha1s + sidx, mod_sha1) == 0:
if string.strcmp(_g_reexport_funcs + fidx, func_name) == 0:
# 已存在,更新 source_module(以防变化;64 字节槽,strncpy 钳制)
string.strncpy(_g_reexport_srcs + fidx, source_module, 63)
_g_reexport_srcs[fidx + 63] = '\0'
return 0
# 添加新条目(槽位定长 17/64 字节,strcpy 无界会越界写相邻槽,全部 strncpy 钳制)
idx2: t.CSizeT = t.CSizeT(_g_reexport_count) * 17
fidx2: t.CSizeT = t.CSizeT(_g_reexport_count) * 64
string.strncpy(_g_reexport_sha1s + idx2, mod_sha1, 16)
_g_reexport_sha1s[idx2 + 16] = '\0'
string.strncpy(_g_reexport_funcs + fidx2, func_name, 63)
_g_reexport_funcs[fidx2 + 63] = '\0'
string.strncpy(_g_reexport_srcs + fidx2, source_module, 63)
_g_reexport_srcs[fidx2 + 63] = '\0'
_g_reexport_count += 1
"""注册 re-export 映射(幂等),返回 0 成功,-1 失败(委托到 gen.register_reexport)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.register_reexport(mod_sha1, func_name, source_module)
return 0
@@ -340,17 +168,11 @@ def register_reexport(mod_sha1: str, func_name: str, source_module: str) -> int:
# 调用方通过 _lookup_module_sha1(source_module) 获取源模块的 SHA1。
# ============================================================
def lookup_reexport(mod_sha1: str, func_name: str) -> str:
"""查找 re-export 映射,返回源模块名或 None"""
if mod_sha1 is None or func_name is None:
return None
if _g_reexport_sha1s is None or _g_reexport_count <= 0:
return None
for i in range(_g_reexport_count):
sidx: t.CSizeT = t.CSizeT(i) * 17
fidx: t.CSizeT = t.CSizeT(i) * 64
if string.strcmp(_g_reexport_sha1s + sidx, mod_sha1) == 0:
if string.strcmp(_g_reexport_funcs + fidx, func_name) == 0:
return _g_reexport_srcs + fidx
"""查找 re-export 映射,返回源模块名或 None(委托到 gen.lookup_reexport)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.lookup_reexport(mod_sha1, func_name)
return None
@@ -375,57 +197,15 @@ def lookup_reexport(mod_sha1: str, func_name: str) -> str:
# 无法解析时返回 module(回退到原始值)
# ============================================================
def _resolve_relative_module(pool: memhub.MemBuddy | t.CPtr,
current_package: str,
level: t.CInt,
module: str) -> str:
"""解析相对导入为完整模块名"""
if level <= 0:
return module
if current_package is None:
return module
# 从 current_package 开始,上溯 (level-1) 级
pkg: str = current_package
up: t.CInt = level - 1
while up > 0:
pkg_len: t.CSizeT = string.strlen(pkg)
last_dot: t.CSizeT = 0
found: int = 0
i: t.CSizeT = 0
while i < pkg_len:
if pkg[i] == '.':
last_dot = i
found = 1
i += 1
if found == 0:
# 无更多父级,包变为空
pkg = None
break
# 截断到最后一个 '.' 处
new_pkg: str = pool.alloc(last_dot + 1)
if new_pkg is None:
return module
string.strncpy(new_pkg, pkg, last_dot)
new_pkg[last_dot] = '\0'
pkg = new_pkg
up -= 1
if module is None:
# from . import Y → 模块就是包本身
return pkg
if pkg is None:
# 包已上溯到空,直接用 module
return module
# 拼接 pkg + "." + module
pkg_len2: t.CSizeT = string.strlen(pkg)
mod_len: t.CSizeT = string.strlen(module)
buf: str = pool.alloc(pkg_len2 + 1 + mod_len + 1)
if buf is None:
return module
string.strcpy(buf, pkg)
buf[pkg_len2] = '.'
string.strcpy(buf + pkg_len2 + 1, module)
return buf
current_package: str,
level: t.CInt,
module: str) -> str:
"""解析相对导入为完整模块名(委托到 gen._resolve_relative_module)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g._resolve_relative_module(pool, current_package, level, module)
return None
# ============================================================
@@ -441,56 +221,27 @@ def _resolve_relative_module(pool: memhub.MemBuddy | t.CPtr,
# "ast.vp" → None(顶级文件)
# ============================================================
def compute_package_from_relpath(pool: memhub.MemBuddy | t.CPtr,
rel_path: str) -> str:
"""从相对路径计算包名(目录部分,分隔符替换为 .)"""
if rel_path is None:
return None
rlen: t.CSizeT = string.strlen(rel_path)
# 找最后一个 / 或 \
last_sep: t.CSizeT = 0
found: int = 0
i: t.CSizeT = 0
while i < rlen:
ch: t.CChar = rel_path[i]
if ch == '/' or ch == '\\':
last_sep = i
found = 1
i += 1
if found == 0:
# 无目录分隔符 → 顶级文件,无包
return None
# 复制目录部分,将 / 和 \ 替换为 .
dir_len: t.CSizeT = last_sep
buf: str = pool.alloc(dir_len + 1)
if buf is None:
return None
j: t.CSizeT = 0
while j < dir_len:
ch2: t.CChar = rel_path[j]
if ch2 == '/' or ch2 == '\\':
buf[j] = '.'
else:
buf[j] = ch2
j += 1
buf[dir_len] = '\0'
return buf
rel_path: str) -> str:
"""从相对路径计算包名(目录部分,分隔符替换为 .,委托到 gen.compute_package_from_relpath)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.compute_package_from_relpath(pool, rel_path)
return None
# ============================================================
# 全局当前文件名(镜像 HandlesType._g_current_file)
# set_current_file - 设置当前编译的文件名
#
# HandlesImports 因循环依赖(HandlesType import 了本模块)不能
# import HandlesType,无法读取其 _g_current_file。因此由
# BuildPipeline/Phase1 在调用 HandlesType.set_current_file 时
# 同步调用本模块的 set_current_file,供导入时 SHA1 检查报错使用。
# 与 HandlesType.set_current_file 同步调用,写入 gen.CurrentFile
# (委托到 gen.set_current_file)。
# ============================================================
_g_current_file: str = None
def set_current_file(file_path: str) -> None:
"""设置当前正在编译的文件名(与 HandlesType.set_current_file 同步调用)"""
global _g_current_file
_g_current_file = file_path
"""设置当前正在编译的文件名(与 HandlesType.set_current_file 同步调用,委托到 gen.set_current_file)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
g.set_current_file(file_path)
# ============================================================
@@ -503,38 +254,26 @@ def set_current_file(file_path: str) -> None:
# ImportError: <msg>
# ============================================================
def _report_import_error(node: ast.AST | t.CPtr, msg: str) -> None:
"""以 Python 风格报错并退出(本地实现,避免循环依赖)"""
stdio.printf("Traceback (most recent call last):\n")
lineno: int = 0
if node is not None:
lineno = node.lineno
file_name: str = _g_current_file
if file_name is None:
file_name = "<unknown>"
stdio.printf(' File "%s", line %d\n', file_name, lineno)
# 显示行内内容(读源文件第 lineno 行的实际代码,便于快速定位)
if lineno > 0 and file_name is not None:
f_err: fileio.File | t.CPtr = fileio.File(file_name, fileio.MODE.R)
if not f_err.closed:
line_buf_err: bytes = stdlib.malloc(512)
if line_buf_err is not None:
cur_ln: int = 0
while cur_ln < lineno:
r_err: LONG = f_err.readline(line_buf_err, 511)
if r_err <= 0:
break
cur_ln += 1
if cur_ln == lineno:
ll_err: t.CSizeT = string.strlen(line_buf_err)
while ll_err > 0 and (line_buf_err[ll_err - 1] == '\n' or line_buf_err[ll_err - 1] == '\r'):
ll_err -= 1
line_buf_err[ll_err] = '\0'
stdio.printf(" %s\n", line_buf_err)
break
stdlib.free(line_buf_err)
f_err.close()
stdio.printf("ImportError: %s\n", msg)
sys.exit(1)
"""以 Python 风格报错并退出(本地实现,避免循环依赖,委托到 gen._report_import_error)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
g._report_import_error(node, msg)
# ============================================================
# _is_local_module_file - 当前文件同目录存在 {mod_name}.vp/.py
#
# 多文件项目(如 Test/G4/App 的 caller1.vp import g4node)的兄弟模块
# 不在 includes 扫描存储器中(SHA1 在项目源文件列表),检查应豁免。
# ============================================================
def _is_local_module_file(mod_name: str) -> int:
"""当前文件同目录存在 {mod_name}.vp/.py → 项目内兄弟模块(委托到 gen._is_local_module_file)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g._is_local_module_file(mod_name)
return 0
# ============================================================
@@ -548,56 +287,8 @@ def _report_import_error(node: ast.AST | t.CPtr, msg: str) -> None:
#
# t/c 是内部库,不参与 includes 扫描,豁免检查。
# ============================================================
def _is_local_module_file(mod_name: str) -> int:
"""当前文件同目录存在 {mod_name}.vp/.py → 项目内兄弟模块
多文件项目(如 Test/G4/App 的 caller1.vp import g4node)的兄弟模块
不在 includes 扫描存储器中(SHA1 在项目源文件列表),检查应豁免。
"""
cur: str = _g_current_file
if cur is None or mod_name is None:
return 0
cur_len: t.CSizeT = string.strlen(cur)
if cur_len == 0:
return 0
sep_pos: t.CSizeT = cur_len
while sep_pos > 0:
sep_pos -= 1
ch: t.CChar = cur[sep_pos]
if ch == '/' or ch == '\\':
sep_pos += 1
break
mod_len: t.CSizeT = string.strlen(mod_name)
path_len: t.CSizeT = sep_pos + mod_len + 5
path_buf: bytes = stdlib.malloc(path_len + 1)
if path_buf is None:
return 0
# .vp 文件
string.strncpy(path_buf, cur, sep_pos)
path_buf[sep_pos] = '\0'
string.strcat(path_buf, mod_name)
string.strcat(path_buf, ".vp")
fex: fileio.File | t.CPtr = fileio.File(path_buf, fileio.MODE.R)
if not fex.closed:
fex.close()
stdlib.free(path_buf)
return 1
# .py 文件(Python 模块可能无 .vp)
string.strncpy(path_buf, cur, sep_pos)
path_buf[sep_pos] = '\0'
string.strcat(path_buf, mod_name)
string.strcat(path_buf, ".py")
fex2: fileio.File | t.CPtr = fileio.File(path_buf, fileio.MODE.R)
if not fex2.closed:
fex2.close()
stdlib.free(path_buf)
return 1
stdlib.free(path_buf)
return 0
def _check_import_sha1(node: ast.AST | t.CPtr, mod_name: str) -> int:
"""导入时校验模块 SHA1 是否已注册,未注册则立即报错退出
"""导入时校验模块 SHA1 是否已注册,未注册则立即报错退出(委托到 gen._check_import_sha1)
Args:
node: Import/ImportFrom AST 节点(提供行号)
@@ -606,33 +297,18 @@ def _check_import_sha1(node: ast.AST | t.CPtr, mod_name: str) -> int:
Returns:
1=检查通过;模块未注册时直接报错退出(不会返回 0)
"""
if mod_name is None:
return 1
# t/c 是内部库,不参与 includes 扫描,豁免检查
if string.strcmp(mod_name, "t") == 0 or string.strcmp(mod_name, "c") == 0:
return 1
mod_sha1: str = StubMerger.LookupSha1ByModName(mod_name)
if mod_sha1 is None:
# App 兄弟模块豁免:当前文件同目录存在 {mod_name}.vp/.py
# (如 Test/G4/App/caller1.vp import g4node——同项目源文件,
# SHA1 在项目文件列表而非 includes 扫描存储器,不应报错)
if _is_local_module_file(mod_name) != 0:
return 1
err_buf: t.CChar | t.CPtr = stdlib.malloc(256)
if err_buf is not None:
viperlib.snprintf(err_buf, 256,
"模块 '%s' 未注册 SHA1(includes 扫描未找到该模块,请检查 project.json 的 includes 路径配置)",
mod_name)
_report_import_error(node, err_buf)
else:
_report_import_error(node, "导入模块 SHA1 未注册(includes 扫描未找到该模块)")
return 1
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g._check_import_sha1(node, mod_name)
return 0
# ============================================================
# ImportsHandle - 导入语句处理器(Mixin 继承模式)
#
# 方法版本:直接更新 trans._imported_modules / trans._from_imports
# (内部调用的模块级工具函数经上方委托函数路由到 gen 方法)
# ============================================================
@t.NoVTable
class ImportsHandle(HandlesBase.Mixin):
+59 -403
View File
@@ -27,9 +27,29 @@ import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign
#
# trans 单参模式:所有共享状态从 trans 获取,无需 11 个参数
# 注意: str = bytes = t.CChar | t.CPtr = i8*
#
# P6-E 对象化重构:全部函数已迁移为 lib.core.Gen.TranslatorGenMixin
# 的方法,本模块保留同名模块级函数作为"一行委托"(同 P2-P5 模式):
# 延迟 import Gen 取全局单例,再调用 gen 的对应方法。
# ============================================================
# ============================================================
# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式)
#
# 由 BuildPipeline/main 在 gen 创建后调用 set_global_gen 注入。
# P6-E 委托函数用本地 _g_gen(cast 成 Generator 类型)调
# TranslatorGenMixin 方法,避免函数体 import 包模块与类/模块名歧义。
# ============================================================
_g_gen: t.CVoid | t.CPtr = None
def set_global_gen(gen: t.CVoid | t.CPtr) -> None:
"""注入全局 gen 单例(BuildPipeline/main 调用)"""
global _g_gen
_g_gen = gen
# ============================================================
# _register_cexport_from_funcdef - Phase 1a 预注册 CExport/State 函数
#
@@ -39,23 +59,11 @@ import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign
# ============================================================
def _register_cexport_from_funcdef(trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""预注册 CExport/State 函数到全局表(仅注册,不生成 IR)"""
fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(node)
if fd is None or fd.name is None:
return 0
if trans is None or trans.ModuleSha1 is None:
return 0
# 检查返回类型是否有 CExport 或 State 标记
has_export: int = 0
has_state: int = 0
if fd.returns is not None:
has_export = HandlesType.has_decorator_marker(fd.returns, "CExport")
has_state = HandlesType.has_decorator_marker(fd.returns, "State")
if has_export != 0 or has_state != 0:
HandlesExprCall.register_cexport_func(trans.ModuleSha1, fd.name)
"""预注册 CExport/State 函数到全局表(仅注册,不生成 IR)(委托到 gen._register_cexport_from_funcdef)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g._register_cexport_from_funcdef(trans, node)
return 0
@@ -67,7 +75,7 @@ def _register_cexport_from_funcdef(trans: HT.Translator | t.CPtr,
# ============================================================
def translate_children(trans: HT.Translator | t.CPtr,
tree: ast.AST | t.CPtr) -> int:
"""遍历 tree.children 并翻译每个子节点
"""遍历 tree.children 并翻译每个子节点(委托到 gen.translate_children)
Args:
trans: 翻译器(含所有共享状态)
@@ -76,64 +84,11 @@ def translate_children(trans: HT.Translator | t.CPtr,
Returns:
t.CInt: 新增的变量数
"""
ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children
if ch is None:
return 0
cn_count: t.CSizeT = ch.__len__()
added_total: int = 0
for ci in range(cn_count):
child: ast.AST | t.CPtr = ch.get(ci)
if child is None: continue
kd: int = child.kind()
# _declare_only == 0 时,_translate_module_level 已预处理导入语句,
# 此处跳过避免重复处理(from_imports 条目重复)
if trans._declare_only == 0 and (kd == ast.ASTKind.Import or kd == ast.ASTKind.ImportFrom):
continue
if kd == ast.ASTKind.Import:
trans.ImportsH.HandleImport(child)
elif kd == ast.ASTKind.ImportFrom:
trans.ImportsH.HandleImportFromModule(child)
trans.ImportsH.HandleImportFromNames(child)
elif kd == ast.ASTKind.FunctionDef:
# Phase 1a 声明模式:只注册 CExport/State 函数到全局表(解决翻译顺序依赖)
# Phase 1b 全量翻译:正常翻译函数体
if trans._declare_only == 0:
added: int = HandlesFunctions.translate_function_def(trans, child)
added_total += added
elif trans._declare_only == 1:
_register_cexport_from_funcdef(trans, child)
# 预解析函数签名类型,触发泛型类特化(如 numpy 的 _empty_like
# 签名 ndarray[t.CDouble] → 特化结构体注册)。
# 1a 阶段在 mark1 之前,特化结构体的 Ty/Fields 分配在 mark1 前,
# 不被 1b 的 mark/reset 回收 → 避免 Phase2 翻译 App 文件时 UAF
# (Phase1 1b 才触发特化时,结构体 Ty/Fields 在 pool 被 reset 覆写)。
# 仅触发特化,不验证结果(1b 全量翻译时仍会重新解析)。
_prescan_funcdef_signatures(trans, child)
elif kd == ast.ASTKind.ClassDef:
# ClassDef 在模块级直接处理(不需要 builder)
# _declare_only=2(import扫描模式)时跳过,只处理 import 依赖
if trans._declare_only != 2:
HandlesClassDef.translate_class_def(trans, child)
elif trans._declare_only == 0 and trans._cur_builder is not None:
# 有 builder → 委托 HandlesBody 分派
added = HandlesBody.translate_stmt(trans, child)
added_total += added
elif kd == ast.ASTKind.AnnAssign and trans._declare_only != 2:
# 模块级 AnnAssign
# _declare_only=2(import扫描模式)时跳过
# _declare_only=1(struct注册模式)时只处理 CDefine(在 handle_module_level_var 内部判断)
# _declare_only=0(全量翻译)时处理所有模块级 AnnAssign
added = handle_module_level_var(trans, child)
added_total += added
elif trans._declare_only == 0 and kd == ast.ASTKind.Assign:
# 无 builder 的模块级 Assign → 创建全局变量(仅全量翻译模式)
added = handle_module_level_var(trans, child)
added_total += added
return added_total
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.translate_children(trans, tree)
return 0
# ============================================================
@@ -146,26 +101,11 @@ def translate_children(trans: HT.Translator | t.CPtr,
# ============================================================
def _prescan_funcdef_signatures(trans: HT.Translator | t.CPtr,
fd: ast.FunctionDef | t.CPtr) -> None:
"""预解析模块级函数签名的返回/参数类型,触发泛型类特化"""
if trans is None or fd is None:
return
pool: memhub.MemBuddy | t.CPtr = trans.Pool
if pool is None:
return
imp: str = trans._imported_modules
fi: str = trans._from_imports
if fd.returns is not None:
HandlesType.resolve_annotation_type(pool, fd.returns, imp, fi, trans)
if fd.args is not None:
ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(fd.args)
if ags.args is not None:
al: list[ast.AST | t.CPtr] | t.CPtr = ags.args
an: t.CSizeT = al.__len__()
ai: t.CSizeT
for ai in range(an):
ag: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(al.get(ai))
if ag is not None and ag.annotation is not None:
HandlesType.resolve_annotation_type(pool, ag.annotation, imp, fi, trans)
"""预解析模块级函数签名的返回/参数类型,触发泛型类特化(委托到 gen._prescan_funcdef_signatures)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
g._prescan_funcdef_signatures(trans, fd)
# ============================================================
@@ -177,81 +117,12 @@ def _prescan_funcdef_signatures(trans: HT.Translator | t.CPtr,
def _build_array_initializer_text(pool: memhub.MemBuddy | t.CPtr,
var_ty: llvmlite.LLVMType | t.CPtr,
list_node: ast.List | t.CPtr) -> str:
"""从 AST List 节点生成 LLVM IR 数组初始化器文本,None 失败"""
if var_ty is None or list_node is None:
return None
# 重新进行类型转换,确保 TPV 编译器正确识别 ast.List 类型
# (避免 init_list_node 初始值为 None 时类型推断退化为 t.CPtr)
ln: ast.List | t.CPtr = (ast.List | t.CPtr)(list_node)
if ln is None:
return None
# 从 var_ty 提取数组元素类型和数量
elem_ty: llvmlite.LLVMType | t.CPtr = None
arr_count: t.CInt = 0
match var_ty:
case llvmlite.LLVMType.Array(et, cnt):
elem_ty = et
arr_count = cnt
if elem_ty is None or arr_count <= 0:
return None
# 确定元素类型的 IR 表示
elem_ir_ty: str = "i8"
match elem_ty:
case llvmlite.LLVMType.Int(bits):
if bits == 8:
elem_ir_ty = "i8"
elif bits == 16:
elem_ir_ty = "i16"
elif bits == 32:
elem_ir_ty = "i32"
elif bits == 64:
elem_ir_ty = "i64"
# 获取列表元素(通过 ln.elts 而非 list_node.elts,确保类型正确识别)
elts: list[ast.AST | t.CPtr] | t.CPtr = ln.elts
if elts is None:
return None
elts_count: t.CSizeT = elts.__len__()
# 计算缓冲区大小: 每个元素最多 "i32 -9223372036854775808, " 约 26 字符
buf_size: t.CSizeT = 64 + elts_count * 32
buf: t.CChar | t.CPtr = pool.alloc(buf_size)
if buf is None:
return None
# 写入前缀: "["(类型前缀由 _print_global 输出,初始化器只需元素列表)
written: t.CInt = viperlib.snprintf(buf, buf_size, "[")
pos: t.CSizeT = t.CSizeT(written)
# 逐个元素写入
i: t.CSizeT = 0
while i < elts_count:
elem_node: ast.AST | t.CPtr = elts.get(i)
# 直接从 Constant 节点提取 int_val(避免 extract_cdefine_int_value 的 t.CInt 截断)
elem_val: t.CInt64T = 0
if elem_node is not None:
ek: int = elem_node.kind()
if ek == ast.ASTKind.Constant:
ec: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(elem_node)
if ec is not None and ec.const_kind == ast.CONST_INT:
elem_val = ec.int_val
elif ek == ast.ASTKind.UnaryOp:
# 负数: UnaryOp(USub, Constant)
elem_val = HandlesAnnAssign.extract_cdefine_int_value(elem_node)
if i > 0:
written = viperlib.snprintf(buf + pos, buf_size - pos, ", ")
pos += t.CSizeT(written)
written = viperlib.snprintf(buf + pos, buf_size - pos, "%s %lld", elem_ir_ty, elem_val)
pos += t.CSizeT(written)
i += 1
# 写入后缀 "]"
viperlib.snprintf(buf + pos, buf_size - pos, "]")
return buf
"""从 AST List 节点生成 LLVM IR 数组初始化器文本,None 失败(委托到 gen._build_array_initializer_text)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g._build_array_initializer_text(pool, var_ty, list_node)
return None
# ============================================================
@@ -265,31 +136,12 @@ def _build_string_ptr_initializer(pool: memhub.MemBuddy | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
var_name: str,
str_val: str) -> str:
"""为字符串字面量创建内部常量全局并返回 GEP 初始化器文本,None 失败"""
if str_val is None or var_name is None:
return None
# 构造内部字符串常量名称: .str.{var_name}
str_name_buf: t.CChar | t.CPtr = pool.alloc(64)
if str_name_buf is None:
return None
viperlib.snprintf(str_name_buf, 64, ".str.%s", var_name)
# 调用 llvmlite.create_global_string 创建字符串常量全局
str_gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.create_global_string(
pool, mod, str_name_buf, str_val)
if str_gv is None:
return None
# 生成 GEP 初始化器文本
str_len: t.CSizeT = string.strlen(str_val)
init_buf: t.CChar | t.CPtr = pool.alloc(128)
if init_buf is None:
return None
viperlib.snprintf(init_buf, 128,
"getelementptr inbounds ([%d x i8], [%d x i8]* @%s, i32 0, i32 0)",
str_len + 1, str_len + 1, str_name_buf)
return init_buf
"""为字符串字面量创建内部常量全局并返回 GEP 初始化器文本,None 失败(委托到 gen._build_string_ptr_initializer)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g._build_string_ptr_initializer(pool, mod, var_name, str_val)
return None
# ============================================================
@@ -301,158 +153,11 @@ def _build_string_ptr_initializer(pool: memhub.MemBuddy | t.CPtr,
# ============================================================
def handle_module_level_var(trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""处理模块级变量声明,创建全局变量"""
pool: memhub.MemBuddy | t.CPtr = trans.Pool
mod: llvmlite.LLVMModule | t.CPtr = trans.Module
# CDefine 注解: 编译期常量,不创建全局变量
# 注册到全局 CDefine 表供 t.CArray[elem_ty, NAME] 解析
k: int = node.kind()
if k == ast.ASTKind.AnnAssign:
aa_cd: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node)
if aa_cd is not None and aa_cd.target is not None:
if aa_cd.target.kind() == ast.ASTKind.Name:
nm_cd: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa_cd.target)
if nm_cd.id is not None:
if HandlesAnnAssign.is_cdefine_annotation(aa_cd.annotation) != 0:
# 浮点/整数自动识别注册(浮点 CDefine 如 vipermath U_M_PI)
HandlesAnnAssign._register_cdefine_from_value(
pool, nm_cd.id, aa_cd.value)
return 0
# _declare_only=1(struct注册模式)时只处理 CDefine,不创建全局变量
# CDefine 已在上面处理并返回,到这里说明不是 CDefine,直接跳过
if trans._declare_only == 1:
return 0
var_name: str = None
var_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
init_val: t.CInt64T = 0
init_kind: int = 0 # 0=none, 1=int, 2=list, 3=str
init_str_val: str = None
init_list_node: ast.List | t.CPtr = None
if k == ast.ASTKind.AnnAssign:
aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node)
if aa is None or aa.target is None:
return 0
if aa.target.kind() != ast.ASTKind.Name:
return 0
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa.target)
var_name = nm.id
# 解析类型
if aa.annotation is not None:
resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
pool, aa.annotation, trans._imported_modules, trans._from_imports, trans)
if resolved is not None:
var_ty = resolved
# 解析初始值(支持整数、列表字面量、字符串字面量)
if aa.value is not None:
val_kind: int = aa.value.kind()
if val_kind == ast.ASTKind.Constant:
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(aa.value)
if cn.const_kind == ast.CONST_INT:
init_val = cn.int_val
init_kind = 1
elif cn.const_kind == ast.CONST_STR:
init_str_val = cn.str_val
init_kind = 3
elif val_kind == ast.ASTKind.List:
init_list_node = (ast.List | t.CPtr)(aa.value)
init_kind = 2
elif k == ast.ASTKind.Assign:
asgn: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(node)
if asgn is None or asgn.targets is None:
return 0
targets: list[ast.AST | t.CPtr] | t.CPtr = asgn.targets
if targets.__len__() < 1:
return 0
t0: ast.AST | t.CPtr = targets.get(0)
if t0 is None or t0.kind() != ast.ASTKind.Name:
return 0
nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(t0)
var_name = nm2.id
if asgn.value is not None:
val_kind2: int = asgn.value.kind()
if val_kind2 == ast.ASTKind.Constant:
cn2: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(asgn.value)
if cn2.const_kind == ast.CONST_INT:
init_val = cn2.int_val
init_kind = 1
elif cn2.const_kind == ast.CONST_STR:
init_str_val = cn2.str_val
init_kind = 3
elif val_kind2 == ast.ASTKind.List:
init_list_node = (ast.List | t.CPtr)(asgn.value)
init_kind = 2
if var_name is None:
return 0
# 检查是否已注册
existing: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var(
trans.SymTab, var_name)
if existing is not None:
return 0
# 创建全局变量 @var_name
# 先确保 var_ty 中的跨模块结构体类型在模块中有 opaque 声明
# 否则 @var_name = global %"sha1.ClassName"* zeroinitializer 会报
# "use of undefined type named 'sha1.ClassName'" 错误
# (如 _mbuddy: memhub.MemManager | t.CPtr → Ptr(Struct("aeb3...MemManager")))
llvmlite.module_ensure_opaque_for_type(mod, pool, var_ty)
gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, var_name, var_ty)
if gv is None:
return 0
llvmlite.module_add_global(mod, gv)
# 设置初始值(有初始值时清除 external linkage,因为 LLVM 22+ 不允许 external global 带初始值)
gv.Linkage = None
if init_kind == 1:
# 整数初始值
init_buf: t.CChar | t.CPtr = pool.alloc(48)
if init_buf is not None:
viperlib.snprintf(init_buf, 48, "%lld", init_val)
gv.Initializer = init_buf
elif init_kind == 2:
# 列表字面量 → 数组初始化器 [N x elem_ty] [elem_ty val0, ...]
arr_init: str = _build_array_initializer_text(pool, var_ty, init_list_node)
if arr_init is not None:
gv.Initializer = arr_init
else:
gv.Initializer = "zeroinitializer"
elif init_kind == 3:
# 字符串字面量 → 创建字符串常量全局 + GEP 引用
str_init: str = _build_string_ptr_initializer(pool, mod, var_name, init_str_val)
if str_init is not None:
gv.Initializer = str_init
else:
gv.Initializer = "zeroinitializer"
else:
# 使用 zeroinitializer 而非 "0":指针类型必须用 null/zeroinitializer,
# 整数/聚合类型也兼容 zeroinitializer,避免 "integer constant must have integer type"
gv.Initializer = "zeroinitializer"
# 创建 Value 引用(@var_name, 类型为 var_ty*)
var_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, var_ty)
ref_name: t.CChar | t.CPtr = pool.alloc(64)
if ref_name is not None:
viperlib.snprintf(ref_name, 64, "@%s", var_name)
gv_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, var_ptr_ty, ref_name)
# 注册到模块作用域
if HandlesVar.define_module_var(trans.SymTab, var_name, gv_ref) == 0:
# 设置 AnnotClassName(联合类型如 Logger|t.CPtr 简化为 Ptr(i8) 时,
# 属性访问需要通过 AnnotClassName 回退到类名查找结构体)
if k == ast.ASTKind.AnnAssign:
aa_ml: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node)
if aa_ml is not None and aa_ml.annotation is not None:
cls_nm_ml: str = HandlesType.extract_class_name_from_annotation(
aa_ml.annotation, trans._imported_modules)
if cls_nm_ml is not None:
HandlesVar.set_var_annot_class_name(
trans.SymTab, var_name, cls_nm_ml)
return 1
"""处理模块级变量声明,创建全局变量(委托到 gen.handle_module_level_var)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.handle_module_level_var(trans, node)
return 0
@@ -466,7 +171,7 @@ def handle_module_level_var(trans: HT.Translator | t.CPtr,
def create_wrapper_main(trans: HT.Translator | t.CPtr,
tree: ast.AST | t.CPtr,
i32_ty: llvmlite.LLVMType | t.CPtr) -> int:
"""创建包装 main 函数并翻译所有顶层语句
"""创建包装 main 函数并翻译所有顶层语句(委托到 gen.create_wrapper_main)
Args:
trans: 翻译器(含所有共享状态)
@@ -476,57 +181,8 @@ def create_wrapper_main(trans: HT.Translator | t.CPtr,
Returns:
t.CInt: 新增的变量数
"""
pool: memhub.MemBuddy | t.CPtr = trans.Pool
mod: llvmlite.LLVMModule | t.CPtr = trans.Module
main_func: llvmlite.Function | t.CPtr = llvmlite.create_function(
pool, mod, "main", i32_ty)
if main_func is None:
VLogger.error("CreateFunction main returned NULL", "TR")
return 0
entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(
pool, main_func, "entry")
if entry_blk is None:
VLogger.error("CreateBlock returned NULL", "TR")
return 0
builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, main_func)
if builder is None:
VLogger.error("NewBuilder returned NULL", "TR")
return 0
llvmlite.position_at_end(builder, entry_blk)
# 设置当前翻译上下文(供 Handle 通过 self.Trans._cur_builder 访问)
trans._cur_func = main_func
trans._cur_builder = builder
# 预处理模块级变量:为 AnnAssign/Assign 创建 LLVM 全局变量
# 必须在 pre_scan_allocas 之前执行,否则 PreScan 会创建局部 alloca,
# 导致其他函数通过 SSA 编号引用 wrapper main 的局部变量(无效 IR)
ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children
if ch is not None:
cn_count: t.CSizeT = ch.__len__()
for ci in range(cn_count):
child: ast.AST | t.CPtr = ch.get(ci)
if child is not None:
kd: int = child.kind()
if kd == ast.ASTKind.AnnAssign or kd == ast.ASTKind.Assign:
handle_module_level_var(trans, child)
# 预扫描顶层语句:为函数内 AnnAssign 提前创建 alloca
# (模块级变量已在上面注册到模块作用域,PreScan 的 lookup_current 会跳过它们)
if ch is not None:
for ci in range(cn_count):
child: ast.AST | t.CPtr = ch.get(ci)
if child is not None:
HandlesBody.pre_scan_allocas(trans, child)
# 翻译子节点
added_total: int = translate_children(trans, tree)
# 返回 0
zero_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0)
llvmlite.build_ret(builder, zero_val)
return added_total
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.create_wrapper_main(trans, tree, i32_ty)
return 0
+28 -8
View File
@@ -15,7 +15,11 @@ import lib.core.Handles.HandlesStruct as HandlesStruct
# ============================================================
# HandlesMatch - match 语句处理(Mixin 继承模式)
# HandlesMatch - match 语句处理(P6 对象化后的委托层)
#
# NewMatchHandle 工厂已迁移为 lib.core.Gen.StmtGenMixin 的方法
# (MatchHandle 类保留:trans.MatchH 的类型,由 HandlesTranslator.
# _init_state 经 NewMatchHandle 委托创建)。
#
# 逻辑移植自 TPC 的 HandlesMatch.py,用 Viper 语法重写。
# 两条路径:
@@ -39,6 +43,22 @@ MAX_MATCH_CASES: t.CDefine = 32
SCOPE_MATCH: t.CDefine = 6
# ============================================================
# 全局 gen 单例(模块级镜像,同 HandlesStruct 模式)
#
# 由 BuildPipeline/main 在 gen 创建后调用 set_global_gen 注入。
# 委托函数用本地 _g_gen(cast 成 Generator 类型)调
# StmtGenMixin 方法,避免函数体 import 包模块与类/模块名歧义。
# ============================================================
_g_gen: t.CVoid | t.CPtr = None
def set_global_gen(gen: t.CVoid | t.CPtr) -> None:
"""注入全局 gen 单例(BuildPipeline/main 调用)"""
global _g_gen
_g_gen = gen
@t.NoVTable
class MatchHandle(HandlesBase.Mixin):
"""match 语句处理器:REnum + 非 REnum 两条路径"""
@@ -799,13 +819,13 @@ class MatchHandle(HandlesBase.Mixin):
# ============================================================
# NewMatchHandle - 工厂函数
# NewMatchHandle - 工厂函数(委托到 gen.NewMatchHandle)
# ============================================================
def NewMatchHandle(pool: memhub.MemBuddy | t.CPtr,
trans: HT.Translator | t.CPtr) -> MatchHandle | t.CPtr:
h: MatchHandle | t.CPtr = pool.alloc(MatchHandle.__sizeof__())
if h is None:
return None
string.memset(h, 0, MatchHandle.__sizeof__())
h.Trans = trans
return h
"""创建 MatchHandle 实例(委托到 gen.NewMatchHandle)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.NewMatchHandle(pool, trans)
return None
+52 -91
View File
@@ -11,7 +11,12 @@ import lib.core.Handles.HandlesVar as HandlesVar
# ============================================================
# HandlesNonlocal - nonlocal 变量访问(通过闭包 env)
# HandlesNonlocal - nonlocal 变量访问(通过闭包 env)(P6 对象化后的委托层)
#
# 全部模块级函数已迁移为 lib.core.Gen.StmtGenMixin 的方法,本模块
# 保留同名模块级函数作为"一行委托":延迟 import Gen 取全局单例
# (BuildPipeline/main 创建后 set_global_gen 注册),再调用 gen 的
# 对应方法。签名与旧函数完全一致,调用方零改动。
#
# 闭包 env 结构: {i8* ptr0, i8* ptr1, ...} (每个 nonlocal 变量一个 i8* 指针)
# 指针指向父函数中变量的 alloca(原始存储位置),父与子共享同一存储,
@@ -33,6 +38,22 @@ import lib.core.Handles.HandlesVar as HandlesVar
# ============================================================
# ============================================================
# 全局 gen 单例(模块级镜像,同 HandlesStruct 模式)
#
# 由 BuildPipeline/main 在 gen 创建后调用 set_global_gen 注入。
# 委托函数用本地 _g_gen(cast 成 Generator 类型)调
# StmtGenMixin 方法,避免函数体 import 包模块与类/模块名歧义。
# ============================================================
_g_gen: t.CVoid | t.CPtr = None
def set_global_gen(gen: t.CVoid | t.CPtr) -> None:
"""注入全局 gen 单例(BuildPipeline/main 调用)"""
global _g_gen
_g_gen = gen
# ============================================================
# _is_void_type — 判断是否为 Void 类型(非法用作变量类型)
#
@@ -41,35 +62,24 @@ import lib.core.Handles.HandlesVar as HandlesVar
# 回退为 i32,避免生成 "bitcast ... to void*" / "load void, void*" 的非法 IR。
# ============================================================
def _is_void_type(ty: llvmlite.LLVMType | t.CPtr) -> int:
"""判断是否为 Void 类型,是则返回 1,否则 0"""
if ty is None:
return 0
match ty:
case llvmlite.LLVMType.Void():
return 1
case _:
return 0
"""判断是否为 Void 类型,是则返回 1,否则 0(委托到 gen._is_void_type)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g._is_void_type(ty)
return 0
# ============================================================
# 获取或创建 _env_ptr 变量(存储 env 参数的 alloca)
# ============================================================
def get_env_ptr_var(trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
"""获取或创建 _env_ptr 变量(存储闭包 env 指针)"""
env_var: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
trans.SymTab, "_env_ptr")
if env_var is not None:
return env_var
# 创建 alloca 存储 env
pool: memhub.MemBuddy | t.CPtr = trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, i8_ptr_ty)
if alloca is None:
return None
HandlesVar.define_var(trans.SymTab, "_env_ptr", alloca)
return alloca
"""获取或创建 _env_ptr 变量(存储闭包 env 指针)(委托到 gen.get_env_ptr_var)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.get_env_ptr_var(trans)
return None
# ============================================================
@@ -79,39 +89,15 @@ def get_env_ptr_var(trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
# ============================================================
def _load_raw_var_ptr(trans: HT.Translator | t.CPtr,
name: str) -> llvmlite.Value | t.CPtr:
"""从闭包 env 加载 nonlocal 变量的原始指针(i8*)
"""从闭包 env 加载 nonlocal 变量的原始指针(i8*)(委托到 gen._load_raw_var_ptr)
返回 i8* 类型的 Value,调用方需 bitcast 为具体类型指针后 load/store。
"""
idx: int = HT.get_nonlocal_index(trans, name)
if idx < 0:
return None
pool: memhub.MemBuddy | t.CPtr = trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
i8_ptr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty)
# 1. 加载 env_ptr
env_alloca: llvmlite.Value | t.CPtr = get_env_ptr_var(trans)
if env_alloca is None:
return None
env_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, env_alloca)
if env_ptr is None:
return None
# 2. GEP to offset (idx * 8) — env 存储指针数组,每槽 8 字节
offset_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, idx * 8)
addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, env_ptr, offset_val)
if addr is None:
return None
# 3. Bitcast to i8** and load the raw pointer
ptr_addr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, addr, i8_ptr_ptr_ty)
if ptr_addr is None:
return None
return llvmlite.build_load(builder, i8_ptr_ty, ptr_addr)
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g._load_raw_var_ptr(trans, name)
return None
# ============================================================
@@ -121,29 +107,15 @@ def _load_raw_var_ptr(trans: HT.Translator | t.CPtr,
# ============================================================
def load_nonlocal_var(trans: HT.Translator | t.CPtr,
name: str) -> llvmlite.Value | t.CPtr:
"""从闭包 env 加载 nonlocal 变量值
"""从闭包 env 加载 nonlocal 变量值(委托到 gen.load_nonlocal_var)
通过 HT.get_nonlocal_type 获取变量类型,bitcast 原始指针后 load。
"""
raw_ptr: llvmlite.Value | t.CPtr = _load_raw_var_ptr(trans, name)
if raw_ptr is None:
return None
pool: memhub.MemBuddy | t.CPtr = trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
# 获取变量类型(从注册时存储的类型信息)
var_ty: llvmlite.LLVMType | t.CPtr = HT.get_nonlocal_type(trans, name)
if var_ty is None or _is_void_type(var_ty) != 0:
# Void 类型视为无效(会导致 "load void, void*" 非法 IR),回退为 i32
var_ty = llvmlite.Int32(pool)
# bitcast raw i8* to var_ty*
var_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, var_ty)
var_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, raw_ptr, var_ptr_ty)
if var_ptr is None:
return None
return llvmlite.build_load(builder, var_ty, var_ptr)
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.load_nonlocal_var(trans, name)
return None
# ============================================================
@@ -153,23 +125,12 @@ def load_nonlocal_var(trans: HT.Translator | t.CPtr,
# ============================================================
def get_nonlocal_var_ptr(trans: HT.Translator | t.CPtr,
name: str) -> llvmlite.Value | t.CPtr:
"""获取 nonlocal 变量的存储指针(var_ty*),用于 store 操作
"""获取 nonlocal 变量的存储指针(var_ty*),用于 store 操作(委托到 gen.get_nonlocal_var_ptr)
返回的指针指向父函数的 alloca,store 操作对父函数可见。
"""
raw_ptr: llvmlite.Value | t.CPtr = _load_raw_var_ptr(trans, name)
if raw_ptr is None:
return None
pool: memhub.MemBuddy | t.CPtr = trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
# 获取变量类型
var_ty: llvmlite.LLVMType | t.CPtr = HT.get_nonlocal_type(trans, name)
if var_ty is None or _is_void_type(var_ty) != 0:
# Void 类型视为无效(会导致 "bitcast ... to void*" 非法 IR),回退为 i32
var_ty = llvmlite.Int32(pool)
# bitcast raw i8* to var_ty*
var_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, var_ty)
return llvmlite.build_bitcast(builder, raw_ptr, var_ptr_ty)
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.get_nonlocal_var_ptr(trans, name)
return None
+28 -8
View File
@@ -11,10 +11,30 @@ import lib.core.Handles.HandlesVar as HandlesVar
# ============================================================
# HandlesReturn - Return 语句处理(Mixin 继承模式)
# HandlesReturn - Return 语句处理(P6 对象化后的委托层)
#
# NewReturnHandle 工厂已迁移为 lib.core.Gen.StmtGenMixin 的方法
# (ReturnHandle 类保留:trans.ReturnH 的类型,由 HandlesTranslator.
# _init_state 经 NewReturnHandle 委托创建)。
# ============================================================
# ============================================================
# 全局 gen 单例(模块级镜像,同 HandlesStruct 模式)
#
# 由 BuildPipeline/main 在 gen 创建后调用 set_global_gen 注入。
# 委托函数用本地 _g_gen(cast 成 Generator 类型)调
# StmtGenMixin 方法,避免函数体 import 包模块与类/模块名歧义。
# ============================================================
_g_gen: t.CVoid | t.CPtr = None
def set_global_gen(gen: t.CVoid | t.CPtr) -> None:
"""注入全局 gen 单例(BuildPipeline/main 调用)"""
global _g_gen
_g_gen = gen
@t.NoVTable
class ReturnHandle(HandlesBase.Mixin):
"""Return 语句处理器:继承 Mixin 获得 Trans 回指针"""
@@ -139,13 +159,13 @@ class ReturnHandle(HandlesBase.Mixin):
# ============================================================
# NewReturnHandle - 工厂函数
# NewReturnHandle - 工厂函数(委托到 gen.NewReturnHandle)
# ============================================================
def NewReturnHandle(pool: memhub.MemBuddy | t.CPtr,
trans: HT.Translator | t.CPtr) -> ReturnHandle | t.CPtr:
h: ReturnHandle | t.CPtr = pool.alloc(ReturnHandle.__sizeof__())
if h is None:
return None
string.memset(h, 0, ReturnHandle.__sizeof__())
h.Trans = trans
return h
"""创建 ReturnHandle 实例(委托到 gen.NewReturnHandle)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.NewReturnHandle(pool, trans)
return None
+59 -115
View File
@@ -39,6 +39,10 @@ import lib.Projectrans.Config as Config
# HandlesExpr - 表达式翻译
# HandlesFunctions - 函数定义处理
# 注意:str = bytes = t.CChar | t.CPtr = i8*
#
# P6-E 对象化重构:模块级 global/nonlocal 名称管理函数已迁移为
# lib.core.Gen.TranslatorGenMixin 的方法,本模块保留同名模块级
# 函数作为"一行委托"(同 P2-P5 模式)。Translator 类保留在本模块。
# ============================================================
# 常量
@@ -47,6 +51,22 @@ MAX_FUNCS: t.CDefine = 256
MAX_GLOBAL_NAMES: t.CDefine = 32
# ============================================================
# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式)
#
# 由 BuildPipeline/main 在 gen 创建后调用 set_global_gen 注入。
# P6-E 委托函数用本地 _g_gen(cast 成 Generator 类型)调
# TranslatorGenMixin 方法,避免函数体 import 包模块与类/模块名歧义。
# ============================================================
_g_gen: t.CVoid | t.CPtr = None
def set_global_gen(gen: t.CVoid | t.CPtr) -> None:
"""注入全局 gen 单例(BuildPipeline/main 调用)"""
global _g_gen
_g_gen = gen
@t.NoVTable
class Translator:
"""翻译器:管理编译状态,委托 Handles 模块执行翻译"""
@@ -397,154 +417,78 @@ class Translator:
# ============================================================
# global/nonlocal 名称管理(模块级辅助函数)
# global/nonlocal 名称管理(模块级辅助函数,委托到 gen 方法)
# ============================================================
def add_global_name(trans: HT.Translator | t.CPtr, name: str):
"""添加一个 global 变量名"""
if trans is None or name is None:
return
if trans._global_names is None:
return
# 检查是否已存在
if is_global_name(trans, name) != 0:
return
if trans._global_name_count >= MAX_GLOBAL_NAMES:
pool_err: memhub.MemBuddy | t.CPtr = trans.Pool
err_buf: str = None
if pool_err is not None:
err_buf = pool_err.alloc(256)
if err_buf is not None:
viperlib.snprintf(err_buf, 256, "global 变量数量超过上限 MAX_GLOBAL_NAMES=%d,请减少 global 声明或增大 MAX_GLOBAL_NAMES", MAX_GLOBAL_NAMES)
VLogger.error(err_buf, "ScopeDecl")
else:
VLogger.error("global 变量数量超过上限,请减少 global 声明或增大 MAX_GLOBAL_NAMES", "ScopeDecl")
return
entry_addr: t.CUInt64T = t.CUInt64T(trans._global_names) + trans._global_name_count * 8
slot_ptr: str | t.CPtr = (t.CVoid | t.CPtr)(entry_addr)
slot_ptr[0] = name
trans._global_name_count += 1
"""添加一个 global 变量名(委托到 gen.add_global_name)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
g.add_global_name(trans, name)
def is_global_name(trans: HT.Translator | t.CPtr, name: str) -> int:
"""检查 name 是否在当前函数的 global 集合中"""
if trans is None or name is None or trans._global_names is None:
return 0
for i in range(trans._global_name_count):
entry_addr: t.CUInt64T = t.CUInt64T(trans._global_names) + i * 8
slot_ptr: str | t.CPtr = (t.CVoid | t.CPtr)(entry_addr)
entry: str = slot_ptr[0]
if entry is not None:
if string.strcmp(entry, name) == 0:
return 1
"""检查 name 是否在当前函数的 global 集合中(委托到 gen.is_global_name)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.is_global_name(trans, name)
return 0
def add_nonlocal_name(trans: HT.Translator | t.CPtr, name: str,
var_ty: llvmlite.LLVMType | t.CPtr = None):
"""添加一个 nonlocal 变量名
"""添加一个 nonlocal 变量名(委托到 gen.add_nonlocal_name)
Args:
name: nonlocal 变量名
var_ty: 变量的 LLVM 类型(用于 env 指针数组方案的类型恢复,
None 时回退为 i32)
"""
if trans is None or name is None:
return
if trans._nonlocal_names is None:
return
if is_nonlocal_name(trans, name) != 0:
# 已存在:更新类型信息(可能在预扫描时类型未知,正式翻译时更新)
# _nonlocal_types 每槽 8 字节,存 LLVMType* 指针。
# 用 str|t.CPtr (i8**) 二级指针存取(与 _nonlocal_names 模式一致),
# [0] 解引用只拷贝 8 字节指针,避免值拷贝 24+ 字节 LLVMType 结构体溢出。
if var_ty is not None and trans._nonlocal_types is not None:
idx: int = get_nonlocal_index(trans, name)
if idx >= 0:
ty_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_types) + idx * 8
ty_slot: str | t.CPtr = (t.CVoid | t.CPtr)(ty_addr)
ty_slot[0] = var_ty
return
if trans._nonlocal_name_count >= MAX_GLOBAL_NAMES:
pool_err_nl: memhub.MemBuddy | t.CPtr = trans.Pool
err_buf_nl: str = None
if pool_err_nl is not None:
err_buf_nl = pool_err_nl.alloc(256)
if err_buf_nl is not None:
viperlib.snprintf(err_buf_nl, 256, "nonlocal 变量数量超过上限 MAX_GLOBAL_NAMES=%d,请减少 nonlocal 声明或增大 MAX_GLOBAL_NAMES", MAX_GLOBAL_NAMES)
VLogger.error(err_buf_nl, "ScopeDecl")
else:
VLogger.error("nonlocal 变量数量超过上限,请减少 nonlocal 声明或增大 MAX_GLOBAL_NAMES", "ScopeDecl")
return
entry_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_names) + trans._nonlocal_name_count * 8
slot_ptr: str | t.CPtr = (t.CVoid | t.CPtr)(entry_addr)
slot_ptr[0] = name
# 存储类型信息(用 str|t.CPtr = i8** 二级指针,与 _nonlocal_names 一致)
if trans._nonlocal_types is not None:
ty_addr2: t.CUInt64T = t.CUInt64T(trans._nonlocal_types) + trans._nonlocal_name_count * 8
ty_slot2: str | t.CPtr = (t.CVoid | t.CPtr)(ty_addr2)
# var_ty 为 None 时存入 i32 作为默认类型
stored_ty: llvmlite.LLVMType | t.CPtr = var_ty
if stored_ty is None:
pool: memhub.MemBuddy | t.CPtr = trans.Pool
if pool is not None:
stored_ty = llvmlite.Int32(pool)
ty_slot2[0] = stored_ty
trans._nonlocal_name_count += 1
trans._closure_env_count += 1
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
g.add_nonlocal_name(trans, name, var_ty)
def get_nonlocal_type(trans: HT.Translator | t.CPtr,
name: str) -> llvmlite.LLVMType | t.CPtr:
"""获取 nonlocal 变量的 LLVM 类型
"""获取 nonlocal 变量的 LLVM 类型(委托到 gen.get_nonlocal_type)
Returns: 找到的类型指针,找不到返回 None
"""
if trans is None or name is None or trans._nonlocal_types is None:
return None
idx: int = get_nonlocal_index(trans, name)
if idx < 0:
return None
ty_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_types) + idx * 8
ty_slot: str | t.CPtr = (t.CVoid | t.CPtr)(ty_addr)
return (llvmlite.LLVMType | t.CPtr)(ty_slot[0])
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.get_nonlocal_type(trans, name)
return None
def is_nonlocal_name(trans: HT.Translator | t.CPtr, name: str) -> int:
"""检查 name 是否在当前函数的 nonlocal 集合中"""
if trans is None or name is None or trans._nonlocal_names is None:
return 0
for i in range(trans._nonlocal_name_count):
entry_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_names) + i * 8
slot_ptr: str | t.CPtr = (t.CVoid | t.CPtr)(entry_addr)
entry: str = slot_ptr[0]
if entry is not None:
if string.strcmp(entry, name) == 0:
return 1
"""检查 name 是否在当前函数的 nonlocal 集合中(委托到 gen.is_nonlocal_name)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.is_nonlocal_name(trans, name)
return 0
def get_nonlocal_index(trans: HT.Translator | t.CPtr, name: str) -> int:
"""获取 nonlocal 变量在 env 中的索引(0-based),找不到返回 -1"""
if trans is None or name is None or trans._nonlocal_names is None:
return -1
for i in range(trans._nonlocal_name_count):
entry_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_names) + i * 8
slot_ptr: str | t.CPtr = (t.CVoid | t.CPtr)(entry_addr)
entry: str = slot_ptr[0]
if entry is not None:
if string.strcmp(entry, name) == 0:
return i
return -1
"""获取 nonlocal 变量在 env 中的索引(0-based),找不到返回 -1(委托到 gen.get_nonlocal_index)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.get_nonlocal_index(trans, name)
return 0
def clear_scope_names(trans: HT.Translator | t.CPtr):
"""清空当前函数的 global/nonlocal 名称集合(进入新函数时调用)"""
if trans is None:
return
trans._global_name_count = 0
trans._nonlocal_name_count = 0
trans._closure_env_count = 0
"""清空当前函数的 global/nonlocal 名称集合(进入新函数时调用)(委托到 gen.clear_scope_names)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
g.clear_scope_names(trans)
# 全局 mbuddy 指针
_mbuddy: memhub.MemBuddy | t.CPtr
_mbuddy: memhub.MemBuddy | t.CPtr
+143 -177
View File
@@ -6,7 +6,7 @@ import string
# ============================================================
# HandlesVar - 嵌套作用域符号表 + 变量管理
# HandlesVar - 嵌套作用域符号表 + 变量管理(P6 对象化后的委托层)
#
# 使用 Scope 链(Parent 指针)管理嵌套作用域,
# 每个作用域包含一个 VarEntry 数组(扁平化,已验证可工作)。
@@ -15,6 +15,14 @@ import string
# SCOPE_MODULE — 模块级(根作用域)
# SCOPE_FUNCTION — 函数级
# SCOPE_BLOCK — 块级(if/for/while,当前未使用块作用域)
#
# P6 对象化重构(wiki/14-oo-refactor.md):
# 全部模块级函数已迁移为 lib.core.Gen.VarGenMixin 的方法(方法化迁移,
# 无全局状态),本模块保留同名模块级函数作为"一行委托":延迟 import
# Gen 取全局单例(BuildPipeline/main 创建后 set_global_gen 注册),
# 再调用 gen 的对应方法。签名与旧函数完全一致,调用方零改动。
#
# VarEntry/Scope/SymbolTable 类型与常量保留在本模块(gen 方法签名引用)。
# ============================================================
# 作用域类型常量
@@ -68,16 +76,39 @@ class SymbolTable:
Current: Scope | t.CPtr
# ============================================================
# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式)
#
# 由 BuildPipeline/main 在 gen 创建后调用 set_global_gen 注入。
# P6 委托函数用本地 _g_gen(cast 成 Generator 类型)调
# VarGenMixin 方法,避免函数体 import 包模块与 Generator
# 类/模块名歧义。
# ============================================================
_g_gen: t.CVoid | t.CPtr = None
def set_global_gen(gen: t.CVoid | t.CPtr) -> None:
"""注入全局 gen 单例(BuildPipeline/main 调用)"""
global _g_gen
_g_gen = gen
# ============================================================
# 委托函数:延迟 import Gen 取全局单例 → 调 gen 方法
# (gen 未注册时正常流程不会发生;有返回值函数返回默认值)
# ============================================================
# ============================================================
# init_vars — 分配并清零 VarEntry 数组
# ============================================================
def init_vars(pool: memhub.MemBuddy | t.CPtr) -> VarEntry | t.CPtr:
"""分配并清零变量表数组"""
size: t.CSizeT = MAX_VARS * VarEntry.__sizeof__()
vars_ptr: VarEntry | t.CPtr = pool.alloc(size)
if vars_ptr is not None:
string.memset(vars_ptr, 0, size)
return vars_ptr
"""分配并清零变量表数组(委托到 gen.init_vars)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.init_vars(pool)
return None
# ============================================================
@@ -86,16 +117,11 @@ def init_vars(pool: memhub.MemBuddy | t.CPtr) -> VarEntry | t.CPtr:
def find_var(vars_ptr: VarEntry | t.CPtr,
var_count: int,
name: str) -> llvmlite.Value | t.CPtr:
"""在变量表中按名称查找"""
if name is None or vars_ptr is None:
return None
entry_size: t.CSizeT = VarEntry.__sizeof__()
for i in range(var_count):
entry_addr: t.CUInt64T = t.CUInt64T(vars_ptr) + i * entry_size
entry: VarEntry | t.CPtr = (VarEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
if entry.Name is not None and entry.Used != 0:
if string.strcmp(entry.Name, name) == 0:
return entry.Alloca
"""在变量表中按名称查找(委托到 gen.find_var)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.find_var(vars_ptr, var_count, name)
return None
@@ -105,16 +131,11 @@ def find_var(vars_ptr: VarEntry | t.CPtr,
def find_var_entry(vars_ptr: VarEntry | t.CPtr,
var_count: int,
name: str) -> VarEntry | t.CPtr:
"""在变量表中按名称查找,返回 VarEntry 或 None"""
if name is None or vars_ptr is None:
return None
entry_size: t.CSizeT = VarEntry.__sizeof__()
for i in range(var_count):
entry_addr: t.CUInt64T = t.CUInt64T(vars_ptr) + i * entry_size
entry: VarEntry | t.CPtr = (VarEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
if entry.Name is not None and entry.Used != 0:
if string.strcmp(entry.Name, name) == 0:
return entry
"""在变量表中按名称查找,返回 VarEntry 或 None(委托到 gen.find_var_entry)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.find_var_entry(vars_ptr, var_count, name)
return None
@@ -123,15 +144,11 @@ def find_var_entry(vars_ptr: VarEntry | t.CPtr,
# ============================================================
def lookup_var_entry(symtab: SymbolTable | t.CPtr,
name: str) -> VarEntry | t.CPtr:
"""从当前作用域逐级向上查找变量,返回 VarEntry 或 None"""
if symtab is None or name is None:
return None
scope: Scope | t.CPtr = symtab.Current
while scope is not None:
result: VarEntry | t.CPtr = find_var_entry(scope.Vars, scope.VarCount, name)
if result is not None:
return result
scope = scope.Parent
"""从当前作用域逐级向上查找变量,返回 VarEntry 或 None(委托到 gen.lookup_var_entry)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.lookup_var_entry(symtab, name)
return None
@@ -145,13 +162,11 @@ def lookup_var_entry(symtab: SymbolTable | t.CPtr,
def set_var_annot_class_name(symtab: SymbolTable | t.CPtr,
name: str,
class_name: str) -> int:
"""设置变量的原始类型注解类名,返回 0=成功 / 1=失败"""
if symtab is None or name is None:
return 1
entry: VarEntry | t.CPtr = lookup_var_entry(symtab, name)
if entry is None:
return 1
entry.AnnotClassName = class_name
"""设置变量的原始类型注解类名,返回 0=成功 / 1=失败(委托到 gen.set_var_annot_class_name)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.set_var_annot_class_name(symtab, name, class_name)
return 0
@@ -164,13 +179,11 @@ def set_var_annot_class_name(symtab: SymbolTable | t.CPtr,
# ============================================================
def set_var_ptr_element(symtab: SymbolTable | t.CPtr,
name: str) -> int:
"""标记变量为 ptr_element 类型,返回 0=成功 / 1=失败"""
if symtab is None or name is None:
return 1
entry: VarEntry | t.CPtr = lookup_var_entry(symtab, name)
if entry is None:
return 1
entry.IsPtrElement = 1
"""标记变量为 ptr_element 类型,返回 0=成功 / 1=失败(委托到 gen.set_var_ptr_element)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.set_var_ptr_element(symtab, name)
return 0
@@ -181,17 +194,11 @@ def add_var(vars_ptr: VarEntry | t.CPtr,
var_count: int,
name: str,
alloca: llvmlite.Value | t.CPtr) -> int:
"""添加变量到变量表"""
if name is None or alloca is None or vars_ptr is None:
return 1
if var_count >= MAX_VARS:
return 1
entry_size: t.CSizeT = VarEntry.__sizeof__()
entry_addr: t.CUInt64T = t.CUInt64T(vars_ptr) + var_count * entry_size
entry: VarEntry | t.CPtr = (VarEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
entry.Name = name
entry.Alloca = alloca
entry.Used = 1
"""添加变量到变量表(委托到 gen.add_var)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.add_var(vars_ptr, var_count, name, alloca)
return 0
@@ -206,14 +213,16 @@ def add_var(vars_ptr: VarEntry | t.CPtr,
# ============================================================
def _alloca_at_entry(builder: llvmlite.IRBuilder | t.CPtr,
ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr:
"""在函数入口块生成 alloca,返回 alloca 值
"""在函数入口块生成 alloca,返回 alloca 值(委托到 gen._alloca_at_entry)
使用 llvmlite.build_alloca_at_entry 在入口块终止指令之前插入 alloca,
确保所有 alloca 在入口块,避免支配性违规。
"""
if builder is None or ty is None:
return None
return llvmlite.build_alloca_at_entry(builder, ty)
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g._alloca_at_entry(builder, ty)
return None
# ============================================================
@@ -225,16 +234,12 @@ def get_or_create_var(pool: memhub.MemBuddy | t.CPtr,
var_count: int,
name: str,
ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr:
"""查找或创建变量 alloca"""
existing: llvmlite.Value | t.CPtr = find_var(vars_ptr, var_count, name)
if existing is not None:
return existing
alloca: llvmlite.Value | t.CPtr = _alloca_at_entry(builder, ty)
if alloca is None:
return None
if add_var(vars_ptr, var_count, name, alloca) != 0:
return None
return alloca
"""查找或创建变量 alloca(委托到 gen.get_or_create_var)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.get_or_create_var(pool, builder, vars_ptr, var_count, name, ty)
return None
# ============================================================
@@ -243,41 +248,24 @@ def get_or_create_var(pool: memhub.MemBuddy | t.CPtr,
def _create_scope(pool: memhub.MemBuddy | t.CPtr,
parent: Scope | t.CPtr,
kind: int) -> Scope | t.CPtr:
"""创建并初始化作用域节点"""
scope: Scope | t.CPtr = pool.alloc(Scope.__sizeof__())
if scope is None:
return None
string.memset(scope, 0, Scope.__sizeof__())
scope.Parent = parent
scope.Vars = init_vars(pool)
scope.VarCount = 0
scope.Kind = kind
if scope.Vars is None:
return None
return scope
"""创建并初始化作用域节点(委托到 gen._create_scope)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g._create_scope(pool, parent, kind)
return None
# ============================================================
# init_symbol_table — 创建符号表(含模块级根作用域)
# ============================================================
def init_symbol_table(pool: memhub.MemBuddy | t.CPtr) -> SymbolTable | t.CPtr:
"""创建并初始化符号表,包含模块级根作用域"""
if pool is None:
return None
symtab: SymbolTable | t.CPtr = pool.alloc(SymbolTable.__sizeof__())
if symtab is None:
return None
string.memset(symtab, 0, SymbolTable.__sizeof__())
symtab.Pool = pool
# 创建根作用域(模块级)
root: Scope | t.CPtr = _create_scope(pool, None, SCOPE_MODULE)
if root is None:
return None
symtab.Root = root
symtab.Current = root
return symtab
"""创建并初始化符号表,包含模块级根作用域(委托到 gen.init_symbol_table)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.init_symbol_table(pool)
return None
# ============================================================
@@ -285,24 +273,23 @@ def init_symbol_table(pool: memhub.MemBuddy | t.CPtr) -> SymbolTable | t.CPtr:
# ============================================================
def enter_scope(symtab: SymbolTable | t.CPtr,
kind: int) -> Scope | t.CPtr:
"""进入新作用域,返回新创建的作用域"""
if symtab is None:
return None
pool: memhub.MemBuddy | t.CPtr = symtab.Pool
scope: Scope | t.CPtr = _create_scope(pool, symtab.Current, kind)
if scope is None:
return None
symtab.Current = scope
return scope
"""进入新作用域,返回新创建的作用域(委托到 gen.enter_scope)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.enter_scope(symtab, kind)
return None
# ============================================================
# exit_scope — 退出当前作用域
# ============================================================
def exit_scope(symtab: SymbolTable | t.CPtr):
"""退出当前作用域,恢复到父作用域"""
if symtab is not None and symtab.Current is not None:
symtab.Current = symtab.Current.Parent
"""退出当前作用域,恢复到父作用域(委托到 gen.exit_scope)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
g.exit_scope(symtab)
# ============================================================
@@ -311,16 +298,12 @@ def exit_scope(symtab: SymbolTable | t.CPtr):
def define_var(symtab: SymbolTable | t.CPtr,
name: str,
alloca: llvmlite.Value | t.CPtr) -> int:
"""在当前作用域定义变量,返回 0 成功"""
if symtab is None or name is None or alloca is None:
return 1
scope: Scope | t.CPtr = symtab.Current
if scope is None:
return 1
ret: int = add_var(scope.Vars, scope.VarCount, name, alloca)
if ret == 0:
scope.VarCount = scope.VarCount + 1
return ret
"""在当前作用域定义变量,返回 0 成功(委托到 gen.define_var)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.define_var(symtab, name, alloca)
return 0
# ============================================================
@@ -329,16 +312,12 @@ def define_var(symtab: SymbolTable | t.CPtr,
def define_module_var(symtab: SymbolTable | t.CPtr,
name: str,
alloca: llvmlite.Value | t.CPtr) -> int:
"""在模块作用域定义变量,返回 0 成功"""
if symtab is None or name is None or alloca is None:
return 1
scope: Scope | t.CPtr = symtab.Root
if scope is None:
return 1
ret: int = add_var(scope.Vars, scope.VarCount, name, alloca)
if ret == 0:
scope.VarCount = scope.VarCount + 1
return ret
"""在模块作用域定义变量,返回 0 成功(委托到 gen.define_module_var)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.define_module_var(symtab, name, alloca)
return 0
# ============================================================
@@ -346,16 +325,11 @@ def define_module_var(symtab: SymbolTable | t.CPtr,
# ============================================================
def lookup_var(symtab: SymbolTable | t.CPtr,
name: str) -> llvmlite.Value | t.CPtr:
"""从当前作用域逐级向上查找变量,返回 alloca 或 None"""
if symtab is None or name is None:
return None
scope: Scope | t.CPtr = symtab.Current
while scope is not None:
result: llvmlite.Value | t.CPtr = find_var(
scope.Vars, scope.VarCount, name)
if result is not None:
return result
scope = scope.Parent
"""从当前作用域逐级向上查找变量,返回 alloca 或 None(委托到 gen.lookup_var)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.lookup_var(symtab, name)
return None
@@ -364,13 +338,12 @@ def lookup_var(symtab: SymbolTable | t.CPtr,
# ============================================================
def lookup_current(symtab: SymbolTable | t.CPtr,
name: str) -> llvmlite.Value | t.CPtr:
"""仅在当前作用域查找变量"""
if symtab is None or name is None:
return None
scope: Scope | t.CPtr = symtab.Current
if scope is None:
return None
return find_var(scope.Vars, scope.VarCount, name)
"""仅在当前作用域查找变量(委托到 gen.lookup_current)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.lookup_current(symtab, name)
return None
# ============================================================
@@ -378,13 +351,12 @@ def lookup_current(symtab: SymbolTable | t.CPtr,
# ============================================================
def lookup_module_var(symtab: SymbolTable | t.CPtr,
name: str) -> llvmlite.Value | t.CPtr:
"""在模块作用域查找变量"""
if symtab is None or name is None:
return None
scope: Scope | t.CPtr = symtab.Root
if scope is None:
return None
return find_var(scope.Vars, scope.VarCount, name)
"""在模块作用域查找变量(委托到 gen.lookup_module_var)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.lookup_module_var(symtab, name)
return None
# ============================================================
@@ -395,17 +367,14 @@ def lookup_module_var(symtab: SymbolTable | t.CPtr,
# - 函数内代码:无 global 声明时 AnnAssign 应创建局部变量(Python 语义)
# ============================================================
def is_module_scope(symtab: SymbolTable | t.CPtr) -> int:
"""判断当前作用域是否为模块级作用域(Current == Root)
"""判断当前作用域是否为模块级作用域(Current == Root,委托到 gen.is_module_scope)
Returns: 1=模块级作用域, 0=函数内作用域
"""
if symtab is None:
return 0
if symtab.Root is None or symtab.Current is None:
return 0
# 比较指针:Current 与 Root 相同则为模块级
if t.CUInt64T(symtab.Current) == t.CUInt64T(symtab.Root):
return 1
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.is_module_scope(symtab)
return 0
@@ -417,12 +386,9 @@ def get_or_create_sym(symtab: SymbolTable | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
name: str,
ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr:
"""查找或创建变量 alloca(在当前作用域)"""
existing: llvmlite.Value | t.CPtr = lookup_current(symtab, name)
if existing is not None:
return existing
alloca: llvmlite.Value | t.CPtr = _alloca_at_entry(builder, ty)
if alloca is None:
return None
define_var(symtab, name, alloca)
return alloca
"""查找或创建变量 alloca(在当前作用域,委托到 gen.get_or_create_sym)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.get_or_create_sym(symtab, pool, builder, name, ty)
return None
+28 -8
View File
@@ -13,7 +13,11 @@ import lib.core.Handles.HandlesBody as HandlesBody
# ============================================================
# HandlesWhile - while 循环语句处理(Mixin 继承模式)
# HandlesWhile - while 循环语句处理(P6 对象化后的委托层)
#
# NewWhileHandle 工厂已迁移为 lib.core.Gen.StmtGenMixin 的方法
# (WhileHandle 类保留:trans.WhileH 的类型,由 HandlesTranslator.
# _init_state 经 NewWhileHandle 委托创建)。
#
# 翻译 while 语句为 LLVM IR 控制流:
# br label %cond
@@ -28,6 +32,22 @@ import lib.core.Handles.HandlesBody as HandlesBody
# ============================================================
# ============================================================
# 全局 gen 单例(模块级镜像,同 HandlesStruct 模式)
#
# 由 BuildPipeline/main 在 gen 创建后调用 set_global_gen 注入。
# 委托函数用本地 _g_gen(cast 成 Generator 类型)调
# StmtGenMixin 方法,避免函数体 import 包模块与类/模块名歧义。
# ============================================================
_g_gen: t.CVoid | t.CPtr = None
def set_global_gen(gen: t.CVoid | t.CPtr) -> None:
"""注入全局 gen 单例(BuildPipeline/main 调用)"""
global _g_gen
_g_gen = gen
@t.NoVTable
class WhileHandle(HandlesBase.Mixin):
"""while 循环语句处理器:继承 Mixin 获得 Trans 回指针"""
@@ -123,13 +143,13 @@ class WhileHandle(HandlesBase.Mixin):
# ============================================================
# NewWhileHandle - 工厂函数
# NewWhileHandle - 工厂函数(委托到 gen.NewWhileHandle)
# ============================================================
def NewWhileHandle(pool: memhub.MemBuddy | t.CPtr,
trans: HT.Translator | t.CPtr) -> WhileHandle | t.CPtr:
h: WhileHandle | t.CPtr = pool.alloc(WhileHandle.__sizeof__())
if h is None:
return None
string.memset(h, 0, WhileHandle.__sizeof__())
h.Trans = trans
return h
"""创建 WhileHandle 实例(委托到 gen.NewWhileHandle)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.NewWhileHandle(pool, trans)
return None
+28
View File
@@ -21,6 +21,19 @@ import lib.core.Handles.HandlesExprCall as HandlesExprCall
import lib.core.Handles.HandlesFunctions as HandlesFunctions
import lib.core.Handles.HandlesClassDef as HandlesClassDef
import lib.core.Handles.HandlesType as HandlesType
import lib.core.Handles.HandlesImports as HandlesImports
import lib.core.Handles.HandlesBody as HandlesBody
import lib.core.Handles.HandlesIf as HandlesIf
import lib.core.Handles.HandlesWhile as HandlesWhile
import lib.core.Handles.HandlesFor as HandlesFor
import lib.core.Handles.HandlesReturn as HandlesReturn
import lib.core.Handles.HandlesNonlocal as HandlesNonlocal
import lib.core.Handles.HandlesMatch as HandlesMatch
import lib.core.Handles.HandlesEnum as HandlesEnum
import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign
import lib.core.Handles.HandlesAugAssign as HandlesAugAssign
import lib.core.Handles.HandlesVar as HandlesVar
import lib.core.Handles.HandlesMain as HandlesMain
import lib.core.BuildPipeline as BuildPipeline
import lib.core.IncludesScanner as IncludesScanner
import lib.core.StubMerger as StubMerger
@@ -99,6 +112,21 @@ def main() -> int:
HandlesExprCall.set_global_gen(gen)
HandlesFunctions.set_global_gen(gen)
HandlesClassDef.set_global_gen(gen)
# P6: 注入语句/赋值/变量/导入/翻译驱动模块的单例
HandlesImports.set_global_gen(gen)
HandlesBody.set_global_gen(gen)
HandlesIf.set_global_gen(gen)
HandlesWhile.set_global_gen(gen)
HandlesFor.set_global_gen(gen)
HandlesReturn.set_global_gen(gen)
HandlesNonlocal.set_global_gen(gen)
HandlesMatch.set_global_gen(gen)
HandlesEnum.set_global_gen(gen)
HandlesAnnAssign.set_global_gen(gen)
HandlesAugAssign.set_global_gen(gen)
HandlesVar.set_global_gen(gen)
HandlesTranslator.set_global_gen(gen)
HandlesMain.set_global_gen(gen)
# 初始化 VLogger 并打印启动日志
log: VLogger.Logger | t.CPtr = VLogger.get_logger()