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:
1 parent
9717ce0107
commit
185a2196ca
57 files changed
+1078
-1078
No files matched your search
@@ -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
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;误报无害(最多多编译两个空壳模块)。
|
||||
# ============================================================
|
||||
|
||||
|
||||
@@ -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,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
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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 前缀的依赖函数名与本文件同名声明不会相互顶替。
|
||||
|
||||
@@ -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 到栈缓冲并返回
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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] == '*'):
|
||||
|
||||
@@ -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]
|
||||
@@ -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'
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 与右邻
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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 防重复检查会拦截补译,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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* 双向互转都放行;
|
||||
|
||||
@@ -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))
|
||||
@@ -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] == '*'):
|
||||
|
||||
@@ -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 数据区
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
# 无返回类型注解 → 无返回值过程函数,默认零值返回
|
||||
|
||||
@@ -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
|
||||
# 递归遍历常见表达式子节点
|
||||
|
||||
@@ -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 # 最近执行的片段号(宿主写,供检视)
|
||||
@@ -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,
|
||||
|
||||
@@ -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 链需把
|
||||
|
||||
@@ -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};"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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__())
|
||||
|
||||
@@ -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,由调用方继续原有查找与报错路径。
|
||||
"""
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
Reference in new issue
Block a user