Files
ViperC/App/lib/core/Gen/ExprGenCdef.vp
T
TermiNexus f2bfe82834 fix(gen): Gargantua 编译修复——循环 alloca 入入口块 + 跨模块 CDefine 拼路径/门控
- translate_for 循环计数 alloca 改回 _alloca_at_entry(入口块生成),
  修复分支内 for 循环(Terminal _cmd_cd 的 for i in range(1,64))产生
  "Instruction does not dominate all uses! %197 = alloca i32"
- _build_source_path_from_sha1 优先用条目存储的 IncDir(绝对 includes 根,
  多目录支持)拼路径,修复 Gargantua 多 includes 目录下 stdint.vp 拼到
  首目录 ViperOS → 文件不存在 → XMOD-CD 误报
- translate_name_value 对 ALL_CAPS 名先查 lookup_var:当前作用域已有
  同名变量(如 Gargantua CAM/FWD/RIGHT/UP 模块全局)则跳过跨模块
  CDefine 查找,避免 star-import 误命中 stdint
2026-08-26 16:14:05 +08:00

1091 lines
55 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import t, c
from stdint import *
import ast
import llvmlite
import memhub
import string
import stdio
import stdlib
import viperlib
import w32.fileio as fileio
import lib.core.CompilerFactory as CompilerFactory
import lib.core.Handles.HandlesBase as HandlesBase
import lib.core.Handles.HandlesTranslator as HT
import lib.core.Handles.HandlesExpr as HandlesExpr
import lib.core.Handles.HandlesExprCall as HandlesExprCall
import lib.Stub.StubMerger as StubMerger
import lib.core.VLogger as VLogger
import lib.Projectrans.Config as Config
import lib.Projectrans.Utils as Utils
import lib.core.Gen.ExprGenBase as ExprGenBase
import lib.Stub.StubMerger.StubMergerCollect as StubMergerCollect
import lib.Stub.StubMerger.StubMergerStore as StubMergerStore
# ============================================================
# ExprGenCdef - ExprGenMixin 拆分(阶段 D):跨模块 CDefine 查找
#
# 继承 ExprGenBase(1 级,TPV self 调用仅支持 1 级父类)。
# 跨 Mixin 调用统一走 HandlesExpr 委托(经 _g_gen)。
# @t.NoVTable:静态绑定。
# ============================================================
@t.NoVTable
class ExprGenCdef(ExprGenBase.ExprGenBase):
"""跨模块 CDefine 查找"""
# ============================================================
# _build_source_path_from_sha1 - 通过 SHA1 从存储器构建源 .vp/.py 文件路径
#
# .vpi 文件可能未生成(Phase1 未输出 vpi),此时回退读取源 .py 文件。
# 从 StubMerger 全局存储器查找 SHA1 对应的相对路径,
# 根据 rel_path 前缀选择基础目录:
# - rel_path 以 "lib/" 开头 → App 源文件,用 {Config.SourceDir}/{rel_path}
# - 其他 → includes 文件,用 {Config.IncludesDir}/{rel_path}
#
# Returns:
# stdlib.malloc 分配的路径字符串(调用者负责 free),None 失败
# ============================================================
def _build_source_path_from_sha1(self, sha1: str) -> str:
"""通过 SHA1 从全局存储器构建源 .py 文件路径"""
if sha1 is None:
return None
if Config.IncludesDir is None:
return None
# 从 StubMerger 全局存储器获取相对路径数组
rel_arr_ptr: bytes = StubMergerStore.GetSha1StoreRelArrPtr()
count: int = StubMergerStore.GetSha1StoreCount()
if rel_arr_ptr is None or count <= 0:
return None
sha1_arr_ptr: bytes = StubMergerStore.GetSha1StoreArrPtr()
if sha1_arr_ptr is None:
return None
# 遍历查找匹配的 SHA1
idx_s: int = -1
for i in range(count):
sidx: t.CSizeT = t.CSizeT(i) * 17
cur_sha1: str = sha1_arr_ptr + sidx
if cur_sha1[0] == '\0':
continue
if string.strcmp(cur_sha1, sha1) == 0:
idx_s = i
break
if idx_s < 0:
return None
# 获取相对路径(MAX_REL_PATH_LEN=256,避免跨模块 CDefine 解析问题)
MAX_RPL: t.CSizeT = 256
ridx: t.CSizeT = t.CSizeT(idx_s) * MAX_RPL
rel_path: str = rel_arr_ptr + ridx
if rel_path[0] == '\0':
return None
# 选择基础目录(优先级):
# 1. 条目存储的 includes 根目录 IncDir(绝对路径,多 includes 目录
# 支持):PopulateSha1MapStore 按每条目保存所属根目录,跨模块
# CDefine 查找回退读源时按 IncDir 直接拼路径,避免"首 includes
# 目录"启发式对非首目录文件失效(Gargantua 多 includes 目录:
# stdint.vp 属于 TransPyC/includes,而 IncludesDir=首目录 ViperOS
# → 拼错路径 → 文件不存在 → XMOD-CD 误报根因)。
# 2. rel_path 前缀启发式:以 "lib/" 开头 → App 源文件(SourceDir);
# "includes/" 开头 → includes 文件(去掉前缀);其他无前缀路径
# (如 VKernel 的 "drivers/core/cpu/cpu.vp")先试 SourceDir,
# 文件不存在再试 IncludesDir。
base_dir: str = None
rel_used: str = rel_path
inc_arr_ptr: bytes = StubMergerStore.GetSha1StoreIncdirArrPtr()
if inc_arr_ptr is not None:
iidx: t.CSizeT = t.CSizeT(idx_s) * StubMerger.MAX_INC_DIR_LEN
inc_dir: str = inc_arr_ptr + iidx
if inc_dir[0] != '\0':
base_dir = inc_dir
if base_dir is None and string.strlen(rel_path) >= 4:
if (rel_path[0] == 'l' and rel_path[1] == 'i' and
rel_path[2] == 'b' and rel_path[3] == '/'):
base_dir = Config.SourceDir if Config.SourceDir is not None else Config.IncludesDir
if base_dir is None and string.strlen(rel_path) >= 9:
if (rel_path[0] == 'i' and rel_path[1] == 'n' and
rel_path[2] == 'c' and rel_path[3] == 'l' and
rel_path[4] == 'u' and rel_path[5] == 'd' and
rel_path[6] == 'e' and rel_path[7] == 's' and
rel_path[8] == '/'):
rel_used = rel_path + 9
base_dir = Config.IncludesDir
if base_dir is None:
base_dir = Config.SourceDir if Config.SourceDir is not None else Config.IncludesDir
# 构建完整路径: {base_dir}/{rel_used}
base_len: t.CSizeT = string.strlen(base_dir)
rel_len: t.CSizeT = string.strlen(rel_used)
path_len: t.CSizeT = base_len + rel_len + 2
buf: str = stdlib.malloc(path_len)
if buf is None:
return None
viperlib.snprintf(buf, path_len, "%s/%s", base_dir, rel_used)
# 存在性检查:SourceDir 下不存在且 IncludesDir 不同 → 重试 IncludesDir
pf_chk: fileio.File | t.CPtr = fileio.File(buf, fileio.MODE.R)
if pf_chk.closed:
pf_chk.close()
if Config.IncludesDir is not None and base_dir != Config.IncludesDir:
stdlib.free(buf)
base_len2: t.CSizeT = string.strlen(Config.IncludesDir)
path_len2: t.CSizeT = base_len2 + rel_len + 2
buf = stdlib.malloc(path_len2)
if buf is None:
return None
viperlib.snprintf(buf, path_len2, "%s/%s", Config.IncludesDir, rel_used)
pf_chk2: fileio.File | t.CPtr = fileio.File(buf, fileio.MODE.R)
if pf_chk2.closed:
pf_chk2.close()
stdlib.free(buf)
return None
pf_chk2.close()
else:
stdlib.free(buf)
return None
else:
pf_chk.close()
return buf
# ============================================================
# _lookup_cross_module_cdefine - 跨模块查找 CDefine 常量
#
# 当当前模块的 CDefine 表中找不到某个 Name 时,从 from_imports
# 解析出源模块,再从该模块的 pyi 文件中解析 CDefine 常量值。
# 找到后缓存到当前模块的 CDefine 表中,避免重复查找。
#
# pyi 文件格式: "NAME: t.CDefine = value"
# ============================================================
def _lookup_cross_module_cdefine(self, pool: memhub.MemBuddy | t.CPtr,
name: str,
from_imports: str,
imported_modules: str = None,
depth: int = 0,
node: ast.AST | t.CPtr = None) -> t.CInt64T:
"""跨模块查找 CDefine 常量,返回值(64 位)或 -1(未找到)
查找顺序:
1. from_imports 精确匹配(from X import NAME)
2. from_imports star 回退(from X import *)
3. imported_modules 遍历(import X):当通过 import X 导入模块时,
模块中定义的 CDefine 常量可通过此路径找到(如方法签名默认参数引用)
depth: 递归深度(子模块递归/imported_modules 遍历的内部调用递增)。
node: 触发查找的 AST 节点(递归内传 None,line 0;顶层调用点传实际节点)。
"""
# 递归深度守卫:子模块递归(from .X import NAME re-export 链)与
# imported_modules 遍历组合可能形成循环(模块间互相 from import),
# 无上限时无限递归 → 每次递归 pool.alloc 缓冲(rc_sub_buf/rc_full_mod/
# rc_fi/im_buf/sub_fi)→ O(n²) 累积 → 主池 1.5GB OOM
# (NewAstTest CONST_INT 单次查找 14593 次调用,fi 恒为 CONST_INT:ast)。
# 正常跨模块 CDefine 查找深度 < 8(如 ast → ast.base),32 上限 fail-fast
# 暴露循环 import 链(而非静默 OOM)。报错带 node 行号 + 当前递归模块链。
if depth > 32:
err_buf: str = pool.alloc(256)
if err_buf is not None:
viperlib.snprintf(err_buf, 256,
"跨模块 CDefine 查找递归过深(疑似模块循环 import/re-export): %s (depth=%d fi=%s)",
name, depth,
from_imports if from_imports is not None else "(nil)")
self.Gen.TypeGenErr.fatal_error(node, err_buf, "InternalCompilerError")
self.Gen.TypeGenErr.fatal_error(node,
"跨模块 CDefine 查找递归过深(疑似模块循环 import/re-export)", "InternalCompilerError")
# 入口处清零标志,确保所有早退路径(return -1)都返回"未找到"状态
# 避免递归调用时前一次成功的标志残留导致误判
self.Gen.TypeGenCDef.set_cdefine_found(0)
if name is None:
return -1
if from_imports is None:
from_imports = ""
# 1. 从 from_imports 查找名称对应的模块名
# 先尝试精确匹配(allow_star_fallback=0),避免 CDefine 常量被 star import 误导
mod_name_raw: str = self.Gen.ImportsGen.lookup_from_import(from_imports, name, 0)
if mod_name_raw is None:
# 精确匹配失败:尝试 star import 回退
mod_name_raw = self.Gen.ImportsGen.lookup_from_import(from_imports, name, 1)
# 截断模块名到 NUL 结尾:lookup_from_import 返回指向 from_imports 内部的
# 指针(非 NUL 结尾,后随空格分隔的其他条目,如 "ast CONST_STR:ast ...")。
# 不截断会污染 base_mod:strlen 读到整个 from_imports 末尾 → rc_full_mod
# 每层累积整个列表 + ".base"(dump:ast.base.base.base 无限递归根因),
# 且缓存 key 错乱("CONST_INT@ast CONST_STR:ast ...")无法命中。
# 与 _lookup_sha1_from_modname_raw 的截断逻辑一致(空格/冒号/NUL 分隔)。
base_mod: str = None
if mod_name_raw is not None:
mbl: t.CSizeT = 0
while mod_name_raw[mbl] != ' ' and mod_name_raw[mbl] != '\0' \
and mod_name_raw[mbl] != ':':
mbl += 1
mb_buf: str = pool.alloc(mbl + 1)
if mb_buf is not None:
mi2: t.CSizeT
for mi2 in range(mbl):
mb_buf[mi2] = mod_name_raw[mi2]
mb_buf[mbl] = '\0'
base_mod = mb_buf
while base_mod is not None and base_mod[0] == '.':
base_mod = base_mod + 1
# 跨模块 CDefine 查找缓存(perm_pool 永久,跨文件复用):
# 首次查找成功后结果缓存,后续文件(含 reset_to(mark2)/模块切换)直接命中,
# 避免 CONST_INT 跨模块递归查找反复触发(NewAstTest OOM 根因——
# 14593 次调用全部重复递归 ast → ast.base → ...)。
# key = "name@源模块"(源模块维度,用去点后的 base_mod 保证一致),
# 保持模块隔离:不同源模块的同名 CDefine 值不同时不串值。
# 仅 ALL_CAPS 全局唯一宏名才进入本函数(_is_cdefine_name_pattern 已过滤)。
xkey_buf: str = None
if base_mod is not None:
xk_len: t.CSizeT = string.strlen(name) + string.strlen(base_mod) + 2
xkey_buf = pool.alloc(xk_len)
if xkey_buf is not None:
viperlib.snprintf(xkey_buf, xk_len, "%s@%s", name, base_mod)
xval: str = self.Gen.TypeGenCDef.lookup_xmod_cdefine(xkey_buf)
if self.Gen.TypeGenCDef.is_cdefine_found() != 0:
if self.Gen.TypeGenCDef.is_cdefine_str() != 0:
self.Gen.TypeGenCDef.register_cdefine_string(pool, name, xval)
elif self.Gen.TypeGenCDef.is_cdefine_double() != 0:
xd_v: double = string.atof(xval)
self.Gen.TypeGenCDef.register_cdefine_double(pool, name, xd_v)
else:
xv_i: t.CInt64T = string.atoll(xval)
self.Gen.TypeGenCDef.register_cdefine_constant(pool, name, xv_i)
return string.atoll(xval)
# 2. from_imports 查找失败:直接回退到 imported_modules 遍历(步骤 9.6)
# 注意:star fallback 可能返回错误模块(如 stdint),常量实际不在其中,
# 步骤 9.6 会在该模块查找失败后继续遍历 imported_modules
if mod_name_raw is None:
# from_imports 完全没有匹配(精确和 star 都失败)
# 直接进入 imported_modules 遍历(步骤 9.6)
if imported_modules is None:
return -1
# 跳过 from_imports 模块读取,直接走步骤 9.6 的 imported_modules 遍历
# 设置 result_found=0 跳过步骤 3-9,直接到 9.6
self.Gen.TypeGenCDef.set_cdefine_found(0)
# 直接遍历 imported_modules
im_len: t.CSizeT = string.strlen(imported_modules)
im_ci: t.CSizeT = 0
while im_ci < im_len:
while im_ci < im_len and imported_modules[im_ci] == ' ':
im_ci += 1
if im_ci >= im_len:
break
im_start: t.CSizeT = im_ci
while im_ci < im_len and imported_modules[im_ci] != ' ':
im_ci += 1
im_end: t.CSizeT = im_ci
im_nlen: t.CSizeT = im_end - im_start
if im_nlen > 0 and im_nlen < 256:
im_buf: str = pool.alloc(im_nlen + 1)
if im_buf is not None:
mk: t.CSizeT = 0
while mk < im_nlen:
im_buf[mk] = imported_modules[im_start + mk]
mk += 1
im_buf[im_nlen] = '\0'
sub_fi: str = pool.alloc(im_nlen + 3)
if sub_fi is not None:
sub_fi[0] = '*'
sub_fi[1] = ':'
mk2: t.CSizeT = 0
while mk2 < im_nlen:
sub_fi[2 + mk2] = im_buf[mk2]
mk2 += 1
sub_fi[2 + im_nlen] = '\0'
sub_val: t.CInt64T = self._lookup_cross_module_cdefine(pool, name, sub_fi, None, depth + 1, node)
if self.Gen.TypeGenCDef.is_cdefine_found() != 0:
return sub_val
return -1
# 2. 截断模块名 → 去前导点 → 精确+后缀查找 SHA1(复用 HandlesExprCall 公共逻辑)
sha1: str = self.Gen.CallGenBase._lookup_sha1_from_modname_raw(pool, mod_name_raw)
if sha1 is None:
return -1
# 5. 获取 temp_dir
temp_dir: str = self.Gen.TypeGenBase.get_temp_dir()
if temp_dir is None:
return -1
# 6. 构建 vpi 文件路径
td_len: t.CSizeT = string.strlen(temp_dir)
pyi_path: str = StubMergerCollect._sliced_path(temp_dir, td_len, sha1, "vpi")
if pyi_path is None:
return -1
# 7. 读取 vpi 文件;若不存在或内容过短(空 stub)则回退读取源 .vp/.py 文件
PYI_READ_BUF_SIZE: t.CSizeT = 65536
pyi_buf: bytes = stdlib.malloc(PYI_READ_BUF_SIZE)
if pyi_buf is None:
stdlib.free(pyi_path)
return -1
pf: fileio.File | t.CPtr = fileio.File(pyi_path, fileio.MODE.R)
need_py_fallback: int = 0
bytes_read: LONG = 0
if pf.closed:
# .vpi 文件不存在:回退读取源 .vp/.py 文件
need_py_fallback = 1
else:
bytes_read = pf.read_all(pyi_buf, PYI_READ_BUF_SIZE)
pf.close()
# vpi 内容过短(< 10 字节)视为空 stub,回退 .py
if bytes_read < 10:
need_py_fallback = 1
else:
if bytes_read < PYI_READ_BUF_SIZE:
pyi_buf[bytes_read] = 0
else:
pyi_buf[PYI_READ_BUF_SIZE - 1] = 0
# vpi(存根签名文件)中的 CDefine 声明可能只带名字不带值
# (Converter 旧版只对 CONST_INT/BOOL 等输出 "= value",CONST_FLOAT
# 等不输出 → numpy 的 pi/e 在 stub 中无值),真正的值在源
# .vp/.py 文件中。旧启发式"vpi 中任一 CDefine 带值 → 不读源"是错的:
# 模块同时含 int CDefine(带值,如 numpy.MAX_NDIM=4)与 float
# CDefine(无值,如 pi)时,int 行让 cd_sig=1 而漏回退源 → pi
# 解析失败 → 退化 @pi 全局指针 → float<->ptr 报错(NumpyTest 根因)。
# 改为按目标名判定:仅当 vpi 中 name 的 CDefine 行带值时才信任
# vpi,否则(name 行无值 / name 不在 vpi / 整个 vpi 无带值 CDefine)
# 一律回退读源文件。
cd_sig: int = 0
name_has_val: int = 0
cs_name_len: t.CSizeT = string.strlen(name)
cs_total: t.CSizeT = string.strlen(pyi_buf)
cs_i: t.CSizeT = 0
while cs_i + 9 < cs_total:
if (pyi_buf[cs_i] == 't' and pyi_buf[cs_i + 1] == '.' and
pyi_buf[cs_i + 2] == 'C' and pyi_buf[cs_i + 3] == 'D' and
pyi_buf[cs_i + 4] == 'e' and pyi_buf[cs_i + 5] == 'f' and
pyi_buf[cs_i + 6] == 'i' and pyi_buf[cs_i + 7] == 'n' and
pyi_buf[cs_i + 8] == 'e'):
# 检查该行剩余部分是否有 '='(带值声明才在 vpi 中匹配)
cd_eq: int = 0
cs_j: t.CSizeT = cs_i + 9
while cs_j < cs_total and pyi_buf[cs_j] != '\n':
if pyi_buf[cs_j] == '=':
cd_eq = 1
break
cs_j += 1
if cd_eq != 0:
cd_sig = 1
# 定位该行行首,检查是否以 "name:" 开头(目标名带值)
cs_line_start: t.CSizeT = cs_i
while cs_line_start > 0 and pyi_buf[cs_line_start - 1] != '\n':
cs_line_start -= 1
if cs_i - cs_line_start >= cs_name_len + 1:
nm_ok: int = 1
for ki2 in range(cs_name_len):
if pyi_buf[cs_line_start + ki2] != name[ki2]:
nm_ok = 0
break
if nm_ok == 1 and pyi_buf[cs_line_start + cs_name_len] == ':':
name_has_val = 1
cs_i += 1
if cd_sig == 0 or name_has_val == 0:
need_py_fallback = 1
stdlib.free(pyi_path)
if need_py_fallback != 0:
# 从 SHA1 存储器查找相对路径,构建 {base_dir}/{rel_path}
src_path: str = self._build_source_path_from_sha1(sha1)
if src_path is None:
# 存储器中找不到 SHA1 = 编译器 bug(Phase1/Phase2 未填充存储器)
# 报错终止,不静默返回 -1(避免后续生成错误的 @UNDEFINED 全局变量引用)
err_buf: str = pool.alloc(512)
if err_buf is not None:
viperlib.snprintf(err_buf, 512,
"跨模块 CDefine 查找失败:SHA1 %s 不在存储器中(base_mod=%s name=%s)。"
"Phase1/Phase2 未正确填充 PopulateSha1MapStore/AppendToSha1MapStore",
sha1, base_mod, name)
VLogger.error(err_buf, "XMOD-CD")
stdlib.free(pyi_buf)
return -1
pf = fileio.File(src_path, fileio.MODE.R)
stdlib.free(src_path)
if pf.closed:
stdlib.free(pyi_buf)
return -1
bytes_read = pf.read_all(pyi_buf, PYI_READ_BUF_SIZE)
pf.close()
if bytes_read <= 0:
stdlib.free(pyi_buf)
return -1
if bytes_read < PYI_READ_BUF_SIZE:
pyi_buf[bytes_read] = 0
else:
pyi_buf[PYI_READ_BUF_SIZE - 1] = 0
# 8. 在 pyi_buf 中查找 "name: t.CDefine = value" 行
# 格式: NAME: t.CDefine = value
name_len: t.CSizeT = string.strlen(name)
total_len: t.CSizeT = string.strlen(pyi_buf)
pos: t.CSizeT = 0
result_val: t.CInt64T = 0
result_found: int = 0
res_is_double: int = 0
res_is_str: int = 0
while pos < total_len:
# 找到行首
line_start: t.CSizeT = pos
# 找到行尾
while pos < total_len and pyi_buf[pos] != '\n':
pos += 1
line_len: t.CSizeT = pos - line_start
if pos < total_len:
pos += 1 # 跳过 '\n'
# 检查行是否以 "name:" 开头
if line_len < name_len + 1:
continue
match_ok: int = 1
for ki in range(name_len):
if pyi_buf[line_start + ki] != name[ki]:
match_ok = 0
break
if match_ok == 0:
continue
if pyi_buf[line_start + name_len] != ':':
continue
# 检查行是否包含 "t.CDefine"
# 在行中查找 "t.CDefine"
has_cdefine: int = 0
ci: t.CSizeT = line_start + name_len + 1
while ci + 8 <= line_start + line_len:
if (pyi_buf[ci] == 't' and pyi_buf[ci + 1] == '.' and
pyi_buf[ci + 2] == 'C' and pyi_buf[ci + 3] == 'D' and
pyi_buf[ci + 4] == 'e' and pyi_buf[ci + 5] == 'f' and
pyi_buf[ci + 6] == 'i' and pyi_buf[ci + 7] == 'n' and
pyi_buf[ci + 8] == 'e'):
has_cdefine = 1
break
ci += 1
if has_cdefine == 0:
continue
# 找到 "=" 后面的值
eq_pos: t.CSizeT = line_start + name_len + 1
while eq_pos < line_start + line_len and pyi_buf[eq_pos] != '=':
eq_pos += 1
if eq_pos >= line_start + line_len:
continue
eq_pos += 1 # 跳过 '='
# 跳过空格
while eq_pos < line_start + line_len and pyi_buf[eq_pos] == ' ':
eq_pos += 1
# 检查是否是 t.CUnsignedLong(...) / t.CLong(...) / t.CInt(...) 等类型构造函数
# 格式: t.CUnsignedLong(-11) / t.CUnsignedLong(0xFFFFFFFF)
# 如果是,跳过 "t.CXxx(" 前缀,解析括号内的值,忽略结尾 ')'
is_type_ctor: int = 0
if eq_pos + 2 < line_start + line_len:
if pyi_buf[eq_pos] == 't' and pyi_buf[eq_pos + 1] == '.':
# 找到 '(' 的位置
paren_pos: t.CSizeT = eq_pos + 2
while paren_pos < line_start + line_len and pyi_buf[paren_pos] != '(':
paren_pos += 1
if paren_pos < line_start + line_len and pyi_buf[paren_pos] == '(':
is_type_ctor = 1
eq_pos = paren_pos + 1 # 跳过 '('
# 跳过括号内可能的前导空格
while eq_pos < line_start + line_len and pyi_buf[eq_pos] == ' ':
eq_pos += 1
# 括号包裹标记:(1 << 23) / (512) / (A | B)
is_paren_expr: int = 0
if eq_pos < line_start + line_len and pyi_buf[eq_pos] == '(':
is_paren_expr = 1
eq_pos += 1
while eq_pos < line_start + line_len and pyi_buf[eq_pos] == ' ':
eq_pos += 1
# === 解析左操作数 token(数字 / hex / 负号 / 名称) ===
# 负号标记
is_neg: int = 0
if eq_pos < line_start + line_len and pyi_buf[eq_pos] == '-':
is_neg = 1
eq_pos += 1
val_str_start: t.CSizeT = eq_pos
val_str_len: t.CSizeT = 0
is_hex: int = 0
is_float_val: int = 0
is_name_val: int = 0
is_str_val: int = 0
# 字符串值(如 ZLIB_VERSION: t.CDefine = "1.3.2"):读引号内内容。
# 跨模块读回此前不支持引号 → val_str_len=0 被跳过 → "跨模块 CDefine
# 未找到"(test_pyzlib.vp pyzlib.ZLIB_VERSION 根因)
if eq_pos < line_start + line_len and pyi_buf[eq_pos] == '"':
is_str_val = 1
eq_pos += 1 # 跳过开引号
val_str_start = eq_pos
while eq_pos < line_start + line_len and pyi_buf[eq_pos] != '"':
val_str_len += 1
eq_pos += 1
if eq_pos < line_start + line_len and pyi_buf[eq_pos] == '"':
eq_pos += 1 # 跳过闭引号
if eq_pos + 1 < line_start + line_len:
if pyi_buf[eq_pos] == '0' and (pyi_buf[eq_pos + 1] == 'x' or pyi_buf[eq_pos + 1] == 'X'):
is_hex = 1
val_str_len = 2
eq_pos += 2
elif (pyi_buf[eq_pos] >= 'A' and pyi_buf[eq_pos] <= 'Z') or \
(pyi_buf[eq_pos] >= 'a' and pyi_buf[eq_pos] <= 'z') or \
pyi_buf[eq_pos] == '_':
is_name_val = 1
while eq_pos < line_start + line_len:
c_tk: t.CChar = pyi_buf[eq_pos]
if (c_tk >= 'A' and c_tk <= 'Z') or (c_tk >= 'a' and c_tk <= 'z') or \
(c_tk >= '0' and c_tk <= '9') or c_tk == '_':
val_str_len += 1
eq_pos += 1
else:
break
# 数字/hex 字符续读(字符串值已整体读取,跳过)
while eq_pos < line_start + line_len and is_name_val == 0 and is_str_val == 0:
ch: t.CChar = pyi_buf[eq_pos]
if is_hex == 1:
if ((ch >= '0' and ch <= '9') or
(ch >= 'a' and ch <= 'f') or
(ch >= 'A' and ch <= 'F')):
val_str_len += 1
eq_pos += 1
else:
break
else:
if ch >= '0' and ch <= '9':
val_str_len += 1
eq_pos += 1
elif ch == '.' and is_float_val == 0:
# 浮点值:'3.14159'('.' 只允许一次)
is_float_val = 1
val_str_len += 1
eq_pos += 1
else:
break
if val_str_len == 0 and is_str_val == 0:
continue
# 复制左 token 到缓冲区
val_buf: str = pool.alloc(val_str_len + 1)
if val_buf is None:
continue
for vi in range(val_str_len):
val_buf[vi] = pyi_buf[val_str_start + vi]
val_buf[val_str_len] = '\0'
# 左 token 求值
lval: t.CInt64T = 0
l_is_double: int = 0
ldbl: double = 0.0
if is_str_val != 0:
# 字符串 CDefine(如 ZLIB_VERSION = "1.3.2"):注册字符串值
# (含空串 ""),result_found 标记 + res_is_str 供尾部跳过整数
# 注册/缓存(否则 register_cdefine_constant 把字符串当 0 整数)
self.Gen.TypeGenCDef.register_cdefine_string(pool, name, val_buf)
result_val = 0
result_found = 1
res_is_str = 1
elif is_name_val != 0:
# True/False 布尔字面量 → 1/0(对齐 TPC:bool 在 CDefine 语境按整数处理)
if string.strcmp(val_buf, "True") == 0:
lval = 1
elif string.strcmp(val_buf, "False") == 0:
lval = 0
else:
# 名称引用:查当前 CDefine 表(如 FOREGROUND_COMBO = FOREGROUND_RED)
lval = self.Gen.TypeGenCDef.lookup_cdefine_constant(val_buf)
if self.Gen.TypeGenCDef.is_cdefine_found() == 0:
# 名称未注册:该行无法求值,跳过
continue
elif is_hex == 1:
# 手动解析十六进制(跳过 0x 前缀)——64 位累加,
# 0xFFFFFFFF=4294967295 保持全精度(常量生成端 i32 截断回 -1)
hex_result: t.CInt64T = 0
hex_buf: str = val_buf + 2 # 跳过 "0x"
for hi in range(val_str_len - 2):
hc: t.CChar = hex_buf[hi]
hd: int = 0
if hc >= '0' and hc <= '9':
hd = hc - '0'
elif hc >= 'a' and hc <= 'f':
hd = hc - 'a' + 10
elif hc >= 'A' and hc <= 'F':
hd = hc - 'A' + 10
else:
break
hex_result = hex_result * 16 + hd
lval = hex_result
elif is_float_val != 0:
l_is_double = 1
ldbl = string.atof(val_buf)
lval = string.atoll(val_buf)
else:
lval = string.atoll(val_buf)
if is_neg != 0:
lval = -lval
if l_is_double != 0:
ldbl = -ldbl
# 跳过空格,检查是否有二元运算符
while eq_pos < line_start + line_len and pyi_buf[eq_pos] == ' ':
eq_pos += 1
# 解析运算符(<< >> | & ^ + - * /)
cd_op: int = 0
if eq_pos + 1 < line_start + line_len:
if pyi_buf[eq_pos] == '<' and pyi_buf[eq_pos + 1] == '<':
cd_op = 1 # LShift
eq_pos += 2
elif pyi_buf[eq_pos] == '>' and pyi_buf[eq_pos + 1] == '>':
cd_op = 2 # RShift
eq_pos += 2
if cd_op == 0 and eq_pos < line_start + line_len:
if pyi_buf[eq_pos] == '|':
cd_op = 3 # BitOr
eq_pos += 1
elif pyi_buf[eq_pos] == '&':
cd_op = 4 # BitAnd
eq_pos += 1
elif pyi_buf[eq_pos] == '^':
cd_op = 5 # BitXor
eq_pos += 1
elif pyi_buf[eq_pos] == '+':
cd_op = 6 # Add
eq_pos += 1
elif pyi_buf[eq_pos] == '-':
cd_op = 7 # Sub
eq_pos += 1
elif pyi_buf[eq_pos] == '*':
cd_op = 8 # Mult
eq_pos += 1
elif pyi_buf[eq_pos] == '/':
cd_op = 9 # Div
eq_pos += 1
if cd_op != 0:
# === 解析右操作数 token ===
while eq_pos < line_start + line_len and pyi_buf[eq_pos] == ' ':
eq_pos += 1
r_neg: int = 0
if eq_pos < line_start + line_len and pyi_buf[eq_pos] == '-':
r_neg = 1
eq_pos += 1
r_start: t.CSizeT = eq_pos
r_len: t.CSizeT = 0
r_hex: int = 0
r_name: int = 0
if eq_pos + 1 < line_start + line_len:
if pyi_buf[eq_pos] == '0' and (pyi_buf[eq_pos + 1] == 'x' or pyi_buf[eq_pos + 1] == 'X'):
r_hex = 1
r_len = 2
eq_pos += 2
elif (pyi_buf[eq_pos] >= 'A' and pyi_buf[eq_pos] <= 'Z') or \
(pyi_buf[eq_pos] >= 'a' and pyi_buf[eq_pos] <= 'z') or \
pyi_buf[eq_pos] == '_':
r_name = 1
while eq_pos < line_start + line_len:
c_r: t.CChar = pyi_buf[eq_pos]
if (c_r >= 'A' and c_r <= 'Z') or (c_r >= 'a' and c_r <= 'z') or \
(c_r >= '0' and c_r <= '9') or c_r == '_':
r_len += 1
eq_pos += 1
else:
break
while eq_pos < line_start + line_len and r_name == 0:
c_r2: t.CChar = pyi_buf[eq_pos]
if r_hex == 1:
if ((c_r2 >= '0' and c_r2 <= '9') or
(c_r2 >= 'a' and c_r2 <= 'f') or
(c_r2 >= 'A' and c_r2 <= 'F')):
r_len += 1
eq_pos += 1
else:
break
else:
if c_r2 >= '0' and c_r2 <= '9':
r_len += 1
eq_pos += 1
else:
break
if r_len == 0:
# 运算符后无右操作数:无法求值,跳过该行
continue
r_buf: str = pool.alloc(r_len + 1)
if r_buf is None:
continue
for r_i in range(r_len):
r_buf[r_i] = pyi_buf[r_start + r_i]
r_buf[r_len] = '\0'
rval: t.CInt64T = 0
if r_name != 0:
# True/False 布尔字面量 → 1/0
if string.strcmp(r_buf, "True") == 0:
rval = 1
elif string.strcmp(r_buf, "False") == 0:
rval = 0
else:
rval = self.Gen.TypeGenCDef.lookup_cdefine_constant(r_buf)
if self.Gen.TypeGenCDef.is_cdefine_found() == 0:
# 名称未注册:无法求值,跳过该行
continue
elif r_hex != 0:
rhex_v: t.CInt64T = 0
rh_buf: str = r_buf + 2
for rh_i in range(r_len - 2):
rc: t.CChar = rh_buf[rh_i]
rd: int = 0
if rc >= '0' and rc <= '9':
rd = rc - '0'
elif rc >= 'a' and rc <= 'f':
rd = rc - 'a' + 10
elif rc >= 'A' and rc <= 'F':
rd = rc - 'A' + 10
else:
break
rhex_v = rhex_v * 16 + rd
rval = rhex_v
else:
rval = string.atoll(r_buf)
if r_neg != 0:
rval = -rval
# 计算二元表达式结果(对齐 TPC ConstEvaluator)
if cd_op == 1:
result_val = lval << rval
elif cd_op == 2:
result_val = lval >> rval
elif cd_op == 3:
result_val = lval | rval
elif cd_op == 4:
result_val = lval & rval
elif cd_op == 5:
result_val = lval ^ rval
elif cd_op == 6:
result_val = lval + rval
elif cd_op == 7:
result_val = lval - rval
elif cd_op == 8:
result_val = lval * rval
else:
if rval == 0:
continue
result_val = lval // rval
result_found = 1
break
else:
# 单值(无运算符):括号内单值如 (512) / (-11) 也走这里
if is_paren_expr != 0:
while eq_pos < line_start + line_len and pyi_buf[eq_pos] == ' ':
eq_pos += 1
if eq_pos < line_start + line_len and pyi_buf[eq_pos] == ')':
eq_pos += 1
if is_float_val != 0:
# 浮点 CDefine(如 U_M_PI = 3.14159...):
# 值缓存为 double(register_cdefine_double),供调用处生成
# double 常量;整数部分供 int 路径使用(is_cdefine_double 标志)。
self.Gen.TypeGenCDef.register_cdefine_double(pool, name, ldbl)
result_val = lval
result_found = 1
res_is_double = 1
else:
result_val = lval
result_found = 1
break
# 9.5 如果当前模块文件中没找到,递归查找子模块
# 处理 from .X import NAME 和 from .X import * 的情况
# 例如 ast.__init__.vp 中 from .base import CONST_INT, ...
# 需要递归查找 ast.base 子模块中的 CONST_INT: t.CDefine = 1
if result_found == 0:
# base_mod 已在函数开头计算(mod_name_raw 去前导点),
# 供子模块递归构建 "base_mod.X" 全名。
name_len_rc: t.CSizeT = string.strlen(name)
rc_pos: t.CSizeT = 0
while rc_pos < total_len and result_found == 0:
# 找到行首
rc_line_start: t.CSizeT = rc_pos
# 找到行尾
while rc_pos < total_len and pyi_buf[rc_pos] != '\n':
rc_pos += 1
rc_line_len: t.CSizeT = rc_pos - rc_line_start
if rc_pos < total_len:
rc_pos += 1
# 检查行是否以 "from ." 开头(相对导入子模块)
if rc_line_len < 12:
continue
if pyi_buf[rc_line_start] != 'f' or pyi_buf[rc_line_start+1] != 'r' or \
pyi_buf[rc_line_start+2] != 'o' or pyi_buf[rc_line_start+3] != 'm' or \
pyi_buf[rc_line_start+4] != ' ' or pyi_buf[rc_line_start+5] != '.':
continue
# 提取子模块名(从 rc_line_start+6 开始,到空格/tab 为止)
rc_sub_start: t.CSizeT = rc_line_start + 6
rc_sub_end: t.CSizeT = rc_sub_start
while rc_sub_end < rc_line_start + rc_line_len and \
pyi_buf[rc_sub_end] != ' ' and pyi_buf[rc_sub_end] != '\t':
rc_sub_end += 1
rc_sub_len: t.CSizeT = rc_sub_end - rc_sub_start
if rc_sub_len == 0:
continue
# 检查行是否包含 "import"
rc_has_import: int = 0
rc_ipos: t.CSizeT = rc_sub_end
while rc_ipos + 6 <= rc_line_start + rc_line_len:
if pyi_buf[rc_ipos] == 'i' and pyi_buf[rc_ipos+1] == 'm' and \
pyi_buf[rc_ipos+2] == 'p' and pyi_buf[rc_ipos+3] == 'o' and \
pyi_buf[rc_ipos+4] == 'r' and pyi_buf[rc_ipos+5] == 't':
rc_has_import = 1
break
rc_ipos += 1
if rc_has_import == 0:
continue
# 检查 NAME 是否在导入列表中,或导入是 *
# 处理多行导入:from .X import (... NAME, ...)
# 从 "import" 之后扫描,如果有 "(" 则扫描到 ")" 为止
rc_imp_start: t.CSizeT = rc_ipos + 6
rc_star: int = 0
rc_name_match: int = 0
# 确定扫描范围:单行或跨行(括号内)
rc_scan_end: t.CSizeT = rc_line_start + rc_line_len
rc_has_paren: int = 0
rc_pp: t.CSizeT = rc_imp_start
while rc_pp < rc_line_start + rc_line_len:
if pyi_buf[rc_pp] == '(':
rc_has_paren = 1
break
if pyi_buf[rc_pp] == '*':
rc_star = 1
rc_pp += 1
if rc_has_paren != 0:
# 多行导入:从 "(" 之后扫描到 ")" 为止
rc_scan_end = rc_pp + 1
rc_paren_closed: int = 0
rc_sp: t.CSizeT = rc_pp + 1
while rc_sp < total_len and rc_paren_closed == 0:
if pyi_buf[rc_sp] == ')':
rc_paren_closed = 1
rc_scan_end = rc_sp
break
rc_sp += 1
if rc_paren_closed == 0:
rc_scan_end = total_len
# 在 rc_imp_start 到 rc_scan_end 范围内查找 NAME 和 *
rc_cpos: t.CSizeT = rc_imp_start
while rc_cpos < rc_scan_end:
rc_ch: t.CChar = pyi_buf[rc_cpos]
if rc_ch == '*':
rc_star = 1
# 检查 NAME 是否匹配(作为完整单词)
if rc_cpos + name_len_rc <= rc_scan_end:
rc_match: int = 1
rc_ki: t.CSizeT
for rc_ki in range(name_len_rc):
if pyi_buf[rc_cpos + rc_ki] != name[rc_ki]:
rc_match = 0
break
if rc_match == 1:
# 检查前字符是否是非标识符字符
rc_before_ok: int = 0
if rc_cpos == rc_imp_start:
rc_before_ok = 1
else:
rc_before_ch: t.CChar = pyi_buf[rc_cpos - 1]
if rc_before_ch == ' ' or rc_before_ch == '\t' or \
rc_before_ch == '(' or rc_before_ch == ',' or \
rc_before_ch == '\n' or rc_before_ch == '\r':
rc_before_ok = 1
# 检查后字符是否是非标识符字符
rc_after_ok: int = 0
rc_after_pos: t.CSizeT = rc_cpos + name_len_rc
if rc_after_pos >= rc_scan_end:
rc_after_ok = 1
else:
rc_after_ch: t.CChar = pyi_buf[rc_after_pos]
if rc_after_ch == ' ' or rc_after_ch == '\t' or \
rc_after_ch == ')' or rc_after_ch == ',' or \
rc_after_ch == '\r' or rc_after_ch == '\n':
rc_after_ok = 1
if rc_before_ok == 1 and rc_after_ok == 1:
rc_name_match = 1
rc_cpos += 1
if rc_star == 0 and rc_name_match == 0:
continue
# 复制子模块名到新缓冲区(pyi_buf + rc_sub_start 不是 NUL 结尾)
rc_sub_buf: str = pool.alloc(rc_sub_len + 1)
if rc_sub_buf is None:
continue
rc_si: t.CSizeT
for rc_si in range(rc_sub_len):
rc_sub_buf[rc_si] = pyi_buf[rc_sub_start + rc_si]
rc_sub_buf[rc_sub_len] = '\0'
# 构建完整子模块名 base_mod.X
rc_full_len: t.CSizeT = string.strlen(base_mod) + 1 + rc_sub_len + 1
rc_full_mod: str = pool.alloc(rc_full_len)
if rc_full_mod is None:
continue
viperlib.snprintf(rc_full_mod, rc_full_len, "%s.%s", base_mod, rc_sub_buf)
# 防循环:若 base_mod 已以 "."+rc_sub_buf 结尾(如 ast.base 再拼
# .base → ast.base.base),说明子模块递归在重复追加同一模块段
# (模块间循环 re-export / 后缀匹配容错命中自身),跳过该次递归
# (NewAstTest CONST_INT 查找 dump:ast.base.base.base 无限增长根因)。
rc_blen: t.CSizeT = string.strlen(base_mod)
if rc_blen > rc_sub_len + 1:
rc_tail: str = base_mod + (rc_blen - rc_sub_len)
if rc_tail[0] == '.' and \
string.strncmp(rc_tail + 1, rc_sub_buf, rc_sub_len) == 0:
continue
# 构建临时 from_imports "name:full_mod"
rc_fi_len: t.CSizeT = name_len_rc + 1 + string.strlen(rc_full_mod) + 1
rc_fi: str = pool.alloc(rc_fi_len)
if rc_fi is None:
continue
viperlib.snprintf(rc_fi, rc_fi_len, "%s:%s", name, rc_full_mod)
# 递归调用查找子模块
rc_sub_val: int = self._lookup_cross_module_cdefine(pool, name, rc_fi, None, depth + 1, node)
if self.Gen.TypeGenCDef.is_cdefine_found() != 0:
result_val = rc_sub_val
result_found = 1
stdlib.free(pyi_buf)
# 9.6 from_imports star fallback 模块中未找到:回退到 imported_modules 遍历
# 当 `from stdint import *` 导致 star fallback 返回 stdint,但目标常量
# (如 SHARE_READ)实际在 `import w32.fileio` 导入的模块中时,
# 需要遍历 imported_modules 逐个查找
if result_found == 0 and imported_modules is not None:
im2_len: t.CSizeT = string.strlen(imported_modules)
im2_ci: t.CSizeT = 0
while im2_ci < im2_len and result_found == 0:
while im2_ci < im2_len and imported_modules[im2_ci] == ' ':
im2_ci += 1
if im2_ci >= im2_len:
break
im2_start: t.CSizeT = im2_ci
while im2_ci < im2_len and imported_modules[im2_ci] != ' ':
im2_ci += 1
im2_end: t.CSizeT = im2_ci
im2_nlen: t.CSizeT = im2_end - im2_start
if im2_nlen > 0 and im2_nlen < 256:
im2_buf: str = pool.alloc(im2_nlen + 1)
if im2_buf is not None:
mk3: t.CSizeT = 0
while mk3 < im2_nlen:
im2_buf[mk3] = imported_modules[im2_start + mk3]
mk3 += 1
im2_buf[im2_nlen] = '\0'
sub_fi2: str = pool.alloc(im2_nlen + 3)
if sub_fi2 is not None:
sub_fi2[0] = '*'
sub_fi2[1] = ':'
mk4: t.CSizeT = 0
while mk4 < im2_nlen:
sub_fi2[2 + mk4] = im2_buf[mk4]
mk4 += 1
sub_fi2[2 + im2_nlen] = '\0'
sub_val2: t.CInt64T = self._lookup_cross_module_cdefine(pool, name, sub_fi2, None, depth + 1, node)
if self.Gen.TypeGenCDef.is_cdefine_found() != 0:
result_val = sub_val2
result_found = 1
# 10. 缓存到当前模块的 CDefine 表中,并写入跨模块 perm_pool 缓存
# 浮点 CDefine 已在匹配循环中 register_cdefine_double 缓存
# (res_is_double=1),此处只缓存整数 CDefine,避免覆盖 double。
if result_found != 0:
if res_is_str != 0:
# 字符串 CDefine:值已在匹配循环 register_cdefine_string(val_buf
# 是命中行的字符串内容,pool 分配跨函数有效),此处只写跨模块缓存
if base_mod is not None:
ck_len_s: t.CSizeT = string.strlen(name) + string.strlen(base_mod) + 2
ckey_s: str = pool.alloc(ck_len_s)
if ckey_s is not None:
viperlib.snprintf(ckey_s, ck_len_s, "%s@%s", name, base_mod)
self.Gen.TypeGenCDef.register_xmod_cdefine(ckey_s, val_buf, 0, 1)
elif res_is_double == 0:
self.Gen.TypeGenCDef.register_cdefine_constant(pool, name, result_val)
# 跨模块查找缓存(perm_pool 永久,跨文件复用):整数
# key 与入口查询一致:"name@源模块"(用截断后的 base_mod,
# 与 mod_name_raw 一致——两者都是去点后的模块名,保证 key 匹配)
if base_mod is not None:
ck_len: t.CSizeT = string.strlen(name) + string.strlen(base_mod) + 2
ckey_buf: str = pool.alloc(ck_len)
if ckey_buf is not None:
viperlib.snprintf(ckey_buf, ck_len, "%s@%s", name, base_mod)
cbuf_i: str = pool.alloc(32)
if cbuf_i is not None:
viperlib.snprintf(cbuf_i, 32, "%lld", result_val)
self.Gen.TypeGenCDef.register_xmod_cdefine(ckey_buf, cbuf_i, 0, 0)
else:
# 浮点:从本地表取回 %.17g 文本,写入跨模块缓存(保精度)
if base_mod is not None:
ck_len2: t.CSizeT = string.strlen(name) + string.strlen(base_mod) + 2
ckey2: str = pool.alloc(ck_len2)
if ckey2 is not None:
viperlib.snprintf(ckey2, ck_len2, "%s@%s", name, base_mod)
dval_cc: double = self.Gen.TypeGenCDef.lookup_cdefine_double(name)
if self.Gen.TypeGenCDef.is_cdefine_double() != 0:
cbuf_d: str = pool.alloc(64)
if cbuf_d is not None:
stdio.snprintf(cbuf_d, 64, "%.17g", dval_cc)
self.Gen.TypeGenCDef.register_xmod_cdefine(ckey2, cbuf_d, 1, 0)
self.Gen.TypeGenCDef.set_cdefine_found(1)
else:
self.Gen.TypeGenCDef.set_cdefine_found(0)
return result_val
# ============================================================
# _is_cdefine_name_pattern - 检查名字是否符合 CDefine 命名约定
#
# CDefine 常量(如 FOREGROUND_GREEN, STD_OUTPUT_HANDLE, SCOPE_MODULE)
# 都遵循 ALL_CAPS 约定:仅含大写字母 A-Z、数字 0-9、下划线 _,
# 且至少含一个大写字母。
#
# Python 关键字(match, if, for)和变量名(self, pool, builder)
# 都含小写字母,不会匹配,从而避免 fail-fast 误报。
#
# 返回: 1=符合 CDefine 命名约定, 0=不符合
# ============================================================
def _is_cdefine_name_pattern(self, name: str) -> int:
"""检查名字是否符合 CDefine 命名约定(全大写+下划线+数字)"""
if name is None:
return 0
has_upper: int = 0
i: t.CSizeT = 0
while name[i] != '\0':
c: t.CChar = name[i]
if c >= 'a' and c <= 'z':
return 0
if c >= 'A' and c <= 'Z':
has_upper = 1
i += 1
return has_upper
# ============================================================
# 翻译变量引用(Name 节点)→ load
# ============================================================
def _const_int_for_cdefine(self, pool: memhub.MemBuddy | t.CPtr,
value: t.CInt64T) -> llvmlite.Value | t.CPtr:
"""CDefine 整数常量 → LLVM 常量(对齐 TPC TypeConvert 的 64 位升级)
规则(与 translate_constant 的 i32 溢出升级一致,但保留 0xFFFFFFFF 语义):
值超 32 位无符号范围(> 0xFFFFFFFF)→ i64 全精度常量
(如 sys.maxsize = 9223372036854775807);
否则 → i32 常量,内部 t.CInt 截断(0xFFFFFFFF → -1,保持既有
INVALID_HANDLE_VALUE / WAIT_FAILED = -1 语义不变,避免 i32 4294967295
生成非法 LLVM IR 文本 "i32 4294967295")。
注意:不能用 `value > 4294967295` 直接比较——TPV 编译自身源码时大数字面量
(> 0x7FFFFFFF)在字面量层回绕成 i32(sext 后等于 -1),阈值恒成立导致所有
正数 CDefine 都被升 i64(INVALID_FILE_ATTRIBUTES 0xFFFFFFFF 从 i32 -1 变
i64 4294967295 → 与 _get_attrs 的 sext(-1) 比较失败,SysLibTest exists FAIL 根因)。
改用截断回比较:t.CUInt32T(value) 回绕后还原,与 value 不等即超 u32 范围。
"""
if value >= 0 and t.CUInt64T(t.CUInt32T(value)) != value:
return llvmlite.const_int64(pool, value)
return llvmlite.const_int32(pool, t.CInt(value))