refactor(tpv): 迁移新语法 R1/R2/R7/R8/R3/R4/R5(指针 T*、短别名、define、&/*、__asm__)

按 wiki/新规范:
- T | t.CPtr → T*(无 | 标准)
- t.CInt/t.CUInt64T/t.CChar/t.CDouble 等 → int/uint64/char/double 等短别名
- X: t.CDefine = Y → define X = Y
- c.Asm → __asm__,c.AsmInp/c.AsmOut → asminp/asmout,t.ASM_DESCR. → ASM_DESCR.
- c.Addr(x) → &x,c.Deref(p) → *p,c.DerefAs(p, v) → *p = v

种子自举通过(96s)。
This commit is contained in:
TermiNexus committed 2026-10-04 22:49:01 +08:00
1 parent 9717ce0107
commit 185a2196ca
57 files changed
+1078 -1078

No files matched your search

+90 -90
View File
@@ -82,7 +82,7 @@ def _ir_sibling_path(ir_path: str, suffix: str) -> str:
return buf
# 源代码缓冲区大小(1MB)
SRC_BUF_SIZE: t.CDefine = 1048576 # 2^20 = 1MB
define SRC_BUF_SIZE = 1048576 # 2^20 = 1MB
# .vpi 存根缓冲区大小(256KB,与 Phase1 一致)
PYI_BUF_SIZE: sizet = 262144
@@ -128,7 +128,7 @@ def _append_traceback_dbghelp(linker_flags: str) -> str:
# 写盘并登记路径。WriteStackMap 链接后按登记表读取,结合 llvm-objdump 归一地址。
# 仅 --traceback 时产生;关闭时不写任何旁文件、不登记。
# ============================================================
TB_VPCALL_MAX: t.CDefine = 8192
define TB_VPCALL_MAX = 8192
_tb_vpcall_buf: bytes = None # TB_VPCALL_MAX * 8:每槽一个 char*(stdlib 分配,进程内一次性)
_tb_vpcall_n: int = 0
@@ -147,7 +147,7 @@ def _tb_register_vpcall(path: str) -> int:
if _tb_vpcall_n >= TB_VPCALL_MAX:
VLogger.error("--traceback: .vpcall 路径表溢出(模块数超上限),终止编译", "TRACEBACK")
return 1
slot: str | t.CPtr = (str | t.CPtr)(uint64(_tb_vpcall_buf) + sizet(_tb_vpcall_n) * 8)
slot: str* = (str*)(uint64(_tb_vpcall_buf) + sizet(_tb_vpcall_n) * 8)
slot[0] = path
_tb_vpcall_n += 1
return 0
@@ -581,7 +581,7 @@ def compile_ll_to_obj(ir_path: str, output_dir: str, module_name: str, cc_cmd: s
# - 依赖 CreateProcessA + Win32 句柄接口的多线程安全性
# ============================================================
# llc 并行最大线程数(参考 TPC Phase2Translator n_workers=os.cpu_count(),本机 16 核)
LLC_MAX_THREADS: t.CDefine = 16
define LLC_MAX_THREADS = 16
# LlcTask.FailStage:worker 写"失败发生在哪一步"
# 0 = 未失败/成功;1 = mlir-opt 校验;2 = mlir-translate 降级;3 = ASan opt 插桩;4 = llc
@@ -611,7 +611,7 @@ class LlcTask:
FailStage: int # worker 写:失败发生在哪一步
def init_llc_task(task: LlcTask | t.CPtr, ir_path: str, output_dir: str,
def init_llc_task(task: LlcTask*, ir_path: str, output_dir: str,
module_name: str, cc_cmd: str, cc_flags: str) -> int:
"""填充 llc 任务(全部 stdlib.malloc,线程运行期不被回收),0 成功"""
if task is None or ir_path is None or output_dir is None or module_name is None:
@@ -675,7 +675,7 @@ def init_llc_task(task: LlcTask | t.CPtr, ir_path: str, output_dir: str,
return 0
def free_llc_task(task: LlcTask | t.CPtr):
def free_llc_task(task: LlcTask*):
"""释放任务的命令串;记录本身是任务数组的连续槽(非独立 malloc),
由调用方对数组整体 stdlib.free(此前对槽 free 导致 double-free)"""
if task is None:
@@ -745,9 +745,9 @@ def _run_cmd_wait(cmd: str) -> int:
# 栈垃圾,多线程并发调用时垃圾随机 → dwFlags 垃圾位让 CreateProcessA
# 用垃圾句柄作子进程 stdio → 子进程行为不定/父进程线程崩溃(ClassArrayTest
# e5fb worker 崩溃、edd8 正常的原因)。si/sa/pi 全部显式清零。
string.memset(t.CPtr(c.Addr(si)), 0, win32process.STARTUPINFOA.__sizeof__())
string.memset(t.CPtr(c.Addr(sa)), 0, w32.win32base.SECURITY_ATTRIBUTES.__sizeof__())
string.memset(t.CPtr(c.Addr(pi)), 0, win32process.PROCESS_INFORMATION.__sizeof__())
string.memset(t.CPtr(&si), 0, win32process.STARTUPINFOA.__sizeof__())
string.memset(t.CPtr(&sa), 0, w32.win32base.SECURITY_ATTRIBUTES.__sizeof__())
string.memset(t.CPtr(&pi), 0, win32process.PROCESS_INFORMATION.__sizeof__())
sa.nLength = w32.win32base.SECURITY_ATTRIBUTES.__sizeof__()
sa.lpSecurityDescriptor = t.CPtr(0)
sa.bInheritHandle = 1
@@ -756,7 +756,7 @@ def _run_cmd_wait(cmd: str) -> int:
# si.dwFlags 保持 memset 后的 0(不置 STARTF_USESTDHANDLES、不设 std 句柄)
ok: int = win32process.CreateProcessA(
t.CPtr(0), cmd_line, t.CPtr(0), t.CPtr(0), 1, 0,
t.CPtr(0), t.CPtr(0), t.CPtr(c.Addr(si)), t.CPtr(c.Addr(pi)))
t.CPtr(0), t.CPtr(0), t.CPtr(&si), t.CPtr(&pi))
# CreateProcessA 失败诊断:GetLastError 必须在返回后立即取(此后 stdlib.free/
# CloseHandle/SetConsoleTextAttribute 等都会覆盖它)。用 warning 不用 error——
# VLogger.error 会 sys.exit(1),而本函数可能在 worker 线程里执行;warning 只走
@@ -769,7 +769,7 @@ def _run_cmd_wait(cmd: str) -> int:
return -1
win32sync.WaitForSingleObject(pi.hProcess, w32.win32base.INFINITE)
exit_code: uint32 = 0
win32process.GetExitCodeProcess(pi.hProcess, t.CPtr(c.Addr(exit_code)))
win32process.GetExitCodeProcess(pi.hProcess, t.CPtr(&exit_code))
w32.win32base.CloseHandle(pi.hProcess)
w32.win32base.CloseHandle(pi.hThread)
return int(exit_code)
@@ -779,7 +779,7 @@ def _llc_task_worker(arg: t.CPtr) -> t.CPtr:
"""llc 线程入口:只调 _run_cmd_wait(),不做任何池分配(线程安全)
Result 仅在命令链执行完后写入(初始 -1;join 超时保持 -1 → 报失败);
ExitCode 记录失败命令的退出码,供主线程打印"""
task: LlcTask | t.CPtr = (LlcTask | t.CPtr)(arg)
task: LlcTask* = (LlcTask*)(arg)
if task is None:
return t.CPtr(0)
# MLIR 后端:先校验(mlir-opt)→ 降级(mlir-translate),再 ASan opt → llc
@@ -826,7 +826,7 @@ def run_llc_parallel(tasks: bytes, task_count: int, max_threads: int) -> int:
# --phase2command 模式:不 spawn 线程,把 opt(ASan)+ llc 命令全部写入 bat
if _phase2_cmd_path is not None:
for pi2 in range(task_count):
tsk_p: LlcTask | t.CPtr = (LlcTask | t.CPtr)(uint64(tasks) + sizet(pi2) * LlcTask.__sizeof__())
tsk_p: LlcTask* = (LlcTask*)(uint64(tasks) + sizet(pi2) * LlcTask.__sizeof__())
if tsk_p is None:
continue
if tsk_p.MlirOptCmd is not None:
@@ -856,7 +856,7 @@ def run_llc_parallel(tasks: bytes, task_count: int, max_threads: int) -> int:
batch_n = task_count - batch_start
# 本批 spawn
for j in range(batch_n):
tsk: LlcTask | t.CPtr = (LlcTask | t.CPtr)(uint64(tasks) + sizet(batch_start + j) * slot_size)
tsk: LlcTask* = (LlcTask*)(uint64(tasks) + sizet(batch_start + j) * slot_size)
th: rawptr[vthreading.Thread] = vthreading.Thread(_llc_task_worker, t.CPtr(tsk))
th.start()
# start() 后立即取出句柄(Thread 对象栈地址可能被后续构造复用,
@@ -870,7 +870,7 @@ def run_llc_parallel(tasks: bytes, task_count: int, max_threads: int) -> int:
w32.win32base.CloseHandle(h_j)
# 本批结果检查
for j in range(batch_n):
tsk2: LlcTask | t.CPtr = (LlcTask | t.CPtr)(uint64(tasks) + sizet(batch_start + j) * slot_size)
tsk2: LlcTask* = (LlcTask*)(uint64(tasks) + sizet(batch_start + j) * slot_size)
if tsk2 is not None and tsk2.Result != 0:
# 失败:按 FailStage 定位到**具体哪一步**并打印对应该步的命令。
# 此前一律打印 LlcCmd + "llc 编译失败":MLIR 后端下 mlir-opt /
@@ -902,7 +902,7 @@ def _CollectObjFilesImpl(base_dir: str, bd_len: sizet,
支持切片子目录(如 dir/43/{sha1}.obj)。
"""
find_data: w32.win32file.WIN32_FIND_DATAA | t.CPtr = _mbuddy.alloc(w32.win32file.WIN32_FIND_DATAA.__sizeof__())
find_data: w32.win32file.WIN32_FIND_DATAA* = _mbuddy.alloc(w32.win32file.WIN32_FIND_DATAA.__sizeof__())
if find_data is None:
VLogger.warning("_CollectObjFilesImpl 分配 find_data 失败,少收集 .obj", "collect")
return out_pos
@@ -1401,22 +1401,22 @@ def link_objs_to_exe(obj_paths: str, obj_paths_len: sizet,
# row record: u64 rva | u64 file_path | u32 line | u32 pad | u64 func_name(可空)
# func_name 仅我方 .vpcall 派生行携带(objdump 标签名);DWARF 行写 0,序列化时
# 回退到 DWARF 子程序表查名。
TB_ROW_SIZE: t.CDefine = 32
TB_ROW_OFF_FILE: t.CDefine = 8
TB_ROW_OFF_LINE: t.CDefine = 16
TB_ROW_OFF_FUNC: t.CDefine = 24
define TB_ROW_SIZE = 32
define TB_ROW_OFF_FILE = 8
define TB_ROW_OFF_LINE = 16
define TB_ROW_OFF_FUNC = 24
# func record: u64 low_rva | u64 high_rva | u64 name
TB_FUNC_SIZE: t.CDefine = 24
define TB_FUNC_SIZE = 24
# dir record: u32 idx | u32 pad | u64 name
TB_DIR_SIZE: t.CDefine = 16
define TB_DIR_SIZE = 16
# file record: u32 idx | u32 dir_index | u64 name | u64 resolved_path
TB_FILE_SIZE: t.CDefine = 32
define TB_FILE_SIZE = 32
# initial capacities for the (growable) row / func tables
TB_ROW_CAP0: t.CDefine = 65536
TB_FUNC_CAP0: t.CDefine = 65536
define TB_ROW_CAP0 = 65536
define TB_FUNC_CAP0 = 65536
# fixed per-CU table capacities (exceeding either aborts the build)
TB_DIR_CAP: t.CDefine = 4096
TB_FILE_CAP: t.CDefine = 65536
define TB_DIR_CAP = 4096
define TB_FILE_CAP = 65536
class TbPeLayout:
@@ -1769,7 +1769,7 @@ def _tb_resolve_file(mb: memhub.MemBuddy*, files: bytes, fcount: int,
path = _tb_join(mb, base, name)
if path is None or string.strlen(path) == 0:
path = "??"
_tb_wr_u64(files, roff + 24, t.CUInt64T(path))
_tb_wr_u64(files, roff + 24, uint64(path))
return path
@@ -1783,7 +1783,7 @@ def _tb_grow_rec(mb: memhub.MemBuddy*, buf: bytes, old_cap: int,
return nb
def _tb_emit_row(mb: memhub.MemBuddy*, d: TbDump | t.CPtr,
def _tb_emit_row(mb: memhub.MemBuddy*, d: TbDump*,
addr: uint64, path: str, line: int, fname: str = None) -> int:
if d is None:
return 1
@@ -1797,18 +1797,18 @@ def _tb_emit_row(mb: memhub.MemBuddy*, d: TbDump | t.CPtr,
d.RowCap = ncap
off: sizet = sizet(d.RowCount) * TB_ROW_SIZE
_tb_wr_u64(d.RowBuf, off, addr)
_tb_wr_u64(d.RowBuf, off + TB_ROW_OFF_FILE, t.CUInt64T(path))
_tb_wr_u64(d.RowBuf, off + TB_ROW_OFF_FILE, uint64(path))
_tb_wr_u32(d.RowBuf, off + TB_ROW_OFF_LINE, uint64(line))
fv: uint64 = 0
if fname is not None:
fv = t.CUInt64T(fname)
fv = uint64(fname)
_tb_wr_u64(d.RowBuf, off + TB_ROW_OFF_FUNC, fv)
d.RowCount = d.RowCount + 1
d.RawRowCount = d.RawRowCount + 1
return 0
def _tb_emit_func(mb: memhub.MemBuddy*, d: TbDump | t.CPtr,
def _tb_emit_func(mb: memhub.MemBuddy*, d: TbDump*,
low: uint64, high: uint64, name: str) -> int:
if d is None:
return 1
@@ -1823,7 +1823,7 @@ def _tb_emit_func(mb: memhub.MemBuddy*, d: TbDump | t.CPtr,
off: sizet = sizet(d.FuncCount) * TB_FUNC_SIZE
_tb_wr_u64(d.FuncBuf, off, low)
_tb_wr_u64(d.FuncBuf, off + 8, high)
_tb_wr_u64(d.FuncBuf, off + 16, t.CUInt64T(name))
_tb_wr_u64(d.FuncBuf, off + 16, uint64(name))
d.FuncCount = d.FuncCount + 1
return 0
@@ -1850,7 +1850,7 @@ def _tb_func_name_for(fbuf: bytes, fcount: int, rva: uint64) -> str:
return None
def _tb_intern(p: TbPool | t.CPtr, s: str) -> uint64:
def _tb_intern(p: TbPool*, s: str) -> uint64:
"""Intern s into the pool (linear scan; keeps offset 0 as the empty sentinel)."""
if p is None or s is None:
return 0
@@ -1870,9 +1870,9 @@ def _tb_intern(p: TbPool | t.CPtr, s: str) -> uint64:
return off
def _tb_read_pe_layout(mb: memhub.MemBuddy*, exe_path: str) -> TbPeLayout | t.CPtr:
def _tb_read_pe_layout(mb: memhub.MemBuddy*, exe_path: str) -> TbPeLayout*:
"""Read (ImageBase, SizeOfImage, .text RVA) from the PE headers."""
lay: TbPeLayout | t.CPtr = TbPeLayout()
lay: TbPeLayout* = TbPeLayout()
if lay is None:
return None
f: rawptr[fileio.File] = fileio.File(exe_path, fileio.MODE.R)
@@ -1938,9 +1938,9 @@ def _tb_read_pe_layout(mb: memhub.MemBuddy*, exe_path: str) -> TbPeLayout | t.CP
return lay
def _tb_parse_dump(mb: memhub.MemBuddy*, dump: str) -> TbDump | t.CPtr:
def _tb_parse_dump(mb: memhub.MemBuddy*, dump: str) -> TbDump*:
"""Parse llvm-dwarfdump text into a row table (addr, path, line) and a func table."""
d: TbDump | t.CPtr = TbDump()
d: TbDump* = TbDump()
if d is None:
return None
LINE_CAP: sizet = 8192
@@ -2003,7 +2003,7 @@ def _tb_parse_dump(mb: memhub.MemBuddy*, dump: str) -> TbDump | t.CPtr:
if pkind == 1 and pname is not None and file_count < TB_FILE_CAP:
_tb_wr_u32(files, sizet(file_count) * TB_FILE_SIZE, uint64(pidx))
_tb_wr_u32(files, sizet(file_count) * TB_FILE_SIZE + 4, uint64(pdir))
_tb_wr_u64(files, sizet(file_count) * TB_FILE_SIZE + 8, t.CUInt64T(pname))
_tb_wr_u64(files, sizet(file_count) * TB_FILE_SIZE + 8, uint64(pname))
_tb_wr_u64(files, sizet(file_count) * TB_FILE_SIZE + 24, uint64(0))
file_count += 1
pkind = 0
@@ -2016,7 +2016,7 @@ def _tb_parse_dump(mb: memhub.MemBuddy*, dump: str) -> TbDump | t.CPtr:
if pkind == 1 and pname is not None and file_count < TB_FILE_CAP:
_tb_wr_u32(files, sizet(file_count) * TB_FILE_SIZE, uint64(pidx))
_tb_wr_u32(files, sizet(file_count) * TB_FILE_SIZE + 4, uint64(pdir))
_tb_wr_u64(files, sizet(file_count) * TB_FILE_SIZE + 8, t.CUInt64T(pname))
_tb_wr_u64(files, sizet(file_count) * TB_FILE_SIZE + 8, uint64(pname))
_tb_wr_u64(files, sizet(file_count) * TB_FILE_SIZE + 24, uint64(0))
file_count += 1
pname = None
@@ -2028,7 +2028,7 @@ def _tb_parse_dump(mb: memhub.MemBuddy*, dump: str) -> TbDump | t.CPtr:
if pkind == 1 and pname is not None and file_count < TB_FILE_CAP:
_tb_wr_u32(files, sizet(file_count) * TB_FILE_SIZE, uint64(pidx))
_tb_wr_u32(files, sizet(file_count) * TB_FILE_SIZE + 4, uint64(pdir))
_tb_wr_u64(files, sizet(file_count) * TB_FILE_SIZE + 8, t.CUInt64T(pname))
_tb_wr_u64(files, sizet(file_count) * TB_FILE_SIZE + 8, uint64(pname))
_tb_wr_u64(files, sizet(file_count) * TB_FILE_SIZE + 24, uint64(0))
file_count += 1
pname = None
@@ -2038,7 +2038,7 @@ def _tb_parse_dump(mb: memhub.MemBuddy*, dump: str) -> TbDump | t.CPtr:
if val is not None and _tb_len_trimmed(val) > 0:
if dir_count < TB_DIR_CAP:
_tb_wr_u32(dirs, sizet(dir_count) * TB_DIR_SIZE, uint64(pidx))
_tb_wr_u64(dirs, sizet(dir_count) * TB_DIR_SIZE + 8, t.CUInt64T(_tb_unquote(mb, val)))
_tb_wr_u64(dirs, sizet(dir_count) * TB_DIR_SIZE + 8, uint64(_tb_unquote(mb, val)))
dir_count += 1
pkind = 0
else:
@@ -2051,7 +2051,7 @@ def _tb_parse_dump(mb: memhub.MemBuddy*, dump: str) -> TbDump | t.CPtr:
else:
if dir_count < TB_DIR_CAP and val2 is not None:
_tb_wr_u32(dirs, sizet(dir_count) * TB_DIR_SIZE, uint64(pidx))
_tb_wr_u64(dirs, sizet(dir_count) * TB_DIR_SIZE + 8, t.CUInt64T(val2))
_tb_wr_u64(dirs, sizet(dir_count) * TB_DIR_SIZE + 8, uint64(val2))
dir_count += 1
pkind = 0
continue
@@ -2064,7 +2064,7 @@ def _tb_parse_dump(mb: memhub.MemBuddy*, dump: str) -> TbDump | t.CPtr:
if pkind == 1 and pname is not None and file_count < TB_FILE_CAP:
_tb_wr_u32(files, sizet(file_count) * TB_FILE_SIZE, uint64(pidx))
_tb_wr_u32(files, sizet(file_count) * TB_FILE_SIZE + 4, uint64(pdir))
_tb_wr_u64(files, sizet(file_count) * TB_FILE_SIZE + 8, t.CUInt64T(pname))
_tb_wr_u64(files, sizet(file_count) * TB_FILE_SIZE + 8, uint64(pname))
_tb_wr_u64(files, sizet(file_count) * TB_FILE_SIZE + 24, uint64(0))
file_count += 1
pkind = 0
@@ -2075,7 +2075,7 @@ def _tb_parse_dump(mb: memhub.MemBuddy*, dump: str) -> TbDump | t.CPtr:
if pkind == 1 and pname is not None and file_count < TB_FILE_CAP:
_tb_wr_u32(files, sizet(file_count) * TB_FILE_SIZE, uint64(pidx))
_tb_wr_u32(files, sizet(file_count) * TB_FILE_SIZE + 4, uint64(pdir))
_tb_wr_u64(files, sizet(file_count) * TB_FILE_SIZE + 8, t.CUInt64T(pname))
_tb_wr_u64(files, sizet(file_count) * TB_FILE_SIZE + 8, uint64(pname))
_tb_wr_u64(files, sizet(file_count) * TB_FILE_SIZE + 24, uint64(0))
file_count += 1
pkind = 0
@@ -2177,26 +2177,26 @@ def _tb_parse_dump(mb: memhub.MemBuddy*, dump: str) -> TbDump | t.CPtr:
# ============================================================
# 调用记录:u64 caller | u64 callee | u64 file | u32 line | u32 next(组内下一个, NONE=尾)
TB_CR_SIZE: t.CDefine = 32
TB_CR_OFF_CALLER: t.CDefine = 0
TB_CR_OFF_CALLEE: t.CDefine = 8
TB_CR_OFF_FILE: t.CDefine = 16
TB_CR_OFF_LINE: t.CDefine = 24
TB_CR_OFF_NEXT: t.CDefine = 28
define TB_CR_SIZE = 32
define TB_CR_OFF_CALLER = 0
define TB_CR_OFF_CALLEE = 8
define TB_CR_OFF_FILE = 16
define TB_CR_OFF_LINE = 24
define TB_CR_OFF_NEXT = 28
# 函数记录:u64 sym | u64 file | u32 defline | u32 pad
TB_FR_SIZE: t.CDefine = 24
TB_FR_OFF_SYM: t.CDefine = 0
TB_FR_OFF_FILE: t.CDefine = 8
TB_FR_OFF_DEFLINE: t.CDefine = 16
define TB_FR_SIZE = 24
define TB_FR_OFF_SYM = 0
define TB_FR_OFF_FILE = 8
define TB_FR_OFF_DEFLINE = 16
# 组哈希槽(以 (caller,callee) 为键;开放寻址 + 线性探测):
# u64 caller | u64 callee | u32 used | u32 head | u32 tail | u32 cursor
TB_GRP_SIZE: t.CDefine = 32
TB_GRP_OFF_CALLER: t.CDefine = 0
TB_GRP_OFF_CALLEE: t.CDefine = 8
TB_GRP_OFF_USED: t.CDefine = 16
TB_GRP_OFF_HEAD: t.CDefine = 20
TB_GRP_OFF_TAIL: t.CDefine = 24
TB_GRP_OFF_CURSOR: t.CDefine = 28
define TB_GRP_SIZE = 32
define TB_GRP_OFF_CALLER = 0
define TB_GRP_OFF_CALLEE = 8
define TB_GRP_OFF_USED = 16
define TB_GRP_OFF_HEAD = 20
define TB_GRP_OFF_TAIL = 24
define TB_GRP_OFF_CURSOR = 28
# 无效索引哨兵(u32 全 1)
TB_IDX_NONE: uint64 = 0xFFFFFFFF
@@ -2258,8 +2258,8 @@ def _tb_grp_get(grp: bytes, cap: int, caller: str, callee: str, do_insert: int)
if do_insert == 0:
return -1
_tb_wr_u32(grp, off + TB_GRP_OFF_USED, uint64(1))
_tb_wr_u64(grp, off + TB_GRP_OFF_CALLER, t.CUInt64T(caller))
_tb_wr_u64(grp, off + TB_GRP_OFF_CALLEE, t.CUInt64T(callee))
_tb_wr_u64(grp, off + TB_GRP_OFF_CALLER, uint64(caller))
_tb_wr_u64(grp, off + TB_GRP_OFF_CALLEE, uint64(callee))
_tb_wr_u32(grp, off + TB_GRP_OFF_HEAD, uint64(TB_IDX_NONE))
_tb_wr_u32(grp, off + TB_GRP_OFF_TAIL, uint64(TB_IDX_NONE))
_tb_wr_u32(grp, off + TB_GRP_OFF_CURSOR, uint64(TB_IDX_NONE))
@@ -2273,8 +2273,8 @@ def _tb_grp_get(grp: bytes, cap: int, caller: str, callee: str, do_insert: int)
return -1
def _tb_cp_init(mb: memhub.MemBuddy*) -> TbCallParse | t.CPtr:
cp: TbCallParse | t.CPtr = TbCallParse()
def _tb_cp_init(mb: memhub.MemBuddy*) -> TbCallParse*:
cp: TbCallParse* = TbCallParse()
if cp is None:
return None
cp.CrCap = 1024
@@ -2288,7 +2288,7 @@ def _tb_cp_init(mb: memhub.MemBuddy*) -> TbCallParse | t.CPtr:
return cp
def _tb_cp_add_cr(mb: memhub.MemBuddy*, cp: TbCallParse | t.CPtr,
def _tb_cp_add_cr(mb: memhub.MemBuddy*, cp: TbCallParse*,
caller: str, callee: str, file: str, line: int) -> int:
if cp.CrN >= cp.CrCap:
ncap: int = cp.CrCap * 2
@@ -2299,16 +2299,16 @@ def _tb_cp_add_cr(mb: memhub.MemBuddy*, cp: TbCallParse | t.CPtr,
cp.Cr = nb
cp.CrCap = ncap
off: sizet = sizet(cp.CrN) * TB_CR_SIZE
_tb_wr_u64(cp.Cr, off + TB_CR_OFF_CALLER, t.CUInt64T(caller))
_tb_wr_u64(cp.Cr, off + TB_CR_OFF_CALLEE, t.CUInt64T(callee))
_tb_wr_u64(cp.Cr, off + TB_CR_OFF_FILE, t.CUInt64T(file))
_tb_wr_u64(cp.Cr, off + TB_CR_OFF_CALLER, uint64(caller))
_tb_wr_u64(cp.Cr, off + TB_CR_OFF_CALLEE, uint64(callee))
_tb_wr_u64(cp.Cr, off + TB_CR_OFF_FILE, uint64(file))
_tb_wr_u32(cp.Cr, off + TB_CR_OFF_LINE, uint64(line))
_tb_wr_u32(cp.Cr, off + TB_CR_OFF_NEXT, uint64(TB_IDX_NONE))
cp.CrN = cp.CrN + 1
return 0
def _tb_cp_add_fr(mb: memhub.MemBuddy*, cp: TbCallParse | t.CPtr,
def _tb_cp_add_fr(mb: memhub.MemBuddy*, cp: TbCallParse*,
sym: str, file: str, defline: int) -> int:
if cp.FrN >= cp.FrCap:
ncap: int = cp.FrCap * 2
@@ -2319,8 +2319,8 @@ def _tb_cp_add_fr(mb: memhub.MemBuddy*, cp: TbCallParse | t.CPtr,
cp.Fr = nb
cp.FrCap = ncap
off: sizet = sizet(cp.FrN) * TB_FR_SIZE
_tb_wr_u64(cp.Fr, off + TB_FR_OFF_SYM, t.CUInt64T(sym))
_tb_wr_u64(cp.Fr, off + TB_FR_OFF_FILE, t.CUInt64T(file))
_tb_wr_u64(cp.Fr, off + TB_FR_OFF_SYM, uint64(sym))
_tb_wr_u64(cp.Fr, off + TB_FR_OFF_FILE, uint64(file))
_tb_wr_u32(cp.Fr, off + TB_FR_OFF_DEFLINE, uint64(defline))
cp.FrN = cp.FrN + 1
return 0
@@ -2347,7 +2347,7 @@ def _tb_read_whole(mb: memhub.MemBuddy*, path: str) -> str:
def _tb_parse_f_line(mb: memhub.MemBuddy*, s: str, a: sizet, b: sizet,
cp: TbCallParse | t.CPtr) -> int:
cp: TbCallParse*) -> int:
"""解析 `F\t<sym>\t<defline>\t<file>`。"""
p: sizet = a
while p < b and _tb_cc(s, p) != 9:
@@ -2376,7 +2376,7 @@ def _tb_parse_f_line(mb: memhub.MemBuddy*, s: str, a: sizet, b: sizet,
def _tb_parse_c_line(mb: memhub.MemBuddy*, s: str, a: sizet, b: sizet,
cp: TbCallParse | t.CPtr) -> int:
cp: TbCallParse*) -> int:
"""解析 `C\t<caller>\t<callee>\t<line>\t<file>`。"""
p: sizet = a
while p < b and _tb_cc(s, p) != 9:
@@ -2412,7 +2412,7 @@ def _tb_parse_c_line(mb: memhub.MemBuddy*, s: str, a: sizet, b: sizet,
def _tb_parse_vpcall_file(mb: memhub.MemBuddy*, path: str,
cp: TbCallParse | t.CPtr) -> int:
cp: TbCallParse*) -> int:
whole: str = _tb_read_whole(mb, path)
if whole is None:
VLogger.error(f"--traceback: 读取 .vpcall 失败:{path},终止编译", "TRACEBACK")
@@ -2439,12 +2439,12 @@ def _tb_parse_vpcall_file(mb: memhub.MemBuddy*, path: str,
return 0
def _tb_load_vpcalls(mb: memhub.MemBuddy*, cp: TbCallParse | t.CPtr) -> int:
def _tb_load_vpcalls(mb: memhub.MemBuddy*, cp: TbCallParse*) -> int:
if _tb_vpcall_buf is None or _tb_vpcall_n <= 0:
return 0
k: int = 0
while k < _tb_vpcall_n:
slot: str | t.CPtr = (str | t.CPtr)(uint64(_tb_vpcall_buf) + sizet(k) * 8)
slot: str* = (str*)(uint64(_tb_vpcall_buf) + sizet(k) * 8)
path: str = slot[0]
if path is not None:
if _tb_parse_vpcall_file(mb, path, cp) != 0:
@@ -2453,7 +2453,7 @@ def _tb_load_vpcalls(mb: memhub.MemBuddy*, cp: TbCallParse | t.CPtr) -> int:
return 0
def _tb_build_groups(mb: memhub.MemBuddy*, cp: TbCallParse | t.CPtr) -> int:
def _tb_build_groups(mb: memhub.MemBuddy*, cp: TbCallParse*) -> int:
"""把所有 C 记录按 (caller,callee) 串成组链表(组槽存 head/tail/cursor)。"""
if cp.CrN <= 0:
return 0
@@ -2486,8 +2486,8 @@ def _tb_build_groups(mb: memhub.MemBuddy*, cp: TbCallParse | t.CPtr) -> int:
return 0
def _tb_emit_call_row(mb: memhub.MemBuddy*, d: TbDump | t.CPtr,
cp: TbCallParse | t.CPtr, img_lo: uint64,
def _tb_emit_call_row(mb: memhub.MemBuddy*, d: TbDump*,
cp: TbCallParse*, img_lo: uint64,
caller: str, callee: str, ret_va: uint64) -> int:
"""按 (caller,callee) 的下一条未消费 C 记录为返回地址生成一条行记录。"""
if caller is None or callee is None or cp.Grp is None or ret_va < img_lo:
@@ -2508,8 +2508,8 @@ def _tb_emit_call_row(mb: memhub.MemBuddy*, d: TbDump | t.CPtr,
return _tb_emit_row(mb, d, ret_va, file, line, caller)
def _tb_emit_entry_row(mb: memhub.MemBuddy*, d: TbDump | t.CPtr,
cp: TbCallParse | t.CPtr, img_lo: uint64,
def _tb_emit_entry_row(mb: memhub.MemBuddy*, d: TbDump*,
cp: TbCallParse*, img_lo: uint64,
addr: uint64, sym: str) -> int:
"""为 objdump 标签 `sym` 生成函数入口兜底行(文件/定义行取自 F 记录)。"""
if sym is None or cp.Fr is None or cp.FrN <= 0 or addr < img_lo:
@@ -2560,7 +2560,7 @@ def _tb_run_objdump(mb: memhub.MemBuddy*, exe_path: str) -> str:
def _tb_scan_objdump(mb: memhub.MemBuddy*, dump: str, img_lo: uint64,
d: TbDump | t.CPtr, cp: TbCallParse | t.CPtr) -> int:
d: TbDump*, cp: TbCallParse*) -> int:
"""解析 `llvm-objdump -d` 文本,匹配 C/F 记录并把我方行写入 d。"""
dlen: sizet = string.strlen(dump)
pos: sizet = 0
@@ -2679,7 +2679,7 @@ def WriteStackMap(mb: memhub.MemBuddy*, exe_path: str) -> int:
VLogger.error("--traceback: WriteStackMap 参数为空,终止编译", "TRACEBACK")
return 1
lay: TbPeLayout | t.CPtr = _tb_read_pe_layout(mb, exe_path)
lay: TbPeLayout* = _tb_read_pe_layout(mb, exe_path)
if lay is None or lay.Ok == 0:
VLogger.error(f"--traceback: 只支持 Windows PE 产物,但 {exe_path} 不是有效 PE(这是 --traceback 的要求)", "TRACEBACK")
return 1
@@ -2710,7 +2710,7 @@ def WriteStackMap(mb: memhub.MemBuddy*, exe_path: str) -> int:
VLogger.error("--traceback: llvm-dwarfdump 无输出,终止编译", "TRACEBACK")
return 1
d: TbDump | t.CPtr = _tb_parse_dump(mb, dump)
d: TbDump* = _tb_parse_dump(mb, dump)
if d is None:
return 1
@@ -2718,7 +2718,7 @@ def WriteStackMap(mb: memhub.MemBuddy*, exe_path: str) -> int:
# DWARF 行仅覆盖链接进来的 mingw CRT(我方 .vp 函数无 .debug_line);这里用编译器
# 落盘的 .vpcall + objdump 反汇编补上「返回地址 → 调用点行 / 函数入口行」。
if _tb_vpcall_n > 0:
cp: TbCallParse | t.CPtr = _tb_cp_init(mb)
cp: TbCallParse* = _tb_cp_init(mb)
if cp is None:
VLogger.error("--traceback: 调用点解析状态分配失败,终止编译", "TRACEBACK")
return 1
@@ -2876,7 +2876,7 @@ def WriteStackMap(mb: memhub.MemBuddy*, exe_path: str) -> int:
if nm0 is not None:
pool_need += string.strlen(nm0) + 1
i += 1
p: TbPool | t.CPtr = TbPool()
p: TbPool* = TbPool()
if p is None:
VLogger.error("--traceback: 字符串池对象分配失败,终止编译", "TRACEBACK")
return 1
@@ -2990,7 +2990,7 @@ def run_pipeline(ir_buf: bytes, ir_len: sizet,
temp_dir: str, output_dir: str, module_name: str,
cc_cmd: str, cc_flags: str,
linker_cmd: str, linker_flags: str, linker_output: str,
includes_binary_dir: str, linker_static_libs: str = None, linker_dynamic_libs: str = None) -> BuildResult | t.CPtr:
includes_binary_dir: str, linker_static_libs: str = None, linker_dynamic_libs: str = None) -> BuildResult*:
"""执行完整编译管线
Args:
@@ -3010,7 +3010,7 @@ def run_pipeline(ir_buf: bytes, ir_len: sizet,
Returns:
BuildResult 对象
"""
result: BuildResult | t.CPtr = BuildResult()
result: BuildResult* = BuildResult()
if result is None:
return None
+5 -5
View File
@@ -508,7 +508,7 @@ def RunPhase1(mb: memhub.MemBuddy*, includes_dir: str, temp_dir: str,
topo_order, topo_count_box,
temp_dir, td_len_ts_call)
if ret_topo == 0:
tc_ptr: t.CPtr = (int | t.CPtr)(topo_count_box)
tc_ptr: t.CPtr = (int*)(topo_count_box)
if tc_ptr is not None:
topo_count = tc_ptr[0]
VLogger.info(f"拓扑排序: {class_count_scanned} 个类, {topo_count} 个文件按依赖顺序处理", "Phase1")
@@ -551,7 +551,7 @@ def RunPhase1(mb: memhub.MemBuddy*, includes_dir: str, temp_dir: str,
file_idx: int = i
if topo_count > 0:
od_addr: uint64 = uint64(topo_order) + i * 4
od_ptr: t.CPtr = (int | t.CPtr)(t.CPtr(od_addr))
od_ptr: t.CPtr = (int*)(t.CPtr(od_addr))
if od_ptr is not None:
file_idx = od_ptr[0]
@@ -839,7 +839,7 @@ def RunPhase1(mb: memhub.MemBuddy*, includes_dir: str, temp_dir: str,
file_idx_b: int = i
if topo_count > 0:
od_addr_b: uint64 = uint64(topo_order) + sizet(i) * 4
od_ptr_b: t.CPtr = (int | t.CPtr)(od_addr_b)
od_ptr_b: t.CPtr = (int*)(od_addr_b)
if od_ptr_b is not None:
file_idx_b = od_ptr_b[0]
entry_addr: uint64 = uint64(result.Entries) + sizet(file_idx_b) * entry_size
@@ -1101,8 +1101,8 @@ def RunPhase1(mb: memhub.MemBuddy*, includes_dir: str, temp_dir: str,
# dump stub IR(declarations only)
# 1MB 不够:ast/parser.vp 的 text.ll 超 1MB 被截断 → 合并 IR 尾部丢字
# (opt: "end of file in global variable name"),提至 8MB。
PHASE1_IR_SIZE: sizet = 8388608
# FULL dump = stub + text(同一模块),留 2× 余量
PHASE1_IR_SIZE: sizet = 8388608
# FULL dump = stub + text(同一模块),留 2× 余量
PHASE1_FULL_SIZE: sizet = 16777216
stub_buf: bytes = stdlib.malloc(PHASE1_IR_SIZE)
if stub_buf is None:
+3 -3
View File
@@ -154,12 +154,12 @@ def _ScanClassInheritance(mb: memhub.MemBuddy*,
if tp_scan is not None:
file_has_generic = 1
if generic_file_count_box is not None:
gfc_ptr_scan: t.CPtr = (int | t.CPtr)(generic_file_count_box)
gfc_ptr_scan: t.CPtr = (int*)(generic_file_count_box)
if gfc_ptr_scan is not None:
gfc_scan: int = gfc_ptr_scan[0]
if gfc_scan < Phase1.MAX_FILE_DEPS and generic_file_indices is not None:
gi_addr_scan: uint64 = uint64(generic_file_indices) + gfc_scan * 4
gi_ptr_scan: t.CPtr = (int | t.CPtr)(gi_addr_scan)
gi_ptr_scan: t.CPtr = (int*)(gi_addr_scan)
if gi_ptr_scan is not None:
gi_ptr_scan[0] = i
gfc_ptr_scan[0] = gfc_scan + 1
@@ -405,7 +405,7 @@ def _FindClassDefSha1(class_names_buf: bytes, def_sha1s_buf: bytes,
# _ScanTreeForContainers - 递归扫描 AST 检测 list/dict 容器使用
#
# TPV 的 AST 中语句块挂在 children,而表达式/注解树全部以结构体字段挂载(value/slice/func/args/annotation/targets/returns/bases/left/right 等);
# 只递归 children 会漏掉 list[...] | t.CPtr、list[...](...)、字段注解等非语句块位置,故每个节点先递归表达式承载字段、再递归 children。
# 只递归 children 会漏掉 list[...]*、list[...](...)、字段注解等非语句块位置,故每个节点先递归表达式承载字段、再递归 children。
# 命中即置 need_list/need_dict;误报无害(最多多编译两个空壳模块)。
# ============================================================
+15 -15
View File
@@ -141,7 +141,7 @@ def _TopoSortFiles(mb: memhub.MemBuddy*,
# 读取当前依赖数量
cnt_addr: uint64 = uint64(file_dep_counts) + fi * 4
cnt_ptr: t.CPtr = (int | t.CPtr)(cnt_addr)
cnt_ptr: t.CPtr = (int*)(cnt_addr)
if cnt_ptr is None:
break
cur_cnt: int = cnt_ptr[0]
@@ -209,7 +209,7 @@ def _TopoSortFiles(mb: memhub.MemBuddy*,
break
# 去重 + 加边:fi_imp 依赖 fj_imp(InDegree[fi_imp]++)
cnt_addr_imp: uint64 = uint64(file_dep_counts) + fi_imp * 4
cnt_ptr_imp: t.CPtr = (int | t.CPtr)(cnt_addr_imp)
cnt_ptr_imp: t.CPtr = (int*)(cnt_addr_imp)
if cnt_ptr_imp is None:
break
cur_cnt_imp: int = cnt_ptr_imp[0]
@@ -235,9 +235,9 @@ def _TopoSortFiles(mb: memhub.MemBuddy*,
# 依赖为 0 的先处理,处理后减少依赖它的文件入度
for fi in range(file_count):
cnt_addr3: uint64 = uint64(file_dep_counts) + fi * 4
cnt_ptr3: t.CPtr = (int | t.CPtr)(cnt_addr3)
cnt_ptr3: t.CPtr = (int*)(cnt_addr3)
ind_addr3: uint64 = uint64(file_indegrees) + fi * 4
ind_ptr3: t.CPtr = (int | t.CPtr)(ind_addr3)
ind_ptr3: t.CPtr = (int*)(ind_addr3)
if cnt_ptr3 is not None and ind_ptr3 is not None:
ind_ptr3[0] = cnt_ptr3[0]
@@ -249,12 +249,12 @@ def _TopoSortFiles(mb: memhub.MemBuddy*,
for fi in range(file_count):
# 检查处理状态
proc_addr4: uint64 = uint64(file_processed) + fi * 4
proc_ptr4: t.CPtr = (int | t.CPtr)(proc_addr4)
proc_ptr4: t.CPtr = (int*)(proc_addr4)
if proc_ptr4 is None or proc_ptr4[0] != 0:
continue
# 检查入度
ind_addr4: uint64 = uint64(file_indegrees) + fi * 4
ind_ptr4: t.CPtr = (int | t.CPtr)(ind_addr4)
ind_ptr4: t.CPtr = (int*)(ind_addr4)
if ind_ptr4 is None or ind_ptr4[0] > 0:
continue
@@ -268,7 +268,7 @@ def _TopoSortFiles(mb: memhub.MemBuddy*,
if string.strcmp(ent_r.Sha1, target_sha1) == 0:
# 写入输出索引数组
out_idx_addr: uint64 = uint64(out_order) + out_idx * 4
out_int_ptr: t.CPtr = (int | t.CPtr)(out_idx_addr)
out_int_ptr: t.CPtr = (int*)(out_idx_addr)
if out_int_ptr is not None:
out_int_ptr[0] = ri
out_idx += 1
@@ -281,12 +281,12 @@ def _TopoSortFiles(mb: memhub.MemBuddy*,
# 减少依赖该文件的其他文件的入度
for fj in range(file_count):
proc_addr5: uint64 = uint64(file_processed) + fj * 4
proc_ptr5: t.CPtr = (int | t.CPtr)(proc_addr5)
proc_ptr5: t.CPtr = (int*)(proc_addr5)
if proc_ptr5 is None or proc_ptr5[0] != 0:
continue
# 读取 fj 的依赖数量
cnt_addr5: uint64 = uint64(file_dep_counts) + fj * 4
cnt_ptr5: t.CPtr = (int | t.CPtr)(cnt_addr5)
cnt_ptr5: t.CPtr = (int*)(cnt_addr5)
if cnt_ptr5 is None:
continue
fj_dep_cnt: int = cnt_ptr5[0]
@@ -294,7 +294,7 @@ def _TopoSortFiles(mb: memhub.MemBuddy*,
dep_slot5: str = file_deps_buf + fj * Phase1.MAX_DEP_EDGES * Phase1.SHA1_LEN + di * Phase1.SHA1_LEN
if string.strcmp(dep_slot5, target_sha1) == 0:
ind_addr5: uint64 = uint64(file_indegrees) + fj * 4
ind_ptr5: t.CPtr = (int | t.CPtr)(ind_addr5)
ind_ptr5: t.CPtr = (int*)(ind_addr5)
if ind_ptr5 is not None:
ind_ptr5[0] = ind_ptr5[0] - 1
break
@@ -310,7 +310,7 @@ def _TopoSortFiles(mb: memhub.MemBuddy*,
if rem_idx is not None and rem_depcnt is not None:
for fi in range(file_count):
proc_addr7: uint64 = uint64(file_processed) + fi * 4
proc_ptr7: t.CPtr = (int | t.CPtr)(proc_addr7)
proc_ptr7: t.CPtr = (int*)(proc_addr7)
if proc_ptr7 is not None and proc_ptr7[0] == 0:
rem_idx[rem_count] = fi
rem_depcnt[rem_count] = 0
@@ -324,7 +324,7 @@ def _TopoSortFiles(mb: memhub.MemBuddy*,
if fi_b == fi_a:
continue
cnt_addr_b: uint64 = uint64(file_dep_counts) + fi_b * 4
cnt_ptr_b: t.CPtr = (int | t.CPtr)(cnt_addr_b)
cnt_ptr_b: t.CPtr = (int*)(cnt_addr_b)
if cnt_ptr_b is None:
continue
cnt_b: int = cnt_ptr_b[0]
@@ -347,7 +347,7 @@ def _TopoSortFiles(mb: memhub.MemBuddy*,
for i_a in range(rem_count):
fi_a2: int = rem_idx[i_a]
proc_addr8: uint64 = uint64(file_processed) + fi_a2 * 4
proc_ptr8: t.CPtr = (int | t.CPtr)(proc_addr8)
proc_ptr8: t.CPtr = (int*)(proc_addr8)
if proc_ptr8 is None or proc_ptr8[0] != 0:
continue
target_sha1_2: str = file_sha1s_buf + fi_a2 * Phase1.SHA1_LEN
@@ -357,7 +357,7 @@ def _TopoSortFiles(mb: memhub.MemBuddy*,
if ent_r2 is not None and ent_r2.Sha1 is not None:
if string.strcmp(ent_r2.Sha1, target_sha1_2) == 0:
out_idx_addr2: uint64 = uint64(out_order) + out_idx * 4
out_int_ptr2: t.CPtr = (int | t.CPtr)(out_idx_addr2)
out_int_ptr2: t.CPtr = (int*)(out_idx_addr2)
if out_int_ptr2 is not None:
out_int_ptr2[0] = ri
out_idx += 1
@@ -367,7 +367,7 @@ def _TopoSortFiles(mb: memhub.MemBuddy*,
stdlib.free(rem_depcnt)
# 写入输出数量
out_count_ptr: t.CPtr = (int | t.CPtr)(out_count)
out_count_ptr: t.CPtr = (int*)(out_count)
if out_count_ptr is not None:
out_count_ptr[0] = out_idx
+6 -6
View File
@@ -6,14 +6,14 @@ import memhub
_mbuddy: memhub.MemBuddy*
# 源代码缓冲区大小(1MB)
SRC_BUF_SIZE: t.CDefine = 1048576
define SRC_BUF_SIZE = 1048576
# vpi 缓冲区大小(256KB)
PYI_BUF_SIZE: sizet = 262144
# 拓扑排序相关常量
MAX_CLASSES: t.CDefine = 512
MAX_FILE_DEPS: t.CDefine = 256
MAX_DEP_EDGES: t.CDefine = 16
SHA1_LEN: t.CDefine = 17
CLASS_NAME_LEN: t.CDefine = 64
define MAX_CLASSES = 512
define MAX_FILE_DEPS = 256
define MAX_DEP_EDGES = 16
define SHA1_LEN = 17
define CLASS_NAME_LEN = 64
+35 -35
View File
@@ -33,10 +33,10 @@ import lib.Stub.StubGen.Converter as StubConverter
_mbuddy: memhub.MemBuddy*
# 源代码缓冲区大小(1MB)
SRC_BUF_SIZE: t.CDefine = 1048576
define SRC_BUF_SIZE = 1048576
# 最大源文件数(递归扫描子目录后文件数增多;过小会截断文件列表 → 链接 undefined symbol,故留余量)
MAX_SRC_FILES: t.CDefine = 128
define MAX_SRC_FILES = 128
@t.NoVTable
class SrcFileEntry:
@@ -52,7 +52,7 @@ class SrcFileEntry:
# ============================================================
def _ScanDirForPyFiles(mb: memhub.MemBuddy*,
dir_path: str,
entries: SrcFileEntry | t.CPtr,
entries: SrcFileEntry*,
entry_size: sizet,
file_count: int, max_files: int) -> int:
"""递归扫描目录,收集 .vp/.py 文件到 entries,返回新的 file_count"""
@@ -68,7 +68,7 @@ def _ScanDirForPyFiles(mb: memhub.MemBuddy*,
viperlib.snprintf(pattern, dir_len + 16, "%s/*", dir_path)
find_data_size: sizet = w32.win32file.WIN32_FIND_DATAA.__sizeof__()
find_data: w32.win32file.WIN32_FIND_DATAA | t.CPtr = stdlib.malloc(find_data_size + 16)
find_data: w32.win32file.WIN32_FIND_DATAA* = stdlib.malloc(find_data_size + 16)
if find_data is None:
stdlib.free(pattern)
return file_count
@@ -130,7 +130,7 @@ def _ScanDirForPyFiles(mb: memhub.MemBuddy*,
sha1_val: str = IncludesScanner.compute_file_sha1(mb, full_path)
if sha1_val is not None:
ea: uint64 = uint64(entries) + file_count * entry_size
ent: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(ea)
ent: SrcFileEntry* = (SrcFileEntry*)(ea)
if ent is not None:
ent.Path = full_path
ent.Sha1 = sha1_val
@@ -158,7 +158,7 @@ def _ScanDirForPyFiles(mb: memhub.MemBuddy*,
# ============================================================
def _ScanDirForAsmFiles(mb: memhub.MemBuddy*,
dir_path: str,
entries: SrcFileEntry | t.CPtr,
entries: SrcFileEntry*,
entry_size: sizet,
file_count: int, max_files: int) -> int:
"""递归扫描目录,收集 .s 汇编文件到 entries,返回新的 file_count"""
@@ -174,7 +174,7 @@ def _ScanDirForAsmFiles(mb: memhub.MemBuddy*,
viperlib.snprintf(pattern, dir_len + 16, "%s/*", dir_path)
find_data_size: sizet = w32.win32file.WIN32_FIND_DATAA.__sizeof__()
find_data: w32.win32file.WIN32_FIND_DATAA | t.CPtr = stdlib.malloc(find_data_size + 16)
find_data: w32.win32file.WIN32_FIND_DATAA* = stdlib.malloc(find_data_size + 16)
if find_data is None:
stdlib.free(pattern)
return file_count
@@ -231,7 +231,7 @@ def _ScanDirForAsmFiles(mb: memhub.MemBuddy*,
sha1_val: str = IncludesScanner.compute_file_sha1(mb, full_path)
if sha1_val is not None:
ea: uint64 = uint64(entries) + file_count * entry_size
ent: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(ea)
ent: SrcFileEntry* = (SrcFileEntry*)(ea)
if ent is not None:
ent.Path = full_path
ent.Sha1 = sha1_val
@@ -257,7 +257,7 @@ def _ScanDirForAsmFiles(mb: memhub.MemBuddy*,
# 重复注册由 _register_generic_template 查重跳过。
# ============================================================
def _PreRegisterAppGenericTemplates(mb: memhub.MemBuddy*,
entries: SrcFileEntry | t.CPtr,
entries: SrcFileEntry*,
file_count: int,
entry_size: sizet) -> int:
"""mark2 前预注册 App 源文件的泛型类模板,返回处理到的泛型类数量"""
@@ -266,7 +266,7 @@ def _PreRegisterAppGenericTemplates(mb: memhub.MemBuddy*,
handled: int = 0
for i in range(file_count):
ea_pa: uint64 = uint64(entries) + i * entry_size
ent_pa: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(ea_pa)
ent_pa: SrcFileEntry* = (SrcFileEntry*)(ea_pa)
if ent_pa is None or ent_pa.Path is None or ent_pa.Sha1 is None:
continue
# 读取文件
@@ -643,7 +643,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy*,
# === 1. 递归扫描 source_dir 下的 .vp/.py 文件(包括子目录)===
entry_size: sizet = SrcFileEntry.__sizeof__()
entries: SrcFileEntry | t.CPtr = stdlib.malloc(MAX_SRC_FILES * entry_size)
entries: SrcFileEntry* = stdlib.malloc(MAX_SRC_FILES * entry_size)
if entries is None:
return 1
string.memset(entries, 0, MAX_SRC_FILES * entry_size)
@@ -652,7 +652,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy*,
VLogger.info(f"共 {file_count} 个源文件", "project")
# 扫描 .s 汇编文件(独立数组,不参与 Phase A 翻译,Phase B 后 llvm-mc 汇编)
asm_entries: SrcFileEntry | t.CPtr = stdlib.malloc(MAX_SRC_FILES * entry_size)
asm_entries: SrcFileEntry* = stdlib.malloc(MAX_SRC_FILES * entry_size)
if asm_entries is None:
stdlib.free(entries)
return 1
@@ -717,7 +717,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy*,
app_filled: int = 0
for i in range(file_count):
ea_am: uint64 = uint64(entries) + i * entry_size
ent_am: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(ea_am)
ent_am: SrcFileEntry* = (SrcFileEntry*)(ea_am)
if ent_am is None or ent_am.Path is None or ent_am.Sha1 is None:
continue
# 计算相对路径(去除 source_dir 前缀,保留目录结构)
@@ -759,7 +759,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy*,
vpi_failed_p2: int = 0
for i_vp2 in range(file_count):
ea_vp2: uint64 = uint64(entries) + i_vp2 * entry_size
ent_vp2: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(ea_vp2)
ent_vp2: SrcFileEntry* = (SrcFileEntry*)(ea_vp2)
if ent_vp2 is None or ent_vp2.Path is None or ent_vp2.Sha1 is None:
vpi_failed_p2 += 1
VLogger.error("[Phase A-pre-vpi] 源文件条目无效(Path/Sha1 缺失),跳过", "PhaseA")
@@ -890,7 +890,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy*,
is_app_file_inc: int = 0
for i_app_inc in range(file_count):
ea_app_inc: uint64 = uint64(entries) + i_app_inc * entry_size
ent_app_inc: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(ea_app_inc)
ent_app_inc: SrcFileEntry* = (SrcFileEntry*)(ea_app_inc)
if ent_app_inc is not None and ent_app_inc.Sha1 is not None \
and string.strcmp(ent_app_inc.Sha1, inc_sha1_pre) == 0:
is_app_file_inc = 1
@@ -951,18 +951,18 @@ def RunMultiFileProject(mb: memhub.MemBuddy*,
struct_count_before: int = GenApi.get_struct_count()
for i in range(file_count):
ea_pre: uint64 = uint64(entries) + i * entry_size
ent_pre: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(ea_pre)
ent_pre: SrcFileEntry* = (SrcFileEntry*)(ea_pre)
if ent_pre is None or ent_pre.Path is None:
continue
pkg_pre: str = None
if string.strlen(ent_pre.Path) > src_dir_len_pre + 1:
rel_path_pre: str = ent_pre.Path + src_dir_len_pre + 1
pkg_pre = GenApi.compute_package_from_relpath(mb, rel_path_pre)
# App 预注册传 pre_allow_dep_inject=1:声明期也做导入处理 + 依赖 vpi 注入,
# 使类字段注解在预注册期即与阶段 A 同上下文(否则包重导出类
# list[ast.ClassDef*] 的票名前缀会在预注册期被冻结成包前缀,与阶段 A
# 解析出的真定义前缀分裂 → 结构体布局不兼容,见 Translator 字段说明)。
tr_pre: rawptr[HandlesTranslator.Translator] = BuildPipeline.TranslateFileGetTrans(
# App 预注册传 pre_allow_dep_inject=1:声明期也做导入处理 + 依赖 vpi 注入,
# 使类字段注解在预注册期即与阶段 A 同上下文(否则包重导出类
# list[ast.ClassDef*] 的票名前缀会在预注册期被冻结成包前缀,与阶段 A
# 解析出的真定义前缀分裂 → 结构体布局不兼容,见 Translator 字段说明)。
tr_pre: rawptr[HandlesTranslator.Translator] = BuildPipeline.TranslateFileGetTrans(
mb, ent_pre.Path, ent_pre.Sha1, pkg_pre, 1, None, 1)
if tr_pre is None:
VLogger.error(f"预注册失败: {ent_pre.Path}", "PhaseA")
@@ -1009,7 +1009,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy*,
if done_flags[i] != 0:
continue
ea: uint64 = uint64(entries) + i * entry_size
ent: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(ea)
ent: SrcFileEntry* = (SrcFileEntry*)(ea)
# 计时点 0:本文件处理开始(translate 段起点)
t_pa0: uint64 = w32.win32base.GetTickCount64()
if ent is None or ent.Path is None:
@@ -1159,7 +1159,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy*,
for i_err in range(file_count):
if done_flags[i_err] == 0:
ea_err: uint64 = uint64(entries) + i_err * entry_size
ent_err: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(ea_err)
ent_err: SrcFileEntry* = (SrcFileEntry*)(ea_err)
if ent_err is not None and ent_err.Path is not None:
if ent_err.Sha1 is not None:
_PhaseADumpFailGraph(temp_dir, td_len_fail, ent_err.Path, ent_err.Sha1)
@@ -1214,7 +1214,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy*,
for i in range(file_count):
ea: uint64 = uint64(entries) + i * entry_size
ent: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(ea)
ent: SrcFileEntry* = (SrcFileEntry*)(ea)
if ent is None or ent.Path is None or ent.Sha1 is None:
continue
# 单文件三步计时起点(GetTickCount64,ms)
@@ -1310,7 +1310,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy*,
asm_compiled: int = 0
for ai_as in range(asm_file_count):
ea_as: uint64 = uint64(asm_entries) + ai_as * entry_size
ent_as: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(ea_as)
ent_as: SrcFileEntry* = (SrcFileEntry*)(ea_as)
if ent_as is None or ent_as.Path is None or ent_as.Sha1 is None:
continue
aret_as: int = BuildPipeline.asm_to_obj(
@@ -1380,7 +1380,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy*,
stdlib.free(app_deps_buf)
app_deps_buf = None
# 从全局存储器获取 SHA1/模块名 数组:复制局部副本(bytes),避免 store 联合返回值(bytes|t.CPtr)跨函数传参/索引的地址异常。
# 从全局存储器获取 SHA1/模块名 数组:复制局部副本(bytes),避免 store 联合返回值(bytes*)跨函数传参/索引的地址异常。
# rel/incdir 仅本函数内按索引读取(不跨函数传参),保留 store 指针。
td_len_pb: sizet = string.strlen(temp_dir)
store_sha1_arr_mi: bytes = stdlib.malloc(StubMerger.MAX_INCLUDES * 17)
@@ -1416,7 +1416,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy*,
app_skip_mi: int = 0
for ai_mi in range(file_count):
ea_ap: uint64 = uint64(entries) + ai_mi * entry_size
ent_ap: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(ea_ap)
ent_ap: SrcFileEntry* = (SrcFileEntry*)(ea_ap)
if ent_ap is not None and ent_ap.Sha1 is not None:
if string.strcmp(ent_ap.Sha1, inc_sha1_mi) == 0:
app_skip_mi = 1
@@ -1426,7 +1426,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy*,
# 检查 .obj 是否已存在于 includes.binary(切片子目录)
ibd_len_mi: sizet = string.strlen(includes_binary_dir)
check_pat_mi: str = StubMergerCollect._sliced_path(includes_binary_dir, ibd_len_mi, inc_sha1_mi, "obj")
check_fd_mi: w32.win32file.WIN32_FIND_DATAA | t.CPtr = stdlib.malloc(w32.win32file.WIN32_FIND_DATAA.__sizeof__())
check_fd_mi: w32.win32file.WIN32_FIND_DATAA* = stdlib.malloc(w32.win32file.WIN32_FIND_DATAA.__sizeof__())
obj_exists_mi: int = 0
if check_pat_mi is not None and check_fd_mi is not None:
string.memset(check_fd_mi, 0, w32.win32file.WIN32_FIND_DATAA.__sizeof__())
@@ -1529,12 +1529,12 @@ def RunMultiFileProject(mb: memhub.MemBuddy*,
ifff.write(inc_full_buf, inc_full_len)
ifff.close()
stdlib.free(inc_full_path)
stdlib.free(inc_full_buf)
# --traceback: 取出本模块的调试调用点记录并写 <sha1>.vpcall。
if BuildPipeline._traceback_mode != 0:
vpcall_text_mi: str = mlirlite.DebugTakeText()
if vpcall_text_mi is not None:
BuildPipeline.WriteCallSidecar(temp_dir, inc_sha1_mi, vpcall_text_mi)
stdlib.free(inc_full_buf)
# --traceback: 取出本模块的调试调用点记录并写 <sha1>.vpcall。
if BuildPipeline._traceback_mode != 0:
vpcall_text_mi: str = mlirlite.DebugTakeText()
if vpcall_text_mi is not None:
BuildPipeline.WriteCallSidecar(temp_dir, inc_sha1_mi, vpcall_text_mi)
stdlib.free(vpcall_text_mi)
# 重试读 full.ll
inc_combined_len_mi = StubMergerBuild.LoadFullIR(temp_dir, inc_sha1_mi, inc_combined_mi, COMBINED_IR_SIZE)
@@ -1683,7 +1683,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy*,
app_skip_pc: int = 0
for ai_pc in range(file_count):
ea_pc: uint64 = uint64(entries) + ai_pc * entry_size
ent_pc: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(ea_pc)
ent_pc: SrcFileEntry* = (SrcFileEntry*)(ea_pc)
if ent_pc is not None and ent_pc.Sha1 is not None:
if string.strcmp(ent_pc.Sha1, rsha1_pc) == 0:
app_skip_pc = 1
+24 -24
View File
@@ -88,75 +88,75 @@ def Load_project_config(path: str) -> int:
if bytes_read <= 0: return 1
# 解析 JSON
root: JsonValue | t.CPtr = json_parse(_mbuddy, buf)
root: JsonValue* = json_parse(_mbuddy, buf)
if root is None: return 1
if not root.is_object(): return 1
# 读取顶层字段(使用显式 __getitem__ 调用,兼容旧编译器二进制)
sd_val: JsonValue | t.CPtr = root["source_dir"]
sd_val: JsonValue* = root["source_dir"]
SourceDir = sd_val.as_string() if sd_val is not None else None
# build_dir: 统一构建目录(默认 ./.tpv_build),temp 和 output 作为其子目录
bd_val: JsonValue | t.CPtr = root["build_dir"]
bd_val: JsonValue* = root["build_dir"]
if bd_val is not None and bd_val.is_string():
BuildDir = bd_val.as_string()
else:
BuildDir = "./.tpv_build"
name_val: JsonValue | t.CPtr = root["name"]
name_val: JsonValue* = root["name"]
ProjectName = name_val.as_string() if name_val is not None else None
ver_val: JsonValue | t.CPtr = root["version"]
ver_val: JsonValue* = root["version"]
ProjectVersion = ver_val.as_string() if ver_val is not None else None
# 读取 compiler 子对象
compiler: JsonValue | t.CPtr = root["compiler"]
compiler: JsonValue* = root["compiler"]
if compiler is not None and compiler.is_object():
cc_cmd_val: JsonValue | t.CPtr = compiler["cmd"]
cc_cmd_val: JsonValue* = compiler["cmd"]
CompilerCmd = cc_cmd_val.as_string() if cc_cmd_val is not None else None
# 读取 compiler.flags 数组,拼接成空格分隔的字符串
cc_flags_val: JsonValue | t.CPtr = compiler["flags"]
cc_flags_val: JsonValue* = compiler["flags"]
CompilerFlags = _join_flags_array(cc_flags_val)
# 读取 linker 子对象
linker: JsonValue | t.CPtr = root["linker"]
linker: JsonValue* = root["linker"]
if linker is not None and linker.is_object():
ld_cmd_val: JsonValue | t.CPtr = linker["cmd"]
ld_cmd_val: JsonValue* = linker["cmd"]
LinkerCmd = ld_cmd_val.as_string() if ld_cmd_val is not None else None
ld_out_val: JsonValue | t.CPtr = linker["output"]
ld_out_val: JsonValue* = linker["output"]
LinkerOutput = ld_out_val.as_string() if ld_out_val is not None else None
# 读取 linker.flags 数组,拼接成空格分隔的字符串
ld_flags_val: JsonValue | t.CPtr = linker["flags"]
ld_flags_val: JsonValue* = linker["flags"]
LinkerFlags = _join_flags_array(ld_flags_val)
# 读取 linker.static_libs 数组:显式静态链接文件(.a/.obj),
# 先拼接原样字符串,resolve_paths 中再基于 project_dir 解析绝对路径
sl_val: JsonValue | t.CPtr = linker["static_libs"]
sl_val: JsonValue* = linker["static_libs"]
LinkerStaticLibs = _join_flags_array(sl_val)
# 读取 linker.dynamic_libs 数组:显式动态链接文件(.dll/.so),
# 同样先拼接原样字符串,resolve_paths 中基于 project_dir 解析绝对路径
dl_val: JsonValue | t.CPtr = linker["dynamic_libs"]
dl_val: JsonValue* = linker["dynamic_libs"]
LinkerDynamicLibs = _join_flags_array(dl_val)
# 读取 target 子对象
target: JsonValue | t.CPtr = root["target"]
target: JsonValue* = root["target"]
if target is not None and target.is_object():
tgt_triple_val: JsonValue | t.CPtr = target["triple"]
tgt_triple_val: JsonValue* = target["triple"]
TargetTriple = tgt_triple_val.as_string() if tgt_triple_val is not None else None
tgt_dl_val: JsonValue | t.CPtr = target["datalayout"]
tgt_dl_val: JsonValue* = target["datalayout"]
TargetDataLayout = tgt_dl_val.as_string() if tgt_dl_val is not None else None
# 读取 options 子对象
# Sha1SliceLevel: SHA1 切片层数(默认 1,每层取 SHA1 前 2 字符作为子目录:0=不切片, 1=b7/, 2=b7/90/)
options: JsonValue | t.CPtr = root["options"]
options: JsonValue* = root["options"]
Sha1SliceLevel = 1
StrictMode = 1
if options is not None and options.is_object():
sl: JsonValue | t.CPtr = options["sha1_slice_level"]
sl: JsonValue* = options["sha1_slice_level"]
if sl is not None and sl.is_int():
Sha1SliceLevel = sl.as_int()
sm: JsonValue | t.CPtr = options["strict_mode"]
sm: JsonValue* = options["strict_mode"]
if sm is not None and sm.is_bool():
StrictMode = 1 if sm.as_bool() else 0
# 读取 includes 数组(支持多目录:首元素存 IncludesDir,全部拼接存 IncludesDirs)
includes_val: JsonValue | t.CPtr = root["includes"]
includes_val: JsonValue* = root["includes"]
if includes_val is not None and includes_val.is_array():
arr_len: sizet = len(includes_val)
inc_buf: bytes = stdlib.malloc(2048)
@@ -164,7 +164,7 @@ def Load_project_config(path: str) -> int:
inc_buf[0] = '\0'
inc_pos: sizet = 0
for inc_i in range(arr_len):
inc_item: JsonValue | t.CPtr = includes_val.get_item(inc_i)
inc_item: JsonValue* = includes_val.get_item(inc_i)
if inc_item is None or not inc_item.is_string():
continue
inc_str: str = inc_item.as_string()
@@ -186,7 +186,7 @@ def Load_project_config(path: str) -> int:
return 0
def _join_flags_array(flags_val: JsonValue | t.CPtr) -> str:
def _join_flags_array(flags_val: JsonValue*) -> str:
"""将 JSON 字符串数组拼接成空格分隔的字符串
用于 linker.flags 和 compiler.flags 数组。
@@ -208,7 +208,7 @@ def _join_flags_array(flags_val: JsonValue | t.CPtr) -> str:
# 第一遍:计算总长度(所有 flag 长度 + 空格分隔符)
total_len: sizet = 0
for i in range(arr_len):
item: JsonValue | t.CPtr = flags_val.get_item(i)
item: JsonValue* = flags_val.get_item(i)
if item is not None and item.is_string():
s: str = item.as_string()
if s is not None:
+1 -1
View File
@@ -207,7 +207,7 @@ def CleanDir(dir_path: str) -> int:
return -1
viperlib.snprintf(pattern, dir_len + 8, "%s/*", dir_path)
find_data: w32.win32file.WIN32_FIND_DATAA | t.CPtr = stdlib.malloc(w32.win32file.WIN32_FIND_DATAA.__sizeof__())
find_data: w32.win32file.WIN32_FIND_DATAA* = stdlib.malloc(w32.win32file.WIN32_FIND_DATAA.__sizeof__())
if find_data is None:
stdlib.free(pattern)
return -1
+8 -8
View File
@@ -104,8 +104,8 @@ _g_pyi_cdefine_found: int = 0
# 本文件 CDefine 值缓存(vpi 生成专用):vpi 生成早于翻译阶段注册(全局表为空),_GeneratePyiFromAst 开头按声明顺序注册,Name 引用先查本缓存。
# 两个缓存必须是 C 数组(int64* / i8**)而非 list[T]——list[int].get 会误解析为 list[str].get(返回元素地址)、list[str] 联合接收者的 .get 会误分派为 HashTable.get(索引 inttoptr 成 key 指针 → 零页崩溃);索引一律用 t.CPtr(base + i*8) + e[0]。
_g_pyi_cdef_names: str | t.CPtr = None
_g_pyi_cdef_vals: int64 | t.CPtr = None
_g_pyi_cdef_names: str* = None
_g_pyi_cdef_vals: int64* = None
_g_pyi_cdef_count: int = 0
@@ -117,7 +117,7 @@ def _lookup_cdefine_for_pyi(name: str) -> int64:
# 循环上限用 _g_pyi_cdef_count,且绝不能用 len()/.get:i8** 指针数组上 len() 回退 strlen(基址当字符串算长度 → 垃圾小值 → 靠后注册项查不到),.get 会被误分派为 HashTable.get(索引 inttoptr 成 key 指针 → 零页崩溃);用 t.CPtr(base + i*8) + e[0] 依次取名。
pn: sizet = sizet(_g_pyi_cdef_count)
for pi in range(pn):
entry_pc: str | t.CPtr = (str | t.CPtr)(uint64(_g_pyi_cdef_names) + pi * 8)
entry_pc: str* = (str*)(uint64(_g_pyi_cdef_names) + pi * 8)
pnm: str = entry_pc[0]
if pnm is not None and string.strcmp(pnm, name) == 0:
_g_pyi_cdefine_found = 1
@@ -310,7 +310,7 @@ def _PyiTypeStr(buf: bytes, buf_size: sizet, pos: sizet,
if k == ast.ASTKind.Compare:
cmp_t: rawptr[ast.Compare] = rawptr[ast.Compare](annot)
pos = _PyiTypeStr(buf, buf_size, pos, cmp_t.left, depth + 1)
ops_ct: list[int] | t.CPtr = (list[int] | t.CPtr)(cmp_t.ops)
ops_ct: list[int]* = (list[int]*)(cmp_t.ops)
cmps_ct: list[ast.AST*]* = cmp_t.comparators
if ops_ct is not None:
on_ct: sizet = len(ops_ct)
@@ -826,8 +826,8 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy*, tree: ast.AST*,
if ann_pc0.attr is not None and string.strcmp(ann_pc0.attr, "CDefine") == 0:
_g_pyi_cdef_count += 1
if _g_pyi_cdef_count > 0:
_g_pyi_cdef_names = (str | t.CPtr)(mb.alloc(sizet(_g_pyi_cdef_count) * 8))
_g_pyi_cdef_vals = (int64 | t.CPtr)(mb.alloc(sizet(_g_pyi_cdef_count) * 8))
_g_pyi_cdef_names = (str*)(mb.alloc(sizet(_g_pyi_cdef_count) * 8))
_g_pyi_cdef_vals = (int64*)(mb.alloc(sizet(_g_pyi_cdef_count) * 8))
# 第二遍:按声明顺序注册(BinOp 内 Name 引用依赖先前注册项)
pci: sizet = 0
cdi: int = 0
@@ -842,7 +842,7 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy*, tree: ast.AST*,
ann_pc: ast.Attribute* = ast.Attribute*(aa_pc.annotation)
if ann_pc.attr is not None and string.strcmp(ann_pc.attr, "CDefine") == 0:
if _g_pyi_cdef_names is not None and _g_pyi_cdef_vals is not None:
slot_pc: str | t.CPtr = (str | t.CPtr)(uint64(_g_pyi_cdef_names) + cdi * 8)
slot_pc: str* = (str*)(uint64(_g_pyi_cdef_names) + cdi * 8)
slot_pc[0] = tgt_pc.id
_g_pyi_cdef_vals[cdi] = _eval_cdefine_value_cache(aa_pc.value)
cdi += 1
@@ -1159,7 +1159,7 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy*, tree: ast.AST*,
if inferred == 1:
pos = _PyiEmit(buf, buf_size, pos, "int")
elif inferred == 2:
pos = _PyiEmit(buf, buf_size, pos, "t.CDouble")
pos = _PyiEmit(buf, buf_size, pos, "double")
elif inferred == 3:
pos = _PyiEmit(buf, buf_size, pos, "str")
elif inferred == 4:
+44 -44
View File
@@ -26,7 +26,7 @@ import lib.Projectrans.Config as Config
# 该机制仅在 ReplStubLayoutMode != 0(REPL 会话初始化)时生效,批处理恒 0。
# ============================================================
_REPL_STUB_CLS_MAX: t.CDefine = 1024
define _REPL_STUB_CLS_MAX = 1024
_REPL_STUB_FIELD_MAX: int = 128
_REPL_STUB_VT_MAX: int = 128
_REPL_STUB_TXT_CAP: sizet = 4194304
@@ -42,22 +42,22 @@ _REPL_STUB_NOCOUNT_OPAQUE: int = -2 # meta 里该 key 是 OPAQUE(无 body
# 布局"不可用 ⇒ 明确拒绝"的原因码(_repl_stub_warn_nodata):把"数据缺失"
# (上层数据没到位,补 meta/重跑即可消除)与"判据拒绝"(数据在但不可信,绝不放行)
# 在文案与汇总计数上分开 —— 两类都会走到"不登记 StructEntry",但成因完全不同。
_REPL_SU_NOSTUB: t.CDefine = 1 # 数据缺失:整个模块没有 {sha1}.meta
_REPL_SU_NOCLASS: t.CDefine = 2 # 判据拒绝:meta 存在但无该类的 STRUCT 行
_REPL_SU_OPAQUE: t.CDefine = 3 # 判据拒绝:meta 里该类为 OPAQUE(无 body)
_REPL_SU_PARENT: t.CDefine = 4 # 上游无数据:父类布局不可用/未在会话注册(走 _repl_stub_warn_parent)
define _REPL_SU_NOSTUB = 1 # 数据缺失:整个模块没有 {sha1}.meta
define _REPL_SU_NOCLASS = 2 # 判据拒绝:meta 存在但无该类的 STRUCT 行
define _REPL_SU_OPAQUE = 3 # 判据拒绝:meta 里该类为 OPAQUE(无 body)
define _REPL_SU_PARENT = 4 # 上游无数据:父类布局不可用/未在会话注册(走 _repl_stub_warn_parent)
# ReplStubClass.Flags / MethodFlags 位
_REPL_SF_CVTABLE: t.CDefine = 1
_REPL_SF_NOVTABLE: t.CDefine = 2
_REPL_SF_ANYFUNC: t.CDefine = 4
_REPL_SF_PACKED: t.CDefine = 8
define _REPL_SF_CVTABLE = 1
define _REPL_SF_NOVTABLE = 2
define _REPL_SF_ANYFUNC = 4
define _REPL_SF_PACKED = 8
# ReplStubClass.State
_REPL_SS_REFUSED: t.CDefine = 0 # 布局不可信:永不登记(字段访问明确失败)
_REPL_SS_OK: t.CDefine = 1 # 完整布局已登记
_REPL_SS_PENDING: t.CDefine = 2 # 父类尚未就绪:留待收尾遍
_REPL_SS_EMPTY: t.CDefine = 3 # 无父类/无虚表/字段类型不可解析:交既有 vpi 注入口径
define _REPL_SS_REFUSED = 0 # 布局不可信:永不登记(字段访问明确失败)
define _REPL_SS_OK = 1 # 完整布局已登记
define _REPL_SS_PENDING = 2 # 父类尚未就绪:留待收尾遍
define _REPL_SS_EMPTY = 3 # 无父类/无虚表/字段类型不可解析:交既有 vpi 注入口径
class ReplStubClass:
Key: str # "<sha1>.<类名>"(= 定义侧命名结构体名)
@@ -97,9 +97,9 @@ class ReplStubClass:
# 故改文本提取:ParseVpiIntoModule 读 .vpi stub 时从 vpi_buf 原始文本(函数末尾才释放,始终有效)按行提取 "def m(...) -> Ret:" 的返回注解字符串缓存到 stdlib(持久,不受 pool 状态影响);
# HandlesExprCall._lookup_method_ret_ty_via_vpi 按 sha1.类名.方法名 查表并用 _resolve_vpi_ret_annot_str 纯字符串解析为 LLVMType,返回类型始终来自方法定义处,无白名单/无硬编码。
# ============================================================
VPI_RET_MAX: t.CDefine = 4096
VPI_KEY_LEN: t.CDefine = 224
VPI_RET_LEN: t.CDefine = 224
define VPI_RET_MAX = 4096
define VPI_KEY_LEN = 224
define VPI_RET_LEN = 224
_g_vpi_ret_keys: bytes = None
_g_vpi_ret_strs: bytes = None
@@ -113,9 +113,9 @@ _g_vpi_ret_cap: int = 0
# 调用点缺参(fill 无法超 declare 补)→ 被调函数按 x64 ABI 读残留寄存器/栈槽垃圾。故与返回注解同源:从 vpi_buf 原始文本按行提取参数注解串缓存,
# 注入 declare 时若 tree 参数数不足则用缓存补全,保证 declare 与 define 参数数一致。
# ============================================================
VPI_PARAM_MAX: t.CDefine = 4096
VPI_PARAM_KEY_LEN: t.CDefine = 224
VPI_PARAM_LEN: t.CDefine = 1024
define VPI_PARAM_MAX = 4096
define VPI_PARAM_KEY_LEN = 224
define VPI_PARAM_LEN = 1024
# ============================================================
# 键表开放寻址索引(名 → 槽下标)
@@ -127,12 +127,12 @@ VPI_PARAM_LEN: t.CDefine = 1024
# 顺序递增排列,查找取链上首个"当前键相等"者 = 原线性扫描首个命中(首注册
# 优先)。可信判据 = Built == Count;不可信/未命中一律回退原线性扫描。
# ============================================================
VPI_RET_IDX_CAP: t.CDefine = 8192
VPI_PARAM_IDX_CAP: t.CDefine = 8192
define VPI_RET_IDX_CAP = 8192
define VPI_PARAM_IDX_CAP = 8192
# 索引哈希常量(32 位 FNV-1a,与 StructGenMixin 范式一致)
VPI_IDX_FNV_OFFSET: t.CDefine = 2166136261
VPI_IDX_FNV_PRIME: t.CDefine = 16777619
VPI_IDX_FNV_MASK: t.CDefine = 4294967295
define VPI_IDX_FNV_OFFSET = 2166136261
define VPI_IDX_FNV_PRIME = 16777619
define VPI_IDX_FNV_MASK = 4294967295
_g_vpi_param_keys: bytes = None
_g_vpi_param_strs: bytes = None
@@ -845,7 +845,7 @@ def _resolve_vpi_param_annot_seg_template(pool: memhub.MemBuddy*,
break
string.strncpy(seg_buf_t, annots_t + seg_start_t, seg_len_t)
seg_buf_t[seg_len_t] = '\0'
# 类型形参 token(如 T)→ 特化实参(如 str / rawptr[AST] / AST|t.CPtr):
# 类型形参 token(如 T)→ 特化实参(如 str / rawptr[AST] / AST*):
# 模板注解按源码原样缓存,不替换则 `item: T` 解析不出类型(None 跳过)
tparam_t: bytes = stdlib.malloc(tplen_t + 1)
if tparam_t is not None:
@@ -1069,7 +1069,7 @@ def _vpi_param_annot_seg_is(src_sha1: str, cls_name: str, method_name: str,
self 占位(空串)。本函数只做逐字节等值比较,不解析、不做模板类型形参替换
——调用方是跨模块调用的**热路径**(每个实参一次),不能在此分配/解析。
典型用途:判定定义侧形参注解是否为**裸** `str` / `bytes`(用于"str/bytes
不是通用指针通配"这条规则;`str | t.CPtr` 这类组合段不等值,不受影响)。
不是通用指针通配"这条规则;`str*` 这类组合段不等值,不受影响)。
"""
if want is None or seg_idx < 0:
return 0
@@ -1264,8 +1264,8 @@ def _lookup_vpi_ret_annot(src_sha1: str, cls_name: str, method_name: str) -> str
if hit_r >= 0:
stdlib.free(key_buf)
return _g_vpi_ret_strs + hit_r * VPI_RET_LEN
# 泛型特化归一化匹配:list[AST|t.CPtr].get → list[T].get 模板缓存。
# 命中后把模板注解中的类型参数名(如 T)替换为实参(AST|t.CPtr)再返回。
# 泛型特化归一化匹配:list[AST*].get → list[T].get 模板缓存。
# 命中后把模板注解中的类型参数名(如 T)替换为实参(AST*)再返回。
# 不依赖模板类已注册/特化已发生(base.vp 可能先于 list 模块翻译)。
if cls_name is not None:
lbkt_v: str = string.strchr(cls_name, '[')
@@ -1324,13 +1324,13 @@ def _resolve_single_vpi_type_str(pool: memhub.MemBuddy*,
if seg is None or pool is None:
return None
# 【指针实参唯一规范形 `T*`(用户定口径,2026-09-30)】`rawptr[T]` ≡
# `t.CPtr[T]` ≡ `T | t.CPtr` ⇒ 一律折叠为 `T*`(见 TypeGenResolve
# `t.CPtr[T]` ≡ `T*` ⇒ 一律折叠为 `T*`(见 TypeGenResolve
# ._norm_type_arg_name 规则 1.0/1.5)。为什么必须在此补:_subst_template_arg
# 会用**特化类名 `[...]` 内的已归一实参文本**(如 "{sha}.AST*")替换模板注解
# 里的 T,替换结果再送到本函数解析;本函数此前只认 `rawptr[` / `t.CPtr[` /
# 裸 `t.CPtr`,遇到 `{sha}.AST*` 会落到下方 strrchr('.') 取末段得 "AST*" →
# 查 struct miss → **静默**返回 None(跨模块参数/返回宽度被悄悄收窄)。
# 现场:Test/AstTest/App/main.vp:21 的 `list[ast.AST | t.CPtr] | t.CPtr` 特化链。
# 现场:Test/AstTest/App/main.vp:21 的 `list[ast.AST*] | t.CPtr` 特化链。
# 最小改法:把尾随 `*`(先跳尾随空格)按层数重写回**已存在**的 `rawptr[...]`
# 文本形再走原分支(与 `rawptr[` 分支逐字等价,不新写 Ptr 包装逻辑):
# "{sha}.AST*" → "rawptr[{sha}.AST]";"i8**" → "rawptr[rawptr[i8]]"。
@@ -1482,7 +1482,7 @@ def _resolve_single_vpi_type_str(pool: memhub.MemBuddy*,
#
# 纯字符串解析,避免 _parse_type_string 跨模块构造 ast.Name/ast.BinOp 时节点 kind() 异常(可能退化为裸函数调用)导致 resolve 得到垃圾类型(如 Ptr(i8))。
#
# 支持: "str"/"bytes" → i8*; "int" → i32; "bool" → i1; "char" 等 → map_t_type 映射; "X | t.CPtr" → Ptr(Struct X); "t.CPtr" → i8*; "memhub.MemBuddy*" → Ptr(Struct MemBuddy)。
# 支持: "str"/"bytes" → i8*; "int" → i32; "bool" → i1; "char" 等 → map_t_type 映射; "X*" → Ptr(Struct X); "t.CPtr" → i8*; "memhub.MemBuddy*" → Ptr(Struct MemBuddy)。
# ============================================================
def _resolve_vpi_ret_annot_str(pool: memhub.MemBuddy*,
ret_annot: str,
@@ -1576,13 +1576,13 @@ def _resolve_vpi_ret_annot_str(pool: memhub.MemBuddy*,
# first_wl =1 段是白名单裸标量名(int/char/str/bytes/bool/float/double)
# first_td =1 段是裸 typedef 别名且已成功解析出**非指针**类型(N13,
# 如 sizet/uint64 ⇒ i64):判据=“解析是否成功”,与定义侧
# TypeGenResolve.resolve_annotation_type 的 BinOp(A | t.CPtr)
# TypeGenResolve.resolve_annotation_type 的 BinOp(A*)
# 分支同源(同一 resolve_typedef_or_map 口径)。
first_qual: int = 0
first_wl: int = 0
first_td: int = 0
# CPtr 下标段(t.CPtr[T]/c.CPtr[T],含嵌套)的联合合并参数:cptr_sub_lvl = 该段解析后的外层 Ptr 层数 N(如 t.CPtr[t.CPtr] ⇒ 2);cptr_sub_ty = 该段解析出的类型本身。
# 与定义侧 `X | t.CPtr[T]` 分支同口径:CPtr 侧贡献 N 层指针、另一侧提供基类型 ⇒ Ptr^N(基类型)。
# 与定义侧 `X*[T]` 分支同口径:CPtr 侧贡献 N 层指针、另一侧提供基类型 ⇒ Ptr^N(基类型)。
# 与 has_cptr(裸 t.CPtr 段)分开记录:裸标记恒「追加 1 层」且有 struct 吸收特例,下标路径无吸收,两者在定义侧分属互斥分支。
cptr_sub_lvl: int = 0
cptr_sub_ty: mlirlite.LLVMType* = None
@@ -1595,7 +1595,7 @@ def _resolve_vpi_ret_annot_str(pool: memhub.MemBuddy*,
pos += 1
seg_start: sizet = pos
# 只在**顶层**切 `|`:`[...]` 内的 `|` 属于泛型实参内部的联合注解,裸切会把首段
# 截成 `list[ast.AST`(来自 `list[ast.AST | t.CPtr] | t.CPtr`),该段再经
# 截成 `list[ast.AST`(来自 `list[ast.AST*] | t.CPtr`),该段再经
# strrchr('.') 落到 `AST` ⇒ 定义侧解析成 `AST*`(元素的指针),而正确答案是
# list 专化结构的指针(至少也应落 i8* 通配)。深度计数按 `[`/`]`,与
# _cache_vpi_param_annots_text 的顶层逗号切分同口径。
@@ -1624,7 +1624,7 @@ def _resolve_vpi_ret_annot_str(pool: memhub.MemBuddy*,
seg_buf[seg_len2] = '\0'
# CPtr 下标段(t.CPtr[T]/c.CPtr[T],含嵌套如 t.CPtr[t.CPtr]):
# 必须先行识别,不能落普通段分支取 first_ty——定义侧
# TypeGenResolve.vp L2596-2639 对 `X | t.CPtr[T]` 是"CPtr 侧贡献
# TypeGenResolve.vp L2596-2639 对 `X*[T]` 是"CPtr 侧贡献
# N 层指针、另一侧给基类型 ⇒ Ptr^N(X)",与"把该段本身当联合取值"
# 语义不同(如 X=struct S、t.CPtr[t.CPtr]:定义侧 Ptr(Ptr(S)),
# 取该段本身则得 i8**)。此处只记录 N 与段类型,末尾统一合并。
@@ -1652,7 +1652,7 @@ def _resolve_vpi_ret_annot_str(pool: memhub.MemBuddy*,
cptr_sub_ty = seg_ty_cs
elif string.strcmp(seg_buf, "t.CPtr") == 0 or string.strcmp(seg_buf, "CPtr") == 0:
has_cptr = 1
elif string.strcmp(seg_buf, "t.CVoid") == 0 or string.strcmp(seg_buf, "CVoid") == 0 \
elif string.strcmp(seg_buf, "void") == 0 or string.strcmp(seg_buf, "CVoid") == 0 \
or string.strcmp(seg_buf, "void") == 0:
# 裸名 void 是 t.CVoid 的别名(用户 2026-10-01):必须与 CVoid 同处理,
# 否则会走 else 分支取到 first_td=1 → Ptr(Void) 这种非法类型
@@ -1665,7 +1665,7 @@ def _resolve_vpi_ret_annot_str(pool: memhub.MemBuddy*,
# 记录该段属性(N12):定义侧 TypeGenResolve.resolve_annotation_type
# 对**裸名** pointee 仅在它解析为已注册结构体、泛型参数名或白名单
# 裸标量时才保留 pointee,否则联合坍缩为 i8*;stub 侧此前无条件
# Ptr(first_ty) → `uint64 | t.CPtr` 两侧不一致(定义 i8* vs declare i64*)。
# Ptr(first_ty) → `uint64*` 两侧不一致(定义 i8* vs declare i64*)。
if string.strchr(seg_buf, 46) is not None:
first_qual = 1
if string.strcmp(seg_buf, "int") == 0 or \
@@ -1700,7 +1700,7 @@ def _resolve_vpi_ret_annot_str(pool: memhub.MemBuddy*,
pass
# 复刻定义侧规则(N12/N13):限定名 / 白名单裸标量 / 已注册结构体 / 可解析的非指针裸 typedef 别名 → 保留 pointee;
# 其余(解析失败、裸枚举名、指针别名)→ 联合坍缩为 i8*,与定义侧 resolve_annotation_type 对称(两侧同型即收敛)。
# 指针别名(first_td 不置位,如 VOIDPTR = CVoid|CPtr → i8*):`| t.CPtr`
# 指针别名(first_td 不置位,如 VOIDPTR = CVoid* → i8*):`| t.CPtr`
# **恒追加恰好 1 层** → i8**(不吸收);指针型 T 同理(见下)。
if first_qual != 0 or first_wl != 0 or first_td != 0:
return mlirlite.Ptr(pool, first_ty)
@@ -1809,7 +1809,7 @@ def _extract_sha1_from_path(vpi_path: str) -> str:
# → 参数类型解析失败退化为 i8_ptr_ty → 调用侧整数实参触发「整数隐式转指针已禁止」CastError 误报。
# 本函数在被读 stub 的 import 闭包上递归注册 CTypedef/CDefine(防环、限深),使注解解析上下文完整,参数/返回类型不再静默退化。
# ============================================================
_TYPEDEF_VISIT_MAX: t.CDefine = 1024
define _TYPEDEF_VISIT_MAX = 1024
_g_vpi_typedef_visited: bytes = None
_g_vpi_typedef_visited_count: int = 0
@@ -2348,7 +2348,7 @@ def _ParseVpiIntoModuleImpl(pool: memhub.MemBuddy*,
else:
src_mod_buf[sri_src] = ch_src
src_mod_buf[sr_len_src] = '\0'
imported_modules = StubMergerStore.AppendImportedModule(
imported_modules = StubMergerStore.AppendImportedModule(
pool, imported_modules, src_mod_buf)
stdlib.free(src_mod_buf)
@@ -2549,7 +2549,7 @@ def _ParseVpiIntoModuleImpl(pool: memhub.MemBuddy*,
# 故在重导出注册发现「源 entry 为空」时,按需把 sub_sha1 的 vpi 注入当前模块再重试注册(注入过程递归触发同一逻辑,依赖闭包自动补齐,与加载顺序无关)。
# 防重入表按 sha1 去重(环直接短路);注入失败不改语义,照原逻辑 return 0,不把可恢复问题升级为 fatal。
# ============================================================
VPI_INJ_MAX: t.CDefine = 1024
define VPI_INJ_MAX = 1024
_vpi_inj_sha1s: bytes = None
_vpi_inj_count: int = 0
_vpi_inj_depth: int = 0
@@ -3105,7 +3105,7 @@ def _AggregateParamTy(mod: mlirlite.LLVMModule*,
# ============================================================
# _inject_global_variable_declare - 从 vpi AnnAssign 创建模块级全局变量 declare
#
# vpi 里模块级全局变量(如 tokens.vp 的 _op_head: OpEntry | t.CPtr = None)需在当前模块创建 external global 声明(短名 @name,COFF 按名链接),
# vpi 里模块级全局变量(如 tokens.vp 的 _op_head: OpEntry* = None)需在当前模块创建 external global 声明(短名 @name,COFF 按名链接),
# 否则跨模块 from-import 读取全局变量时 find_global_in_module 找不到 → 误杀「跨模块全局变量类型未知(stub 未注入)」。
# ============================================================
def _inject_global_variable_declare(pool: memhub.MemBuddy*,
@@ -3272,8 +3272,8 @@ def _inject_function_declare(pool: memhub.MemBuddy*,
# 依赖版本会占用该名字 → forward_declare_functions 见名已存在即 continue
# (FuncGenDef.vp:178-182)→ 本文件自己的签名被静默丢弃,调用点改按依赖签名
# coerce。现场:includes/socket.vp 的
# `extern def connect(fd: u64, addr: SocketAddr | t.CPtr, addrlen: INT)`
# 被 w32.winsock2 的 `connect(..., WSASocketAddr | t.CPtr, ...)` 顶掉 →
# `extern def connect(fd: u64, addr: SocketAddr*, addrlen: INT)`
# 被 w32.winsock2 的 `connect(..., WSASocketAddr*, ...)` 顶掉 →
# socket.vp:236 `connect(self.fd, c.Addr(addr), 16)` 报
# 「指针隐式转指针已禁止:SocketAddr* → WSASocketAddr*」。
# 判据只用**裸名**:带 SHA1 前缀的依赖函数名与本文件同名声明不会相互顶替。
+1 -1
View File
@@ -363,7 +363,7 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy*, source_dir: str,
stdlib.free(mod_buf)
continue
# 输出槽防御性初始化(成功路径必全写;未找到/未命中时仅 free 槽本身)
# 槽联合必须用 (sizet*):t.CPtr|t.CPtr 会被折叠成 t.CPtr,
# 槽联合必须用 (sizet*):t.CPtr* 会被折叠成 t.CPtr,
# [0] 变成 1 字节访问 → 指针被截断(0x2e 崩溃根因)。CSizeT 成员为
# 8 字节:写侧 sizet(ptr),读侧必须用 rawptr(slot[0]) 做 u64→
# 指针转换;str(slot[0]) 是内置"数字转字符串"(snprintf 到栈缓冲并返回
+1 -1
View File
@@ -422,7 +422,7 @@ def LookupSha1ByModName(mod_name: str) -> str:
# 批处理不登记(表恒空 ⇒ 查询恒 None ⇒ 批处理路径一字不改)。
# 容量:includes 现有 6 个泛型类定义(list/dict 系 + Vector/GSList/ndarray),取 32 槽。
# ============================================================
GENERIC_OWNER_MAX: t.CDefine = 32
define GENERIC_OWNER_MAX = 32
_generic_owner_names: bytes = None
_generic_owner_sha1s: bytes = None
_generic_owner_count: int = 0
+1 -1
View File
@@ -103,7 +103,7 @@ def BuildTopoSortedIndices(store_count: int, store_sha1_arr: bytes,
dsha1: str = StubMergerIR._FindSha1ByModName(store_sha1_arr, store_mod_arr, store_count, dname_buf)
stdlib.free(dname_buf)
if dsha1 is not None and StubMergerCollect._is_in_sha1_set(dsha1, reachable_set, reachable_count) != 0:
# 中间 int 变量累加:绕过联合类型(CSizeT|CPtr)+ 整数的指针算术编译 bug
# 中间 int 变量累加:绕过联合类型(CSizeT*)+ 整数的指针算术编译 bug
indg: int = indegree[si]
indg = indg + 1
indegree[si] = indg
+7 -7
View File
@@ -30,16 +30,16 @@ import lib.Projectrans.Config as Config
_mbuddy: memhub.MemBuddy*
# 最大 includes SHA1 数(用于过滤)
MAX_INCLUDES_SHA1: t.CDefine = 1024
define MAX_INCLUDES_SHA1 = 1024
# stub/text 读取缓冲区大小
# 1MB 不够:ast/parser.vp 的 text.ll >1MB,读取本地 text.ll 单次截断
# → 尾部丢字(opt: "end of file in global variable name")。
STUB_READ_BUF_SIZE: t.CDefine = 8388608
define STUB_READ_BUF_SIZE = 8388608
# 最大 includes 条目数
MAX_INCLUDES: t.CDefine = 1024
define MAX_INCLUDES = 1024
# 可达性分析 worklist/processed 缓冲区大小(8192 不够:递归扫描 source_dir
# 后 worklist 含全部 App 文件 imports 的拼接 + BFS 依赖展开,追加82 溢出)
REACH_WORKLIST_BUF: t.CDefine = 65536
define REACH_WORKLIST_BUF = 65536
# 全局 SHA1 映射存储器(内存中,不依赖 _sha1_map.txt 文件)
# Phase1 扫描完成后填充,供所有函数使用
@@ -57,9 +57,9 @@ _includes_deps_str: bytes # 依赖字符串数组(每个 512 字节,MAX_IN
_includes_deps_count: int # 条目数
# 单条依赖字符串最大长度
MAX_DEPS_STR_LEN: t.CDefine = 512
define MAX_DEPS_STR_LEN = 512
# rel_path 最大长度
MAX_REL_PATH_LEN: t.CDefine = 256
define MAX_REL_PATH_LEN = 256
# includes 根目录最大长度(绝对路径,多 includes 支持)
MAX_INC_DIR_LEN: t.CDefine = 512
define MAX_INC_DIR_LEN = 512
+39 -39
View File
@@ -119,7 +119,7 @@ novirtual class AssignGenMixin:
# Case 4: Call — 如 t.CUnsignedLong(-11)
if k == ast.ASTKind.Call:
cl: ast.Call* = ast.Call*(val_node)
# 必须先把属性赋给显式类型为 list[...] | t.CPtr 的局部变量再调用 __len__(),
# 必须先把属性赋给显式类型为 list[...]* 的局部变量再调用 __len__(),
# 否则编译器无法识别属性返回的 list 类型,GEP base 会变成 i32 0 导致 llc 报错
cl_args_list: list[ast.AST*]* = cl.args
if cl_args_list is not None and len(cl_args_list) > 0:
@@ -216,7 +216,7 @@ novirtual class AssignGenMixin:
只看联合**首个**操作数(与 TPC 的"首个非 void 基类型胜出"同口径):
`T | t.CDefine`(define 常量与 TPC 展开产物)⇒ T;
`t.CDefine | T`(既有手写惯用法,如 CODE_SEG: t.CDefine | t.CUInt16T)⇒
`t.CDefine | T`(既有手写惯用法,如 CODE_SEG: t.CDefine | uint16)⇒
首个是 CDefine 标记 ⇒ 无显式类型 ⇒ **既有声明行为逐字不变**。
"""
if annot is None:
@@ -236,7 +236,7 @@ novirtual class AssignGenMixin:
名称解析与 TPC EnumMemberAnnotationIntWidth 同源:t 模块类型名走
TypeGenResolve.map_t_type(CLong/CSizeT 等平台相关宽度由它权威给出);
`int` / `bool` 两个"注解直通名"补在此表(TPC: int → t.CInt 32 位、
`int` / `bool` 两个"注解直通名"补在此表(TPC: int → int 32 位、
bool → 8 位,与 include/builtins 口径一致)。
"""
if annot is None:
@@ -473,8 +473,8 @@ novirtual class AssignGenMixin:
f"[TPV] define 常量数值不可存储: 常量 '{name}' 的初始值 {text} 超出 64 位"
f"(本语言最宽的整数类型为 64 位,按有符号/无符号两种解释的可存储范围为 "
f"-9223372036854775808..18446744073709551615,不存在更宽的整数类型 ⇒ 需要扩容)。"
f"禁止静默截断/降级,已终止编译。可用整数类型: t.CInt8T/t.CUInt8T、"
f"t.CInt16T/t.CUInt16T、t.CInt32T/t.CUInt32T、t.CInt64T/t.CUInt64T"
f"禁止静默截断/降级,已终止编译。可用整数类型: int8/uint8、"
f"int16/uint16、int32/uint32、int64/uint64"
f"(或 int8/uint8/…/uint64、char、sizet)。"
f"修法: 把值改到 64 位范围内,或为该数字引入更大的整数类型(扩容)。",
"TypeError")
@@ -502,7 +502,7 @@ novirtual class AssignGenMixin:
f"最小可容纳宽度 W_min: {wmin} 位;声明类型位宽 {bits} 位,"
f"该声明可存储范围: {lo}..{hi}。"
f"禁止静默截断/降级,已终止编译。"
f"修法: 把显式类型改为更宽的类型(如 t.CInt32T / t.CInt64T / uint64),"
f"修法: 把显式类型改为更宽的类型(如 int32 / int64 / uint64),"
f"或修正该字面量。",
"TypeError")
@@ -545,7 +545,7 @@ novirtual class AssignGenMixin:
f"需要至少 {wmin} 位(最小可容纳宽度 W_min),"
f"但使用处(变量声明注解)只提供 {bits} 位。"
f"禁止静默截断/降级,已终止编译。"
f"修法: 把变量声明注解加宽到至少 {wmin} 位(如 t.CInt{wmin}T / CUInt{wmin}T),"
f"修法: 把变量声明注解加宽到至少 {wmin} 位(如 int{wmin}T / CUInt{wmin}T),"
f"或改用更小的常量值。",
"TypeError")
@@ -600,8 +600,8 @@ novirtual class AssignGenMixin:
# 源文件重读恢复(最可靠: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:
rec_d: double = 0.0
if self._recover_cdefine_float(name, t.CPtr(&rec_d)) != 0:
use_val = rec_d
else:
# 源文件恢复失败:直接报错终止(fail-fast),避免注册被 pool 覆写的错误浮点值
@@ -627,14 +627,14 @@ novirtual class AssignGenMixin:
"""检查最近一次 _recover_cdefine_float 是否成功"""
return self.RecoverFound
def _recover_float_literal(self, name: str, out: t.CDouble | t.CPtr,
def _recover_float_literal(self, name: str, out: double*,
require_cdefine: int) -> int:
"""从当前模块源文件按变量名恢复浮点字面量,写入 out[0],成功返回 1
用输出参数传递 double,避免 TPV 跨模块 double 返回值传递 bug。
require_cdefine=1:只认带 t.CDefine 的行(CDefine 注册路径);
=0:模块级普通浮点全局也接受(handle_module_level_var 路径,
如 torch `LCG_M: t.CDouble = 2147483647.0`)。
如 torch `LCG_M: double = 2147483647.0`)。
"""
self.RecoverFound = 0
fp: str = self.Gen.TypeGenResolve.get_current_file()
@@ -767,7 +767,7 @@ novirtual class AssignGenMixin:
stdlib.free(buf)
return 0
def _recover_cdefine_float(self, name: str, out: t.CDouble | t.CPtr) -> int:
def _recover_cdefine_float(self, name: str, out: double*) -> int:
"""CDefine 浮点值恢复(只认带 t.CDefine 的行),见 _recover_float_literal"""
return self._recover_float_literal(name, out, 1)
@@ -800,19 +800,19 @@ novirtual class AssignGenMixin:
return 0
# ============================================================
# _is_ptr_element_annotation - 检查注解是否为 bytes|t.CPtr 或 str|t.CPtr
# _is_ptr_element_annotation - 检查注解是否为 bytes* 或 str*
#
# 返回 1=是(下标按 8 字节步长, i8** 语义), 0=否(下标按 1 字节步长, i8* 语义)
#
# 规则:
# bytes|t.CPtr / str|t.CPtr → i8**(8 字节步长)→ 返回 1
# char|t.CPtr / int8|t.CPtr → i8*(1 字节步长)→ 返回 0
# bytes* / str* → i8**(8 字节步长)→ 返回 1
# char* / int8* → i8*(1 字节步长)→ 返回 0
# 纯 bytes / str → i8*(1 字节步长)→ 返回 0
#
# 注: 注解中的 "|" 是"和"的意思(组合类型),非右值中的位或运算
# ============================================================
def _is_ptr_element_annotation(self, annot: ast.AST*) -> int:
"""检查注解是否为 bytes|t.CPtr 或 str|t.CPtr 形式"""
"""检查注解是否为 bytes* 或 str* 形式"""
if annot is None:
return 0
k: int = annot.kind()
@@ -825,7 +825,7 @@ novirtual class AssignGenMixin:
return 1
if self._annotation_contains_name(annot, "bytes") != 0:
return 1
# 泛型类型参数/嵌套联合 | t.CPtr(如 _list.vp 的 elem_ptr: T | t.CPtr):
# 泛型类型参数/嵌套联合 | t.CPtr(如 _list.vp 的 elem_ptr: T*):
# 先经泛型上下文解析 T 的具体类型——纯标量(int/float 等 sizeof≠8)时
# 元素按标量自身大小(list[int] elem_size=4 匹配 i32),不能按 8 字节
# 指针槽(否则 8 字节写 / 4 字节步长互相覆盖,pop 读到 0);
@@ -848,7 +848,7 @@ novirtual class AssignGenMixin:
if self._is_scalar_ty_name(gp_resolved) != 0:
return 0
return 1
# 64 位标量数值类型 | CPtr(如 CUInt64T | CPtr / CSizeT | CPtr):
# 64 位标量数值类型 | CPtr(如 CUInt64T* / CSizeT*):
# 联合解析后同样退化为指针表示,元素为 8 字节(i64 或指针)。
# 下标必须按 8 字节步长读写——否则 GEP 步长 1 + trunc i8 截断,
# 指针存进数组只剩低 1 字节(BuddyTest OOM/fill 的 ptrs 数组全错位:
@@ -889,9 +889,9 @@ novirtual class AssignGenMixin:
def _is_addrlike_call(self, node: ast.AST*) -> int:
"""检查 rhs 是否为 c.Addr/c.Deref 等显式指针操作调用。
此类调用返回指针(如 c.Addr(obj) 返回对象 storage 地址,类型 Ptr(Struct)),
此类调用返回指针(如 &obj 返回对象 storage 地址,类型 Ptr(Struct)),
但语义是"取地址/解引用",不是对象值引用/构造——storage 绑定分支不应捕获:
X = c.Addr(Y) 应直接 store &Y 到 @X(X 与 Y 指向同一对象),若误绑定则
X = &Y 应直接 store &Y 到 @X(X 与 Y 指向同一对象),若误绑定则
@X 自指 X.stg 并值复制 Y 的当前值(devfs DevFSObject 脱钩根因)。
"""
if node is None or node.kind() != ast.ASTKind.Call:
@@ -938,7 +938,7 @@ novirtual class AssignGenMixin:
def _is_scalar_ty_name(self, ty_name: str) -> int:
"""判断类型名是否为已知纯标量(整数/浮点/字符),白名单判定
泛型 T | t.CPtr(如 _list.vp 的 elem_ptr)经 Fix A(TypeGenMixin 联合
泛型 T*(如 _list.vp 的 elem_ptr)经 Fix A(TypeGenMixin 联合
解析保留泛型标量)后 alloca 变 Ptr(标量):T 为纯标量(int/float/double/
i64 等)时下标按标量自身大小步长,不能再按 8 字节指针槽——否则
Ptr(标量) alloca + IsPtrElement 路径(load 标量当指针)产生非法 IR。
@@ -1206,7 +1206,7 @@ novirtual class AssignGenMixin:
# 读对象首字的**唯一可用**写法是 `c.Deref((uint64*)(p))`(正常发射
# `bitcast p → i64*` + `load i64`:b5883dc9c114a604.ll:10611-10613);
# 写成 `rawptr(*(uint64*)(p))` 会被折成裸 0(同文件 :10382),不可用。
elem_vptr: uint64 = c.Deref((uint64*)(elem_node))
elem_vptr: uint64 = *((uint64*)(elem_node))
if elem_vptr == 0:
ctx_vt: str = ""
if owner_ctx is not None:
@@ -1930,7 +1930,7 @@ novirtual class AssignGenMixin:
annot: ast.AST* = aa.annotation
if annot is not None:
# 泛型特化补救(在解析之前无条件执行,_specialize_generic_class 幂等):
# 注解可能是 list[X](Subscript)或 list[X] | t.CPtr(含 CPtr 的 BinOp)。
# 注解可能是 list[X](Subscript)或 list[X]*(含 CPtr 的 BinOp)。
# 若泛型类尚未特化,resolve_annotation_type 会把 list[X] 退化为不透明
# 基类 list*(丢掉元素类型)——预建的 alloca 因此变成 list*,之后
# body_list.get(i) 会分派到默认 list[int] 特化(返回 i32)→ inttoptr
@@ -1965,7 +1965,7 @@ novirtual class AssignGenMixin:
cls_nm_ps: str = self.Gen.TypeGenResolve.extract_class_name_from_annotation(annot, trans._imported_modules, pool, trans._from_imports)
if cls_nm_ps is not None:
self.Gen.VarGen.set_var_annot_class_name(trans.SymTab, nm.id, cls_nm_ps)
# 检查是否为 bytes|t.CPtr 或 str|t.CPtr(i8** 语义,8 字节步长)
# 检查是否为 bytes* 或 str*(i8** 语义,8 字节步长)
if self._is_ptr_element_annotation(annot) != 0:
self.Gen.VarGen.set_var_ptr_element(trans.SymTab, nm.id)
# const 对象(注解含 t.CConst 且声明类型非指针):整个作用域内
@@ -2001,7 +2001,7 @@ novirtual class AssignGenMixin:
"""泛型注解预特化(见上方注释),返回 1=已尝试 / 0=不适用"""
if annot is None or trans is None:
return 0
# 取注解中的泛型 Subscript 一侧:Subscript 本身,或 A | t.CPtr 的 Subscript 分支
# 取注解中的泛型 Subscript 一侧:Subscript 本身,或 A* 的 Subscript 分支
spec_annot: ast.Subscript* = None
if annot.kind() == ast.ASTKind.Subscript:
spec_annot = ast.Subscript*(annot)
@@ -2042,7 +2042,7 @@ novirtual class AssignGenMixin:
var_ty: mlirlite.LLVMType*) -> int:
"""fail-fast:泛型注解解析成了「裸泛型基类指针」(丢失类型实参)
场景:注解是泛型下标 `list[X]` 或 `list[X] | t.CPtr`,但
场景:注解是泛型下标 `list[X]` 或 `list[X]*`,但
`resolve_annotation_type` 退化成裸基类 `list*`(没有 `[...]`)
⇒ 之后该变量的任何泛型方法调用(`.get()`/`.set()`/...)都会按**错误**
元素类型特化(实测 `list[int].get` 返回 i32)⇒ `inttoptr` 把 i32 当
@@ -2057,7 +2057,7 @@ novirtual class AssignGenMixin:
"""
if aa is None or annot is None or var_ty is None:
return 0
# 取注解里的泛型 Subscript 一侧:Subscript 本身,或 A | t.CPtr 的 Subscript 分支
# 取注解里的泛型 Subscript 一侧:Subscript 本身,或 A* 的 Subscript 分支
ann_sub: ast.Subscript* = None
if annot.kind() == ast.ASTKind.Subscript:
ann_sub = ast.Subscript*(annot)
@@ -2159,7 +2159,7 @@ novirtual class AssignGenMixin:
# - 独立局部:换一个不与全局重名的变量名
# 目的:不让错误延后到 RHS 的 coerce_to_type,暴露成与根因无关的
# 「指针隐式转整数」(如 PointerTest/App/main.vp:46 `_g_ptr: int = None`:
# 全局已是 t.CUInt32T | t.CPtr)。范围仅函数内——模块级自身的重复注解
# 全局已是 t.CUInt32T*)。范围仅函数内——模块级自身的重复注解
# 不归本检查(模块级由 handle_module_level_var 登记,本就不构成"遮蔽")。
if nm.id is not None and trans is not None \
and self.Gen.VarGen.is_module_scope(trans.SymTab) == 0 \
@@ -2457,7 +2457,7 @@ novirtual class AssignGenMixin:
"TypeError")
# FakeDuck: str 变量创建影子结构体 {var}__meta__(per-instance 字段存储)
# 仅裸 str 注解(Name("str"))且 _str 已注册时创建;bytes / char|t.CPtr 不创建。
# 仅裸 str 注解(Name("str"))且 _str 已注册时创建;bytes / char* 不创建。
# a 保持为 i8*(可 printf/len),a__meta__ 存 __data__/__mbuddy__ 等字段,
# 属性读写(fd3)与方法调用(fd5)均通过该影子解析。
fd_str_ty: mlirlite.LLVMType* = None
@@ -2487,7 +2487,7 @@ novirtual class AssignGenMixin:
cls_nm_hd: str = self.Gen.TypeGenResolve.extract_class_name_from_annotation(annot, trans._imported_modules, pool, trans._from_imports)
if cls_nm_hd is not None:
self.Gen.VarGen.set_var_annot_class_name(trans.SymTab, nm.id, cls_nm_hd)
# 检查是否为 bytes|t.CPtr 或 str|t.CPtr(i8** 语义,8 字节步长)
# 检查是否为 bytes* 或 str*(i8** 语义,8 字节步长)
if self._is_ptr_element_annotation(annot) != 0:
self.Gen.VarGen.set_var_ptr_element(trans.SymTab, nm.id)
@@ -2995,7 +2995,7 @@ novirtual class AssignGenMixin:
sub_pointee: mlirlite.LLVMType* = sub_alloca.Ty.Pointee
cls_nm_set: str = self.Gen.StructGen.get_class_name_by_type(pool, sub_pointee)
obj_val_set: mlirlite.Value* = mlirlite.build_load(builder, sub_pointee, sub_alloca)
# 指针类型变量 (X|t.CPtr): sub_pointee 是 Ptr(Struct),
# 指针类型变量 (X*): sub_pointee 是 Ptr(Struct),
# 需 load 获取 Ptr(Struct) 再检查 inner struct
if cls_nm_set is None and obj_val_set is not None \
and self.Gen.ExprGenBase.is_ptr_type(sub_pointee) != 0 \
@@ -3021,7 +3021,7 @@ novirtual class AssignGenMixin:
field_pointee_set: mlirlite.LLVMType* = field_ptr_set.Ty.Pointee
cls_nm_attr: str = self.Gen.StructGen.get_class_name_by_type(pool, field_pointee_set)
obj_val_attr: mlirlite.Value* = field_ptr_set
# field_ptr 是 Ptr(Ptr(Struct)) (X|t.CPtr 字段):
# field_ptr 是 Ptr(Ptr(Struct)) (X* 字段):
# load 解引用获取 Ptr(Struct)
if cls_nm_attr is None \
and self.Gen.ExprGenBase.is_ptr_type(field_pointee_set) != 0 \
@@ -3290,7 +3290,7 @@ novirtual class AssignGenMixin:
alloca: mlirlite.Value* = self.Gen.VarGen.get_or_create_sym(trans.SymTab, pool, builder, nm.id, rhs_val.Ty)
if alloca is not None:
# 无注解赋值:从 RHS 表达式推断类名设置变量注解
# (联合类型 X|t.CPtr 简化为 Ptr(i8),属性访问按需过滤需要
# (联合类型 X* 简化为 Ptr(i8),属性访问按需过滤需要
# AnnotClassName 才能定位结构体字段)
cls_inf: str = self._infer_rhs_annot(pool, mod, asgn.value, trans, rhs_val)
if cls_inf is not None:
@@ -3332,7 +3332,7 @@ novirtual class AssignGenMixin:
#
# 不拦(判据刻意收窄,避免误伤):
# · 元素是标量(rawptr[int] 等):元素类型不是 Struct,直接返回;
# · 元素本身是指针(rawptr[rawptr[T]]、rawptr[T]|t.CPtr、str|t.CPtr):
# · 元素本身是指针(rawptr[rawptr[T]]、rawptr[T]*、str*):
# elem_ptr.Ty.Pointee 是 Ptr,不是 Struct,直接返回;
# · 数组槽(t.CArray[T,N] / 内建 Array):subscript_base_store_kind==1,
# `v[i] = T(...)`(构造函数返回临时对象地址)是合法的整对象复制;
@@ -3360,7 +3360,7 @@ novirtual class AssignGenMixin:
if elem_ty is None:
return
# 元素必须是对象(结构体)。标量元素(rawptr[int])与指针元素
# (rawptr[rawptr[T]] / X|t.CPtr)在此返回。
# (rawptr[rawptr[T]] / X*)在此返回。
if elem_ty.kind() != mlirlite.LLVMType.Struct:
return
rhs_inner_wo: mlirlite.LLVMType* = None
@@ -3403,7 +3403,7 @@ novirtual class AssignGenMixin:
f"而不是按指针写 {ptr_sz_wo} 字节。若该地址实际按 8 字节槽存放指针"
f"(如 rawptr[T] 缓冲/空闲链表),每写一个元素就越界 {over_wo} 字节,"
f"直接写穿相邻块。修法:把指针槽的基座类型写成指针元素形态"
f"(`rawptr[T] | t.CPtr` 或 `rawptr[rawptr[T]]`)后再赋值;"
f"(`rawptr[T]*` 或 `rawptr[rawptr[T]]`)后再赋值;"
f"或把基座显式转为 t.CPtr(无类型指针)后按 8 字节指针语义写入。",
"TypeError", col_s_wo, col_e_wo)
@@ -3411,7 +3411,7 @@ novirtual class AssignGenMixin:
# _infer_rhs_annot - 从 RHS 表达式推断变量注解类名
#
# 无注解赋值(如 v = Vec2(...) / v3 = v1 + v2)时,变量 AnnotClassName
# 缺失会导致后续属性访问(.x)无法"按需过滤":联合类型 X|t.CPtr 在 LLVM
# 缺失会导致后续属性访问(.x)无法"按需过滤":联合类型 X* 在 LLVM
# 中简化为 Ptr(i8),不携带类名,无法定位结构体字段(字段未找到 → fast-fail)。
# 此函数按 RHS 结构推断类名:
# Call → 类实例化(func 为已注册结构体名才采用,避免普通函数误标);
@@ -3560,7 +3560,7 @@ novirtual class AssignGenMixin:
while s < e and (annot[s] == ' ' or annot[s] == '\'' or annot[s] == '"'):
s += 1
# 段尾另需剥 '*':实参归一后段文本是 `{sha}.AST*`(旧形态
# `{sha}.AST | t.CPtr` 按 '|' 分段能落到 `{sha}.AST` 命中),与
# `{sha}.AST*` 按 '|' 分段能落到 `{sha}.AST` 命中),与
# ExprGenName._list_elem_obj_ty_from_struct_name 的尾剔除同口径;
# 不剥则 find_struct 落空 → 返回 None → 链式 .get(0).kind() 分派退化。
while e > s and (annot[e - 1] == ' ' or annot[e - 1] == '\'' or annot[e - 1] == '"' or annot[e - 1] == '*'):
@@ -3579,7 +3579,7 @@ novirtual class AssignGenMixin:
while s < e and (annot[s] == ' ' or annot[s] == '\'' or annot[s] == '"'):
s += 1
# 段尾另需剥 '*':实参归一后段文本是 `{sha}.AST*`(旧形态
# `{sha}.AST | t.CPtr` 按 '|' 分段能落到 `{sha}.AST` 命中),与
# `{sha}.AST*` 按 '|' 分段能落到 `{sha}.AST` 命中),与
# ExprGenName._list_elem_obj_ty_from_struct_name 的尾剔除同口径;
# 不剥则 find_struct 落空 → 返回 None → 链式 .get(0).kind() 分派退化。
while e > s and (annot[e - 1] == ' ' or annot[e - 1] == '\'' or annot[e - 1] == '"' or annot[e - 1] == '*'):
+16 -16
View File
@@ -135,7 +135,7 @@ novirtual class AsyncGenMixin(CallGenBase.CallGenBase):
if cnt >= HT.MAX_CORO_VARS:
break
addr: uint64 = uint64(trans._coro_params) + cnt * 8
slot: str | t.CPtr = (str | t.CPtr)(addr)
slot: str* = (str*)(addr)
slot[0] = aname
cnt = cnt + 1
trans._coro_param_count = cnt
@@ -678,7 +678,7 @@ novirtual class AsyncGenMixin(CallGenBase.CallGenBase):
if cnt >= HT.MAX_CORO_VARS:
return
addr: uint64 = uint64(trans._coro_locals) + cnt * 8
slot: str | t.CPtr = (str | t.CPtr)(addr)
slot: str* = (str*)(addr)
slot[0] = name
trans._coro_local_count = cnt + 1
@@ -896,7 +896,7 @@ novirtual class AsyncGenMixin(CallGenBase.CallGenBase):
if cnt >= HT.MAX_CORO_FUNCS:
return
addr: uint64 = uint64(trans._coro_wake_names) + cnt * 8
slot: str | t.CPtr = (str | t.CPtr)(addr)
slot: str* = (str*)(addr)
slot[0] = name
trans._coro_wake_idxs[cnt] = wake_idx
trans._coro_wake_count = cnt + 1
@@ -909,7 +909,7 @@ novirtual class AsyncGenMixin(CallGenBase.CallGenBase):
i: int = 0
for i in range(trans._coro_wake_count):
addr: uint64 = uint64(trans._coro_wake_names) + i * 8
slot: str | t.CPtr = (str | t.CPtr)(addr)
slot: str* = (str*)(addr)
if slot[0] is not None and string.strcmp(slot[0], name) == 0:
return trans._coro_wake_idxs[i]
return -1
@@ -1624,7 +1624,7 @@ novirtual class AsyncGenMixin(CallGenBase.CallGenBase):
if trans is None or trans._coro_params is None:
return None
addr: uint64 = uint64(trans._coro_params) + idx * 8
slot: str | t.CPtr = (str | t.CPtr)(addr)
slot: str* = (str*)(addr)
return slot[0]
# ============================================================
@@ -1835,7 +1835,7 @@ novirtual class AsyncGenMixin(CallGenBase.CallGenBase):
check_bbs[hi + 1] = sizet(mlirlite.create_block(pool, func, chk_name))
handler_bbs[hi] = sizet(mlirlite.create_block(pool, func, exc_name))
unmatched_bb: rawptr[mlirlite.BasicBlock] = mlirlite.create_block(pool, func, "coro.try_reraise")
codes_buf: int | t.CPtr = pool.alloc(256)
codes_buf: int* = pool.alloc(256)
# 每个 handler:check 链
for hi in range(nhandlers):
h_node: ast.AST* = tr.handlers.get(hi)
@@ -2413,7 +2413,7 @@ novirtual class AsyncGenMixin(CallGenBase.CallGenBase):
i: int = 0
for i in range(cnt):
addr: uint64 = uint64(trans._async_funcs) + i * 8
slot: str | t.CPtr = (str | t.CPtr)(addr)
slot: str* = (str*)(addr)
if slot[0] is not None and string.strcmp(slot[0], name) == 0:
return 1
return 0
@@ -2430,13 +2430,13 @@ novirtual class AsyncGenMixin(CallGenBase.CallGenBase):
i: int = 0
for i in range(cnt):
addr: uint64 = uint64(trans._coro_var_async) + i * 16
pair: str | t.CPtr = (str | t.CPtr)(addr)
pair: str* = (str*)(addr)
if pair[0] is not None and string.strcmp(pair[0], var_name) == 0:
return 0
if cnt >= HT.MAX_CORO_VARS:
return 1
pair2_addr: uint64 = uint64(trans._coro_var_async) + cnt * 16
pair2: str | t.CPtr = (str | t.CPtr)(pair2_addr)
pair2: str* = (str*)(pair2_addr)
pair2[0] = var_name
pair2[1] = func_name
trans._coro_var_async_count = cnt + 1
@@ -2451,13 +2451,13 @@ novirtual class AsyncGenMixin(CallGenBase.CallGenBase):
i: int = 0
for i in range(cnt):
addr: uint64 = uint64(trans._async_funcs) + i * 8
slot: str | t.CPtr = (str | t.CPtr)(addr)
slot: str* = (str*)(addr)
if slot[0] is not None and string.strcmp(slot[0], name) == 0:
return 0
if cnt >= HT.MAX_CORO_FUNCS:
return 1
addr2: uint64 = uint64(trans._async_funcs) + cnt * 8
slot2: str | t.CPtr = (str | t.CPtr)(addr2)
slot2: str* = (str*)(addr2)
slot2[0] = name
trans._async_func_count = cnt + 1
return 0
@@ -2474,14 +2474,14 @@ novirtual class AsyncGenMixin(CallGenBase.CallGenBase):
i: int = 0
for i in range(cnt):
addr: uint64 = uint64(trans._coro_frames) + i * 16
pair: str | t.CPtr = (str | t.CPtr)(addr)
pair: str* = (str*)(addr)
if pair[0] is not None and string.strcmp(pair[0], name) == 0:
pair[1] = str(frame_ty)
return 0
if cnt >= HT.MAX_CORO_FUNCS:
return 1
pair2_addr: uint64 = uint64(trans._coro_frames) + cnt * 16
pair2: str | t.CPtr = (str | t.CPtr)(pair2_addr)
pair2: str* = (str*)(pair2_addr)
pair2[0] = name
pair2[1] = str(frame_ty)
trans._coro_frame_count = cnt + 1
@@ -2496,7 +2496,7 @@ novirtual class AsyncGenMixin(CallGenBase.CallGenBase):
i: int = 0
for i in range(cnt):
addr: uint64 = uint64(trans._coro_frames) + i * 16
pair: str | t.CPtr = (str | t.CPtr)(addr)
pair: str* = (str*)(addr)
if pair[0] is not None and string.strcmp(pair[0], name) == 0:
if pair[1] is not None:
ty_addr: sizet = sizet(pair[1])
@@ -2513,7 +2513,7 @@ novirtual class AsyncGenMixin(CallGenBase.CallGenBase):
i: int = 0
for i in range(cnt):
addr: uint64 = uint64(trans._coro_var_async) + i * 16
pair: str | t.CPtr = (str | t.CPtr)(addr)
pair: str* = (str*)(addr)
if pair[0] is not None and string.strcmp(pair[0], var_name) == 0:
return pair[1]
return None
@@ -2644,5 +2644,5 @@ novirtual class AsyncGenMixin(CallGenBase.CallGenBase):
if trans is None or trans._coro_locals is None:
return None
addr: uint64 = uint64(trans._coro_locals) + idx * 8
slot: str | t.CPtr = (str | t.CPtr)(addr)
slot: str* = (str*)(addr)
return slot[0]
+28 -28
View File
@@ -45,9 +45,9 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
mod: mlirlite.LLVMModule*,
cl: ast.Call*,
trans: HT.Translator* = None) -> mlirlite.Value*:
"""c.Deref(ptr) → load,宽度只由 ptr 的 pointee 类型决定
"""*ptr → load,宽度只由 ptr 的 pointee 类型决定
pointee 是 i8(t.CPtr / void* / str / bytes)恒读 1 字节;不再按赋值
目标注解(CurAssignAnnot)反推宽度——那会让同一处 c.Deref(i8*) 的读取
目标注解(CurAssignAnnot)反推宽度——那会让同一处 *(i8*) 的读取
宽度取决于它是否恰好出现在带注解赋值的 RHS 里。需要按更宽类型读时,
由调用点显式给出元素类型指针后再解引用(见下方读取分支注释)。
"""
@@ -63,7 +63,7 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
# 读取宽度只由指针类型决定:按 pointee 类型 load 一个元素。
# pointee 是 i8(t.CPtr / void* / str / bytes)即恒读 1 字节。
# 需要 4/8 字节等更宽读取时,必须在调用点把指针显式变成有元素类型的
# 指针再解引用(c.Deref((rawptr[T])(p)) / c.Deref((T | t.CPtr)(x))),
# 指针再解引用(c.Deref((rawptr[T])(p)) / c.Deref((T*)(x))),
# 不再由赋值目标注解反推——否则同一处 c.Deref(i8*) 的宽度会随上下文
# (是否带注解赋值的 RHS)而变。
if self.Gen.ExprGenBase.is_ptr_type(ptr_val.Ty) != 0:
@@ -81,7 +81,7 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
cl: ast.Call*,
trans: HT.Translator* = None) -> mlirlite.Value*:
"""c.DerefAs(ptr, val) → store val to ptr(bitcast 后 store)
单参形式 c.DerefAs(ptr) → 读取 ptr 指向的值(等价 c.Deref(ptr))。
单参形式 c.DerefAs(ptr) → 读取 ptr 指向的值(等价 *ptr)。
"""
if cl is None:
return None
@@ -250,7 +250,7 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
mod: mlirlite.LLVMModule*,
cl: ast.Call*,
trans: HT.Translator* = None) -> mlirlite.Value*:
"""c.Addr(var) → 返回变量的 alloca 指针(不 load)"""
"""&var → 返回变量的 alloca 指针(不 load)"""
if cl is None:
return None
cargs: list[ast.AST*]* = cl.args
@@ -462,7 +462,7 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
return mlirlite.build_gep_struct(builder, struct_ty, fe_addr.Ty, obj_ptr, fe_addr.Index)
# Subscript 形式: c.Addr(arr[i]) / c.Addr(a.b[i][j]) → 元素地址(GEP,不 load)
# 统一走 get_subscript_ptr(递归处理嵌套下标、数组/指针/str|t.CPtr 形态)。
# 统一走 get_subscript_ptr(递归处理嵌套下标、数组/指针/str* 形态)。
# 此前仅处理单层数组 GEP:嵌套下标(c.Addr(self.lines[line_idx][0]),
# vpui.vp L985)的 value 是内层 Subscript,translate_value 把内层加载成
# 数组值([80 x i8])→ 非 Ptr → return None → 跌落跨模块函数调用生成
@@ -671,7 +671,7 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
def _resolve_register(self, attr_name: str) -> str:
"""将 t.ASM_DESCR.XXX 的属性名映射到约束字符串值"""
"""将 ASM_DESCR.XXX 的属性名映射到约束字符串值"""
if attr_name is None:
return ""
@@ -836,7 +836,7 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
支持两种等价写法(裸名写法省去 c. 前缀),裸名统一返回规范名,
使调用点的 string.strcmp 判定无需分支:
- 内联汇编:c.AsmInp/c.AsmOut ↔ asminp/asmout("AsmInp"/"AsmOut")
- 内联汇编:asminp/asmout ↔ asminp/asmout("AsmInp"/"AsmOut")
- LLVM IR:c.LInp/c.LOut ↔ irinp/irout("LInp"/"LOut")
"""
if node is None or node.func is None:
@@ -894,7 +894,7 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
"""添加操作数到数组,返回新计数(失败返回原计数)
去重:f-string 模板内嵌的 AsmOut/AsmInp 与 out=/inp= 声明指向
同一变量时会重复收集(如 vrandom.vp 的 c.Asm(f"...{AsmOut(v)}",
同一变量时会重复收集(如 vrandom.vp 的 __asm__(f"...{AsmOut(v)}",
out=[AsmOut(v)])),同一 (Value, IsOutput) 只保留第一个,
避免约束数多于 asm 返回元素数(llc: output constraints mismatch)。
"""
@@ -905,7 +905,7 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
# 且裸机链接要求裸名 —— 必须将对应定义标记为 t.CExport。
if val is not None and val.Name is not None:
if self._asm_name_is_mangled(val.Name) != 0:
self.Gen.TypeGenErr.fatal_error(None, f"c.Asm 操作数(AsmInp/AsmOut)不允许带 SHA1 混淆头的符号 '{val.Name}',请将对应函数/全局定义标记为 t.CExport(裸名)", "TypeError")
self.Gen.TypeGenErr.fatal_error(None, f"__asm__ 操作数(AsmInp/AsmOut)不允许带 SHA1 混淆头的符号 '{val.Name}',请将对应函数/全局定义标记为 t.CExport(裸名)", "TypeError")
if val is not None:
for ei in range(count):
eop: rawptr[GenTypes.AsmOperand] = self._asm_get_operand(operands, ei)
@@ -933,7 +933,7 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
mod: mlirlite.LLVMModule*,
cl: ast.Call*,
trans: HT.Translator* = None) -> mlirlite.Value*:
"""翻译 c.Asm 内联汇编,返回结果 Value(无输出时返回 None)"""
"""翻译 __asm__ 内联汇编,返回结果 Value(无输出时返回 None)"""
if cl is None:
return None
@@ -954,9 +954,9 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
# 的寄存器 → 寄存器错乱/零页崩溃)
# 类型必须是**单级**裸缓冲(t.CPtr = i8*):pool.alloc 返回 t.CPtr、
# string.memset 首参也是 t.CPtr;每槽按 8 字节字符串指针写入由下方的
# `cl_ptr: str | t.CPtr = (str | t.CPtr)(cl_addr)` 显式 cast 完成
# (与 includes/_dict.vp 的一致模式:缓冲单级、槽视图 str | t.CPtr)。
# 此前声明成 str | t.CPtr(=i8**) 与 alloc/memset 层数不符,隐式指针转换
# `cl_ptr: str* = (str*)(cl_addr)` 显式 cast 完成
# (与 includes/_dict.vp 的一致模式:缓冲单级、槽视图 str*)。
# 此前声明成 str*(=i8**) 与 alloc/memset 层数不符,隐式指针转换
# 禁止"层数不同",首行即报错。
clobbers: t.CPtr = pool.alloc(8 * ASM_MAX_CLOBBERS)
if clobbers is None:
@@ -984,7 +984,7 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
string.memset(out_ptys, 0, 8 * ASM_MAX_OPERANDS)
# 分配 fv 索引数组(记录每个 FormattedValue 对应的操作数原始索引)
fv_orig_indices: int | t.CPtr = pool.alloc(4 * ASM_MAX_OPERANDS)
fv_orig_indices: int* = pool.alloc(4 * ASM_MAX_OPERANDS)
if fv_orig_indices is None:
return None
string.memset(fv_orig_indices, 0, 4 * ASM_MAX_OPERANDS)
@@ -1190,7 +1190,7 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
if cstr is None or cstr[0] == '\0': continue
if clobber_count < ASM_MAX_CLOBBERS:
cl_addr: uint64 = uint64(clobbers) + clobber_count * 8
cl_ptr: str | t.CPtr = (str | t.CPtr)(cl_addr)
cl_ptr: str* = (str*)(cl_addr)
cl_ptr[0] = cstr
clobber_count += 1
@@ -1211,7 +1211,7 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
if pstr is None or pstr[0] == '\0': continue
if clobber_count < ASM_MAX_CLOBBERS:
pcl_addr: uint64 = uint64(clobbers) + clobber_count * 8
pcl_ptr: str | t.CPtr = (str | t.CPtr)(pcl_addr)
pcl_ptr: str* = (str*)(pcl_addr)
pcl_ptr[0] = pstr
clobber_count += 1
@@ -1239,7 +1239,7 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
if output_count > 1:
# 多输出返回类型 {T1, T2, ...} 的字段链表是 ParamNode 链
# (new_param_node 返回 rawptr[ParamNode]、Struct 形参 rawptr[ParamNode]、
# ParamNode.Next: ParamNode|CPtr),原先误注解为 Function*(不相关类)
# ParamNode.Next: ParamNode*),原先误注解为 Function*(不相关类)
# → 1264/1268 两处会被判 struct↔struct 隐式转换禁止。
out_pn_head: mlirlite.ParamNode* = None
out_pn_last: mlirlite.ParamNode* = None
@@ -1269,7 +1269,7 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
if out_pn_head is not None and out_pn_n > 0:
ret_ty = mlirlite.Struct(pool, out_pn_head, out_pn_n, None)
else:
self.Gen.TypeGenErr.fatal_error(cl, "c.Asm 输出操作数类型缺失(变量 alloca 类型退化)", "TypeError")
self.Gen.TypeGenErr.fatal_error(cl, "__asm__ 输出操作数类型缺失(变量 alloca 类型退化)", "TypeError")
ret_ty = mlirlite.Int32(pool)
else:
out_op: rawptr[GenTypes.AsmOperand] = self._asm_get_operand(operands, first_output_idx)
@@ -1282,7 +1282,7 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
if out_pt is not None:
ret_ty = out_pt
else:
self.Gen.TypeGenErr.fatal_error(cl, "c.Asm 输出操作数类型缺失(变量 alloca 类型退化)", "TypeError")
self.Gen.TypeGenErr.fatal_error(cl, "__asm__ 输出操作数类型缺失(变量 alloca 类型退化)", "TypeError")
ret_ty = mlirlite.Int32(pool)
# 判断 void — 直接基于 output_count 判断,避免 match 类型匹配问题
@@ -1306,7 +1306,7 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
ret_re = re_op.Value.Ty.Pointee
break
if ret_re is None:
self.Gen.TypeGenErr.fatal_error(cl, "c.Asm 输出操作数类型缺失(变量 alloca 类型退化)", "TypeError")
self.Gen.TypeGenErr.fatal_error(cl, "__asm__ 输出操作数类型缺失(变量 alloca 类型退化)", "TypeError")
ret_ty = ret_re
case _:
pass
@@ -1317,8 +1317,8 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
# new_order[new_idx] = orig_idx — 新位置对应原索引
# orig_to_new[orig_idx] = new_idx — 原索引映射到新位置(用于占位符编号)
# ============================================================
new_order: int | t.CPtr = pool.alloc(4 * (operand_count + 1))
orig_to_new: int | t.CPtr = pool.alloc(4 * (operand_count + 1))
new_order: int* = pool.alloc(4 * (operand_count + 1))
orig_to_new: int* = pool.alloc(4 * (operand_count + 1))
if new_order is None or orig_to_new is None:
return None
@@ -1405,7 +1405,7 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
# 追加 clobber 约束 ~{name}
for cidx in range(clobber_count):
cl_addr2: uint64 = uint64(clobbers) + cidx * 8
cname: str = (str | t.CPtr)(cl_addr2)[0]
cname: str = (str*)(cl_addr2)[0]
if cname is None or cname[0] == '\0':
continue
if first_const == 0:
@@ -1418,10 +1418,10 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
# ============================================================
# 6. 构建参数列表文本(仅输入操作数)
# ============================================================
# 每个实参 = 类型文本(MLIR 内联具名结构体完整字段体,可达 512 字节)
# + 值名;固定 ASM_ARGS_BUF_SIZE(512) 只够一个短类型,须按操作数个数给足。
asm_arg_cap: sizet = sizet(operand_count + 1) * 544 + 64
args_buf: str = pool.alloc(asm_arg_cap)
# 每个实参 = 类型文本(MLIR 内联具名结构体完整字段体,可达 512 字节)
# + 值名;固定 ASM_ARGS_BUF_SIZE(512) 只够一个短类型,须按操作数个数给足。
asm_arg_cap: sizet = sizet(operand_count + 1) * 544 + 64
args_buf: str = pool.alloc(asm_arg_cap)
if args_buf is None:
return None
args_buf[0] = '\0'
+4 -4
View File
@@ -585,7 +585,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
# 修复: 构造器调用 __init__(ptr, base, 4096) 时 size 形参是 i64 (sizet),
# 但 4096 字面量按 i32 传递,未提升导致运行时 size 高 32 位垃圾,
# 破坏伙伴分配器的池大小元数据(如 total=2048)引发 calloc 失败/OOM。
# self 在运算符重载路径 2(lhs 为 X|t.CPtr 联合简化的 Vec3** 对象指针)时
# self 在运算符重载路径 2(lhs 为 X* 联合简化的 Vec3** 对象指针)时
# 与形参 Vec3* 不匹配,需 bitcast(coerce 指针→指针生成 bitcast),
# 否则 call 参数类型与声明不一致 llc 报错。
if found_func is not None and head is not None:
@@ -936,7 +936,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
mi_s0 += 1
# 泛型特化方法调用:特化函数可能尚未注册(如 ast.base 用
# list[AST|t.CPtr].get)。主动触发特化(幂等,MethodsEmitted 防重入),
# list[AST*].get)。主动触发特化(幂等,MethodsEmitted 防重入),
# 特化后重新查找即可命中,返回类型来自特化函数定义(天然精确)。
gen_done: int = 0
# text.ll 查找结果提升为函数级并显式初始化:gen_done==1 成功时
@@ -1242,7 +1242,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
self.Gen.TypeGenErr.fatal_error(cl, f"this-adjust 父类结构体未注册: 方法'{method_name}'定义类'{mc_anc}'的 struct 未找到", "InternalCompilerError")
# self 参数按声明首参类型 coerce:跨模块 declare self 是类指针
# (%"sha1.Class"*,见 VpiReader._inject_method_declare),而对象指针
# 可能是 i8*(X|t.CPtr 联合简化)或 this-adjust 后的祖先指针,需
# 可能是 i8*(X* 联合简化)或 this-adjust 后的祖先指针,需
# bitcast 匹配声明签名(对齐 _call_method_on_ptr 的 coerce 块),
# 否则 llc 报 call 参数类型与 declare 不一致。
if found_func is not None:
@@ -1696,7 +1696,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
self.Gen.TypeGenErr.fatal_error(cl, "list.append: 找不到 _list 模块 SHA1(依赖模块未编译)", "InternalCompilerError")
if ap_sha1 is not None:
# 特化类名提取:list.append 的符号名是
# {sha1}.list[AST|CPtr].append(带类型参数特化名),而非
# {sha1}.list[AST*].append(带类型参数特化名),而非
# {sha1}.list.append。lm_obj 类型即特化结构体 Ptr(list[...]),
# 从类型解析特化类名拼接调用名,否则 ld.lld undefined symbol
ap_spec_nm: str = None
+10 -10
View File
@@ -9,7 +9,7 @@ import stdlib
import viperlib
import lib.core.VLogger as VLogger
import lib.core.Gen.Translator as HT
import lib.core.Gen.GenTypes as GenTypes
import lib.core.Gen.GenTypes as GenTypes
import lib.core.Gen.Type.TypeSpec as TSpec
from . import CallGenBase
@@ -742,7 +742,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
list[int] -> ["int"]
dict[str, int] -> ["str", "int"]
list[AST | t.CPtr] -> ["f467978339422f32.AST|t.CPtr"]
list[AST*] -> ["f467978339422f32.AST*"]
from_imports 可用时,各类型实参经 TypeGenResolve._norm_type_arg_name
规范化为 "{定义模块SHA1}.{Class}"(ast.AST/AST → f467978339422f32.AST),
@@ -780,16 +780,16 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
# _ptr_layer_type_arg - 构造推断类型实参的指针层补足(与注解侧同票名)
#
# 口径来源(用户定,2026-09-30):指针类型实参**唯一规范形是 `T*`**
# (rawptr[T] ≡ t.CPtr[T] ≡ T | t.CPtr;见 TypeGenResolve._norm_type_arg_name)。
# (rawptr[T] ≡ t.CPtr[T] ≡ T*;见 TypeGenResolve._norm_type_arg_name)。
# 为什么必须补:_infer_generic_ctor_type_arg 的 Name/Attribute 分支把
# 「注解类名」(AnnotClassName)直接当泛型类型实参返回,而
# TypeGenResolve.extract_class_name_from_annotation 对 `rawptr[AST]` 只返回
# pointee "AST"、对 `AST | t.CPtr` 也只返回 "AST"(丢指针层)⇒ 构造侧推出
# `{sha}.AST`,注解侧(Box[rawptr[AST]] / Box[AST | t.CPtr])归一形却是
# pointee "AST"、对 `AST*` 也只返回 "AST"(丢指针层)⇒ 构造侧推出
# `{sha}.AST`,注解侧(Box[rawptr[AST]] / Box[AST*])归一形却是
# `{sha}.AST*`,同一 `Box(x)` 隐式特化会分裂成两个结构体(undefined symbol /
# 同布局两 struct)。
# 判据:变量/字段的**值类型**指针层级由 Spec.PtrLevel 承载(`x: AST` 为 0;
# `x: rawptr[AST]` / `x: AST | t.CPtr` 为 1),即"注解本身是指针形"。
# `x: rawptr[AST]` / `x: AST*` 为 1),即"注解本身是指针形"。
# 顺序:**先经 _norm_type_arg_name 归一再加 `*`** —— 裸名 "AST*" 不再是可查
# 类名,_norm 无法给它补 SHA1 前缀 ⇒ 会与 "{sha}.AST*" 分裂;故必须先归一成
# `{定义模块SHA1}.{类}` 再补层。仅当归一结果确为类名(带 SHA1 前缀)时补;
@@ -889,7 +889,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
if ve_i is not None:
# 注解类名经 _ptr_layer_type_arg:走 _norm_type_arg_name 归一后,
# 变量值类型为指针(Spec.PtrLevel>0,如 `x: rawptr[AST]` /
# `x: AST | t.CPtr`)时补足 `*`,与注解侧归一形 `{sha}.AST*` 同票名。
# `x: AST*`)时补足 `*`,与注解侧归一形 `{sha}.AST*` 同票名。
cn_nm_i: str = self.Gen.VarGen.var_annot_class_name(ve_i)
pl_nm_i: int = 0
if ve_i.Spec is not None:
@@ -900,7 +900,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
# 同样只查表)。取不到 ⇒ None ⇒ 调用方 fail-fast。
if k == ast.ASTKind.Attribute:
# 同上:字段值类型为指针时(FieldEntry.Spec.PtrLevel>0,如字段注解
# `AST | t.CPtr`)补足 `*`。_resolve_attr_field_entry 为只读非 fatal
# `AST*`)补足 `*`。_resolve_attr_field_entry 为只读非 fatal
# 解析,仅支持单层基座;更深的属性链取不到 PtrLevel 时保持原样(原行为)。
cn_at_i: str = self.Gen.ExprGenAttr._resolve_attr_field_class(pool, trans, arg_node)
pl_at_i: int = 0
@@ -1113,7 +1113,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
ctx_annot = trans.CurFuncRetAnnot
if ctx_annot is None: return None
# 取注解里的泛型 Subscript 一侧(与 _prespecialize_generic_annotation 同构:
# 支持 `X[T]` 与 `X[T] | t.CPtr` 两种形态)
# 支持 `X[T]` 与 `X[T]*` 两种形态)
spec_annot: ast.Subscript* = None
if ctx_annot.kind() == ast.ASTKind.Subscript:
spec_annot = ast.Subscript*(ctx_annot)
@@ -1177,7 +1177,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
string.memset(extra_args, 0, 8 * 32)
# 槽占用标志(0=空 1=已填),用于关键字定位后的连续性校验。
# 尺寸口径 = extra_args 同源:槽位数固定 32(下标 0..31,由下方
# `ai >= 32` / `slot_kw >= 32` 守卫界定),元素类型 = sizet|t.CPtr ⇒ 步长
# `ai >= 32` / `slot_kw >= 32` 守卫界定),元素类型 = sizet* ⇒ 步长
# 8 字节 ⇒ 必须 32 * 8 = 256 字节。原写 alloc(32) 是"按 1 字节/槽"的
# 第二份真相源,与 `arg_filled[i] = 1` 的 8 字节步长写自相矛盾:只要实参
# 数/关键字槽位 ≥ 4(下标 4 落在偏移 32)即越界写穿本块尾 canary 与右邻
+17 -17
View File
@@ -244,9 +244,9 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
if fp is not None:
fp = mlirlite.param_get_next(fp)
ai += 1
# build_call 的第二参是**被调符号名字符串**(callee: str),不是 Function*——
# 传 Function* 会被当成字符串读到结构体首字段(Next 指针),发射出
# `call i32 @(i32 7)`(空名字)这种非法 IR。这里用查找时同一符号名。
# build_call 的第二参是**被调符号名字符串**(callee: str),不是 Function*——
# 传 Function* 会被当成字符串读到结构体首字段(Next 指针),发射出
# `call i32 @(i32 7)`(空名字)这种非法 IR。这里用查找时同一符号名。
return mlirlite.build_call(builder, spec_name, head, int(can), ret_ty, 0)
def _tc_h1_super_ctraits(self, pool: memhub.MemBuddy*,
@@ -317,7 +317,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
"""c.Deref/Asm/LLVMIR 等特殊调用(未命中返回 None)
hit_box: 命中标记(t.CPtr,[0]=1 表示已识别为 c.* 特殊调用)。
仅对 c.Asm/c.LLVMIR 等返回 None(void,无返回值)的调用置位——
仅对 __asm__/c.LLVMIR 等返回 None(void,无返回值)的调用置位——
translate_c_asm/translate_c_llvmir 成功处理 void 时返回 None,
若不加 hit_box 会被 translate_call 误判为"未命中"继续走外部函数路径。
"""
@@ -532,7 +532,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
tc_mod_nm: ast.Name* = ast.Name*(tc_at.value)
if tc_mod_nm.id is not None and string.strcmp(tc_mod_nm.id, "t") == 0:
# t.CType 特殊形式:t.CType(value, TypeName, t.CPtr) →
# 把 value 转为 TypeName|t.CPtr(TypeName* 指针)。TypeName
# 把 value 转为 TypeName*(TypeName* 指针)。TypeName
# 是类型名(Name/Attribute),不是值表达式——此前被当普通
# 参数翻译 → NameError: 未定义名称 'memory_block'
# (VKernel mm.vp merge_blocks 根因)。CType 不是 map_t_type
@@ -581,7 +581,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
# t.CType 语法已确认:即使类型解析失败也不跌落到跨模块 FATAL
return None
# CConst const 标记:CConst(val, t.CPtr) → Ptr(i8)(const void*)。
# CConst 不是 map_t_type 具名类型——t.CConst|char|t.CPtr 注解 =
# CConst 不是 map_t_type 具名类型——t.CConst|char* 注解 =
# const char*(i8*),显式调用 t.CConst(addr, t.CPtr) 把整数地址转
# const 指针。此前 map_t_type 失败 → 跌落跨模块函数调用 → 生成
# call @CConst(裸名,无 obj 定义)→ ld.lld undefined symbol:
@@ -825,17 +825,17 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
break
sz_resolved_name = sz_cls_name
# 指针包装类型检查必须在 dot-strip 之前:类型实参可能带 sha1
# 前缀内嵌点号(rawptr[7565e081d88517ac.AST]、f4679...AST|t.CPtr),
# 前缀内嵌点号(rawptr[7565e081d88517ac.AST]、f4679...AST*),
# strrchr('.') 会把括号内 ".AST"/".CPtr" 剥掉 → "AST]"/"CPtr",
# 前缀/联合判断永远失配 → 落回把接收者 Name(T) 当实例翻译 →
# NameError: 未定义名称 'T'(SlotsBugTest rawptr[list[rawptr[AST]]] 根因)。
# 联合类型(X | t.CPtr)与新一代指针包装 rawptr[X] 均按指针大小 8。
# 联合类型(X*)与新一代指针包装 rawptr[X] 均按指针大小 8。
if string.strstr(sz_cls_name, "|") is not None:
return mlirlite.const_int64(pool, 8)
if string.strncmp(sz_cls_name, "rawptr[", 7) == 0:
return mlirlite.const_int64(pool, 8)
# 归一后的指针唯一规范形 `T*`(TypeGenResolve._norm_type_arg_name
# 的指针书写归一:rawptr[T] ≡ t.CPtr[T] ≡ T|t.CPtr ≡ T*)
# 的指针书写归一:rawptr[T] ≡ t.CPtr[T] ≡ T* ≡ T*)
# ⇒ **尾随** '*' 一律按指针大小 8(多级 `**` 同为 8)。
# 判据必须是"尾随",不能用 strrchr:接收者是
# `list[{sha}.AST*]`(元素为指针的容器)时串内也含 '*',
@@ -843,7 +843,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
# 缺本判据时 `T.__sizeof__()` 的实参串 `{sha}.AST*` 既不命中
# '|' 也不命中 'rawptr[',落回把接收者 Name(T) 当实例翻译 →
# NameError: 未定义名称 'T'(现场 Test/AstTest/App/main.vp:21
# 特化 list[ast.AST|t.CPtr] → includes/_list.vp:36)。
# 特化 list[ast.AST*] → includes/_list.vp:36)。
_sz_len_s: sizet = string.strlen(sz_cls_name)
while _sz_len_s > 0 and sz_cls_name[_sz_len_s - 1] == ' ':
_sz_len_s -= 1
@@ -1708,13 +1708,13 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
expr_obj: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, expr_method_at.value, funcs_ptr, func_count, trans)
if expr_obj is not None and expr_obj.Ty is not None:
expr_cls_nm: str = None
# 递归解 Ptr:识别 X|t.CPtr 联合简化的 Ptr(Ptr(Struct))
# 递归解 Ptr:识别 X* 联合简化的 Ptr(Ptr(Struct))
# (如 (a*2.0 - b) 中 __mul__ 返回 Vec3**),否则方法
# 调用被当裸函数 @dot 解析 → 链接 undefined symbol
expr_struct_ty: mlirlite.LLVMType* = self.Gen.StructGen.get_struct_type_from_value(expr_obj)
if expr_struct_ty is not None:
expr_cls_nm = self.Gen.StructGen.get_class_name_by_type(pool, expr_struct_ty)
# 回退:LLVM 类型为 Ptr(i8)(方法返回 X|t.CPtr 无类型信息)时,
# 回退:LLVM 类型为 Ptr(i8)(方法返回 X* 无类型信息)时,
# 从接收者表达式结构推断类名(链式调用 c2.scale(2.0).move(...)
# 的 scale 返回 Ptr(i8),经 infer_expr_class → vpi 返回注解)
# 跨 Mixin 不能 self 调用 ExprGenMixin 方法,经全局单例
@@ -1979,9 +1979,9 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
self.Gen.TypeGenErr.fatal_error(cl, "list.append: 找不到 _list 模块 SHA1(依赖模块未编译)", "InternalCompilerError")
if ap_sha1 is not None:
# 特化类名提取:list.append 的符号名是
# {sha1}.list[AST|CPtr].append(带类型参数特化名),
# {sha1}.list[AST*].append(带类型参数特化名),
# 而非 {sha1}.list.append。lm_obj 类型即特化结构体
# Ptr(list[AST|CPtr]),从类型解析特化类名拼接调用名,
# Ptr(list[AST*]),从类型解析特化类名拼接调用名,
# 否则 ld.lld undefined symbol(定义端是特化名)。
ap_spec_nm: str = None
ap_struct_ty: mlirlite.LLVMType* = self.Gen.StructGen.get_struct_type_from_value(lm_obj)
@@ -1990,9 +1990,9 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
if ap_spec_nm is None:
ap_spec_nm = "list"
# 触发泛型特化翻译(幂等,MethodsEmitted 防重入):
# list[AST|CPtr].append 的 define 方法体在特化类翻译时
# list[AST*].append 的 define 方法体在特化类翻译时
# 生成。仅构造调用名不触发特化会导致定义缺失
# (ld.lld undefined symbol: list[AST|CPtr].append)。
# (ld.lld undefined symbol: list[AST*].append)。
if trans is not None and ap_spec_nm is not None:
lbkt_ap: str = string.strchr(ap_spec_nm, '[')
if lbkt_ap is not None:
@@ -2028,7 +2028,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
# 调用名 "{sha1}.{spec}.append":
# sha1(16) + '.'(1) + spec + '.append'(7) + NUL(1) = spec + 25。
# 此前 +8 少 1 字节,snprintf 截断末尾 'd' →
# undefined symbol: ...list[AST|CPtr].appen(缺 d)。
# undefined symbol: ...list[AST*].appen(缺 d)。
ap_mlen: sizet = string.strlen(ap_sha1) + string.strlen(ap_spec_nm) + 26
ap_mangled: str = pool.alloc(ap_mlen)
if ap_mangled is not None:
+3 -3
View File
@@ -277,7 +277,7 @@ novirtual class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
if obj_val is None or obj_val.Ty is None:
# obj 类型推断失败:fail-fast,绝不返回 True 掩盖
self.Gen.TypeGenErr.fatal_error(cls_node, "isinstance() 参数类型推断失败", "TypeError")
# 对象指针规整:二级指针(变量 alloca / 联合 Class|t.CPtr)先 load
# 对象指针规整:二级指针(变量 alloca / 联合 Class*)先 load
obj_ptr: mlirlite.Value* = obj_val
match obj_val.Ty:
case mlirlite.LLVMType.Ptr(inner_ty):
@@ -1336,8 +1336,8 @@ novirtual class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
return 0
# 提取常量快照到 stdlib
if default_count > 0:
kinds: int | t.CPtr = CompilerFactory.factory.PermPool.alloc(default_count * 4)
ints: int64 | t.CPtr = CompilerFactory.factory.PermPool.alloc(default_count * 8)
kinds: int* = CompilerFactory.factory.PermPool.alloc(default_count * 4)
ints: int64* = CompilerFactory.factory.PermPool.alloc(default_count * 8)
strs: sizet* = CompilerFactory.factory.PermPool.alloc(default_count * 8)
if kinds is not None and ints is not None and strs is not None:
string.memset(kinds, 0, default_count * 4)
+2 -2
View File
@@ -268,7 +268,7 @@ novirtual class CallGenLib(CallGenBase.CallGenBase):
# 转换校验,于是"把结构体/类/数组/函数指针传给 str 形参"会被静默放行
# ⇒ 后续把该指针当 C 字符串用时生成非法 IR(现场:把 Function* 传给
# `callee: str`,发射出 `call i32 @(i32 7)` 空符号名,直到 llc 才炸)。
# 判据:定义侧形参注解**恰为**裸 str/bytes(组合段如 `str|t.CPtr` 不
# 判据:定义侧形参注解**恰为**裸 str/bytes(组合段如 `str*` 不
# 等值、不受影响),且实参是指向聚合类型的指针。判据与报错统一委托
# ExprGenBase._str_rejects_ptr_kind / fail_if_str_annot_agg_ptr(单一
# 真源,字符数组 [N x i8] 衰减与其在同模块路径同口径豁免)。
@@ -444,7 +444,7 @@ novirtual class CallGenLib(CallGenBase.CallGenBase):
# Config 模块函数(跨模块调用时 stub 未注入,返回 i8* 被 inttoptr i32 截断导致路径损坏)
if string.strcmp(func_name, "get_includes_binary_dir") == 0:
return mlirlite.Ptr(pool, mlirlite.Int8(pool))
# HandlesType 模块函数(返回 ast.AST|t.CPtr 联合类型,跨模块推断为 i32 导致指针截断)
# HandlesType 模块函数(返回 ast.AST* 联合类型,跨模块推断为 i32 导致指针截断)
if string.strcmp(bare_name, "_parse_type_string") == 0:
return mlirlite.Ptr(pool, mlirlite.Int8(pool))
+3 -3
View File
@@ -196,7 +196,7 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
self.Gen.TypeGenErr.fatal_error(gen_nm_node, gt_err)
self.Gen.TypeGenErr.fatal_error(gen_nm_node, "泛型类模板未找到")
if func_name is None:
# 检查是否是 (A | t.CPtr)(value) 形式的类型转换
# 检查是否是 (A*)(value) 形式的类型转换
# BinOp 节点作为 Call func: 联合类型注解用作类型转换
if cl.func is not None and cl.func.kind() == ast.ASTKind.BinOp and trans is not None:
binop_ty: mlirlite.LLVMType* = self.Gen.TypeGenResolve.resolve_annotation_type(pool, cl.func, trans._imported_modules, trans._from_imports, trans, 0)
@@ -385,7 +385,7 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
return self.Gen.CallGenCtor._translate_struct_ctor(pool, builder, mod, struct_ty, func_name, cargs, sizet(0), trans, cl.IsVolatile)
# @t.NoVTable 类(无方法、类语义/指针对象):无参构造也应分配内存
# 返回指针。否则按值结构体返回 ConstZero(struct_ty),LHS 联合注解
# (如 Plain|CPtr)存 0 指针 → p.v 解引用 NULL 段错误
# (如 Plain*)存 0 指针 → p.v 解引用 NULL 段错误
# (TpvIsinstanceTest Plain 场景崩溃根因)。
ctor_is_novt: int = 0
if gen_ctor_entry is not None:
@@ -1019,7 +1019,7 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
# Ptr(i8)(TypeGenResolve.vp:2525-2531),与 t.CPtr 的
# Spec 完全同型 ⇒ 类型层无区分度,标记只能由注解名承载。
# 原 strstr 子串匹配会误命中含 "CPtr" 的类名(如 CPtrHolder)。
# 已知局限(与改造前一致,非回归):`Foo | t.CPtr` 的
# 已知局限(与改造前一致,非回归):`Foo*` 的
# SourceName 只留 "Foo"(取非 CPtr 侧类名)⇒ 此处判为非标记。
if TSpec.SpecTypeNameBaseIs(fp_annot, "CPtr") != 0:
is_cptr_annot_fp = 1
+4 -4
View File
@@ -156,8 +156,8 @@ novirtual class CallGenProp(CallGenBase.CallGenBase):
if annot_val is not None:
# [D32] 取「模块限定名」末段时只按**括号外**的 '.' 切分。
# 此前用 string.strrchr 在整个串上找最后一个 '.':泛型特化名
# "list[e94ef9e139461915.AST|t.CPtr]" 的 '.' 落在 '[' 内 ⇒
# 返回 "AST|t.CPtr]" 这种垃圾短名 ⇒ 后续按它查表必落空,
# "list[e94ef9e139461915.AST*]" 的 '.' 落在 '[' 内 ⇒
# 返回 "AST*]" 这种垃圾短名 ⇒ 后续按它查表必落空,
# 进而可能被兜底成任意特化(.get() 误分派)。
n_av: sizet = string.strlen(annot_val)
last_dot_av: sizet = n_av
@@ -345,7 +345,7 @@ novirtual class CallGenProp(CallGenBase.CallGenBase):
# list[T] 是内置泛型容器(_list.vp),其方法(append/get/set/pop/clear/
# __iter__/__len__/__getitem__/__setitem__)由 translate_call 的 list
# 内置分支内联 GEP 处理,不注册为方法函数。若 obj.method() 检测把
# list 特化 struct(如 list[AST | CPtr])误当普通结构体走
# list 特化 struct(如 list[AST*])误当普通结构体走
# _translate_method_call,会查不到 append 返回类型 → fail-fast
# (NewAstTest body.append 根因)。此判断用于跳过 method_call 路径。
#
@@ -357,7 +357,7 @@ novirtual class CallGenProp(CallGenBase.CallGenBase):
method_name: str) -> int:
"""判断 (class_name, method_name) 是否是 list 泛型内置方法"""
if class_name is None or method_name is None: return 0
# 类名必须以 "list" 开头(list / list[AST | CPtr] 特化名)
# 类名必须以 "list" 开头(list / list[AST*] 特化名)
if string.strncmp(class_name, "list", 4) != 0: return 0
# 方法名必须是 list 内置方法集合
if string.strcmp(method_name, "append") == 0: return 1
+1 -1
View File
@@ -53,7 +53,7 @@ novirtual class CallGenVa(CallGenBase.CallGenBase):
支持的类型表达式:
int / int32 → i32
int64 → i64
t.CDouble → double
double → double
t.CPtr / str → i8*
str / bytes → i8*
无类型参数时默认 i32(vsnprintf 中 va_arg(ap) 常用于读取 i32)
+1 -1
View File
@@ -162,7 +162,7 @@ novirtual class CallGenVt(CallGenBase.CallGenBase):
else:
obj_ptr_v = self.Gen.ExprGen.translate_value(builder, pool, mod, at.value, None, 0, trans)
if obj_ptr_v is None or obj_ptr_v.Ty is None: return 0
# X|t.CPtr 变量(Ptr(Ptr))load 解引用取对象指针
# X* 变量(Ptr(Ptr))load 解引用取对象指针
match obj_ptr_v.Ty:
case mlirlite.LLVMType.Ptr(inner_v):
match inner_v:
+18 -18
View File
@@ -81,7 +81,7 @@ novirtual class ClassGenBase:
# --- 类编译期元数据表(__provides__/__requires__/__require_must__) ---
# perm_pool 分配(跨 mark/reset 存活):每槽 kind(4B) + cls(64B) + field(64B)
# FakeDuck:_str.__requires__=['__mbuddy__'] 等(FakeDuck 移植点 1)
ClassMetaKinds: int | t.CPtr
ClassMetaKinds: int*
ClassMetaClss: bytes
ClassMetaFields: bytes
ClassMetaCount: int
@@ -131,18 +131,18 @@ novirtual class ClassGenBase:
# 可能失效(VectorGenericTest 特化 Vector[int].__init__ 的 T.__sizeof__()
# NameError 根因方向);注册时展平深拷贝到 stdlib,特化时从本表恢复。
# 每槽指向一个空格分隔、NUL 结尾的 stdlib 缓冲区(如 "T" 或 "T K")。
GenericClassTpParams: sizet*
# --- 泛型函数模板表(与上面 GenericClass* 同构:键 "{sha1}.{fname}" 定位
# 模板节点/来源 SHA1/来源文件/类型参数名)。
# 必须与其它字段一起声明在类顶——方法中间的字段注解可能被编译器当作
# 局部声明处理,破坏 Mixin 布局/this_adjust 对齐(见 _exception_codes_tmp_count)。
# 之前只写了 __before_init__ 里的赋值而漏了这里,导致 ClassGenGeneric
# 上的读取触发 fast-fail:属性 'GenericFuncKeys' 在类中找不到。 ---
GenericFuncKeys: list[str]*
GenericFuncNodes: list[ast.FunctionDef*]*
GenericFuncSha1s: list[str]*
GenericFuncFiles: list[str]*
GenericClassTpParams: sizet*
# --- 泛型函数模板表(与上面 GenericClass* 同构:键 "{sha1}.{fname}" 定位
# 模板节点/来源 SHA1/来源文件/类型参数名)。
# 必须与其它字段一起声明在类顶——方法中间的字段注解可能被编译器当作
# 局部声明处理,破坏 Mixin 布局/this_adjust 对齐(见 _exception_codes_tmp_count)。
# 之前只写了 __before_init__ 里的赋值而漏了这里,导致 ClassGenGeneric
# 上的读取触发 fast-fail:属性 'GenericFuncKeys' 在类中找不到。 ---
GenericFuncKeys: list[str]*
GenericFuncNodes: list[ast.FunctionDef*]*
GenericFuncSha1s: list[str]*
GenericFuncFiles: list[str]*
GenericFuncTpParams: sizet*
# --- vtable 方法收集表(原 _g_vt_full_names/_g_vt_method_names/
@@ -695,7 +695,7 @@ novirtual class ClassGenBase:
if string.strcmp(self.ExceptionNames + i * EXCEPTION_NAME_LEN, name) == 0:
return 1
return 0
def collect_descendant_codes(self, name: str, out_codes: int | t.CPtr,
def collect_descendant_codes(self, name: str, out_codes: int*,
max_codes: int) -> int:
"""把 name 及其所有子孙异常类的编码收集到 out_codes,返回数量
(对齐 TPC HandlesTry.py _get_all_match_codes/_collect_descendant_codes:
@@ -705,7 +705,7 @@ novirtual class ClassGenBase:
self._exception_codes_tmp_count = 0
self._collect_desc_codes_rec(name, out_codes, max_codes, 0)
return self._exception_codes_tmp_count
def _collect_desc_codes_rec(self, name: str, out_codes: int | t.CPtr,
def _collect_desc_codes_rec(self, name: str, out_codes: int*,
max_codes: int, depth: int) -> None:
"""递归收集 name 编码 + 全部子孙编码(BFS 语义对齐 TPC)"""
if depth > 32:
@@ -828,7 +828,7 @@ novirtual class ClassGenBase:
i: int
for i in range(self.MethodMetaCount):
if string.strcmp(self.MethodMetaKeys + i * META_KEY_LEN, key_buf) == 0:
flags_ptr: t.CPtr = (int | t.CPtr)(uint64(self.MethodMetaFlags) + i * 4)
flags_ptr: t.CPtr = (int*)(uint64(self.MethodMetaFlags) + i * 4)
# 按位或合并:同一属性名先 @property(getter=4) 再 @x.setter(8)/
# @x.deleter(16) 会多次注册(如 Config.value / Counter.value)。
# 若整值替换,后注册的位会覆盖 GETTER 位 → _try_property_getter_attr
@@ -841,7 +841,7 @@ novirtual class ClassGenBase:
# 槽位定长 META_KEY_LEN=128 字节,key 超长时 strncpy 钳制防越界写相邻槽
string.strncpy(self.MethodMetaKeys + self.MethodMetaCount * META_KEY_LEN,
key_buf, META_KEY_LEN - 1)
flags_ptr2: t.CPtr = (int | t.CPtr)(uint64(self.MethodMetaFlags) + self.MethodMetaCount * 4)
flags_ptr2: t.CPtr = (int*)(uint64(self.MethodMetaFlags) + self.MethodMetaCount * 4)
flags_ptr2[0] = meta
self.MethodMetaCount += 1
stdlib.free(key_buf)
@@ -861,7 +861,7 @@ novirtual class ClassGenBase:
i: int
for i in range(self.MethodMetaCount):
if string.strcmp(self.MethodMetaKeys + i * META_KEY_LEN, key_buf) == 0:
flags_ptr: t.CPtr = (int | t.CPtr)(uint64(self.MethodMetaFlags) + i * 4)
flags_ptr: t.CPtr = (int*)(uint64(self.MethodMetaFlags) + i * 4)
found = flags_ptr[0]
break
stdlib.free(key_buf)
+2 -2
View File
@@ -392,7 +392,7 @@ novirtual class ClassGenDef(ClassGenBase.ClassGenBase):
# Phase A-pre(declare_only=1):依赖的类可能尚未注册,延迟到下一遍
# Phase B(declare_only=0):真正的类型解析错误,fast-fail 终止该类翻译
# 不再用 i32 回退(会导致结构体布局错误 + GEP 索引错乱)
# 例外:泛型 Subscript(如 list[AST|t.CPtr])未特化时回退为 Ptr(i8),
# 例外:泛型 Subscript(如 list[AST*])未特化时回退为 Ptr(i8),
# 因为泛型特化可能延迟到构造调用时。AnnotClassName 会携带 mangled name
# 供 translate_attribute 做后续 bitcast。
is_generic_sub: int = 0
@@ -441,7 +441,7 @@ novirtual class ClassGenDef(ClassGenBase.ClassGenBase):
else:
field_defaults_buf[field_count] = 0
# 提取原始类型注解的类名(联合类型简化为 Ptr(i8) 时回退查找结构体)
# BUG 1 方案3:传 pool 使泛型 Subscript 返回 mangled name(如 "list[ast.AST|t.CPtr]")
# BUG 1 方案3:传 pool 使泛型 Subscript 返回 mangled name(如 "list[ast.AST*]")
if aa.annotation is not None:
annot_cn: str = self.Gen.TypeGenResolve.extract_class_name_from_annotation(aa.annotation, trans._imported_modules, pool, trans._from_imports)
if annot_cn is not None:
+5 -5
View File
@@ -186,7 +186,7 @@ novirtual class ClassGenEnum(ClassGenBase.ClassGenBase):
def _enum_member_annotation_is_ptr(self, ann_node: ast.AST*) -> int:
"""枚举成员注解(**含联合类型逐边**)是否含指针类型,1=是 / 0=否
联合形态必须逐边检查:`t.CInt | t.CPtr` 在 _resolve_enum_member_type 的
联合形态必须逐边检查:`int*` 在 _resolve_enum_member_type 的
BinOp 分支会"优先返回具体整数类型"(源码 L94-105)——只看解析结果会把
含指针的联合静默当整数,故在解析前按注解树拦。
"""
@@ -335,7 +335,7 @@ novirtual class ClassGenEnum(ClassGenBase.ClassGenBase):
# 临时数组存储成员信息
member_names_buf: sizet* = pool.alloc(8 * ENUM_MEMBER_MAX_LOCAL)
member_types_buf: sizet* = pool.alloc(8 * ENUM_MEMBER_MAX_LOCAL)
member_values_buf: int64 | t.CPtr = pool.alloc(8 * ENUM_MEMBER_MAX_LOCAL)
member_values_buf: int64* = pool.alloc(8 * ENUM_MEMBER_MAX_LOCAL)
if member_names_buf is None or member_types_buf is None or member_values_buf is None:
return 0
string.memset(member_names_buf, 0, 8 * ENUM_MEMBER_MAX_LOCAL)
@@ -365,7 +365,7 @@ novirtual class ClassGenEnum(ClassGenBase.ClassGenBase):
# [枚举规格 fail-fast] 成员不允许指针类型:t.CPtr / CNeedPtr /
# CAutoPtr / rawptr[...] / str / bytes,以及**联合类型里夹带指针**
# 的形态(t.CInt | t.CPtr)。必须先于类型解析——联合分支会优先返回
# 的形态(t.CInt*)。必须先于类型解析——联合分支会优先返回
# 具体整数类型、rawptr[...] 又是 Subscript(非 Name/Attribute/BinOp)
# 会在解析里报笼统的"注解解析失败",两者都盖不住"指针成员"这个真因。
if self._enum_member_annotation_is_ptr(aa.annotation) == 1:
@@ -884,7 +884,7 @@ novirtual class ClassGenEnum(ClassGenBase.ClassGenBase):
# 直接注册变体字段名别名(避免 CSizeT→str 转换问题)
# 同时解析成员实际类型(对齐 TPC class_members,供 match
# 绑定 bitcast 槽位地址用)。自引用注解(如
# LLVMType|t.CPtr 引用自身类)此时解析失败返回 None →
# LLVMType* 引用自身类)此时解析失败返回 None →
# 不存类型,绑定回退槽位类型。variant_cd.name 在 1a reset
# 后悬空,注册内部会 strcpy 到 perm_pool。
if vnm is not None and vnm.id is not None:
@@ -1352,7 +1352,7 @@ novirtual class ClassGenEnum(ClassGenBase.ClassGenBase):
"""注册 REnum 变体字段名别名到全局表
field_ty: 变体成员的实际 LLVM 类型(可选;自引用类型如
LLVMType|t.CPtr 在注册期解析失败时为 None,match 绑定回退槽位类型)。
LLVMType* 在注册期解析失败时为 None,match 绑定回退槽位类型)。
variant_name: 所属变体名(可选;match 绑定按 (class, 变体, 位置) 定位成员)
"""
if pool is None or class_name is None or field_name is None:
+32 -32
View File
@@ -442,10 +442,10 @@ novirtual class ClassGenGeneric(ClassGenBase.ClassGenBase):
位宽 无符号 有符号 / 默认
i1 bool (bool 唯一)
i8 t.CUInt8T char
i16 t.CUInt16T t.CInt16T(无裸名别名)
i32 t.CUInt32T int
i64 t.CUInt64T t.CInt64T(无裸名别名)
i8 uint8 char
i16 uint16 int16(无裸名别名)
i32 uint32 int
i64 uint64 int64(无裸名别名)
f16 t.CFloat16T (浮点无符号性)
f32 float
f64 double
@@ -489,19 +489,19 @@ novirtual class ClassGenGeneric(ClassGenBase.ClassGenBase):
if string.strcmp(buf, "i1") == 0: return "bool"
if string.strcmp(buf, "i8") == 0:
# 无符号 i8(CUInt8T/CUnsignedChar)走裸名 char 会静默变号
if sign == TSpec.TS_SIGN_UNSIGNED: return "t.CUInt8T"
if sign == TSpec.TS_SIGN_UNSIGNED: return "uint8"
return "char"
if string.strcmp(buf, "i16") == 0:
if sign == TSpec.TS_SIGN_UNSIGNED: return "t.CUInt16T"
if sign == TSpec.TS_SIGN_SIGNED: return "t.CInt16T"
if sign == TSpec.TS_SIGN_UNSIGNED: return "uint16"
if sign == TSpec.TS_SIGN_SIGNED: return "int16"
return None
if string.strcmp(buf, "i32") == 0:
# 无符号 i32(CUInt32T/CSizeT/CUIntPtrT)走裸名 int 会静默变号
if sign == TSpec.TS_SIGN_UNSIGNED: return "t.CUInt32T"
if sign == TSpec.TS_SIGN_UNSIGNED: return "uint32"
return "int"
if string.strcmp(buf, "i64") == 0:
if sign == TSpec.TS_SIGN_UNSIGNED: return "t.CUInt64T"
if sign == TSpec.TS_SIGN_SIGNED: return "t.CInt64T"
if sign == TSpec.TS_SIGN_UNSIGNED: return "uint64"
if sign == TSpec.TS_SIGN_SIGNED: return "int64"
return None
# ---- 浮点:位宽精确(无符号性概念,无歧义)----
if string.strcmp(buf, "half") == 0: return "t.CFloat16T"
@@ -950,7 +950,7 @@ novirtual class ClassGenGeneric(ClassGenBase.ClassGenBase):
tpn: str = tp_names.get(i)
if tpn is not None and string.strcmp(nm.id, tpn) == 0:
ta: str = type_args.get(i)
# 类型实参可能是复合类型(如 "AST|t.CPtr"),用 _parse_type_string 解析
# 类型实参可能是复合类型(如 "AST*"),用 _parse_type_string 解析
parsed_node: ast.AST* = self.Gen.TypeGenResolve._parse_type_string(pool, ta, nm.ctx)
return parsed_node
return ast.Name(pool, nm.id, nm.ctx)
@@ -962,7 +962,7 @@ novirtual class ClassGenGeneric(ClassGenBase.ClassGenBase):
new_value: ast.AST* = self._clone_annotation(pool, at.value, tp_names, type_args)
return ast.Attribute(pool, new_value, at.attr, at.ctx)
# BinOp: T | t.CPtr 等
# BinOp: T* 等
if k == ast.ASTKind.BinOp:
bop: ast.BinOp* = ast.BinOp*(node)
new_left: ast.AST* = self._clone_annotation(pool, bop.left, tp_names, type_args)
@@ -1167,25 +1167,25 @@ novirtual class ClassGenGeneric(ClassGenBase.ClassGenBase):
string.strcpy(ts_buf_r, trigger_sha1)
entry_rt.SpecTriggerSha1 = ts_buf_r
return 1
def _tp_names_for_spec(self, pool: memhub.MemBuddy*, class_name: str,
template_cd: ast.ClassDef*) -> list[str]*:
"""取特化用的类型参数名列表(优先 stdlib 深拷贝表,退化模板节点)
两条来源都拿不到/为空时 fail-fast,**绝不**用空泛型上下文继续特化:
空上下文会让模板方法体里的类型形参(如 `T.__sizeof__()`)落到普通名字
查找 → 报 "NameError: 未定义名称 'T'",现象与真因(元数据缺失)严重脱节。
"""
tp: list[str]* = self._find_generic_template_tp_params(pool, class_name)
if tp is not None and len(tp) > 0:
return tp
if template_cd is not None and template_cd.type_params is not None \
and len(template_cd.type_params) > 0:
return template_cd.type_params
self.Gen.TypeGenErr.fatal_error(None,
f"泛型类模板 '{class_name}' 的类型参数名缺失(GenericClassTpParams 对应槽为空,"
f"模板节点也无 type_params)——拒绝用空泛型上下文特化", "InternalCompilerError")
return None
def _tp_names_for_spec(self, pool: memhub.MemBuddy*, class_name: str,
template_cd: ast.ClassDef*) -> list[str]*:
"""取特化用的类型参数名列表(优先 stdlib 深拷贝表,退化模板节点)
两条来源都拿不到/为空时 fail-fast,**绝不**用空泛型上下文继续特化:
空上下文会让模板方法体里的类型形参(如 `T.__sizeof__()`)落到普通名字
查找 → 报 "NameError: 未定义名称 'T'",现象与真因(元数据缺失)严重脱节。
"""
tp: list[str]* = self._find_generic_template_tp_params(pool, class_name)
if tp is not None and len(tp) > 0:
return tp
if template_cd is not None and template_cd.type_params is not None \
and len(template_cd.type_params) > 0:
return template_cd.type_params
self.Gen.TypeGenErr.fatal_error(None,
f"泛型类模板 '{class_name}' 的类型参数名缺失(GenericClassTpParams 对应槽为空,"
f"模板节点也无 type_params)——拒绝用空泛型上下文特化", "InternalCompilerError")
return None
def _specialize_generic_class(self, trans: HT.Translator*,
class_name: str,
type_args: list[str]*) -> str:
@@ -1253,7 +1253,7 @@ novirtual class ClassGenGeneric(ClassGenBase.ClassGenBase):
pre_existing: GenTypes.StructEntry* = self.Gen.StructGen.find_struct(spec_name)
if pre_existing is not None and pre_existing.MethodsEmitted == 0:
# 防重入:先标记 MethodsEmitted=1,避免补译过程中方法体/返回类型注解
# 再次触发 _specialize_generic_class(如 __iter__ 返回 list[T]|t.CPtr)
# 再次触发 _specialize_generic_class(如 __iter__ 返回 list[T]*)
# 导致无限递归补译 → OOM。补译完成后已设置,无需恢复。
# 注意:此处提前置位后调用 _translate_oop_methods 必须传 reemit=1
# (补译模式),否则其 MethodsEmitted==1 防重复检查会拦截补译,
+2 -2
View File
@@ -510,7 +510,7 @@ novirtual class ClassGenVTable(ClassGenBase.ClassGenBase):
return 0
# 防重入:方法体翻译前先标记 MethodsEmitted=1。
# 根因:若等全部方法译完再标记,翻译 __iter__(返回 list[T]|t.CPtr)时,
# 根因:若等全部方法译完再标记,翻译 __iter__(返回 list[T]*)时,
# 返回类型注解会再次触发 _specialize_generic_class,此时 MethodsEmitted
# 仍为 0,走补译分支把同一特化类方法全部重发 → invalid redefinition。
if oop_entry is not None:
@@ -712,7 +712,7 @@ novirtual class ClassGenVTable(ClassGenBase.ClassGenBase):
if decl_reuse == 0:
# 提取默认参数信息(普通方法 args[0] 是 self,不含在 param_count 中;
# @staticmethod 无 self,param_count 为完整参数数)
# 注意: 必须先把属性赋给显式类型为 list[...] | t.CPtr 的局部变量再调用 __len__(),
# 注意: 必须先把属性赋给显式类型为 list[...]* 的局部变量再调用 __len__(),
# 否则编译器无法识别属性返回的 list 类型,GEP base 会变成 i32 0 导致 llc 报错
md_defaults: t.CPtr = None
md_default_count: int = 0
+10 -10
View File
@@ -49,15 +49,15 @@ _g_depth: int = 0
# current DISubprogram was pushed on (e.g. an async state machine emitted inside
# a bracketed function): such instructions must carry no !dbg, otherwise LLVM's
# verifier rejects "!dbg attachment points at wrong subprogram for function".
DBG_STACK_MAX: t.CDefine = 256
define DBG_STACK_MAX = 256
_g_stk_sp: sizet* = None
_g_stk_ref: str = None
_g_stk_bld: str = None
# DILocation cache: direct-mapped, up to 8-way linear probe, key (sp, line, col).
DBG_LOC_SLOTS: t.CDefine = 8192
DBG_LOC_PROBE: t.CDefine = 8
DBG_LOC_KEY_STRIDE: t.CDefine = 3
define DBG_LOC_SLOTS = 8192
define DBG_LOC_PROBE = 8
define DBG_LOC_KEY_STRIDE = 3
_g_loc_key: sizet* = None
_g_loc_ref: str = None
_g_loc_used: bytes = None
@@ -264,7 +264,7 @@ def _EnsureModuleNodes(pool: memhub.MemBuddy*) -> int:
# _LocRefAt - read a cached DILocation ref string pointer
# ============================================================
def _LocRefAt(slot: int) -> str:
slotp: str | t.CPtr = (str | t.CPtr)(uint64(_g_loc_ref) + sizet(slot) * 8)
slotp: str* = (str*)(uint64(_g_loc_ref) + sizet(slot) * 8)
r: str = slotp[0]
return r
@@ -309,7 +309,7 @@ def _EnsureLocation(pool: memhub.MemBuddy*, sp: int, line: int, col: int) -> str
_g_loc_key[kbase2] = sizet(sp)
_g_loc_key[kbase2 + 1] = sizet(line)
_g_loc_key[kbase2 + 2] = sizet(c)
rslot: str | t.CPtr = (str | t.CPtr)(uint64(_g_loc_ref) + sizet(slot2) * 8)
rslot: str* = (str*)(uint64(_g_loc_ref) + sizet(slot2) * 8)
rslot[0] = lref
_g_loc_used[slot2] = 1
return lref
@@ -365,9 +365,9 @@ def PushFunction(pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*,
mlirlite.function_set_dbg(func, sp_ref)
# save the enclosing function's DI context (LIFO), then switch to this one
_g_stk_sp[_g_depth] = sizet(_g_cur_sp + 1)
rslot: str | t.CPtr = (str | t.CPtr)(uint64(_g_stk_ref) + sizet(_g_depth) * 8)
rslot: str* = (str*)(uint64(_g_stk_ref) + sizet(_g_depth) * 8)
rslot[0] = _g_cur_entry_ref
bslot: str | t.CPtr = (str | t.CPtr)(uint64(_g_stk_bld) + sizet(_g_depth) * 8)
bslot: str* = (str*)(uint64(_g_stk_bld) + sizet(_g_depth) * 8)
bslot[0] = _g_cur_builder
_g_depth += 1
_g_cur_sp = sp_id
@@ -395,9 +395,9 @@ def PopFunction(builder: mlirlite.IRBuilder*) -> int:
return 0
_g_depth -= 1
_g_cur_sp = int(_g_stk_sp[_g_depth]) - 1
rslot: str | t.CPtr = (str | t.CPtr)(uint64(_g_stk_ref) + sizet(_g_depth) * 8)
rslot: str* = (str*)(uint64(_g_stk_ref) + sizet(_g_depth) * 8)
_g_cur_entry_ref = rslot[0]
bslot: str | t.CPtr = (str | t.CPtr)(uint64(_g_stk_bld) + sizet(_g_depth) * 8)
bslot: str* = (str*)(uint64(_g_stk_bld) + sizet(_g_depth) * 8)
_g_cur_builder = (mlirlite.IRBuilder*)(bslot[0])
if builder is not None:
mlirlite.builder_clear_debug_location(builder)
+20 -20
View File
@@ -351,7 +351,7 @@ novirtual class ExprGenAttr(ExprGenBase.ExprGenBase):
mod: mlirlite.LLVMModule*,
at_value: ast.AST*,
trans: HT.Translator* = None) -> mlirlite.Value*:
"""检测 at.value 是否为 c.Deref(ptr) 调用,返回 ptr 指针(不做 load)"""
"""检测 at.value 是否为 *ptr 调用,返回 ptr 指针(不做 load)"""
if at_value is None or at_value.kind() != ast.ASTKind.Call:
return None
cl_cd: ast.Call* = ast.Call*(at_value)
@@ -398,12 +398,12 @@ novirtual class ExprGenAttr(ExprGenBase.ExprGenBase):
VLogger.error(diag_buf_an, "ATTR")
return None
# static 符号(禁止跨模块使用):`mod.name` 命中别的模块登记的 static 符号
# 即 fail-fast。逻辑全部收敛在 _CheckStaticCrossModule 内——不在此内联展开
# (内联会让本函数的类型推断受干扰:新增分支/跨函数调用改变了后续变量
# 的推断结果,曾导致本函数 L765 的 `match obj_ptr.Ty` 报"指针隐式转整数")。
self._CheckStaticCrossModule(pool, trans, at)
# static 符号(禁止跨模块使用):`mod.name` 命中别的模块登记的 static 符号
# 即 fail-fast。逻辑全部收敛在 _CheckStaticCrossModule 内——不在此内联展开
# (内联会让本函数的类型推断受干扰:新增分支/跨函数调用改变了后续变量
# 的推断结果,曾导致本函数 L765 的 `match obj_ptr.Ty` 报"指针隐式转整数")。
self._CheckStaticCrossModule(pool, trans, at)
# 魔法属性 __doc__:查询 docstring 登记表(预注册阶段从 AST 提取),
# 命中则当前模块内联生成字符串常量返回;未命中(无 docstring 的
# 函数/类/方法)返回 null 指针(i8*)。支持本模块与跨模块符号:
@@ -760,7 +760,7 @@ novirtual class ExprGenAttr(ExprGenBase.ExprGenBase):
obj_ptr = self.Gen.ExprGenName.get_subscript_ptr(builder, pool, mod, at.value, trans)
elif at.value.kind() == ast.ASTKind.Attribute:
# 嵌套属性基座(如 r.origin.x):取内层字段地址(get_attribute_ptr 递归,
# 地址语义),指针字段(X|t.CPtr)由 _deref_if_ptr_ptr load 解引用
# 地址语义),指针字段(X*)由 _deref_if_ptr_ptr load 解引用
obj_ptr = self.get_attribute_ptr(builder, pool, mod, at.value, trans)
if obj_ptr is None:
obj_ptr = self.Gen.ExprGen.translate_value(builder, pool, mod, at.value, None, 0, trans)
@@ -770,7 +770,7 @@ novirtual class ExprGenAttr(ExprGenBase.ExprGenBase):
if obj_ptr is None or obj_ptr.Ty is None:
return None
# 如果 obj_ptr 是 Ptr(Ptr(Struct))(X|t.CPtr 变量的 alloca),
# 如果 obj_ptr 是 Ptr(Ptr(Struct))(X* 变量的 alloca),
# load 解引用获取 Ptr(Struct)
obj_ptr = self._deref_if_ptr_ptr(builder, obj_ptr)
@@ -800,7 +800,7 @@ novirtual class ExprGenAttr(ExprGenBase.ExprGenBase):
if alias_fe is not None and alias_fe.Ty is not None:
alias_ptr: mlirlite.Value* = mlirlite.build_gep_struct(builder, struct_ty, alias_fe.Ty, obj_ptr, alias_idx)
if alias_ptr is not None:
# REnum 变体字段按声明类型读取(对齐 match 绑定 _lookup_renum_member_ty):槽位是 i32/i64(布局按最大字段大小),直接 load 得整数位模式,赋给 X|t.CPtr 指针变量会触发 int→ptr 禁令误报。用别名表存的成员声明类型(自引用退化为 i8*)把槽位地址 bitcast 后按声明类型 load——同宽无信息丢失,指针字段读出真正的指针值
# REnum 变体字段按声明类型读取(对齐 match 绑定 _lookup_renum_member_ty):槽位是 i32/i64(布局按最大字段大小),直接 load 得整数位模式,赋给 X* 指针变量会触发 int→ptr 禁令误报。用别名表存的成员声明类型(自引用退化为 i8*)把槽位地址 bitcast 后按声明类型 load——同宽无信息丢失,指针字段读出真正的指针值
decl_ty_rn: mlirlite.LLVMType* = self.Gen.ClassGenEnum._lookup_renum_field_alias_ty(renum_se.Name, at.attr)
if decl_ty_rn is not None:
decl_ptr_rn: mlirlite.LLVMType* = mlirlite.Ptr(pool, decl_ty_rn)
@@ -854,7 +854,7 @@ novirtual class ExprGenAttr(ExprGenBase.ExprGenBase):
if rn_fe is not None and rn_fe.Ty is not None:
field_info = rn_fe
# 按需过滤成功:bitcast obj_ptr 到 AnnotClassName 对应的结构体类型
# 原始 struct_ty 可能是 i8(X|t.CPtr 简化为 Ptr(i8)),
# 原始 struct_ty 可能是 i8(X* 简化为 Ptr(i8)),
# 需用实际结构体类型做 GEP,否则 GEP i8 失败
if field_info is not None:
annot_se: GenTypes.StructEntry* = self.Gen.StructGen.find_struct(base_class)
@@ -889,7 +889,7 @@ novirtual class ExprGenAttr(ExprGenBase.ExprGenBase):
if field_ptr is not None:
# [FIX 2026-08-31] REnum 变体字段按声明类型读取(与主路径
# 变体别名回退一致):field_info 是 _pN 槽位(i32/i64),
# 直接 load 得整数位模式 → 赋给 X|t.CPtr 指针变量触发 int→ptr
# 直接 load 得整数位模式 → 赋给 X* 指针变量触发 int→ptr
# 误报。bitcast 槽位地址后按声明类型 load(同宽无信息丢失)。
rn_rd_se: GenTypes.StructEntry* = \
self.Gen.StructGen.find_struct_by_type(struct_ty)
@@ -908,7 +908,7 @@ novirtual class ExprGenAttr(ExprGenBase.ExprGenBase):
if self.is_array_type(field_ty) != 0:
return field_ptr
loaded_val: mlirlite.Value* = mlirlite.build_load(builder, field_ty, field_ptr, field_vol_rd)
# 联合类型字段(如 Token | t.CPtr)被编译为 i8*,
# 联合类型字段(如 Token*)被编译为 i8*,
# 若 AnnotClassName 指示了具体结构体类型,bitcast 为正确的结构体指针。
# 注意:仅当字段类型本身是指针时才 bitcast(指针→指针);
# 内嵌结构体字段(field_ty=Struct)load 出的是结构体值,
@@ -988,7 +988,7 @@ novirtual class ExprGenAttr(ExprGenBase.ExprGenBase):
allow_module_global: int = 0) -> str:
"""解析属性链(a.b.c)中 c 字段的注解类名。
联合类型字段(X | t.CPtr)被简化为 Ptr(i8),属性链写入时
联合类型字段(X*)被简化为 Ptr(i8),属性链写入时
(如 lx.tokens_tail.next = tok)obj_ptr.Ty 是 Ptr(i8),
lookup_field(i8, ...) 必然失败。此函数沿属性链递归解析
最终字段的 AnnotClassName(如 tokens_tail → 'Token'),
@@ -1043,8 +1043,8 @@ novirtual class ExprGenAttr(ExprGenBase.ExprGenBase):
# ============================================================
# _base_class_from_cast_base - 指针强转基座 `T*(x)` 的类名
#
# `T*(x)` 被 parser 的 _consume_ptr_suffix_call 解析成 `(T | t.CPtr)(x)`
# 强转调用(与手写 `(T | t.CPtr)(x)` 逐字同形),与 `t.CPtr` 取联合后结果
# `T*(x)` 被 parser 的 _consume_ptr_suffix_call 解析成 `(T*)(x)`
# 强转调用(与手写 `(T*)(x)` 逐字同形),与 `t.CPtr` 取联合后结果
# 的 LLVM 类型是**简化后的 i8***。于是 `(ast.Call*(vinner)).IsVolatile`
# 这类强转基座的字段访问/写入里 lookup_field(i8, ...) 必然失败。
#
@@ -1076,7 +1076,7 @@ novirtual class ExprGenAttr(ExprGenBase.ExprGenBase):
bo_cb: ast.BinOp* = ast.BinOp*(cl_cb.func)
if bo_cb.op != ast.OpKind.BitOr:
return None
# 联合一侧是 t.CPtr 标记(`T | t.CPtr` / `T**` 展开的嵌套联合)时取另一侧;
# 联合一侧是 t.CPtr 标记(`T*` / `T**` 展开的嵌套联合)时取另一侧;
# 否则(手写 `X | Y`)取左侧——与 parser 的 _make_ptr_type 产物一致。
tgt_cb: ast.AST* = bo_cb.left
if self.Gen.TypeGenResolve._is_cptr_marker(bo_cb.left, trans._imported_modules) != 0:
@@ -1259,7 +1259,7 @@ novirtual class ExprGenAttr(ExprGenBase.ExprGenBase):
仅当基址可解析到具体 VarEntry(Name)/ FieldEntry(Attribute)时生效;
基址是函数返回/下标/调用/更复杂表达式时返回 0(明确不支持)。
消费点:p[i] / p.field / c.Deref(p) 的 load/store 据此加 LLVM volatile。
消费点:p[i] / p.field / *p 的 load/store 据此加 LLVM volatile。
"""
if base_node is None or trans is None:
return 0
@@ -1363,7 +1363,7 @@ novirtual class ExprGenAttr(ExprGenBase.ExprGenBase):
if obj_ptr is None or obj_ptr.Ty is None:
return None
# 如果 obj_ptr 是 Ptr(Ptr(Struct))(X|t.CPtr 变量的 alloca),
# 如果 obj_ptr 是 Ptr(Ptr(Struct))(X* 变量的 alloca),
# load 解引用获取 Ptr(Struct)
obj_ptr = self._deref_if_ptr_ptr(builder, obj_ptr)
@@ -1413,7 +1413,7 @@ novirtual class ExprGenAttr(ExprGenBase.ExprGenBase):
if rn_fe_g is not None and rn_fe_g.Ty is not None:
field_info = rn_fe_g
# 按需过滤成功:bitcast obj_ptr 到 AnnotClassName 对应的结构体类型
# 原始 struct_ty 可能是 i8(X|t.CPtr 简化为 Ptr(i8)),
# 原始 struct_ty 可能是 i8(X* 简化为 Ptr(i8)),
# 需用实际结构体类型做 GEP,否则 GEP i8 失败
if field_info is not None:
annot_se: GenTypes.StructEntry* = self.Gen.StructGen.find_struct(base_class)
+14 -14
View File
@@ -224,7 +224,7 @@ novirtual class ExprGenBase:
#
# 属性访问的 Subscript 基座(如 lst[i].x)需要区分:
# - list[T] 变量:translate_subscript 走 __getitem__ 内联返回元素地址
# - 普通结构体指针数组(如 pts: Point | t.CPtr):get_subscript_ptr 返回元素地址
# - 普通结构体指针数组(如 pts: Point*):get_subscript_ptr 返回元素地址
# 路由错误会让 list[T] 被当作结构体数组 GEP,访问错位崩溃。
# ============================================================
def _is_list_subscript_base(self, pool: memhub.MemBuddy*,
@@ -282,7 +282,7 @@ novirtual class ExprGenBase:
# 属性访问的 Subscript 基座路由依据:
# - list[T] / OOP 定义 __getitem__ 的类(如 dict[key])→ translate_value
# (translate_subscript 走 __getitem__ 内联/方法调用返回元素值或地址)
# - 普通结构体指针数组(如 pts: Point | t.CPtr)→ get_subscript_ptr
# - 普通结构体指针数组(如 pts: Point*)→ get_subscript_ptr
# (GEP 元素地址,避免结构体值 base=非指针 报错)
# ============================================================
def _sub_base_uses_getitem(self, pool: memhub.MemBuddy*,
@@ -301,9 +301,9 @@ novirtual class ExprGenBase:
# ============================================================
# _deref_if_ptr_ptr - 如果 obj_ptr 是 Ptr(Ptr(...)),load 解引用
#
# 用于支持 X|t.CPtr 类型变量的属性访问:
# 用于支持 X* 类型变量的属性访问:
# - 值类型变量 (cnt: Counter): alloca 类型是 Ptr(Struct) → 不解引用
# - 指针类型变量 (r: Vec2|t.CPtr): alloca 类型是 Ptr(Ptr(Struct)) → load 解引用
# - 指针类型变量 (r: Vec2*): alloca 类型是 Ptr(Ptr(Struct)) → load 解引用
# ============================================================
def _deref_if_ptr_ptr(self, builder: mlirlite.IRBuilder*,
obj_ptr: mlirlite.Value*) -> mlirlite.Value*:
@@ -344,8 +344,8 @@ novirtual class ExprGenBase:
v = (ast.Return*(node)).value
if v is None:
return node
return v
# ============================================================
return v
# ============================================================
# IsNoneValue - 判据:源值是否为 None(空值常量),返回 1=是 / 0=否
#
# None 是特殊的空值常量:语义上「无值」,按语言规则**允许隐式转换为任意
@@ -437,7 +437,7 @@ novirtual class ExprGenBase:
# 调用方从**注解来源**给出:赋值侧 trans.CurAssignAnnot、返回侧
# trans.CurFuncRetAnnot、形参侧 vpi/函数签名注解段。
#
# 只认**裸名**:`str` / `bytes`。`str | t.CPtr` 的语义是 i8**(指针槽,
# 只认**裸名**:`str` / `bytes`。`str*` 的语义是 i8**(指针槽,
# 见 AssignGenMixin._is_ptr_element_annotation),不是字符串值本体,不适用。
# ============================================================
def _annot_name_is_bare_str(self, txt: str) -> int:
@@ -864,18 +864,18 @@ novirtual class ExprGenBase:
# (inttoptr 要求同宽,对齐 MatchGenMixin 模式),再 inttoptr 成空指针。
if val.IsConst == 1 and val.IntVal == 0:
return mlirlite.build_inttoptr(builder, mlirlite.const_int64(builder.Pool, 0), target_ty)
m_i2p: str = "整数隐式转指针已禁止:必须显式强转为指针(如 t.CPtr(x))才能把整数赋给指针类型"
self.Gen.TypeGenErr.fatal_error(self._value_node_of(node),
m_i2p, "CastError")
m_i2p: str = "整数隐式转指针已禁止:必须显式强转为指针(如 t.CPtr(x))才能把整数赋给指针类型"
self.Gen.TypeGenErr.fatal_error(self._value_node_of(node),
m_i2p, "CastError")
return val
# Pointer -> integer: rejected (symmetric with the integer -> pointer rule above).
# No implicit pointer <-> integer conversion is allowed; an explicit cast is
# required. (The old code silently did ptrtoint, and for 8-bit targets fell
# through to the build_load branch below, copying the pointee's first byte.)
if self.is_ptr_type(val.Ty) != 0 and target_bits != 0 and self.is_ptr_type(target_ty) == 0:
m_p2i: str = "指针隐式转整数已禁止:必须显式强转(如 uint64(p) / t.CInt64T(p) / int(p))才能把指针赋给整数类型"
self.Gen.TypeGenErr.fatal_error(self._value_node_of(node),
m_p2i, "CastError")
m_p2i: str = "指针隐式转整数已禁止:必须显式强转(如 uint64(p) / int64(p) / int(p))才能把指针赋给整数类型"
self.Gen.TypeGenErr.fatal_error(self._value_node_of(node),
m_p2i, "CastError")
return val
if val_bits != 0 and target_bits != 0:
if val_bits == target_bits:
@@ -981,7 +981,7 @@ novirtual class ExprGenBase:
return val
return mlirlite.build_load(builder, target_ty, val)
self.Gen.TypeGenErr.fatal_error(self._value_node_of(node),
f"指针隐式转非指针值已禁止:必须显式解引用(c.Deref(p) / *p)或显式强转(uint64(p))", "CastError")
f"指针隐式转非指针值已禁止:必须显式解引用(*p / *p)或显式强转(uint64(p))", "CastError")
return val
# 指针 → 指针: 隐式转换须满足两条新规则(见 _ptr_cast_reason 单一真源):
# 规则 1 通用指针(t.CPtr / i8*)与任何 T* 双向互转都放行;
+1 -1
View File
@@ -1187,7 +1187,7 @@ novirtual class ExprGenCdef(ExprGenBase.ExprGenBase):
f"(该位宽按有符号/无符号两种解释可接受的范围: {lo}..{hi})。"
f"禁止静默截断/降级,已终止编译。"
f"修法: 把使用处{ctx}的类型加宽到至少 {wmin} 位"
f"(如 t.CInt{wmin}T / CUInt{wmin}T 及更宽类型),或改用更小的常量值。",
f"(如 int{wmin}T / CUInt{wmin}T 及更宽类型),或改用更小的常量值。",
"TypeError")
return None
return mlirlite.const_int(pool, bits, self._cdefine_bits_value(value, bits))
+3 -3
View File
@@ -258,7 +258,7 @@ novirtual class ExprGenCls(ExprGenBase.ExprGenBase):
# infer_expr_class - 从表达式推断结构体类名(共享推断)
#
# 无注解赋值(HandlesAssign)与方法调用分派(CallGenMixin)共用:
# 联合类型 X|t.CPtr 简化为 Ptr(i8),不含类名,需按表达式结构推断:
# 联合类型 X* 简化为 Ptr(i8),不含类名,需按表达式结构推断:
# Call → 类实例化(func 为已注册结构体名);func 为 Attribute
# 时是方法调用,经 vpi 返回注解缓存解析返回类名
# Name → 源变量的 AnnotClassName
@@ -415,7 +415,7 @@ novirtual class ExprGenCls(ExprGenBase.ExprGenBase):
while s < e and (annot[s] == ' ' or annot[s] == '\'' or annot[s] == '"'):
s += 1
# 段尾另需剥 '*':实参归一后段文本是 `{sha}.AST*`(旧形态
# `{sha}.AST | t.CPtr` 按 '|' 分段能落到 `{sha}.AST` 命中),与
# `{sha}.AST*` 按 '|' 分段能落到 `{sha}.AST` 命中),与
# ExprGenName._list_elem_obj_ty_from_struct_name 的尾剔除同口径;
# 不剥则 find_struct 落空 → 返回 None → 链式 .get(0).kind() 分派退化。
while e > s and (annot[e - 1] == ' ' or annot[e - 1] == '\'' or annot[e - 1] == '"' or annot[e - 1] == '*'):
@@ -440,7 +440,7 @@ novirtual class ExprGenCls(ExprGenBase.ExprGenBase):
while s < e and (annot[s] == ' ' or annot[s] == '\'' or annot[s] == '"'):
s += 1
# 段尾另需剥 '*':实参归一后段文本是 `{sha}.AST*`(旧形态
# `{sha}.AST | t.CPtr` 按 '|' 分段能落到 `{sha}.AST` 命中),与
# `{sha}.AST*` 按 '|' 分段能落到 `{sha}.AST` 命中),与
# ExprGenName._list_elem_obj_ty_from_struct_name 的尾剔除同口径;
# 不剥则 find_struct 落空 → 返回 None → 链式 .get(0).kind() 分派退化。
while e > s and (annot[e - 1] == ' ' or annot[e - 1] == '\'' or annot[e - 1] == '"' or annot[e - 1] == '*'):
+30 -30
View File
@@ -97,7 +97,7 @@ novirtual class ExprGenName(ExprGenBase.ExprGenBase):
if self.Gen.ExprGenCdef._is_cdefine_name_pattern(nm_id) != 0:
if trans is not None:
# ALL_CAPS 也可能是普通变量(如 Gargantua 的
# CAM/FWD/RIGHT/UP: V3|t.CPtr 模块级全局)。若当前作用域
# CAM/FWD/RIGHT/UP: V3* 模块级全局)。若当前作用域
# (含模块级 Root,lookup_var 逐级上溯)已存在同名变量,
# 优先按变量处理,跳过跨模块 CDefine 查找——否则 ALL_CAPS
# 命中 star-import 模块(from stdint import *)→ 无谓读源
@@ -385,17 +385,17 @@ novirtual class ExprGenName(ExprGenBase.ExprGenBase):
or string.strcmp(nm_id, "CIf") == 0 or string.strcmp(nm_id, "CIfdef") == 0 \
or string.strcmp(nm_id, "CIfndef") == 0:
return None
# 诊断:把当前泛型上下文一并报出 —— "未定义名称 'T'" 常与真因(泛型上下文
# 为空 / 装不上)严重脱节:形参 0 个 ⇒ 上下文根本没建起来;形参 >0 而实参 0
# 个 ⇒ 实参表丢了;两者皆 >0 ⇒ 上下文在、但该名字不在其中。一眼可分。
# (现场 includes/vector.vp:12 `T.__sizeof__()`,Vector[CFloat64T] 特化)
ctx_txt: str = ""
if trans is not None and trans.GenericTypeParamNames is not None:
ctp_n: sizet = len(trans.GenericTypeParamNames)
cta_n: sizet = 0
if trans.GenericTypeArgs is not None:
cta_n = len(trans.GenericTypeArgs)
ctx_txt = f"(当前泛型上下文: 类型形参 {ctp_n} 个 / 类型实参 {cta_n} 个)"
# 诊断:把当前泛型上下文一并报出 —— "未定义名称 'T'" 常与真因(泛型上下文
# 为空 / 装不上)严重脱节:形参 0 个 ⇒ 上下文根本没建起来;形参 >0 而实参 0
# 个 ⇒ 实参表丢了;两者皆 >0 ⇒ 上下文在、但该名字不在其中。一眼可分。
# (现场 includes/vector.vp:12 `T.__sizeof__()`,Vector[CFloat64T] 特化)
ctx_txt: str = ""
if trans is not None and trans.GenericTypeParamNames is not None:
ctp_n: sizet = len(trans.GenericTypeParamNames)
cta_n: sizet = 0
if trans.GenericTypeArgs is not None:
cta_n = len(trans.GenericTypeArgs)
ctx_txt = f"(当前泛型上下文: 类型形参 {ctp_n} 个 / 类型实参 {cta_n} 个)"
self.Gen.TypeGenErr.fatal_error(node, f"未定义名称 '{nm_id}'{ctx_txt}", "NameError")
return None
# ============================================================
@@ -481,7 +481,7 @@ novirtual class ExprGenName(ExprGenBase.ExprGenBase):
if string.strstr(struct_name, "list[CPtr]") is not None:
return mlirlite.Ptr(pool, i8_ty_d)
# 未知 list[T] 元素类型(自定义结构体元素,如
# list[rawptr[7565e081d88517ac.AST]] / list[sha1.Foo|t.CPtr]):
# list[rawptr[7565e081d88517ac.AST]] / list[sha1.Foo*]):
# 元素槽存对象指针(8 字节)。从元素类型文本还原对象指针 LLVM 类型
# Ptr(%Struct),使 list.get/__getitem__/pop 内联返回值的 LLVM 类型
# 携带元素原型类——链式方法调用(mod.children.get(0).kind())的接收者
@@ -500,7 +500,7 @@ novirtual class ExprGenName(ExprGenBase.ExprGenBase):
# _list_elem_obj_ty_from_struct_name — 从 list 特化类型名还原元素对象指针类型
#
# struct_name 形如 "{_list_sha1}.list[rawptr[{sha1}.AST]]" 或
# "{_list_sha1}.list[{sha1}.AST|t.CPtr]"(联合元素)。取 '[' 与最后 ']'
# "{_list_sha1}.list[{sha1}.AST*]"(联合元素)。取 '[' 与最后 ']'
# 之间的元素描述文本:剥 rawptr[...] 包装、按 '|' 联合分段、去首尾空白,
# 逐段按已注册结构体还原(元素类带模块 SHA1 前缀时 find_struct 走
# find_struct_by_module 精确匹配,规避跨模块同名歧义);命中返回
@@ -857,10 +857,10 @@ novirtual class ExprGenName(ExprGenBase.ExprGenBase):
return mlirlite.build_load(builder, elem_ty_list, casted_addr_list)
return None
# inner_ty 是 Ptr 说明 alloca.Ty 是三重指针 Ptr(Ptr(Ptr(...))),
# 即 X|t.CPtr 当 X 本身是指针类型 (如 T=AST|t.CPtr, T|t.CPtr=AST**)。
# 即 X* 当 X 本身是指针类型 (如 T=AST*, T*=AST**)。
# 此时 [i] 应该是指针解引用 (步长 sizeof(ptr)=8), 而非调用
# 结构体的 __getitem__ 方法 (会错误生成 AST.__getitem__ 调用)。
# 对比 HashTable|t.CPtr: alloca.Ty=HashTable**, inner_ty=Struct(HashTable)
# 对比 HashTable*: alloca.Ty=HashTable**, inner_ty=Struct(HashTable)
# (非 Ptr), 仍走下面的方法调用转发路径。
if self.is_ptr_type(inner_ty) != 0:
ptr_val_pp: mlirlite.Value* = mlirlite.build_load(builder, pointee, alloca)
@@ -870,7 +870,7 @@ novirtual class ExprGenName(ExprGenBase.ExprGenBase):
# volatile 指针指向物:解引用 load 带 volatile
return mlirlite.build_load(builder, inner_ty, elem_ptr_pp, vol_sub_rd)
return None
# 自定义结构体 (如 HashTable|t.CPtr, JsonValue|t.CPtr):
# 自定义结构体 (如 HashTable*, JsonValue*):
# 仅当类定义了 __getitem__(当前模块定义或跨模块 stub declare 注入)
# 才转发方法调用;否则普通结构体指针按下标做 GEP 数组访问
# (对齐 TPC _HandleSubscriptLlvm: if ClassName and has_function(__getitem__))
@@ -896,14 +896,14 @@ novirtual class ExprGenName(ExprGenBase.ExprGenBase):
# volatile 指针指向物:解引用 load 带 volatile
return mlirlite.build_load(builder, inner_ty, elem_rd_g, vol_sub_rd)
return None
# bytes|t.CPtr / str|t.CPtr: alloca 是 i8**,
# bytes* / str*: alloca 是 i8**,
# 直接 GEP 按 i8* 步长(8 字节),load i8*
# 仅当 inner_ty 不是自定义结构体时才走指针遍历
if trans is not None:
ve_pe_ts: GenTypes.VarEntry* = \
self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm.id)
if self.Gen.VarGen.var_is_ptr_element(ve_pe_ts) != 0:
# bytes|t.CPtr / str|t.CPtr / T|t.CPtr:变量存指针值(i8*),
# bytes* / str* / T*:变量存指针值(i8*),
# elem[i] 语义 = load [指针值 + i*8](8 字节指针元素)。
# 必须先 load alloca 得指针值,再 GEP i8*(步长 8)——
# 否则 GEP base 用 alloca(&elem_ptr)读到栈变量而非数据区,
@@ -925,7 +925,7 @@ novirtual class ExprGenName(ExprGenBase.ExprGenBase):
return None
case _:
# 联合类型变量(IsPtrElement=1,如 _list.vp 的
# elem_ptr: T | t.CPtr 退化为 i8*):pointee=i8 但
# elem_ptr: T* 退化为 i8*):pointee=i8 但
# 元素是 8 字节指针,须按 i8* 步长 GEP + load i8*——
# 否则 list.get 只读 1 字节,指针截断 inttoptr 崩溃。
if trans is not None:
@@ -991,7 +991,7 @@ novirtual class ExprGenName(ExprGenBase.ExprGenBase):
case _:
pass
# 64-bit scalar pointer fields (e.g. `sizet*`, `uint64*`, written as
# `t.CUInt64T | t.CPtr`) keep the declared element type here: the slot is
# `t.CUInt64T*`) keep the declared element type here: the slot is
# a u64, so it is read as i64 -- same element type the write path uses
# (see get_subscript_ptr). Loading it as i8* fabricated a pointer value
# out of an integer slot and forced the caller through an implicit
@@ -1027,7 +1027,7 @@ novirtual class ExprGenName(ExprGenBase.ExprGenBase):
# ============================================================
def _annot_is_64bit_scalar(self, annot: str) -> int:
"""注解是否为 64 位标量 | t.CPtr 联合(AnnotClassName 为提取出的
非 CPtr 侧类型名,如 int64|t.CPtr → "CInt64T")。此类联合的
非 CPtr 侧类型名,如 int64* → "CInt64T")。此类联合的
8 字节单元格存 i64 标量,下标元素类型应为 Int64 而非指针。"""
if annot is None: return 0
if string.strstr(annot, "CInt64T") is not None: return 1
@@ -1140,14 +1140,14 @@ novirtual class ExprGenName(ExprGenBase.ExprGenBase):
return mlirlite.build_gep_array(builder, pointee, elem_ty, alloca, idx_val)
case mlirlite.LLVMType.Ptr(inner_ty):
# inner_ty 是 Ptr 说明 alloca.Ty 是三重指针,
# 即 X|t.CPtr 当 X 本身是指针类型 (如 T=AST|t.CPtr, T|t.CPtr=AST**)。
# 即 X* 当 X 本身是指针类型 (如 T=AST*, T*=AST**)。
# 此时 [i]=val 应该是指针解引用赋值, 而非调用 __setitem__。
if self.is_ptr_type(inner_ty) != 0:
ptr_val_gsp: mlirlite.Value* = mlirlite.build_load(builder, pointee, alloca)
if ptr_val_gsp is not None:
return mlirlite.build_gep(builder, inner_ty, ptr_val_gsp, idx_val)
return None
# 自定义结构体 (如 HashTable|t.CPtr, JsonValue|t.CPtr):
# 自定义结构体 (如 HashTable*, JsonValue*):
# 仅当类定义了 __setitem__(当前模块定义或跨模块 stub declare 注入)
# 才返回 None 触发 __setitem__ 重载;否则普通结构体指针按下标
# 做 GEP 数组访问(走下方指针遍历路径)
@@ -1158,22 +1158,22 @@ novirtual class ExprGenName(ExprGenBase.ExprGenBase):
viperlib.snprintf(si_lookup_gsp, 128, "%s.__setitem__", cls_nm_ptr_chk)
if self.Gen.CallGenBase.find_func_in_module(mod, si_lookup_gsp) is not None:
return None
# bytes|t.CPtr / str|t.CPtr: alloca 是 i8**,
# bytes* / str*: alloca 是 i8**,
# 直接 GEP 按 i8* 步长(8 字节),不 load
# 仅当 inner_ty 不是自定义结构体时才走指针遍历
if trans is not None:
ve_pe: GenTypes.VarEntry* = \
self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm.id)
if self.Gen.VarGen.var_is_ptr_element(ve_pe) != 0:
# bytes|t.CPtr / str|t.CPtr / T|t.CPtr:变量存指针值,
# bytes* / str* / T*:变量存指针值,
# 下标语义 = [指针值 + i*8](8 字节指针元素)。必须先 load
# alloca 得指针值,再 GEP——否则 GEP base 用 alloca(&elem_ptr)
# 读到栈变量而非数据区,赋值写不进 list 数据
# (data 全 0xbaadf00d,dump 虚调用读错 vtable 崩溃)。
ptr_val_pe: mlirlite.Value* = mlirlite.build_load(builder, pointee, alloca)
if ptr_val_pe is not None:
# [FIX 2026-08-30] 64 位标量联合(int64|t.CPtr /
# uint64|t.CPtr / sizet|t.CPtr):8 字节单元格存
# [FIX 2026-08-30] 64 位标量联合(int64* /
# uint64* / sizet*):8 字节单元格存
# i64 标量(viperlib %n 的 np[0]=write_count 是解引用写入,
# 语义 *np=(i64)x)。GEP 元素必须用 Int64(标量)而非指针,
# 否则元素类型为指针 → i64 存储触发整数隐式转指针
@@ -1201,13 +1201,13 @@ novirtual class ExprGenName(ExprGenBase.ExprGenBase):
# alloca 是 Ptr(标量), 直接 GEP 获取第 idx 个元素指针
# 支持 arg_vals[i] = val 这类参数数组下标赋值
# 联合类型变量(IsPtrElement=1,如 _list.vp 的
# elem_ptr: T | t.CPtr 退化为 i8*):pointee=i8 但
# elem_ptr: T* 退化为 i8*):pointee=i8 但
# 元素是 8 字节指针,须按 i8* 步长 GEP(防只写 1 字节截断)
if trans is not None:
ve_pe_cs: GenTypes.VarEntry* = \
self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm.id)
if self.Gen.VarGen.var_is_ptr_element(ve_pe_cs) != 0:
# T|t.CPtr(退化为 i8*,如 _list.vp 的 elem_ptr)变量
# T*(退化为 i8*,如 _list.vp 的 elem_ptr)变量
# 存数据区指针,元素为 8 字节指针:必须先 load alloca
# 得指针值,再按 i8* 步长 GEP——否则 GEP base 用 alloca
# (&elem_ptr)算到栈地址,赋值写不进 list 数据区
+6 -6
View File
@@ -271,7 +271,7 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase):
return 0
if k == ast.ASTKind.Subscript:
# 数组/指针下标: md5_buf[i](t.CArray[uint8, N])或 buf[i]
# (形参 uint8 | t.CPtr)元素是无符号整型 → printf("%02x", ...) zext。
# (形参 uint8*)元素是无符号整型 → printf("%02x", ...) zext。
sub_su: ast.Subscript* = ast.Subscript*(node)
if sub_su.value is not None and sub_su.value.kind() == ast.ASTKind.Name:
snm_su: ast.Name* = ast.Name*(sub_su.value)
@@ -427,7 +427,7 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase):
真源按顶层 '|' 分段、去括号/空白、取 `IDENT[INNER]` 的元素、去模块限定前缀,
再走精确名白名单 + CTypedef 链展开 —— 已覆盖原 `_annot_str_unsigned_scan`
对复合注解(`t.CArray[uint8, 16]` / `uint8 | t.CPtr`)的全部能力,
对复合注解(`t.CArray[uint8, 16]` / `uint8*`)的全部能力,
且无子串假阳性。UNKNOWN = 不表态 ⇒ 返回 0。
"""
if annot is not None:
@@ -444,7 +444,7 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase):
if cmp is None:
return None
ops_list: list[int] | t.CPtr = (list[int] | t.CPtr)(cmp.ops)
ops_list: list[int]* = (list[int]*)(cmp.ops)
if ops_list is None or len(ops_list) == 0:
return None
op: int = ops_list.get(0)
@@ -907,7 +907,7 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase):
不能在这里再套 alloca+store:那会得到 Ptr(Ptr(Struct))(存放地址的槽
地址),赋值端还得 load 一次才回落,语义也从"对象地址"变成"槽地址"。
· 其它返回值(标量、按值返回的结构体值等):rvalue 的地址只能靠临时槽
承载——入口 alloca 同类型槽 → store → 返回槽地址(与 c.Addr(expr) 的
承载——入口 alloca 同类型槽 → store → 返回槽地址(与 &expr 的
Call 形式同口径,见 CallGenCBuiltin.translate_c_addr)。
"""
if call_val is None or call_val.Ty is None:
@@ -1549,7 +1549,7 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase):
lhs_alloca: mlirlite.Value* = self.Gen.VarGen.lookup_var(trans.SymTab, nm.id)
if lhs_alloca is not None:
ovl_self1: mlirlite.Value* = lhs_alloca
# alloca 是 Ptr(Ptr(Struct))(X|t.CPtr 对象存储槽)时,
# alloca 是 Ptr(Ptr(Struct))(X* 对象存储槽)时,
# load 出对象指针作为 self——若把槽地址当 self,dunder 内
# load 槽内容(对象指针值)当字段读 → 垃圾(MultiInheritTest
# Vec2Both __add__ 输出 (1.0,2.0) 根因;get_struct_type_from_value
@@ -1567,7 +1567,7 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase):
if lhs is None:
return None
# === 运算符重载路径 2: lhs 是 Ptr(Struct)(如 Counter|t.CPtr 变量 load 后)===
# === 运算符重载路径 2: lhs 是 Ptr(Struct)(如 Counter* 变量 load 后)===
ovl_result2: mlirlite.Value* = self.try_operator_overload(pool, builder, mod, lhs, rhs, op, trans, 0)
if ovl_result2 is not None:
return ovl_result2
+16 -16
View File
@@ -183,7 +183,7 @@ novirtual class FuncGenDef(CallGenBase.CallGenBase):
continue
# 提取默认参数信息
# 注意: 必须先把属性赋给显式类型为 list[...] | t.CPtr 的局部变量再调用 __len__(),
# 注意: 必须先把属性赋给显式类型为 list[...]* 的局部变量再调用 __len__(),
# 否则编译器无法识别属性返回的 list 类型,GEP base 会变成 i32 0 导致 llc 报错
fd_args_node: ast.Arguments* = fd.args
fd_defaults: t.CPtr = None
@@ -987,21 +987,21 @@ novirtual class FuncGenDef(CallGenBase.CallGenBase):
_is_void = 1
if _is_void != 0:
mlirlite.build_ret_void(func_builder)
elif last_is_ctrl != 0 and trans._ctrl_merge_reachable == 0:
# 追加90:非 void 函数末句是控制流且 merge 块**结构性**不可达
# (全分支 return,无 br 到 merge)→ LLVM 语义 unreachable。
# merge 可达(分支 br 到 merge,如 testcheck.check 的 if/else 无 return)
# 时不是结构性不可达,需正常收尾(下方 ConstZero / fail-fast):可达块的
# unreachable 是 UB,llc 不生成任何指令 ⇒ 执行掉进布局紧随其后的块。
# ★ 可达性判据**只用 `_ctrl_merge_reachable`**(MatchGenMixin 逐臂真正
# `br end_bb` 时才置 1,并由"用本 match 自身的 br 记录覆盖"写回):
# 实测反面教材 —— includes/mlirlite/__types.vp::_TypePrintDepth 末句
# `match ty:` 带 `case _:`,各臂只 snprintf 后 br 到 merge;旧判据(追加92
# 的 MatchHasWildcardArm 子句)按"穷尽 ⇒ 流程不可能掉出末尾"推断,给这个
# 可达 merge 生成了 unreachable ⇒ 打印完 "i32" 后掉进同一 switch 的跳转表,
# 用上一条 snprintf 的返回值("i%d" → 3)当 tag 取 table[3] = Array 臂,
# 把 Int 的 Bits(32) 当指针递归解引用 ⇒ AV at 0x20。
# 穷尽性 ≠ 各臂都终止:只有"有没有 br 到 merge"才是可达性。
elif last_is_ctrl != 0 and trans._ctrl_merge_reachable == 0:
# 追加90:非 void 函数末句是控制流且 merge 块**结构性**不可达
# (全分支 return,无 br 到 merge)→ LLVM 语义 unreachable。
# merge 可达(分支 br 到 merge,如 testcheck.check 的 if/else 无 return)
# 时不是结构性不可达,需正常收尾(下方 ConstZero / fail-fast):可达块的
# unreachable 是 UB,llc 不生成任何指令 ⇒ 执行掉进布局紧随其后的块。
# ★ 可达性判据**只用 `_ctrl_merge_reachable`**(MatchGenMixin 逐臂真正
# `br end_bb` 时才置 1,并由"用本 match 自身的 br 记录覆盖"写回):
# 实测反面教材 —— includes/mlirlite/__types.vp::_TypePrintDepth 末句
# `match ty:` 带 `case _:`,各臂只 snprintf 后 br 到 merge;旧判据(追加92
# 的 MatchHasWildcardArm 子句)按"穷尽 ⇒ 流程不可能掉出末尾"推断,给这个
# 可达 merge 生成了 unreachable ⇒ 打印完 "i32" 后掉进同一 switch 的跳转表,
# 用上一条 snprintf 的返回值("i%d" → 3)当 tag 取 table[3] = Array 臂,
# 把 Int 的 Bits(32) 当指针递归解引用 ⇒ AV at 0x20。
# 穷尽性 ≠ 各臂都终止:只有"有没有 br 到 merge"才是可达性。
mlirlite.build_unreachable(func_builder)
elif fd.returns is None:
# 无返回类型注解 → 无返回值过程函数,默认零值返回
+9 -9
View File
@@ -93,7 +93,7 @@ novirtual class FuncGenMixin(CallGenBase.CallGenBase):
case _:
pty_n = resolved_n
if param_count < 64 and param_tys is not None:
pty_slot_n: str | t.CPtr = (str | t.CPtr)(uint64(param_tys) + param_count * 8)
pty_slot_n: str* = (str*)(uint64(param_tys) + param_count * 8)
pty_slot_n[0] = pty_n
pname_n: str = pool.alloc(32)
if pname_n is not None:
@@ -142,7 +142,7 @@ novirtual class FuncGenMixin(CallGenBase.CallGenBase):
pty2_n: mlirlite.LLVMType* = i32_ty
if param_tys is not None:
ty_addr_n: uint64 = uint64(param_tys) + idx_p * 8
ty_slot_n: str | t.CPtr = (str | t.CPtr)(ty_addr_n)
ty_slot_n: str* = (str*)(ty_addr_n)
pty2_n = (mlirlite.LLVMType*)(ty_slot_n[0])
if pty2_n is None:
pty2_n = i32_ty
@@ -306,7 +306,7 @@ novirtual class FuncGenMixin(CallGenBase.CallGenBase):
for ni in range(nested_nonlocal_count):
# 从 _nonlocal_names 缓冲区读取名称
name_addr: uint64 = uint64(trans._nonlocal_names) + ni * 8
nl_slot: str | t.CPtr = (str | t.CPtr)(name_addr)
nl_slot: str* = (str*)(name_addr)
nl_name: str = nl_slot[0]
if nl_name is None:
continue
@@ -1180,7 +1180,7 @@ novirtual class FuncGenMixin(CallGenBase.CallGenBase):
cap_slot: str = cap_names + ci * 64
if cap_slot[0] == '\0': continue
ty_addr3: uint64 = uint64(cap_tys) + ci * 8
ty_slot3: str | t.CPtr = (str | t.CPtr)(ty_addr3)
ty_slot3: str* = (str*)(ty_addr3)
cap_ty: mlirlite.LLVMType* = (mlirlite.LLVMType*)(ty_slot3[0])
if cap_ty is None: continue
off_val: mlirlite.Value* = mlirlite.const_int32(pool, ci * 8)
@@ -1200,7 +1200,7 @@ novirtual class FuncGenMixin(CallGenBase.CallGenBase):
# 10. 参数 alloca
for pi3 in range(param_count):
ty_addr4: uint64 = uint64(param_tys) + pi3 * 8
ty_slot4: str | t.CPtr = (str | t.CPtr)(ty_addr4)
ty_slot4: str* = (str*)(ty_addr4)
p_ty3: mlirlite.LLVMType* = (mlirlite.LLVMType*)(ty_slot4[0])
if p_ty3 is None:
# fail-fast:lambda 参数类型槽缺失(内部状态不一致),不再静默保持 i32
@@ -1260,11 +1260,11 @@ novirtual class FuncGenMixin(CallGenBase.CallGenBase):
if cap_slot3[0] == '\0':
continue
al_addr: uint64 = uint64(cap_allocas) + ci3 * 8
al_slot: str | t.CPtr = (str | t.CPtr)(al_addr)
al_slot: str* = (str*)(al_addr)
var_alloca2: mlirlite.Value* = (mlirlite.Value*)(al_slot[0])
if var_alloca2 is None: continue
ty_addr5: uint64 = uint64(cap_tys) + ci3 * 8
ty_slot5: str | t.CPtr = (str | t.CPtr)(ty_addr5)
ty_slot5: str* = (str*)(ty_addr5)
cap_ty2: mlirlite.LLVMType* = (mlirlite.LLVMType*)(ty_slot5[0])
if cap_ty2 is None: continue
# 堆存储大小:位宽/8,至少 8 字节(容纳指针/标量)
@@ -1374,9 +1374,9 @@ novirtual class FuncGenMixin(CallGenBase.CallGenBase):
if cap_count >= 64:
return cap_count
string.strncpy(cap_names + cap_count * 64, nm.id, 63)
al_slot: str | t.CPtr = (str | t.CPtr)(uint64(cap_allocas) + cap_count * 8)
al_slot: str* = (str*)(uint64(cap_allocas) + cap_count * 8)
al_slot[0] = alloca
ty_slot: str | t.CPtr = (str | t.CPtr)(uint64(cap_tys) + cap_count * 8)
ty_slot: str* = (str*)(uint64(cap_tys) + cap_count * 8)
ty_slot[0] = pointee
return cap_count + 1
# 递归遍历常见表达式子节点
+61 -61
View File
@@ -18,33 +18,33 @@ import lib.core.Gen.Type.TypeSpec as TSpec
# ============================================================
# 类编译期元数据(原 HandlesType.CLASS_META_*)
# ============================================================
CLASS_META_PROVIDES: t.CDefine = 1
CLASS_META_REQUIRES: t.CDefine = 2
CLASS_META_REQUIRE_MUST: t.CDefine = 3
define CLASS_META_PROVIDES = 1
define CLASS_META_REQUIRES = 2
define CLASS_META_REQUIRE_MUST = 3
# ============================================================
# 属性/静态/类方法元数据(原 HandlesClassDef.META_*)
# ============================================================
META_STATIC: t.CDefine = 1
META_CLASS: t.CDefine = 2
META_PROP_GETTER: t.CDefine = 4
META_PROP_SETTER: t.CDefine = 8
META_PROP_DELETER: t.CDefine = 16
define META_STATIC = 1
define META_CLASS = 2
define META_PROP_GETTER = 4
define META_PROP_SETTER = 8
define META_PROP_DELETER = 16
# ============================================================
# 结构体容量(原 HandlesStruct.FIELD_MAX/FIELD_NAME_MAX/PARENT_MAX/MRO_MAX)
# ============================================================
FIELD_MAX: t.CDefine = 256
FIELD_NAME_MAX: t.CDefine = 64
PARENT_MAX: t.CDefine = 64
MRO_MAX: t.CDefine = 64
define FIELD_MAX = 256
define FIELD_NAME_MAX = 64
define PARENT_MAX = 64
define MRO_MAX = 64
# ============================================================
# for 迭代序列种类(原 HandlesFor.SEQ_KIND_*)
# ============================================================
SEQ_KIND_RANGE: t.CDefine = 1
SEQ_KIND_STR: t.CDefine = 2
SEQ_KIND_LIST: t.CDefine = 3
define SEQ_KIND_RANGE = 1
define SEQ_KIND_STR = 2
define SEQ_KIND_LIST = 3
# ============================================================
# TraceFrame - 仿 Python Traceback 调用栈帧(原 HandlesType.TraceFrame)
@@ -84,7 +84,7 @@ class VarEntry:
# 1=该变量是 **const 对象**(注解含 t.CConst 且声明类型**不是指针**):
# 整个作用域内禁止对该变量名赋值 / 增量赋值 / 元素赋值(fail-fast)。
# 与 TPC 的 Gen.var_const_flags / global_const_flags 同判据、同报文,见
# Debugger/type-descriptors.md。指针类型(如 `p: t.CConst | T | t.CPtr`)的
# Debugger/type-descriptors.md。指针类型(如 `p: t.CConst | T*`)的
# CConst 只约束 pointee,不使指针变量自身不可写,故不置 1。
# 追加在末尾:既有字段偏移不变,__sizeof__() 自动纳入,条目数组步长同步。
IsConst: int
@@ -95,8 +95,8 @@ class VarEntry:
# ============================================================
novirtual class Scope:
"""作用域节点"""
Parent: Scope | t.CPtr
Vars: VarEntry | t.CPtr
Parent: Scope*
Vars: VarEntry*
VarCount: int
Kind: int
@@ -107,8 +107,8 @@ novirtual class Scope:
novirtual class SymbolTable:
"""嵌套作用域符号表"""
Pool: memhub.MemBuddy*
Root: Scope | t.CPtr
Current: Scope | t.CPtr
Root: Scope*
Current: Scope*
# ============================================================
@@ -147,7 +147,7 @@ novirtual class StructEntry:
Name: str # 类名
Ty: mlirlite.LLVMType* # LLVM StructType
FieldCount: int # 字段数量
Fields: FieldEntry | t.CPtr # 字段数组(FIELD_MAX 个槽位)
Fields: FieldEntry* # 字段数组(FIELD_MAX 个槽位)
IsUnion: int # 1=联合体 / 0=普通结构体
IsPacked: int # 1=@c.Attribute(t.attr.packed) 打包结构体(无字段填充)
Align: int # @c.Attribute(t.attr.aligned(N)) 对齐字节数(0=默认,如 fpu_context=16)
@@ -166,7 +166,7 @@ novirtual class StructEntry:
SpecTriggerSha1: str # 泛型特化类的触发文件 SHA1(None=非特化类)。特化类 ModuleSha1=模板
# sha1(方法名带模板前缀),作废重译时 reset_module_methods_emitted
# 按触发文件 sha1 精确重置 MethodsEmitted,防特化方法体残留 1 不补译
# → 链接 undefined symbol(list[ast.ClassDef|t.CPtr].* 根因)
# → 链接 undefined symbol(list[ast.ClassDef*].* 根因)
IsForwardDecl: int # 1=前向声明占位条目(Ty=不透明具名结构体 {sha}.Class,FieldCount=0;
# 定义侧随后**原位填充**同一 Ty 对象并清零本标记)。
# 语义对齐 TPC:未注册类 → 具名空 CStruct 占位 + 后续 set_body 填充。
@@ -188,7 +188,7 @@ novirtual class EnumEntry:
Name: str # 枚举类名
BaseTy: mlirlite.LLVMType* # 基准类型(所有成员类型中最大的)
MemberCount: int # 成员数量
Members: EnumMember | t.CPtr # 成员数组(ENUM_MEMBER_MAX 个槽位)
Members: EnumMember* # 成员数组(ENUM_MEMBER_MAX 个槽位)
# ============================================================
@@ -208,7 +208,7 @@ novirtual class FuncEntry:
"""函数表条目"""
Name: str
Func: mlirlite.Function*
Defaults: t.CPtr # defaults 列表节点指针 (list[AST | CPtr]),None=无默认值
Defaults: t.CPtr # defaults 列表节点指针 (list[AST*]),None=无默认值
DefaultCount: int # 默认值数量
ParamCount: int # 形参数量(不含 self)
# TypeSpec(S3 条目双写):Kind=TS_FUNC 的**整签名**(Ret/Params/ParamCount/IsVarArg
@@ -225,14 +225,14 @@ novirtual class FuncDefaultsEntry:
"""默认参数表条目"""
Name: str
ModuleSha1: str # 定义该函数的模块 SHA1(限定名去重,避免跨模块同名串味)
Defaults: t.CPtr # defaults 列表节点指针 (list[AST | CPtr])(pool 内,可能被 reset)
Defaults: t.CPtr # defaults 列表节点指针 (list[AST*])(pool 内,可能被 reset)
DefaultCount: int
ParamCount: int # 形参数量(不含 self)
# 常量快照(stdlib 分配,跨文件永久存活):
# 注册时提取每个默认值 Constant 的值,跨模块调用时优先用快照重建常量 IR,
# 避免读取已被 1b reset_to(mark1) 回收的 pool 内 AST。
ConstKinds: int | t.CPtr # const_kind 数组(DefaultCount 个 i32)
ConstInts: int64 | t.CPtr # int_val 数组(DefaultCount 个 i64)
ConstKinds: int* # const_kind 数组(DefaultCount 个 i32)
ConstInts: int64* # int_val 数组(DefaultCount 个 i64)
ConstStrs: sizet* # str_val 指针数组(DefaultCount 个 i8*)
@@ -279,24 +279,24 @@ novirtual class FuncDefaultsEntry:
# GetProcAddress(裸名) 取得地址并写入槽;后续片段的调用点从槽 load 地址后
# 间接调用 ⇒ 函数代码只有一份(在定义片段里),调用点不复制代码。
# ============================================================
REPL_CTX_MARKER: t.CDefine = 1397571916 # 宿主侧对象标记(自比对;非 ctx 头字段)
REPL_CTX_MAGIC: t.CDefine = 0x5245504C # 'REPL'(ctx 头 +0,小端字节序为 R E P L)
REPL_CTX_VERSION: t.CDefine = 2 # ctx 头 +4(1 → 2:尾部追加函数指针槽区)
REPL_SLOT_SIZE: t.CDefine = 16 # 每个会话变量占用字节数(步长)
REPL_SLOT_BASE: t.CDefine = 64 # 槽区起点 = 固定头字节数(= +40..63 保留之后)
REPL_CTX_PARAM: t.CDefine = "__repl_ctx__" # 包裹模板里 ctx 形参名(与 Repl.vp 同源)
REPL_VAR_CAP: t.CDefine = 64 # 会话变量上限(变量区 = 64 + 64*16 = 1088 字节)
define REPL_CTX_MARKER = 1397571916 # 宿主侧对象标记(自比对;非 ctx 头字段)
define REPL_CTX_MAGIC = 0x5245504C # 'REPL'(ctx 头 +0,小端字节序为 R E P L)
define REPL_CTX_VERSION = 2 # ctx 头 +4(1 → 2:尾部追加函数指针槽区)
define REPL_SLOT_SIZE = 16 # 每个会话变量占用字节数(步长)
define REPL_SLOT_BASE = 64 # 槽区起点 = 固定头字节数(= +40..63 保留之后)
define REPL_CTX_PARAM = "__repl_ctx__" # 包裹模板里 ctx 形参名(与 Repl.vp 同源)
define REPL_VAR_CAP = 64 # 会话变量上限(变量区 = 64 + 64*16 = 1088 字节)
# 会话函数指针槽区(M3):起点紧跟变量区,步长与变量槽一致(16B,低 8 字节存地址)
REPL_FUNC_BASE: t.CDefine = 1088 # = REPL_SLOT_BASE + REPL_VAR_CAP*REPL_SLOT_SIZE
REPL_FUNC_SLOT_SIZE: t.CDefine = 16 # 每个会话函数占用字节数(步长)
REPL_FUNC_CAP: t.CDefine = 32 # 会话函数上限(函数区 = 32*16 = 512 字节)
define REPL_FUNC_BASE = 1088 # = REPL_SLOT_BASE + REPL_VAR_CAP*REPL_SLOT_SIZE
define REPL_FUNC_SLOT_SIZE = 16 # 每个会话函数占用字节数(步长)
define REPL_FUNC_CAP = 32 # 会话函数上限(函数区 = 32*16 = 512 字节)
# ctx 总字节数 = 64 + 64*16 + 32*16 = 1600(宿主 Repl._REPL_CTX_SIZE 必须一致)
REPL_CTX_SIZE: t.CDefine = 1600
define REPL_CTX_SIZE = 1600
# 会话函数的形参上限(签名 token 数组定长;超出 ⇒ 注册期明确报错)
REPL_FUNC_PARAM_MAX: t.CDefine = 8
define REPL_FUNC_PARAM_MAX = 8
# 片段入口函数名前缀(Repl.vp 生成 "__repl_frag_%d";用于区分"片段入口函数"与
# 被提升的会话函数本体——前者是会话变量写入的作用域,后者只读会话槽)
REPL_ENTRY_PREFIX: t.CDefine = "__repl_frag_"
define REPL_ENTRY_PREFIX = "__repl_frag_"
# 会话模块 SHA1(M4):片段翻译器的 ModuleSha1 取此**稳定**值 ⇒ 片段内定义的类型
# 名形如 "<16位hex>.<Type>",且**跨片段逐字一致**——这是"先前片段定义的类在后续
# 片段可见/可用"的基础(类型名是跨片段查找的唯一键)。
@@ -310,35 +310,35 @@ REPL_ENTRY_PREFIX: t.CDefine = "__repl_frag_"
# 与裸名约定的关系:`export def`(含片段入口与会话函数)走 has_export 分支取裸名
# (FuncGenDef.vp:482-485),**不受**该值影响;受影响的只有类/方法/模块级全局
# 等经 _mangle_name/_mangle_name_with_sha1 命名的符号。
REPL_SESSION_SHA1: t.CDefine = "71f67b7cb405f0e4"
define REPL_SESSION_SHA1 = "71f67b7cb405f0e4"
# ctx 头字段偏移(与 ReplResult 字段顺序/宽度一一对应)
REPL_RES_KIND_OFF: t.CDefine = 8 # i32
REPL_RES_A_OFF: t.CDefine = 16 # u64
REPL_RES_B_OFF: t.CDefine = 24 # u64
REPL_RES_VARCOUNT_OFF: t.CDefine = 32 # i32
REPL_RES_LASTFRAG_OFF: t.CDefine = 36 # i32
define REPL_RES_KIND_OFF = 8 # i32
define REPL_RES_A_OFF = 16 # u64
define REPL_RES_B_OFF = 24 # u64
define REPL_RES_VARCOUNT_OFF = 32 # i32
define REPL_RES_LASTFRAG_OFF = 36 # i32
# 结果 Kind(宿主按此回显)
REPL_RES_NONE: t.CDefine = 0 # 本片段无结果(如仅声明)
REPL_RES_INT: t.CDefine = 1 # 整数(读 result_a 位模式)
REPL_RES_FLOAT: t.CDefine = 2 # float64(读 result_a 的 double 位模式)
REPL_RES_STR: t.CDefine = 3 # str/bytes(读 result_a 指针 + result_b 长度)
REPL_RES_OBJ: t.CDefine = 4 # 结构体/其它指针(读 result_a 地址)
define REPL_RES_NONE = 0 # 本片段无结果(如仅声明)
define REPL_RES_INT = 1 # 整数(读 result_a 位模式)
define REPL_RES_FLOAT = 2 # float64(读 result_a 的 double 位模式)
define REPL_RES_STR = 3 # str/bytes(读 result_a 指针 + result_b 长度)
define REPL_RES_OBJ = 4 # 结构体/其它指针(读 result_a 地址)
# 会话变量类型标签(ReplVarEntry.TyTag)
REPL_TY_INT: t.CDefine = 1
REPL_TY_FLOAT: t.CDefine = 2
REPL_TY_STR: t.CDefine = 3 # i8*(str/bytes)
REPL_TY_PTR: t.CDefine = 4 # 其他指针(Bits=pointee 位宽 / TyName=结构体名)
REPL_TY_STRUCT: t.CDefine = 5 # 结构体值(按声明类型内联在槽里;≤ 槽容量)
define REPL_TY_INT = 1
define REPL_TY_FLOAT = 2
define REPL_TY_STR = 3 # i8*(str/bytes)
define REPL_TY_PTR = 4 # 其他指针(Bits=pointee 位宽 / TyName=结构体名)
define REPL_TY_STRUCT = 5 # 结构体值(按声明类型内联在槽里;≤ 槽容量)
# 会话变量存放形态(ReplVarEntry.Kind)
REPL_KIND_UNTYPED: t.CDefine = 0 # 已登记槽位但尚未定型(未赋值/无注解)
REPL_KIND_SCALAR: t.CDefine = 1 # 值内联存槽(标量/指针/≤16B 结构体值)
define REPL_KIND_UNTYPED = 0 # 已登记槽位但尚未定型(未赋值/无注解)
define REPL_KIND_SCALAR = 1 # 值内联存槽(标量/指针/≤16B 结构体值)
# 会话函数签名的返回类型 token(M3;只用于 ReplFuncEntry.RetTag)
REPL_TY_VOID: t.CDefine = 0 # 无返回值(void;不作为形参 token)
define REPL_TY_VOID = 0 # 无返回值(void;不作为形参 token)
# ============================================================
@@ -428,7 +428,7 @@ novirtual class ReplResult:
Version: int # REPL_CTX_VERSION
Kind: int # REPL_RES_*
Reserved0: int # 保留(0)
A: t.CInt64T # result_a
B: t.CInt64T # result_b
A: int64 # result_a
B: int64 # result_b
VarCount: int # 已分配槽数(宿主写,供检视)
LastFrag: int # 最近执行的片段号(宿主写,供检视)
+7 -7
View File
@@ -28,7 +28,7 @@ import lib.core.VLogger as VLogger
# ============================================================
# 常量(与 HandlesImports 保持一致)
# ============================================================
MAX_REEXPORT: t.CDefine = 512
define MAX_REEXPORT = 512
# ============================================================
@@ -977,12 +977,12 @@ novirtual class ImportsGenMixin:
fi_target = jb_t
trans._from_imports = self.add_from_import(trans.Pool, trans._from_imports,
local_name, fi_target, orig_name)
# static 符号(禁止跨模块使用):from mod import name 命中源
# 模块登记的 static 符号 → fail-fast。逻辑收敛在
# _CheckStaticFromImport 内(不内联——内联新增分支会干扰本函数
# 的类型推断,与 ExprGenAttr/CallGenMixin 同款处理)。
self._CheckStaticFromImport(trans, fi_target, alias.name, node)
# 命名空间隔离:from-import 的名称标记为可见结构体
# static 符号(禁止跨模块使用):from mod import name 命中源
# 模块登记的 static 符号 → fail-fast。逻辑收敛在
# _CheckStaticFromImport 内(不内联——内联新增分支会干扰本函数
# 的类型推断,与 ExprGenAttr/CallGenMixin 同款处理)。
self._CheckStaticFromImport(trans, fi_target, alias.name, node)
# 命名空间隔离:from-import 的名称标记为可见结构体
self.Gen.StructGen.add_visible_struct(trans.Pool, local_name)
# 注册 re-export 映射:当前模块 re-export 了 local_name,
# 源模块为 fi_target(from . import Y 时是子模块名 vpsdk.Y,
+8 -8
View File
@@ -480,8 +480,8 @@ novirtual class MatchGenMixin:
# BB 指针数组、case 值指针数组、default 标记数组、nobreak 标记数组
bb_arr: sizet* = pool.alloc(8 * MAX_MATCH_CASES)
cv_arr: sizet* = pool.alloc(8 * MAX_MATCH_CASES)
def_arr: int | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES)
nb_arr: int | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES)
def_arr: int* = pool.alloc(4 * MAX_MATCH_CASES)
nb_arr: int* = pool.alloc(4 * MAX_MATCH_CASES)
# pass1 缓存的 mc 指针数组(pass2 复用,避免重索引)
mc_arr: sizet* = pool.alloc(8 * MAX_MATCH_CASES)
if bb_arr is None or cv_arr is None or def_arr is None or nb_arr is None \
@@ -1020,8 +1020,8 @@ novirtual class MatchGenMixin:
case_count: sizet = len(cases_list)
check_arr: sizet* = pool.alloc(8 * MAX_MATCH_CASES)
body_arr: sizet* = pool.alloc(8 * MAX_MATCH_CASES)
def_arr: int | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES)
nb_arr: int | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES)
def_arr: int* = pool.alloc(4 * MAX_MATCH_CASES)
nb_arr: int* = pool.alloc(4 * MAX_MATCH_CASES)
guard_arr: sizet* = pool.alloc(8 * MAX_MATCH_CASES)
if check_arr is None or body_arr is None or def_arr is None \
or nb_arr is None or guard_arr is None:
@@ -1350,8 +1350,8 @@ novirtual class MatchGenMixin:
bb_arr: sizet* = pool.alloc(8 * MAX_MATCH_CASES)
cv_arr: sizet* = pool.alloc(8 * MAX_MATCH_CASES)
def_arr: int | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES)
nb_arr: int | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES)
def_arr: int* = pool.alloc(4 * MAX_MATCH_CASES)
nb_arr: int* = pool.alloc(4 * MAX_MATCH_CASES)
# 每个已收集臂的 MatchOr 节点指针(0 = 非 MatchOr):`case 1 | 2:` 需为
# 每个备选各产出一个 switch case 值(同一 body BB),故此处记录节点,
# 建 sw 链时逐备选展开。非 MatchOr 恒为 0,走原单 cv 路径逐字不变。
@@ -1648,8 +1648,8 @@ novirtual class MatchGenMixin:
case_count: sizet = len(cases_list)
check_arr: sizet* = pool.alloc(8 * MAX_MATCH_CASES)
body_arr: sizet* = pool.alloc(8 * MAX_MATCH_CASES)
def_arr: int | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES)
nb_arr: int | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES)
def_arr: int* = pool.alloc(4 * MAX_MATCH_CASES)
nb_arr: int* = pool.alloc(4 * MAX_MATCH_CASES)
mc_arr: sizet* = pool.alloc(8 * MAX_MATCH_CASES)
cv_arr: sizet* = pool.alloc(8 * MAX_MATCH_CASES)
# 每个已收集臂的 MatchOr 节点指针(0 = 非 MatchOr):check 链需把
+4 -4
View File
@@ -258,7 +258,7 @@ novirtual class StmtGenCifMixin:
lv: int = self._cif_eval_node(pool, trans, cmp.left)
if self.CifEvalOk == 0:
return 0
ops_list: list[int] | t.CPtr = (list[int] | t.CPtr)(cmp.ops)
ops_list: list[int]* = (list[int]*)(cmp.ops)
comps: list[ast.AST*]* = cmp.comparators
if ops_list is None or comps is None:
self.CifEvalOk = 0
@@ -630,7 +630,7 @@ novirtual class StmtGenCifMixin:
ret_is_ptr: int = self.Gen.ExprGenBase.is_ptr_type(ret_ty_rt)
# ptr 类型不一致性:val 是整数但 ret 是 ptr(或反之),必须转换
if val_is_ptr != ret_is_ptr:
# [FIX 2026-08-30] __new__ 返回类型是类指针(T | t.CPtr 语义):
# [FIX 2026-08-30] __new__ 返回类型是类指针(T* 语义):
# 返回的实例存储指针来自跨模块调用(如 pool.alloc),Phase A
# 依赖未就绪时其返回类型退化为默认 i32。此时 int→ptr 是退化
# 指针重建而非隐式转换错误——允许 inttoptr,文件保持 pending
@@ -2203,7 +2203,7 @@ novirtual class StmtGenCifMixin:
# 对象有效性校验(vptr 非 0,硬约定与证据见 AssignGenMixin.vp:1174-1183):
# @t.CVTable 类对象首字即 vptr,为 0 时下游任意虚调用(kind()/dump())都会
# `load [0+slot]` ⇒ ASan READ at 0x0。读首字的唯一可用写法是 c.Deref((uint64*)(p))。
if c.Deref((uint64*)(first_el)) == 0:
if *((uint64*)(first_el)) == 0:
self.Gen.TypeGenErr.fatal_error(for_node,
f"列表字面量迭代遇到【对象无效】的 AST 元素(vptr 为 0):第 0 个元素指针非 0"
f"(地址 {uint64(first_el)})但其对象首字(vtable 指针)为 0,元素计数 {elts_count};"
@@ -2235,7 +2235,7 @@ novirtual class StmtGenCifMixin:
f"但元素计数为 {elts_count}(元素与计数不一致);上层某处产生了空 AST 元素,已终止编译。",
"ValueError")
# 对象有效性校验(vptr 非 0),同第 0 元素处:同族"取元素后即用"路径。
if c.Deref((uint64*)(el_node)) == 0:
if *((uint64*)(el_node)) == 0:
self.Gen.TypeGenErr.fatal_error(for_node,
f"列表字面量迭代遇到【对象无效】的 AST 元素(vptr 为 0):第 {i} 个元素指针非 0"
f"(地址 {uint64(el_node)})但其对象首字(vtable 指针)为 0,元素计数 {elts_count};"
+3 -3
View File
@@ -251,9 +251,9 @@ novirtual class StmtGenMixin(StmtGenDeclMixin.StmtGenDeclMixin):
# 注意:list[ptr](pool, N) 第二参数是 elem_size 不是容量!
# 指针元素必须显式传 8(T.__sizeof__ 对联合类型不可靠),
# 否则 append 按 N 字节步长错位存取 → 读出垃圾指针(崩溃)。
except_bbs: list[rawptr[mlirlite.BasicBlock]] | t.CPtr = \
except_bbs: list[rawptr[mlirlite.BasicBlock]]* = \
list[rawptr[mlirlite.BasicBlock]](pool, 8)
match_bbs: list[rawptr[mlirlite.BasicBlock]] | t.CPtr = \
match_bbs: list[rawptr[mlirlite.BasicBlock]]* = \
list[rawptr[mlirlite.BasicBlock]](pool, 8)
if except_bbs is None or match_bbs is None:
return 0
@@ -319,7 +319,7 @@ novirtual class StmtGenMixin(StmtGenDeclMixin.StmtGenDeclMixin):
# 匹配编码缓冲:必须是 int*(i32 步长)——collect_descendant_codes 按
# out_codes[i](4 字节)写入;用 sizet*(8 字节)读会读出 64 位拼接垃圾
# (多码时 code[i+1]<<32|code[i];单码时高位恰为 0 掩盖)。
codes_buf_t: int | t.CPtr = pool.alloc(64 * 4)
codes_buf_t: int* = pool.alloc(64 * 4)
if codes_buf_t is None:
return 0
n_codes_t: int = 0
+23 -23
View File
@@ -27,22 +27,22 @@ import lib.core.Gen.GenApi as GenApi
# ============================================================
# 常量(与 HandlesStruct 保持一致)
# ============================================================
STRUCT_MAX: t.CDefine = 512
define STRUCT_MAX = 512
# 名 | 类型 下标索引槽数(2 的幂且 > 2*STRUCT_MAX ⇒ 负载 < 0.5,探测必然终止)
STRUCT_IDX_CAP: t.CDefine = 1024
define STRUCT_IDX_CAP = 1024
# 字段槽位上限制(与 HandlesStruct 保持一致):Generator 43 Mixin 展平后约 120 字段,
# 上限取 64 会导致第 9+ 父类字段丢失 → __init__ 写属性失败。
FIELD_MAX: t.CDefine = 256
FIELD_NAME_MAX: t.CDefine = 64
define FIELD_MAX = 256
define FIELD_NAME_MAX = 64
# 多继承(MRO)支持:单类最大父类数 / MRO 链最大长度(Generator 43 父类;
# PARENT_MAX=16 时第 17+ 父类字段丢失 → __init__ 写 self.DiagStmtCount 失败)
PARENT_MAX: t.CDefine = 64
MRO_MAX: t.CDefine = 64
define PARENT_MAX = 64
define MRO_MAX = 64
# 索引哈希常量(32 位 FNV-1a,常量均 < 2^63 以避开大十进制字面量解析风险)
FNV32_OFFSET: t.CDefine = 2166136261
FNV32_PRIME: t.CDefine = 16777619
FNV32_MASK: t.CDefine = 4294967295
define FNV32_OFFSET = 2166136261
define FNV32_PRIME = 16777619
define FNV32_MASK = 4294967295
# ============================================================
@@ -351,9 +351,9 @@ novirtual class StructGenMixin:
声明被静默丢弃**,调用点改按依赖的签名 coerce。
现场:includes/socket.vp 的
`extern def connect(fd: u64, addr: SocketAddr | t.CPtr, addrlen: INT)`
被 w32.winsock2 的 `connect(..., WSASocketAddr | t.CPtr, ...)` 顶掉 →
socket.vp:236 `connect(self.fd, c.Addr(addr), 16)` 报
`extern def connect(fd: u64, addr: SocketAddr*, addrlen: INT)`
被 w32.winsock2 的 `connect(..., WSASocketAddr*, ...)` 顶掉 →
socket.vp:236 `connect(self.fd, &addr, 16)` 报
「指针隐式转指针已禁止:%"…SocketAddr"* → %"…WSASocketAddr"*」。
注入侧据本表跳过"本文件已声明的裸名"(VpiReader._inject_function_declare),
@@ -889,7 +889,7 @@ novirtual class StructGenMixin:
# (!424 = 本函数 :587 行;!426 = :590 行;两者之间无任何指令)。
# 对照可用写法(List 分支,同文件 :10611-10615):`bitcast AST* → i64*` +
# `load i64` + `inttoptr i64 → i8*` + `bitcast List* → i8**` + `store i8*`。
vt_ptr_c: t.CPtr = t.CPtr(c.Deref((uint64*)(default_val)))
vt_ptr_c: t.CPtr = t.CPtr(*((uint64*)(default_val)))
c.DerefAs(dst_c, vt_ptr_c)
# 拷贝位置字段(报错定位用)
dst_c.lineno = src_c.lineno
@@ -920,15 +920,15 @@ novirtual class StructGenMixin:
if dst_l is None: return None
string.memset(dst_l, 0, ast.List.__sizeof__())
# 拷贝 vtable 指针(AST 是 @t.CVTable,kind() 虚调用依赖首字段 vptr)
vt_l: t.CPtr = t.CPtr(c.Deref((uint64*)(default_val)))
c.DerefAs(dst_l, vt_l)
vt_l: t.CPtr = t.CPtr(*((uint64*)(default_val)))
*dst_l = vt_l
# 拷贝位置字段与 ctx
dst_l.lineno = src_l.lineno
dst_l.col_offset = src_l.col_offset
dst_l.end_lineno = src_l.end_lineno
dst_l.end_col_offset = src_l.end_col_offset
dst_l.ctx = src_l.ctx
# 深拷贝 elts:stdlib 手动构造 list[AST | t.CPtr] 容器
# 深拷贝 elts:stdlib 手动构造 list[AST*] 容器
src_elts_l: list[ast.AST*]* = src_l.elts
if src_elts_l is not None:
cnt_l: sizet = len(src_elts_l)
@@ -984,7 +984,7 @@ novirtual class StructGenMixin:
# "结构体赋值"编译成 48 字节 load + 48 字节 store,而本
# 缓冲只申请 cnt_l*elem_sz_l ⇒ 每槽越界 40 字节,写穿本块
# canary 与右邻空闲块首字(三代 [FREEFRAME] 现场根因)。
# 按本仓既有合并规则(hashtable.vp:82-85):`X | t.CPtr`
# 按本仓既有合并规则(hashtable.vp:82-85):`X*`
# = Ptr(resolve(X)) ⇒ 取下标得到**指针元素** ⇒ 8 字节
# 指针 store,与申请宽度同源。
slot_l: ast.AST** = (ast.AST**)(uint64(data_l) + li_l * elem_sz_l)
@@ -1426,8 +1426,8 @@ novirtual class StructGenMixin:
def _last_dot_outside_brackets(self, s: str) -> str:
"""返回字符串中最后一个位于 [...] 括号外的 '.' 指针,无则 None
泛型特化类名含下标(如 'numpy.ndarray[t.CDouble]'、
'list[f467978339422f32.AST|t.CPtr]'),下标内部也含 '.'(t.CDouble
泛型特化类名含下标(如 'numpy.ndarray[double]'、
'list[f467978339422f32.AST*]'),下标内部也含 '.'(double
的模块限定 / sha1.AST)。strrchr 直接找最后一个 '.' 会落到下标内部,
把模块名截错('numpy.ndarray[t' → sha1 映射表无法解析,NumpyTest
lookup_field_by_class FAIL 根因)。从末尾扫描并跟踪括号深度,
@@ -1512,7 +1512,7 @@ novirtual class StructGenMixin:
# 模块段是 16 位 hex = SHA1 字面量("{16hex}.Class" 类键形态,
# 泛型类型实参 _norm_type_arg_name 规范化产物,如
# "29fdb5e25dc949f4.Param"——GSList[Param] 特化方法体内
# `cur: T | t.CPtr = self.Head` 经 resolve_generic_type_name
# `cur: T* = self.Head` 经 resolve_generic_type_name
# 替换 T 为实参串后 AnnotClassName 即该形态):模块段即模块
# SHA1,类已注册就证明该模块已编译,直接按 name+sha1 精确匹配,
# 不走 _resolve_module_sha1(store 键是模块名不是 sha1,查
@@ -1706,7 +1706,7 @@ novirtual class StructGenMixin:
def get_struct_type_from_value(self, val: mlirlite.Value*) -> mlirlite.LLVMType*:
"""从 Value 的类型推断结构体类型
递归解 Ptr:支持 X|t.CPtr 联合简化产生的 Ptr(Ptr(Struct)) 对象指针
递归解 Ptr:支持 X* 联合简化产生的 Ptr(Ptr(Struct)) 对象指针
(如运算符重载中间结果 a*2.0 的 Vec3**),否则 try_operator_overload
重载识别失败回退原生运算,对指针生成非法 sub 指令(llc: invalid
operand type for instruction)。
@@ -2158,8 +2158,8 @@ novirtual class StructGenMixin:
if string.strchr(sname, 46) is None:
return # 非跨模块引用,无需处理
# 提取类名(第一个 '.' 之后的部分)
# 必须用 strchr 而非 strrchr:泛型特化名如 "list[ast.AST|t.CPtr]"
# 内部含 '.'(ast.AST),strrchr 会错误地把类名解析为 "AST|t.CPtr]"
# 必须用 strchr 而非 strrchr:泛型特化名如 "list[ast.AST*]"
# 内部含 '.'(ast.AST),strrchr 会错误地把类名解析为 "AST*]"
dot_pos: str = string.strchr(sname, '.')
if dot_pos is None:
return
+251 -251
View File
@@ -135,11 +135,11 @@ novirtual class Translator:
_coro_uses_sleep: int # 函数体是否用 coro_sleep(预扫描置位)
_coro_extra_types: str # 额外槽类型表(i8 数组:1=i32 2=i64)
_coro_extra_count: int # 额外槽总数
_coro_await_slots: int | t.CPtr # __await_N 的帧相对槽 index(预扫描填)
_coro_for_slots: int | t.CPtr # range-For N 的 __f_idx 帧相对槽 index(预扫描填)
_coro_await_slots: int* # __await_N 的帧相对槽 index(预扫描填)
_coro_for_slots: int* # range-For N 的 __f_idx 帧相对槽 index(预扫描填)
# per-async wake 槽 index 表(coro_run/gather 轮询反查用)
_coro_wake_names: str # char* 数组(8B/项)
_coro_wake_idxs: int | t.CPtr # i32 数组(4B/项,-1=无 wake 槽)
_coro_wake_idxs: int* # i32 数组(4B/项,-1=无 wake 槽)
_coro_wake_count: int
# 导入模块跟踪
@@ -581,19 +581,19 @@ novirtual class Translator:
# "非基本类型指针不可隐式转换"报出。
# 登记只依赖 tree + 本文件模块 SHA1,与导入、类定义窗口、类定义顺序都无关,
# 故提到门之前,三种模式(1a=1 / 1a-pre=2 / 全量=0)共用。
GenApi.register_file_classes(pool, self.ModuleSha1, tree)
# 本文件顶层函数名预登记(同址、同目的):依赖 vpi 注入的**裸名**声明
# (extern/state/export 不带 SHA1 前缀)若与本文件自己的声明同名,会先占用
# 该名字,使本文件声明在 forward_declare_functions 被静默丢弃(调用点改按
# 依赖签名 coerce)。现场:includes/socket.vp 的 extern def connect 被
# w32.winsock2 的 connect 顶掉 → socket.vp:236 报
# 「指针隐式转指针已禁止:SocketAddr* → WSASocketAddr*」。
GenApi.register_file_funcs(pool, tree)
# viperbuild 宏语句擦除:把模块级 `import viperbuild` 配套的宏语句
# proj = vb.Project(...) / proj.<字段> = ... / proj.config(...) / proj.build(...)
# 从 tree.children 里摘掉(Pass 0 已在配置面消费;翻译期若留着重放会被当真实
# 调用 codegen ⇒ `vb.Project` 未定义类)。位置必须在下面 import 处理/变量预注册/
# translate_children 之前,使三者看到同一份已擦除的 children。
GenApi.register_file_classes(pool, self.ModuleSha1, tree)
# 本文件顶层函数名预登记(同址、同目的):依赖 vpi 注入的**裸名**声明
# (extern/state/export 不带 SHA1 前缀)若与本文件自己的声明同名,会先占用
# 该名字,使本文件声明在 forward_declare_functions 被静默丢弃(调用点改按
# 依赖签名 coerce)。现场:includes/socket.vp 的 extern def connect 被
# w32.winsock2 的 connect 顶掉 → socket.vp:236 报
# 「指针隐式转指针已禁止:SocketAddr* → WSASocketAddr*」。
GenApi.register_file_funcs(pool, tree)
# viperbuild 宏语句擦除:把模块级 `import viperbuild` 配套的宏语句
# proj = vb.Project(...) / proj.<字段> = ... / proj.config(...) / proj.build(...)
# 从 tree.children 里摘掉(Pass 0 已在配置面消费;翻译期若留着重放会被当真实
# 调用 codegen ⇒ `vb.Project` 未定义类)。位置必须在下面 import 处理/变量预注册/
# translate_children 之前,使三者看到同一份已擦除的 children。
self._erase_viperbuild_macros(pool, tree)
# 先处理导入语句,再创建前向声明,解决前向引用问题。
# 两道门分开:
@@ -636,242 +636,242 @@ novirtual class Translator:
# CTypedef 声明由 Phase1 1b 文本扫描注册(RegisterCTypedefFromSource)——
# AST 字符串字段 token 零拷贝指向 src_buf,跨阶段内容不稳定,此处 AST 扫描
# 读 attr 会 0xC0000005,故移除。
# 跨模块 .vpi 注入:加载依赖模块的 .vpi,把函数 declare 注入当前模块。
# 注入条件 = 全量翻译,或 **App 预注册**(_pre_allow_dep_inject):后者必须
# 与阶段 A 同上下文,否则预注册期解析出的类字段票名(包重导出类的
# 真定义前缀校正依赖包别名 entry)会与阶段 A 分裂。includes 预注册
# (Phase A-pre-inc)不置位该开关 ⇒ 仍不注入,避免依赖环自锁。
if self._imported_modules is not None:
# 错误上下文帧:当前模块触发依赖 stub 加载的 import 位置
GenApi.push_trace(GenApi.get_current_file(), cur_imp_lineno)
StubMergerBuild.LoadDepVpiIntoModule(pool, mod, self._imported_modules, self._from_imports, GenApi.get_temp_dir(), self)
GenApi.pop_trace()
# 文件级类名预登记已提前到本函数开头执行(覆盖三种 _declare_only 模式;
# 为什么必须早于模块级变量/前向声明,见那里的说明)。
# 模块级变量预注册 + 函数前向声明:仍**只在全量翻译**做(声明期跳过,
# 保持 Phase A-pre"只注册 struct/enum/union"的语义)。
if self._declare_only == 0:
# 预注册模块级变量(AnnAssign/Assign)到 SymTab
# 解决时序问题:class Logger 的 __init__ 引用 _mbuddy 时,
# _mbuddy 的 AnnAssign 在 AST 中位于 class Logger 之后,
# 按 AST 顺序翻译时 _mbuddy 尚未注册 → lookup_var 返回 None → rhs_val is None
# 预处理先于 translate_children 注册所有模块级变量,
# 后续 translate_children 遍历到同一 AnnAssign 时 handle_module_level_var
# 通过 lookup_module_var 检测已存在并跳过(HandlesMain.py:206-209)
if ch is not None:
for ci in range(cn_count):
child: ast.AST* = ch.get(ci)
if child is None:
continue
kd_mv: int = child.kind()
if kd_mv == ast.ASTKind.AnnAssign or kd_mv == ast.ASTKind.Assign:
GenApi.handle_module_level_var(self, child)
# 创建前向声明
# 跨模块 .vpi 注入:加载依赖模块的 .vpi,把函数 declare 注入当前模块。
# 注入条件 = 全量翻译,或 **App 预注册**(_pre_allow_dep_inject):后者必须
# 与阶段 A 同上下文,否则预注册期解析出的类字段票名(包重导出类的
# 真定义前缀校正依赖包别名 entry)会与阶段 A 分裂。includes 预注册
# (Phase A-pre-inc)不置位该开关 ⇒ 仍不注入,避免依赖环自锁。
if self._imported_modules is not None:
# 错误上下文帧:当前模块触发依赖 stub 加载的 import 位置
GenApi.push_trace(GenApi.get_current_file(), cur_imp_lineno)
StubMergerBuild.LoadDepVpiIntoModule(pool, mod, self._imported_modules, self._from_imports, GenApi.get_temp_dir(), self)
GenApi.pop_trace()
# 文件级类名预登记已提前到本函数开头执行(覆盖三种 _declare_only 模式;
# 为什么必须早于模块级变量/前向声明,见那里的说明)。
# 模块级变量预注册 + 函数前向声明:仍**只在全量翻译**做(声明期跳过,
# 保持 Phase A-pre"只注册 struct/enum/union"的语义)。
if self._declare_only == 0:
# 预注册模块级变量(AnnAssign/Assign)到 SymTab
# 解决时序问题:class Logger 的 __init__ 引用 _mbuddy 时,
# _mbuddy 的 AnnAssign 在 AST 中位于 class Logger 之后,
# 按 AST 顺序翻译时 _mbuddy 尚未注册 → lookup_var 返回 None → rhs_val is None
# 预处理先于 translate_children 注册所有模块级变量,
# 后续 translate_children 遍历到同一 AnnAssign 时 handle_module_level_var
# 通过 lookup_module_var 检测已存在并跳过(HandlesMain.py:206-209)
if ch is not None:
for ci in range(cn_count):
child: ast.AST* = ch.get(ci)
if child is None:
continue
kd_mv: int = child.kind()
if kd_mv == ast.ASTKind.AnnAssign or kd_mv == ast.ASTKind.Assign:
GenApi.handle_module_level_var(self, child)
# 创建前向声明
GenApi.forward_declare_functions(self, tree)
added: int = GenApi.translate_children(self, tree)
# ============================================================
# _erase_viperbuild_macros - 擦除模块级 viperbuild 宏语句
# ------------------------------------------------------------
# viperbuild 是**编译器内建宏库**(编译期配置面),其用法形如:
# import viperbuild as vb
# proj = vb.Project("Test", "1.0.0")
# proj.build(selfmachine=True)
# 这些是**宏语句**:Pass 0(lib.core.builtin.ViperBuild)已从依赖闭包把它们消费成
# Config 配置;翻译期若原样放行,`vb.Project`/`proj.build` 会被当真实调用
# codegen(未定义类/函数)⇒ 报错。故此处把整组语句从 tree.children 摘除。
# 只处理**模块级顶层语句**(配置不允许写在函数体里)。
# ============================================================
def _vb_in_proj_vars(self, name: str, proj_vars: list[str]*) -> int:
"""name 是否为已登记的 Project 宏变量;1=是"""
if name is None or proj_vars is None:
return 0
n: sizet = len(proj_vars)
i: sizet = 0
while i < n:
s: str = proj_vars.get(i)
if s is not None and string.strcmp(s, name) == 0:
return 1
i += 1
return 0
def _vb_is_project_ctor(self, value: ast.AST*, alias: str, ctor: str) -> int:
"""value 是否为 `vb.Project(...)` / `Project(...)`;1=是"""
if value is None or value.kind() != ast.ASTKind.Call:
return 0
cl: ast.Call* = ast.Call*(value)
if cl is None or cl.func is None:
return 0
fk: int = cl.func.kind()
if fk == ast.ASTKind.Attribute:
if alias is None:
return 0
at: ast.Attribute* = ast.Attribute*(cl.func)
if at is None or at.attr is None or at.value is None:
return 0
if at.value.kind() != ast.ASTKind.Name:
return 0
bn: ast.Name* = ast.Name*(at.value)
if bn is None or bn.id is None:
return 0
if string.strcmp(bn.id, alias) != 0:
return 0
if string.strcmp(at.attr, "Project") == 0:
return 1
return 0
if fk == ast.ASTKind.Name:
if ctor is None:
return 0
nm: ast.Name* = ast.Name*(cl.func)
if nm is None or nm.id is None:
return 0
if string.strcmp(nm.id, ctor) == 0:
return 1
return 0
def _vb_is_macro_assign(self, target: ast.AST*, value: ast.AST*,
alias: str, ctor: str,
proj_vars: list[str]*) -> int:
"""赋值是否为 viperbuild 宏语句(Project 绑定 / 字段赋值);1=是且已登记"""
if target is None or value is None:
return 0
tk: int = target.kind()
if tk == ast.ASTKind.Name:
nm: ast.Name* = ast.Name*(target)
if nm is None or nm.id is None:
return 0
if self._vb_is_project_ctor(value, alias, ctor) != 0:
proj_vars.append(nm.id)
return 1
return 0
if tk == ast.ASTKind.Attribute:
at: ast.Attribute* = ast.Attribute*(target)
if at is None or at.value is None:
return 0
if at.value.kind() != ast.ASTKind.Name:
return 0
bn: ast.Name* = ast.Name*(at.value)
if bn is None or bn.id is None:
return 0
if self._vb_in_proj_vars(bn.id, proj_vars) != 0:
return 1
return 0
def _vb_is_macro_call(self, value: ast.AST*, proj_vars: list[str]*) -> int:
"""表达式是否为 `proj.config(...)` / `proj.build(...)`;1=是"""
if value is None or value.kind() != ast.ASTKind.Call:
return 0
cl: ast.Call* = ast.Call*(value)
if cl is None or cl.func is None:
return 0
if cl.func.kind() != ast.ASTKind.Attribute:
return 0
at: ast.Attribute* = ast.Attribute*(cl.func)
if at is None or at.attr is None or at.value is None:
return 0
if at.value.kind() != ast.ASTKind.Name:
return 0
bn: ast.Name* = ast.Name*(at.value)
if bn is None or bn.id is None:
return 0
if self._vb_in_proj_vars(bn.id, proj_vars) == 0:
return 0
if string.strcmp(at.attr, "config") == 0:
return 1
if string.strcmp(at.attr, "build") == 0:
return 1
return 0
def _vb_is_macro_stmt(self, child: ast.AST*, alias: str, ctor: str,
proj_vars: list[str]*) -> int:
"""单条模块级语句是否为 viperbuild 宏语句;1=是(应擦除)"""
if child is None:
return 0
kd: int = child.kind()
if kd == ast.ASTKind.Assign:
a: ast.Assign* = ast.Assign*(child)
if a is None or a.targets is None or a.value is None:
return 0
if len(a.targets) != 1:
return 0
return self._vb_is_macro_assign(a.targets.get(0), a.value, alias, ctor, proj_vars)
if kd == ast.ASTKind.AnnAssign:
an: ast.AnnAssign* = ast.AnnAssign*(child)
if an is None or an.target is None or an.value is None:
return 0
return self._vb_is_macro_assign(an.target, an.value, alias, ctor, proj_vars)
if kd == ast.ASTKind.Expr:
ex: ast.Expr* = ast.Expr*(child)
if ex is None or ex.value is None:
return 0
return self._vb_is_macro_call(ex.value, proj_vars)
return 0
def _erase_viperbuild_macros(self, pool: memhub.MemBuddy*, tree: ast.AST*) -> int:
"""擦除模块级 viperbuild 宏语句(就地替换 tree.children);1=发生擦除"""
if tree is None or tree.children is None:
return 0
ch: list[ast.AST*]* = tree.children
cn: sizet = len(ch)
if cn == 0:
return 0
# ① 找 viperbuild 的本地名 / Project 构造名
alias: str = None
ctor: str = None
ci: sizet = 0
while ci < cn:
child: ast.AST* = ch.get(ci)
if child is not None:
kd: int = child.kind()
if kd == ast.ASTKind.Import:
names: list[ast.AST*]* = ast.Import*(child).names
if names is not None:
ni: sizet = 0
while ni < len(names):
al: ast.Alias* = ast.Alias*(names.get(ni))
if al is not None and al.name is not None:
if string.strcmp(al.name, "viperbuild") == 0:
if al.asname is not None:
alias = al.asname
else:
alias = "viperbuild"
ni += 1
elif kd == ast.ASTKind.ImportFrom:
ifr: ast.ImportFrom* = ast.ImportFrom*(child)
if ifr is not None and ifr.level == 0 and ifr.names is not None:
if ifr.module is not None and string.strcmp(ifr.module, "viperbuild") == 0:
ni: sizet = 0
while ni < len(ifr.names):
al: ast.Alias* = ast.Alias*(ifr.names.get(ni))
if al is not None and al.name is not None:
if string.strcmp(al.name, "Project") == 0:
if al.asname is not None:
ctor = al.asname
else:
ctor = "Project"
ni += 1
ci += 1
if alias is None and ctor is None:
return 0
# ② 过滤:先登记 Project 宏变量,再摘掉相关语句
proj_vars: list[str]* = list[str](pool, 8)
kept: list[ast.AST*]* = list[ast.AST*](pool, 8)
if proj_vars is None or kept is None:
return 0
erased: int = 0
ci = 0
while ci < cn:
child = ch.get(ci)
if child is not None:
if self._vb_is_macro_stmt(child, alias, ctor, proj_vars) != 0:
erased = 1
else:
kept.append(child)
ci += 1
if erased != 0:
tree.children = kept
return erased
# ============================================================
# _erase_viperbuild_macros - 擦除模块级 viperbuild 宏语句
# ------------------------------------------------------------
# viperbuild 是**编译器内建宏库**(编译期配置面),其用法形如:
# import viperbuild as vb
# proj = vb.Project("Test", "1.0.0")
# proj.build(selfmachine=True)
# 这些是**宏语句**:Pass 0(lib.core.builtin.ViperBuild)已从依赖闭包把它们消费成
# Config 配置;翻译期若原样放行,`vb.Project`/`proj.build` 会被当真实调用
# codegen(未定义类/函数)⇒ 报错。故此处把整组语句从 tree.children 摘除。
# 只处理**模块级顶层语句**(配置不允许写在函数体里)。
# ============================================================
def _vb_in_proj_vars(self, name: str, proj_vars: list[str]*) -> int:
"""name 是否为已登记的 Project 宏变量;1=是"""
if name is None or proj_vars is None:
return 0
n: sizet = len(proj_vars)
i: sizet = 0
while i < n:
s: str = proj_vars.get(i)
if s is not None and string.strcmp(s, name) == 0:
return 1
i += 1
return 0
def _vb_is_project_ctor(self, value: ast.AST*, alias: str, ctor: str) -> int:
"""value 是否为 `vb.Project(...)` / `Project(...)`;1=是"""
if value is None or value.kind() != ast.ASTKind.Call:
return 0
cl: ast.Call* = ast.Call*(value)
if cl is None or cl.func is None:
return 0
fk: int = cl.func.kind()
if fk == ast.ASTKind.Attribute:
if alias is None:
return 0
at: ast.Attribute* = ast.Attribute*(cl.func)
if at is None or at.attr is None or at.value is None:
return 0
if at.value.kind() != ast.ASTKind.Name:
return 0
bn: ast.Name* = ast.Name*(at.value)
if bn is None or bn.id is None:
return 0
if string.strcmp(bn.id, alias) != 0:
return 0
if string.strcmp(at.attr, "Project") == 0:
return 1
return 0
if fk == ast.ASTKind.Name:
if ctor is None:
return 0
nm: ast.Name* = ast.Name*(cl.func)
if nm is None or nm.id is None:
return 0
if string.strcmp(nm.id, ctor) == 0:
return 1
return 0
def _vb_is_macro_assign(self, target: ast.AST*, value: ast.AST*,
alias: str, ctor: str,
proj_vars: list[str]*) -> int:
"""赋值是否为 viperbuild 宏语句(Project 绑定 / 字段赋值);1=是且已登记"""
if target is None or value is None:
return 0
tk: int = target.kind()
if tk == ast.ASTKind.Name:
nm: ast.Name* = ast.Name*(target)
if nm is None or nm.id is None:
return 0
if self._vb_is_project_ctor(value, alias, ctor) != 0:
proj_vars.append(nm.id)
return 1
return 0
if tk == ast.ASTKind.Attribute:
at: ast.Attribute* = ast.Attribute*(target)
if at is None or at.value is None:
return 0
if at.value.kind() != ast.ASTKind.Name:
return 0
bn: ast.Name* = ast.Name*(at.value)
if bn is None or bn.id is None:
return 0
if self._vb_in_proj_vars(bn.id, proj_vars) != 0:
return 1
return 0
def _vb_is_macro_call(self, value: ast.AST*, proj_vars: list[str]*) -> int:
"""表达式是否为 `proj.config(...)` / `proj.build(...)`;1=是"""
if value is None or value.kind() != ast.ASTKind.Call:
return 0
cl: ast.Call* = ast.Call*(value)
if cl is None or cl.func is None:
return 0
if cl.func.kind() != ast.ASTKind.Attribute:
return 0
at: ast.Attribute* = ast.Attribute*(cl.func)
if at is None or at.attr is None or at.value is None:
return 0
if at.value.kind() != ast.ASTKind.Name:
return 0
bn: ast.Name* = ast.Name*(at.value)
if bn is None or bn.id is None:
return 0
if self._vb_in_proj_vars(bn.id, proj_vars) == 0:
return 0
if string.strcmp(at.attr, "config") == 0:
return 1
if string.strcmp(at.attr, "build") == 0:
return 1
return 0
def _vb_is_macro_stmt(self, child: ast.AST*, alias: str, ctor: str,
proj_vars: list[str]*) -> int:
"""单条模块级语句是否为 viperbuild 宏语句;1=是(应擦除)"""
if child is None:
return 0
kd: int = child.kind()
if kd == ast.ASTKind.Assign:
a: ast.Assign* = ast.Assign*(child)
if a is None or a.targets is None or a.value is None:
return 0
if len(a.targets) != 1:
return 0
return self._vb_is_macro_assign(a.targets.get(0), a.value, alias, ctor, proj_vars)
if kd == ast.ASTKind.AnnAssign:
an: ast.AnnAssign* = ast.AnnAssign*(child)
if an is None or an.target is None or an.value is None:
return 0
return self._vb_is_macro_assign(an.target, an.value, alias, ctor, proj_vars)
if kd == ast.ASTKind.Expr:
ex: ast.Expr* = ast.Expr*(child)
if ex is None or ex.value is None:
return 0
return self._vb_is_macro_call(ex.value, proj_vars)
return 0
def _erase_viperbuild_macros(self, pool: memhub.MemBuddy*, tree: ast.AST*) -> int:
"""擦除模块级 viperbuild 宏语句(就地替换 tree.children);1=发生擦除"""
if tree is None or tree.children is None:
return 0
ch: list[ast.AST*]* = tree.children
cn: sizet = len(ch)
if cn == 0:
return 0
# ① 找 viperbuild 的本地名 / Project 构造名
alias: str = None
ctor: str = None
ci: sizet = 0
while ci < cn:
child: ast.AST* = ch.get(ci)
if child is not None:
kd: int = child.kind()
if kd == ast.ASTKind.Import:
names: list[ast.AST*]* = ast.Import*(child).names
if names is not None:
ni: sizet = 0
while ni < len(names):
al: ast.Alias* = ast.Alias*(names.get(ni))
if al is not None and al.name is not None:
if string.strcmp(al.name, "viperbuild") == 0:
if al.asname is not None:
alias = al.asname
else:
alias = "viperbuild"
ni += 1
elif kd == ast.ASTKind.ImportFrom:
ifr: ast.ImportFrom* = ast.ImportFrom*(child)
if ifr is not None and ifr.level == 0 and ifr.names is not None:
if ifr.module is not None and string.strcmp(ifr.module, "viperbuild") == 0:
ni: sizet = 0
while ni < len(ifr.names):
al: ast.Alias* = ast.Alias*(ifr.names.get(ni))
if al is not None and al.name is not None:
if string.strcmp(al.name, "Project") == 0:
if al.asname is not None:
ctor = al.asname
else:
ctor = "Project"
ni += 1
ci += 1
if alias is None and ctor is None:
return 0
# ② 过滤:先登记 Project 宏变量,再摘掉相关语句
proj_vars: list[str]* = list[str](pool, 8)
kept: list[ast.AST*]* = list[ast.AST*](pool, 8)
if proj_vars is None or kept is None:
return 0
erased: int = 0
ci = 0
while ci < cn:
child = ch.get(ci)
if child is not None:
if self._vb_is_macro_stmt(child, alias, ctor, proj_vars) != 0:
erased = 1
else:
kept.append(child)
ci += 1
if erased != 0:
tree.children = kept
return erased
# 容器模块自动可见性注入(对齐 TPC _inject_auto_imports)
# TPC 在翻译前自动注入 `import _list / import _dict (+json)`,使 list/dict 内建容器类
# 在符号表中可见;TPV 用可见性机制等效替代:_list.vp/_dict.vp 已由 Phase1 注册,
@@ -1231,9 +1231,9 @@ def InjectTracebackInstallCtor(tr: rawptr[Translator]) -> int:
# ============================================================
novirtual class Mixin:
"""所有 Handle 的非多态基类:持有 Translator 回指针 + 共享委托方法"""
Trans: Translator | t.CPtr
Trans: Translator*
def InitMixin(self, trans: Translator | t.CPtr) -> int:
def InitMixin(self, trans: Translator*) -> int:
"""初始化 Mixin 字段(子类 __init__ 中调用)"""
self.Trans = trans
return 0
+18 -18
View File
@@ -510,8 +510,8 @@ novirtual class TranslatorGenMixin:
fc: int = se.FieldCount
if fc <= start_idx:
return None
# 每个字段元素 = 类型前缀(MLIR 形态可达 _TY_TEXT_CAP 字节)+ 值文本;
# 160 是按旧的短类型估的,会截断。
# 每个字段元素 = 类型前缀(MLIR 形态可达 _TY_TEXT_CAP 字节)+ 值文本;
# 160 是按旧的短类型估的,会截断。
buf_size: sizet = 256 + sizet(fc) * 576
buf: str = pool.alloc(buf_size)
if buf is None:
@@ -708,11 +708,11 @@ novirtual class TranslatorGenMixin:
resolved_stg_ty: mlirlite.LLVMType* = None # 对象类全局:静态 storage 类型(BSS 实例)
resolved_stg_entry: GenTypes.StructEntry* = None # 对象类全局:对应 StructEntry(vtable 初始化用)
init_val: int64 = 0
init_fval: t.CDouble = 0.0 # init_kind==4(浮点字面量)时的数值
init_fval: double = 0.0 # init_kind==4(浮点字面量)时的数值
init_kind: int = 0 # 0=none, 1=int, 2=list, 3=str, 4=float
init_str_val: str = None
init_list_node: ast.List* = None
# = None 显式初始化(如 tokens.vp `_kw_head: KwEntry | t.CPtr = None`):
# = None 显式初始化(如 tokens.vp `_kw_head: KwEntry* = None`):
# 对象类全局的懒初始化指针语义——必须保持 NULL,不能创建 BSS storage
# (storage 会让 @g = &g.stg 恒非 NULL,破坏 `if _kw_head != None` 守卫,
# 懒初始化代码永不执行)。
@@ -775,7 +775,7 @@ novirtual class TranslatorGenMixin:
resolved_stg_entry = gv_entry
resolved = mlirlite.Ptr(pool, resolved)
elif resolved.kind() == mlirlite.LLVMType.Ptr:
# 对象类联合注解(T | t.CPtr → T*):同样创建 storage;否则入口/方法
# 对象类联合注解(T* → T*):同样创建 storage;否则入口/方法
# 虚调用 load @g 得 NULL → 读 [NULL] 拿 vtable → #PF。
# var_ty 保持 Ptr(联合注解语义:指针全局),storage 承载对象实例。
pointee_uv: mlirlite.LLVMType* = resolved.Pointee
@@ -888,7 +888,7 @@ novirtual class TranslatorGenMixin:
self.Gen.TypeGenErr.fatal_error(node, f"模块级变量 '{var_name}' 用浮点字面量初始化,但注解不是浮点类型",
"TypeError")
return 0
if self.Gen.AssignGen._recover_float_literal(var_name, t.CPtr(c.Addr(init_fval)), 0) != 1:
if self.Gen.AssignGen._recover_float_literal(var_name, t.CPtr(&init_fval), 0) != 1:
self.Gen.TypeGenErr.fatal_error(node, f"模块级浮点变量 '{var_name}' 初始化值源文件恢复失败", "InternalCompilerError")
return 0
@@ -1178,7 +1178,7 @@ novirtual class TranslatorGenMixin:
# 前者是变量自身限定(BinOp 联合),后者是 rawptr 下标实参标记。
if self.Gen.TypeGenErr.has_pointee_volatile_marker(annot_node) != 0:
self.Gen.VarGen.set_var_pointee_volatile(trans.SymTab, var_name)
# 设置 AnnotClassName(联合类型如 Logger|t.CPtr 简化为 Ptr(i8) 时,
# 设置 AnnotClassName(联合类型如 Logger* 简化为 Ptr(i8) 时,
# 属性访问需要通过 AnnotClassName 回退到类名查找结构体)
if k == ast.ASTKind.AnnAssign:
aa_ml: ast.AnnAssign* = ast.AnnAssign*(node)
@@ -1186,7 +1186,7 @@ novirtual class TranslatorGenMixin:
cls_nm_ml: str = self.Gen.TypeGenResolve.extract_class_name_from_annotation(aa_ml.annotation, trans._imported_modules, pool, trans._from_imports)
if cls_nm_ml is not None:
self.Gen.VarGen.set_var_annot_class_name(trans.SymTab, var_name, cls_nm_ml)
# 模块级 str|t.CPtr / bytes|t.CPtr 全局:标记 IsPtrElement
# 模块级 str* / bytes* 全局:标记 IsPtrElement
# (i8** 语义,var[i] 按 8 字节指针步长),对齐 TPC 的
# global_var_ptr_element(_argv 等字符串指针数组)。否则
# var[i] 退化为 1 字节字符步长 GEP + load i8 截断指针。
@@ -1296,7 +1296,7 @@ novirtual class TranslatorGenMixin:
VLogger.error("global 变量数量超过上限,请减少 global 声明或增大 MAX_GLOBAL_NAMES", "ScopeDecl")
return
entry_addr: uint64 = uint64(trans._global_names) + trans._global_name_count * 8
slot_ptr: str | t.CPtr = (str | t.CPtr)(entry_addr)
slot_ptr: str* = (str*)(entry_addr)
slot_ptr[0] = name
trans._global_name_count += 1
@@ -1306,7 +1306,7 @@ novirtual class TranslatorGenMixin:
return 0
for i in range(trans._global_name_count):
entry_addr: uint64 = uint64(trans._global_names) + i * 8
slot_ptr: str | t.CPtr = (str | t.CPtr)(entry_addr)
slot_ptr: str* = (str*)(entry_addr)
entry: str = slot_ptr[0]
if entry is not None:
if string.strcmp(entry, name) == 0:
@@ -1329,13 +1329,13 @@ novirtual class TranslatorGenMixin:
if self.is_nonlocal_name(trans, name) != 0:
# 已存在:更新类型信息(可能在预扫描时类型未知,正式翻译时更新)
# _nonlocal_types 每槽 8 字节,存 LLVMType* 指针。
# 用 str|t.CPtr (i8**) 二级指针存取(与 _nonlocal_names 模式一致),
# 用 str* (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: uint64 = uint64(trans._nonlocal_types) + idx * 8
ty_slot: str | t.CPtr = (str | t.CPtr)(ty_addr)
ty_slot: str* = (str*)(ty_addr)
ty_slot[0] = var_ty
return
if trans._nonlocal_name_count >= HT.MAX_GLOBAL_NAMES:
@@ -1350,12 +1350,12 @@ novirtual class TranslatorGenMixin:
VLogger.error("nonlocal 变量数量超过上限,请减少 nonlocal 声明或增大 MAX_GLOBAL_NAMES", "ScopeDecl")
return
entry_addr: uint64 = uint64(trans._nonlocal_names) + trans._nonlocal_name_count * 8
slot_ptr: str | t.CPtr = (str | t.CPtr)(entry_addr)
slot_ptr: str* = (str*)(entry_addr)
slot_ptr[0] = name
# 存储类型信息(用 str|t.CPtr = i8** 二级指针,与 _nonlocal_names 一致)
# 存储类型信息(用 str* = i8** 二级指针,与 _nonlocal_names 一致)
if trans._nonlocal_types is not None:
ty_addr2: uint64 = uint64(trans._nonlocal_types) + trans._nonlocal_name_count * 8
ty_slot2: str | t.CPtr = (str | t.CPtr)(ty_addr2)
ty_slot2: str* = (str*)(ty_addr2)
# var_ty 为 None 时直接报错终止(fail-fast),不再默认 i32
stored_ty: mlirlite.LLVMType* = var_ty
if stored_ty is None:
@@ -1377,7 +1377,7 @@ novirtual class TranslatorGenMixin:
if idx < 0:
return None
ty_addr: uint64 = uint64(trans._nonlocal_types) + idx * 8
ty_slot: str | t.CPtr = (str | t.CPtr)(ty_addr)
ty_slot: str* = (str*)(ty_addr)
return (mlirlite.LLVMType*)(ty_slot[0])
def is_nonlocal_name(self, trans: HT.Translator*, name: str) -> int:
@@ -1386,7 +1386,7 @@ novirtual class TranslatorGenMixin:
return 0
for i in range(trans._nonlocal_name_count):
entry_addr: uint64 = uint64(trans._nonlocal_names) + i * 8
slot_ptr: str | t.CPtr = (str | t.CPtr)(entry_addr)
slot_ptr: str* = (str*)(entry_addr)
entry: str = slot_ptr[0]
if entry is not None:
if string.strcmp(entry, name) == 0:
@@ -1399,7 +1399,7 @@ novirtual class TranslatorGenMixin:
return -1
for i in range(trans._nonlocal_name_count):
entry_addr: uint64 = uint64(trans._nonlocal_names) + i * 8
slot_ptr: str | t.CPtr = (str | t.CPtr)(entry_addr)
slot_ptr: str* = (str*)(entry_addr)
entry: str = slot_ptr[0]
if entry is not None:
if string.strcmp(entry, name) == 0:
+4 -4
View File
@@ -45,8 +45,8 @@ novirtual class TypeGenBase:
# --- 全局 CDefine 编译期常量表(原 _g_cdefine_*) ---
CDefineNames: list[str]*
CDefineValues: list[str]*
CDefineDoubleFlags: list[int] | t.CPtr
CDefineStrFlags: list[int] | t.CPtr # 1=字符串值(如 ZLIB_VERSION: t.CDefine = "1.3.2")
CDefineDoubleFlags: list[int]*
CDefineStrFlags: list[int]* # 1=字符串值(如 ZLIB_VERSION: t.CDefine = "1.3.2")
CDefineIsDouble: int
CDefineIsStr: int
CDefineFound: int
@@ -63,8 +63,8 @@ novirtual class TypeGenBase:
# CONST_INT 递归查找只做一次。
XmodCdefNames: list[str]*
XmodCdefValues: list[str]*
XmodCdefDoubleFlags: list[int] | t.CPtr
XmodCdefStrFlags: list[int] | t.CPtr
XmodCdefDoubleFlags: list[int]*
XmodCdefStrFlags: list[int]*
# --- 当前模块 SHA1(原 _g_current_module_sha1) ---
CurrentModuleSha1: str
+6 -6
View File
@@ -159,8 +159,8 @@ novirtual class TypeGenCDef(TypeGenBase.TypeGenBase):
tp: memhub.MemBuddy* = self._cdefine_table_pool(pool)
tn: list[str]* = list[str](tp, 64)
tv: list[str]* = list[str](tp, 64)
td: list[int] | t.CPtr = list[int](tp, 64)
tsf: list[int] | t.CPtr = list[int](tp, 64)
td: list[int]* = list[int](tp, 64)
tsf: list[int]* = list[int](tp, 64)
# 建表失败(池不可用/耗尽)⇒ 明确报错并返回,绝不让下面的 append
# 落到 None 或未初始化地址(原实现无检查 ⇒ append 写进 NULL/0xCD 区崩)
if tn is None or tv is None or td is None or tsf is None:
@@ -213,8 +213,8 @@ novirtual class TypeGenCDef(TypeGenBase.TypeGenBase):
tp: memhub.MemBuddy* = self._cdefine_table_pool(pool)
tn: list[str]* = list[str](tp, 64)
tv: list[str]* = list[str](tp, 64)
td: list[int] | t.CPtr = list[int](tp, 64)
tsf: list[int] | t.CPtr = list[int](tp, 64)
td: list[int]* = list[int](tp, 64)
tsf: list[int]* = list[int](tp, 64)
if tn is None or tv is None or td is None or tsf is None:
self.Gen.TypeGenErr.fatal_error(None, "CDefine 浮点表分配失败(表本体池不可用或耗尽)", "MemoryError")
return
@@ -269,8 +269,8 @@ novirtual class TypeGenCDef(TypeGenBase.TypeGenBase):
tp: memhub.MemBuddy* = self._cdefine_table_pool(pool)
tn: list[str]* = list[str](tp, 64)
tv: list[str]* = list[str](tp, 64)
td: list[int] | t.CPtr = list[int](tp, 64)
tsf: list[int] | t.CPtr = list[int](tp, 64)
td: list[int]* = list[int](tp, 64)
tsf: list[int]* = list[int](tp, 64)
if tn is None or tv is None or td is None or tsf is None:
self.Gen.TypeGenErr.fatal_error(None, "CDefine 字符串表分配失败(表本体池不可用或耗尽)", "MemoryError")
return
+1 -1
View File
@@ -326,7 +326,7 @@ class TypeGenCType(TypeGenBase.TypeGenBase):
return self._spec_sign_of_span(text, 0, string.strlen(text), depth)
def _spec_sign_of_span(self, text: str, start: sizet, end: sizet,
depth: int) -> int:
"""顶层 '|' 分段,返回首个能确定的符号性(`X | t.CPtr` 取 X)"""
"""顶层 '|' 分段,返回首个能确定的符号性(`X*` 取 X)"""
seg_start: sizet = start
bracket_depth: int = 0
i: sizet = start
+4 -4
View File
@@ -240,12 +240,12 @@ novirtual class TypeGenErr(TypeGenBase.TypeGenBase):
"""检测指针注解 rawptr[...] 的下标实参是否含 t.CVolatile 标记,1=是 / 0=否
语义:rawptr[t.CVolatile | T] 等价 C 的 volatile T*,即"指针所指对象按
volatile 访问"——解引用(p[i] / p.field / c.Deref(p))的 load/store 带
volatile 访问"——解引用(p[i] / p.field / *p)的 load/store 带
LLVM volatile。与 has_decorator_marker 的区别:后者检测变量/字段**自身**
的可见性限定(如 `locked: t.CVolatile | t.CInt`),对 Subscript 节点返回 0;
的可见性限定(如 `locked: t.CVolatile | int`),对 Subscript 节点返回 0;
本函数专检 rawptr 的 pointee 侧标记(下标实参子树),两者互不串味。
标注形态(vast.parse 实证):
rawptr[t.CVolatile | t.CInt]
rawptr[t.CVolatile | int]
→ Subscript(value=Name('rawptr'),
slice=BinOp(BitOr, Attribute(t,CVolatile), Attribute(t,CInt)))
多级指针 rawptr[rawptr[t.CVolatile|T]] 的 slice 是 Subscript,
@@ -272,7 +272,7 @@ novirtual class TypeGenErr(TypeGenBase.TypeGenBase):
② 声明类型的 LLVM 形态**不是指针**(TPC 用 PtrCount==0 表达同一件事)。
`t.CConst` 在本语言里承载「指向的数据 const」(对齐 TPC 的 DataConst 语义),
对非指针类型该限定退化为「该对象自身 const」⇒ 登记为 const 变量/字段;
对指针类型(`p: t.CConst | T | t.CPtr`)限定只作用于 pointee ⇒ 指针变量自身
对指针类型(`p: t.CConst | T*`)限定只作用于 pointee ⇒ 指针变量自身
仍可重新赋值,不登记。
"""
if self.has_decorator_marker(node, "CConst", 0) == 0:
+87 -87
View File
@@ -387,8 +387,8 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
依据是容器本身的定义(不是我猜的):TPC 侧 t.CArray 明写"第一个参数为元素类型,
第二个参数为数组大小(整数或常量名)"(lib/includes/t.py CArray);`list[T, N]`
与 includes/_list.vp 的堆上 STL 容器 `list` 无关(`list[T, N]` 不是定长数组);
这里把 list 一并纳入,只是因为历史写法 `list[E, N]` 的第 2 实参是常量,
与 includes/_list.vp 的堆上 STL 容器 `list` 无关(`list[T, N]` 不是定长数组);
这里把 list 一并纳入,只是因为历史写法 `list[E, N]` 的第 2 实参是常量,
须避免它被误当类名归一。
故这两个容器的第 2 实参是常量表达式 —— 对它做"裸类名 → {定义模块SHA1}.类"归一
既无意义,又会落进 `_norm_type_arg_name` 规则 5.5 的"保留裸名"取证 ⇒ 误报为
@@ -420,14 +420,14 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
`SymbolUtils.NormalizeGenericArgName` 同样原样保留)⇒ 对它报 ERROR 是纯噪声。
现场(2026-09-30):includes/traceback.vp:532
`FrameAddr: t.CArray[uint64, TRACEBACK_FRAME_BUF]` 的实参 'uint64' 是
includes/builtins.vp 的 `typedef uint64 = t.CUInt64T`,不进类归属是**预期**,
includes/builtins.vp 的 `typedef uint64 = uint64`,不进类归属是**预期**,
却每次编译刷一条 ERROR。
判据(正向白名单,逐条可查,不猜):
① CTypedef 动态表命中 —— typedef 唯一真源(Phase1 1b 的
register_ctypedef_from_source 文本扫描注册;表在文件边界被 clear 后重建,
故紧跟 ② 的 builtins 兜底,与 `resolve_typedef_or_map` 的"统一口径"一致);
② builtins.vp 的 typedef(如 `typedef uint64 = t.CUInt64T`):builtins 始终
② builtins.vp 的 typedef(如 `typedef uint64 = uint64`):builtins 始终
在编译链内,但其 typedef 不随当前文件 from_imports 注入 ⇒ 表可能 miss,
必须走与 `resolve_typedef_or_map` 同一兜底(命中即注册进表,幂等);
③ 语言内置标量/字符串名 —— 与 `_resolve_annot_type_name` 的跳过清单同口径;
@@ -471,7 +471,7 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
# _is_ptr_marker_text - 文本是否为"裸指针标记"(t.CPtr / c.CPtr / CPtr)
#
# 用途:泛型类型实参**文本**归一(_norm_type_arg_name)的唯一判据 ——
# 用户定口径(2026-09-30):`rawptr[T]` ≡ `t.CPtr[T]` ≡ `T | t.CPtr`
# 用户定口径(2026-09-30):`rawptr[T]` ≡ `t.CPtr[T]` ≡ `T*`
# ⇒ 统一为 **`T*`**。裸标记只贡献一层指针、自身不是类型名。
# (形式无关:四种写法在类型域恒等价——`rawptr[T]` / `t.CPtr[T]` 一律追加 1 层。)
#
@@ -544,13 +544,13 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
收敛同一类型的不同书写(ast.AST / AST → f467978339422f32.AST),
消除跨模块特化名分裂(undefined symbol: 7cadfe07e983fd90.list[AST].set 根因:
一侧注解写 "list[ast.AST*]"、另一侧写 "list[AST | t.CPtr]",
一侧注解写 "list[ast.AST*]"、另一侧写 "list[AST*]",
生成两个不同特化名 → 结构体/方法注册与调用不一致)。
规则(自顶向下):
1. 联合类型 "A|B"('|' 分割):左右段各自规范化后重组
1.0【指针书写归一(2026-09-30,用户定口径)】指针类型实参**唯一规范形
是 `T*`**:`rawptr[T]` ≡ `t.CPtr[T]` ≡ `T | t.CPtr`
是 `T*`**:`rawptr[T]` ≡ `t.CPtr[T]` ≡ `T*`
⇒ 一律折叠为 `T*`(裸标记只贡献一层指针)。与 TPC 侧
SymbolUtils.ResolveTypeArgStr/AddPointerLayers 逐字同形,两侧必须
同票名(否则 .vpi/.stub.ll 的结构体名与方法符号名分叉)。
@@ -595,7 +595,7 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
return type_name
# ---- 1. 顶层联合 "A|B"('|' 仅在括号外才分割)----
# 括号感知:list[A|B] 的 '|' 在 '[' 内不是顶层联合,应留给第 1.5 步
# 泛型 slice 递归处理;list[A]|t.CPtr 的 '|' 在括号外才是联合分割。
# 泛型 slice 递归处理;list[A]* 的 '|' 在括号外才是联合分割。
seg_len: sizet = string.strlen(type_name)
if seg_len == 0:
return type_name
@@ -630,16 +630,16 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
l_n = left_buf
if r_n is None:
r_n = right_buf
# 【指针联合归一(2026-09-30,用户定口径)】`X | t.CPtr` ≡ `X | rawptr`
# 【指针联合归一(2026-09-30,用户定口径)】`X*` ≡ `X | rawptr`
# ≡ `rawptr[X]` ≡ `t.CPtr[X]` ⇒ 统一为 **`X*`**(T* 形)。裸指针标记
# 只贡献一层指针;这不是新类型规则,只是**书写形式的唯一规范形**
# (四种写法在类型域恒等价:下标形与联合形都只追加 1 层指针)。
# 为什么必须归一:同一元素类型 `AST*` 若一半写 `rawptr[AST]`、一半写
# `AST|t.CPtr`,泛型特化名会分裂成两个结构体(现场
# `AST*`,泛型特化名会分裂成两个结构体(现场
# Test/AstTest/App/main.vp:63 `classify_list(ifn.orelse, ...)`:
# 源 %"….list[rawptr[<sha>.AST]]"* vs 目标 %"….list[<sha>.AST|t.CPtr]"*
# 源 %"….list[rawptr[<sha>.AST]]"* vs 目标 %"….list[<sha>.AST*]"*
# ⇒ 指针隐式转换规则按"不同非基本类型"拒绝,属假报错)。
# 判据只拦"一侧恰为裸标记"这一确定形态;多层标记链(X|t.CPtr|t.CPtr)
# 判据只拦"一侧恰为裸标记"这一确定形态;多层标记链(X*|t.CPtr)
# 与其它联合维持原有重组行为(不回归)。
l_is_mk: int = self._is_ptr_marker_text(l_n)
r_is_mk: int = self._is_ptr_marker_text(r_n)
@@ -753,12 +753,12 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
# 直接产出 "<实参规范化文本>*",与 TPC 侧
# SymbolUtils.ResolveTypeArgStr+AddPointerLayers 的逐字口径一致。
# 不做这一步时,同一元素类型(都是 AST*)会分裂成
# `list[rawptr[<sha>.AST]]` 与 `list[<sha>.AST|t.CPtr]` 两个特化体
# `list[rawptr[<sha>.AST]]` 与 `list[<sha>.AST*]` 两个特化体
# ⇒ 调用点被严格指针规则按"不同非基本类型"拒绝(现场
# Test/AstTest/App/main.vp:63,假报错)。多实参(异常写法)不拦。
# 【判据必须用**下标容器**判据(2026-09-30)】不能复用
# _is_ptr_marker_text(它只认 CPtr 一族,用于联合写法):
# 复用它会让 `rawptr[T]` 漏折叠 ⇒ 与 `T | t.CPtr` 折叠后的
# 复用它会让 `rawptr[T]` 漏折叠 ⇒ 与 `T*` 折叠后的
# `T*` 并存两个特化体(现场 _list.vp:83 return self 的
# CastError:list[<sha>.AST*] ↔ list[rawptr[<sha>.AST]])。
# 详见 _is_ptr_subscript_container_text 的头注释。
@@ -792,7 +792,7 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
string.strcat(g_out, "]")
return g_out
# ---- 1.6 尾随指针星号:先归一基名,再回贴星号(2026-10-01)----
# parser 把源码 `X*` 展开为 `X | t.CPtr`,但**泛型实参文本**里的星号是原样
# parser 把源码 `X*` 展开为 `X*`,但**泛型实参文本**里的星号是原样
# 带进来的(如字段 `list[ast.ClassDef*]` 的实参段文本就是 "ast.ClassDef*")。
# 不剥离时规则 4 的 attr 会带上星号变成 "ClassDef*":
# ① `_class_true_def_sha1` 按名查不到 "ClassDef*" ⇒ 真定义模块校正失效 ⇒
@@ -801,7 +801,7 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
# `list[e70bd9b4487d921d.ClassDef*]` ⇒ TPV 报「指针隐式转指针已禁止」,
# 且该票名在全部产物里从未定义为实体结构体);
# ② 与 TPC 名称域不一致 —— SymbolUtils.ResolveTypeArgStr 的 BinOp 分支明确
# 规定 `X | t.CPtr` ≡ `rawptr[X]` ≡ `t.CPtr[X]` → `{sha}.X*`(先解析基
# 规定 `X*` ≡ `rawptr[X]` ≡ `t.CPtr[X]` → `{sha}.X*`(先解析基
# 类型 X,再 AddPointerLayers 追加星号)。
# 故统一为:剥掉全部尾随 '*' → 递归归一基名 → 回贴同样多的 '*'。
# `i8**` / `int*` / `T*` / 已带 SHA1 前缀的文本都逐字不变(基名归一回原样)。
@@ -1040,10 +1040,10 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
def _str_contains_ident(self, s: str, ident: str) -> int:
"""检查 s 中是否包含独立标识符 ident(两侧非字母/数字/下划线)
用于泛型实参污染检测:单字符参数名(如 'T')在实参串 "AST|t.CPtr"
用于泛型实参污染检测:单字符参数名(如 'T')在实参串 "AST*"
中作为 AST/CPtr 内部字符出现时不算污染——必须两侧是边界
(空格/|/[/]/,等)才算独立标识符。strstr 子串匹配会把实参内部
的 'T' 误判为参数名 → 合法特化 list[AST|t.CPtr] 被误杀。
的 'T' 误判为参数名 → 合法特化 list[AST*] 被误杀。
"""
if s is None or ident is None or ident[0] == '\0':
return 0
@@ -1077,10 +1077,10 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
ctx: int) -> ast.AST*:
"""将类型名字符串解析为 AST 节点
正确处理 '|' 与 '.' 周围的空格(如 "ParsedArgs | t.CPtr"):
正确处理 '|' 与 '.' 周围的空格(如 "ParsedArgs*"):
- '|' 分割后左段可能带尾随空格("ParsedArgs "),右段可能带前导空格(" t.CPtr")
- 段内空格会导致 Name.id 带空格("ParsedArgs "、" t"),结构体/模块按名查找失败,
最终退化 i8*/i32,如 parse_args -> "ParsedArgs | t.CPtr" 解析出垃圾类型。
最终退化 i8*/i32,如 parse_args -> "ParsedArgs*" 解析出垃圾类型。
"""
if type_str is None or pool is None:
return None
@@ -1096,7 +1096,7 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
# 【`T*` 形反解析(2026-09-30)】泛型实参归一后指针类型一律是 `T*` 形
# (TypeGenResolve._norm_type_arg_name 的指针书写归一:rawptr[T] ≡
# t.CPtr[T] ≡ T|t.CPtr ≡ T*),而本函数负责把**类型名文本**还原成注解 AST
# t.CPtr[T] ≡ T* ≡ T*),而本函数负责把**类型名文本**还原成注解 AST
# (典型调用方:ClassGenGeneric._clone_annotation 把泛型参数 T 替换为
# 已归一的实参文本)⇒ 必须能解析尾随 '*'。语义与 `rawptr[T]` 逐字等价
# (下标形与联合形恒等价,都只追加 1 层指针),故按层数包成 rawptr[...]:
@@ -2054,7 +2054,7 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
cls_nm = nm.id
if from_imports is not None:
sha1 = self.Gen.CallGenBase._lookup_mod_sha1(pool, from_imports, cls_nm, 0)
# 本文件顶层类(如自我引用 JsonValue | t.CPtr,或同文件内前向引用):
# 本文件顶层类(如自我引用 JsonValue*,或同文件内前向引用):
# register_file_classes 已登记"名字 → 本文件模块 SHA1"(规则 5.5 证据⑤同源),
# 用它前向声明——与 TPC 的同类前向引用同等处理。
if sha1 is None:
@@ -2068,7 +2068,7 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
# 成功(还没 register_struct),它的归属同样可判——据此前向声明为具名占位
# "{src_sha1}.{类名}",而不是退化成 Ptr(i8)。
# 现场:Translator.vp 的 `class Translator`(:84) 与 `class Mixin`(:1011),
# 字段 `Mixin.Trans: Translator | t.CPtr` 在 Translator.vpi 注入到
# 字段 `Mixin.Trans: Translator*` 在 Translator.vpi 注入到
# CallGenLeafKit.vp 时解析(self.Trans.Pool 属性访问失败根因):若本遍
# Translator 尚未登记就退化成 i8*,随后 Mixin 因 field_count>0 被判"注册
# 成功"、i8* 被永久冻结(inject_class 的已注册检查直接早退)。
@@ -2161,7 +2161,7 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
elif string.strcmp(type_name, "callable") == 0:
return mlirlite.Ptr(pool, mlirlite.Int8(pool))
# 裸名 void 是 t.CVoid 的别名(用户 2026-10-01 定):单独出现即 LLVM void;
# `void*`(= `void | t.CPtr`)由下方 BinOp 分支归并为 i8*。
# `void*`(= `void*`)由下方 BinOp 分支归并为 i8*。
elif string.strcmp(type_name, "CVoid") == 0 or string.strcmp(type_name, "void") == 0:
return mlirlite.Void(pool)
# CDefine: 编译期常量定义标记(X: t.CDefine = 64),底层为 32 位有符号整数
@@ -2233,7 +2233,7 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
- t.CPtr / t\.CVoid(Attribute 形式)
- 裸名 CPtr / CVoid(from t import CPtr 形式)
裸名识别是必要功能:测试/库代码大量用 `from t import CPtr` 后直接写
`X | CPtr`、`CVoid` 参数注解等,若只认 t.XXX 会漏判。
`X*`、`CVoid` 参数注解等,若只认 t.XXX 会漏判。
"""
if node is None or attr_name is None:
return 0
@@ -2278,7 +2278,7 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
def _is_cptr_subscript(self, node: ast.AST*) -> int:
"""检测节点是否为 t.CPtr[T] 下标指针类型(t.CPtr[t.CPtr] / t.CPtr[int] 等)
用于联合类型 X | t.CPtr[T] 的指针层级合并(TPC 联合合并规则:
用于联合类型 X*[T] 的指针层级合并(TPC 联合合并规则:
CPtr 侧贡献 PtrCount,另一侧提供 BaseType)。t.CPtr[...] 不是
普通 CPtr 标记(_is_cptr_marker 只认 t.CPtr/CPtr 裸形式)。
"""
@@ -2435,8 +2435,8 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
from_imports: str = None) -> str:
"""从类型注解 AST 中提取类名,返回 None=无法提取
pool 可用时,对泛型 Subscript(如 list[AST | t.CPtr])返回 mangled name
(如 "list[f467978339422f32.AST|t.CPtr]"),与 resolve_annotation_type 的
pool 可用时,对泛型 Subscript(如 list[AST*])返回 mangled name
(如 "list[f467978339422f32.AST*]"),与 resolve_annotation_type 的
mangled name 格式一致,使 find_struct 能找到特化的泛型结构体。
from_imports 可用时,slice 类型参数经 _norm_type_arg_name 规范化为
"{定义模块SHA1}.{Class}"(ast.AST/AST → f467978339422f32.AST),
@@ -2476,7 +2476,7 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
if nm.id is None:
return None
# 泛型特化上下文:T → 具体类型(特化方法体内局部变量注解
# 如 `cur: T | t.CPtr` 未被 _clone_classdef_for_spec 克隆替换,
# 如 `cur: T*` 未被 _clone_classdef_for_spec 克隆替换,
# 依赖此处在翻译时经上下文解析;否则 cur.annot="T",
# 属性访问 cur.Next → lookup_field_by_class("T") 未注册报错)
resolved_id: str = self.Gen.TypeGenBase.resolve_generic_type_name(nm.id)
@@ -2560,7 +2560,7 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
return None
# BUG 1 方案3:Subscript 节点拼接 mangled name
# list[AST | t.CPtr] → "list[ast.AST|t.CPtr]"(pool 可用时)
# list[AST*] → "list[ast.AST*]"(pool 可用时)
# 与 resolve_annotation_type 的 mangled name 格式一致,使 find_struct 能找到特化结构体
if k == ast.ASTKind.Subscript:
sub: ast.Subscript* = ast.Subscript*(node)
@@ -2632,9 +2632,9 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
string.strcat(tup_buf, elt_name2)
slice_name = tup_buf
else:
# 非 Tuple slice: list[AST | t.CPtr] → "ast.AST|t.CPtr"
# 非 Tuple slice: list[AST*] → "ast.AST*"
# 类型参数经 _norm_type_arg_name 规范化为 "{SHA1}.Class",
# 与特化注册名一致(list[f467978339422f32.AST|t.CPtr])
# 与特化注册名一致(list[f467978339422f32.AST*])
slice_raw: str = self._get_type_name_from_annotation(pool, sub.slice)
slice_name = self._norm_type_arg_name(pool, slice_raw, from_imports)
if slice_name is None:
@@ -2819,7 +2819,7 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
gen_spec_ty = self.Gen.StructGen.get_struct_type(gen_mangled)
# gen_mangled 由本函数自行拼接,而 _specialize_generic_class 内部还会对
# 每个实参再规范化一次,两处命名可能不一致(如元素注解 `ast.AST*`
# 本函数拼 "list[<sha1>.AST|t.CPtr]",特化侧规范化 "list[<sha1>.ASTptr]")
# 本函数拼 "list[<sha1>.AST*]",特化侧规范化 "list[<sha1>.ASTptr]")
# → 按 gen_mangled 重查恒 miss → 静默退化为裸 list* → .get() 误分派截断。
# spec_name_chk 是特化侧返回的权威特化名,必须按它重查。
# 注:非联合实参(如 list[int])两侧命名一致,本步恒 miss 不改变行为。
@@ -2868,7 +2868,7 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
return None
# ============================================================
# _check_bare_generic_annotation - fail-fast:注解(或其 A | t.CPtr 联合的一侧)
# _check_bare_generic_annotation - fail-fast:注解(或其 A* 联合的一侧)
# 里出现"已注册的泛型模板类名"却没写 [类型实参] 的裸用法(如 GSList、vector.Vector)。
#
# 与 AssignGenMixin._fail_on_degenerated_generic_annotation 互补:后者防"写了实参
@@ -2931,7 +2931,7 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
self.Gen.TypeGenErr.fatal_type_error(node, "类型注解递归过深(AST 环或嵌套超过 128 层)")
# 裸泛型注解 fail-fast(集中守卫,见 _check_bare_generic_annotation):
# 注解本身或 A | t.CPtr 的一侧是"已注册泛型模板类名"却没写 [类型实参] 即终止。
# 注解本身或 A* 的一侧是"已注册泛型模板类名"却没写 [类型实参] 即终止。
self._check_bare_generic_annotation(node)
k: int = node.kind()
@@ -2970,7 +2970,7 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
if gp_ta is not None:
# 自映射/污染实参防护(泛型循环套用):
# 1) 实参与参数名完全一致(T→T)
# 2) 实参串包含任一类型参数名(如 "T | t.CPtr"、" T "、
# 2) 实参串包含任一类型参数名(如 "T*"、" T "、
# "list[T]")——_parse_type_string 解析后仍会产出
# Name(参数名) → 递归再次进入本分支 → 无条件自递归
# 无退出条件 → 编译卡死。该递归不经 _specialize_generic_class
@@ -2989,13 +2989,13 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
# "独立标识符"参数名(两侧非字母/数字/_)。否则 strstr
# 把实参内部字符误判为参数名——"e9dfb296a8674aee.AST|
# t.CPtr" 含 'T' 字符但 T 在 AST/CPtr 内部不是独立
# 参数名 → 合法特化 list[AST|t.CPtr] 被误杀(_list.vp
# L57 elem_ptr: T | t.CPtr 根因)。
# 参数名 → 合法特化 list[AST*] 被误杀(_list.vp
# L57 elem_ptr: T* 根因)。
if gp_pn is not None and self._str_contains_ident(gp_ta, gp_pn) != 0:
polluted = 1
break
if polluted != 0:
# 实参串包含类型参数名(如 "T | t.CPtr"/"list[T]"):
# 实参串包含类型参数名(如 "T*"/"list[T]"):
# 解析后仍产出 Name(参数名) → 无条件自递归卡死。编译期
# 报错(此前 return None 静默退化)。
self.Gen.TypeGenErr.fatal_error(nm, f"泛型类型实参污染:实参 '{gp_ta}' 包含类型参数名,无法特化", "TypeError")
@@ -3021,8 +3021,8 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
sp_entry2: GenTypes.StructEntry* = self.Gen.StructGen.find_struct_by_module(nm.id + sp_len2, sp_sha_buf2)
if sp_entry2 is not None and sp_entry2.Ty is not None:
# 裸类名恒为**原型**(struct 本身,值/布局语义),不再看 HasNew:
# 堆对象引用必须显式写 `T*` / `T | t.CPtr` / `rawptr[T]`
# (用户 2026-10-01 定;TPC 侧注解链路本无 __new__ 升指针逻辑,
# 堆对象引用必须显式写 `T*` / `T*` / `rawptr[T]`
# (用户 2026-10-01 定;TPC 侧注解链路本无 __new__ 升指针逻辑,
# 天然同口径,故 TPC 无需同步改)。
return sp_entry2.Ty
# 兜底:按完整前缀名直接查(部分注册键即全名)
@@ -3062,27 +3062,27 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
if own_entry is not None and own_entry.Ty is not None:
# 裸类名恒为**原型**(struct 本身):注解说的是"类型/布局",
# 不再按 HasNew 自动升成 Ptr(struct)。堆对象引用一律显式写
# `T*` / `T | t.CPtr` / `rawptr[T]`(用户 2026-10-01 定;
# `T*` / `T*` / `rawptr[T]`(用户 2026-10-01 定;
# TPC 侧注解链路本无 __new__ 升指针逻辑,天然同口径,
# 故 TPC 无需同步改)。旧行为(有 __new__ ⇒ Ptr(struct))是
# 为兼容 `d: dict = dict(bd)` 这类"裸名 + 构造"写法而设,
# 代价是同一类型出现"裸名=指针 / 联合=再加一层"的分裂
# (现场 includes/json/__init__.vp:90 CastError)。
return own_entry.Ty
# vpi 注入期:CurDefModuleSha1 = **本次注入的 stub 源模块**(inject_class 入口
# 的 mark_module_class 建立)。注入期 trans.ModuleSha1 是"正在翻译的文件",
# 故上面的本模块查找必然落空。此处按同一口径认"被注入 stub 自己声明的类":
# 已登记条目、或先前由指针前向声明建立的具名占位,都返回原型(裸类名恒为原型,
# 见上),使同一 stub 内"先声明/先被引用"的类在后继字段注解里口径一致,不再
# 绕经"联合回退 → 前向声明 → 退化为 Ptr(i8)"那条链。
# 注:此处**不新建**占位——值语义位置凭空建不透明原型会得到不可用布局;
# 占位创建仍归 _forward_declare_ptr_from_node(指针语境)。
if trans is not None and trans.ModuleSha1 is not None:
inj_mod_rn: str = self.Gen.StructGen.CurDefModuleSha1
if inj_mod_rn is not None:
if string.strcmp(inj_mod_rn, trans.ModuleSha1) != 0:
inj_e_rn: GenTypes.StructEntry* = self.Gen.StructGen.find_struct_by_module(nm.id, inj_mod_rn)
if inj_e_rn is not None and inj_e_rn.Ty is not None:
return own_entry.Ty
# vpi 注入期:CurDefModuleSha1 = **本次注入的 stub 源模块**(inject_class 入口
# 的 mark_module_class 建立)。注入期 trans.ModuleSha1 是"正在翻译的文件",
# 故上面的本模块查找必然落空。此处按同一口径认"被注入 stub 自己声明的类":
# 已登记条目、或先前由指针前向声明建立的具名占位,都返回原型(裸类名恒为原型,
# 见上),使同一 stub 内"先声明/先被引用"的类在后继字段注解里口径一致,不再
# 绕经"联合回退 → 前向声明 → 退化为 Ptr(i8)"那条链。
# 注:此处**不新建**占位——值语义位置凭空建不透明原型会得到不可用布局;
# 占位创建仍归 _forward_declare_ptr_from_node(指针语境)。
if trans is not None and trans.ModuleSha1 is not None:
inj_mod_rn: str = self.Gen.StructGen.CurDefModuleSha1
if inj_mod_rn is not None:
if string.strcmp(inj_mod_rn, trans.ModuleSha1) != 0:
inj_e_rn: GenTypes.StructEntry* = self.Gen.StructGen.find_struct_by_module(nm.id, inj_mod_rn)
if inj_e_rn is not None and inj_e_rn.Ty is not None:
return inj_e_rn.Ty
# from-import 归属查找:注解里的裸名(或 import 别名)经 from_imports 定位到
# 定义模块,再按 (name, sha1) 精确取类——这是 stub 注入场景的正解:此刻
@@ -3365,7 +3365,7 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
# t.CEnum 枚举类非结构体,get_struct_type 查不到)
if self.Gen.StmtGenDecl.is_enum_class(at.attr) == 1:
return self.Gen.StmtGenDecl.get_enum_base_type(at.attr)
# 模块限定 typedef(posix.DIR = t.CTypedef = t\.CVoid|t.CPtr 等):
# 模块限定 typedef(posix.DIR = t.CTypedef = t\.CVoid* 等):
# 与 Name 分支同一套 lookup_ctypedef + 递归解析(单层 Module.Typedef
# 与嵌套 Attribute 都要支持)。
if self.Gen.TypeGenCType.CTypedefResolveDepth < TypeGenMixin.MAX_CTYPEDEF_DEPTH:
@@ -3439,7 +3439,7 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
# BinOp 节点: 联合类型注解 A | B
# 处理三种语义:
# 1. ActualType | t.CPtr → Ptr(ActualType)(指针包装,如 MemBuddy | t.CPtr → MemBuddy*)
# 1. ActualType* → Ptr(ActualType)(指针包装,如 MemBuddy* → MemBuddy*)
# 2. t.CPtr → i8* (void* 等价于 i8*)
# 3. ActualType | DecoratorMarker → ActualType(忽略装饰器标记如 CExport/CExtern)
if k == ast.ASTKind.BinOp:
@@ -3477,20 +3477,20 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
other_is_cvoid = 1
if other_is_cvoid != 0:
return mlirlite.Ptr(pool, mlirlite.Int8(pool))
other_ty: mlirlite.LLVMType* = self.resolve_annotation_type(pool, other_node, imported_modules, from_imports, trans, depth + 1)
# 解析结果本身即 void(如 `typedef 不透明结构体 = void` 的那个名字,
# 或经 typedef 兜底解析出的 void)⇒ 与 CPtr 合并即 void* = i8*,
# 与上方 other_is_cvoid 分支同一结论(否则会拼出非法的 Ptr(void))。
# **必须守 None**:`X*`(parser 展开为 BinOp `X | t.CPtr`)在 Phase 1a
# prescan 时 X 很可能尚未注册(类定义在函数之后),resolve 返回 None;
# 对 None 做 case 匹配会按 REnum tag 解引用空指针(ASan 现场:address 0x0
# READ,栈 _prescan_funcdef_signatures → resolve_annotation_type)。
# None 交由下方既有 `if other_ty is None:` 分支处理。
if other_ty is not None:
match other_ty:
case mlirlite.LLVMType.Void():
return mlirlite.Ptr(pool, mlirlite.Int8(pool))
case _:
other_ty: mlirlite.LLVMType* = self.resolve_annotation_type(pool, other_node, imported_modules, from_imports, trans, depth + 1)
# 解析结果本身即 void(如 `typedef 不透明结构体 = void` 的那个名字,
# 或经 typedef 兜底解析出的 void)⇒ 与 CPtr 合并即 void* = i8*,
# 与上方 other_is_cvoid 分支同一结论(否则会拼出非法的 Ptr(void))。
# **必须守 None**:`X*`(parser 展开为 BinOp `X*`)在 Phase 1a
# prescan 时 X 很可能尚未注册(类定义在函数之后),resolve 返回 None;
# 对 None 做 case 匹配会按 REnum tag 解引用空指针(ASan 现场:address 0x0
# READ,栈 _prescan_funcdef_signatures → resolve_annotation_type)。
# None 交由下方既有 `if other_ty is None:` 分支处理。
if other_ty is not None:
match other_ty:
case mlirlite.LLVMType.Void():
return mlirlite.Ptr(pool, mlirlite.Int8(pool))
case _:
pass
# 仅裸名(Name)场景验证解析结果必须是已注册 struct:
# 损坏节点可能解析出基础类型垃圾(如 Int8 → Ptr(i8))。
@@ -3507,7 +3507,7 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
# 泛型类型参数(T→int 等)经上下文替换解析出的合法标量
# 必须保留——"Name 且未注册 struct 即丢弃"本为拦截损坏
# 节点解析出基础类型垃圾,但会误杀泛型替换的合法标量,
# 导致 T | t.CPtr(T=int)退化为 i8*:list[int] elem_ptr
# 导致 T*(T=int)退化为 i8*:list[int] elem_ptr
# 按 8 字节槽写、elem_size=4 步长读 → 元素互相覆盖,
# pop 读到 0(ListTest 根因)。泛型参数名放行。
keep_other_ty: int = 0
@@ -3523,7 +3523,7 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
keep_other_ty = 1
break
# 内建标量类型名(int/str/bytes/bool/float/double)是合法
# 标量,不是损坏节点解析出的垃圾:int | t.CPtr 应解析为
# 标量,不是损坏节点解析出的垃圾:int* 应解析为
# i32*(int 指针),若按"Name 未注册 struct 即丢弃"踢掉
# int → 联合退化为 i8* → int_ptr[0]=val 写 1 字节截断、
# 读回符号扩展(DictTest key5=500 读出 -12 根因)。
@@ -3547,7 +3547,7 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
# (对齐 TPC HandlesTypeMerge._MergeAllComponentTypes)。
# 指针层数口径(本处 / VpiReader 注入侧 / 调用侧三处必须同步):`| t.CPtr`
# **恒为"追加恰好 1 层指针",无例外**——裸类名恒为原型 struct,
# `X | t.CPtr` 由 Ptr(struct) 天然得到 X*,不再需要"pointee 是已注册
# `X*` 由 Ptr(struct) 天然得到 X*,不再需要"pointee 是已注册
# struct 就吸收这 1 层"的旧补偿(该补偿曾把指针型 T 的 `T*` 降一层)。
if keep_other_ty == 0 and other_node is not None and other_node.kind() == ast.ASTKind.Name:
other_nm_td: ast.Name* = ast.Name*(other_node)
@@ -3569,8 +3569,8 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
other_ty = None
if other_ty is None:
# 严格模式(App 文件)下裸类名不可见时,回退到全局
# struct 注册表按类名查找。X | t.CPtr 是明确的指针包装
# 注解(如 vpi stub 的 "ParsedArgs | t.CPtr"),X 已注册
# struct 注册表按类名查找。X* 是明确的指针包装
# 注解(如 vpi stub 的 "ParsedArgs*"),X 已注册
# 时不应静默退化为 i8*——i8* 会让方法返回值的无注解变量
# (如 args = parser.parse_args())类型退化,后续 obj.method
# get_class_name_by_type 查不到类名,误报
@@ -3599,26 +3599,26 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
if _fwd_ptr_ty is not None:
return _fwd_ptr_ty
return mlirlite.Ptr(pool, mlirlite.Int8(pool))
# `X | t.CPtr` **恒追加恰好 1 层**(用户口径,与 rawptr[T]/t.CPtr[T] 下标形
# `X*` **恒追加恰好 1 层**(用户口径,与 rawptr[T]/t.CPtr[T] 下标形
# 以及 `_parse_type_string` 的 `T*` 反解析三处同源):
# T* ≡ rawptr[T] ≡ t.CPtr[T] ≡ T | t.CPtr
# T* ≡ rawptr[T] ≡ t.CPtr[T] ≡ T*
# 这里原先还有一段"struct 引用语义吸收"(other_ty 若已是 Ptr(已注册 struct)
# 就直接返回它、吞掉 CPtr 这层),那是"裸类名自动升指针"时代的补偿:
# 当时裸类名/引号注解解析成 Ptr(struct),所以要吸收;自 2026-10-01 起
# 裸类名恒为**原型 struct**(见本文件 Name/Attribute 各分支),
# `X | t.CPtr` 由 Ptr(struct) 天然得到 X*,吸收已无正当对象
# `X*` 由 Ptr(struct) 天然得到 X*,吸收已无正当对象
# (json/__init__.vp:90 的引号注解 `'JsonValue' | t.CPtr` 现在 other_ty
# 就是 struct,吸收本就不触发,删除后行为不变)。
# 而**泛型形参实例化为指针类型**时(`list[rawptr[AST]]` 里 `T` 的实参文本是
# `{sha}.AST*`,parser 把源码 `T*` 解析成 BinOp `T | t.CPtr`)other_ty 正是
# `{sha}.AST*`,parser 把源码 `T*` 解析成 BinOp `T*`)other_ty 正是
# Ptr(已注册 struct) ⇒ 误吸收把 `T*` 降成 AST*(应为 AST**),
# 现场 includes/_list.vp:54 `elem_ptr[0] = item` 被误判为"左值元素是对象
# AST(48 字节)、右值是指针"而 fail-fast。
return mlirlite.Ptr(pool, other_ty)
# t.CPtr[...] 下标指针标记(普通 _is_cptr_marker 不识别 Subscript):
# X | t.CPtr[T] → 指针层级合并(对齐 TPC HandlesTypeMerge.py L864-884:
# CPtr 侧贡献 PtrCount,另一侧提供 BaseType),如 uint8 | t.CPtr[t.CPtr] → u8**。
# X*[T] → 指针层级合并(对齐 TPC HandlesTypeMerge.py L864-884:
# CPtr 侧贡献 PtrCount,另一侧提供 BaseType),如 uint8*[t.CPtr] → u8**。
# 不处理会落到"无 CPtr 标记"分支返回左值 i8 → c.Deref 报"参数不是指针类型"。
cptr_sub_side: ast.AST* = None
cptr_other: ast.AST* = None
@@ -3762,7 +3762,7 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
# rawptr[T] 内建裸指针:等价 t.CPtr[T] → Ptr(T)(T 自身可含指针层级)。
# 与 t.CPtr[T] 语义一致;不处理则泛型特化/builtins 兜底失败 →
# "函数返回类型解析失败:注解不可解析"。
# **恒追加 1 层,无例外**:`rawptr[T]` ≡ `t.CPtr[T]` ≡ `T*` ≡ `T | t.CPtr`。
# **恒追加 1 层,无例外**:`rawptr[T]` ≡ `t.CPtr[T]` ≡ `T*` ≡ `T*`。
# 旧实现在此处做"切片是裸类引用(解析结果为 Ptr(已注册 struct))就吸收这层"
# ——那是"裸类名自动升指针"时代的补偿;自 2026-10-01 起裸类名恒为**原型**
# (struct 值),`Ptr(struct)` 天然就是 X*,补偿已无对象,反而在**泛型形参
@@ -3834,7 +3834,7 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
# 指针类型: t.CPtr[T] → Ptr(T)(T 自身可含指针层级):t.CPtr[t.CPtr] → i8**,
# t.CPtr[int] → i32*(DeclarationGenerator.py L1014-1016 文档化语法)。
# **恒追加 1 层,无例外**(与 rawptr[T] 分支同口径):`t.CPtr[T]` ≡ `T*`
# ≡ `T | t.CPtr`。此处原先也做"切片是裸类引用就吸收一层",同 rawptr[T]
# ≡ `T*`。此处原先也做"切片是裸类引用就吸收一层",同 rawptr[T]
# 分支:裸类名恒为原型后该补偿无对象,且会在 T 实例化为指针类型时吃掉
# 真层数(`t.CPtr[T]` 应得 T**)。
if string.strcmp(arr_at.attr, "CPtr") == 0:
@@ -3846,7 +3846,7 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
# 元素类型依赖未就绪(如 t.CPtr[类]/rawptr[类] 中类尚未注册,
# rawptr[T] 经 builtins typedef 归一到本分支):优先**前向声明**
# 具名占位 {sha}.Class 并返回 Ptr(占位.Ty),保住类身份(对齐
# X|t.CPtr 分支与 TPC);无法确定类名/模块时仍返回 None 交上层
# X* 分支与 TPC);无法确定类名/模块时仍返回 None 交上层
# 多遍收敛,不在此 fatal 中断 Phase 1a 预注册(UINT 等只经
# CTypedef 动态表解析)。真实类型错误由 Phase A 收敛检查暴露。
_fwd_cptr_ty: mlirlite.LLVMType* = self._forward_declare_ptr_from_node(
+24 -24
View File
@@ -178,8 +178,8 @@ def SpecSignFromTypeName(name: str) -> int:
# ============================================================
# TypeSpec - 类型描述符
#
# 元素语义三字段(ElemBits/IsElemPtr/DerefBase):`str | t.CPtr`、`bytes | t.CPtr`、
# 泛型 `T | t.CPtr`、`64 位标量 | t.CPtr` 退化后的 LLVM 类型都是单层 Ptr(i8),
# 元素语义三字段(ElemBits/IsElemPtr/DerefBase):`str*`、`bytes*`、
# 泛型 `T*`、`64 位标量 | t.CPtr` 退化后的 LLVM 类型都是单层 Ptr(i8),
# PtrLevel=1 同时对应两种相反语义,仅靠指针层级无法区分 ⇒ 靠「元素宽度 + 元素是否
# 指针 + 基址是否需二次解引用」三元组区分(替代旧的单一布尔 IsPtrElement)。
# ============================================================
@@ -195,10 +195,10 @@ class TypeSpec:
BaseName: str # 结构体/枚举/类名(带模块 sha1;PermPool 深拷贝)
# SourceName: 注解侧「来源名」(替代 AnnotClassName)。
# 与 BaseName 的区别是命名域:BaseName = LLVM 结构体注册名(跨模块/特化时形如
# {16hex sha1}.Class 或 list[...|t.CPtr]),由 SpecFromLLVMType 反推;
# {16hex sha1}.Class 或 list[...*]),由 SpecFromLLVMType 反推;
# SourceName = 注解**书写形态**的名字(裸名 / 模块限定名 / t.XXX 裸 attr 名 /
# Subscript mangled 名),由注解侧 SpecWithSource 填写。
# 为何需要:`X | t.CPtr` 联合被简化为 Ptr(i8) 后 BaseName 恒为 None(类名已丢),
# 为何需要:`X*` 联合被简化为 Ptr(i8) 后 BaseName 恒为 None(类名已丢),
# 而属性访问/方法分派/结构体查找仍要靠注解侧名字恢复。
# **不参与驻留键**:注解名种类远多于类型种类(每个泛型 mangled 名/别名各一份),
# 入键会让 InternSpec 条目暴增且线性查找变慢;驻留本意只是跨 reset 存活,
@@ -268,7 +268,7 @@ def _spec_key_at(keys: bytes, index: int) -> str:
# 槽存 index+1(0=空槽);线性探测,逐槽比较键文本——必须按键内容区分,
# 不能只比哈希(否则冲突键会误命中并返回错误实例)。
# ============================================================
def _spec_index_find(arena: TypeSpecArena | t.CPtr, key: str, h: uint64) -> int:
def _spec_index_find(arena: TypeSpecArena*, key: str, h: uint64) -> int:
"""查驻留哈希索引,命中返回条目下标;未命中返回 -1"""
if arena.Index is None or arena.IndexCap <= 0:
return -1
@@ -294,7 +294,7 @@ def _spec_index_find(arena: TypeSpecArena | t.CPtr, key: str, h: uint64) -> int:
# 返回 0=成功 / 1=索引不可用或已满。仅在追加新条目后调用
# (条目只增不删,故无需墓碑;槽数 > 2*Cap ⇒ 必然存在空槽,探测终止)。
# ============================================================
def _spec_index_insert(arena: TypeSpecArena | t.CPtr, key: str, h: uint64, ei: int) -> int:
def _spec_index_insert(arena: TypeSpecArena*, key: str, h: uint64, ei: int) -> int:
"""把下标 ei 写入驻留哈希索引,返回 0=成功 / 1=不可用"""
if arena.Index is None or arena.IndexCap <= 0:
return 1
@@ -315,7 +315,7 @@ def _spec_index_insert(arena: TypeSpecArena | t.CPtr, key: str, h: uint64, ei: i
# SpecArenaInit - 初始化驻留表(幂等;cap<=0 时用 SPEC_INTERN_MAX)
# 返回 0=成功 / 1=失败(分配失败 fail-fast 由调用方处理,此处返回错误码)
# ============================================================
def SpecArenaInit(arena: TypeSpecArena | t.CPtr, cap: int) -> int:
def SpecArenaInit(arena: TypeSpecArena*, cap: int) -> int:
"""初始化驻留表;已初始化则直接返回 0"""
if arena is None:
return 1
@@ -409,7 +409,7 @@ def _spec_set_struct_name(sp: TypeSpec*, name: str) -> int:
# ============================================================
# NewTypeSpec - 构造基础类型(驻留)
# ============================================================
def NewTypeSpec(arena: TypeSpecArena | t.CPtr, kind: int,
def NewTypeSpec(arena: TypeSpecArena*, kind: int,
bits: int, is_signed: int) -> TypeSpec*:
"""构造基础 TypeSpec 并驻留,失败返回 None"""
sp: TypeSpec* = _spec_make(kind, bits, is_signed)
@@ -421,7 +421,7 @@ def NewTypeSpec(arena: TypeSpecArena | t.CPtr, kind: int,
# ============================================================
# NewTypeStruct - 构造结构体/枚举/类类型(驻留)
# ============================================================
def NewTypeStruct(arena: TypeSpecArena | t.CPtr, kind: int,
def NewTypeStruct(arena: TypeSpecArena*, kind: int,
base_name: str) -> TypeSpec*:
"""构造 struct/union/enum 类型(BaseName 深拷贝 + 驻留),失败返回 None"""
sp: TypeSpec* = _spec_make(kind, 0, TS_SIGN_UNKNOWN)
@@ -435,7 +435,7 @@ def NewTypeStruct(arena: TypeSpecArena | t.CPtr, kind: int,
# ============================================================
# NewTypePtr - 构造指针类型(PtrLevel = 元素 PtrLevel + 1,驻留)
# ============================================================
def NewTypePtr(arena: TypeSpecArena | t.CPtr,
def NewTypePtr(arena: TypeSpecArena*,
elem: TypeSpec*) -> TypeSpec*:
"""构造指针类型:指向 elem(PtrLevel 逐层递增),失败返回 None"""
if elem is None:
@@ -455,7 +455,7 @@ def NewTypePtr(arena: TypeSpecArena | t.CPtr,
# ============================================================
# NewTypeArray - 构造数组类型(ArrayCount 个 elem,驻留)
# ============================================================
def NewTypeArray(arena: TypeSpecArena | t.CPtr, elem: TypeSpec*,
def NewTypeArray(arena: TypeSpecArena*, elem: TypeSpec*,
count: int) -> TypeSpec*:
"""构造数组类型:elem[count](count<=0 表示长度未知/动态),失败返回 None"""
if elem is None or count < 0:
@@ -476,7 +476,7 @@ def NewTypeArray(arena: TypeSpecArena | t.CPtr, elem: TypeSpec*,
# NewTypeFunc - 构造函数签名类型(ret + 参数数组 + 变参,驻留)
# params:TypeSpec* 连续数组(由调用方预先构造并保证存活);count 个
# ============================================================
def NewTypeFunc(arena: TypeSpecArena | t.CPtr, ret: TypeSpec*,
def NewTypeFunc(arena: TypeSpecArena*, ret: TypeSpec*,
params: sizet*, count: int,
is_vararg: int) -> TypeSpec*:
"""构造函数签名类型,失败返回 None"""
@@ -841,7 +841,7 @@ def _text_to_func(text: str, depth: int) -> TypeSpec*:
# 静默丢失类型信息);**键文本**装不下 SPEC_TEXT_MAX → 保留实例但放弃去重
# (绝不写入截断键)。
# ============================================================
def InternSpec(arena: TypeSpecArena | t.CPtr,
def InternSpec(arena: TypeSpecArena*,
sp: TypeSpec*) -> TypeSpec*:
"""按规范文本键驻留 TypeSpec;失败返回 None"""
if arena is None or sp is None:
@@ -958,7 +958,7 @@ def _spec_clone(sp: TypeSpec*) -> TypeSpec*:
#
# 仅当符号性实际变化才复制并驻留,否则返回原实例。驻留去重 ⇒ 同「结构+符号」共享一份。
# ============================================================
def SpecWithSign(arena: TypeSpecArena | t.CPtr,
def SpecWithSign(arena: TypeSpecArena*,
sp: TypeSpec*,
is_signed: int) -> TypeSpec*:
"""复制 sp 并覆盖整数符号性,驻留后返回;无变化返回原实例,失败返回 None"""
@@ -1008,7 +1008,7 @@ def _spec_set_source_name(sp: TypeSpec*, name: str) -> int:
# ============================================================
# SpecWithSource - 复制 Spec 并附上注解侧来源名(独立副本,**不驻留**)
#
# 用途(S4 注解侧填 Spec 的「类名块」):`X | t.CPtr` 简化成 Ptr(i8) 后 Spec 里
# 用途(S4 注解侧填 Spec 的「类名块」):`X*` 简化成 Ptr(i8) 后 Spec 里
# 没有类名,而属性访问/方法分派/结构体查找要靠注解侧名字恢复,故在注解侧把
# 来源名附到 Spec 上(SourceName),供消费点逐步切读(替代 AnnotClassName)。
#
@@ -1035,8 +1035,8 @@ def SpecWithSource(sp: TypeSpec*, name: str) -> TypeSpec*:
# ============================================================
# SpecWithElemBits - 复制 Spec 并覆盖元素槽位宽(独立副本,**不驻留**)
#
# 用途(S4 的 IsPtrElement 替代):`str | t.CPtr` / `bytes | t.CPtr` /
# `T | t.CPtr` / `64 位标量 | t.CPtr` 在 LLVM 层**都是单层 Ptr(i8)**
# 用途(S4 的 IsPtrElement 替代):`str*` / `bytes*` /
# `T*` / `64 位标量 | t.CPtr` 在 LLVM 层**都是单层 Ptr(i8)**
# (PtrLevel=1 同时对应两种相反语义),无法据类型区分"1 字节步长"与
# "8 字节槽步长";区分只能靠注解判定 ⇒ 注解侧把元素槽宽覆盖为 8 字节。
#
@@ -1146,7 +1146,7 @@ def SpecTypeBits(ty: mlirlite.LLVMType*) -> int:
#
# 返回 0=已写入 / 1=不适用或失败(调用方显式处置,不静默兜底)
# ============================================================
SPEC_LLVM_TEXT_MAX_DEPTH: t.CDefine = 100
define SPEC_LLVM_TEXT_MAX_DEPTH = 100
def SpecToLLVMText(sp: TypeSpec*, buf: str, buf_size: sizet) -> int:
@@ -1279,7 +1279,7 @@ def _spec_llvm_text(sp: TypeSpec*, buf: str, buf_size: sizet,
#
# 本函数当前**无调用点**(S2 只入库;接线在后续步骤)。
# ============================================================
def SpecFromLLVMType(arena: TypeSpecArena | t.CPtr,
def SpecFromLLVMType(arena: TypeSpecArena*,
ty: mlirlite.LLVMType*) -> TypeSpec*:
"""把已解析的 LLVM 类型翻译成 TypeSpec;不支持或为 None 时返回 None"""
if arena is None or ty is None:
@@ -1305,7 +1305,7 @@ def SpecFromLLVMType(arena: TypeSpecArena | t.CPtr,
return None
def _spec_from_ptr(arena: TypeSpecArena | t.CPtr,
def _spec_from_ptr(arena: TypeSpecArena*,
pointee: mlirlite.LLVMType*) -> TypeSpec*:
"""Ptr(pointee) → TypeSpec(PtrLevel/ElemBits/IsElemPtr 由 NewTypePtr 填)"""
inner: TypeSpec* = SpecFromLLVMType(arena, pointee)
@@ -1314,7 +1314,7 @@ def _spec_from_ptr(arena: TypeSpecArena | t.CPtr,
return NewTypePtr(arena, inner)
def _spec_from_array(arena: TypeSpecArena | t.CPtr,
def _spec_from_array(arena: TypeSpecArena*,
elem_ty: mlirlite.LLVMType*,
count: int) -> TypeSpec*:
"""[count x elem] → TypeSpec(ArrayCount/ElemBits/IsElemPtr 由 NewTypeArray 填)"""
@@ -1324,7 +1324,7 @@ def _spec_from_array(arena: TypeSpecArena | t.CPtr,
return NewTypeArray(arena, inner, count)
def _spec_from_func(arena: TypeSpecArena | t.CPtr,
def _spec_from_func(arena: TypeSpecArena*,
ret: mlirlite.LLVMType*,
params: mlirlite.ParamNode*,
pcount: int) -> TypeSpec*:
@@ -1354,7 +1354,7 @@ def _spec_from_func(arena: TypeSpecArena | t.CPtr,
return NewTypeFunc(arena, ret_s, params_arr, pcount, 0)
def _spec_from_struct(arena: TypeSpecArena | t.CPtr,
def _spec_from_struct(arena: TypeSpecArena*,
sname: str) -> TypeSpec*:
"""有名结构体 → TS_STRUCT + BaseName;匿名结构体 → 无名 TS_STRUCT"""
if sname is not None:
@@ -1370,7 +1370,7 @@ def _spec_from_struct(arena: TypeSpecArena | t.CPtr,
# ============================================================
def SpecSelfCheck() -> int:
"""TypeSpec 编解码自检,返回 0=通过 / 失败用例号"""
arena: TypeSpecArena | t.CPtr = (TypeSpecArena | t.CPtr)(CompilerFactory.factory.PermPool.alloc(TypeSpecArena.__sizeof__()))
arena: TypeSpecArena* = (TypeSpecArena*)(CompilerFactory.factory.PermPool.alloc(TypeSpecArena.__sizeof__()))
if arena is None:
return 1
string.memset(arena, 0, TypeSpecArena.__sizeof__())
+8 -8
View File
@@ -111,7 +111,7 @@ novirtual class VarGenMixin:
[S4] 原 VarEntry.AnnotClassName 字段已删除,注解名统一承载在 Spec.SourceName:
- 整数符号性:SpecFromLLVMType 反推恒 TS_INT(LLVM iN 不分符号),
注解名携带真实无符号性(uint32/CUInt32T 等)→ 切 TS_INT→TS_UINT;
- 来源名:`X | t.CPtr` 简化为 Ptr(i8) 后 Spec 里没有类名,附上供
- 来源名:`X*` 简化为 Ptr(i8) 后 Spec 里没有类名,附上供
属性访问/方法分派恢复(消费点经 var_annot_class_name 读取)。
类型信息缺失(SpecFromLLVMType 不适用致 Spec 为 None)时建 TS_UNKNOWN
承载注解名 —— TS_UNKNOWN 不表态任何具体类型,等价于原来的"Spec 缺失"。
@@ -151,7 +151,7 @@ novirtual class VarGenMixin:
return TSpec.SpecSourceName(entry.Spec)
# set_var_ptr_element — 标记变量为「指针元素(ptr-element)」语义
# 注解为 bytes|t.CPtr / str|t.CPtr / T|t.CPtr / 64位标量|t.CPtr 的变量,其
# 注解为 bytes* / str* / T* / 64位标量|t.CPtr 的变量,其
# LLVM 类型退化为 i8*(Ptr(Int8)),但下标访问应按 8 字节槽步长(i8** 语义),
# 而非 1 字节步长(i8* 语义)。
# 该语义由 Spec.ElemBits 承载:上述四类在 LLVM 层都是 Ptr(Int8)(ElemBits=8,
@@ -177,7 +177,7 @@ novirtual class VarGenMixin:
# var_is_ptr_element - 变量是否「指针元素」语义(Spec.ElemBits 承载)
# 判据:PtrLevel>=1 且元素位宽为 8(LLVM 层退化后的 i8*)且 ElemBits==64
# (注解侧覆盖的 8 字节槽)。后两个条件缺一不可:真实 i64* 变量 ElemBits 也为 64
# 但 Elem.Bits=64,不命中;纯 str/bytes/char|t.CPtr 变量 ElemBits=8,同样不命中。
# 但 Elem.Bits=64,不命中;纯 str/bytes/char* 变量 ElemBits=8,同样不命中。
def var_is_ptr_element(self, entry: GenTypes.VarEntry*) -> int:
"""变量是否为 ptr-element 语义(1=是 / 0=否)"""
if entry is None or entry.Spec is None:
@@ -754,7 +754,7 @@ novirtual class VarGenMixin:
if pty_chk is None:
self.Gen.TypeGenErr.fatal_error(node, f"REPL: 会话函数 '{func_name}' 第 {ai_chk + 1} 个形参的类型 token 不受支持(M3 支持 iN/float/double/i8*)", "TypeError")
return None
pty_slot: str | t.CPtr = (str | t.CPtr)(uint64(ptypes) + ai_chk * 8)
pty_slot: str* = (str*)(uint64(ptypes) + ai_chk * 8)
pty_slot[0] = pty_chk
# ③ 实参:首实参 = 本片段 ctx,其后按签名类型逐个翻译并 coerce
head: mlirlite.Value* = ctx_val
@@ -767,7 +767,7 @@ novirtual class VarGenMixin:
if arg is None:
self.Gen.TypeGenErr.fatal_error(node, f"REPL: 会话函数 '{func_name}' 的第 {ai + 1} 个实参缺失", "SyntaxError")
return None
pty_slot2: str | t.CPtr = (str | t.CPtr)(uint64(ptypes) + ai * 8)
pty_slot2: str* = (str*)(uint64(ptypes) + ai * 8)
pty: mlirlite.LLVMType* = (mlirlite.LLVMType*)(pty_slot2[0])
arg_val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, arg, None, 0, trans, pty)
if arg_val is None:
@@ -797,7 +797,7 @@ novirtual class VarGenMixin:
for pi in range(arg_count):
cur_ty: mlirlite.LLVMType* = i8_ptr_ty
if pi > 0:
pty_slot3: str | t.CPtr = (str | t.CPtr)(uint64(ptypes) + (pi - 1) * 8)
pty_slot3: str* = (str*)(uint64(ptypes) + (pi - 1) * 8)
cur_ty = (mlirlite.LLVMType*)(pty_slot3[0])
pn: mlirlite.ParamNode* = mlirlite.new_param_node(pool, cur_ty)
if pn is not None:
@@ -831,7 +831,7 @@ novirtual class VarGenMixin:
return None
i8_ty: mlirlite.LLVMType* = mlirlite.Int8(pool)
target_ptr_ty: mlirlite.LLVMType* = mlirlite.Ptr(pool, val_ty)
off_val: mlirlite.Value* = mlirlite.const_int64(pool, t.CInt64T(off))
off_val: mlirlite.Value* = mlirlite.const_int64(pool, int64(off))
if off_val is None:
return None
base: mlirlite.Value* = mlirlite.build_gep(builder, i8_ty, ctx_val, off_val)
@@ -1387,7 +1387,7 @@ novirtual class VarGenMixin:
node: ast.AST*) -> mlirlite.Value*:
"""会话变量取址:返回槽地址(Ptr(值类型))
值只存一份(宿主持有的 ctx arena)且内联在槽里,故 c.Addr(x) 得到的
值只存一份(宿主持有的 ctx arena)且内联在槽里,故 &x 得到的
就是该槽的地址:后续经该指针的读写直接作用于会话变量(地址同一性)。
未登记/未定型/不在片段函数本体返回 None,由调用方继续原有查找与报错路径。
"""
+1 -1
View File
@@ -411,7 +411,7 @@ def _TryResolveModuleFile(inc_dir: str, rel_seg: bytes, rel_len: sizet,
return 0
string.strcpy(inc_buf, inc_dir)
# 写输出槽(stdlib 深拷贝,调用方负责 free)
# 槽联合必须用 (sizet*):t.CPtr|t.CPtr 会被折叠成 t.CPtr,
# 槽联合必须用 (sizet*):t.CPtr* 会被折叠成 t.CPtr,
# [0] 变成 1 字节访问 → 指针被截断(0x2e 崩溃根因)。CSizeT 成员为
# 8 字节,写入用 sizet(ptr) 直接转换;读取用 t\.CVoid(u64, t.CPtr)
# 转回指针(t\.CVoid 仅配合 t.CPtr 表示 void* 强转)。
+31 -31
View File
@@ -91,75 +91,75 @@ _perm_pool: memhub.MemBuddy*
# ⇒ ≤ 1024)+ 包裹头尾开销 512 ⇒ ≤ 26112。
# 缩进是"块路径"的唯一放大项,故上界必须按"行数上界"而非"行数×行长"估;
# 提升行按原文进入模块区(不缩进),其代价低于按 4 空格放大的上界,故不再附加项。
_REPL_FRAG_SRC_CAP: t.CDefine = 26624
define _REPL_FRAG_SRC_CAP = 26624
# 提升出的模块级 def 源码缓冲容量(含 NUL):提升行原文 ≤ 8192 + 注入 ≤ 1024
_REPL_LIFT_CAP: t.CDefine = 12288
define _REPL_LIFT_CAP = 12288
# 单片段最多提升的会话函数数(≤ GenTypes.REPL_FUNC_CAP;超出 ⇒ 明确报错)
_REPL_LIFT_MAX: t.CDefine = 16
define _REPL_LIFT_MAX = 16
# 会话函数名长度上限(写入 ReplLiftNames 的槽宽 = 上限 + 1)
_REPL_FN_NAME_MAX: t.CDefine = 64
define _REPL_FN_NAME_MAX = 64
# 会话函数名表容量(_REPL_LIFT_MAX 个定长槽)
_REPL_FN_NAMES_CAP: t.CDefine = 1024
define _REPL_FN_NAMES_CAP = 1024
# 诊断显示缓冲(把非 NUL 结尾的行/名字截断后供 %s 打印)
_REPL_DIAG_CAP: t.CDefine = 128
define _REPL_DIAG_CAP = 128
# 签名渲染缓冲容量("(int, str) -> int" 最长 ≈ 8×(5+2)+8+8 < 96)
_REPL_SIG_TEXT_CAP: t.CDefine = 192
define _REPL_SIG_TEXT_CAP = 192
# 片段符号名/探针缓冲容量("__repl_frag_<n>" / "llvm.func @<name>(%__repl_ctx__: !llvm.ptr) -> i32")
_REPL_NAME_CAP: t.CDefine = 64
_REPL_NEEDLE_CAP: t.CDefine = 128
define _REPL_NAME_CAP = 64
define _REPL_NEEDLE_CAP = 128
# 临时文件路径缓冲容量(目录/源文件路径)
_REPL_PATH_CAP: t.CDefine = 512
define _REPL_PATH_CAP = 512
# 完整模块 IR 文本容量(与 App/main.vp IR_BUF_SIZE 一致)
_REPL_IR_CAP: t.CDefine = 262144
define _REPL_IR_CAP = 262144
# GetTempPathA 输出缓冲容量(MAX_PATH)
_REPL_TMP_CAP: t.CDefine = 260
define _REPL_TMP_CAP = 260
# 外部命令(clang++ -shared)命令行容量。
# M4 扩容 1024 → 16384:片段链接命令行现在除了宿主 import lib,还要带上**先前
# 片段**的 import lib(每个 ≈ 80~110 字节路径),否则"片段 N 定义的类/方法"在
# 后续片段里是 undefined symbol(见 ReplFragImplibs 段)。
_REPL_CMD_CAP: t.CDefine = 16384
define _REPL_CMD_CAP = 16384
# includes 源文件读取缓冲(与 Phase1.SRC_BUF_SIZE / BuildPipeline.SRC_BUF_SIZE 一致)
_REPL_SRC_BUF_CAP: t.CDefine = 1048576
define _REPL_SRC_BUF_CAP = 1048576
# .vpi 存根缓冲(与 BuildPipeline.PYI_BUF_SIZE 一致)
_REPL_VPI_BUF_CAP: t.CDefine = 262144
define _REPL_VPI_BUF_CAP = 262144
# ---- M4:会话 sha1 / 片段 import lib / 会话基线(CDefine + CTypedef)----
# 先前片段 import lib 的槽数上限(每个"IR 里出现会话前缀符号"的片段最多一条;
# 判据是"出现过"而非"定义过" ⇒ 纯调用片段也会占一个槽,故留足余量)
_REPL_FRAG_IMPLIB_MAX: t.CDefine = 128
define _REPL_FRAG_IMPLIB_MAX = 128
# 片段 import lib 记录数组容量(槽数 × 8 字节指针)
_REPL_FRAG_IMPLIB_ARR_CAP: t.CDefine = 1024
define _REPL_FRAG_IMPLIB_ARR_CAP = 1024
# 会话基线(CDefine)条目上限:每片段重建表时按基线回灌
_REPL_BASE_CDEFINE_MAX: t.CDefine = 512
define _REPL_BASE_CDEFINE_MAX = 512
# 会话基线(CTypedef)条目上限
_REPL_BASE_CTYPEDEF_MAX: t.CDefine = 512
define _REPL_BASE_CTYPEDEF_MAX = 512
# includes 类注册(会话初始化做一次):参与 vpi 注入的模块数上限
_REPL_INC_CLS_MOD_MAX: t.CDefine = 512
define _REPL_INC_CLS_MOD_MAX = 512
# includes 类注册的收敛遍数(字段类型依赖同批其它类 ⇒ 多遍收敛)
_REPL_INC_CLS_PASSES: t.CDefine = 3
define _REPL_INC_CLS_PASSES = 3
# includes 类注册的结构体表水位守卫(STRUCT_MAX = 512;预留余量)
_REPL_INC_CLS_STRUCT_GUARD: t.CDefine = 448
define _REPL_INC_CLS_STRUCT_GUARD = 448
# includes 类注册的逐模块告警行上限(超出只累计计数,由汇总行给出总数)
_REPL_INC_CLS_WARN_MAX: t.CDefine = 3
define _REPL_INC_CLS_WARN_MAX = 3
# includes 类注册(会话初始化)的启动时间预算(ms):多遍 vpi 注入 + 逐类布局校验是
# 会话启动的主要耗时,且失败模块会在后续遍重试 ⇒ 模块数 × 遍数的上界虽有限,但
# 上界本身可能很长(缺存根时每模块仍要读一遍 .vpi + 解析 + 注入了 declare)。
# 超预算即停止"启动期注册",剩余模块留待片段 `import` 时按既有 on-demand 路径注册。
# 取舍:宁可让部分 includes 类在启动后仍不可用(且明确告知),也不能让启动"看起来
# 死了"——提示符必须先出现(REPL 可用性 > 启动期注册完整度)。
_REPL_INC_CLS_BUDGET_MS: t.CDefine = 20000
define _REPL_INC_CLS_BUDGET_MS = 20000
# includes 类注册用的临时 LLVM 模块名(.vpi 注入的目标模块,会话初始化时一次)
_REPL_INC_MOD_NAME: t.CDefine = "repl_inc_init"
define _REPL_INC_MOD_NAME = "repl_inc_init"
# ctx 会话缓冲字节数 = 固定头 64 + 槽数上限 64 × 槽步长 16
#(M3 追加函数指针槽区:+ 函数上限 32 × 槽步长 16 ⇒ 64 + 1024 + 512 = 1600)
# 必须与 GenTypes.REPL_CTX_SIZE / REPL_SLOT_BASE / REPL_VAR_CAP / REPL_SLOT_SIZE /
# REPL_FUNC_BASE / REPL_FUNC_CAP / REPL_FUNC_SLOT_SIZE 一致
_REPL_CTX_SIZE: t.CDefine = 1600
define _REPL_CTX_SIZE = 1600
# 模板工程文件名(--repl 未给 --project 时在 cwd → exe 同目录查找)
_REPL_PROJECT_FILE: t.CDefine = "repl.vpj"
define _REPL_PROJECT_FILE = "repl.vpj"
# cwd 候选后缀:GetCurrentDirectoryA 返回值不含结尾分隔符,故须补 '/'
_REPL_PROJECT_SEP_FILE: t.CDefine = "/repl.vpj"
define _REPL_PROJECT_SEP_FILE = "/repl.vpj"
# 上述两种后缀的最长长度 + NUL 余量(候选缓冲余量检查用)
_REPL_PROJECT_PROBE_CAP: t.CDefine = 16
define _REPL_PROJECT_PROBE_CAP = 16
# ============================================================
@@ -175,7 +175,7 @@ novirtual class ReplFloatView:
Version: int
Kind: int
Reserved0: int
F: t.CDouble
F: double
# ============================================================
@@ -1998,7 +1998,7 @@ def _repl_entry_sig_text(e: rawptr[GenTypes.ReplFuncEntry]) -> str:
# 注册(DLL 加载成功后调用):GetProcAddress(裸名) → 写 ctx 函数指针槽 → 追加/更新表
# 返回 0=成功;1=失败(已打印;调用方按 ReplSavedFuncCount 回滚表水位后放弃本片段)
def _repl_register_session_funcs(h_lib: win32base.HANDLE, frag_no: int,
def _repl_register_session_funcs(h_lib: win32base.HANDLE, frag_no: int,
mod: mlirlite.LLVMModule*) -> int:
if ReplLiftNameCount <= 0:
return 0