chore(messages): TransPyV 运行时中文字符串英文化
把 TransPyV/App 下 57 个文件的运行时中文字符串(编译器报错/告警/日志、CLI 帮助与横幅、REPL 提示、Phase1/Phase2 流程日志、Codegen 各 Mixin 的类型与调用报错、Stub/Vpi 诊断等)共 1091 行译为英文。 口径:只改字符串字面量内部文字,行数零变化(+1092/-1092);printf 格式符与转义序列多重集合校验不变(_strcheck 异常 0);译文不引入撇号以免干扰单引号字面量解析。验证:三重重编 SUCCESS(136.20s)+ 全量 77/77 顺序回归通过 + VET 编译 SUCCESS / --search-paths 7 条 exit 0;新产物 help/日志输出已为英文。
This commit is contained in:
1 parent
0cf80632c1
commit
7a9bc5ae75
57 files changed
+1092
-1092
No files matched your search
@@ -85,7 +85,7 @@ def _append_traceback_dbghelp(linker_flags: str) -> str:
|
||||
need: sizet = string.strlen(linker_flags) + 16
|
||||
buf: str = _mbuddy.alloc(need)
|
||||
if buf is None:
|
||||
VLogger.error("--traceback: -ldbghelp 链接参数缓冲分配失败,终止编译", "TRACEBACK")
|
||||
VLogger.error("--traceback: failed to allocate -ldbghelp linker argument buffer, aborting compilation", "TRACEBACK")
|
||||
return linker_flags
|
||||
viperlib.snprintf(buf, need, "%s -ldbghelp", linker_flags)
|
||||
return buf
|
||||
@@ -105,11 +105,11 @@ def _tb_register_vpcall(path: str) -> int:
|
||||
if _tb_vpcall_buf is None:
|
||||
_tb_vpcall_buf = stdlib.malloc(sizet(TB_VPCALL_MAX) * 8)
|
||||
if _tb_vpcall_buf is None:
|
||||
VLogger.error("--traceback: .vpcall 路径表分配失败,终止编译", "TRACEBACK")
|
||||
VLogger.error("--traceback: failed to allocate .vpcall path table, aborting compilation", "TRACEBACK")
|
||||
return 1
|
||||
_tb_vpcall_n = 0
|
||||
if _tb_vpcall_n >= TB_VPCALL_MAX:
|
||||
VLogger.error("--traceback: .vpcall 路径表溢出(模块数超上限),终止编译", "TRACEBACK")
|
||||
VLogger.error("--traceback: .vpcall path table overflow (module count exceeds limit), aborting compilation", "TRACEBACK")
|
||||
return 1
|
||||
slot: str* = (str*)(uint64(_tb_vpcall_buf) + sizet(_tb_vpcall_n) * 8)
|
||||
slot[0] = path
|
||||
@@ -122,11 +122,11 @@ def WriteCallSidecar(temp_dir: str, sha1: str, text: str) -> int:
|
||||
if temp_dir is None or sha1 is None or text is None: return 0
|
||||
vpath: str = StubMergerCollect._sliced_path(temp_dir, string.strlen(temp_dir), sha1, "vpcall")
|
||||
if vpath is None:
|
||||
VLogger.error(f"--traceback: .vpcall 路径构造失败(sha1={sha1}),终止编译", "TRACEBACK")
|
||||
VLogger.error(f"--traceback: failed to build .vpcall path (sha1={sha1}), aborting compilation", "TRACEBACK")
|
||||
return 1
|
||||
vf: fileio.File* = fileio.File(vpath, fileio.MODE.W)
|
||||
if vf.closed:
|
||||
VLogger.error(f"--traceback: 写出 .vpcall 失败(无法打开 {vpath}),终止编译", "TRACEBACK")
|
||||
VLogger.error(f"--traceback: failed to write .vpcall (cannot open {vpath}), aborting compilation", "TRACEBACK")
|
||||
stdlib.free(vpath)
|
||||
return 1
|
||||
vf.write(text, string.strlen(text))
|
||||
@@ -154,7 +154,7 @@ def TranslateFileGetTrans(mb: memhub.MemBuddy*, file_path: str, sha1_val: str, c
|
||||
# read_all's capacity includes the terminator (reads cap-1 bytes max) and silently
|
||||
# truncates longer files; reject by size first, else parsing gets confusing syntax errors.
|
||||
if f.size() >= SRC_BUF_SIZE:
|
||||
VLogger.error(f"源文件超过 {SRC_BUF_SIZE} 字节上限, 拒绝读取: {file_path}", "fileio")
|
||||
VLogger.error(f"source file exceeds {SRC_BUF_SIZE} byte limit, refusing to read: {file_path}", "fileio")
|
||||
f.close()
|
||||
return None
|
||||
src_buf: bytes = stdlib.malloc(SRC_BUF_SIZE)
|
||||
@@ -179,7 +179,7 @@ def TranslateFileGetTrans(mb: memhub.MemBuddy*, file_path: str, sha1_val: str, c
|
||||
GenApi.dump_parse_traceback(file_path)
|
||||
err_line: int = ast.get_parse_err_line()
|
||||
err_col: int = ast.get_parse_err_col()
|
||||
VLogger.error(f"解析失败: {file_path} (line {err_line} col {err_col})", "PARSE")
|
||||
VLogger.error(f"parse failed: {file_path} (line {err_line} col {err_col})", "PARSE")
|
||||
return None
|
||||
# Generate the .vpi stub from the AST before tr.translate (same as Phase1); it lets
|
||||
# other modules query function signatures and CTypedef definitions.
|
||||
@@ -247,7 +247,7 @@ def TranslateFileGetTrans(mb: memhub.MemBuddy*, file_path: str, sha1_val: str, c
|
||||
if gen is not None: gen.ExprGenCls.extract_module_docstrings(tree, sha1_val)
|
||||
ret: int = tr.translate(tree)
|
||||
if ret != 0:
|
||||
VLogger.error(f"文件翻译失败: {file_path}", "Translate")
|
||||
VLogger.error(f"file translation failed: {file_path}", "Translate")
|
||||
return None
|
||||
# --traceback: for includes/traceback.vp, inject the startup Install() ctor into its IR.
|
||||
# The injector lives in the Gen layer, so no new cross-module mlirlite dependency.
|
||||
@@ -385,11 +385,11 @@ def compile_ll_to_obj(ir_path: str, output_dir: str, module_name: str, cc_cmd: s
|
||||
else:
|
||||
mo_rc: int = _run_cmd_wait(cmd_mo)
|
||||
if mo_rc != 0:
|
||||
VLogger.error(f"mlir-opt 失败 (module={module_name}, exit={mo_rc}, cmd={cmd_mo})", "MLIR")
|
||||
VLogger.error(f"mlir-opt failed (module={module_name}, exit={mo_rc}, cmd={cmd_mo})", "MLIR")
|
||||
return 1
|
||||
mt_rc: int = _run_cmd_wait(cmd_mt)
|
||||
if mt_rc != 0:
|
||||
VLogger.error(f"mlir-translate 失败 (module={module_name}, exit={mt_rc}, cmd={cmd_mt})", "MLIR")
|
||||
VLogger.error(f"mlir-translate failed (module={module_name}, exit={mt_rc}, cmd={cmd_mt})", "MLIR")
|
||||
return 1
|
||||
compile_input = ll_local_path
|
||||
|
||||
@@ -422,7 +422,7 @@ def compile_ll_to_obj(ir_path: str, output_dir: str, module_name: str, cc_cmd: s
|
||||
viperlib.snprintf(opt_cmd, opt_cmd_len, "opt -passes=forceattrs,asan -force-attribute=sanitize_address -asan-globals=false -o %s %s", asan_path, compile_input)
|
||||
opt_ret: int = stdlib.system(opt_cmd)
|
||||
if opt_ret != 0:
|
||||
VLogger.error(f"opt ASan 插桩失败 (module={module_name})", "ASAN")
|
||||
VLogger.error(f"opt ASan instrumentation failed (module={module_name})", "ASAN")
|
||||
return 1
|
||||
compile_input = asan_path
|
||||
|
||||
@@ -437,7 +437,7 @@ def compile_ll_to_obj(ir_path: str, output_dir: str, module_name: str, cc_cmd: s
|
||||
# inherits the console. On failure, log module sha1 + exit code + full command.
|
||||
sys_ret: int = _run_cmd_wait(cmd)
|
||||
if sys_ret != 0:
|
||||
VLogger.error(f"编译失败 (module={module_name}, exit={sys_ret}, cmd={cmd})", "LLC")
|
||||
VLogger.error(f"compilation failed (module={module_name}, exit={sys_ret}, cmd={cmd})", "LLC")
|
||||
return 1
|
||||
return 0
|
||||
|
||||
@@ -545,7 +545,7 @@ def _phase2_write_cmd(cmd: str) -> None:
|
||||
if _phase2_cmd_path is None or cmd is None: return
|
||||
f: fileio.File* = fileio.File(_phase2_cmd_path, fileio.MODE.A)
|
||||
if f.closed:
|
||||
VLogger.error("phase2command: bat 打开失败", "phase2cmd")
|
||||
VLogger.error("phase2command: failed to open bat", "phase2cmd")
|
||||
return
|
||||
if _phase2_bat_init == 0:
|
||||
_phase2_bat_init = 1
|
||||
@@ -584,7 +584,7 @@ def _run_cmd_wait(cmd: str) -> int:
|
||||
# it). Use warning, not error (error would sys.exit in a worker thread).
|
||||
if ok == 0:
|
||||
cp_err: uint32 = w32.win32base.GetLastError()
|
||||
VLogger.warning(f"CreateProcessA 失败 (GetLastError={cp_err}) 外部命令未启动: cmd={cmd}", "LLC")
|
||||
VLogger.warning(f"CreateProcessA failed (GetLastError={cp_err}) external command not started: cmd={cmd}", "LLC")
|
||||
stdlib.free(cmd_line)
|
||||
if ok == 0: return -1
|
||||
win32sync.WaitForSingleObject(pi.hProcess, w32.win32base.INFINITE)
|
||||
@@ -644,14 +644,14 @@ def run_llc_parallel(tasks: bytes, task_count: int, max_threads: int) -> int:
|
||||
if tsk_p.MlirTranslateCmd is not None: _phase2_write_cmd(tsk_p.MlirTranslateCmd)
|
||||
if tsk_p.OptCmd is not None: _phase2_write_cmd(tsk_p.OptCmd)
|
||||
if tsk_p.LlcCmd is not None: _phase2_write_cmd(tsk_p.LlcCmd)
|
||||
VLogger.info(f"phase2command 模式:{task_count} 条 llc 命令已写入 {_phase2_cmd_path}", "phase2cmd")
|
||||
VLogger.info(f"phase2command mode: {task_count} llc commands written to {_phase2_cmd_path}", "phase2cmd")
|
||||
return 0
|
||||
if max_threads <= 0: max_threads = 1
|
||||
# Thread-handle array: list[str] (str=bytes=i8*, explicit elem_size=8) stores handles;
|
||||
# list[t.CPtr] append crashes reading page zero. Grab the handle right after start().
|
||||
handles: list[str]* = list[str](_mbuddy, 8)
|
||||
if handles is None:
|
||||
VLogger.error("run_llc_parallel: 线程句柄数组分配失败", "PhaseB")
|
||||
VLogger.error("run_llc_parallel: failed to allocate thread handle array", "PhaseB")
|
||||
return 1
|
||||
slot_size: sizet = LlcTask.__sizeof__()
|
||||
ret: int = 0
|
||||
@@ -670,7 +670,7 @@ def run_llc_parallel(tasks: bytes, task_count: int, max_threads: int) -> int:
|
||||
for j in range(batch_n):
|
||||
h_j: t.CPtr = t.CPtr(handles.get(batch_start + j))
|
||||
wr: uint32 = win32sync.WaitForSingleObject(h_j, 600000)
|
||||
if wr != 0: VLogger.error("llc 线程 join 超时/失败(600 秒未完成)", "PhaseB")
|
||||
if wr != 0: VLogger.error("llc thread join timeout/failure (not finished within 600 seconds)", "PhaseB")
|
||||
w32.win32base.CloseHandle(h_j)
|
||||
# check this batch's results
|
||||
for j in range(batch_n):
|
||||
@@ -679,21 +679,21 @@ def run_llc_parallel(tasks: bytes, task_count: int, max_threads: int) -> int:
|
||||
# Failure: use FailStage to pinpoint the step and print that step's command.
|
||||
# Previously everything printed the LlcCmd as "llc failed", misdirecting MLIR failures.
|
||||
st: int = tsk2.FailStage
|
||||
stage_name: str = "未知阶段(worker 未跑完)"
|
||||
stage_name: str = "unknown stage (worker did not finish)"
|
||||
stage_cmd: bytes = tsk2.LlcCmd
|
||||
if st == LLC_STAGE_MLIR_OPT:
|
||||
stage_name = "mlir-opt 校验"
|
||||
stage_name = "mlir-opt validation"
|
||||
stage_cmd = tsk2.MlirOptCmd
|
||||
elif st == LLC_STAGE_MLIR_TRANSLATE:
|
||||
stage_name = "mlir-translate 降级"
|
||||
stage_name = "mlir-translate lowering"
|
||||
stage_cmd = tsk2.MlirTranslateCmd
|
||||
elif st == LLC_STAGE_ASAN_OPT:
|
||||
stage_name = "opt ASan 插桩"
|
||||
stage_name = "opt ASan instrumentation"
|
||||
stage_cmd = tsk2.OptCmd
|
||||
elif st == LLC_STAGE_LLC:
|
||||
stage_name = "llc 编译"
|
||||
stage_name = "llc compile"
|
||||
stage_cmd = tsk2.LlcCmd
|
||||
VLogger.error(f"{stage_name}失败: {(tsk2.ModuleSha1 if tsk2.ModuleSha1 is not None else "?")} (exit={tsk2.ExitCode} cmd={(stage_cmd if stage_cmd is not None else "?")})", "LLC")
|
||||
VLogger.error(f"{stage_name} failed: {(tsk2.ModuleSha1 if tsk2.ModuleSha1 is not None else "?")} (exit={tsk2.ExitCode} cmd={(stage_cmd if stage_cmd is not None else "?")})", "LLC")
|
||||
ret = 1
|
||||
return ret
|
||||
|
||||
@@ -702,20 +702,20 @@ def _CollectObjFilesImpl(base_dir: str, bd_len: sizet, out_buf: bytes, out_pos:
|
||||
"""Recursively scan base_dir, collect .obj paths into out_buf, return the new out_pos."""
|
||||
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")
|
||||
VLogger.warning("_CollectObjFilesImpl failed to allocate find_data, fewer .obj collected", "collect")
|
||||
return out_pos
|
||||
string.memset(find_data, 0, w32.win32file.WIN32_FIND_DATAA.__sizeof__())
|
||||
|
||||
pattern: bytes = _mbuddy.alloc(bd_len + 8)
|
||||
if pattern is None:
|
||||
VLogger.warning("_CollectObjFilesImpl 分配 pattern 失败,少收集 .obj", "collect")
|
||||
VLogger.warning("_CollectObjFilesImpl failed to allocate pattern, fewer .obj collected", "collect")
|
||||
return out_pos
|
||||
viperlib.snprintf(pattern, bd_len + 8, "%s/*", base_dir)
|
||||
|
||||
handle: w32.win32base.HANDLE = w32.win32file.FindFirstFileA(pattern, find_data)
|
||||
_mbuddy.free(pattern)
|
||||
if handle == w32.win32base.INVALID_HANDLE_VALUE:
|
||||
VLogger.warning("_CollectObjFilesImpl 无法打开目录,少收集 .obj", "collect")
|
||||
VLogger.warning("_CollectObjFilesImpl cannot open directory, fewer .obj collected", "collect")
|
||||
return out_pos
|
||||
|
||||
while True:
|
||||
@@ -774,10 +774,10 @@ def _append_host_export_implib(linker_flags: str, implib_path: str) -> str:
|
||||
extra: sizet = string.strlen(" -Wl,--out-implib=") + string.strlen(implib_path) + 1
|
||||
buf: str = _mbuddy.alloc(string.strlen(linker_flags) + extra)
|
||||
if buf is None:
|
||||
VLogger.warning("宿主导出:import lib 参数缓冲分配失败(片段将无法导入宿主符号)", "link")
|
||||
VLogger.warning("host export: failed to allocate import lib argument buffer (fragments cannot import host symbols)", "link")
|
||||
return linker_flags
|
||||
viperlib.snprintf(buf, string.strlen(linker_flags) + extra, "%s -Wl,--out-implib=%s", linker_flags, implib_path)
|
||||
VLogger.info(f"宿主导出:产出 import lib {implib_path}", "link")
|
||||
VLogger.info(f"host export: produced import lib {implib_path}", "link")
|
||||
return buf
|
||||
|
||||
|
||||
@@ -808,8 +808,8 @@ def link_obj_to_exe(output_dir: str, module_name: str, linker_cmd: str, linker_f
|
||||
extra_len: sizet = 0
|
||||
if includes_binary_dir is not None:
|
||||
extra_len = collect_obj_files(includes_binary_dir, extra_objs, EXTRA_BUF_SIZE)
|
||||
if extra_len > 0: VLogger.info(f"附加 {extra_len} 字节的 includes.binary .obj 文件", "link")
|
||||
else: VLogger.warning(f"includes.binary 无 .obj 文件: {includes_binary_dir}", "link")
|
||||
if extra_len > 0: VLogger.info(f"appended {extra_len} bytes of includes.binary .obj files", "link")
|
||||
else: VLogger.warning(f"includes.binary has no .obj files: {includes_binary_dir}", "link")
|
||||
|
||||
# Command: clang++ {obj_path} extra_objs [libs] -o {...}/{linker_output} linker_flags. Objects
|
||||
# and explicit libs must precede -l flags. The ASan runtime is declared in project.vpj, not hardcoded.
|
||||
@@ -846,15 +846,15 @@ def link_obj_to_exe(output_dir: str, module_name: str, linker_cmd: str, linker_f
|
||||
|
||||
result: subprocess.CompletedProcess* = subprocess.run(cmd, True, True)
|
||||
if result is None:
|
||||
VLogger.error("subprocess.run 返回 None", "link")
|
||||
VLogger.error("subprocess.run returned None", "link")
|
||||
return 1
|
||||
if result.returncode != 0:
|
||||
VLogger.error(f"链接失败,返回码: {result.returncode}", "link")
|
||||
VLogger.error(f"命令: {cmd}", "link")
|
||||
VLogger.error(f"link failed, return code: {result.returncode}", "link")
|
||||
VLogger.error(f"command: {cmd}", "link")
|
||||
# Show linker error output.
|
||||
# Note: subprocess merges stderr into stdout on Windows, so result.stderr is always None.
|
||||
if result.stdout is not None: VLogger.error(result.stdout, "link")
|
||||
else: VLogger.error("无输出捕获", "link")
|
||||
else: VLogger.error("no output captured", "link")
|
||||
if result.stderr is not None: VLogger.error(result.stderr, "link")
|
||||
return 1
|
||||
return 0
|
||||
@@ -879,12 +879,12 @@ def asm_to_obj(asm_path: str, sha1_val: str, output_dir: str, triple: str) -> in
|
||||
|
||||
result: subprocess.CompletedProcess* = subprocess.run(cmd, True, True)
|
||||
if result is None:
|
||||
VLogger.error("llvm-mc subprocess.run 返回 None", "asm")
|
||||
VLogger.error("llvm-mc subprocess.run returned None", "asm")
|
||||
return 1
|
||||
if result.returncode != 0:
|
||||
if result.stdout is not None: stdio.printf("%s\n", result.stdout)
|
||||
if result.stderr is not None: stdio.printf("%s\n", result.stderr)
|
||||
VLogger.error(f"llvm-mc 汇编失败,返回码: {result.returncode}, 命令: {cmd}", "asm")
|
||||
VLogger.error(f"llvm-mc assembly failed, return code: {result.returncode}, command: {cmd}", "asm")
|
||||
return 1
|
||||
return 0
|
||||
|
||||
@@ -896,7 +896,7 @@ def compile_module_to_obj(ir_buf: bytes, ir_len: sizet, temp_dir: str, output_di
|
||||
# Step 1: write the .ll file
|
||||
ret: int = write_ir_to_file(ir_buf, ir_len, temp_dir, module_name)
|
||||
if ret != 0:
|
||||
VLogger.error(f"写 .ll 失败: {module_name}", "compile")
|
||||
VLogger.error(f"failed to write .ll: {module_name}", "compile")
|
||||
return 1
|
||||
|
||||
# Step 2: build the sliced .ll path and compile -> .obj
|
||||
@@ -905,7 +905,7 @@ def compile_module_to_obj(ir_buf: bytes, ir_len: sizet, temp_dir: str, output_di
|
||||
|
||||
ret = compile_ll_to_obj(ir_path, output_dir, module_name, cc_cmd, cc_flags)
|
||||
if ret != 0:
|
||||
VLogger.error(f"llc 编译失败: {module_name}", "compile")
|
||||
VLogger.error(f"llc compilation failed: {module_name}", "compile")
|
||||
return 1
|
||||
return 0
|
||||
|
||||
@@ -1008,15 +1008,15 @@ def link_objs_to_exe(obj_paths: str, obj_paths_len: sizet, linker_cmd: str, link
|
||||
return 0
|
||||
result: subprocess.CompletedProcess* = subprocess.run(cmd, True, True)
|
||||
if result is None:
|
||||
VLogger.error("subprocess.run 返回 None", "link")
|
||||
VLogger.error("subprocess.run returned None", "link")
|
||||
return 1
|
||||
if result.returncode != 0:
|
||||
# First print clang++'s full error output (incl. undefined reference) with stdio.printf;
|
||||
# it must precede VLogger.error, which calls sys.exit(1) and terminates the process.
|
||||
if result.stdout is not None: stdio.printf("=== clang++ 链接错误输出 ===\n%s\n", result.stdout)
|
||||
if result.stdout is not None: stdio.printf("=== clang++ link error output ===\n%s\n", result.stdout)
|
||||
if result.stderr is not None:
|
||||
stdio.printf("=== clang++ stderr ===\n%s\n", result.stderr)
|
||||
VLogger.error(f"链接失败,返回码: {result.returncode}, 命令: {cmd}", "link")
|
||||
VLogger.error(f"link failed, return code: {result.returncode}, command: {cmd}", "link")
|
||||
return 1
|
||||
return 0
|
||||
|
||||
@@ -1347,7 +1347,7 @@ def _tb_emit_row(mb: memhub.MemBuddy*, d: TbDump*, addr: uint64, path: str, line
|
||||
ncap: int = d.RowCap * 2
|
||||
nb: bytes = _tb_grow_rec(mb, d.RowBuf, d.RowCap, TB_ROW_SIZE, ncap)
|
||||
if nb is None:
|
||||
VLogger.error("--traceback: DWARF 行记录表扩容失败,终止编译", "TRACEBACK")
|
||||
VLogger.error("--traceback: failed to grow DWARF line record table, aborting compilation", "TRACEBACK")
|
||||
return 1
|
||||
d.RowBuf = nb
|
||||
d.RowCap = ncap
|
||||
@@ -1369,7 +1369,7 @@ def _tb_emit_func(mb: memhub.MemBuddy*, d: TbDump*, low: uint64, high: uint64, n
|
||||
ncap: int = d.FuncCap * 2
|
||||
nb: bytes = _tb_grow_rec(mb, d.FuncBuf, d.FuncCap, TB_FUNC_SIZE, ncap)
|
||||
if nb is None:
|
||||
VLogger.error("--traceback: DWARF 子程序表扩容失败,终止编译", "TRACEBACK")
|
||||
VLogger.error("--traceback: failed to grow DWARF subprogram table, aborting compilation", "TRACEBACK")
|
||||
return 1
|
||||
d.FuncBuf = nb
|
||||
d.FuncCap = ncap
|
||||
@@ -1478,7 +1478,7 @@ def _tb_parse_dump(mb: memhub.MemBuddy*, dump: str) -> TbDump*:
|
||||
files: bytes = mb.alloc(sizet(TB_FILE_CAP) * TB_FILE_SIZE)
|
||||
linebuf: bytes = mb.alloc(LINE_CAP)
|
||||
if d.RowBuf is None or d.FuncBuf is None or dirs is None or files is None or linebuf is None:
|
||||
VLogger.error("--traceback: dwarfdump 解析缓冲分配失败,终止编译", "TRACEBACK")
|
||||
VLogger.error("--traceback: failed to allocate dwarfdump parse buffer, aborting compilation", "TRACEBACK")
|
||||
return None
|
||||
|
||||
in_line: int = 0
|
||||
@@ -1778,7 +1778,7 @@ def _tb_cp_add_cr(mb: memhub.MemBuddy*, cp: TbCallParse*, caller: str, callee: s
|
||||
ncap: int = cp.CrCap * 2
|
||||
nb: bytes = _tb_grow_rec(mb, cp.Cr, cp.CrCap, TB_CR_SIZE, ncap)
|
||||
if nb is None:
|
||||
VLogger.error("--traceback: 调用记录表扩容失败,终止编译", "TRACEBACK")
|
||||
VLogger.error("--traceback: failed to grow call record table, aborting compilation", "TRACEBACK")
|
||||
return 1
|
||||
cp.Cr = nb
|
||||
cp.CrCap = ncap
|
||||
@@ -1797,7 +1797,7 @@ def _tb_cp_add_fr(mb: memhub.MemBuddy*, cp: TbCallParse*, sym: str, file: str, d
|
||||
ncap: int = cp.FrCap * 2
|
||||
nb: bytes = _tb_grow_rec(mb, cp.Fr, cp.FrCap, TB_FR_SIZE, ncap)
|
||||
if nb is None:
|
||||
VLogger.error("--traceback: 函数记录表扩容失败,终止编译", "TRACEBACK")
|
||||
VLogger.error("--traceback: failed to grow function record table, aborting compilation", "TRACEBACK")
|
||||
return 1
|
||||
cp.Fr = nb
|
||||
cp.FrCap = ncap
|
||||
@@ -1877,7 +1877,7 @@ def _tb_parse_c_line(mb: memhub.MemBuddy*, s: str, a: sizet, b: sizet, cp: TbCal
|
||||
def _tb_parse_vpcall_file(mb: memhub.MemBuddy*, path: str, cp: TbCallParse*) -> int:
|
||||
whole: str = _tb_read_whole(mb, path)
|
||||
if whole is None:
|
||||
VLogger.error(f"--traceback: 读取 .vpcall 失败:{path},终止编译", "TRACEBACK")
|
||||
VLogger.error(f"--traceback: failed to read .vpcall: {path}, aborting compilation", "TRACEBACK")
|
||||
return 1
|
||||
n: sizet = string.strlen(whole)
|
||||
pos: sizet = 0
|
||||
@@ -1912,7 +1912,7 @@ def _tb_build_groups(mb: memhub.MemBuddy*, cp: TbCallParse*) -> int:
|
||||
cp.GrpCap = _tb_next_pow2(cp.CrN * 2 + 16)
|
||||
cp.Grp = mb.alloc(sizet(cp.GrpCap) * TB_GRP_SIZE)
|
||||
if cp.Grp is None:
|
||||
VLogger.error("--traceback: 调用点分组表分配失败,终止编译", "TRACEBACK")
|
||||
VLogger.error("--traceback: failed to allocate call-site group table, aborting compilation", "TRACEBACK")
|
||||
return 1
|
||||
string.memset(cp.Grp, 0, sizet(cp.GrpCap) * TB_GRP_SIZE)
|
||||
for i in range(cp.CrN):
|
||||
@@ -1921,7 +1921,7 @@ def _tb_build_groups(mb: memhub.MemBuddy*, cp: TbCallParse*) -> int:
|
||||
callee: str = rawptr(_tb_rd_u64(cp.Cr, off + TB_CR_OFF_CALLEE))
|
||||
slot: int = _tb_grp_get(cp.Grp, cp.GrpCap, caller, callee, 1)
|
||||
if slot < 0:
|
||||
VLogger.error("--traceback: 调用点分组哈希表溢出,终止编译", "TRACEBACK")
|
||||
VLogger.error("--traceback: call-site group hash table overflow, aborting compilation", "TRACEBACK")
|
||||
return 1
|
||||
goff: sizet = sizet(slot) * TB_GRP_SIZE
|
||||
tailv: uint64 = uint64(_tb_rd_u32(cp.Grp, goff + TB_GRP_OFF_TAIL))
|
||||
@@ -1981,18 +1981,18 @@ def _tb_run_objdump(mb: memhub.MemBuddy*, exe_path: str) -> str:
|
||||
cl: sizet = string.strlen(exe_path) + 64
|
||||
cmd: bytes = mb.alloc(cl)
|
||||
if cmd is None:
|
||||
VLogger.error("--traceback: objdump 命令缓冲分配失败,终止编译", "TRACEBACK")
|
||||
VLogger.error("--traceback: failed to allocate objdump command buffer, aborting compilation", "TRACEBACK")
|
||||
return None
|
||||
viperlib.snprintf(cmd, cl, "llvm-objdump -d \"%s\"", exe_path)
|
||||
res: subprocess.CompletedProcess* = subprocess.run(cmd, True, True)
|
||||
if res is None or res.returncode != 0:
|
||||
rc: int = -1
|
||||
if res is not None: rc = res.returncode
|
||||
VLogger.error(f"--traceback: 调用 llvm-objdump 失败(返回码 {rc};请确认 PATH 内含 LLVM 工具),终止编译", "TRACEBACK")
|
||||
VLogger.error(f"--traceback: failed to run llvm-objdump (return code {rc}; ensure LLVM tools are in PATH), aborting compilation", "TRACEBACK")
|
||||
return None
|
||||
dump: str = res.stdout
|
||||
if dump is None:
|
||||
VLogger.error("--traceback: llvm-objdump 无输出,终止编译", "TRACEBACK")
|
||||
VLogger.error("--traceback: llvm-objdump produced no output, aborting compilation", "TRACEBACK")
|
||||
return None
|
||||
return dump
|
||||
|
||||
@@ -2087,16 +2087,16 @@ def _tb_scan_objdump(mb: memhub.MemBuddy*, dump: str, img_lo: uint64, d: TbDump*
|
||||
def WriteStackMap(mb: memhub.MemBuddy*, exe_path: str) -> int:
|
||||
"""--traceback: export <exe>.stackmap after a successful link. 0 = ok."""
|
||||
if mb is None or exe_path is None:
|
||||
VLogger.error("--traceback: WriteStackMap 参数为空,终止编译", "TRACEBACK")
|
||||
VLogger.error("--traceback: WriteStackMap argument is null, aborting compilation", "TRACEBACK")
|
||||
return 1
|
||||
|
||||
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")
|
||||
VLogger.error(f"--traceback: only Windows PE output is supported, but {exe_path} is not a valid PE (required by --traceback)", "TRACEBACK")
|
||||
return 1
|
||||
size_of_image: uint64 = lay.SizeOfImage
|
||||
if size_of_image == 0:
|
||||
VLogger.error(f"--traceback: 读到的 PE.SizeOfImage 非正({size_of_image}),无法界定 RVA 域(这是 --traceback 的要求)", "TRACEBACK")
|
||||
VLogger.error(f"--traceback: read PE.SizeOfImage is not positive ({size_of_image}), cannot bound RVA range (required by --traceback)", "TRACEBACK")
|
||||
return 1
|
||||
img_lo: uint64 = lay.ImageBase
|
||||
img_hi: uint64 = lay.ImageBase + size_of_image
|
||||
@@ -2106,18 +2106,18 @@ def WriteStackMap(mb: memhub.MemBuddy*, exe_path: str) -> int:
|
||||
cmd_len: sizet = string.strlen(exe_path) + 64
|
||||
cmd: bytes = mb.alloc(cmd_len)
|
||||
if cmd is None:
|
||||
VLogger.error("--traceback: dwarfdump 命令缓冲分配失败,终止编译", "TRACEBACK")
|
||||
VLogger.error("--traceback: failed to allocate dwarfdump command buffer, aborting compilation", "TRACEBACK")
|
||||
return 1
|
||||
viperlib.snprintf(cmd, cmd_len, "llvm-dwarfdump --debug-line --debug-info \"%s\"", exe_path)
|
||||
res: subprocess.CompletedProcess* = subprocess.run(cmd, True, True)
|
||||
if res is None or res.returncode != 0:
|
||||
rc: int = -1
|
||||
if res is not None: rc = res.returncode
|
||||
VLogger.error(f"--traceback: 调用 llvm-dwarfdump 失败(返回码 {rc};请确认 PATH 内含 LLVM 工具),终止编译", "TRACEBACK")
|
||||
VLogger.error(f"--traceback: failed to run llvm-dwarfdump (return code {rc}; ensure LLVM tools are in PATH), aborting compilation", "TRACEBACK")
|
||||
return 1
|
||||
dump: str = res.stdout
|
||||
if dump is None:
|
||||
VLogger.error("--traceback: llvm-dwarfdump 无输出,终止编译", "TRACEBACK")
|
||||
VLogger.error("--traceback: llvm-dwarfdump produced no output, aborting compilation", "TRACEBACK")
|
||||
return 1
|
||||
|
||||
d: TbDump* = _tb_parse_dump(mb, dump)
|
||||
@@ -2128,7 +2128,7 @@ def WriteStackMap(mb: memhub.MemBuddy*, exe_path: str) -> int:
|
||||
if _tb_vpcall_n > 0:
|
||||
cp: TbCallParse* = _tb_cp_init(mb)
|
||||
if cp is None:
|
||||
VLogger.error("--traceback: 调用点解析状态分配失败,终止编译", "TRACEBACK")
|
||||
VLogger.error("--traceback: failed to allocate call-site parse state, aborting compilation", "TRACEBACK")
|
||||
return 1
|
||||
if _tb_load_vpcalls(mb, cp) != 0: return 1
|
||||
if _tb_build_groups(mb, cp) != 0: return 1
|
||||
@@ -2137,12 +2137,12 @@ def WriteStackMap(mb: memhub.MemBuddy*, exe_path: str) -> int:
|
||||
our_before: int = d.RowCount
|
||||
if _tb_scan_objdump(mb, odump, img_lo, d, cp) != 0: return 1
|
||||
our_added: int = d.RowCount - our_before
|
||||
if our_added > 0: VLogger.success(f"--traceback: 从 {_tb_vpcall_n} 个 .vpcall 生成 {our_added} 条我方调用点记录(F={cp.FrN} 函数, C={cp.CrN} 调用)", "TRACEBACK")
|
||||
else: VLogger.warning(f"--traceback: 读到 {_tb_vpcall_n} 个 .vpcall(F={cp.FrN}, C={cp.CrN})但未匹配到任何 objdump 调用点——我方帧行号仍缺,退化到 DWARF", "TRACEBACK")
|
||||
else: VLogger.warning("--traceback: 未登记任何 .vpcall(我方模块无调用点记录),退化到 DWARF 行为", "TRACEBACK")
|
||||
if our_added > 0: VLogger.success(f"--traceback: from {_tb_vpcall_n} .vpcall files generated {our_added} own call-site records (F={cp.FrN} functions, C={cp.CrN} calls)", "TRACEBACK")
|
||||
else: VLogger.warning(f"--traceback: read {_tb_vpcall_n} .vpcall files (F={cp.FrN}, C={cp.CrN}) but matched no objdump call sites -- own frame line numbers still missing, falling back to DWARF", "TRACEBACK")
|
||||
else: VLogger.warning("--traceback: no .vpcall registered (own modules have no call-site records), falling back to DWARF behavior", "TRACEBACK")
|
||||
|
||||
if d.RawRowCount == 0:
|
||||
VLogger.error(f"--traceback: 未能从 {exe_path} 解析出任何行记录(DWARF .debug_line 为空且无我方 .vpcall 记录,这是 --traceback 的要求)", "TRACEBACK")
|
||||
VLogger.error(f"--traceback: could not parse any line records from {exe_path} (DWARF .debug_line is empty and there are no own .vpcall records; required by --traceback)", "TRACEBACK")
|
||||
return 1
|
||||
|
||||
# ---- 2) rows: normalise to RVA, same rva keeps the largest line ----
|
||||
@@ -2166,7 +2166,7 @@ def WriteStackMap(mb: memhub.MemBuddy*, exe_path: str) -> int:
|
||||
i += 1
|
||||
tmp: bytes = mb.alloc(TB_ROW_SIZE)
|
||||
if tmp is None:
|
||||
VLogger.error("--traceback: 行记录排序缓冲分配失败,终止编译", "TRACEBACK")
|
||||
VLogger.error("--traceback: failed to allocate line record sort buffer, aborting compilation", "TRACEBACK")
|
||||
return 1
|
||||
si2: int = 1
|
||||
while si2 < kept:
|
||||
@@ -2200,9 +2200,9 @@ def WriteStackMap(mb: memhub.MemBuddy*, exe_path: str) -> int:
|
||||
_tb_wr_u64(d.RowBuf, sizet(uniq) * TB_ROW_SIZE + TB_ROW_OFF_FUNC, bf)
|
||||
uniq += 1
|
||||
i = j
|
||||
if dropped_rows > 0: VLogger.warning(f"--traceback: 丢弃 {dropped_rows} 条无法归一化的 DWARF 行记录(地址不在影像 VA 区间,多为 COMDAT 去重副本)", "TRACEBACK")
|
||||
if dropped_rows > 0: VLogger.warning(f"--traceback: dropped {dropped_rows} DWARF line records that cannot be normalised (address not in image VA range, mostly COMDAT dedup copies)", "TRACEBACK")
|
||||
if uniq == 0:
|
||||
VLogger.error(f"--traceback: 从 {exe_path} 得到的行记录全部无法归一到运行期 RVA 域,终止编译", "TRACEBACK")
|
||||
VLogger.error(f"--traceback: all line records from {exe_path} cannot be normalised to runtime RVA range, aborting compilation", "TRACEBACK")
|
||||
return 1
|
||||
|
||||
# ---- 3) subprograms: normalise + sort by low_rva ----
|
||||
@@ -2228,7 +2228,7 @@ def WriteStackMap(mb: memhub.MemBuddy*, exe_path: str) -> int:
|
||||
fi += 1
|
||||
ftmp: bytes = mb.alloc(TB_FUNC_SIZE)
|
||||
if ftmp is None:
|
||||
VLogger.error("--traceback: 子程序排序缓冲分配失败,终止编译", "TRACEBACK")
|
||||
VLogger.error("--traceback: failed to allocate subprogram sort buffer, aborting compilation", "TRACEBACK")
|
||||
return 1
|
||||
fj: int = 1
|
||||
while fj < fkept:
|
||||
@@ -2240,7 +2240,7 @@ def WriteStackMap(mb: memhub.MemBuddy*, exe_path: str) -> int:
|
||||
fk -= 1
|
||||
string.memcpy(d.FuncBuf + sizet(fk) * TB_FUNC_SIZE, ftmp, TB_FUNC_SIZE)
|
||||
fj += 1
|
||||
if dropped_funcs > 0: VLogger.warning(f"--traceback: 丢弃 {dropped_funcs} 个无法归一化的 DWARF 子程序(low_pc 不在影像 VA 区间)", "TRACEBACK")
|
||||
if dropped_funcs > 0: VLogger.warning(f"--traceback: dropped {dropped_funcs} DWARF subprograms that cannot be normalised (low_pc not in image VA range)", "TRACEBACK")
|
||||
|
||||
# ---- 4) string pool: exact upper bound, then intern (offset 0 = sentinel) ----
|
||||
pool_need: sizet = 1
|
||||
@@ -2264,12 +2264,12 @@ def WriteStackMap(mb: memhub.MemBuddy*, exe_path: str) -> int:
|
||||
i += 1
|
||||
p: TbPool* = TbPool()
|
||||
if p is None:
|
||||
VLogger.error("--traceback: 字符串池对象分配失败,终止编译", "TRACEBACK")
|
||||
VLogger.error("--traceback: failed to allocate string pool object, aborting compilation", "TRACEBACK")
|
||||
return 1
|
||||
p.Pool = mb.alloc(pool_need)
|
||||
p.Offs = mb.alloc((sizet(uniq) * 2 + sizet(fkept)) * 8 + 64)
|
||||
if p.Pool is None or p.Offs is None:
|
||||
VLogger.error("--traceback: 字符串池缓冲分配失败,终止编译", "TRACEBACK")
|
||||
VLogger.error("--traceback: failed to allocate string pool buffer, aborting compilation", "TRACEBACK")
|
||||
return 1
|
||||
p.Pool[0] = '\0'
|
||||
p.PoolLen = 1
|
||||
@@ -2278,7 +2278,7 @@ def WriteStackMap(mb: memhub.MemBuddy*, exe_path: str) -> int:
|
||||
# file_off / func_off per unique row (u32 each)
|
||||
ro: bytes = mb.alloc(sizet(uniq) * 8 + 8)
|
||||
if ro is None:
|
||||
VLogger.error("--traceback: 记录偏移缓冲分配失败,终止编译", "TRACEBACK")
|
||||
VLogger.error("--traceback: failed to allocate record offset buffer, aborting compilation", "TRACEBACK")
|
||||
return 1
|
||||
for i in range(uniq):
|
||||
pth2: str = rawptr(_tb_rd_u64(d.RowBuf, sizet(i) * TB_ROW_SIZE + TB_ROW_OFF_FILE))
|
||||
@@ -2301,31 +2301,31 @@ def WriteStackMap(mb: memhub.MemBuddy*, exe_path: str) -> int:
|
||||
while ci < uniq:
|
||||
cv: uint64 = _tb_rd_u64(d.RowBuf, sizet(ci) * TB_ROW_SIZE)
|
||||
if ci > 0 and cv <= prev_rva:
|
||||
VLogger.error(f"--traceback 自检失败:记录 RVA 非严格升序(第 {ci} 条会破坏运行期二分查找),终止编译", "TRACEBACK")
|
||||
VLogger.error(f"--traceback self-check failed: record RVAs not strictly ascending (record {ci} would break runtime binary search), aborting compilation", "TRACEBACK")
|
||||
return 1
|
||||
prev_rva = cv
|
||||
if cv >= size_of_image: outside += 1
|
||||
if cv >= text_rva and cv < size_of_image: plausible += 1
|
||||
ci += 1
|
||||
if outside > 0:
|
||||
VLogger.error(f"--traceback 自检失败:有 {outside} 条记录的 RVA 落在 [0, SizeOfImage=0x{size_of_image:x}) 之外,终止编译", "TRACEBACK")
|
||||
VLogger.error(f"--traceback self-check failed: {outside} records have RVA outside [0, SizeOfImage=0x{size_of_image:x}), aborting compilation", "TRACEBACK")
|
||||
return 1
|
||||
if plausible <= 0:
|
||||
VLogger.error("--traceback 自检失败:没有任何记录的 RVA 落在运行期可能出现的区间(RVA 口径疑似错误),终止编译", "TRACEBACK")
|
||||
VLogger.error("--traceback self-check failed: no record RVA falls in the range possible at runtime (RVA basis likely wrong), aborting compilation", "TRACEBACK")
|
||||
return 1
|
||||
# file_off must be >= 1: offset 0 is the empty-string sentinel and the runtime
|
||||
# rejects a whole map whose record file_off is 0.
|
||||
for ci in range(uniq):
|
||||
fo: uint64 = uint64(_tb_rd_u32(ro, sizet(ci) * 8))
|
||||
if fo == 0:
|
||||
VLogger.error("--traceback 自检失败:存在 file_off==0 的记录(空路径,运行期会拒绝该旁文件),终止编译", "TRACEBACK")
|
||||
VLogger.error("--traceback self-check failed: a record has file_off==0 (empty path; runtime would reject that sidecar file), aborting compilation", "TRACEBACK")
|
||||
return 1
|
||||
|
||||
# ---- 6) serialise and write <exe>.stackmap ----
|
||||
total: sizet = 20 + sizet(uniq) * 20 + sizet(p.PoolLen)
|
||||
out: bytes = mb.alloc(total)
|
||||
if out is None:
|
||||
VLogger.error("--traceback: 旁文件输出缓冲分配失败,终止编译", "TRACEBACK")
|
||||
VLogger.error("--traceback: failed to allocate sidecar output buffer, aborting compilation", "TRACEBACK")
|
||||
return 1
|
||||
out[0] = 'T'
|
||||
out[1] = 'P'
|
||||
@@ -2348,16 +2348,16 @@ def WriteStackMap(mb: memhub.MemBuddy*, exe_path: str) -> int:
|
||||
map_len: sizet = string.strlen(exe_path) + 16
|
||||
map_path: str = mb.alloc(map_len)
|
||||
if map_path is None:
|
||||
VLogger.error("--traceback: 旁文件路径缓冲分配失败,终止编译", "TRACEBACK")
|
||||
VLogger.error("--traceback: failed to allocate sidecar path buffer, aborting compilation", "TRACEBACK")
|
||||
return 1
|
||||
viperlib.snprintf(map_path, map_len, "%s.stackmap", exe_path)
|
||||
mf: fileio.File* = fileio.File(map_path, fileio.MODE.W)
|
||||
if mf.closed:
|
||||
VLogger.error(f"--traceback: 写出旁文件失败(无法打开 {map_path}),终止编译", "TRACEBACK")
|
||||
VLogger.error(f"--traceback: failed to write sidecar file (cannot open {map_path}), aborting compilation", "TRACEBACK")
|
||||
return 1
|
||||
mf.write(out, total)
|
||||
mf.close()
|
||||
VLogger.success(f"--traceback: 已写出地址→源行旁文件 {map_path}({uniq} 条记录,{total} 字节)", "TRACEBACK")
|
||||
VLogger.success(f"--traceback: wrote address-to-source-line sidecar {map_path} ({uniq} records, {total} bytes)", "TRACEBACK")
|
||||
return 0
|
||||
|
||||
|
||||
@@ -2374,7 +2374,7 @@ def run_pipeline(ir_buf: bytes, ir_len: sizet, temp_dir: str, output_dir: str, m
|
||||
ret: int = write_ir_to_file(ir_buf, ir_len, temp_dir, module_name)
|
||||
if ret != 0:
|
||||
result.Success = 0
|
||||
result.ErrorMsg = "写 .ll 文件失败"
|
||||
result.ErrorMsg = "failed to write .ll file"
|
||||
return result
|
||||
|
||||
# Step 2: llc-compile .ll -> .obj.
|
||||
@@ -2382,20 +2382,20 @@ def run_pipeline(ir_buf: bytes, ir_len: sizet, temp_dir: str, output_dir: str, m
|
||||
ir_path: str = build_sliced_path(temp_dir, module_name, "ll")
|
||||
if ir_path is None:
|
||||
result.Success = 0
|
||||
result.ErrorMsg = "内存分配失败"
|
||||
result.ErrorMsg = "memory allocation failed"
|
||||
return result
|
||||
|
||||
ret = compile_ll_to_obj(ir_path, output_dir, module_name, cc_cmd, cc_flags)
|
||||
if ret != 0:
|
||||
result.Success = 0
|
||||
result.ErrorMsg = "llc 编译失败"
|
||||
result.ErrorMsg = "llc compilation failed"
|
||||
return result
|
||||
|
||||
# Step 3: clang++ link .obj -> .exe (plus includes.binary prebuilt .obj and static/dynamic libs)
|
||||
ret = link_obj_to_exe(output_dir, module_name, linker_cmd, linker_flags, linker_output, includes_binary_dir, linker_static_libs, linker_dynamic_libs)
|
||||
if ret != 0:
|
||||
result.Success = 0
|
||||
result.ErrorMsg = "链接失败"
|
||||
result.ErrorMsg = "link failed"
|
||||
return result
|
||||
|
||||
result.Success = 1
|
||||
|
||||
@@ -247,7 +247,7 @@ def _BuildReachableResult(mb: memhub.MemBuddy*, includes_dir: str) -> IncludesSc
|
||||
def RunPhase1(mb: memhub.MemBuddy*, includes_dir: str, temp_dir: str, log: VLogger.Logger*) -> int:
|
||||
"""Phase1: scan the includes directory and translate/generate stubs on demand"""
|
||||
if includes_dir is None or temp_dir is None:
|
||||
VLogger.error("includes_dir 或 temp_dir 为空,无法运行 Phase1", "Phase1")
|
||||
VLogger.error("includes_dir or temp_dir is empty; cannot run Phase1", "Phase1")
|
||||
return 1
|
||||
|
||||
# Set the global temp_dir (used for cross-module CDefine lookup)
|
||||
@@ -259,7 +259,7 @@ def RunPhase1(mb: memhub.MemBuddy*, includes_dir: str, temp_dir: str, log: VLogg
|
||||
# Ensure the temp dir exists (build_dir/temp may not exist yet)
|
||||
BuildPipeline.ensure_dir(temp_dir)
|
||||
|
||||
log.banner("Phase1: 扫描 includes(按需翻译)")
|
||||
log.banner("Phase1: scanning includes (on-demand translation)")
|
||||
|
||||
# Init the AST tables once, before the dependency-graph BFS: if _init_tables first runs
|
||||
# after the BFS file-level mark, reset_to frees the tables and later tokenize crashes.
|
||||
@@ -277,30 +277,30 @@ def RunPhase1(mb: memhub.MemBuddy*, includes_dir: str, temp_dir: str, log: VLogg
|
||||
string.memset(reachable_set, 0, StubMerger.MAX_INCLUDES_SHA1 * 17)
|
||||
reachable_count = StubMergerBuild._BuildReachableSha1Set(mb, Config.SourceDir, temp_dir, reachable_set, None, includes_dir)
|
||||
if reachable_count < 0:
|
||||
VLogger.error("可达集合构建失败(依赖图扫描失败),终止编译", "Phase1")
|
||||
VLogger.error("failed to build the reachable set (dependency-graph scan failed); aborting compilation", "Phase1")
|
||||
return 1
|
||||
if reachable_count <= 0:
|
||||
VLogger.warning("App 无可达 includes 依赖,跳过 Phase1", "Phase1")
|
||||
VLogger.warning("App has no reachable includes dependencies; skipping Phase1", "Phase1")
|
||||
stdlib.free(reachable_set)
|
||||
reachable_set = None
|
||||
return 0
|
||||
use_reachable = 1
|
||||
else:
|
||||
VLogger.error("reachable_set 分配失败,终止编译", "Phase1")
|
||||
VLogger.error("failed to allocate reachable_set; aborting compilation", "Phase1")
|
||||
return 1
|
||||
else:
|
||||
VLogger.warning("SourceDir 不可用,无法构建依赖图,跳过 Phase1", "Phase1")
|
||||
VLogger.warning("SourceDir unavailable; cannot build the dependency graph; skipping Phase1", "Phase1")
|
||||
return 0
|
||||
t_scan1: uint64 = w32.win32base.GetTickCount64()
|
||||
VLogger.info(f"依赖图扫描总耗时: {t_scan1 - t_scan0} ms(可达 {reachable_count} 个 includes)", "Phase1")
|
||||
VLogger.info(f"dependency-graph scan total time: {t_scan1 - t_scan0} ms (reachable {reachable_count} includes)", "Phase1")
|
||||
|
||||
# Build the reachable FileEntry list from the Sha1Store; 1a/1b-pre/1b iterate result
|
||||
# (non-empty incdir = includes). use_reachable filtering is idempotent.
|
||||
result: IncludesScanner.ScanResult* = _BuildReachableResult(mb, includes_dir)
|
||||
if result is None:
|
||||
VLogger.error("可达 FileEntry 列表构建失败,终止编译", "Phase1")
|
||||
VLogger.error("failed to build the reachable FileEntry list; aborting compilation", "Phase1")
|
||||
return 1
|
||||
VLogger.info(f"可达 includes 条目: {result.Count}", "Phase1")
|
||||
VLogger.info(f"reachable includes entries: {result.Count}", "Phase1")
|
||||
|
||||
# After scanning, clear _list/_dict injection cycle edges (e.g. _list<->memhub) so the
|
||||
# graph has none and Phase A converges; deps.txt is rewritten in sync.
|
||||
@@ -332,7 +332,7 @@ def RunPhase1(mb: memhub.MemBuddy*, includes_dir: str, temp_dir: str, log: VLogg
|
||||
# dump_stats, so skip dump_stats when self_check returns 4 (cycle).
|
||||
p1_sc: int = mb.self_check()
|
||||
if p1_sc != 4: mb.dump_stats("phase1-pre")
|
||||
else: VLogger.info("[取证] self_check=4(free list 成环),跳过 dump_stats 防死循环", "Phase1")
|
||||
else: VLogger.info("[EVIDENCE] self_check=4 (free list cycle); skipping dump_stats to prevent an infinite loop", "Phase1")
|
||||
p1_mo: int = mb.max_order
|
||||
if p1_mo < 0 or p1_mo > 32:
|
||||
p1_mo = 32 # Clamp: prevents this probe from out-of-bounds reading free_lists if max_order is corrupted
|
||||
@@ -341,8 +341,8 @@ def RunPhase1(mb: memhub.MemBuddy*, includes_dir: str, temp_dir: str, log: VLogg
|
||||
p1_base_addr: uint64 = uint64(mb.base)
|
||||
p1_usable_addr: uint64 = uint64(mb.usable)
|
||||
p1_chkbase_addr: uint64 = uint64(mb.chk_base)
|
||||
VLogger.info(f"[取证] mb={p1_mb_addr} base={p1_base_addr} usable={p1_usable_addr} " f"usable_size={mb.usable_size} max_order={mb.max_order} self_check={p1_sc} " f"detection={mb.detection}", "Phase1")
|
||||
VLogger.info(f"[取证] chk_base={p1_chkbase_addr} chk_depth={mb.chk_depth} " f"chk_cap={mb.chk_cap} free_lists[clamp={p1_mo}]={p1_fl_head}", "Phase1")
|
||||
VLogger.info(f"[EVIDENCE] mb={p1_mb_addr} base={p1_base_addr} usable={p1_usable_addr} " f"usable_size={mb.usable_size} max_order={mb.max_order} self_check={p1_sc} " f"detection={mb.detection}", "Phase1")
|
||||
VLogger.info(f"[EVIDENCE] chk_base={p1_chkbase_addr} chk_depth={mb.chk_depth} " f"chk_cap={mb.chk_cap} free_lists[clamp={p1_mo}]={p1_fl_head}", "Phase1")
|
||||
p1_sz_cn: sizet = sizet(Phase1.MAX_CLASSES * Phase1.CLASS_NAME_LEN)
|
||||
p1_sz_ds: sizet = sizet(Phase1.MAX_CLASSES * Phase1.SHA1_LEN)
|
||||
p1_sz_tp: sizet = sizet(4 * Phase1.MAX_FILE_DEPS)
|
||||
@@ -353,7 +353,7 @@ def RunPhase1(mb: memhub.MemBuddy*, includes_dir: str, temp_dir: str, log: VLogg
|
||||
p1_o_bx: int = mb._order_for_size(p1_sz_bx + 16)
|
||||
p1_fl_cn: uint64 = uint64(mb.free_lists[p1_o_cn])
|
||||
p1_fl_ds: uint64 = uint64(mb.free_lists[p1_o_ds])
|
||||
VLogger.info(f"[取证] order(class_names {p1_sz_cn}B+16)={p1_o_cn} fl={p1_fl_cn} " f"order(def_sha1s {p1_sz_ds}B+16)={p1_o_ds} fl={p1_fl_ds} " f"order(topo {p1_sz_tp}B+16)={p1_o_tp} order(box {p1_sz_bx}B+16)={p1_o_bx} " f"(fl==0 只说明该阶空、仍可由更高阶拆分;若 alloc 失败而 dump_stats 的 free>0 才是元数据损坏铁证," f"任一 order>max_order={mb.max_order} 则是 size 异常)", "Phase1")
|
||||
VLogger.info(f"[EVIDENCE] order(class_names {p1_sz_cn}B+16)={p1_o_cn} fl={p1_fl_cn} " f"order(def_sha1s {p1_sz_ds}B+16)={p1_o_ds} fl={p1_fl_ds} " f"order(topo {p1_sz_tp}B+16)={p1_o_tp} order(box {p1_sz_bx}B+16)={p1_o_bx} " f"(fl==0 only means that order is empty and can still be split by a higher order; if alloc fails while dump_stats shows free>0 that is the definitive proof of metadata corruption; " f"any order>max_order={mb.max_order} means an abnormal size)", "Phase1")
|
||||
|
||||
# Pre-scan class inheritance and build the topo order (flat byte arrays avoid str-pointer NULL crashes)
|
||||
class_names_buf: bytes = mb.alloc(Phase1.MAX_CLASSES * Phase1.CLASS_NAME_LEN)
|
||||
@@ -369,9 +369,9 @@ def RunPhase1(mb: memhub.MemBuddy*, includes_dir: str, temp_dir: str, log: VLogg
|
||||
|
||||
# These three flat buffers are Phase1Scan._ScanClassInheritance's contract pre-buffers; it
|
||||
# fails fast on NULL, so report and abort per buffer on allocation failure (never fall back).
|
||||
if class_names_buf is None: VLogger.error("类继承预扫描扁平缓冲分配失败:class_names_buf 为 NULL,终止编译", "Phase1")
|
||||
if parent_names_buf is None: VLogger.error("类继承预扫描扁平缓冲分配失败:parent_names_buf 为 NULL,终止编译", "Phase1")
|
||||
if def_sha1s_buf is None: VLogger.error("类继承预扫描扁平缓冲分配失败:def_sha1s_buf 为 NULL,终止编译", "Phase1")
|
||||
if class_names_buf is None: VLogger.error("class-inheritance pre-scan flat buffer allocation failed: class_names_buf is NULL; aborting compilation", "Phase1")
|
||||
if parent_names_buf is None: VLogger.error("class-inheritance pre-scan flat buffer allocation failed: parent_names_buf is NULL; aborting compilation", "Phase1")
|
||||
if def_sha1s_buf is None: VLogger.error("class-inheritance pre-scan flat buffer allocation failed: def_sha1s_buf is NULL; aborting compilation", "Phase1")
|
||||
|
||||
string.memset(class_names_buf, 0, Phase1.MAX_CLASSES * Phase1.CLASS_NAME_LEN)
|
||||
string.memset(parent_names_buf, 0, Phase1.MAX_CLASSES * Phase1.CLASS_NAME_LEN)
|
||||
@@ -389,12 +389,12 @@ def RunPhase1(mb: memhub.MemBuddy*, includes_dir: str, temp_dir: str, log: VLogg
|
||||
if ret_topo == 0:
|
||||
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")
|
||||
VLogger.info(f"topological sort: {class_count_scanned} classes, {topo_count} files processed in dependency order", "Phase1")
|
||||
else:
|
||||
VLogger.error("拓扑排序失败(类继承依赖无法解析),终止编译", "Phase1")
|
||||
VLogger.error("topological sort failed (class-inheritance dependencies could not be resolved); aborting compilation", "Phase1")
|
||||
return 1
|
||||
else:
|
||||
VLogger.warning("类继承预扫描无结果,回退到字母序", "Phase1")
|
||||
VLogger.warning("class-inheritance pre-scan produced no result; falling back to alphabetical order", "Phase1")
|
||||
topo_count = 0
|
||||
|
||||
# ============================================================
|
||||
@@ -455,7 +455,7 @@ def RunPhase1(mb: memhub.MemBuddy*, includes_dir: str, temp_dir: str, log: VLogg
|
||||
|
||||
# read_all's capacity includes the terminator (reads at most cap-1 bytes); longer files are truncated
|
||||
if f_r.size() >= Phase1.SRC_BUF_SIZE:
|
||||
VLogger.error(f"源文件超过 {Phase1.SRC_BUF_SIZE} 字节上限, 拒绝读取: {file_path_r}", "Phase1")
|
||||
VLogger.error(f"source file exceeds the {Phase1.SRC_BUF_SIZE}-byte limit, refusing to read: {file_path_r}", "Phase1")
|
||||
f_r.close()
|
||||
p1a_fl += 1
|
||||
continue
|
||||
@@ -525,7 +525,7 @@ def RunPhase1(mb: memhub.MemBuddy*, includes_dir: str, temp_dir: str, log: VLogg
|
||||
if mb.deep_detect != 0:
|
||||
chk_rc_1a: int = mb.check_alive_blocks(p1a_mark)
|
||||
if chk_rc_1a != 0:
|
||||
VLogger.error(f"内存损坏(1a 每文件后续, rc={chk_rc_1a}): {file_path_r}", "Phase1")
|
||||
VLogger.error(f"memory corruption (1a per-file post-check, rc={chk_rc_1a}): {file_path_r}", "Phase1")
|
||||
stdlib.exit(1)
|
||||
|
||||
# Reclaim this file's transient AST/lexer/token/IR (registered data is in perm_pool, so
|
||||
@@ -534,10 +534,10 @@ def RunPhase1(mb: memhub.MemBuddy*, includes_dir: str, temp_dir: str, log: VLogg
|
||||
|
||||
# 1a total time (struct/enum/union registration, incl. per-file read+parse+declaration)
|
||||
t_a1: uint64 = w32.win32base.GetTickCount64()
|
||||
VLogger.info(f"1a 总耗时: {t_a1-t_a0} ms (注册 struct/enum, reg={p1a_reg} skp={p1a_skp})", "Phase1")
|
||||
VLogger.info(f"1a total time: {t_a1-t_a0} ms (registering struct/enum, reg={p1a_reg} skp={p1a_skp})", "Phase1")
|
||||
|
||||
if p1a_fl > 0:
|
||||
VLogger.error(f"Phase 1a 有 {p1a_fl} 个文件 struct 注册失败", "Phase1")
|
||||
VLogger.error(f"Phase 1a: {p1a_fl} files failed to register struct", "Phase1")
|
||||
return 1
|
||||
|
||||
# Release topo-sort resources (topo_order/topo_count_box stay until Phase 1b ends;
|
||||
@@ -576,7 +576,7 @@ def RunPhase1(mb: memhub.MemBuddy*, includes_dir: str, temp_dir: str, log: VLogg
|
||||
vpi_path_pv: str = StubMergerCollect._sliced_path(temp_dir, dir_len_pv, sha1_pv, "vpi")
|
||||
if vpi_path_pv is None:
|
||||
p1bpre_failed += 1
|
||||
VLogger.error(f"[Phase 1b-pre] {entry_pv.Path} | vpi 路径生成失败", "Phase1")
|
||||
VLogger.error(f"[Phase 1b-pre] {entry_pv.Path} | failed to generate the vpi path", "Phase1")
|
||||
continue
|
||||
vf_pv: fileio.File* = fileio.File(vpi_path_pv, fileio.MODE.R)
|
||||
if not vf_pv.closed:
|
||||
@@ -589,33 +589,33 @@ def RunPhase1(mb: memhub.MemBuddy*, includes_dir: str, temp_dir: str, log: VLogg
|
||||
f_pv: fileio.File* = fileio.File(file_path_pv, fileio.MODE.R)
|
||||
if f_pv.closed:
|
||||
p1bpre_failed += 1
|
||||
VLogger.error(f"[Phase 1b-pre] {file_path_pv} | 无法打开源文件", "Phase1")
|
||||
VLogger.error(f"[Phase 1b-pre] {file_path_pv} | cannot open the source file", "Phase1")
|
||||
continue
|
||||
# read_all's capacity includes the terminator (reads at most cap-1 bytes); longer files are truncated
|
||||
if f_pv.size() >= Phase1.SRC_BUF_SIZE:
|
||||
p1bpre_failed += 1
|
||||
VLogger.error(f"[Phase 1b-pre] {file_path_pv} | 源文件超过 {Phase1.SRC_BUF_SIZE} 字节上限", "Phase1")
|
||||
VLogger.error(f"[Phase 1b-pre] {file_path_pv} | source file exceeds the {Phase1.SRC_BUF_SIZE}-byte limit", "Phase1")
|
||||
f_pv.close()
|
||||
continue
|
||||
src_buf_pv: bytes = stdlib.malloc(Phase1.SRC_BUF_SIZE)
|
||||
if src_buf_pv is None:
|
||||
f_pv.close()
|
||||
p1bpre_failed += 1
|
||||
VLogger.error(f"[Phase 1b-pre] {file_path_pv} | 源文件缓冲分配失败(OOM)", "Phase1")
|
||||
VLogger.error(f"[Phase 1b-pre] {file_path_pv} | source buffer allocation failed (OOM)", "Phase1")
|
||||
continue
|
||||
bytes_read_pv: LONG = f_pv.read_all(src_buf_pv, Phase1.SRC_BUF_SIZE)
|
||||
f_pv.close()
|
||||
if bytes_read_pv <= 0:
|
||||
stdlib.free(src_buf_pv)
|
||||
p1bpre_failed += 1
|
||||
VLogger.error(f"[Phase 1b-pre] {file_path_pv} | 文件读取失败或为空", "Phase1")
|
||||
VLogger.error(f"[Phase 1b-pre] {file_path_pv} | file read failed or is empty", "Phase1")
|
||||
continue
|
||||
if bytes_read_pv < Phase1.SRC_BUF_SIZE: src_buf_pv[bytes_read_pv] = 0
|
||||
lx_pv: ast.Lexer* = ast.new_lexer(mb)
|
||||
if lx_pv is None:
|
||||
stdlib.free(src_buf_pv)
|
||||
p1bpre_failed += 1
|
||||
VLogger.error(f"[Phase 1b-pre] {file_path_pv} | 词法器分配失败(OOM)", "Phase1")
|
||||
VLogger.error(f"[Phase 1b-pre] {file_path_pv} | lexer allocation failed (OOM)", "Phase1")
|
||||
continue
|
||||
ast._lexer_init(lx_pv, src_buf_pv, mb)
|
||||
tokens_pv: ast.Token* = ast.tokenize(lx_pv)
|
||||
@@ -625,7 +625,7 @@ def RunPhase1(mb: memhub.MemBuddy*, includes_dir: str, temp_dir: str, log: VLogg
|
||||
p1bpre_failed += 1
|
||||
# Parse failure: the log line inlines line/col + reason, plus a full Python-style
|
||||
# traceback (same reporting path as the single-file BuildPipeline).
|
||||
VLogger.error(f"[Phase 1b-pre] {file_path_pv} | AST 解析失败(第 {ast.get_parse_err_line()} 行第 {ast.get_parse_err_col()} 列: {ast.get_parse_err_msg()})", "Phase1")
|
||||
VLogger.error(f"[Phase 1b-pre] {file_path_pv} | AST parse failed (line {ast.get_parse_err_line()} col {ast.get_parse_err_col()}: {ast.get_parse_err_msg()})", "Phase1")
|
||||
GenApi.dump_parse_traceback(file_path_pv)
|
||||
continue
|
||||
pyi_buf_pv: bytes = stdlib.malloc(Phase1.PYI_BUF_SIZE)
|
||||
@@ -642,14 +642,14 @@ def RunPhase1(mb: memhub.MemBuddy*, includes_dir: str, temp_dir: str, log: VLogg
|
||||
stdlib.free(pyi_buf_pv)
|
||||
else:
|
||||
p1bpre_failed += 1
|
||||
VLogger.error(f"[Phase 1b-pre] {file_path_pv} | pyi 缓冲分配失败(OOM)", "Phase1")
|
||||
VLogger.error(f"[Phase 1b-pre] {file_path_pv} | pyi buffer allocation failed (OOM)", "Phase1")
|
||||
stdlib.free(src_buf_pv)
|
||||
# [TEMP-DIAG] 1b-pre per-file sentinel (as above): check the tail canary of live blocks
|
||||
# in [mark1, chk_depth). Must run before reset_to(mark1); only under --detection-deep.
|
||||
if mb.deep_detect != 0:
|
||||
chk_rc_pv: int = mb.check_alive_blocks(mark1)
|
||||
if chk_rc_pv != 0:
|
||||
VLogger.error(f"内存损坏(1b-pre 每文件后续, rc={chk_rc_pv}): {file_path_pv}", "Phase1")
|
||||
VLogger.error(f"memory corruption (1b-pre per-file post-check, rc={chk_rc_pv}): {file_path_pv}", "Phase1")
|
||||
stdlib.exit(1)
|
||||
|
||||
# Reclaim this file's AST (the vpi is written; nothing else persists after mark1)
|
||||
@@ -657,10 +657,10 @@ def RunPhase1(mb: memhub.MemBuddy*, includes_dir: str, temp_dir: str, log: VLogg
|
||||
|
||||
# 1b-pre total time (vpi pre-generation)
|
||||
t_pv1: uint64 = w32.win32base.GetTickCount64()
|
||||
VLogger.info(f"1b-pre 总耗时: {t_pv1-t_pv0} ms (vpi 预生成)", "Phase1")
|
||||
VLogger.info(f"1b-pre total time: {t_pv1-t_pv0} ms (vpi pre-generation)", "Phase1")
|
||||
|
||||
if p1bpre_failed > 0:
|
||||
VLogger.error(f"Phase 1b-pre 有 {p1bpre_failed} 个文件 vpi 预生成失败(失败文件与原因见上方逐条 [Phase 1b-pre] 日志)", "Phase1")
|
||||
VLogger.error(f"Phase 1b-pre: {p1bpre_failed} files failed vpi pre-generation (see the per-file [Phase 1b-pre] log lines above for failures and causes)", "Phase1")
|
||||
return 1
|
||||
|
||||
# Iterate each file (topo order preferred so base-class files translate first and their
|
||||
@@ -740,7 +740,7 @@ def RunPhase1(mb: memhub.MemBuddy*, includes_dir: str, temp_dir: str, log: VLogg
|
||||
if force_translate == 1:
|
||||
# Has class: force translation (overwrite stub/text, re-register classes)
|
||||
rp: str = entry.RelPath
|
||||
VLogger.info(f"含 class 定义,强制翻译: {rp}(sha1={sha1})", "Phase1")
|
||||
VLogger.info(f"contains a class definition, forcing translation: {rp}(sha1={sha1})", "Phase1")
|
||||
else:
|
||||
# Skip already-existing stubs (on-demand translation)
|
||||
sf: fileio.File* = fileio.File(stub_path, fileio.MODE.R)
|
||||
@@ -777,11 +777,11 @@ def RunPhase1(mb: memhub.MemBuddy*, includes_dir: str, temp_dir: str, log: VLogg
|
||||
stdlib.free(text_path)
|
||||
# text.ll missing, re-translate
|
||||
rp: str = entry.RelPath
|
||||
VLogger.info(f"text.ll 不存在,重新翻译: {rp}(sha1={sha1})", "Phase1")
|
||||
VLogger.info(f"text.ll not found, re-translating: {rp}(sha1={sha1})", "Phase1")
|
||||
else:
|
||||
# stub missing, translate
|
||||
rp: str = entry.RelPath
|
||||
VLogger.info(f"翻译: {rp}(sha1={sha1})", "Phase1")
|
||||
VLogger.info(f"translating: {rp}(sha1={sha1})", "Phase1")
|
||||
|
||||
stdlib.free(stub_path)
|
||||
|
||||
@@ -792,17 +792,17 @@ def RunPhase1(mb: memhub.MemBuddy*, includes_dir: str, temp_dir: str, log: VLogg
|
||||
file_path: str = entry.Path
|
||||
f: fileio.File* = fileio.File(file_path, fileio.MODE.R)
|
||||
if f is None:
|
||||
VLogger.error(f"无法打开(f=None): {file_path}", "Phase1")
|
||||
VLogger.error(f"cannot open (f=None): {file_path}", "Phase1")
|
||||
failed += 1
|
||||
continue
|
||||
if f.closed:
|
||||
VLogger.error(f"无法打开: {file_path}", "Phase1")
|
||||
VLogger.error(f"cannot open: {file_path}", "Phase1")
|
||||
failed += 1
|
||||
continue
|
||||
|
||||
# read_all's capacity includes the terminator (reads at most cap-1 bytes); longer files are truncated
|
||||
if f.size() >= Phase1.SRC_BUF_SIZE:
|
||||
VLogger.error(f"源文件超过 {Phase1.SRC_BUF_SIZE} 字节上限, 拒绝读取: {file_path}", "Phase1")
|
||||
VLogger.error(f"source file exceeds the {Phase1.SRC_BUF_SIZE}-byte limit, refusing to read: {file_path}", "Phase1")
|
||||
f.close()
|
||||
failed += 1
|
||||
continue
|
||||
@@ -816,7 +816,7 @@ def RunPhase1(mb: memhub.MemBuddy*, includes_dir: str, temp_dir: str, log: VLogg
|
||||
bytes_read: LONG = f.read_all(src_buf, Phase1.SRC_BUF_SIZE)
|
||||
f.close()
|
||||
if bytes_read <= 0:
|
||||
VLogger.error(f"读取失败: {file_path}", "Phase1")
|
||||
VLogger.error(f"read failed: {file_path}", "Phase1")
|
||||
stdlib.free(src_buf)
|
||||
failed += 1
|
||||
continue
|
||||
@@ -834,7 +834,7 @@ def RunPhase1(mb: memhub.MemBuddy*, includes_dir: str, temp_dir: str, log: VLogg
|
||||
if tree is None:
|
||||
# Parse failure: line/col + reason go into the log line (reason supplied by parser.vp's
|
||||
# _record_* / parse_tokens fallback).
|
||||
VLogger.error(f"AST 解析失败: {file_path}(第 {ast.get_parse_err_line()} 行第 {ast.get_parse_err_col()} 列: {ast.get_parse_err_msg()})", "Phase1")
|
||||
VLogger.error(f"AST parse failed: {file_path} (line {ast.get_parse_err_line()} col {ast.get_parse_err_col()}: {ast.get_parse_err_msg()})", "Phase1")
|
||||
stdlib.free(src_buf)
|
||||
failed += 1
|
||||
continue
|
||||
@@ -889,7 +889,7 @@ def RunPhase1(mb: memhub.MemBuddy*, includes_dir: str, temp_dir: str, log: VLogg
|
||||
# corrupts a live block header is pinned to the current file (deterministic crash location).
|
||||
pre_rc: int = mb.check_alive_blocks(mark1)
|
||||
if pre_rc != 0:
|
||||
VLogger.error(f"内存损坏(翻译前存活块, rc={pre_rc}): {file_path}", "Phase1")
|
||||
VLogger.error(f"memory corruption (live blocks before translate, rc={pre_rc}): {file_path}", "Phase1")
|
||||
stdlib.exit(1)
|
||||
|
||||
ret: int = tr.translate(tree)
|
||||
@@ -897,9 +897,9 @@ def RunPhase1(mb: memhub.MemBuddy*, includes_dir: str, temp_dir: str, log: VLogg
|
||||
t_f2: uint64 = w32.win32base.GetTickCount64()
|
||||
# Diagnostic: translate returned normally (if it hangs inside, this line is not printed,
|
||||
# distinguishing an internal hang from a later dump hang).
|
||||
if ret == 0: VLogger.info(f"翻译完成(translate返回): {file_path}", "Phase1")
|
||||
if ret == 0: VLogger.info(f"translation complete (translate returned): {file_path}", "Phase1")
|
||||
if ret != 0:
|
||||
VLogger.error(f"翻译失败: {file_path}", "Phase1") # error terminates
|
||||
VLogger.error(f"translation failed: {file_path}", "Phase1") # error terminates
|
||||
stdlib.free(src_buf)
|
||||
if tr._global_names is not None: stdlib.free(tr._global_names)
|
||||
if tr._nonlocal_names is not None: stdlib.free(tr._nonlocal_names)
|
||||
@@ -913,7 +913,7 @@ def RunPhase1(mb: memhub.MemBuddy*, includes_dir: str, temp_dir: str, log: VLogg
|
||||
# Diagnostic: the pre-translate sentinel misses write-throughs during translate, so check
|
||||
# live block headers/canaries before dump (rc=6 means a tail canary was overwritten).
|
||||
post_rc: int = mb.check_alive_blocks(mark1)
|
||||
if post_rc != 0: VLogger.error(f"内存损坏(translate后存活块, rc={post_rc}): {file_path}", "Phase1")
|
||||
if post_rc != 0: VLogger.error(f"memory corruption (live blocks after translate, rc={post_rc}): {file_path}", "Phase1")
|
||||
|
||||
# Dump stub IR (declarations only). 1MB is not enough: ast/parser.vp's text.ll exceeds it
|
||||
# and is truncated (opt: "end of file in global variable name"), so use 8MB.
|
||||
@@ -968,7 +968,7 @@ def RunPhase1(mb: memhub.MemBuddy*, includes_dir: str, temp_dir: str, log: VLogg
|
||||
# save {sha1}.full.ll (the online FULL artifact: a self-contained single-module IR for
|
||||
# Phase B to compile directly, replacing the stub + dependency text merge).
|
||||
full_buf_p1: bytes = stdlib.malloc(PHASE1_FULL_SIZE)
|
||||
if full_buf_p1 is None: VLogger.error("full.ll 缓冲区分配失败", "Phase1")
|
||||
if full_buf_p1 is None: VLogger.error("full.ll buffer allocation failed", "Phase1")
|
||||
tr.dump_ir(full_buf_p1, PHASE1_FULL_SIZE, mlirlite.OUTPUT_FULL)
|
||||
full_len_p1: sizet = string.strlen(full_buf_p1)
|
||||
full_path_p1: str = StubMergerCollect._sliced_path(temp_dir, dir_len_p1, sha1, "full.ll")
|
||||
@@ -990,7 +990,7 @@ def RunPhase1(mb: memhub.MemBuddy*, includes_dir: str, temp_dir: str, log: VLogg
|
||||
|
||||
# Timer 3: dump (stub+text) done; print the per-file three-segment timing
|
||||
t_f3: uint64 = w32.win32base.GetTickCount64()
|
||||
VLogger.info(f"[{i+1}/{loop_n_b}] 翻译: {file_path} (parse={t_f1-t_f0} ms, translate={t_f2-t_f1} ms, dump={t_f3-t_f2} ms, total={t_f3-t_f0} ms)", "Phase1")
|
||||
VLogger.info(f"[{i+1}/{loop_n_b}] translating: {file_path} (parse={t_f1-t_f0} ms, translate={t_f2-t_f1} ms, dump={t_f3-t_f2} ms, total={t_f3-t_f0} ms)", "Phase1")
|
||||
|
||||
# save dependencies(_imported_modules) for Phase B
|
||||
deps_path_p1: str = StubMergerCollect._sliced_path(temp_dir, dir_len_p1, sha1, "deps.txt")
|
||||
@@ -1015,25 +1015,25 @@ def RunPhase1(mb: memhub.MemBuddy*, includes_dir: str, temp_dir: str, log: VLogg
|
||||
# OOM reclamation: free this file's transient AST/tokens/lexer/IR/dump data (persistent
|
||||
# tables moved to stdlib). Memory sentinels locate overruns deterministically.
|
||||
chk_rc: int = mb.check_alive_blocks(mark1)
|
||||
if chk_rc != 0: VLogger.error(f"内存损坏(存活块 header, rc={chk_rc}): {file_path}", "Phase1")
|
||||
if chk_rc != 0: VLogger.error(f"memory corruption (live block header, rc={chk_rc}): {file_path}", "Phase1")
|
||||
# Out-of-bounds writes are the crash root cause (unrelated to reclamation/UAF, confirmed
|
||||
# by A/B tests); reset_to plus the tail canary pins the offending file.
|
||||
mb.reset_to(mark1)
|
||||
sc_rc: int = mb.self_check()
|
||||
if sc_rc != 0: VLogger.error(f"内存损坏(free list, rc={sc_rc}): {file_path}", "Phase1")
|
||||
if sc_rc != 0: VLogger.error(f"memory corruption (free list, rc={sc_rc}): {file_path}", "Phase1")
|
||||
|
||||
# 1b total time (full translation + dump)
|
||||
t_b1: uint64 = w32.win32base.GetTickCount64()
|
||||
VLogger.info(f"1b 总耗时: {t_b1-t_b0} ms (全量翻译, trans={translated} skip={skipped} fail={failed})", "Phase1")
|
||||
VLogger.info(f"1b total time: {t_b1-t_b0} ms (full translation, trans={translated} skip={skipped} fail={failed})", "Phase1")
|
||||
|
||||
# Release the topo-sort resources used by Phase 1b
|
||||
if topo_order is not None: mb.free(topo_order)
|
||||
if topo_count_box is not None: mb.free(topo_count_box)
|
||||
|
||||
VLogger.info(f"完成: 翻译={translated} 跳过={skipped} 失败={failed}", "Phase1")
|
||||
VLogger.info(f"done: translated={translated} skipped={skipped} failed={failed}", "Phase1")
|
||||
|
||||
if failed > 0:
|
||||
VLogger.error(f"Phase1 有 {failed} 个文件翻译失败", "Phase1")
|
||||
VLogger.error(f"Phase1: {failed} files failed to translate", "Phase1")
|
||||
return 1
|
||||
|
||||
# Release the reachable SHA1 set (if allocated)
|
||||
|
||||
@@ -45,7 +45,7 @@ def _ScanClassInheritance(mb: memhub.MemBuddy*, result: IncludesScanner.ScanResu
|
||||
if result is None: return -1
|
||||
# The three flat buffers are mb.alloc'ed by the caller; a NULL buffer would make
|
||||
# strcpy write the zero page, so fail-fast abort instead of returning -1 silently.
|
||||
if class_names_buf is None or parent_names_buf is None or def_sha1s_buf is None: VLogger.error("类继承预扫描扁平缓冲分配失败(class_names_buf/parent_names_buf/def_sha1s_buf 为 NULL)", "Phase1")
|
||||
if class_names_buf is None or parent_names_buf is None or def_sha1s_buf is None: VLogger.error("class-inheritance pre-scan flat buffer allocation failed (class_names_buf/parent_names_buf/def_sha1s_buf is NULL)", "Phase1")
|
||||
|
||||
entry_size: sizet = IncludesScanner.FileEntry.__sizeof__()
|
||||
class_count: int = 0
|
||||
@@ -74,7 +74,7 @@ def _ScanClassInheritance(mb: memhub.MemBuddy*, result: IncludesScanner.ScanResu
|
||||
|
||||
# read_all's capacity includes the terminator (reads at most cap-1 bytes); longer files are truncated
|
||||
if f.size() >= Phase1.SRC_BUF_SIZE:
|
||||
VLogger.error(f"源文件超过 {Phase1.SRC_BUF_SIZE} 字节上限, 拒绝读取: {file_path}", "Phase1")
|
||||
VLogger.error(f"source file exceeds the {Phase1.SRC_BUF_SIZE}-byte limit, refusing to read: {file_path}", "Phase1")
|
||||
f.close()
|
||||
continue
|
||||
|
||||
@@ -236,7 +236,7 @@ def _PreRegisterAllGenericTemplates(mb: memhub.MemBuddy*, result: IncludesScanne
|
||||
if f_pg.closed: continue
|
||||
# read_all's capacity includes the terminator (reads at most cap-1 bytes); longer files are truncated
|
||||
if f_pg.size() >= Phase1.SRC_BUF_SIZE:
|
||||
VLogger.error(f"源文件超过 {Phase1.SRC_BUF_SIZE} 字节上限, 拒绝读取: {file_path_pg}", "Phase1")
|
||||
VLogger.error(f"source file exceeds the {Phase1.SRC_BUF_SIZE}-byte limit, refusing to read: {file_path_pg}", "Phase1")
|
||||
f_pg.close()
|
||||
continue
|
||||
src_buf_pg: bytes = stdlib.malloc(Phase1.SRC_BUF_SIZE)
|
||||
@@ -290,8 +290,8 @@ def _PreRegisterAllGenericTemplates(mb: memhub.MemBuddy*, result: IncludesScanne
|
||||
GenApi._register_generic_func_template(perm, fd_pg, entry_pg.Sha1)
|
||||
handled_count += 1
|
||||
stdlib.free(src_buf_pg)
|
||||
if handled_count > 0: VLogger.info(f"mark1 前永久池预注册 {handled_count} 个 includes 泛型模板(类+函数)", "Phase1")
|
||||
else: VLogger.info(f"mark1 前永久池预注册 0 个泛型模板(扫描 {result.Count} 个文件,可能 marker 未命中或全量扫描失败)", "Phase1")
|
||||
if handled_count > 0: VLogger.info(f"pre-registered {handled_count} includes generic templates (classes and functions) in the permanent pool before mark1", "Phase1")
|
||||
else: VLogger.info(f"pre-registered 0 generic templates in the permanent pool before mark1 (scanned {result.Count} files; the marker may not have matched or the full scan failed)", "Phase1")
|
||||
return handled_count
|
||||
# _FindClassDefSha1 - look up a class name's defining file SHA1 in the flat arrays;
|
||||
# returns a pointer into def_sha1s_buf, or None if not found.
|
||||
@@ -326,7 +326,7 @@ def _ScanTreeForContainers(node: ast.AST*, need_list_box: t.CPtr, need_dict_box:
|
||||
"""Recursively scan the AST for list/dict container usage."""
|
||||
# Recursion depth guard: a self-referential AST cycle would recurse until the
|
||||
# stack is exhausted; fail-fast abort.
|
||||
if depth > 128: VLogger.error("容器扫描递归过深(AST 环或嵌套超过 128 层)", "Phase1")
|
||||
if depth > 128: VLogger.error("container scan recursion too deep (AST cycle or nesting over 128 levels)", "Phase1")
|
||||
if node is None: return
|
||||
k_s: int = node.kind()
|
||||
if k_s == ast.ASTKind.Name:
|
||||
|
||||
@@ -222,7 +222,7 @@ def _PreRegisterAppGenericTemplates(mb: memhub.MemBuddy*, entries: SrcFileEntry*
|
||||
if f_pa.closed: continue
|
||||
# read_all's capacity includes the terminator (reads at most cap-1 bytes); longer files are truncated
|
||||
if f_pa.size() >= SRC_BUF_SIZE:
|
||||
VLogger.error(f"源文件超过 {SRC_BUF_SIZE} 字节上限, 拒绝读取: {ent_pa.Path}", "PhaseA")
|
||||
VLogger.error(f"source file exceeds {SRC_BUF_SIZE} byte limit, refusing to read: {ent_pa.Path}", "PhaseA")
|
||||
f_pa.close()
|
||||
continue
|
||||
src_buf_pa: bytes = stdlib.malloc(SRC_BUF_SIZE)
|
||||
@@ -273,7 +273,7 @@ def _PreRegisterAppGenericTemplates(mb: memhub.MemBuddy*, entries: SrcFileEntry*
|
||||
GenApi._register_generic_func_template(perm_pa, fd_pa, ent_pa.Sha1)
|
||||
handled += 1
|
||||
stdlib.free(src_buf_pa)
|
||||
if handled > 0: VLogger.info(f"mark2 前预注册 {handled} 个 App 泛型模板(类+函数)", "PhaseA")
|
||||
if handled > 0: VLogger.info(f"pre-registered {handled} App generic templates before mark2 (classes + functions)", "PhaseA")
|
||||
return handled
|
||||
|
||||
|
||||
@@ -511,10 +511,10 @@ def _PhaseADumpFailGraph(temp_dir: str, td_len: sizet, path: str, sha1: str) ->
|
||||
def RunMultiFileProject(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str, output_dir: str, cc_cmd: str, cc_flags: str, linker_cmd: str, linker_flags: str, linker_output: str, includes_binary_dir: str, includes_dir: str, do_phase1: int, do_phase2: int, log: VLogger.Logger*, args: argparse.ParsedArgs*, linker_static_libs: str = None, linker_dynamic_libs: str = None) -> int:
|
||||
"""Compile a multi-file project; return 0 on success, non-zero on failure"""
|
||||
if source_dir is None:
|
||||
VLogger.error("source_dir 为空", "project")
|
||||
VLogger.error("source_dir is empty", "project")
|
||||
return 1
|
||||
|
||||
VLogger.info(f"多文件项目编译: {source_dir}", "project")
|
||||
VLogger.info(f"multi-file project compilation: {source_dir}", "project")
|
||||
|
||||
# === 1. Recursively scan .vp/.py files under source_dir (including subdirectories) ===
|
||||
entry_size: sizet = SrcFileEntry.__sizeof__()
|
||||
@@ -523,7 +523,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str, ou
|
||||
string.memset(entries, 0, MAX_SRC_FILES * entry_size)
|
||||
|
||||
file_count: int = _ScanDirForPyFiles(mb, source_dir, entries, entry_size, 0, MAX_SRC_FILES)
|
||||
VLogger.info(f"共 {file_count} 个源文件", "project")
|
||||
VLogger.info(f"{file_count} source files in total", "project")
|
||||
|
||||
# Scan .s assembly files (separate array; not translated in Phase A, assembled by llvm-mc after Phase B)
|
||||
asm_entries: SrcFileEntry* = stdlib.malloc(MAX_SRC_FILES * entry_size)
|
||||
@@ -532,7 +532,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str, ou
|
||||
return 1
|
||||
string.memset(asm_entries, 0, MAX_SRC_FILES * entry_size)
|
||||
asm_file_count: int = _ScanDirForAsmFiles(mb, source_dir, asm_entries, entry_size, 0, MAX_SRC_FILES)
|
||||
if asm_file_count > 0: VLogger.info(f"汇编文件 {asm_file_count} 个(llvm-mc 汇编参与链接)", "project")
|
||||
if asm_file_count > 0: VLogger.info(f"{asm_file_count} assembly files (assembled by llvm-mc and linked)", "project")
|
||||
|
||||
if file_count == 0:
|
||||
stdlib.free(entries)
|
||||
@@ -561,12 +561,12 @@ def RunMultiFileProject(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str, ou
|
||||
if includes_dir is not None:
|
||||
if StubMergerStore.GetSha1StoreCount() == 0:
|
||||
rs_05: bytes = stdlib.malloc(StubMerger.MAX_INCLUDES_SHA1 * 17)
|
||||
if rs_05 is None: VLogger.error("reachable_set 分配失败,无法填充 Sha1Store", "project")
|
||||
if rs_05 is None: VLogger.error("reachable_set allocation failed, cannot fill Sha1Store", "project")
|
||||
else:
|
||||
string.memset(rs_05, 0, StubMerger.MAX_INCLUDES_SHA1 * 17)
|
||||
rc_05: int = StubMergerBuild._BuildReachableSha1Set(mb, source_dir, temp_dir, rs_05, None, includes_dir)
|
||||
if rc_05 < 0: VLogger.error("依赖图扫描失败,无法填充 Sha1Store", "project")
|
||||
elif rc_05 > 0: VLogger.info(f"Phase2 依赖图按需填充 Sha1Store: {rc_05} 个", "project")
|
||||
if rc_05 < 0: VLogger.error("dependency graph scan failed, cannot fill Sha1Store", "project")
|
||||
elif rc_05 > 0: VLogger.info(f"Phase2 dependency graph filled Sha1Store on demand: {rc_05} entries", "project")
|
||||
stdlib.free(rs_05)
|
||||
|
||||
# Append App source SHA1s to _sha1_map.txt (human-readable only; format {sha1}:{rel_path}) and to the
|
||||
@@ -592,7 +592,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str, ou
|
||||
if string.strncmp(p_str, source_dir, src_dir_len_am) == 0: rel_path_am = p_str + src_dir_len_am + 1
|
||||
# Also append to the in-memory store (for cross-module CDefine lookups)
|
||||
# rel_path_am looks like "lib/core/StubMerger.vp", matching _sha1_map.txt
|
||||
if StubMergerStore.AppendToSha1MapStore(ent_am.Sha1, rel_path_am) != 0: VLogger.error(f"AppendToSha1MapStore 失败: {rel_path_am}", "project")
|
||||
if StubMergerStore.AppendToSha1MapStore(ent_am.Sha1, rel_path_am) != 0: VLogger.error(f"AppendToSha1MapStore failed: {rel_path_am}", "project")
|
||||
app_filled += 1
|
||||
# Write _sha1_map.txt (human-readable output)
|
||||
if not mf.closed and line_am is not None:
|
||||
@@ -602,7 +602,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str, ou
|
||||
if line_am is not None: stdlib.free(line_am)
|
||||
if not mf.closed:
|
||||
mf.close()
|
||||
VLogger.info(f"已追加 {app_filled} 个 App 文件到 _sha1_map.txt 和内存存储器", "project")
|
||||
VLogger.info(f"appended {app_filled} App files to _sha1_map.txt and the in-memory store", "project")
|
||||
stdlib.free(map_path_am)
|
||||
|
||||
# The module SHA1 map is filled into the StubMerger global store by PopulateSha1MapStore +
|
||||
@@ -619,13 +619,13 @@ def RunMultiFileProject(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str, ou
|
||||
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")
|
||||
VLogger.error("[Phase A-pre-vpi] invalid source entry (Path/Sha1 missing), skipping", "PhaseA")
|
||||
continue
|
||||
# Skip if the vpi already exists (sha1 is content-based, so a same-named vpi is valid; cross-run cache)
|
||||
vpi_path_vp2: str = StubMergerCollect._sliced_path(temp_dir, td_len_vpa, ent_vp2.Sha1, "vpi")
|
||||
if vpi_path_vp2 is None:
|
||||
vpi_failed_p2 += 1
|
||||
VLogger.error(f"[Phase A-pre-vpi] {ent_vp2.Path} | vpi 路径生成失败", "PhaseA")
|
||||
VLogger.error(f"[Phase A-pre-vpi] {ent_vp2.Path} | failed to build vpi path", "PhaseA")
|
||||
continue
|
||||
vf_vp2: fileio.File* = fileio.File(vpi_path_vp2, fileio.MODE.R)
|
||||
if not vf_vp2.closed:
|
||||
@@ -638,33 +638,33 @@ def RunMultiFileProject(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str, ou
|
||||
f_vp2: fileio.File* = fileio.File(ent_vp2.Path, fileio.MODE.R)
|
||||
if f_vp2.closed:
|
||||
vpi_failed_p2 += 1
|
||||
VLogger.error(f"[Phase A-pre-vpi] {ent_vp2.Path} | 无法打开源文件", "PhaseA")
|
||||
VLogger.error(f"[Phase A-pre-vpi] {ent_vp2.Path} | cannot open source file", "PhaseA")
|
||||
continue
|
||||
# read_all's capacity includes the terminator (reads at most cap-1 bytes); longer files are truncated
|
||||
if f_vp2.size() >= SRC_BUF_SIZE:
|
||||
vpi_failed_p2 += 1
|
||||
VLogger.error(f"[Phase A-pre-vpi] {ent_vp2.Path} | 源文件超过 {SRC_BUF_SIZE} 字节上限", "PhaseA")
|
||||
VLogger.error(f"[Phase A-pre-vpi] {ent_vp2.Path} | source file exceeds {SRC_BUF_SIZE} byte limit", "PhaseA")
|
||||
f_vp2.close()
|
||||
continue
|
||||
src_buf_vp2: bytes = stdlib.malloc(SRC_BUF_SIZE)
|
||||
if src_buf_vp2 is None:
|
||||
f_vp2.close()
|
||||
vpi_failed_p2 += 1
|
||||
VLogger.error(f"[Phase A-pre-vpi] {ent_vp2.Path} | 源文件缓冲分配失败(OOM)", "PhaseA")
|
||||
VLogger.error(f"[Phase A-pre-vpi] {ent_vp2.Path} | source buffer allocation failed (OOM)", "PhaseA")
|
||||
continue
|
||||
bytes_read_vp2: LONG = f_vp2.read_all(src_buf_vp2, SRC_BUF_SIZE)
|
||||
f_vp2.close()
|
||||
if bytes_read_vp2 <= 0:
|
||||
stdlib.free(src_buf_vp2)
|
||||
vpi_failed_p2 += 1
|
||||
VLogger.error(f"[Phase A-pre-vpi] {ent_vp2.Path} | 文件读取失败或为空", "PhaseA")
|
||||
VLogger.error(f"[Phase A-pre-vpi] {ent_vp2.Path} | file read failed or empty", "PhaseA")
|
||||
continue
|
||||
if bytes_read_vp2 < SRC_BUF_SIZE: src_buf_vp2[bytes_read_vp2] = 0
|
||||
lx_vp2: ast.Lexer* = ast.new_lexer(mb)
|
||||
if lx_vp2 is None:
|
||||
stdlib.free(src_buf_vp2)
|
||||
vpi_failed_p2 += 1
|
||||
VLogger.error(f"[Phase A-pre-vpi] {ent_vp2.Path} | 词法器分配失败(OOM)", "PhaseA")
|
||||
VLogger.error(f"[Phase A-pre-vpi] {ent_vp2.Path} | lexer allocation failed (OOM)", "PhaseA")
|
||||
continue
|
||||
ast._lexer_init(lx_vp2, src_buf_vp2, mb)
|
||||
tokens_vp2: ast.Token* = ast.tokenize(lx_vp2)
|
||||
@@ -674,7 +674,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str, ou
|
||||
vpi_failed_p2 += 1
|
||||
# Parse failure: inline the line/column + reason in the log line (same source as the full
|
||||
# Python-style traceback below), since "AST parse failed" alone gives no location or cause.
|
||||
VLogger.error(f"[Phase A-pre-vpi] {ent_vp2.Path} | AST 解析失败(第 {ast.get_parse_err_line()} 行第 {ast.get_parse_err_col()} 列: {ast.get_parse_err_msg()})", "PhaseA")
|
||||
VLogger.error(f"[Phase A-pre-vpi] {ent_vp2.Path} | AST parse failed (line {ast.get_parse_err_line()} col {ast.get_parse_err_col()}: {ast.get_parse_err_msg()})", "PhaseA")
|
||||
GenApi.dump_parse_traceback(ent_vp2.Path)
|
||||
continue
|
||||
pyi_buf_vp2: bytes = stdlib.malloc(PYI_BUF_SIZE_P2)
|
||||
@@ -691,12 +691,12 @@ def RunMultiFileProject(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str, ou
|
||||
stdlib.free(pyi_buf_vp2)
|
||||
else:
|
||||
vpi_failed_p2 += 1
|
||||
VLogger.error(f"[Phase A-pre-vpi] {ent_vp2.Path} | pyi 缓冲分配失败(OOM)", "PhaseA")
|
||||
VLogger.error(f"[Phase A-pre-vpi] {ent_vp2.Path} | pyi buffer allocation failed (OOM)", "PhaseA")
|
||||
stdlib.free(src_buf_vp2)
|
||||
# OOM cleanup: free this file's AST (the vpi is already on disk; persistent data is stdlib-allocated)
|
||||
mb.reset_to(mark2)
|
||||
if vpi_failed_p2 > 0:
|
||||
VLogger.error(f"Phase A-pre-vpi 有 {vpi_failed_p2} 个文件 vpi 预生成失败(失败文件与原因见上方逐条 [Phase A-pre-vpi] 日志)", "PhaseA")
|
||||
VLogger.error(f"Phase A-pre-vpi: {vpi_failed_p2} files failed vpi pre-generation (see the per-file [Phase A-pre-vpi] logs above for failing files and causes)", "PhaseA")
|
||||
return 1
|
||||
|
||||
|
||||
@@ -706,7 +706,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str, ou
|
||||
app_deps_buf: bytes = None
|
||||
app_deps_len: sizet = 0
|
||||
if do_phase1 != 0:
|
||||
log.banner("Phase A: 生成 stub + text")
|
||||
log.banner("Phase A: generate stub + text")
|
||||
# Initialize the Phase A convergence-failure diagnostic table (stdlib, survives reset)
|
||||
_PhaseADiagInit(sizet(file_count) + StubMerger.MAX_INCLUDES)
|
||||
|
||||
@@ -772,13 +772,13 @@ def RunMultiFileProject(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str, ou
|
||||
for si_inc_f in range(store_count_inc_pre):
|
||||
if inc_fail_flags[si_inc_f] != 0:
|
||||
rel_f: str = store_rel_inc_pre + sizet(si_inc_f) * StubMerger.MAX_REL_PATH_LEN
|
||||
VLogger.error(f"includes 预注册失败: {rel_f}(文件无法翻译,可能是语法/解析/编译错误),终止编译", "prePhaseA")
|
||||
VLogger.error(f"includes pre-registration failed: {rel_f} (file cannot be translated; possible syntax/parse/compile error), aborting compilation", "prePhaseA")
|
||||
stdlib.free(inc_fail_flags)
|
||||
VLogger.info(f"includes 预注册 + 依赖填充: {deps_filled_pre}/{store_count_inc_pre}", "prePhaseA")
|
||||
VLogger.info(f"includes pre-registration + dependency fill: {deps_filled_pre}/{store_count_inc_pre}", "prePhaseA")
|
||||
|
||||
# === Phase A-pre: pre-register struct/enum/union for all sources ===
|
||||
# Registers declarations only (declare_only=1), no method bodies; multi-pass resolves cross-file ordering.
|
||||
VLogger.info("预注册 struct/enum/union...", "PhaseA")
|
||||
VLogger.info("pre-registering struct/enum/union...", "PhaseA")
|
||||
src_dir_len_pre: sizet = string.strlen(source_dir)
|
||||
PHASE_A_PRE_MAX_PASSES: int = 3
|
||||
for pass_i in range(PHASE_A_PRE_MAX_PASSES):
|
||||
@@ -794,13 +794,13 @@ def RunMultiFileProject(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str, ou
|
||||
# App pre-registration passes pre_allow_dep_inject=1: imports and dep vpi injection happen at
|
||||
# declaration time so field annotations share Phase A's context (else struct layouts diverge).
|
||||
tr_pre: 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")
|
||||
if tr_pre is None: VLogger.error(f"pre-registration failed: {ent_pre.Path}", "PhaseA")
|
||||
# OOM cleanup: free this App file's transient pre-registration data
|
||||
mb.reset_to(mark2)
|
||||
struct_count_after: int = GenApi.get_struct_count()
|
||||
# Convergence check: no new struct registered this pass -> all classes are registered
|
||||
if struct_count_after == struct_count_before: break
|
||||
VLogger.info("预注册完成", "PhaseA")
|
||||
VLogger.info("pre-registration complete", "PhaseA")
|
||||
|
||||
# Phase A IR buffer: 1MB is not enough, ast/parser.vp's text.ll exceeds 1MB and got truncated ->
|
||||
# merged IR lost the tail (opt: "end of file in global variable name").
|
||||
@@ -823,7 +823,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str, ou
|
||||
# (filesystem order); failed files are retried next pass, converging in at most file_count passes.
|
||||
done_flags: bytes = stdlib.malloc(file_count)
|
||||
if done_flags is None:
|
||||
VLogger.error("Phase A done_flags 分配失败", "PhaseA")
|
||||
VLogger.error("Phase A done_flags allocation failed", "PhaseA")
|
||||
stdlib.free(entries)
|
||||
return 1
|
||||
string.memset(done_flags, 0, file_count)
|
||||
@@ -887,7 +887,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str, ou
|
||||
stdlib.free(im_mod_buf)
|
||||
# dump stub IR (declarations only)
|
||||
stub_buf_a: bytes = stdlib.malloc(PHASE_A_IR_SIZE)
|
||||
if stub_buf_a is None: VLogger.error("stub 缓冲区分配失败", "PhaseA")
|
||||
if stub_buf_a is None: VLogger.error("stub buffer allocation failed", "PhaseA")
|
||||
tr_a.dump_ir(stub_buf_a, PHASE_A_IR_SIZE, mlirlite.OUTPUT_STUB)
|
||||
stub_len_a: sizet = string.strlen(stub_buf_a)
|
||||
|
||||
@@ -903,7 +903,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str, ou
|
||||
|
||||
# dump text IR (definitions only)
|
||||
text_buf_a: bytes = stdlib.malloc(PHASE_A_IR_SIZE)
|
||||
if text_buf_a is None: VLogger.error("text 缓冲区分配失败", "PhaseA")
|
||||
if text_buf_a is None: VLogger.error("text buffer allocation failed", "PhaseA")
|
||||
tr_a.dump_ir(text_buf_a, PHASE_A_IR_SIZE, mlirlite.OUTPUT_TEXT)
|
||||
text_len_a: sizet = string.strlen(text_buf_a)
|
||||
|
||||
@@ -922,7 +922,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str, ou
|
||||
|
||||
# Save {sha1}.full.ll (in-memory FULL artifact: a self-contained single-module IR)
|
||||
full_buf_a: bytes = stdlib.malloc(PHASE_A_FULL_SIZE)
|
||||
if full_buf_a is None: VLogger.error("full.ll 缓冲区分配失败", "PhaseA")
|
||||
if full_buf_a is None: VLogger.error("full.ll buffer allocation failed", "PhaseA")
|
||||
tr_a.dump_ir(full_buf_a, PHASE_A_FULL_SIZE, mlirlite.OUTPUT_FULL)
|
||||
full_len_a: sizet = string.strlen(full_buf_a)
|
||||
full_path_a: str = StubMergerCollect._sliced_path(temp_dir, td_len_pa, ent.Sha1, "full.ll")
|
||||
@@ -980,7 +980,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str, ou
|
||||
if ent_err.Sha1 is not None: _PhaseADumpFailGraph(temp_dir, td_len_fail, ent_err.Path, ent_err.Sha1)
|
||||
stdlib.free(done_flags)
|
||||
_PhaseADiagFree()
|
||||
VLogger.error("Phase A 多遍收敛失败,终止编译", "PhaseA")
|
||||
VLogger.error("Phase A multi-pass convergence failed, aborting compilation", "PhaseA")
|
||||
stdlib.free(entries)
|
||||
return 1
|
||||
stdlib.free(done_flags)
|
||||
@@ -988,14 +988,14 @@ def RunMultiFileProject(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str, ou
|
||||
_PhaseADiagFree()
|
||||
|
||||
if do_phase2 == 0:
|
||||
VLogger.info("Phase A 完成(仅 stub 生成)", "project")
|
||||
VLogger.info("Phase A complete (stub generation only)", "project")
|
||||
if app_deps_buf is not None: stdlib.free(app_deps_buf)
|
||||
stdlib.free(entries)
|
||||
return 0
|
||||
|
||||
# === 3. Phase B: compile each file to .obj ===
|
||||
if do_phase2 != 0:
|
||||
log.banner("Phase B: 编译 .obj")
|
||||
log.banner("Phase B: compile .obj")
|
||||
|
||||
# Collect .obj paths (64KB to avoid includes .obj path overflow dropping link symbols).
|
||||
# reachable_set/reachable_count: filled by Phase B+, used by Phase C for on-demand linking.
|
||||
@@ -1020,7 +1020,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str, ou
|
||||
# only writes .ll + builds tasks, then run_llc_parallel runs llc in parallel batches.
|
||||
llc_tasks: bytes = stdlib.malloc(sizet(file_count) * BuildPipeline.LlcTask.__sizeof__())
|
||||
if llc_tasks is None:
|
||||
VLogger.error("llc 任务表分配失败", "PhaseB")
|
||||
VLogger.error("llc task table allocation failed", "PhaseB")
|
||||
return 1
|
||||
llc_task_count: int = 0
|
||||
|
||||
@@ -1033,11 +1033,11 @@ def RunMultiFileProject(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str, ou
|
||||
# Read the in-memory FULL artifact {sha1}.full.ll -> complete IR (replaces merging stub + dep stub/text)
|
||||
combined_ir: bytes = stdlib.malloc(COMBINED_IR_SIZE)
|
||||
if combined_ir is None:
|
||||
VLogger.error(f"combined_ir 分配失败: {ent.Path}", "PhaseB")
|
||||
VLogger.error(f"combined_ir allocation failed: {ent.Path}", "PhaseB")
|
||||
continue
|
||||
combined_len: sizet = StubMergerBuild.LoadFullIR(temp_dir, ent.Sha1, combined_ir, COMBINED_IR_SIZE)
|
||||
if combined_len == 0:
|
||||
VLogger.error(f"读 full.ll 失败: {ent.Path}", "PhaseB")
|
||||
VLogger.error(f"failed to read full.ll: {ent.Path}", "PhaseB")
|
||||
stdlib.free(combined_ir)
|
||||
continue
|
||||
# Timing point 1: full.ll read done
|
||||
@@ -1047,7 +1047,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str, ou
|
||||
ret_w: int = BuildPipeline.write_ir_to_file(combined_ir, combined_len, temp_dir, ent.Sha1)
|
||||
stdlib.free(combined_ir)
|
||||
if ret_w != 0:
|
||||
VLogger.error(f"写 .ll 失败: {ent.Path}", "PhaseB")
|
||||
VLogger.error(f"failed to write .ll: {ent.Path}", "PhaseB")
|
||||
sys.exit(1)
|
||||
# Timing point 2: .ll write done
|
||||
t_pb2: uint64 = w32.win32base.GetTickCount64()
|
||||
@@ -1055,11 +1055,11 @@ def RunMultiFileProject(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str, ou
|
||||
# Build the llc task (command string is stdlib.malloc'd so threads' lifetimes are not reset-reclaimed)
|
||||
llc_ir_path: str = BuildPipeline.build_sliced_path(temp_dir, ent.Sha1, "ll")
|
||||
if llc_ir_path is None:
|
||||
VLogger.error("llc 输入路径构造失败", "PhaseB")
|
||||
VLogger.error("failed to build llc input path", "PhaseB")
|
||||
sys.exit(1)
|
||||
tslot: BuildPipeline.LlcTask* = BuildPipeline.LlcTask*(uint64(llc_tasks) + sizet(llc_task_count) * BuildPipeline.LlcTask.__sizeof__())
|
||||
if BuildPipeline.init_llc_task(tslot, llc_ir_path, output_dir, ent.Sha1, cc_cmd, cc_flags) != 0:
|
||||
VLogger.error(f"llc 任务构造失败: {ent.Path}", "PhaseB")
|
||||
VLogger.error(f"failed to build llc task: {ent.Path}", "PhaseB")
|
||||
sys.exit(1)
|
||||
# Timing point 3: llc task construction done
|
||||
t_pb3: uint64 = w32.win32base.GetTickCount64()
|
||||
@@ -1067,7 +1067,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str, ou
|
||||
|
||||
compiled_count += 1
|
||||
# Show files submitted to llc (with the three timings: merge stub / write .ll / build task)
|
||||
VLogger.info(f"[{i+1}/{file_count}] llc 已提交: {ent.Path} (merge={t_pb1-t_pb0} ms, write={t_pb2-t_pb1} ms, task={t_pb3-t_pb2} ms, total={t_pb3-t_pb0} ms)", "PhaseB")
|
||||
VLogger.info(f"[{i+1}/{file_count}] llc submitted: {ent.Path} (merge={t_pb1-t_pb0} ms, write={t_pb2-t_pb1} ms, task={t_pb3-t_pb2} ms, total={t_pb3-t_pb0} ms)", "PhaseB")
|
||||
# Build the .obj path and detect the main module (test_main.vp or main.vp; .py no longer recognized)
|
||||
od_len: sizet = string.strlen(output_dir)
|
||||
is_main_mod: int = 0
|
||||
@@ -1081,7 +1081,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str, ou
|
||||
if is_main_mod != 0:
|
||||
# main module: copy to main_obj_path (so main is first at link time)
|
||||
if op_sliced_len < 512: string.strcpy(main_obj_path, obj_path_sliced)
|
||||
else: VLogger.error("main_obj_path 缓冲区不足,终止编译", "PhaseB")
|
||||
else: VLogger.error("main_obj_path buffer too small, aborting compilation", "PhaseB")
|
||||
else:
|
||||
# Other modules: append to obj_paths
|
||||
if obj_pos + op_sliced_len + 2 < OBJ_PATHS_SIZE:
|
||||
@@ -1091,13 +1091,13 @@ def RunMultiFileProject(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str, ou
|
||||
string.strcpy(obj_paths + obj_pos, obj_path_sliced)
|
||||
obj_pos += op_sliced_len
|
||||
obj_paths[obj_pos] = '\0'
|
||||
else: VLogger.error(".obj 路径缓冲区不足", "PhaseB")
|
||||
else: VLogger.error(".obj path buffer too small", "PhaseB")
|
||||
stdlib.free(obj_path_sliced)
|
||||
|
||||
# Run all llc jobs in parallel (batched at LLC_MAX_THREADS threads)
|
||||
ret_p: int = BuildPipeline.run_llc_parallel(llc_tasks, llc_task_count, BuildPipeline.LLC_MAX_THREADS)
|
||||
if ret_p != 0:
|
||||
VLogger.error("llc 编译失败,终止编译", "PhaseB")
|
||||
VLogger.error("llc compilation failed, aborting compilation", "PhaseB")
|
||||
sys.exit(1)
|
||||
|
||||
# Free the llc tasks (command strings + records)
|
||||
@@ -1118,7 +1118,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str, ou
|
||||
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(ent_as.Path, ent_as.Sha1, output_dir, Config.TargetTriple)
|
||||
if aret_as != 0:
|
||||
VLogger.error(f"llvm-mc 汇编失败,终止编译: {ent_as.Path}", "PhaseB")
|
||||
VLogger.error(f"llvm-mc assembly failed, aborting compilation: {ent_as.Path}", "PhaseB")
|
||||
sys.exit(1)
|
||||
obj_path_asm: str = StubMergerCollect._sliced_path(output_dir, od_len_as, ent_as.Sha1, "obj")
|
||||
if obj_path_asm is not None:
|
||||
@@ -1132,12 +1132,12 @@ def RunMultiFileProject(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str, ou
|
||||
obj_paths[obj_pos] = '\0'
|
||||
stdlib.free(obj_path_asm)
|
||||
asm_compiled += 1
|
||||
VLogger.info(f"[asm {asm_compiled}] 汇编完成: {ent_as.Path}", "PhaseB")
|
||||
VLogger.info(f"[asm {asm_compiled}] assembly complete: {ent_as.Path}", "PhaseB")
|
||||
|
||||
VLogger.success(f"编译完成: {compiled_count}/{file_count}", "PhaseB")
|
||||
VLogger.success(f"compilation complete: {compiled_count}/{file_count}", "PhaseB")
|
||||
|
||||
if compiled_count == 0:
|
||||
VLogger.error("无成功编译的文件", "PhaseB")
|
||||
VLogger.error("no files compiled successfully", "PhaseB")
|
||||
stdlib.free(entries)
|
||||
stdlib.free(asm_entries)
|
||||
return 1
|
||||
@@ -1149,7 +1149,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str, ou
|
||||
td_len_mi: sizet = string.strlen(temp_dir)
|
||||
|
||||
# Diagnostic log: confirm the Phase B+ entry and Sha1Store state
|
||||
VLogger.info(f"PhaseB+ 入口: store_count={StubMergerStore.GetSha1StoreCount()} includes_binary_dir={includes_binary_dir}", "PhaseB+")
|
||||
VLogger.info(f"PhaseB+ entry: store_count={StubMergerStore.GetSha1StoreCount()} includes_binary_dir={includes_binary_dir}", "PhaseB+")
|
||||
|
||||
# Create includes_binary_dir (so .obj files can be written and collect_obj_files can scan them)
|
||||
BuildPipeline.ensure_dir(includes_binary_dir)
|
||||
@@ -1165,13 +1165,13 @@ def RunMultiFileProject(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str, ou
|
||||
if reachable_set is not None:
|
||||
string.memset(reachable_set, 0, REACHABLE_SET_SIZE)
|
||||
reachable_count = StubMergerBuild._BuildReachableSha1Set(mb, source_dir, temp_dir, reachable_set, app_deps_buf, includes_dir)
|
||||
VLogger.info(f"可达 includes SHA1: {reachable_count} 个", "PhaseB+")
|
||||
VLogger.info(f"reachable includes SHA1: {reachable_count} entries", "PhaseB+")
|
||||
# fast-fail: reachable-set construction failed (deps not found); never fall back, abort
|
||||
if reachable_count < 0:
|
||||
VLogger.error("可达集合构建失败(fast-fail),终止编译", "PhaseB+")
|
||||
VLogger.error("reachable set construction failed (fast-fail), aborting compilation", "PhaseB+")
|
||||
return 1
|
||||
else:
|
||||
VLogger.error("reachable_set 分配失败,终止编译", "PhaseB+")
|
||||
VLogger.error("reachable_set allocation failed, aborting compilation", "PhaseB+")
|
||||
return 1
|
||||
|
||||
# Free app_deps_buf (reachable_set is built, no longer needed)
|
||||
@@ -1196,7 +1196,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str, ou
|
||||
topo_idx: sizet* = (sizet*)(stdlib.malloc(8 * (store_count_mi + 1)))
|
||||
topo_count: int = 0
|
||||
if topo_idx is None:
|
||||
VLogger.error("拓扑排序索引分配失败,终止编译", "PhaseB+")
|
||||
VLogger.error("topological sort index allocation failed, aborting compilation", "PhaseB+")
|
||||
topo_count = 0
|
||||
else:
|
||||
topo_count = StubMergerTopo.BuildTopoSortedIndices(store_count_mi, store_sha1_arr_mi, store_mod_arr_mi, reachable_set, reachable_count, topo_idx)
|
||||
@@ -1244,7 +1244,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str, ou
|
||||
if src_fp_mi is None:
|
||||
stdlib.free(check_pat_mi)
|
||||
if check_fd_mi is not None: stdlib.free(check_fd_mi)
|
||||
VLogger.error("includes 源路径分配失败,终止编译", "PhaseB+")
|
||||
VLogger.error("includes source path allocation failed, aborting compilation", "PhaseB+")
|
||||
viperlib.snprintf(src_fp_mi, inc_dir_len_mi + 1 + rel_path_len_mi + 1, "%s/%s", incdir_mi, inc_rel_mi)
|
||||
|
||||
# Check whether it is a declaration-only file (read {sha1}.meta: no FUNC ... DEF means pure declaration)
|
||||
@@ -1306,7 +1306,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str, ou
|
||||
StubMergerIR.WriteModuleMeta(tr_mi.Module, temp_dir, td_len_mi, inc_sha1_mi)
|
||||
# Save {sha1}.full.ll (in-memory FULL artifact)
|
||||
inc_full_buf: bytes = stdlib.malloc(PBP_FULL_SIZE)
|
||||
if inc_full_buf is None: VLogger.error("full.ll 缓冲区分配失败", "PhaseB+")
|
||||
if inc_full_buf is None: VLogger.error("full.ll buffer allocation failed", "PhaseB+")
|
||||
tr_mi.dump_ir(inc_full_buf, PBP_FULL_SIZE, mlirlite.OUTPUT_FULL)
|
||||
inc_full_len: sizet = string.strlen(inc_full_buf)
|
||||
inc_full_path: str = StubMergerCollect._sliced_path(temp_dir, td_len_mi, inc_sha1_mi, "full.ll")
|
||||
@@ -1355,7 +1355,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str, ou
|
||||
diag_text_ex = 1
|
||||
df_diag_t.close()
|
||||
stdlib.free(diag_text)
|
||||
VLogger.error(f"读 full.ll 失败: {src_fp_mi} (full={diag_full_ex} stub={diag_stub_ex} text={diag_text_ex} is_decl={is_decl_mi})", "PhaseB+")
|
||||
VLogger.error(f"failed to read full.ll: {src_fp_mi} (full={diag_full_ex} stub={diag_stub_ex} text={diag_text_ex} is_decl={is_decl_mi})", "PhaseB+")
|
||||
if inc_combined_mi is not None: stdlib.free(inc_combined_mi)
|
||||
stdlib.free(check_pat_mi)
|
||||
if check_fd_mi is not None: stdlib.free(check_fd_mi)
|
||||
@@ -1367,12 +1367,12 @@ def RunMultiFileProject(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str, ou
|
||||
stdlib.free(inc_combined_mi)
|
||||
|
||||
if inc_cret_mi != 0:
|
||||
VLogger.error(f"llc 编译失败,终止编译: {src_fp_mi}", "PhaseB+")
|
||||
VLogger.error(f"llc compilation failed, aborting compilation: {src_fp_mi}", "PhaseB+")
|
||||
sys.exit(1)
|
||||
|
||||
inc_compiled += 1
|
||||
# Show the compiled includes file
|
||||
VLogger.info(f"[includes {inc_compiled}] 编译完成: {src_fp_mi}", "PhaseB+")
|
||||
VLogger.info(f"[includes {inc_compiled}] compilation complete: {src_fp_mi}", "PhaseB+")
|
||||
|
||||
# Add to obj_paths (sliced path, taken from includes_binary_dir)
|
||||
ibd_len_mi2: sizet = string.strlen(includes_binary_dir)
|
||||
@@ -1387,7 +1387,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str, ou
|
||||
string.strcpy(obj_paths + obj_pos, inc_obj_sliced)
|
||||
obj_pos += inc_obj_len
|
||||
obj_paths[obj_pos] = '\0'
|
||||
else: VLogger.error("includes .obj 路径缓冲区溢出,终止编译", "PhaseB+")
|
||||
else: VLogger.error("includes .obj path buffer overflow, aborting compilation", "PhaseB+")
|
||||
stdlib.free(inc_obj_sliced)
|
||||
|
||||
# Free this iteration's temporary memory
|
||||
@@ -1402,7 +1402,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str, ou
|
||||
if store_sha1_arr_mi is not None: stdlib.free(store_sha1_arr_mi)
|
||||
if store_mod_arr_mi is not None: stdlib.free(store_mod_arr_mi)
|
||||
|
||||
VLogger.info(f"编译缺失 includes: {inc_compiled} 个", "PhaseB+")
|
||||
VLogger.info(f"compiled missing includes: {inc_compiled} entries", "PhaseB+")
|
||||
|
||||
# Free app_deps_buf (fallback when the Phase B+ block did not run)
|
||||
if app_deps_buf is not None:
|
||||
@@ -1410,7 +1410,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str, ou
|
||||
app_deps_buf = None
|
||||
|
||||
# === 4. Phase C: link all .obj -> .exe ===
|
||||
log.banner("Phase C: 链接")
|
||||
log.banner("Phase C: link")
|
||||
|
||||
od_len2: sizet = string.strlen(output_dir)
|
||||
lo_len: sizet = string.strlen(linker_output)
|
||||
@@ -1418,7 +1418,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str, ou
|
||||
if exe_path is not None: viperlib.snprintf(exe_path, od_len2 + lo_len + 2, "%s/%s", output_dir, linker_output)
|
||||
else:
|
||||
exe_path = linker_output
|
||||
VLogger.error("exe_path 分配失败,终止编译", "PhaseC")
|
||||
VLogger.error("exe_path allocation failed, aborting compilation", "PhaseC")
|
||||
|
||||
# Build the final .obj path list: main_obj_path first, reachable .objs after
|
||||
final_obj_paths: bytes = stdlib.malloc(OBJ_PATHS_SIZE + 512)
|
||||
@@ -1490,7 +1490,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str, ou
|
||||
string.strcpy(final_obj_paths + fop_pos, obj_path_pc)
|
||||
fop_pos += op_len_p2
|
||||
final_obj_paths[fop_pos] = '\0'
|
||||
elif StubMergerIR.IsDeclOnlyModule(temp_dir, td_len_pc, rsha1_pc) != 1: VLogger.error(f"可达模块 .obj 缺失: {obj_path_pc}", "PhaseC")
|
||||
elif StubMergerIR.IsDeclOnlyModule(temp_dir, td_len_pc, rsha1_pc) != 1: VLogger.error(f"reachable module .obj missing: {obj_path_pc}", "PhaseC")
|
||||
stdlib.free(obj_path_pc)
|
||||
|
||||
final_obj_paths[fop_pos] = '\0'
|
||||
@@ -1505,19 +1505,19 @@ def RunMultiFileProject(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str, ou
|
||||
lret: int = BuildPipeline.link_objs_to_exe(final_obj_paths, obj_paths_len, linker_cmd, linker_flags, exe_path, None, linker_static_libs, linker_dynamic_libs)
|
||||
|
||||
if lret == 0:
|
||||
VLogger.success(f"输出: {exe_path}", "PhaseC")
|
||||
VLogger.success(f"output: {exe_path}", "PhaseC")
|
||||
# --traceback: export <exe>.stackmap (skipped under --phase2command,
|
||||
# where nothing was actually linked).
|
||||
if BuildPipeline._traceback_mode != 0 and BuildPipeline._phase2_cmd_path is None: BuildPipeline.WriteStackMap(mb, exe_path)
|
||||
if args.get_bool("run") and BuildPipeline._phase2_cmd_path is not None:
|
||||
# phase2command mode: the exe is not linked yet (the command is in the bat); skip --run
|
||||
VLogger.info("phase2command 模式:跳过 --run(exe 尚未链接)", "phase2cmd")
|
||||
VLogger.info("phase2command mode: skipping --run (exe not linked yet)", "phase2cmd")
|
||||
elif args.get_bool("run"):
|
||||
VLogger.info(f"执行: {exe_path}", "run")
|
||||
VLogger.info(f"run: {exe_path}", "run")
|
||||
rp: subprocess.CompletedProcess* = subprocess.run(exe_path, False, False)
|
||||
if rp is not None: VLogger.info(f"退出码: {rp.returncode}", "run")
|
||||
if rp is not None: VLogger.info(f"exit code: {rp.returncode}", "run")
|
||||
else:
|
||||
VLogger.error("链接失败", "PhaseC")
|
||||
VLogger.error("link failed", "PhaseC")
|
||||
stdlib.free(entries)
|
||||
stdlib.free(asm_entries)
|
||||
return 1
|
||||
|
||||
@@ -177,7 +177,7 @@ def _PyiBinOpOpText(buf: bytes, buf_size: sizet, pos: sizet, op: int, node: ast.
|
||||
if op == ast.OpKind.Mod: return _PyiEmit(buf, buf_size, pos, " % ")
|
||||
if op == ast.OpKind.BitAnd: return _PyiEmit(buf, buf_size, pos, " & ")
|
||||
if op == ast.OpKind.RShift: return _PyiEmit(buf, buf_size, pos, " >> ")
|
||||
GenApi.fatal_error(node, "vpi 类型注解节点类型未知", "TypeError")
|
||||
GenApi.fatal_error(node, "unknown vpi type-annotation node type", "TypeError")
|
||||
return pos # unreachable (fatal_error already exited)
|
||||
|
||||
|
||||
@@ -188,7 +188,7 @@ def _PyiTypeStr(buf: bytes, buf_size: sizet, pos: sizet, annot: ast.AST*, depth:
|
||||
# Recursion guard: a self-referential AST would recurse until stack exhaustion.
|
||||
# Fail fast instead of silently falling back.
|
||||
if depth > 64:
|
||||
VLogger.error("vpi 类型注解递归过深(AST 环或嵌套超过 64 层)", "StubGen")
|
||||
VLogger.error("vpi type annotation recursion too deep (AST cycle or nesting over 64 levels)", "StubGen")
|
||||
sys.exit(1)
|
||||
if annot is None: return _PyiEmit(buf, buf_size, pos, "int")
|
||||
|
||||
@@ -234,7 +234,7 @@ def _PyiTypeStr(buf: bytes, buf_size: sizet, pos: sizet, annot: ast.AST*, depth:
|
||||
elif uop_t.op == ast.OpKind.Invert: pos = _PyiEmit(buf, buf_size, pos, "~")
|
||||
elif uop_t.op == ast.OpKind.USub: pos = _PyiEmit(buf, buf_size, pos, "-")
|
||||
else:
|
||||
GenApi.fatal_error(annot, "vpi 类型注解节点类型未知", "TypeError")
|
||||
GenApi.fatal_error(annot, "unknown vpi type-annotation node type", "TypeError")
|
||||
return pos # unreachable (fatal_error already exited)
|
||||
return _PyiTypeStr(buf, buf_size, pos, uop_t.operand, depth + 1)
|
||||
|
||||
@@ -338,7 +338,7 @@ def _PyiTypeStr(buf: bytes, buf_size: sizet, pos: sizet, annot: ast.AST*, depth:
|
||||
return pos
|
||||
|
||||
# Unknown node type: fail fast rather than silently writing "int" and producing a wrong signature.
|
||||
GenApi.fatal_error(annot, "vpi 类型注解节点类型未知", "TypeError")
|
||||
GenApi.fatal_error(annot, "unknown vpi type-annotation node type", "TypeError")
|
||||
return _PyiEmit(buf, buf_size, pos, "int") # unreachable (fatal_error already exited)
|
||||
|
||||
|
||||
@@ -348,7 +348,7 @@ def _PyiDefaultStr(buf: bytes, buf_size: sizet, pos: sizet, node: ast.AST*, dept
|
||||
"""Render a default-value expression into buf and return the new pos"""
|
||||
# Recursion guard: fail fast on a self-referential AST (same as _PyiTypeStr)
|
||||
if depth > 64:
|
||||
VLogger.error("vpi 默认值表达式递归过深(AST 环或嵌套超过 64 层)", "StubGen")
|
||||
VLogger.error("vpi default-value expression recursion too deep (AST cycle or nesting over 64 levels)", "StubGen")
|
||||
sys.exit(1)
|
||||
if node is None: return pos
|
||||
|
||||
@@ -412,7 +412,7 @@ def _PyiRejectCReturnDecorator(node: ast.AST*, decorators: list[ast.AST*]*) -> i
|
||||
elif dnode.kind() == ast.ASTKind.Attribute: dattr = ast.Attribute*(dnode)
|
||||
if dattr is None or dattr.attr is None: continue
|
||||
if string.strcmp(dattr.attr, "CReturn") == 0:
|
||||
GenApi.fatal_error(node, "vpi 中仍带 `@c.CReturn`(已移除):请用返回注解 `-> tuple[ty1, ty2, ...]` 重新生成该 .vpi(可加 --clean)", "TypeError")
|
||||
GenApi.fatal_error(node, "vpi still contains `@c.CReturn` (removed): regenerate the .vpi using a return annotation `-> tuple[ty1, ty2, ...]` (you may add --clean)", "TypeError")
|
||||
return 1
|
||||
return 0
|
||||
|
||||
@@ -712,7 +712,7 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy*, tree: ast.AST*, rel_path: str, buf
|
||||
# fail-fast: an empty alias list would write a broken `import ` line and
|
||||
# lose all names, breaking package re-export registration.
|
||||
if imp2.names is None or len(imp2.names) == 0:
|
||||
GenApi.fatal_error(stmt, "vpi 生成:import 语句别名列表为空(应为 ≥1 个别名)——AST 构造/解析异常", "NameError")
|
||||
GenApi.fatal_error(stmt, "vpi generation: the import statement alias list is empty (expected >=1 alias) -- AST construction/parse anomaly", "NameError")
|
||||
if imp2.names is not None:
|
||||
imp2_names: list[ast.AST*]* = imp2.names
|
||||
an2: sizet = len(imp2_names)
|
||||
@@ -722,9 +722,9 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy*, tree: ast.AST*, rel_path: str, buf
|
||||
# fail-fast: never silently write "import , ". Import names are the
|
||||
# only input for package re-export registration. Report the two causes separately.
|
||||
if al2 is None:
|
||||
GenApi.fatal_error(stmt, "vpi 生成:import 别名**节点指针为空**(Alias(...) 构造未产出对象:" "pool.alloc 失败或 __init__ 未执行)——import 名字丢失会破坏包重导出注册", "NameError")
|
||||
GenApi.fatal_error(stmt, "vpi generation: import alias **node pointer is null** (Alias(...) construction produced no object: " "pool.alloc failed or __init__ was not run) -- losing the import name breaks package re-export registration", "NameError")
|
||||
if al2.name is None or al2.name[0] == '\0':
|
||||
GenApi.fatal_error(stmt, "vpi 生成:import 别名节点存在但 **name 为空**(_copy_str 返回 None / " "__init__ 未赋值 name)——import 名字丢失会破坏包重导出注册", "NameError")
|
||||
GenApi.fatal_error(stmt, "vpi generation: the import alias node exists but **name is empty** (_copy_str returned None / " "__init__ did not set name) -- losing the import name breaks package re-export registration", "NameError")
|
||||
pos = _PyiEmit(buf, buf_size, pos, al2.name)
|
||||
if al2.asname is not None and string.strlen(al2.asname) > 0:
|
||||
pos = _PyiEmit(buf, buf_size, pos, " as ")
|
||||
@@ -744,7 +744,7 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy*, tree: ast.AST*, rel_path: str, buf
|
||||
# fail-fast: same as Import; `from X import *` uses Alias("*"). An empty
|
||||
# list or empty name means a broken AST and would break re-export registration.
|
||||
if ifr.names is None or len(ifr.names) == 0:
|
||||
GenApi.fatal_error(stmt, "vpi 生成:from-import 语句别名列表为空(应为 ≥1 个别名,含 '*')" "——AST 构造/解析异常", "NameError")
|
||||
GenApi.fatal_error(stmt, "vpi generation: the from-import statement alias list is empty (expected >=1 alias, including star)" "-- AST construction/parse anomaly", "NameError")
|
||||
if ifr.names is not None:
|
||||
ifr_names: list[ast.AST*]* = ifr.names
|
||||
an3: sizet = len(ifr_names)
|
||||
@@ -753,9 +753,9 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy*, tree: ast.AST*, rel_path: str, buf
|
||||
al3: ast.Alias* = ast.Alias*(ifr_names.get(ai3))
|
||||
# fail-fast: same as Import (report the two causes separately).
|
||||
if al3 is None:
|
||||
GenApi.fatal_error(stmt, "vpi 生成:from-import 别名**节点指针为空**(Alias(...) 构造未产出对象:" "pool.alloc 失败或 __init__ 未执行)——包重导出注册会因此失效", "NameError")
|
||||
GenApi.fatal_error(stmt, "vpi generation: from-import alias **node pointer is null** (Alias(...) construction produced no object: " "pool.alloc failed or __init__ was not run) -- package re-export registration will therefore fail", "NameError")
|
||||
if al3.name is None or al3.name[0] == '\0':
|
||||
GenApi.fatal_error(stmt, "vpi 生成:from-import 别名节点存在但 **name 为空**(_copy_str 返回 None / " "__init__ 未赋值 name)——包重导出注册会因此失效", "NameError")
|
||||
GenApi.fatal_error(stmt, "vpi generation: the from-import alias node exists but **name is empty** (_copy_str returned None / " "__init__ did not set name) -- package re-export registration will therefore fail", "NameError")
|
||||
pos = _PyiEmit(buf, buf_size, pos, al3.name)
|
||||
if al3.asname is not None and string.strlen(al3.asname) > 0:
|
||||
pos = _PyiEmit(buf, buf_size, pos, " as ")
|
||||
|
||||
@@ -1391,7 +1391,7 @@ def _vpi_typedef_visited_mark(sha1: str) -> None:
|
||||
_g_vpi_typedef_visited = stdlib.malloc(_TYPEDEF_VISIT_MAX * 17)
|
||||
if _g_vpi_typedef_visited is None:
|
||||
# fail-fast: without the cycle table the closure re-parses and exhausts the pool, so do not continue
|
||||
stdio.printf("[VPI] 防环访问表分配失败(无表则闭包重解析爆炸,终止)\n")
|
||||
stdio.printf("[VPI] cycle-proof visit table allocation failed (without the table the closure reparse explodes; aborting)\n")
|
||||
stdio.fflush(None)
|
||||
stdlib.exit(1)
|
||||
string.memset(_g_vpi_typedef_visited, 0, _TYPEDEF_VISIT_MAX * 17)
|
||||
@@ -1404,7 +1404,7 @@ def _vpi_typedef_visited_mark(sha1: str) -> None:
|
||||
new_cap: int = old_cap * 2
|
||||
nb: bytes = stdlib.realloc(_g_vpi_typedef_visited, new_cap * 17)
|
||||
if nb is None:
|
||||
stdio.printf("[VPI] 防环访问表扩容失败 cap=%d(丢标记引发重解析爆炸,终止)\n", old_cap)
|
||||
stdio.printf("[VPI] cycle-proof visit table growth failed cap=%d (lost marks cause a reparse explosion; aborting)\n", old_cap)
|
||||
stdio.fflush(None)
|
||||
stdlib.exit(1)
|
||||
_g_vpi_typedef_visited = nb
|
||||
@@ -1709,7 +1709,7 @@ def _ParseVpiIntoModuleImpl(pool: memhub.MemBuddy*, mod: mlirlite.LLVMModule*, v
|
||||
# [D26 fail-fast] Do not silently skip when a package __init__ from-import cannot
|
||||
# resolve the submodule sha1: report package and submodule names for diagnosis.
|
||||
if is_pkg_init_rt != 0 and sub_sha1_rt is None and sifr_mod is not None and sifr_mod[0] != '\0':
|
||||
GenApi.fatal_error(sifr, f"包 stub 的 from-import 子模块 sha1 查找失败:" f"包={rel_path_rt if rel_path_rt is not None else '?'}," f"子模块='{sifr_mod}'(补前缀后='{sifr_mod_q}');" f"该子模块的类无法注册,引用它们的注解会在后续解析时落空", "NameError")
|
||||
GenApi.fatal_error(sifr, f"Package stub from-import submodule sha1 lookup failed: " f"package={rel_path_rt if rel_path_rt is not None else '?'}, " f"submodule='{sifr_mod}' (after prefix completion='{sifr_mod_q}'); " f"classes of this submodule cannot be registered, and annotations referencing them will fail to resolve later", "NameError")
|
||||
if sifr.names is not None:
|
||||
sifr_nn: sizet = len(sifr.names)
|
||||
sifri: sizet
|
||||
@@ -2375,7 +2375,7 @@ def _inject_function_declare(pool: memhub.MemBuddy*, mod: mlirlite.LLVMModule*,
|
||||
# [S4 fail-fast] A return annotation that does not resolve is not silently downgraded to i32;
|
||||
# no annotation (fd.returns is None) is a legitimate default and keeps i32 below.
|
||||
if ret_ty is None and fd.returns is not None:
|
||||
GenApi.fatal_error(fd.returns, f"extern 声明 '{fd.name}' 返回类型注解解析失败", "NameError")
|
||||
GenApi.fatal_error(fd.returns, f"extern declaration '{fd.name}' return type annotation failed to resolve", "NameError")
|
||||
# default return i32
|
||||
if ret_ty is None: ret_ty = i32_ty
|
||||
|
||||
@@ -2400,7 +2400,7 @@ def _inject_function_declare(pool: memhub.MemBuddy*, mod: mlirlite.LLVMModule*,
|
||||
# Param-count upper-bound sentinel (fail-fast): a corrupted vpi tree node makes __len__()
|
||||
# return a huge value, so add_param runs massively and the Params chain balloons.
|
||||
if param_count < 0 or param_count > 128:
|
||||
stdio.printf("[VPIS] 参数数异常: 函数名=%s param_count=%d(fd.args=%llu,tree 可能被覆盖,终止)\n", fd.name, param_count, uint64(fd.args))
|
||||
stdio.printf("[VPIS] abnormal parameter count: function=%s param_count=%d (fd.args=%llu, tree may be overwritten; aborting)\n", fd.name, param_count, uint64(fd.args))
|
||||
# convergence point: longjmp back to the REPL loop in a REPL session (diagnostics printed)
|
||||
VLogger.repl_abort()
|
||||
pi: sizet
|
||||
@@ -2439,7 +2439,7 @@ def _inject_function_declare(pool: memhub.MemBuddy*, mod: mlirlite.LLVMModule*,
|
||||
else:
|
||||
# [S4 fail-fast] An annotation that does not resolve is not silently downgraded
|
||||
# to i8* (no annotation is a legitimate default and keeps i8*).
|
||||
GenApi.fatal_error(ag.annotation, f"extern 声明 '{fd.name}' 形参 '{pname}' 类型注解解析失败", "NameError")
|
||||
GenApi.fatal_error(ag.annotation, f"extern declaration '{fd.name}' parameter '{pname}' type annotation failed to resolve", "NameError")
|
||||
mlirlite.add_param(pool, func, param_ty, pname)
|
||||
# Text-cache repair: a corrupted vpi tree truncates args, leaving too few declare params;
|
||||
# complete them from the vpi text param annotations so declare matches define.
|
||||
@@ -2455,7 +2455,7 @@ def _inject_function_declare(pool: memhub.MemBuddy*, mod: mlirlite.LLVMModule*,
|
||||
if fd_default_count < 0 or fd_default_count > 128:
|
||||
# A corrupted args.defaults node makes len return a huge value, so
|
||||
# _register_global_defaults would over-allocate and write out of bounds; skip it.
|
||||
stdio.printf("[VPIS] 默认参数数异常: 函数名=%s default_count=%d(tree 可能被覆盖,跳过默认值注册)\n", fd.name, fd_default_count)
|
||||
stdio.printf("[VPIS] abnormal default parameter count: function=%s default_count=%d (tree may be overwritten; skipping default value registration)\n", fd.name, fd_default_count)
|
||||
fd_defaults = None
|
||||
fd_default_count = 0
|
||||
else: fd_defaults = fd_dlist
|
||||
@@ -2512,7 +2512,7 @@ def _inject_method_declare(pool: memhub.MemBuddy*, mod: mlirlite.LLVMModule*, m_
|
||||
# [S4 fail-fast] A return annotation that does not resolve is not silently downgraded to i32;
|
||||
# unannotated __new__ / normal methods keep i32 as the legitimate default below.
|
||||
if ret_ty is None and m_fd.returns is not None:
|
||||
GenApi.fatal_error(m_fd.returns, f"extern 方法 '{cls_name}.{m_fd.name}' 返回类型注解解析失败", "NameError")
|
||||
GenApi.fatal_error(m_fd.returns, f"extern method '{cls_name}.{m_fd.name}' return type annotation failed to resolve", "NameError")
|
||||
# Unannotated __init__ -> Void, matching the definition side (ClassGenVTable always uses Void);
|
||||
# defaulting to i32 would split declare i32 / define void.
|
||||
if ret_ty is None and string.strcmp(m_fd.name, "__init__") == 0: ret_ty = mlirlite.Void(pool)
|
||||
@@ -2534,7 +2534,7 @@ def _inject_method_declare(pool: memhub.MemBuddy*, mod: mlirlite.LLVMModule*, m_
|
||||
# Param-count upper-bound sentinel (fail-fast): same cause as _inject_function_declare
|
||||
# (a corrupted vpi tree node makes __len__() return a huge value).
|
||||
if param_count < 0 or param_count > 128:
|
||||
stdio.printf("[VPIS] 参数数异常: 方法名=%s.%s param_count=%d(m_fd.args=%llu,tree 可能被覆盖,终止)\n", cls_name, m_fd.name, param_count, uint64(m_fd.args))
|
||||
stdio.printf("[VPIS] abnormal parameter count: method=%s.%s param_count=%d (m_fd.args=%llu, tree may be overwritten; aborting)\n", cls_name, m_fd.name, param_count, uint64(m_fd.args))
|
||||
# convergence point: longjmp back to the REPL loop in a REPL session (diagnostics printed)
|
||||
VLogger.repl_abort()
|
||||
pi: sizet
|
||||
@@ -2579,7 +2579,7 @@ def _inject_method_declare(pool: memhub.MemBuddy*, mod: mlirlite.LLVMModule*, m_
|
||||
else:
|
||||
# [S4 fail-fast] An annotation that does not resolve is not silently downgraded
|
||||
# to i8* (no annotation is a legitimate default and keeps i8*).
|
||||
GenApi.fatal_error(ag.annotation, f"extern 方法 '{cls_name}.{m_fd.name}' 形参 '{pname}' 类型注解解析失败", "NameError")
|
||||
GenApi.fatal_error(ag.annotation, f"extern method '{cls_name}.{m_fd.name}' parameter '{pname}' type annotation failed to resolve", "NameError")
|
||||
mlirlite.add_param(pool, func, param_ty, pname)
|
||||
|
||||
# Text-cache repair: a corrupted vpi tree truncates args, leaving too few declare params;
|
||||
@@ -2603,7 +2603,7 @@ def _inject_method_declare(pool: memhub.MemBuddy*, mod: mlirlite.LLVMModule*, m_
|
||||
if md_default_count < 0 or md_default_count > 128:
|
||||
# Same as _inject_function_declare: a corrupted tree node makes defaults len huge,
|
||||
# which would write out of bounds into perm_pool; skip registration.
|
||||
stdio.printf("[VPIS] 默认参数数异常: 方法名=%s.%s default_count=%d(tree 可能被覆盖,跳过默认值注册)\n", cls_name, m_fd.name, md_default_count)
|
||||
stdio.printf("[VPIS] abnormal default parameter count: method=%s.%s default_count=%d (tree may be overwritten; skipping default value registration)\n", cls_name, m_fd.name, md_default_count)
|
||||
md_defaults = None
|
||||
md_default_count = 0
|
||||
else: md_defaults = md_dlist
|
||||
@@ -2902,7 +2902,7 @@ def _repl_stub_warn_refuse(e: ReplStubClass*, why: str, a: int, b: int) -> None:
|
||||
ReplStubRefused += 1
|
||||
if ReplStubWarnLeft <= 0: return
|
||||
ReplStubWarnLeft -= 1
|
||||
stdio.printf("includes 类布局: %s.%s 布局不可信 ⇒ 明确拒绝(原因=判据拒绝:%s;" "存根字段数=%d ≠ 展平字段数+虚表位=%d)。该类字段访问被明确拒绝" "(方法调用不受影响)\n", e.Sha1, e.ClassName, why, a, b)
|
||||
stdio.printf("includes class layout: layout of %s.%s is untrusted => explicitly refused (reason=criterion refused: %s; " "stub field count=%d != flattened field count+vtable slots=%d). Field access on this class is explicitly refused " "(method calls are unaffected)\n", e.Sha1, e.ClassName, why, a, b)
|
||||
|
||||
|
||||
def _repl_stub_warn_nodata(e: ReplStubClass*, cause: int) -> None:
|
||||
@@ -2919,13 +2919,13 @@ def _repl_stub_warn_nodata(e: ReplStubClass*, cause: int) -> None:
|
||||
ReplStubWarnLeft -= 1
|
||||
if cause == _REPL_SU_NOSTUB:
|
||||
# missing data: not even module layout metadata (LayoutCount = -1 is just a "not read" sentinel)
|
||||
stdio.printf("includes 类布局: %s.%s 布局不可用 ⇒ 明确拒绝(原因=『数据缺失』:" "模块 %s 没有 {sha1}.meta 布局元数据;meta 字段数=无 / 推断字段数=未计算 ⇒ " "两侧都没数据,『未做比较』,不是字段数不符)。该类字段访问被" "拒绝(方法调用不受影响);补上该模块 meta(同一工程先跑一次批处理," "Phase A/B 会落盘 {sha1}.meta)后用同一 --project 重跑 REPL 即恢复\n", e.Sha1, e.ClassName, e.Sha1)
|
||||
stdio.printf("includes class layout: layout of %s.%s unavailable => explicitly refused (reason=data missing: " "module %s has no {sha1}.meta layout metadata; meta field count=none / inferred field count=not computed => " "no data on either side, no comparison was made, and this is not a field count mismatch). Field access on this class is " "refused (method calls are unaffected); add the module meta (run batch processing once in the same project, " "Phase A/B writes {sha1}.meta), then rerun REPL with the same --project to recover\n", e.Sha1, e.ClassName, e.Sha1)
|
||||
elif cause == _REPL_SU_OPAQUE:
|
||||
# refused: the key is OPAQUE in meta (no body, so no field count to compare)
|
||||
stdio.printf("includes 类布局: %s.%s 布局不可用 ⇒ 明确拒绝(原因=『判据拒绝』:" "meta %s.meta 里键 %s 为 OPAQUE 声明(无 body);meta 字段数=不可得 / " "推断字段数=未计算 ⇒ 『未做比较』)。该类字段访问被拒绝" "(方法调用不受影响)\n", e.Sha1, e.ClassName, e.Sha1, e.Key)
|
||||
stdio.printf("includes class layout: layout of %s.%s unavailable => explicitly refused (reason=criterion refused: " "key %s in meta %s.meta is declared OPAQUE (no body); meta field count=unavailable / " "inferred field count=not computed => no comparison was made). Field access on this class is refused " "(method calls are unaffected)\n", e.Sha1, e.ClassName, e.Sha1, e.Key)
|
||||
else:
|
||||
# refused: meta exists but has no STRUCT line for this class (LayoutCount = -1 is a "not found" sentinel)
|
||||
stdio.printf("includes 类布局: %s.%s 布局不可用 ⇒ 明确拒绝(原因=『判据拒绝』:" "meta %s.meta 存在但其中没有键 %s 的 `STRUCT … FIELDS n / OPAQUE` 记录;" "meta 字段数=未找到 / 推断字段数=未计算 ⇒ 『未做比较』)。该类字段访问" "被拒绝(方法调用不受影响);若该类确实定义于该模块,说明 meta 陈旧/" "不完整,请重建\n", e.Sha1, e.ClassName, e.Sha1, e.Key)
|
||||
stdio.printf("includes class layout: layout of %s.%s unavailable => explicitly refused (reason=criterion refused: " "meta %s.meta exists but has no `STRUCT ... FIELDS n / OPAQUE` record for key %s; " "meta field count=not found / inferred field count=not computed => no comparison was made). Field access on this class is " "refused (method calls are unaffected); if this class is indeed defined in that module, the meta is stale/" "incomplete, please rebuild\n", e.Sha1, e.ClassName, e.Sha1, e.Key)
|
||||
|
||||
|
||||
def _repl_stub_warn_parent(e: ReplStubClass*, detail: str, pname: str) -> None:
|
||||
@@ -2935,7 +2935,7 @@ def _repl_stub_warn_parent(e: ReplStubClass*, detail: str, pname: str) -> None:
|
||||
ReplStubRefusedParent += 1
|
||||
if ReplStubWarnLeft <= 0: return
|
||||
ReplStubWarnLeft -= 1
|
||||
stdio.printf("includes 类布局: %s.%s 布局不可用 ⇒ 明确拒绝(原因=『上游无数据』:%s," "父类=%s;父类字段与虚表位无法展平 ⇒ 本类未做字段数比较)。该类字段访问" "被拒绝(方法调用不受影响)\n", e.Sha1, e.ClassName, detail, pname)
|
||||
stdio.printf("includes class layout: layout of %s.%s unavailable => explicitly refused (reason=upstream no data: %s, " "parent=%s; parent fields and vtable slots cannot be flattened => no field count comparison was done for this class). Field access on this class is " "refused (method calls are unaffected)\n", e.Sha1, e.ClassName, detail, pname)
|
||||
|
||||
|
||||
def _repl_stub_try(e: ReplStubClass*, mod: mlirlite.LLVMModule*) -> int:
|
||||
@@ -2957,13 +2957,13 @@ def _repl_stub_try(e: ReplStubClass*, mod: mlirlite.LLVMModule*) -> int:
|
||||
if pe.State == _REPL_SS_PENDING: return 0
|
||||
if pe.State == _REPL_SS_REFUSED:
|
||||
e.State = _REPL_SS_REFUSED
|
||||
_repl_stub_warn_parent(e, "父类布局不可信", pe.ClassName)
|
||||
_repl_stub_warn_parent(e, "Parent layout untrusted", pe.ClassName)
|
||||
return -1
|
||||
if pe.State == _REPL_SS_EMPTY and pe.OwnFail != 0:
|
||||
# The base itself had field-annotation failures, so its Count is only partially parsed:
|
||||
# the flattened field count is unusable, so neither compare nor allow it (M4.2: refuse).
|
||||
e.State = _REPL_SS_REFUSED
|
||||
_repl_stub_warn_parent(e, "父类的字段类型未全部解析(其字段数不完整)", pe.ClassName)
|
||||
_repl_stub_warn_parent(e, "Not all field types of the parent are resolved (its field count is incomplete)", pe.ClassName)
|
||||
return -1
|
||||
first: ReplStubClass* = None
|
||||
if e.BaseCount > 0: first = _repl_stub_find_base(e, 0)
|
||||
@@ -3003,7 +3003,7 @@ def _repl_stub_try(e: ReplStubClass*, mod: mlirlite.LLVMModule*) -> int:
|
||||
# __vtable__ (if any) + flattened field count.
|
||||
if e.LayoutCount != cn + hv:
|
||||
e.State = _REPL_SS_REFUSED
|
||||
_repl_stub_warn_refuse(e, "存根字段数与字段名单不符", e.LayoutCount, cn + hv)
|
||||
_repl_stub_warn_refuse(e, "Stub field count does not match the field name list", e.LayoutCount, cn + hv)
|
||||
return -1
|
||||
# (5) virtual method short-name order (base virtuals first + own eligible methods in class order)
|
||||
vn: int = 0
|
||||
@@ -3036,7 +3036,7 @@ def _repl_stub_try(e: ReplStubClass*, mod: mlirlite.LLVMModule*) -> int:
|
||||
if vn == e.VtArity: e.VtTrust = 1
|
||||
elif ReplStubWarnLeft > 0:
|
||||
ReplStubWarnLeft -= 1
|
||||
stdio.printf("includes 类布局: %s.%s 的虚表槽数与存根不符(%d vs %d)" "——该类不做虚分派(退化为直接调用,会话继续)\n", e.Sha1, e.ClassName, vn, e.VtArity)
|
||||
stdio.printf("includes class layout: vtable slot count of %s.%s does not match the stub (%d vs %d) " "-- this class skips virtual dispatch (degrades to direct call, session continues)\n", e.Sha1, e.ClassName, vn, e.VtArity)
|
||||
# (6) build the LLVM struct (named "%<sha1>.<ClassName>", same as the definition side)
|
||||
total: int = cn + hv
|
||||
i8_ptr: mlirlite.LLVMType* = mlirlite.Ptr(pool, mlirlite.Int8(pool))
|
||||
@@ -3255,7 +3255,7 @@ def _repl_stub_collect_module(pool: memhub.MemBuddy*, mod: mlirlite.LLVMModule*,
|
||||
ReplStubNoStub += 1
|
||||
if ReplStubWarnLeft > 0:
|
||||
ReplStubWarnLeft -= 1
|
||||
stdio.printf("includes 类布局: 模块 %s 无 .meta 存根(数据缺失)—— 该模块" "带父类/虚表的类将逐个按『数据缺失』明确拒绝(读不到布局元数据 ⇒ 无" "字段数可比,不是字段数不符)。用同一工程先跑一次批处理生成存根," "再 `--project .\\project.vpj --repl`(TransPyV 目录)即可复用\n", src_sha1)
|
||||
stdio.printf("includes class layout: module %s has no .meta stub (data missing) -- this module " "classes with parent/vtable will each be explicitly refused as data missing (layout metadata cannot be read => no " "field count to compare, not a field count mismatch). First run batch processing once in the same project to generate stubs, " "then reuse them with `--project .\\project.vpj --repl` (in the TransPyV directory)\n", src_sha1)
|
||||
cnt: int = 0
|
||||
i: sizet
|
||||
for i in range(n):
|
||||
@@ -3298,22 +3298,22 @@ def ReplStubLayoutFinish() -> int:
|
||||
if e2 is None or e2.State != _REPL_SS_PENDING: continue
|
||||
e2.State = _REPL_SS_REFUSED
|
||||
# find the still-unready base class name (to identify the upstream)
|
||||
pbad: str = "(未定位)"
|
||||
pbad: str = "(not located)"
|
||||
bi2: int
|
||||
for bi2 in range(e2.BaseCount):
|
||||
peb: ReplStubClass* = _repl_stub_find_base(e2, bi2)
|
||||
if peb is not None and peb.State == _REPL_SS_OK: continue
|
||||
if peb is not None and peb.ClassName is not None: pbad = peb.ClassName
|
||||
break
|
||||
_repl_stub_warn_parent(e2, "父类未在会话注册或其布局被拒", pbad)
|
||||
stdio.printf("includes 类布局: 完整布局 %d 个(其中虚表索引可用 %d 个)/ " "被拒 %d 个 / 缺布局元数据模块 %d 个\n", ReplStubOk, ReplStubVtOk, ReplStubRefused, ReplStubNoStub)
|
||||
stdio.printf(" 拒绝原因分布(自证数据来源):数据缺失-模块无 {sha1}.meta %d 个类 / " "判据拒绝-meta 无此类 %d 个 / 判据拒绝-meta 为 opaque %d 个 / " "上游无数据-父类不可用 %d 个\n", ReplStubRefusedNoStub, ReplStubRefusedNoClass, ReplStubRefusedOpaque, ReplStubRefusedParent)
|
||||
_repl_stub_warn_parent(e2, "Parent not registered in the session or its layout was refused", pbad)
|
||||
stdio.printf("includes class layout: %d complete layouts (%d with a usable vtable index) / " "%d refused / %d modules missing layout metadata\n", ReplStubOk, ReplStubVtOk, ReplStubRefused, ReplStubNoStub)
|
||||
stdio.printf(" refusal reason distribution (self-witnessing data source): data missing-module has no {sha1}.meta %d classes / " "criterion refused-meta has no such class %d / criterion refused-meta is opaque %d / " "upstream no data-parent unavailable %d\n", ReplStubRefusedNoStub, ReplStubRefusedNoClass, ReplStubRefusedOpaque, ReplStubRefusedParent)
|
||||
if ReplStubRefused > 0 or ReplStubNoStub > 0:
|
||||
stdio.printf(" 说明:被拒类的字段访问会报『类未注册/属性访问失败』" "(不按错偏移静默访问);方法调用不受影响。\n")
|
||||
stdio.printf(" Note: field access on refused classes reports class not registered/attribute access failed " "(it does not silently access at a wrong offset); method calls are unaffected.\n")
|
||||
if ReplStubRefusedNoStub > 0:
|
||||
stdio.printf(" 其中『数据缺失』的 %d 个类只是没读到模块布局元数据(本会话临时目录 %s " "缺这些 {sha1}.meta):批处理才会落盘 meta(REPL 分支在 Phase1 之前" "返回,故 --repl 自身不生成存根)。修法:用同一个工程跑一次批处理" "(TransPyV 目录:.\\tpv_build\\output\\TransPyV.exe --project " ".\\project.vpj;includes 有改动时加 --rebuild-includes),随后 " "--project .\\project.vpj --repl 复用其临时目录即可\n", ReplStubRefusedNoStub, ReplStubTempDir)
|
||||
stdio.printf(" Of these, the %d classes with data missing simply failed to read the module layout metadata (the session temp directory %s " "is missing these {sha1}.meta): only batch processing writes meta to disk (the REPL branch runs before Phase1 " "and returns, so --repl itself does not generate stubs). Fix: run batch processing once in the same project " "(TransPyV directory: .\\tpv_build\\output\\TransPyV.exe --project " ".\\project.vpj; add --rebuild-includes when includes changed), then " "reuse its temp directory with --project .\\project.vpj --repl\n", ReplStubRefusedNoStub, ReplStubTempDir)
|
||||
if ReplStubRefusedNoClass + ReplStubRefusedOpaque > 0:
|
||||
stdio.printf(" 其中『判据拒绝』的 %d 个类:数据在但不可信(存根里没有该类的字段数、" "或其声明为 opaque),按 M4.2 一律不放行——请确认该类是否本应按结构体" "登记:应按结构体登记而存根里查不到 ⇒ 存根陈旧/不完整(重建 includes " "存根)\n", ReplStubRefusedNoClass + ReplStubRefusedOpaque)
|
||||
stdio.printf(" Of these, the %d classes with criterion refused: data exists but is untrusted (the stub has no field count for this class, " "or it is declared opaque); per M4.2 none are allowed through -- please confirm whether this class should have been registered as a struct " "in the first place: if it should be registered as a struct but is not found in the stub => the stub is stale/incomplete (rebuild includes " "stubs)\n", ReplStubRefusedNoClass + ReplStubRefusedOpaque)
|
||||
return ReplStubOk
|
||||
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ def _AppendDepsToWorklist(worklist: bytes, wl_len: sizet, deps_str: str, process
|
||||
worklist[cur_len] = '\0'
|
||||
else:
|
||||
stdlib.free(dmod)
|
||||
VLogger.error("依赖 worklist 溢出", "StubMerger")
|
||||
VLogger.error("dependency worklist overflow", "StubMerger")
|
||||
return -1
|
||||
stdlib.free(dmod)
|
||||
return int(cur_len)
|
||||
@@ -83,7 +83,7 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str,
|
||||
"""Build the reachable SHA1 set by on-demand dependency-graph scanning."""
|
||||
if source_dir is None or temp_dir is None or reachable_set is None: return -1
|
||||
if includes_dirs is None:
|
||||
VLogger.error("includes_dirs 缺失,无法按需解析依赖图", "Reachable")
|
||||
VLogger.error("includes_dirs is missing; cannot resolve the dependency graph on demand", "Reachable")
|
||||
return -1
|
||||
|
||||
SRC_BUF_SIZE_R: sizet = 1048576
|
||||
@@ -96,7 +96,7 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str,
|
||||
|
||||
# 1. App scan (skipped when app_deps is non-empty; use the caller-provided initial queue directly)
|
||||
if app_deps is None or app_deps[0] == '\0':
|
||||
VLogger.info("App 扫描:解析 source_dir 的 import 依赖", "Reachable")
|
||||
VLogger.info("App scan: resolving import dependencies of source_dir", "Reachable")
|
||||
scan_res_r: IncludesScanner.ScanResult* = IncludesScanner.scan_includes(mb, source_dir)
|
||||
if scan_res_r is not None:
|
||||
es_r: sizet = IncludesScanner.FileEntry.__sizeof__()
|
||||
@@ -176,7 +176,7 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str,
|
||||
string.strcpy(worklist, app_deps)
|
||||
wl_len = ad_len
|
||||
else:
|
||||
VLogger.error("app_deps 过长,无法构建可达集合", "StubMerger")
|
||||
VLogger.error("app_deps is too long; cannot build the reachable set", "StubMerger")
|
||||
stdlib.free(worklist)
|
||||
return -1
|
||||
|
||||
@@ -212,7 +212,7 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str,
|
||||
if tb_inc is not None: stdlib.free(tb_inc)
|
||||
if tb_found != 0:
|
||||
stdlib.free(worklist)
|
||||
VLogger.error(f"--traceback: 在 includes 目录中找不到 traceback.vp,无法编译并链接 Install()(请确认 project.vpj 的 includes 包含仓库 includes 目录;已扫描: {includes_dirs})", "Traceback")
|
||||
VLogger.error(f"--traceback: traceback.vp not found in the includes dirs; cannot compile and link Install() (make sure the includes of project.vpj contains the repository includes directory; scanned: {includes_dirs})", "Traceback")
|
||||
return -1
|
||||
tb_wl: int = _AppendDepsToWorklist(worklist, wl_len, "traceback", None)
|
||||
if tb_wl < 0:
|
||||
@@ -264,7 +264,7 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str,
|
||||
proc_len = proc_len + 1
|
||||
processed[proc_len] = '\0'
|
||||
else:
|
||||
VLogger.error("依赖 processed 溢出", "StubMerger")
|
||||
VLogger.error("dependency processed overflow", "StubMerger")
|
||||
stdlib.free(mod_buf)
|
||||
continue
|
||||
|
||||
@@ -383,7 +383,7 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str,
|
||||
# parse_tokens keeps the error detail (line/col/message) only in the global channel, so print the unified
|
||||
# parse traceback before the one-line log; without it a reachable-includes syntax error is undiagnosable.
|
||||
GenApi.dump_parse_traceback(abs_path)
|
||||
VLogger.error(f"可达 includes 解析失败: {abs_path}", "Reachable")
|
||||
VLogger.error(f"reachable includes parse failed: {abs_path}", "Reachable")
|
||||
stdlib.free(abs_path)
|
||||
stdlib.free(rel_path)
|
||||
stdlib.free(inc_dir)
|
||||
@@ -421,7 +421,7 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str,
|
||||
GenApi.reset_visible_structs(mb, 0)
|
||||
ret_r2: int = tr_r2.translate(tree_r)
|
||||
if ret_r2 != 0:
|
||||
VLogger.error(f"import 依赖扫描失败(可达 includes): {abs_path}", "Reachable")
|
||||
VLogger.error(f"import dependency scan failed (reachable includes): {abs_path}", "Reachable")
|
||||
stdlib.free(abs_path)
|
||||
stdlib.free(rel_path)
|
||||
stdlib.free(inc_dir)
|
||||
@@ -471,7 +471,7 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str,
|
||||
mb.reset_to(scan_mark_r)
|
||||
return -1
|
||||
wl_len = sizet(ret_w)
|
||||
else: VLogger.debug(f"无依赖: {rel_path}", "Reachable")
|
||||
else: VLogger.debug(f"no dependencies: {rel_path}", "Reachable")
|
||||
|
||||
# Free the Translator's C malloc resources and reclaim this file's AST
|
||||
if tr_r2._global_names is not None: stdlib.free(tr_r2._global_names)
|
||||
@@ -506,7 +506,7 @@ def LoadFullIR(temp_dir: str, sha1: str, out_buf: bytes, out_size: sizet) -> siz
|
||||
if f.closed: return 0
|
||||
if f.size() >= out_size:
|
||||
f.close()
|
||||
VLogger.error("full.ll 超过 IR 缓冲上限", "StubMerger")
|
||||
VLogger.error("full.ll exceeds the IR buffer limit", "StubMerger")
|
||||
return 0
|
||||
rd: int64 = f.read_all(out_buf, out_size)
|
||||
f.close()
|
||||
|
||||
@@ -33,29 +33,29 @@ import lib.Stub.StubMerger as StubMerger
|
||||
def WriteModuleMeta(mod: mlirlite.LLVMModule*, temp_dir: str, td_len: sizet, sha1: str) -> int:
|
||||
"""Write the module's func defines, struct layouts and vtables to {sha1}.meta."""
|
||||
if mod is None or temp_dir is None or sha1 is None:
|
||||
VLogger.error("meta 写出:参数为空", "Meta")
|
||||
VLogger.error("meta write: null argument", "Meta")
|
||||
return 1
|
||||
mpath: str = StubMergerCollect._sliced_path(temp_dir, td_len, sha1, "meta")
|
||||
if mpath is None:
|
||||
VLogger.error("meta 写出:路径构造失败", "Meta")
|
||||
VLogger.error("meta write: path construction failed", "Meta")
|
||||
return 1
|
||||
mf: fileio.File = fileio.File(mpath, fileio.MODE.W)
|
||||
if mf.closed:
|
||||
VLogger.error(f"meta 写出:无法打开 {mpath}", "Meta")
|
||||
VLogger.error(f"meta write: cannot open {mpath}", "Meta")
|
||||
return 1
|
||||
cur: mlirlite.Function* = mod.FuncHead
|
||||
steps: sizet = 0
|
||||
while cur is not None:
|
||||
steps += 1
|
||||
if steps > 100000:
|
||||
VLogger.error("meta 写出:函数链表成环/超限", "Meta")
|
||||
VLogger.error("meta write: function list has a cycle or exceeded the limit", "Meta")
|
||||
break
|
||||
nm: str = mlirlite.function_get_name(cur)
|
||||
if nm is not None:
|
||||
nlen: sizet = string.strlen(nm)
|
||||
line: bytes = stdlib.malloc(nlen + 16)
|
||||
if line is None:
|
||||
VLogger.error("meta 写出:行缓冲分配失败", "Meta")
|
||||
VLogger.error("meta write: line buffer allocation failed", "Meta")
|
||||
break
|
||||
mark: str = "DECL"
|
||||
if mlirlite.function_is_declared(cur) == 0: mark = "DEF"
|
||||
@@ -69,14 +69,14 @@ def WriteModuleMeta(mod: mlirlite.LLVMModule*, temp_dir: str, td_len: sizet, sha
|
||||
while nt is not None:
|
||||
nt_steps += 1
|
||||
if nt_steps > 100000:
|
||||
VLogger.error("meta 写出:命名类型链表成环/超限", "Meta")
|
||||
VLogger.error("meta write: named-type list has a cycle or exceeded the limit", "Meta")
|
||||
break
|
||||
tn: str = mlirlite.get_struct_name(nt.Ty)
|
||||
if tn is not None and tn[0] != '\0':
|
||||
tl: sizet = string.strlen(tn)
|
||||
lb: bytes = stdlib.malloc(tl + 48)
|
||||
if lb is None:
|
||||
VLogger.error("meta 写出:行缓冲分配失败", "Meta")
|
||||
VLogger.error("meta write: line buffer allocation failed", "Meta")
|
||||
break
|
||||
fc: int = mlirlite.get_struct_fcount(nt.Ty)
|
||||
if fc < 0: viperlib.snprintf(lb, tl + 48, "STRUCT %s OPAQUE\n", tn)
|
||||
@@ -90,7 +90,7 @@ def WriteModuleMeta(mod: mlirlite.LLVMModule*, temp_dir: str, td_len: sizet, sha
|
||||
while gv is not None:
|
||||
gv_steps += 1
|
||||
if gv_steps > 100000:
|
||||
VLogger.error("meta 写出:全局变量链表成环/超限", "Meta")
|
||||
VLogger.error("meta write: global-variable list has a cycle or exceeded the limit", "Meta")
|
||||
break
|
||||
gn: str = gv.Name
|
||||
if gn is not None:
|
||||
@@ -104,7 +104,7 @@ def WriteModuleMeta(mod: mlirlite.LLVMModule*, temp_dir: str, td_len: sizet, sha
|
||||
ar: int = mlirlite.get_struct_fcount(gv.Ty)
|
||||
if ar < 0: ar = 0
|
||||
lb2: bytes = stdlib.malloc(base_len + 40)
|
||||
if lb2 is None: VLogger.error("meta 写出:行缓冲分配失败", "Meta")
|
||||
if lb2 is None: VLogger.error("meta write: line buffer allocation failed", "Meta")
|
||||
else:
|
||||
viperlib.snprintf(lb2, base_len + 40, "VTABLE %s SLOTS %d\n", base, ar)
|
||||
mf.write(lb2, string.strlen(lb2))
|
||||
|
||||
@@ -147,7 +147,7 @@ def PopulateSha1MapStore(scan_result: IncludesScanner.ScanResult*) -> int:
|
||||
p_bad: int = 0
|
||||
entry_size_p: sizet = IncludesScanner.FileEntry.__sizeof__()
|
||||
for i in range(scan_result.Count):
|
||||
if StubMerger._sha1_store_count >= StubMerger.MAX_INCLUDES: VLogger.error("includes SHA1 存储超上限,终止", "StubMerger")
|
||||
if StubMerger._sha1_store_count >= StubMerger.MAX_INCLUDES: VLogger.error("includes SHA1 store exceeded the limit; aborting", "StubMerger")
|
||||
ea: uint64 = uint64(scan_result.Entries) + i * entry_size_p
|
||||
ent: IncludesScanner.FileEntry* = IncludesScanner.FileEntry*(ea)
|
||||
if ent is None or ent.Sha1 is None or ent.RelPath is None:
|
||||
@@ -187,7 +187,7 @@ def PopulateSha1MapStore(scan_result: IncludesScanner.ScanResult*) -> int:
|
||||
string.strncpy(StubMerger._sha1_store_incdir + idx_inc, ent.IncDir, StubMerger.MAX_INC_DIR_LEN - 1)
|
||||
StubMerger._sha1_store_incdir[idx_inc + StubMerger.MAX_INC_DIR_LEN - 1] = '\0'
|
||||
StubMerger._sha1_store_count += 1
|
||||
if p_bad > 0: VLogger.error(f"includes SHA1 存储有 {p_bad} 个条目失败", "StubMerger")
|
||||
if p_bad > 0: VLogger.error(f"includes SHA1 store has {p_bad} failed entries", "StubMerger")
|
||||
return StubMerger._sha1_store_count
|
||||
# AppendToSha1MapStore - append an App module entry to the global SHA1 store (Phase2 use);
|
||||
# auto-initializes if empty, skips on duplicate SHA1. Returns 0 ok, 1 failed.
|
||||
|
||||
@@ -52,7 +52,7 @@ novirtual class AssignGenMixin:
|
||||
if cn.const_kind == ast.CONST_BOOL: return 1 if cn.int_val != 0 else 0
|
||||
if cn.const_kind != ast.CONST_INT:
|
||||
# Non-INT constant: fail fast
|
||||
self.Gen.TypeGenErr.fatal_error(val_node, "CDefine 值提取失败:无法从表达式解析编译期常量", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(val_node, "CDefine value extraction failed: cannot parse a compile-time constant from the expression", "TypeError")
|
||||
return cn.int_val
|
||||
|
||||
# Case 2: BinOp - e.g. FOREGROUND_RED | FOREGROUND_GREEN, (1 << N)
|
||||
@@ -72,7 +72,7 @@ novirtual class AssignGenMixin:
|
||||
if bop.op == ast.OpKind.FloorDiv: return left_val // right_val
|
||||
if bop.op == ast.OpKind.Mod: return left_val % right_val
|
||||
# Unknown BinOp operator: fail fast
|
||||
self.Gen.TypeGenErr.fatal_error(val_node, "CDefine 值提取失败:无法从表达式解析编译期常量", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(val_node, "CDefine value extraction failed: cannot parse a compile-time constant from the expression", "TypeError")
|
||||
|
||||
# Case 3: Name - a registered CDefine constant or True/False literal
|
||||
if k == ast.ASTKind.Name:
|
||||
@@ -84,7 +84,7 @@ novirtual class AssignGenMixin:
|
||||
looked_up: int64 = self.Gen.TypeGenCDef.lookup_cdefine_constant(nm.id)
|
||||
if self.Gen.TypeGenCDef.is_cdefine_found() != 0: return looked_up
|
||||
# Unregistered reference: fail fast
|
||||
self.Gen.TypeGenErr.fatal_error(val_node, "CDefine 值提取失败:无法从表达式解析编译期常量", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(val_node, "CDefine value extraction failed: cannot parse a compile-time constant from the expression", "TypeError")
|
||||
|
||||
# Case 4: Call - e.g. t.CUnsignedLong(-11)
|
||||
if k == ast.ASTKind.Call:
|
||||
@@ -96,7 +96,7 @@ novirtual class AssignGenMixin:
|
||||
arg_val: int64 = self.extract_cdefine_int_value(first_arg)
|
||||
return arg_val
|
||||
# Call with no args: fail fast
|
||||
self.Gen.TypeGenErr.fatal_error(val_node, "CDefine 值提取失败:无法从表达式解析编译期常量", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(val_node, "CDefine value extraction failed: cannot parse a compile-time constant from the expression", "TypeError")
|
||||
|
||||
# Case 5: UnaryOp - e.g. -11
|
||||
if k == ast.ASTKind.UnaryOp:
|
||||
@@ -106,10 +106,10 @@ novirtual class AssignGenMixin:
|
||||
if uop.op == ast.OpKind.UAdd: return operand_val
|
||||
if uop.op == ast.OpKind.Invert: return ~operand_val
|
||||
# Unknown UnaryOp operator: fail fast
|
||||
self.Gen.TypeGenErr.fatal_error(val_node, "CDefine 值提取失败:无法从表达式解析编译期常量", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(val_node, "CDefine value extraction failed: cannot parse a compile-time constant from the expression", "TypeError")
|
||||
|
||||
# Unknown node kind: fail fast
|
||||
self.Gen.TypeGenErr.fatal_error(val_node, "CDefine 值提取失败:无法从表达式解析编译期常量", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(val_node, "CDefine value extraction failed: cannot parse a compile-time constant from the expression", "TypeError")
|
||||
# After fatal_error add an explicit return so the block is properly terminated
|
||||
return 0
|
||||
|
||||
@@ -309,7 +309,7 @@ novirtual class AssignGenMixin:
|
||||
bits: int = self._define_annot_bits(pool, annot)
|
||||
wmin: int = self.define_min_width(value)
|
||||
if self._int_text_exceeds_64(text) != 0:
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"[TPV] define 常量数值不可存储: 常量 '{name}' 的初始值 {text} 超出 64 位" f"(本语言最宽的整数类型为 64 位,按有符号/无符号两种解释的可存储范围为 " f"-9223372036854775808..18446744073709551615,不存在更宽的整数类型 ⇒ 需要扩容)。" f"禁止静默截断/降级,已终止编译。可用整数类型: int8/uint8、" f"int16/uint16、int32/uint32、int64/uint64" f"(或 int8/uint8/…/uint64、char、sizet)。" f"修法: 把值改到 64 位范围内,或为该数字引入更大的整数类型(扩容)。", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"[TPV] define constant value not storable: the initial value {text} of constant '{name}' exceeds 64 bits " f"(the widest integer type in this language is 64 bits; the storable range under both signed and unsigned interpretations is " f"-9223372036854775808..18446744073709551615; no wider integer type exists => widening is required). " f"Silent truncation/downgrade is forbidden; compilation aborted. Available integer types: int8/uint8, " f"int16/uint16, int32/uint32, int64/uint64 " f"(or int8/uint8/.../uint64, char, sizet). " f"Fix: move the value into the 64-bit range, or introduce a larger integer type for this number (widen).", "TypeError")
|
||||
return
|
||||
if bits == 0: return
|
||||
# Build the 32-bit bounds from overflow-safe literals (see define_min_width)
|
||||
@@ -324,7 +324,7 @@ novirtual class AssignGenMixin:
|
||||
hi = 65535
|
||||
elif bits == 64: return
|
||||
if value < lo or value > hi:
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"[TPV] define 常量数值不可存储: 常量 '{name}' 的初始值 {value} 不可存储。" f"最小可容纳宽度 W_min: {wmin} 位;声明类型位宽 {bits} 位," f"该声明可存储范围: {lo}..{hi}。" f"禁止静默截断/降级,已终止编译。" f"修法: 把显式类型改为更宽的类型(如 int32 / int64 / uint64)," f"或修正该字面量。", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"[TPV] define constant value not storable: the initial value {value} of constant '{name}' is not storable. " f"Minimal storable width W_min: {wmin} bits; declared type width {bits} bits, " f"storable range of this declaration: {lo}..{hi}. " f"Silent truncation/downgrade is forbidden; compilation aborted. " f"Fix: widen the explicit type to a wider type (such as int32 / int64 / uint64), " f"or correct the literal.", "TypeError")
|
||||
|
||||
def require_cdefine_use_width(self, pool: memhub.MemBuddy*, trans: HT.Translator*, target_annot: ast.AST*, value_node: ast.AST*) -> None:
|
||||
"""Fail fast when a define constant is wider than its use-site type."""
|
||||
@@ -340,7 +340,7 @@ novirtual class AssignGenMixin:
|
||||
if bits == 0: return
|
||||
wmin: int = self.define_min_width(cdef_val)
|
||||
if bits >= wmin: return
|
||||
self.Gen.TypeGenErr.fatal_error(value_node, f"[TPV] define 常量使用处宽度不足: 常量 '{rn.id}' 的实际值 {cdef_val} " f"需要至少 {wmin} 位(最小可容纳宽度 W_min)," f"但使用处(变量声明注解)只提供 {bits} 位。" f"禁止静默截断/降级,已终止编译。" f"修法: 把变量声明注解加宽到至少 {wmin} 位(如 int{wmin}T / CUInt{wmin}T)," f"或改用更小的常量值。", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(value_node, f"[TPV] define constant use-site width insufficient: the actual value {cdef_val} of constant '{rn.id}' " f"needs at least {wmin} bits (minimal storable width W_min), " f"but the use site (variable declaration annotation) provides only {bits} bits. " f"Silent truncation/downgrade is forbidden; compilation aborted. " f"Fix: widen the variable declaration annotation to at least {wmin} bits (such as int{wmin}T / CUInt{wmin}T), " f"or use a smaller constant value.", "TypeError")
|
||||
|
||||
# _register_cdefine_from_value - register a CDefine constant (float or int)
|
||||
def _register_cdefine_from_value(self, pool: memhub.MemBuddy*, name: str, val_node: ast.AST*, annot: ast.AST* = None) -> None:
|
||||
@@ -373,13 +373,13 @@ novirtual class AssignGenMixin:
|
||||
if self._recover_cdefine_float(name, &rec_d) != 0: use_val = rec_d
|
||||
else:
|
||||
# Source recovery failed: fail fast to avoid registering a corrupted float
|
||||
self.Gen.TypeGenErr.fatal_error(val_node, "CDefine 浮点值源文件恢复失败", "InternalCompilerError")
|
||||
self.Gen.TypeGenErr.fatal_error(val_node, "CDefine float value source-file recovery failed", "InternalCompilerError")
|
||||
return
|
||||
self.Gen.TypeGenCDef.register_cdefine_double(pool, name, use_val)
|
||||
return
|
||||
if val_node is None:
|
||||
# CDefine declaration without a value node: fail fast
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"CDefine 值提取失败:'{name}' 缺少初始值", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"CDefine value extraction failed: '{name}' is missing an initial value", "TypeError")
|
||||
return
|
||||
val_fp: int64 = self.extract_cdefine_int_value(val_node)
|
||||
# Check storability before registering (source text >64-bit or explicit T too narrow => fail)
|
||||
@@ -729,7 +729,7 @@ novirtual class AssignGenMixin:
|
||||
if sv_s is not None:
|
||||
n_s: sizet = string.strlen(sv_s)
|
||||
if sizet(arr_count) < n_s:
|
||||
self.Gen.TypeGenErr.fatal_error(list_node, f"字符串字面量长度 {n_s} 超过字符数组声明长度 {arr_count},不允许越界写入", "OverflowError")
|
||||
self.Gen.TypeGenErr.fatal_error(list_node, f"string literal length {n_s} exceeds the declared char array length {arr_count}; out-of-bounds writes are forbidden", "OverflowError")
|
||||
for bi_s in range(n_s):
|
||||
bidx_s: mlirlite.Value* = mlirlite.const_int32(pool, bi_s)
|
||||
bp_s: mlirlite.Value* = mlirlite.build_gep_array(builder, arr_ty, elem_ty, array_alloca, bidx_s)
|
||||
@@ -741,7 +741,7 @@ novirtual class AssignGenMixin:
|
||||
|
||||
# Element count exceeds declared length: fail fast (avoid out-of-range GEP writes)
|
||||
if arr_count > 0 and sizet(arr_count) < elts_count:
|
||||
self.Gen.TypeGenErr.fatal_error(list_node, f"数组初始化元素数 {elts_count} 超过数组声明长度 {arr_count},不允许越界写入", "OverflowError")
|
||||
self.Gen.TypeGenErr.fatal_error(list_node, f"array initializer element count {elts_count} exceeds the declared array length {arr_count}; out-of-bounds writes are forbidden", "OverflowError")
|
||||
|
||||
# Emit GEP + store for each element
|
||||
for i in range(elts_count):
|
||||
@@ -756,7 +756,7 @@ novirtual class AssignGenMixin:
|
||||
if list_node is not None:
|
||||
src_line = list_node.lineno
|
||||
src_col = list_node.col_offset
|
||||
self.Gen.TypeGenErr.fatal_error(list_node, f"全局数组初始化遇到空 AST 元素:{ctx_dbg}第 {i} 个元素为裸空指针(0)," f"但列表元素计数为 {elts_count}(元素与计数不一致)。" f"上层某处产生了空 AST 元素(列表字面量节点 {src_line}:{src_col} 的第 {i} 槽未被填充)," f"拒绝静默跳过/补零,已终止编译。", "ValueError")
|
||||
self.Gen.TypeGenErr.fatal_error(list_node, f"global array initialization hit a null AST element: {ctx_dbg}element {i} is a bare null pointer (0), " f"but the list element count is {elts_count} (element and count mismatch). " f"somewhere upstream produced a null AST element (slot {i} of list-literal node {src_line}:{src_col} was not filled), " f"silently skipping/padding with zero is refused; compilation aborted.", "ValueError")
|
||||
return 1
|
||||
# Object validity check (nonzero vptr): a zero vptr makes any virtual call read address 0
|
||||
elem_vptr: uint64 = *((uint64*)(elem_node))
|
||||
@@ -768,7 +768,7 @@ novirtual class AssignGenMixin:
|
||||
if list_node is not None:
|
||||
vt_line = list_node.lineno
|
||||
vt_col = list_node.col_offset
|
||||
self.Gen.TypeGenErr.fatal_error(list_node, f"全局数组初始化遇到【对象无效】的 AST 元素(vptr 为 0):{ctx_vt}" f"第 {i} 个元素指针非 0(地址 {uint64(elem_node)})但其对象首字(vtable 指针)为 0," f"对它的任何虚调用(kind()/dump()/…) 都会在 `load [0+slot]` 处读地址 0。" f"列表字面量节点位置 {vt_line}:{vt_col},元素计数 {elts_count}。" f"上层某处产生了「未初始化 vptr 的 AST 节点」(典型源:深拷贝/整块拷贝只搬字段未搬 vptr)," f"拒绝继续,已终止编译。", "ValueError", vt_col)
|
||||
self.Gen.TypeGenErr.fatal_error(list_node, f"global array initialization hit an invalid-object AST element (vptr is 0): {ctx_vt}" f"element {i} has a nonzero pointer (address {uint64(elem_node)}) but its object header (vtable pointer) is 0, " f"and any virtual call on it (kind()/dump()/...) reads address 0 at `load [0+slot]`. " f"list-literal node position {vt_line}:{vt_col}, element count {elts_count}. " f"somewhere upstream produced an AST node with an uninitialized vptr (typical source: a deep/block copy that moved only fields, not the vptr), " f"refusing to continue; compilation aborted.", "ValueError", vt_col)
|
||||
return 1
|
||||
idx_val: mlirlite.Value* = mlirlite.const_int32(pool, i)
|
||||
elem_ptr: mlirlite.Value* = mlirlite.build_gep_array(builder, arr_ty, elem_ty, array_alloca, idx_val)
|
||||
@@ -784,7 +784,7 @@ novirtual class AssignGenMixin:
|
||||
elem_val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, elem_node, None, 0, trans)
|
||||
if elem_val is None:
|
||||
# Element translation failed: fail fast to expose the upstream cause
|
||||
self.Gen.TypeGenErr.fatal_error(elem_node, "全局数组初始化元素翻译失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(elem_node, "global array initializer element translation failed", "TypeError")
|
||||
# Type coercion (e.g. i32 -> i8); Pointee is statically i64 so compare with != 0
|
||||
store_val: mlirlite.Value* = elem_val
|
||||
if elem_ptr.Ty is not None and elem_ptr.Ty.Pointee != 0: store_val = self.Gen.ExprGenBase.coerce_to_type(builder, elem_val, elem_ptr.Ty.Pointee, elem_node)
|
||||
@@ -865,9 +865,9 @@ novirtual class AssignGenMixin:
|
||||
# translate_augassign - translate augmented assignment statements
|
||||
def const_assign_msg(self, kind: str, name: str, src_name: str) -> str:
|
||||
"""Build the const-assignment error message used by const_assign_fail."""
|
||||
decl: str = "(注解含 t.CConst,声明处来源名未记录)"
|
||||
decl: str = "(annotation contains t.CConst; the source name at the declaration was not recorded)"
|
||||
if src_name is not None: decl = f"t.CConst | {src_name}"
|
||||
return GenApi.escape_fstring_copy(f"不能对 const 变量 '{name}' {kind}" f"(声明处类型(含 const):{decl}" f";修法:删掉该声明里的 const 描述符 / t.CConst,或改为声明时一次赋值、" f"之后只用非 const 的副本/中间量;const 对象在其作用域内禁止赋值、" f"增量赋值与元素赋值,且不会降级为警告)")
|
||||
return GenApi.escape_fstring_copy(f"cannot assign to const variable '{name}' ({kind}); " f"declaration type (including const): {decl}" f"; fix: remove the const descriptor / t.CConst from the declaration, or assign once at the declaration " f"and afterwards use only non-const copies/temporaries; a const object forbids assignment, " f"augmented assignment and element assignment within its scope, and this never degrades to a warning")
|
||||
|
||||
def const_assign_fail(self, node: ast.AST*, kind: str, name: str, src_name: str) -> int:
|
||||
"""Fail fast when a const target is written."""
|
||||
@@ -896,7 +896,7 @@ novirtual class AssignGenMixin:
|
||||
at_ca: ast.Attribute* = ast.Attribute*(target)
|
||||
if at_ca is not None and at_ca.attr is not None:
|
||||
if self.Gen.ExprGenAttr.attr_field_is_const(pool, trans, target) != 0:
|
||||
self.const_assign_fail(target, "字段赋值", at_ca.attr, self.Gen.ExprGenAttr.attr_field_decl_src(pool, trans, target))
|
||||
self.const_assign_fail(target, "field assignment", at_ca.attr, self.Gen.ExprGenAttr.attr_field_decl_src(pool, trans, target))
|
||||
|
||||
# 1. Get the field pointer
|
||||
field_ptr: mlirlite.Value* = self.Gen.ExprGenAttr.get_attribute_ptr(builder, pool, mod, target, trans)
|
||||
@@ -909,7 +909,7 @@ novirtual class AssignGenMixin:
|
||||
if field_ptr.Ty is not None and field_ptr.Ty.Pointee != 0: target_ty = field_ptr.Ty.Pointee
|
||||
if target_ty is None:
|
||||
# fail-fast: field type missing, no i32 fallback
|
||||
self.Gen.TypeGenErr.fatal_error(target, "字段类型信息缺失", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(target, "field type information missing", "TypeError")
|
||||
# t.CVolatile field: both load and store carry the volatile qualifier
|
||||
vol_fa: int = self.Gen.ExprGenAttr.attr_field_is_volatile(pool, trans, target)
|
||||
# rawptr[t.CVolatile|T] base: field load/store also carry volatile
|
||||
@@ -919,25 +919,25 @@ novirtual class AssignGenMixin:
|
||||
cur_val: mlirlite.Value* = mlirlite.build_load(builder, target_ty, field_ptr, vol_fa)
|
||||
if cur_val is None:
|
||||
# fail-fast: attribute current value load failed
|
||||
self.Gen.TypeGenErr.fatal_error(target, "无法加载 attribute 当前值", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(target, "cannot load the current value of the attribute", "TypeError")
|
||||
|
||||
# 3. Translate the RHS value
|
||||
rhs_val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, aug.value, None, 0, trans)
|
||||
if rhs_val is None:
|
||||
# fail-fast: RHS translation failed
|
||||
self.Gen.TypeGenErr.fatal_error(target, "rhs 翻译失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(target, "rhs translation failed", "TypeError")
|
||||
|
||||
# 4. Apply the binary op
|
||||
result: mlirlite.Value* = self._apply_aug_op(pool, builder, aug.op, cur_val, rhs_val, node, trans, target)
|
||||
if result is None:
|
||||
# fail-fast: attribute binary op failed
|
||||
self.Gen.TypeGenErr.fatal_error(target, f"attribute 二元运算失败 op={aug.op}", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(target, f"attribute binary op failed op={aug.op}", "TypeError")
|
||||
|
||||
# 5. Coerce the type and store
|
||||
result = self.Gen.ExprGenBase.coerce_to_type(builder, result, target_ty, node)
|
||||
if result is None:
|
||||
# fail-fast: type coercion failed
|
||||
self.Gen.TypeGenErr.fatal_error(target, "类型对齐失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(target, "type coercion failed", "TypeError")
|
||||
mlirlite.build_store(builder, result, field_ptr, vol_fa)
|
||||
return 0
|
||||
|
||||
@@ -955,12 +955,12 @@ novirtual class AssignGenMixin:
|
||||
if nm_ca.id is not None:
|
||||
ve_ca: GenTypes.VarEntry* = self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm_ca.id)
|
||||
if self.Gen.VarGen.var_is_const(ve_ca) != 0:
|
||||
self.const_assign_fail(target, "的元素赋值", nm_ca.id, self.Gen.VarGen.var_annot_class_name(ve_ca))
|
||||
self.const_assign_fail(target, "element assignment", nm_ca.id, self.Gen.VarGen.var_annot_class_name(ve_ca))
|
||||
elif sub_ca.value.kind() == ast.ASTKind.Attribute:
|
||||
at_ca2: ast.Attribute* = ast.Attribute*(sub_ca.value)
|
||||
if at_ca2.attr is not None:
|
||||
if self.Gen.ExprGenAttr.attr_field_is_const(pool, trans, sub_ca.value) != 0:
|
||||
self.const_assign_fail(target, "的元素赋值", at_ca2.attr, self.Gen.ExprGenAttr.attr_field_decl_src(pool, trans, sub_ca.value))
|
||||
self.const_assign_fail(target, "element assignment", at_ca2.attr, self.Gen.ExprGenAttr.attr_field_decl_src(pool, trans, sub_ca.value))
|
||||
|
||||
# 1. Get the element pointer
|
||||
elem_ptr: mlirlite.Value* = self.Gen.ExprGenName.get_subscript_ptr(builder, pool, mod, target, trans)
|
||||
@@ -973,7 +973,7 @@ novirtual class AssignGenMixin:
|
||||
if elem_ptr.Ty is not None and elem_ptr.Ty.Pointee != 0: target_ty = elem_ptr.Ty.Pointee
|
||||
if target_ty is None:
|
||||
# fail-fast: element type missing, no i32 fallback
|
||||
self.Gen.TypeGenErr.fatal_error(target, "元素类型信息缺失", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(target, "element type information missing", "TypeError")
|
||||
# rawptr[t.CVolatile|T] base: p[i] load/store carry volatile when the base is resolvable
|
||||
vol_sa: int = 0
|
||||
sub_aug: ast.Subscript* = ast.Subscript*(target)
|
||||
@@ -981,57 +981,57 @@ novirtual class AssignGenMixin:
|
||||
cur_val: mlirlite.Value* = mlirlite.build_load(builder, target_ty, elem_ptr, vol_sa)
|
||||
if cur_val is None:
|
||||
# fail-fast: element current value load failed
|
||||
self.Gen.TypeGenErr.fatal_error(target, "无法加载 subscript 元素当前值", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(target, "cannot load the current value of the subscript element", "TypeError")
|
||||
|
||||
# 3. Translate the RHS value
|
||||
rhs_val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, aug.value, None, 0, trans)
|
||||
if rhs_val is None:
|
||||
# fail-fast: RHS translation failed
|
||||
self.Gen.TypeGenErr.fatal_error(target, "rhs 翻译失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(target, "rhs translation failed", "TypeError")
|
||||
|
||||
# 4. Apply the binary op
|
||||
result: mlirlite.Value* = self._apply_aug_op(pool, builder, aug.op, cur_val, rhs_val, node, trans, target)
|
||||
if result is None:
|
||||
# fail-fast: subscript binary op failed
|
||||
self.Gen.TypeGenErr.fatal_error(target, f"subscript 二元运算失败 op={aug.op}", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(target, f"subscript binary op failed op={aug.op}", "TypeError")
|
||||
|
||||
# 5. Coerce the type and store
|
||||
result = self.Gen.ExprGenBase.coerce_to_type(builder, result, target_ty, node)
|
||||
if result is None:
|
||||
# fail-fast: type coercion failed
|
||||
self.Gen.TypeGenErr.fatal_error(target, "类型对齐失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(target, "type coercion failed", "TypeError")
|
||||
mlirlite.build_store(builder, result, elem_ptr, vol_sa)
|
||||
return 0
|
||||
|
||||
# UnaryOp target: *p += v (deref augmented assignment: load, op, store back)
|
||||
if tk == ast.ASTKind.UnaryOp:
|
||||
uo_ag: ast.UnaryOp* = ast.UnaryOp*(target)
|
||||
if uo_ag is None or uo_ag.operand is None: self.Gen.TypeGenErr.fatal_error(target, "增量赋值目标单目运算缺少操作数", "TypeError")
|
||||
if uo_ag is None or uo_ag.operand is None: self.Gen.TypeGenErr.fatal_error(target, "augmented-assignment target unary op is missing an operand", "TypeError")
|
||||
if uo_ag.op != ast.OpKind.Deref:
|
||||
self.Gen.TypeGenErr.fatal_error(target, "增量赋值目标只支持单目 '*' 解引用(&x / -x / ~x 不是合法左值)", "SyntaxError")
|
||||
self.Gen.TypeGenErr.fatal_error(target, "augmented-assignment target supports only the unary '*' dereference (&x / -x / ~x are not valid lvalues)", "SyntaxError")
|
||||
pool: memhub.MemBuddy* = trans.Pool
|
||||
builder: mlirlite.IRBuilder* = trans._cur_builder
|
||||
mod: mlirlite.LLVMModule* = trans.Module
|
||||
ptr_ag: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, uo_ag.operand, None, 0, trans)
|
||||
if ptr_ag is None or ptr_ag.Ty is None or self.Gen.ExprGenBase.is_ptr_type(ptr_ag.Ty) == 0:
|
||||
self.Gen.TypeGenErr.fatal_error(target, "增量赋值 '*' 的操作数必须是指针类型(类型推断退化)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(target, "the operand of augmented-assignment '*' must be a pointer type (type inference degraded)", "TypeError")
|
||||
ty_ag: mlirlite.LLVMType* = ptr_ag.Ty.Pointee
|
||||
if ty_ag is None:
|
||||
self.Gen.TypeGenErr.fatal_error(target, "解引用增量赋值的目标类型缺失(pointee 为空)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(target, "deref augmented-assignment target type missing (pointee is empty)", "TypeError")
|
||||
old_ag: mlirlite.Value* = mlirlite.build_load(builder, ty_ag, ptr_ag, 0)
|
||||
if old_ag is None: self.Gen.TypeGenErr.fatal_error(target, "无法加载解引用当前值", "TypeError")
|
||||
if old_ag is None: self.Gen.TypeGenErr.fatal_error(target, "cannot load the current dereferenced value", "TypeError")
|
||||
rhs_ag: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, aug.value, None, 0, trans)
|
||||
if rhs_ag is None: self.Gen.TypeGenErr.fatal_error(target, "rhs 翻译失败", "TypeError")
|
||||
if rhs_ag is None: self.Gen.TypeGenErr.fatal_error(target, "rhs translation failed", "TypeError")
|
||||
res_ag: mlirlite.Value* = self._apply_aug_op(pool, builder, aug.op, old_ag, rhs_ag, node, trans, target)
|
||||
if res_ag is None: self.Gen.TypeGenErr.fatal_error(target, f"解引用二元运算失败 op={aug.op}", "TypeError")
|
||||
if res_ag is None: self.Gen.TypeGenErr.fatal_error(target, f"deref binary op failed op={aug.op}", "TypeError")
|
||||
res_ag = self.Gen.ExprGenBase.coerce_to_type(builder, res_ag, ty_ag, node, trans)
|
||||
if res_ag is None: self.Gen.TypeGenErr.fatal_error(target, "类型对齐失败", "TypeError")
|
||||
if res_ag is None: self.Gen.TypeGenErr.fatal_error(target, "type coercion failed", "TypeError")
|
||||
mlirlite.build_store(builder, res_ag, ptr_ag, 0)
|
||||
return 0
|
||||
|
||||
if tk != ast.ASTKind.Name:
|
||||
# fail-fast: unsupported AugAssign target kind
|
||||
self.Gen.TypeGenErr.fatal_error(target, "AugAssign 目标类型不支持,仅支持 Name/Attribute/Subscript/*解引用", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(target, "AugAssign target type unsupported; only Name/Attribute/Subscript/*dereference are supported", "TypeError")
|
||||
|
||||
nm: ast.Name* = ast.Name*(target)
|
||||
if nm is None or nm.id is None: return 0
|
||||
@@ -1039,7 +1039,7 @@ novirtual class AssignGenMixin:
|
||||
# const variable: fail fast immediately
|
||||
ve_aug: GenTypes.VarEntry* = self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm.id)
|
||||
if self.Gen.VarGen.var_is_const(ve_aug) != 0:
|
||||
self.const_assign_fail(target, "增量赋值", nm.id, self.Gen.VarGen.var_annot_class_name(ve_aug))
|
||||
self.const_assign_fail(target, "augmented assignment", nm.id, self.Gen.VarGen.var_annot_class_name(ve_aug))
|
||||
|
||||
# REPL session variable aug-assign: read slot, apply op, write slot and result area
|
||||
if trans.ReplCtx is not None and self.Gen.VarGen.repl_in_frag_entry_scope(trans) != 0:
|
||||
@@ -1068,7 +1068,7 @@ novirtual class AssignGenMixin:
|
||||
if target_alloca is not None:
|
||||
if target_alloca.Ty is None:
|
||||
# fail-fast: variable type missing, no i32 fallback
|
||||
self.Gen.TypeGenErr.fatal_error(target, "变量类型信息缺失", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(target, "variable type information missing", "TypeError")
|
||||
target_ty = target_alloca.Ty.Pointee
|
||||
cur_val = mlirlite.build_load(builder, target_ty, target_alloca, vol_aa)
|
||||
elif scope_type == 2:
|
||||
@@ -1081,19 +1081,19 @@ novirtual class AssignGenMixin:
|
||||
if target_alloca is not None:
|
||||
if target_alloca.Ty is None:
|
||||
# fail-fast: variable type missing, no i32 fallback
|
||||
self.Gen.TypeGenErr.fatal_error(target, "变量类型信息缺失", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(target, "variable type information missing", "TypeError")
|
||||
target_ty = target_alloca.Ty.Pointee
|
||||
cur_val = mlirlite.build_load(builder, target_ty, target_alloca, vol_aa)
|
||||
|
||||
if cur_val is None:
|
||||
# fail-fast: target variable current value load failed
|
||||
self.Gen.TypeGenErr.fatal_error(target, f"无法加载目标变量 '{nm.id}' 的当前值", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(target, f"cannot load the current value of target variable '{nm.id}'", "TypeError")
|
||||
|
||||
# 3. Translate the RHS value
|
||||
rhs_val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, aug.value, None, 0, trans)
|
||||
if rhs_val is None:
|
||||
# fail-fast: RHS translation failed
|
||||
self.Gen.TypeGenErr.fatal_error(target, "rhs 翻译失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(target, "rhs translation failed", "TypeError")
|
||||
|
||||
# 3b. Operator overload: object += -> __iadd__, fall back to __add__ (locals only)
|
||||
if scope_type == 0 and target_alloca is not None:
|
||||
@@ -1124,7 +1124,7 @@ novirtual class AssignGenMixin:
|
||||
if coerced_aug is not None: aug_res = coerced_aug
|
||||
if aug_res is None or target_ty is None or self.Gen.ExprGenBase._same_agg_ty(pool, aug_res.Ty, target_ty) == 0:
|
||||
# fail-fast: overload return type mismatch, do not corrupt memory silently
|
||||
self.Gen.TypeGenErr.fatal_error(node, "增量赋值运算符重载返回值类型与目标变量不匹配", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, "augmented-assignment operator overload return type does not match the target variable", "TypeError")
|
||||
mlirlite.build_store(builder, aug_res, target_alloca, vol_aa)
|
||||
return 0
|
||||
|
||||
@@ -1132,13 +1132,13 @@ novirtual class AssignGenMixin:
|
||||
result: mlirlite.Value* = self._apply_aug_op(pool, builder, aug.op, cur_val, rhs_val, node, trans, target)
|
||||
if result is None:
|
||||
# fail-fast: binary op failed
|
||||
self.Gen.TypeGenErr.fatal_error(target, f"对变量 '{nm.id}' 应用二元运算失败 op={aug.op}", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(target, f"applying binary op to variable '{nm.id}' failed op={aug.op}", "TypeError")
|
||||
|
||||
# 5. Store the result
|
||||
result = self.Gen.ExprGenBase.coerce_to_type(builder, result, target_ty, node)
|
||||
if result is None:
|
||||
# fail-fast: type coercion failed
|
||||
self.Gen.TypeGenErr.fatal_error(target, "类型对齐失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(target, "type coercion failed", "TypeError")
|
||||
|
||||
if scope_type == 1:
|
||||
# global variable
|
||||
@@ -1217,9 +1217,9 @@ novirtual class AssignGenMixin:
|
||||
msg_len: sizet = 640
|
||||
msg_buf: str = stdlib.malloc(msg_len)
|
||||
if msg_buf is None: return ann_txt_x
|
||||
if btd_nm_x is not None and btd_rs_x is not None: viperlib.snprintf(msg_buf, msg_len, "变量类型注解解析失败,变量名: %s,注解: %s。builtins 最后匹配: %s 展开为 %s,仍无法解析", nm_id, ann_txt_x, btd_nm_x, btd_rs_x)
|
||||
elif btd_nm_x is not None: viperlib.snprintf(msg_buf, msg_len, "变量类型注解解析失败,变量名: %s,注解: %s。builtins 最后匹配: %s 未命中(builtins.vp 无该 typedef 或扫描未运行)", nm_id, ann_txt_x, btd_nm_x)
|
||||
else: viperlib.snprintf(msg_buf, msg_len, "变量类型注解解析失败,变量名: %s,注解: %s。builtins 最后匹配: 未触发", nm_id, ann_txt_x)
|
||||
if btd_nm_x is not None and btd_rs_x is not None: viperlib.snprintf(msg_buf, msg_len, "variable type annotation resolution failed, variable name: %s, annotation: %s. last builtins match: %s expanded to %s, still unresolvable", nm_id, ann_txt_x, btd_nm_x, btd_rs_x)
|
||||
elif btd_nm_x is not None: viperlib.snprintf(msg_buf, msg_len, "variable type annotation resolution failed, variable name: %s, annotation: %s. last builtins match: %s missed (builtins.vp has no such typedef, or the scan did not run)", nm_id, ann_txt_x, btd_nm_x)
|
||||
else: viperlib.snprintf(msg_buf, msg_len, "variable type annotation resolution failed, variable name: %s, annotation: %s. last builtins match: not triggered", nm_id, ann_txt_x)
|
||||
return msg_buf
|
||||
|
||||
# translate_annassign_prescan - pre-create alloca for annotated vars
|
||||
@@ -1282,7 +1282,7 @@ novirtual class AssignGenMixin:
|
||||
self.Gen.TypeGenErr.fatal_error(aa, self._build_ann_fail_msg(pool, annot, nm.id), "TypeError")
|
||||
else:
|
||||
# fail-fast: AnnAssign must have an annotation
|
||||
self.Gen.TypeGenErr.fatal_error(aa, f"AnnAssign 缺少类型注解,变量名: {nm.id}", "SyntaxError")
|
||||
self.Gen.TypeGenErr.fatal_error(aa, f"AnnAssign is missing a type annotation, variable name: {nm.id}", "SyntaxError")
|
||||
|
||||
# Ensure the full cross-module struct definition is available (for alloca)
|
||||
self.Gen.StructGen.ensure_struct_def_in_module(pool, trans.Module, var_ty)
|
||||
@@ -1352,7 +1352,7 @@ novirtual class AssignGenMixin:
|
||||
vt_short_ff: str = vt_nm_ff + vt_pf_ff if vt_pf_ff != 0 else vt_nm_ff
|
||||
if string.strchr(vt_short_ff, '[') is not None:
|
||||
return 0 # With type args: not degraded
|
||||
self.Gen.TypeGenErr.fatal_error(aa, f"变量 '{var_name}' 的泛型注解 '{base_nm_ff.id}[...]' 解析成了裸基类 " f"'{vt_nm_ff}*'(丢失类型实参);后续 .get()/.set() 会按错误元素类型" f"特化(如 list[int].get 返回 i32)→ inttoptr 截断指针崩溃。" f"禁止静默继续——请检查该注解在 resolve_annotation_type 中的退化点。", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(aa, f"the generic annotation '{base_nm_ff.id}[...]' of variable '{var_name}' resolved to a bare base class " f"'{vt_nm_ff}*' (type arguments lost); subsequent .get()/.set() will specialize by the wrong element " f"type (such as list[int].get returning i32) -> inttoptr truncates the pointer and crashes. " f"Silent continuation is forbidden -- check the degradation point of this annotation in resolve_annotation_type.", "TypeError")
|
||||
return 0
|
||||
|
||||
def translate_annassign(self, trans: HT.Translator*, node: ast.AST*) -> int:
|
||||
@@ -1395,9 +1395,9 @@ novirtual class AssignGenMixin:
|
||||
dup_decl: int = 0
|
||||
if GenApi.is_global_name(trans, nm.id) != 0 or GenApi.is_nonlocal_name(trans, nm.id) != 0: dup_decl = 1
|
||||
if dup_decl != 0:
|
||||
self.Gen.TypeGenErr.fatal_error(aa, f"重复声明:'{nm.id}' 已是模块级变量,此处声明 global/nonlocal 之后" f"又用类型注解重新声明。请删除本行的类型注解,直接赋值即可修改全局", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(aa, f"duplicate declaration: '{nm.id}' is already a module-level variable; after declaring global/nonlocal here " f"it is re-declared with a type annotation. Remove the type annotation on this line; a plain assignment modifies the global", "TypeError")
|
||||
else:
|
||||
self.Gen.TypeGenErr.fatal_error(aa, f"重复声明:'{nm.id}' 已是模块级变量,函数内未声明 global 时不得再用" f"类型注解声明同名变量(会把全局遮蔽为局部)。如需独立局部变量请换名;" f"如需修改全局请在函数内加 global 声明并删除本行注解", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(aa, f"duplicate declaration: '{nm.id}' is already a module-level variable; without a global declaration in a function, a type annotation must not re-declare " f"the same name (it would shadow the global with a local). For an independent local, use another name; " f"to modify the global, add a global declaration in the function and remove this annotation", "TypeError")
|
||||
|
||||
pool: memhub.MemBuddy* = trans.Pool
|
||||
builder: mlirlite.IRBuilder* = trans._cur_builder
|
||||
@@ -1416,11 +1416,11 @@ novirtual class AssignGenMixin:
|
||||
self.Gen.TypeGenErr.fatal_error(aa, self._build_ann_fail_msg(pool, annot, nm.id), "TypeError")
|
||||
else:
|
||||
# fail-fast: AnnAssign must have an annotation
|
||||
self.Gen.TypeGenErr.fatal_error(aa, f"AnnAssign 缺少类型注解,变量名: {nm.id}", "SyntaxError")
|
||||
self.Gen.TypeGenErr.fatal_error(aa, f"AnnAssign is missing a type annotation, variable name: {nm.id}", "SyntaxError")
|
||||
|
||||
# void cannot be a variable type (only void* and opaque-struct typedef)
|
||||
if var_ty is not None and self.Gen.StmtGenDecl._is_void_type(var_ty) != 0:
|
||||
self.Gen.TypeGenErr.fatal_error(aa, f"不能声明 void 类型的变量 '{nm.id}'(void 只能用于 void* 与 typedef 别名)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(aa, f"cannot declare a variable of void type '{nm.id}' (void may only be used for void* and typedef aliases)", "TypeError")
|
||||
|
||||
# t.Callable function pointer: register the return-type signature
|
||||
callable_ret: mlirlite.LLVMType* = self.Gen.TypeGenErr.try_extract_callable_ret(pool, annot, trans._imported_modules, trans._from_imports, trans)
|
||||
@@ -1442,7 +1442,7 @@ novirtual class AssignGenMixin:
|
||||
# Set CurAssignAnnot/CurAssignNode before translating the RHS (kept in sync across all four branches)
|
||||
trans.CurAssignAnnot = aa.annotation
|
||||
trans.CurAssignNode = aa.value
|
||||
rhs_val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, aa.value, None, 0, trans, aa_glob_ty, "模块级全局")
|
||||
rhs_val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, aa.value, None, 0, trans, aa_glob_ty, "module-level global")
|
||||
if rhs_val is not None:
|
||||
# Object global with static storage: bind storage and copy the object
|
||||
stg_ref_aa: mlirlite.Value* = None
|
||||
@@ -1492,12 +1492,12 @@ novirtual class AssignGenMixin:
|
||||
# Set CurAssignAnnot/CurAssignNode before translating the RHS (sync across all four branches)
|
||||
trans.CurAssignAnnot = aa.annotation
|
||||
trans.CurAssignNode = aa.value
|
||||
rhs_val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, aa.value, None, 0, trans, nl_target_ty, "闭包变量(nonlocal)")
|
||||
rhs_val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, aa.value, None, 0, trans, nl_target_ty, "closure variable (nonlocal)")
|
||||
if rhs_val is not None:
|
||||
if nl_ptr is not None:
|
||||
if nl_target_ty is None:
|
||||
# fail-fast: nl_ptr type lost, cannot store safely
|
||||
VLogger.error(f"nonlocal 变量类型信息丢失,无法写入: {nm.id}", "HandlesAnnAssign")
|
||||
VLogger.error(f"nonlocal variable type information lost, cannot write: {nm.id}", "HandlesAnnAssign")
|
||||
# Clear the assignment context before returning (avoid leaking into later statements)
|
||||
trans.CurAssignAnnot = None
|
||||
trans.CurAssignNode = None
|
||||
@@ -1524,7 +1524,7 @@ novirtual class AssignGenMixin:
|
||||
# Set CurAssignAnnot/CurAssignNode before translating the RHS (sync across all four branches)
|
||||
trans.CurAssignAnnot = aa.annotation
|
||||
trans.CurAssignNode = aa.value
|
||||
rhs_val_mg: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, aa.value, None, 0, trans, mg_val_ty, "模块级全局")
|
||||
rhs_val_mg: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, aa.value, None, 0, trans, mg_val_ty, "module-level global")
|
||||
if rhs_val_mg is not None:
|
||||
# Object global with static storage: bind storage and copy the object
|
||||
stg_ref_mg: mlirlite.Value* = None
|
||||
@@ -1572,7 +1572,7 @@ novirtual class AssignGenMixin:
|
||||
alloca: mlirlite.Value* = self.Gen.VarGen.get_or_create_sym(trans.SymTab, pool, builder, nm.id, var_ty)
|
||||
if alloca is None:
|
||||
# fail-fast: storage creation failed
|
||||
self.Gen.TypeGenErr.fatal_error(aa, f"无法为变量 {nm.id} 创建存储", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(aa, f"cannot create storage for variable {nm.id}", "TypeError")
|
||||
# A reused alloca type must match the resolved annotation type (compare struct names)
|
||||
if alloca is not None and alloca.Ty is not None and var_ty is not None:
|
||||
av_pt_d: mlirlite.LLVMType* = alloca.Ty.Pointee
|
||||
@@ -1589,7 +1589,7 @@ novirtual class AssignGenMixin:
|
||||
if string.strchr(av_short, '[') is None:
|
||||
av_tpl: ast.ClassDef* = self.Gen.ClassGenGeneric._find_generic_template(av_short)
|
||||
if av_tpl is not None:
|
||||
self.Gen.TypeGenErr.fatal_error(aa, f"变量 '{nm.id}' 复用到的存储类型为裸泛型基类 '{av_nm_d}*'" f"(丢了类型实参),与注解解析类型 '{vt_nm_d}*' 不一致;" f"禁止静默混用——方法调用会按错误元素类型特化并截断指针", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(aa, f"the reused storage type of variable '{nm.id}' is the bare generic base class '{av_nm_d}*'" f" (type arguments lost), inconsistent with the annotation-resolved type '{vt_nm_d}*'; " f"silent mixing is forbidden -- method calls would specialize by the wrong element type and truncate the pointer", "TypeError")
|
||||
|
||||
# FakeDuck: a str variable gets a shadow struct {var}__meta__ for per-instance fields
|
||||
fd_str_ty: mlirlite.LLVMType* = None
|
||||
@@ -1608,7 +1608,7 @@ novirtual class AssignGenMixin:
|
||||
fd_meta_alloca = self.Gen.VarGen.get_or_create_sym(trans.SymTab, pool, builder, fd_meta_name, fd_str_ty)
|
||||
if fd_meta_alloca is None:
|
||||
# fail-fast: shadow storage creation failed
|
||||
self.Gen.TypeGenErr.fatal_error(aa, f"无法为 str 影子变量 {fd_meta_name} 创建存储", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(aa, f"cannot create storage for the str shadow variable {fd_meta_name}", "TypeError")
|
||||
# Store the annotation's class name; pass pool so generic Subscript yields the mangled name
|
||||
if annot is not None:
|
||||
cls_nm_hd: str = self.Gen.TypeGenResolve.extract_class_name_from_annotation(annot, trans._imported_modules, pool, trans._from_imports)
|
||||
@@ -1656,7 +1656,7 @@ novirtual class AssignGenMixin:
|
||||
# P1-A: use the local alloca pointee as the target type so integer literals materialize at target width
|
||||
lv_target_ty: mlirlite.LLVMType* = None
|
||||
if alloca.Ty is not None: lv_target_ty = alloca.Ty.Pointee
|
||||
rhs_val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, aa.value, None, 0, trans, lv_target_ty, "局部变量注解")
|
||||
rhs_val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, aa.value, None, 0, trans, lv_target_ty, "local variable annotation")
|
||||
if rhs_val is not None:
|
||||
# Fix degraded annotation: rebuild the alloca with the precise RHS struct type
|
||||
precise_rhs_ty: mlirlite.LLVMType* = None
|
||||
@@ -1785,12 +1785,12 @@ novirtual class AssignGenMixin:
|
||||
if nm_c.id is None: continue
|
||||
ve_c: GenTypes.VarEntry* = self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm_c.id)
|
||||
if self.Gen.VarGen.var_is_const(ve_c) != 0:
|
||||
self.const_assign_fail(tgt_c, "赋值", nm_c.id, self.Gen.VarGen.var_annot_class_name(ve_c))
|
||||
self.const_assign_fail(tgt_c, "assignment", nm_c.id, self.Gen.VarGen.var_annot_class_name(ve_c))
|
||||
elif tgt_c.kind() == ast.ASTKind.Attribute:
|
||||
at_c: ast.Attribute* = ast.Attribute*(tgt_c)
|
||||
if at_c.attr is None: continue
|
||||
if self.Gen.ExprGenAttr.attr_field_is_const(pool, trans, tgt_c) != 0:
|
||||
self.const_assign_fail(tgt_c, "字段赋值", at_c.attr, self.Gen.ExprGenAttr.attr_field_decl_src(pool, trans, tgt_c))
|
||||
self.const_assign_fail(tgt_c, "field assignment", at_c.attr, self.Gen.ExprGenAttr.attr_field_decl_src(pool, trans, tgt_c))
|
||||
elif tgt_c.kind() == ast.ASTKind.Subscript:
|
||||
sub_c: ast.Subscript* = ast.Subscript*(tgt_c)
|
||||
if sub_c.value is None: continue
|
||||
@@ -1799,23 +1799,23 @@ novirtual class AssignGenMixin:
|
||||
if nm_c2.id is None: continue
|
||||
ve_c2: GenTypes.VarEntry* = self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm_c2.id)
|
||||
if self.Gen.VarGen.var_is_const(ve_c2) != 0:
|
||||
self.const_assign_fail(tgt_c, "的元素赋值", nm_c2.id, self.Gen.VarGen.var_annot_class_name(ve_c2))
|
||||
self.const_assign_fail(tgt_c, "element assignment", nm_c2.id, self.Gen.VarGen.var_annot_class_name(ve_c2))
|
||||
elif sub_c.value.kind() == ast.ASTKind.Attribute:
|
||||
at_c2: ast.Attribute* = ast.Attribute*(sub_c.value)
|
||||
if at_c2.attr is None: continue
|
||||
if self.Gen.ExprGenAttr.attr_field_is_const(pool, trans, sub_c.value) != 0:
|
||||
self.const_assign_fail(tgt_c, "的元素赋值", at_c2.attr, self.Gen.ExprGenAttr.attr_field_decl_src(pool, trans, sub_c.value))
|
||||
self.const_assign_fail(tgt_c, "element assignment", at_c2.attr, self.Gen.ExprGenAttr.attr_field_decl_src(pool, trans, sub_c.value))
|
||||
|
||||
# f-string escape: results are function-local temporaries; writing them out is dangling
|
||||
for ti_f in range(len(targets)):
|
||||
tgt_f: ast.AST* = targets.get(ti_f)
|
||||
if tgt_f is None: continue
|
||||
tk_f: int = tgt_f.kind()
|
||||
if tk_f == ast.ASTKind.Attribute: GenApi.fail_if_fstring_escape(asgn.value, "字段赋值")
|
||||
elif tk_f == ast.ASTKind.Subscript: GenApi.fail_if_fstring_escape(asgn.value, "元素赋值")
|
||||
if tk_f == ast.ASTKind.Attribute: GenApi.fail_if_fstring_escape(asgn.value, "field assignment")
|
||||
elif tk_f == ast.ASTKind.Subscript: GenApi.fail_if_fstring_escape(asgn.value, "element assignment")
|
||||
elif tk_f == ast.ASTKind.Name:
|
||||
nm_f: ast.Name* = ast.Name*(tgt_f)
|
||||
if nm_f.id is not None and GenApi.is_global_name(trans, nm_f.id) != 0: GenApi.fail_if_fstring_escape(asgn.value, "全局变量赋值")
|
||||
if nm_f.id is not None and GenApi.is_global_name(trans, nm_f.id) != 0: GenApi.fail_if_fstring_escape(asgn.value, "global variable assignment")
|
||||
|
||||
# Translate the RHS; clear CurAssignAnnot/CurAssignNode (no target type to infer here)
|
||||
trans.CurAssignAnnot = None
|
||||
@@ -1839,8 +1839,8 @@ novirtual class AssignGenMixin:
|
||||
# RHS is None usually means allocation failure; dump both pool statistics
|
||||
mb_diag: memhub.MemBuddy* = CompilerFactory.factory.Pool
|
||||
pp_diag: memhub.MemBuddy* = CompilerFactory.factory.PermPool
|
||||
if mb_diag is not None: mb_diag.dump_stats("主池(Pool)")
|
||||
if pp_diag is not None: pp_diag.dump_stats("常驻池(PermPool)")
|
||||
if mb_diag is not None: mb_diag.dump_stats("Main Pool(Pool)")
|
||||
if pp_diag is not None: pp_diag.dump_stats("Permanent Pool(PermPool)")
|
||||
stdio.fflush(None)
|
||||
# Enhanced error message: file name + lineno + AST node details
|
||||
if asgn.value is not None:
|
||||
@@ -1859,12 +1859,12 @@ novirtual class AssignGenMixin:
|
||||
if at_nv.value.kind() == ast.ASTKind.Name:
|
||||
tn_nm: ast.Name* = ast.Name*(at_nv.value)
|
||||
target_nm = tn_nm.id
|
||||
if rel_path is not None: VLogger.error(f"赋值右侧为 None: {rel_path}:{val_line} '{target_nm}.{attr_nm}' 属性访问失败", "ASGN")
|
||||
else: VLogger.error(f"赋值右侧为 None: sha1={sha1}:{val_line} '{target_nm}.{attr_nm}' 属性访问失败", "ASGN")
|
||||
if rel_path is not None: VLogger.error(f"assignment rhs is None: {rel_path}:{val_line} attribute access of '{target_nm}.{attr_nm}' failed", "ASGN")
|
||||
else: VLogger.error(f"assignment rhs is None: sha1={sha1}:{val_line} attribute access of '{target_nm}.{attr_nm}' failed", "ASGN")
|
||||
elif val_kind == ast.ASTKind.Name:
|
||||
nm_nv: ast.Name* = ast.Name*(asgn.value)
|
||||
if rel_path is not None: VLogger.error(f"赋值右侧为 None: {rel_path}:{val_line} 变量 '{nm_nv.id}' 未找到", "ASGN")
|
||||
else: VLogger.error(f"赋值右侧为 None: sha1={sha1}:{val_line} 变量 '{nm_nv.id}' 未找到", "ASGN")
|
||||
if rel_path is not None: VLogger.error(f"assignment rhs is None: {rel_path}:{val_line} variable '{nm_nv.id}' not found", "ASGN")
|
||||
else: VLogger.error(f"assignment rhs is None: sha1={sha1}:{val_line} variable '{nm_nv.id}' not found", "ASGN")
|
||||
elif val_kind == ast.ASTKind.Call:
|
||||
cl_nv: ast.Call* = ast.Call*(asgn.value)
|
||||
func_nm: str = "?"
|
||||
@@ -1872,12 +1872,12 @@ novirtual class AssignGenMixin:
|
||||
if cl_nv.func.kind() == ast.ASTKind.Name:
|
||||
fn_nm: ast.Name* = ast.Name*(cl_nv.func)
|
||||
func_nm = fn_nm.id
|
||||
if rel_path is not None: VLogger.error(f"赋值右侧为 None: {rel_path}:{val_line} 调用 '{func_nm}(...)' 返回 None", "ASGN")
|
||||
else: VLogger.error(f"赋值右侧为 None: sha1={sha1}:{val_line} 调用 '{func_nm}(...)' 返回 None", "ASGN")
|
||||
if rel_path is not None: VLogger.error(f"assignment rhs is None: {rel_path}:{val_line} call '{func_nm}(...)' returned None", "ASGN")
|
||||
else: VLogger.error(f"assignment rhs is None: sha1={sha1}:{val_line} call '{func_nm}(...)' returned None", "ASGN")
|
||||
else:
|
||||
if rel_path is not None: VLogger.error(f"赋值右侧为 None: {rel_path}:{val_line} [kind={val_kind}]")
|
||||
else: VLogger.error(f"赋值右侧为 None: sha1={sha1}:{val_line} [kind={val_kind}]")
|
||||
else: VLogger.error("赋值右侧为 None (asgn.value 为空)", "ASGN")
|
||||
if rel_path is not None: VLogger.error(f"assignment rhs is None: {rel_path}:{val_line} [kind={val_kind}]")
|
||||
else: VLogger.error(f"assignment rhs is None: sha1={sha1}:{val_line} [kind={val_kind}]")
|
||||
else: VLogger.error("assignment rhs is None (asgn.value is empty)", "ASGN")
|
||||
return 0
|
||||
|
||||
new_vars: int = 0
|
||||
@@ -1910,7 +1910,7 @@ novirtual class AssignGenMixin:
|
||||
fcur = mlirlite.paramnode_get_next(fcur)
|
||||
if fty is None:
|
||||
# fail-fast: field type missing
|
||||
self.Gen.TypeGenErr.fatal_error(target, "元组解包字段类型缺失", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(target, "tuple-unpack field type missing", "TypeError")
|
||||
# Guard: skip non-Name elements (cannot unpack)
|
||||
if tgt_elt.kind() != ast.ASTKind.Name: continue
|
||||
tgt_nm2: ast.Name* = ast.Name*(tgt_elt)
|
||||
@@ -1939,7 +1939,7 @@ novirtual class AssignGenMixin:
|
||||
list_idx_val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, sub_node.slice, None, 0, trans)
|
||||
if list_idx_val is None:
|
||||
# fail-fast: list index translation failed
|
||||
self.Gen.TypeGenErr.fatal_error(target, "list 下标翻译失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(target, "list index translation failed", "TypeError")
|
||||
self.Gen.ExprGenName.list_setitem_inline(builder, pool, list_obj, list_idx_val, rhs_val, target)
|
||||
continue
|
||||
# Ordinary Subscript assignment
|
||||
@@ -2038,15 +2038,15 @@ novirtual class AssignGenMixin:
|
||||
# UnaryOp target: *p = val (deref write); only Deref is a valid lvalue, others fail fast
|
||||
if tk == ast.ASTKind.UnaryOp:
|
||||
uo_w: ast.UnaryOp* = ast.UnaryOp*(target)
|
||||
if uo_w is None or uo_w.operand is None: self.Gen.TypeGenErr.fatal_error(target, "赋值目标单目运算缺少操作数", "TypeError")
|
||||
if uo_w is None or uo_w.operand is None: self.Gen.TypeGenErr.fatal_error(target, "assignment target unary op is missing an operand", "TypeError")
|
||||
if uo_w.op != ast.OpKind.Deref:
|
||||
self.Gen.TypeGenErr.fatal_error(target, "赋值目标只支持单目 '*' 解引用(&x / -x / ~x 不是合法左值)", "SyntaxError")
|
||||
self.Gen.TypeGenErr.fatal_error(target, "assignment target supports only the unary '*' dereference (&x / -x / ~x are not valid lvalues)", "SyntaxError")
|
||||
ptr_w: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, uo_w.operand, None, 0, trans)
|
||||
if ptr_w is None or ptr_w.Ty is None or self.Gen.ExprGenBase.is_ptr_type(ptr_w.Ty) == 0:
|
||||
self.Gen.TypeGenErr.fatal_error(target, "单目 '*' 赋值的操作数必须是指针类型(类型推断退化)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(target, "the operand of unary '*' assignment must be a pointer type (type inference degraded)", "TypeError")
|
||||
pointee_w: mlirlite.LLVMType* = ptr_w.Ty.Pointee
|
||||
if pointee_w is None:
|
||||
self.Gen.TypeGenErr.fatal_error(target, "解引用写入的目标类型缺失(pointee 为空)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(target, "deref write target type missing (pointee is empty)", "TypeError")
|
||||
sv_w: mlirlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, rhs_val, pointee_w, node, trans)
|
||||
mlirlite.build_store(builder, sv_w, ptr_w)
|
||||
continue
|
||||
@@ -2118,7 +2118,7 @@ novirtual class AssignGenMixin:
|
||||
mod_alloca: mlirlite.Value* = self.Gen.VarGen.lookup_module_var(trans.SymTab, nm.id)
|
||||
if mod_alloca is None:
|
||||
# fail-fast: global variable not registered
|
||||
self.Gen.TypeGenErr.fatal_error(target, f"global 变量 '{nm.id}' 未注册,无法赋值", "NameError")
|
||||
self.Gen.TypeGenErr.fatal_error(target, f"global variable '{nm.id}' is not registered; cannot assign", "NameError")
|
||||
# Object global with static storage: bind to storage and copy the object (else dangling/NULL)
|
||||
stg_ref_as: mlirlite.Value* = None
|
||||
if nm.id is not None:
|
||||
@@ -2155,13 +2155,13 @@ novirtual class AssignGenMixin:
|
||||
nl_ptr: mlirlite.Value* = self.Gen.StmtGenDecl.get_nonlocal_var_ptr(trans, nm.id)
|
||||
if nl_ptr is None:
|
||||
# fail-fast: nonlocal variable pointer resolution failed
|
||||
self.Gen.TypeGenErr.fatal_error(target, f"nonlocal 变量 '{nm.id}' 指针解析失败", "NameError")
|
||||
self.Gen.TypeGenErr.fatal_error(target, f"nonlocal variable '{nm.id}' pointer resolution failed", "NameError")
|
||||
# Infer the nonlocal type from nl_ptr instead of forcing i32
|
||||
nl_target_ty: mlirlite.LLVMType* = None
|
||||
if nl_ptr.Ty is not None: nl_target_ty = nl_ptr.Ty.Pointee
|
||||
if nl_target_ty is None:
|
||||
# fail-fast: nl_ptr type lost, cannot store safely
|
||||
self.Gen.TypeGenErr.fatal_error(target, f"nonlocal 变量 '{nm.id}' 类型信息丢失,无法写入", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(target, f"nonlocal variable '{nm.id}' type information lost; cannot write", "TypeError")
|
||||
rhs_coerced: mlirlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, rhs_val, nl_target_ty, node, trans)
|
||||
mlirlite.build_store(builder, rhs_coerced, nl_ptr)
|
||||
continue
|
||||
@@ -2176,7 +2176,7 @@ novirtual class AssignGenMixin:
|
||||
# Block assignment to a module-level global inside a function without a global declaration
|
||||
if self.Gen.VarGen.is_module_scope(trans.SymTab) == 0:
|
||||
mod_gv: mlirlite.Value* = self.Gen.VarGen.lookup_module_var(trans.SymTab, nm.id)
|
||||
if mod_gv is not None: self.Gen.TypeGenErr.fatal_error(target, f"变量 '{nm.id}' 是模块级全局变量,函数内赋值需用 global 声明(否则创建局部变量遮蔽全局,导致全局保持 null 崩溃)", "SyntaxError")
|
||||
if mod_gv is not None: self.Gen.TypeGenErr.fatal_error(target, f"variable '{nm.id}' is a module-level global; assignment inside a function requires a global declaration (otherwise a local variable shadows the global, leaving it null and crashing)", "SyntaxError")
|
||||
|
||||
# Ordinary local variable
|
||||
alloca: mlirlite.Value* = self.Gen.VarGen.get_or_create_sym(trans.SymTab, pool, builder, nm.id, rhs_val.Ty)
|
||||
@@ -2196,7 +2196,7 @@ novirtual class AssignGenMixin:
|
||||
if existing is None: new_vars += 1
|
||||
else:
|
||||
# fail-fast: variable storage creation failed
|
||||
self.Gen.TypeGenErr.fatal_error(target, f"变量 '{nm.id}' 存储创建失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(target, f"variable '{nm.id}' storage creation failed", "TypeError")
|
||||
|
||||
return new_vars
|
||||
|
||||
@@ -2228,7 +2228,7 @@ novirtual class AssignGenMixin:
|
||||
# Array slots (t.CArray[T,N]) are legal; only block when the base is a pointer store
|
||||
if self.Gen.ExprGenName.subscript_base_store_kind(pool, trans, target) != 0: return
|
||||
elem_nm_wo: str = mlirlite.get_struct_name(elem_ty)
|
||||
if elem_nm_wo is None: elem_nm_wo = "<匿名结构体>"
|
||||
if elem_nm_wo is None: elem_nm_wo = "<anonymous struct>"
|
||||
rhs_nm_wo: str = mlirlite.get_struct_name(rhs_inner_wo)
|
||||
if rhs_nm_wo is None: rhs_nm_wo = elem_nm_wo
|
||||
elem_sz_wo: int = self.Gen.ClassGenEnum._get_type_size(elem_ty)
|
||||
@@ -2240,7 +2240,7 @@ novirtual class AssignGenMixin:
|
||||
if target is not None:
|
||||
col_s_wo = target.col_offset + 1
|
||||
col_e_wo = target.end_col_offset + 1
|
||||
self.Gen.TypeGenErr.fatal_error(target, f"下标赋值的左值元素是对象 '{elem_nm_wo}'({elem_sz_wo} 字节)," f"右值却是指向 '{rhs_nm_wo}' 的指针:编译器会静默生成整对象拷贝" f"(load {elem_nm_wo} + store {elem_nm_wo},写 {elem_sz_wo} 字节)," f"而不是按指针写 {ptr_sz_wo} 字节。若该地址实际按 8 字节槽存放指针" f"(如 rawptr[T] 缓冲/空闲链表),每写一个元素就越界 {over_wo} 字节," f"直接写穿相邻块。修法:把指针槽的基座类型写成指针元素形态" f"(`rawptr[T]*` 或 `rawptr[rawptr[T]]`)后再赋值;" f"或把基座显式转为 t.CPtr(无类型指针)后按 8 字节指针语义写入。", "TypeError", col_s_wo, col_e_wo)
|
||||
self.Gen.TypeGenErr.fatal_error(target, f"the lvalue element of the subscript assignment is object '{elem_nm_wo}' ({elem_sz_wo} bytes), " f"but the rhs is a pointer to '{rhs_nm_wo}': the compiler would silently emit a whole-object copy " f"(load {elem_nm_wo} + store {elem_nm_wo}, writing {elem_sz_wo} bytes), " f"instead of writing {ptr_sz_wo} bytes as a pointer. If that address actually stores pointers in 8-byte slots " f"(such as a rawptr[T] buffer/free list), every element written overflows by {over_wo} bytes, " f"writing through adjacent blocks. Fix: declare the base type of the pointer slot in pointer-element form " f"(`rawptr[T]*` or `rawptr[rawptr[T]]`) before assigning; " f"or explicitly cast the base to t.CPtr (untyped pointer) and write with 8-byte pointer semantics.", "TypeError", col_s_wo, col_e_wo)
|
||||
|
||||
# _infer_rhs_annot - infer a variable's annotation class name from the RHS expression
|
||||
def _infer_rhs_annot(self, pool: memhub.MemBuddy*, mod: mlirlite.LLVMModule*, node: ast.AST*, trans: HT.Translator*, rhs_val: mlirlite.Value* = None) -> str:
|
||||
|
||||
@@ -277,7 +277,7 @@ novirtual class AsyncGenMixin(CallGenBase.CallGenBase):
|
||||
if self._is_range_for(stmt) == 0:
|
||||
err_b2: str = trans.Pool.alloc(256)
|
||||
if err_b2 is not None:
|
||||
viperlib.snprintf(err_b2, 256, "[coro-M3] 协程内 For 仅支持 range 迭代(含 await)")
|
||||
viperlib.snprintf(err_b2, 256, "[coro-M3] For inside a coroutine supports only range iteration (including await)")
|
||||
self.Gen.TypeGenErr.fatal_error(stmt, err_b2, "SyntaxError")
|
||||
return
|
||||
# fill __f_idx_N / __f_len_N (i32)
|
||||
@@ -961,7 +961,7 @@ novirtual class AsyncGenMixin(CallGenBase.CallGenBase):
|
||||
if call_name is None: call_name = "(unknown)"
|
||||
err_buf: str = pool.alloc(256)
|
||||
if err_buf is not None:
|
||||
viperlib.snprintf(err_buf, 256, "[coro-M2] await 目标 '%s' 不是 async 函数", call_name)
|
||||
viperlib.snprintf(err_buf, 256, "[coro-M2] await target '%s' is not an async function", call_name)
|
||||
self.Gen.TypeGenErr.fatal_error(stmt, err_buf, "SyntaxError")
|
||||
continue
|
||||
# nested await in the statement -> hoist to __await_N
|
||||
@@ -979,7 +979,7 @@ novirtual class AsyncGenMixin(CallGenBase.CallGenBase):
|
||||
if self._find_expr_await(ifn.test) is not None:
|
||||
err_b: str = pool.alloc(256)
|
||||
if err_b is not None:
|
||||
viperlib.snprintf(err_b, 256, "[coro-M2] if 条件中不支持 await")
|
||||
viperlib.snprintf(err_b, 256, "[coro-M2] await is not supported in an if condition")
|
||||
self.Gen.TypeGenErr.fatal_error(stmt, err_b, "SyntaxError")
|
||||
return
|
||||
cond: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, ifn.test, None, 0, trans)
|
||||
@@ -1013,7 +1013,7 @@ novirtual class AsyncGenMixin(CallGenBase.CallGenBase):
|
||||
if whn.test is not None and self._find_expr_await(whn.test) is not None:
|
||||
err_c: str = pool.alloc(256)
|
||||
if err_c is not None:
|
||||
viperlib.snprintf(err_c, 256, "[coro-M2] while 条件中不支持 await")
|
||||
viperlib.snprintf(err_c, 256, "[coro-M2] await is not supported in a while condition")
|
||||
self.Gen.TypeGenErr.fatal_error(stmt, err_c, "SyntaxError")
|
||||
return
|
||||
func: mlirlite.Function* = trans._cur_func
|
||||
@@ -1421,7 +1421,7 @@ novirtual class AsyncGenMixin(CallGenBase.CallGenBase):
|
||||
if nhandlers == 0:
|
||||
err_t: str = pool.alloc(256)
|
||||
if err_t is not None:
|
||||
viperlib.snprintf(err_t, 256, "[coro-M6] 协程内 try 需要 except 子句")
|
||||
viperlib.snprintf(err_t, 256, "[coro-M6] try inside a coroutine requires an except clause")
|
||||
self.Gen.TypeGenErr.fatal_error(stmt, err_t, "SyntaxError")
|
||||
return
|
||||
func: mlirlite.Function* = trans._cur_func
|
||||
@@ -1531,7 +1531,7 @@ novirtual class AsyncGenMixin(CallGenBase.CallGenBase):
|
||||
if tr.finalbody is not None and self._stmts_deep_await(tr.finalbody) != 0:
|
||||
err_f: str = pool.alloc(256)
|
||||
if err_f is not None:
|
||||
viperlib.snprintf(err_f, 256, "[coro-M7] finally 内暂不支持 await")
|
||||
viperlib.snprintf(err_f, 256, "[coro-M7] await is not yet supported inside finally")
|
||||
self.Gen.TypeGenErr.fatal_error(stmt, err_f, "SyntaxError")
|
||||
return
|
||||
func: mlirlite.Function* = trans._cur_func
|
||||
@@ -1566,7 +1566,7 @@ novirtual class AsyncGenMixin(CallGenBase.CallGenBase):
|
||||
if self._is_range_for(stmt) == 0:
|
||||
err_g: str = pool.alloc(256)
|
||||
if err_g is not None:
|
||||
viperlib.snprintf(err_g, 256, "[coro-M3] 协程内 For 仅支持 range 迭代(含 await)")
|
||||
viperlib.snprintf(err_g, 256, "[coro-M3] For inside a coroutine supports only range iteration (including await)")
|
||||
self.Gen.TypeGenErr.fatal_error(stmt, err_g, "SyntaxError")
|
||||
return
|
||||
fn: ast.For* = ast.For*(stmt)
|
||||
|
||||
@@ -502,7 +502,7 @@ novirtual class CallGenBase:
|
||||
while existing is not None:
|
||||
existing_steps += 1
|
||||
if existing_steps > DECLARE_CHAIN_LIMIT:
|
||||
stdio.printf("[CALLGEN] 链表异常: module funcs(call_name=%s,遍历超限,终止)\n", call_name)
|
||||
stdio.printf("[CALLGEN] linked-list anomaly: module funcs (call_name=%s, traversal limit exceeded, aborting)\n", call_name)
|
||||
# converge: longjmp back to the REPL loop (diagnostic already printed)
|
||||
VLogger.repl_abort()
|
||||
if existing.Name is not None:
|
||||
@@ -519,7 +519,7 @@ novirtual class CallGenBase:
|
||||
while cur_p is not None:
|
||||
cur_count += 1
|
||||
if cur_count > DECLARE_CHAIN_LIMIT:
|
||||
stdio.printf("[CALLGEN] 链表异常: func params(call_name=%s,参数链遍历超限,终止)\n", call_name)
|
||||
stdio.printf("[CALLGEN] linked-list anomaly: func params (call_name=%s, param chain traversal limit exceeded, aborting)\n", call_name)
|
||||
# converge: longjmp back to the REPL loop (diagnostic already printed)
|
||||
VLogger.repl_abort()
|
||||
cur_p = cur_p.Next
|
||||
@@ -665,8 +665,8 @@ novirtual class CallGenBase:
|
||||
# ============================================================
|
||||
def _fail_method_ret_ty(self, method_name: str, node: ast.AST* = None) -> mlirlite.LLVMType*:
|
||||
"""Fail fast when a method return type cannot be resolved precisely (module function, text.ll define, then vpi cache); never default to i32."""
|
||||
VLogger.error(f"方法返回类型无法精确获取(函数/text.ll/vpi stub 均未命中): {method_name}", "HandlesExprCall")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"方法返回类型无法精确获取,默认 i32 会截断指针/i64: {method_name}", "TypeError")
|
||||
VLogger.error(f"method return type cannot be obtained precisely (function/text.ll/vpi stub all missed): {method_name}", "HandlesExprCall")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"method return type cannot be obtained precisely; defaulting to i32 would truncate pointers/i64: {method_name}", "TypeError")
|
||||
return None
|
||||
|
||||
# SetTempDir: set the temp dir path (called before Phase A to read dependency text.ll)
|
||||
|
||||
@@ -48,7 +48,7 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
pointee: mlirlite.LLVMType* = ptr_val.Ty.Pointee
|
||||
if pointee is not None: return mlirlite.build_load(builder, pointee, ptr_val, vol_deref)
|
||||
# Non-pointer arg means degraded type inference: fail-fast, never read as i8.
|
||||
self.Gen.TypeGenErr.fatal_error(cl, "c.Deref 参数不是指针类型(类型推断退化)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(cl, "c.Deref argument is not a pointer type (type inference degraded)", "TypeError")
|
||||
return None
|
||||
|
||||
|
||||
@@ -114,10 +114,10 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
if ptr_expr is not None:
|
||||
ptr_a: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, ptr_expr, None, 0, trans)
|
||||
if ptr_a is None or ptr_a.Ty is None or self.Gen.ExprGenBase.is_ptr_type(ptr_a.Ty) == 0:
|
||||
self.Gen.TypeGenErr.fatal_error(a_node, "c.Set 的解引用目标必须是指针类型(类型推断退化)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(a_node, "c.Set dereference target must be a pointer type (type inference degraded)", "TypeError")
|
||||
pointee_a: mlirlite.LLVMType* = ptr_a.Ty.Pointee
|
||||
if pointee_a is None:
|
||||
self.Gen.TypeGenErr.fatal_error(a_node, "c.Set 解引用目标的 pointee 类型缺失", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(a_node, "c.Set dereference target pointee type missing", "TypeError")
|
||||
sv_a: mlirlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, b_val, pointee_a, a_node, trans)
|
||||
if sv_a is not None: mlirlite.build_store(builder, sv_a, ptr_a)
|
||||
return b_val
|
||||
@@ -411,7 +411,7 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
|
||||
# Other arg0 forms fail-fast: c.Addr is a compile-time instruction and must
|
||||
# never fall through to a runtime call @Addr.
|
||||
self.Gen.TypeGenErr.fatal_error(cl, f"c.Addr 不支持的操作数形式(kind={arg0.kind()}),c.Addr 仅支持 变量/全局/函数/数组元素/字段", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(cl, f"c.Addr unsupported operand form (kind={arg0.kind()}); c.Addr only supports variable/global/function/array element/field", "TypeError")
|
||||
return None
|
||||
|
||||
|
||||
@@ -488,7 +488,7 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
if prev_ok != 0 and next_ok != 0:
|
||||
# fail-fast: an asm template referencing a SHA1-mangled
|
||||
# global cannot be used in LLVM MC; mark it t.CExport.
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"asm 模板引用的全局符号 '{bare_g}' 带 SHA1 混淆头({gname}),内联汇编必须引用裸名符号,请将该全局定义标记为 t.CExport", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"Global symbol '{bare_g}' referenced by the asm template has a SHA1 mangling prefix ({gname}); inline assembly must reference bare-name symbols, so mark that global definition as t.CExport", "TypeError")
|
||||
return asm_text
|
||||
cur = cur.Next
|
||||
if matched == 0:
|
||||
@@ -723,7 +723,7 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
# fail-fast: AsmInp/AsmOut operands must not carry SHA1-mangled symbols;
|
||||
# LLVM MC cannot parse digit-leading names, so mark them 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"__asm__ 操作数(AsmInp/AsmOut)不允许带 SHA1 混淆头的符号 '{val.Name}',请将对应函数/全局定义标记为 t.CExport(裸名)", "TypeError")
|
||||
if self._asm_name_is_mangled(val.Name) != 0: self.Gen.TypeGenErr.fatal_error(None, f"__asm__ operand (AsmInp/AsmOut) does not allow a symbol with a SHA1 mangling prefix '{val.Name}'; mark the corresponding function/global definition as t.CExport (bare name)", "TypeError")
|
||||
if val is not None:
|
||||
for ei in range(count):
|
||||
eop: GenTypes.AsmOperand* = self._asm_get_operand(operands, ei)
|
||||
@@ -1010,7 +1010,7 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
out_pn_n += 1
|
||||
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, "__asm__ 输出操作数类型缺失(变量 alloca 类型退化)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(cl, "__asm__ output operand type missing (variable alloca type degraded)", "TypeError")
|
||||
ret_ty = mlirlite.Int32(pool)
|
||||
else:
|
||||
out_op: GenTypes.AsmOperand* = self._asm_get_operand(operands, first_output_idx)
|
||||
@@ -1020,7 +1020,7 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
elif out_op is not None and out_op.Value is not None and out_op.Value.Ty is not None and out_op.Value.Ty.Pointee != 0: out_pt = out_op.Value.Ty.Pointee
|
||||
if out_pt is not None: ret_ty = out_pt
|
||||
else:
|
||||
self.Gen.TypeGenErr.fatal_error(cl, "__asm__ 输出操作数类型缺失(变量 alloca 类型退化)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(cl, "__asm__ output operand type missing (variable alloca type degraded)", "TypeError")
|
||||
ret_ty = mlirlite.Int32(pool)
|
||||
|
||||
# Determine void directly from output_count to avoid match type issues
|
||||
@@ -1039,7 +1039,7 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
if re_op.Value is not None and re_op.Value.Ty is not None and re_op.Value.Ty.Pointee != 0:
|
||||
ret_re = re_op.Value.Ty.Pointee
|
||||
break
|
||||
if ret_re is None: self.Gen.TypeGenErr.fatal_error(cl, "__asm__ 输出操作数类型缺失(变量 alloca 类型退化)", "TypeError")
|
||||
if ret_re is None: self.Gen.TypeGenErr.fatal_error(cl, "__asm__ output operand type missing (variable alloca type degraded)", "TypeError")
|
||||
ret_ty = ret_re
|
||||
case _:
|
||||
pass
|
||||
@@ -1227,7 +1227,7 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
if cl is None or builder is None or pool is None or trans is None: return None
|
||||
|
||||
cargs: list[ast.AST*]* = cl.args
|
||||
if cargs is None or len(cargs) < 1: self.Gen.TypeGenErr.fatal_error(cl, "c.LLVMIR 缺少模板参数", "TypeError")
|
||||
if cargs is None or len(cargs) < 1: self.Gen.TypeGenErr.fatal_error(cl, "c.LLVMIR missing template argument", "TypeError")
|
||||
|
||||
# LOut writeback records (alloca pointer + register name), up to LLVMIR_MAX_OPS
|
||||
out_alloca: sizet* = pool.alloc(8 * LLVMIR_MAX_OPS)
|
||||
@@ -1288,7 +1288,7 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
nm: ast.Name* = ast.Name*(val_node)
|
||||
if nm.id is not None:
|
||||
alloca: mlirlite.Value* = self.Gen.VarGen.lookup_var(trans.SymTab, nm.id)
|
||||
if alloca is None or out_count >= LLVMIR_MAX_OPS: self.Gen.TypeGenErr.fatal_error(fcall, f"c.LOut 变量 '{nm.id}' 未定义或输出数超过 {LLVMIR_MAX_OPS}", "TypeError")
|
||||
if alloca is None or out_count >= LLVMIR_MAX_OPS: self.Gen.TypeGenErr.fatal_error(fcall, f"c.LOut variable '{nm.id}' is undefined or the output count exceeds {LLVMIR_MAX_OPS}", "TypeError")
|
||||
self.Gen.CallGenBase.LLVMIRRegSeq += 1
|
||||
reg_buf: str = pool.alloc(32)
|
||||
if reg_buf is not None:
|
||||
|
||||
@@ -181,13 +181,13 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
if cls_sha1 is None:
|
||||
# [D6 truncation] Allocate by exact length instead of a fixed 256
|
||||
# buffer so long class/method names are not silently truncated.
|
||||
msg_fmt: str = "类 '%s' 方法 '%s' 找不到模块 SHA1"
|
||||
msg_fmt: str = "Class '%s' method '%s': module SHA1 not found"
|
||||
msg_size: sizet = string.strlen(msg_fmt) + string.strlen(class_name) + string.strlen(method_name) - 4 + 1
|
||||
err_msg: str = pool.alloc(msg_size)
|
||||
if err_msg is not None:
|
||||
viperlib.snprintf(err_msg, msg_size, msg_fmt, class_name, method_name)
|
||||
self.Gen.TypeGenErr.fatal_error(node, err_msg)
|
||||
self.Gen.TypeGenErr.fatal_error(node, "找不到模块 SHA1")
|
||||
self.Gen.TypeGenErr.fatal_error(node, "Module SHA1 not found")
|
||||
# Build the call name: {cls_sha1}.{lookup_name}.
|
||||
mangled2: str = pool.alloc(string.strlen(cls_sha1) + string.strlen(lookup_name) + 2)
|
||||
if mangled2 is not None:
|
||||
@@ -203,13 +203,13 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
elif string.strcmp(method_name, "__getitem__") == 0 or string.strcmp(method_name, "__new__") == 0:
|
||||
# fail-fast: __getitem__/__new__ must return a pointer; a missing
|
||||
# return type means a broken stub declare (silent ptr truncation).
|
||||
msg_fmt1: str = "方法 '%s' 返回类型无法确定(stub declare 返回类型缺失)"
|
||||
msg_fmt1: str = "Cannot determine return type of method '%s' (stub declare return type missing)"
|
||||
msg_size1: sizet = string.strlen(msg_fmt1) + string.strlen(method_name) - 2 + 1
|
||||
err_cm1: str = pool.alloc(msg_size1)
|
||||
if err_cm1 is not None:
|
||||
viperlib.snprintf(err_cm1, msg_size1, msg_fmt1, method_name)
|
||||
self.Gen.TypeGenErr.fatal_error(node, err_cm1)
|
||||
self.Gen.TypeGenErr.fatal_error(node, "方法返回类型无法确定")
|
||||
self.Gen.TypeGenErr.fatal_error(node, "Cannot determine method return type")
|
||||
else:
|
||||
# found_func is None (stub not injected): cannot read the return type
|
||||
# from the declare. __before_init__/__init__ always return void.
|
||||
@@ -220,22 +220,22 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
if cmop_struct_ty is not None: call_ret_ty = mlirlite.Ptr(pool, cmop_struct_ty)
|
||||
else:
|
||||
# [D6 truncation] Use exact length instead of a fixed 256 buffer.
|
||||
msg_fmt2: str = "方法 '%s' 的 self 结构体类型未知(字段类型退化,依赖模块未预注册?)"
|
||||
msg_fmt2: str = "Unknown self struct type of method '%s' (field type degraded, dependency module not preregistered?)"
|
||||
msg_size2: sizet = string.strlen(msg_fmt2) + string.strlen(method_name) - 2 + 1
|
||||
err_cm2: str = pool.alloc(msg_size2)
|
||||
if err_cm2 is not None:
|
||||
viperlib.snprintf(err_cm2, msg_size2, msg_fmt2, method_name)
|
||||
self.Gen.TypeGenErr.fatal_error(node, err_cm2)
|
||||
self.Gen.TypeGenErr.fatal_error(node, "self 结构体类型未知")
|
||||
self.Gen.TypeGenErr.fatal_error(node, "Unknown self struct type")
|
||||
elif string.strcmp(method_name, "__getitem__") == 0:
|
||||
# [D6 truncation] Use exact length instead of a fixed 256 buffer.
|
||||
msg_fmt3: str = "方法 '%s.__getitem__' 的 stub declare 未注入(依赖模块 vpi 缺失或拓扑顺序错误),无法确定返回类型"
|
||||
msg_fmt3: str = "Method '%s.__getitem__': stub declare not injected (dependency module vpi missing or wrong topological order); cannot determine return type"
|
||||
msg_size3: sizet = string.strlen(msg_fmt3) + string.strlen(class_name) - 2 + 1
|
||||
err_cm3: str = pool.alloc(msg_size3)
|
||||
if err_cm3 is not None:
|
||||
viperlib.snprintf(err_cm3, msg_size3, msg_fmt3, class_name)
|
||||
self.Gen.TypeGenErr.fatal_error(node, err_cm3)
|
||||
self.Gen.TypeGenErr.fatal_error(node, "__getitem__ stub declare 未注入")
|
||||
self.Gen.TypeGenErr.fatal_error(node, "__getitem__ stub declare not injected")
|
||||
else:
|
||||
# Other cross-module methods: resolve the return type precisely via
|
||||
# text.ll / vpi; fail fast rather than silently keeping void.
|
||||
@@ -263,9 +263,9 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
else:
|
||||
err_cm4: str = pool.alloc(256)
|
||||
if err_cm4 is not None:
|
||||
viperlib.snprintf(err_cm4, 256, "方法 '%s.%s' 返回类型无法确定(text.ll/vpi 均未命中,跨模块 stub 未注入)", class_name, method_name)
|
||||
viperlib.snprintf(err_cm4, 256, "Cannot determine return type of method '%s.%s' (neither text.ll nor vpi hit, cross-module stub not injected)", class_name, method_name)
|
||||
self.Gen.TypeGenErr.fatal_error(node, err_cm4)
|
||||
self.Gen.TypeGenErr.fatal_error(node, "方法返回类型无法确定")
|
||||
self.Gen.TypeGenErr.fatal_error(node, "Cannot determine method return type")
|
||||
|
||||
# __new__'s signature may be shorter than __init__'s, so trim trailing
|
||||
# args to the callee's non-self param count (__init__ consumes them).
|
||||
@@ -361,7 +361,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
if mdf_val is None:
|
||||
# Use node (this function's line-info node), not cl which is
|
||||
# undefined here and would report "line 0".
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"跨模块默认参数无法重建(快照缺失,默认值需为简单常量): {lookup_name}", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"Cross-module default argument cannot be rebuilt (snapshot missing, the default value must be a simple constant): {lookup_name}", "TypeError")
|
||||
continue
|
||||
mlirlite.value_set_next(mdf_val, None)
|
||||
mlirlite.value_set_next(tail, mdf_val)
|
||||
@@ -556,7 +556,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
if cm_bare is not None and string.strchr(cm_bare, '[') is None:
|
||||
cm_tpl: ast.ClassDef* = self.Gen.ClassGenGeneric._find_generic_template(cm_bare)
|
||||
if cm_tpl is not None:
|
||||
self.Gen.TypeGenErr.fatal_error(cl, f"泛型类 '{cm_bare}' 的方法 '{method_name}' 调用缺少类型实参" f"(接收者静态类型是裸泛型基类,元素类型未知);" f"禁止静默按默认 list[int] 特化(元素按 i32 处理会截断指针)," f"请让该变量的注解/类型带上实参(如 list[ast.AST*])", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(cl, f"Generic class '{cm_bare}' method '{method_name}' call is missing type arguments" f" (receiver static type is a bare generic base, element type unknown); " f"silent specialization as the default list[int] is forbidden (treating elements as i32 truncates pointers), " f"annotate the variable type with arguments (e.g. list[ast.AST*])", "TypeError")
|
||||
|
||||
# Fetch the struct entry early (find_struct_by_type avoids cross-module
|
||||
# same-name collisions) for MRO walking, SHA1 lookup and vtable dispatch.
|
||||
@@ -861,7 +861,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
elif ret_anc_name is not None and ret_anc_sha1 is None:
|
||||
# fail-fast: the defining class's SHA1 is unresolvable and type-name
|
||||
# extraction failed; never emit a silent bare name.
|
||||
self.Gen.TypeGenErr.fatal_error(cl, f"方法 '{method_name}' 所属类 '{ret_anc_name}' 无法解析模块 SHA1(text.ll/vpi/类型名均未命中),跨模块调用名构造失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(cl, f"Cannot resolve module SHA1 for class '{ret_anc_name}' of method '{method_name}' (neither text.ll/vpi nor type name hit); cross-module call name construction failed", "TypeError")
|
||||
|
||||
# Translate the call arguments.
|
||||
cargs: list[ast.AST*]* = cl.args
|
||||
@@ -931,10 +931,10 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
self_arg = mlirlite.build_bitcast(builder, adj_th2, anc_ptr_ty_th2)
|
||||
else:
|
||||
# Defining class struct size unavailable (opaque/unloaded): fail fast.
|
||||
self.Gen.TypeGenErr.fatal_error(cl, f"this-adjust 兄弟 Mixin 定义类大小未知: 方法'{method_name}'定义类'{mc_anc}'的 struct 大小计算失败", "InternalCompilerError")
|
||||
self.Gen.TypeGenErr.fatal_error(cl, f"this-adjust sibling Mixin defining class size unknown: struct size computation failed for method '{method_name}' defining class '{mc_anc}'", "InternalCompilerError")
|
||||
elif is_first_parent_th == 0:
|
||||
self.Gen.TypeGenErr.fatal_error(cl, f"this-adjust 字段查找失败: 方法'{method_name}'定义类'{mc_anc}'首字段'{anc_first_name_th}'在类'{class_name}'/'{mc_anc}'布局中未找到", "InternalCompilerError")
|
||||
elif is_first_parent_th == 0: self.Gen.TypeGenErr.fatal_error(cl, f"this-adjust 子类结构体未注册: 方法'{method_name}'定义类'{mc_anc}',接收类'{class_name}'的 struct 未找到", "InternalCompilerError")
|
||||
self.Gen.TypeGenErr.fatal_error(cl, f"this-adjust field lookup failed: first field '{anc_first_name_th}' of method '{method_name}' defining class '{mc_anc}' not found in the layout of class '{class_name}'/'{mc_anc}'", "InternalCompilerError")
|
||||
elif is_first_parent_th == 0: self.Gen.TypeGenErr.fatal_error(cl, f"this-adjust subclass struct not registered: method '{method_name}' defining class '{mc_anc}', struct of receiver class '{class_name}' not found", "InternalCompilerError")
|
||||
else:
|
||||
# Parent has only the __vtable__ field: the method body reads no
|
||||
# layout fields, so no adjustment is needed.
|
||||
@@ -945,7 +945,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
elif is_first_parent_th == 0:
|
||||
# Parent struct not registered: fail fast, never use an unadjusted
|
||||
# obj_ptr as self.
|
||||
self.Gen.TypeGenErr.fatal_error(cl, f"this-adjust 父类结构体未注册: 方法'{method_name}'定义类'{mc_anc}'的 struct 未找到", "InternalCompilerError")
|
||||
self.Gen.TypeGenErr.fatal_error(cl, f"this-adjust parent struct not registered: struct of method '{method_name}' defining class '{mc_anc}' not found", "InternalCompilerError")
|
||||
# Coerce self to the declared first-param type: the object pointer may be
|
||||
# i8* or an adjusted ancestor pointer and needs a bitcast to match.
|
||||
if found_func is not None:
|
||||
@@ -990,7 +990,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
if arg_node_k is not None:
|
||||
# (a) The arg node exists but translated to None: fail fast;
|
||||
# never substitute a zero value for an unresolved argument.
|
||||
self.Gen.TypeGenErr.fatal_error(arg_node_k, f"方法调用 '{class_name}.{method_name}' 第 {pi_k + 1} 个形参的实参表达式翻译失败(返回 None,禁止按类型零值兜底)","TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(arg_node_k, f"Method call '{class_name}.{method_name}': argument expression for parameter {pi_k + 1} translation failed (returned None, zero-value fallback by type forbidden)","TypeError")
|
||||
continue
|
||||
# (b)/(c) Neither keyword nor positional supplied this param: insert a
|
||||
# typed zero placeholder to keep positions (not a failure fallback).
|
||||
@@ -1012,7 +1012,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
if arg_node is None:
|
||||
# (a) Missing arg node (AST list hole): fail fast, never skip silently
|
||||
# (skipping would reduce arg_count_eff and get zero-filled later).
|
||||
self.Gen.TypeGenErr.fatal_error(cl, f"方法调用 '{class_name}.{method_name}' 第 {ai + 1} 个实参节点缺失(AST 参数列表空洞,无法翻译)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(cl, f"Method call '{class_name}.{method_name}': argument node {ai + 1} missing (hole in the AST argument list, cannot translate)", "TypeError")
|
||||
continue
|
||||
# Fetch the param type first: a CONST_CHAR passed to a str/pointer param
|
||||
# must be materialized, else inttoptr treats the char as a pointer.
|
||||
@@ -1030,7 +1030,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
if arg_val is None:
|
||||
# (a) The arg expression translated to None: fail fast, never continue;
|
||||
# skipping would reduce arg_count_eff and get zero-filled later.
|
||||
self.Gen.TypeGenErr.fatal_error(arg_node, f"方法调用 '{class_name}.{method_name}' 第 {ai + 1} 个实参表达式翻译失败(返回 None,禁止按类型零值兜底)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(arg_node, f"Method call '{class_name}.{method_name}': argument expression {ai + 1} translation failed (returned None, zero-value fallback by type forbidden)", "TypeError")
|
||||
continue
|
||||
# Coerce to the param type (self is param 0, arg ai maps to param ai+1);
|
||||
# an i32 constant passed to an i64 param would read garbage high bits.
|
||||
@@ -1119,7 +1119,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
mdf_val: mlirlite.Value* = None
|
||||
if mdf_gd is not None: mdf_val = self.Gen.CallGenLeafKit._build_const_from_snapshot(pool, mod, mdf_gd, mdf_di, trans, builder)
|
||||
if mdf_val is None:
|
||||
self.Gen.TypeGenErr.fatal_error(cl, f"跨模块默认参数无法重建(快照缺失,默认值需为简单常量): {lookup_name}", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(cl, f"Cross-module default argument cannot be rebuilt (snapshot missing, the default value must be a simple constant): {lookup_name}", "TypeError")
|
||||
continue
|
||||
mlirlite.value_set_next(mdf_val, None)
|
||||
mlirlite.value_set_next(tail, mdf_val)
|
||||
@@ -1130,7 +1130,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
# (c) A known default region and this param index before it means a
|
||||
# missing required arg: fail fast instead of a silent zero fill.
|
||||
if mdf_default_count > 0 and mdf_pi < mdf_offset:
|
||||
self.Gen.TypeGenErr.fatal_error(cl, f"方法调用 '{lookup_name}' 漏传必需实参:第 {mdf_pi + 1} 个形参无默认值(调用点仅提供 {arg_count_eff} 个实参,该函数前 {mdf_offset} 个形参为必需)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(cl, f"Method call '{lookup_name}': missing required argument: parameter {mdf_pi + 1} has no default (call site provides only {arg_count_eff} arguments; the first {mdf_offset} parameters are required)", "TypeError")
|
||||
mdf_pi += 1
|
||||
continue
|
||||
# (b) Other missing params come from missing default info (a missing
|
||||
@@ -1319,7 +1319,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
if ap_sha1 is None:
|
||||
# Dependency module not compiled (_list not in the build chain): fail
|
||||
# fast, never silently skip append.
|
||||
self.Gen.TypeGenErr.fatal_error(cl, "list.append: 找不到 _list 模块 SHA1(依赖模块未编译)", "InternalCompilerError")
|
||||
self.Gen.TypeGenErr.fatal_error(cl, "list.append: _list module SHA1 not found (dependency module not compiled)", "InternalCompilerError")
|
||||
if ap_sha1 is not None:
|
||||
# Extract the specialized class name: list.append's symbol is
|
||||
# {sha1}.list[AST*].append, not {sha1}.list.append.
|
||||
@@ -1391,11 +1391,11 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
self_entry: GenTypes.VarEntry* = self.Gen.VarGen.lookup_var_entry(trans.SymTab, "self")
|
||||
if self_entry is None: self_entry = self.Gen.VarGen.lookup_var_entry(trans.SymTab, "cls")
|
||||
if self_entry is None:
|
||||
self.Gen.TypeGenErr.fatal_error(cl, "super(): 当前作用域无 self 变量(静态方法内不可用)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(cl, "super(): no self variable in the current scope (unavailable inside a static method)", "TypeError")
|
||||
return None
|
||||
cur_class: str = self.Gen.VarGen.var_annot_class_name(self_entry)
|
||||
if cur_class is None:
|
||||
self.Gen.TypeGenErr.fatal_error(cl, "super() 只能在类方法内使用(self 无注解类名)")
|
||||
self.Gen.TypeGenErr.fatal_error(cl, "super() can only be used inside a class method (self has no annotated class name)")
|
||||
return None
|
||||
# 2. Walk the MRO, skipping self, for the first ancestor defining the method.
|
||||
anc: str = None
|
||||
@@ -1414,13 +1414,13 @@ novirtual class CallGenCall(CallGenBase.CallGenBase):
|
||||
if anc is None:
|
||||
err_sp: str = pool.alloc(256)
|
||||
if err_sp is not None:
|
||||
viperlib.snprintf(err_sp, 256, "super(): 当前类 %s 的父类链未定义方法 %s", cur_class, method_name)
|
||||
viperlib.snprintf(err_sp, 256, "super(): the parent chain of current class %s does not define method %s", cur_class, method_name)
|
||||
self.Gen.TypeGenErr.fatal_error(cl, err_sp, "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(cl, "super(): 父类链未定义方法", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(cl, "super(): the parent chain does not define the method", "TypeError")
|
||||
return None
|
||||
# 3. self pointer (load from the self variable's alloca).
|
||||
if self_entry.Alloca is None or self_entry.Alloca.Ty is None:
|
||||
self.Gen.TypeGenErr.fatal_error(cl, "super(): 当前作用域无 self 变量(静态方法内不可用)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(cl, "super(): no self variable in the current scope (unavailable inside a static method)", "TypeError")
|
||||
return None
|
||||
self_ptr: mlirlite.Value* = None
|
||||
match self_entry.Alloca.Ty:
|
||||
|
||||
@@ -27,13 +27,13 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
|
||||
entry: GenTypes.StructEntry* = self.Gen.StructGen.find_struct_by_type(struct_ty)
|
||||
if entry is None:
|
||||
# fail-fast: struct type unregistered; a silent return would leave fields uninitialized
|
||||
VLogger.error(f"结构体类型未注册,无法应用默认值: {class_name}", "HandlesExprCall")
|
||||
VLogger.error(f"Struct type not registered, cannot apply defaults: {class_name}", "HandlesExprCall")
|
||||
return
|
||||
for fi in range(entry.FieldCount):
|
||||
fe: GenTypes.FieldEntry* = self.Gen.StructGen._get_field_entry(entry, fi)
|
||||
if fe is None:
|
||||
# fail-fast: field index out of range (entry.FieldCount mismatch)
|
||||
VLogger.error(f"字段索引越界,无法获取字段 entry: {class_name}", "HandlesExprCall")
|
||||
VLogger.error(f"Field index out of range, cannot get field entry: {class_name}", "HandlesExprCall")
|
||||
continue
|
||||
if fe.DefaultVal is None: continue # reasonable skip: field without a default
|
||||
# Static array field with a list-literal default: zero then per-element GEP+store
|
||||
@@ -48,18 +48,18 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
|
||||
if sd_ctx is not None:
|
||||
fname_sd: str = fe.Name
|
||||
if fname_sd is None: fname_sd = "?"
|
||||
viperlib.snprintf(sd_ctx, 192, "类 %s 字段 %s(结构体构造默认值):", class_name, fname_sd)
|
||||
viperlib.snprintf(sd_ctx, 192, "Class %s field %s (struct ctor defaults):", class_name, fname_sd)
|
||||
self.Gen.AssignGen._init_global_array_from_list(builder, pool, mod, field_ptr_arr2, fe.DefaultVal, trans, sd_ctx)
|
||||
continue
|
||||
default_val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, fe.DefaultVal, None, 0, trans, fe.Ty)
|
||||
if default_val is None:
|
||||
# fail-fast: default value translation failed (e.g. undefined symbol)
|
||||
VLogger.error(f"字段默认值翻译失败: {class_name}", "HandlesExprCall")
|
||||
VLogger.error(f"Field default value translation failed: {class_name}", "HandlesExprCall")
|
||||
continue
|
||||
field_ptr: mlirlite.Value* = mlirlite.build_gep_struct(builder, struct_ty, fe.Ty, tmp, fe.Index)
|
||||
if field_ptr is None:
|
||||
# fail-fast: GEP failed (struct_ty and fe.Ty mismatch)
|
||||
VLogger.error(f"字段 GEP 失败,类型不匹配: {class_name}", "HandlesExprCall")
|
||||
VLogger.error(f"Field GEP failed, type mismatch: {class_name}", "HandlesExprCall")
|
||||
continue
|
||||
default_val = self.Gen.ExprGenBase.coerce_to_type(builder, default_val, fe.Ty, fe.DefaultVal)
|
||||
mlirlite.build_store(builder, default_val, field_ptr, is_volatile)
|
||||
@@ -185,17 +185,17 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
|
||||
else: fe = self.Gen.StructGen.get_field_by_index(class_name, ai)
|
||||
if fe is None:
|
||||
# fail-fast: field index out of range (too many args passed)
|
||||
VLogger.error(f"构造函数参数过多,字段索引越界: {class_name}", "HandlesExprCall")
|
||||
VLogger.error(f"Too many constructor arguments, field index out of range: {class_name}", "HandlesExprCall")
|
||||
continue
|
||||
arg_val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, arg, None, 0, trans, fe.Ty)
|
||||
if arg_val is None:
|
||||
# fail-fast: argument translation failed
|
||||
VLogger.error(f"构造函数参数翻译失败: {class_name}", "HandlesExprCall")
|
||||
VLogger.error(f"Constructor argument translation failed: {class_name}", "HandlesExprCall")
|
||||
continue
|
||||
field_ptr: mlirlite.Value* = mlirlite.build_gep_struct(builder, struct_ty, fe.Ty, storage_ptr, fe.Index)
|
||||
if field_ptr is None:
|
||||
# fail-fast: GEP failed (struct_ty and fe.Ty mismatch)
|
||||
VLogger.error(f"构造函数字段 GEP 失败: {class_name}", "HandlesExprCall")
|
||||
VLogger.error(f"Constructor field GEP failed: {class_name}", "HandlesExprCall")
|
||||
continue
|
||||
arg_val = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val, fe.Ty, arg)
|
||||
mlirlite.build_store(builder, arg_val, field_ptr, is_volatile)
|
||||
@@ -220,18 +220,18 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
|
||||
else: fe = self.Gen.StructGen.get_field_by_index(class_name, ai)
|
||||
if fe is None:
|
||||
# fail-fast: field index out of range (too many args passed)
|
||||
VLogger.error(f"构造函数参数过多,字段索引越界: {class_name}", "HandlesExprCall")
|
||||
VLogger.error(f"Too many constructor arguments, field index out of range: {class_name}", "HandlesExprCall")
|
||||
continue
|
||||
arg_val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, arg, None, 0, trans, fe.Ty)
|
||||
if arg_val is None:
|
||||
# fail-fast: argument translation failed
|
||||
VLogger.error(f"构造函数参数翻译失败: {class_name}", "HandlesExprCall")
|
||||
VLogger.error(f"Constructor argument translation failed: {class_name}", "HandlesExprCall")
|
||||
continue
|
||||
# GEP to field ai
|
||||
field_ptr: mlirlite.Value* = mlirlite.build_gep_struct(builder, struct_ty, fe.Ty, tmp, fe.Index)
|
||||
if field_ptr is None:
|
||||
# fail-fast: GEP failed (struct_ty and fe.Ty mismatch)
|
||||
VLogger.error(f"构造函数字段 GEP 失败: {class_name}", "HandlesExprCall")
|
||||
VLogger.error(f"Constructor field GEP failed: {class_name}", "HandlesExprCall")
|
||||
continue
|
||||
# coerce and store
|
||||
arg_val = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val, fe.Ty, arg)
|
||||
@@ -445,7 +445,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
|
||||
else: fe = self.Gen.StructGen.get_field_by_index(class_name, ai)
|
||||
if fe is None:
|
||||
# positional arg out of range (no matching field): fail-fast, never skip silently
|
||||
self.Gen.TypeGenErr.fatal_error(arg, f"结构体 '{class_name}' 位置参数越界(无对应字段)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(arg, f"Struct '{class_name}': positional argument out of range (no matching field)", "TypeError")
|
||||
continue
|
||||
arg_val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, arg, None, 0, trans, fe.Ty)
|
||||
if arg_val is None: continue
|
||||
@@ -464,7 +464,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
|
||||
fe: GenTypes.FieldEntry* = self.Gen.StructGen.lookup_field_by_class(class_name, kw.arg, kw_sha1, kw, trans._from_imports)
|
||||
if fe is None:
|
||||
# keyword field missing: fail-fast (AttributeError), never skip silently
|
||||
self.Gen.TypeGenErr.fatal_error(kw, f"结构体 '{class_name}' 无字段 '{kw.arg}'", "AttributeError")
|
||||
self.Gen.TypeGenErr.fatal_error(kw, f"Struct '{class_name}' has no field '{kw.arg}'", "AttributeError")
|
||||
continue
|
||||
kw_val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, kw.value, None, 0, trans, fe.Ty)
|
||||
if kw_val is None: continue
|
||||
@@ -583,7 +583,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
|
||||
def _infer_generic_ctor_type_arg(self, pool: memhub.MemBuddy*, arg_node: ast.AST*, class_name: str, trans: HT.Translator*) -> str:
|
||||
"""Infer a generic type-arg name from a ctor arg AST (static AST only, no IR)"""
|
||||
if pool is None or arg_node is None:
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"无法从实参推断泛型类 '{class_name}' 的类型实参,请显式标注如 {class_name}[类型](...)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"Cannot infer the type argument of generic class '{class_name}' from the argument; annotate explicitly, e.g. {class_name}[Type](...)", "TypeError")
|
||||
return None
|
||||
k: int = arg_node.kind()
|
||||
# constant: 42->int, 3.14->double, "abc"->str, 'x'->char
|
||||
@@ -614,7 +614,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
|
||||
if ta_c is not None: return ta_c
|
||||
# A cast call whose callee does not resolve to a scalar type: fail-fast
|
||||
# (return None -> caller fail-fasts).
|
||||
self.Gen.TypeGenErr.fatal_error(arg_node, f"无法从实参推断泛型类 '{class_name}' 的类型实参,请显式标注如 {class_name}[类型](...)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(arg_node, f"Cannot infer the type argument of generic class '{class_name}' from the argument; annotate explicitly, e.g. {class_name}[Type](...)", "TypeError")
|
||||
return None
|
||||
# Plain variable (Name) arg: take the var's annotation class name (same source as
|
||||
# VarGen.set_var_annot_class_name). Lookup only (Spec.SourceName), no IR emitted.
|
||||
@@ -772,7 +772,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
|
||||
# find the struct entry to get the type
|
||||
struct_entry: GenTypes.StructEntry* = self.Gen.StructGen.find_struct(spec_name)
|
||||
if struct_entry is None:
|
||||
self.Gen.TypeGenErr.fatal_error(cl, "泛型类构造调用: 特化类未注册")
|
||||
self.Gen.TypeGenErr.fatal_error(cl, "Generic class ctor call: specialized class not registered")
|
||||
return None
|
||||
struct_ty: mlirlite.LLVMType* = struct_entry.Ty
|
||||
if struct_ty is None: return None
|
||||
@@ -805,7 +805,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
|
||||
for ai in range(can):
|
||||
if ai >= 32:
|
||||
# fixed 8*32 slots: writing past 32 args would corrupt adjacent pool blocks; fail-fast
|
||||
self.Gen.TypeGenErr.fatal_error(cl, "泛型构造实参超过 32 个上限", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(cl, "Generic construction arguments exceed the limit of 32", "TypeError")
|
||||
break
|
||||
arg_node: ast.AST* = cargs.get(ai)
|
||||
if arg_node is not None:
|
||||
@@ -822,12 +822,12 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
|
||||
if kw_slot is None or kw_slot.arg is None or kw_slot.value is None: continue
|
||||
slot_kw: int = self._ctor_init_arg_slot_by_name(tmpl_name, kw_slot.arg)
|
||||
if slot_kw >= 32:
|
||||
self.Gen.TypeGenErr.fatal_error(kw_slot, "泛型构造实参超过 32 个上限", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(kw_slot, "Generic construction arguments exceed the limit of 32", "TypeError")
|
||||
continue
|
||||
if slot_kw < 0:
|
||||
# fail-fast: the keyword name is not an __init__ param (or the template has no
|
||||
# __init__/name). Silent drop would pass misaligned args to __init__.
|
||||
self.Gen.TypeGenErr.fatal_error(kw_slot, f"泛型类 '{tmpl_name}' 的关键字实参 '{kw_slot.arg}' 无法定位到 __init__ 形参", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(kw_slot, f"Generic class '{tmpl_name}': keyword argument '{kw_slot.arg}' cannot be mapped to an __init__ parameter", "TypeError")
|
||||
continue
|
||||
if arg_filled[sizet(slot_kw)] != 0:
|
||||
# This param slot is already taken by a positional/earlier keyword arg:
|
||||
@@ -842,7 +842,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
|
||||
# got neither positional nor keyword arg. Never pass the hole as 0; fail-fast.
|
||||
for ci_hole in range(arg_max_filled + 1):
|
||||
if arg_filled[sizet(ci_hole)] == 0:
|
||||
self.Gen.TypeGenErr.fatal_error(cl, f"泛型类 '{tmpl_name}' 的关键字构造缺少前置形参(第 {ci_hole + 1} 个实参位置既无位置实参也无关键字实参)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(cl, f"Generic class '{tmpl_name}': keyword construction is missing preceding parameters (argument slot {ci_hole + 1} has neither positional nor keyword argument)", "TypeError")
|
||||
break
|
||||
arg_count: int = 0
|
||||
if arg_max_filled >= 0: arg_count = arg_max_filled + 1
|
||||
|
||||
@@ -86,7 +86,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
if explicit_slice is not None:
|
||||
type_args = self.Gen.CallGenCtor._extract_type_args_from_slice(pool, explicit_slice, trans._from_imports)
|
||||
if type_args is None or len(type_args) != tp_count:
|
||||
self.Gen.TypeGenErr.fatal_error(cl, f"泛型函数 '{tpl_name}' 显式类型实参个数不匹配(需要 {tp_count}):请写 {tpl_name}[类型1, 类型2](...)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(cl, f"Generic function '{tpl_name}': explicit type argument count mismatch (expected {tp_count}); write {tpl_name}[Type1, Type2](...)", "TypeError")
|
||||
return None
|
||||
else:
|
||||
# Implicit inference: align by the template signature's param annotated with T
|
||||
@@ -107,13 +107,13 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
if kwn is not None and kwn.value is not None: ta = self.Gen.ClassGenGeneric._infer_generic_func_type_arg(pool, kwn.value, tpl_name, trans)
|
||||
if ta is None and ctx_args is not None and sizet(tpi) < len(ctx_args): ta = ctx_args.get(tpi)
|
||||
if ta is None:
|
||||
self.Gen.TypeGenErr.fatal_error(cl, f"无法从实参推断泛型函数 '{tpl_name}' 的第 {tpi + 1} 个类型实参(类型形参 {tp_name});" f"禁止静默默认 int。请显式标注如 {tpl_name}[类型](...) 或为对应实参标注类型", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(cl, f"Cannot infer type argument {tpi + 1} of generic function '{tpl_name}' from the arguments (type parameter {tp_name});" f"silent default to int is forbidden. Annotate explicitly, e.g. {tpl_name}[Type](...), or annotate the corresponding argument", "TypeError")
|
||||
return None
|
||||
type_args.append(ta)
|
||||
# ---- Specialize ----
|
||||
spec_name: str = self.Gen.ClassGenGeneric._specialize_generic_function(trans, tpl_key, type_args)
|
||||
if spec_name is None:
|
||||
self.Gen.TypeGenErr.fatal_error(cl, f"泛型函数 '{tpl_name}' 特化失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(cl, f"Generic function '{tpl_name}': specialization failed", "TypeError")
|
||||
return None
|
||||
# ---- Emit call ----
|
||||
return self._emit_generic_func_call(pool, builder, mod, trans, cl, spec_name, cargs, can, hit_box)
|
||||
@@ -152,11 +152,11 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
"""Emit the specialized-function call, coercing args to the specialized param types."""
|
||||
func: mlirlite.Function* = self.Gen.CallGenBase.find_func_in_module(mod, spec_name)
|
||||
if func is None:
|
||||
self.Gen.TypeGenErr.fatal_error(cl, f"泛型函数特化符号未在当前模块注册: {spec_name}", "InternalCompilerError")
|
||||
self.Gen.TypeGenErr.fatal_error(cl, f"Generic function specialization symbol not registered in the current module: {spec_name}", "InternalCompilerError")
|
||||
return None
|
||||
kw: list[ast.AST*]* = cl.keywords
|
||||
if kw is not None and len(kw) > 0:
|
||||
self.Gen.TypeGenErr.fatal_error(cl, "泛型函数调用暂不支持关键字实参,请改用位置实参", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(cl, "Generic function calls do not support keyword arguments yet; use positional arguments", "TypeError")
|
||||
return None
|
||||
if hit_box is not None: hit_box[0] = 1
|
||||
param_count: int = 0
|
||||
@@ -165,7 +165,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
param_count += 1
|
||||
pp = mlirlite.param_get_next(pp)
|
||||
if int(can) < param_count:
|
||||
self.Gen.TypeGenErr.fatal_error(cl, "泛型函数调用实参个数少于形参个数(默认参数暂不支持),请补齐实参", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(cl, "Generic function call has fewer arguments than parameters (default parameters are not supported yet); supply the missing arguments", "TypeError")
|
||||
return None
|
||||
ret_ty: mlirlite.LLVMType* = mlirlite.function_get_ret_ty(func)
|
||||
head: mlirlite.Value* = None
|
||||
@@ -176,7 +176,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
fpty: mlirlite.LLVMType* = None
|
||||
if fp is not None: fpty = mlirlite.param_get_ty(fp)
|
||||
if arg is not None:
|
||||
av: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, arg, None, 0, trans, fpty, "形参")
|
||||
av: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, arg, None, 0, trans, fpty, "param")
|
||||
if av is not None:
|
||||
if fpty is not None: av = self.Gen.ExprGenBase.coerce_to_type(builder, av, fpty, arg, trans)
|
||||
av.Next = None
|
||||
@@ -726,10 +726,10 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
sz_val: int = self.Gen.ClassGenEnum._get_type_size(sz_resolved_ty)
|
||||
if sz_val > 0: return mlirlite.const_int64(pool, sz_val)
|
||||
# Type registered but size 0 (opaque struct or unfilled field list): fail with a Python-style error
|
||||
self.Gen.TypeGenErr.fatal_error(sz_at, f"类型 '{sz_resolved_name}' 已注册但大小为 0(字段链表未填充),无法计算大小", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(sz_at, f"Type '{sz_resolved_name}' is registered but its size is 0 (field list not filled); cannot compute size", "TypeError")
|
||||
# Type unregistered: fail with a Python-style error instead of returning 0 (would cause malloc(0)/alloc(0))
|
||||
if sz_resolved_name is None: sz_resolved_name = "(unknown)"
|
||||
self.Gen.TypeGenErr.fatal_error(sz_at, f"类型 '{sz_resolved_name}' 未在结构体表中注册,无法计算大小", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(sz_at, f"Type '{sz_resolved_name}' is not registered in the struct table; cannot compute size", "TypeError")
|
||||
|
||||
# Detect len(obj) on a list object: return its __count__ field (offset 8, i64). __len__ is a
|
||||
# builtin of list[T]. Use translate_value, since len_at.value may be an Attribute (not a Name).
|
||||
@@ -743,7 +743,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
# i32 (misparsed CDefine constant, module-attr fallback), llc reports a non-pointer GEP base.
|
||||
if self.Gen.ExprGenBase.is_ptr_type(obj_val.Ty) == 0:
|
||||
# Type inference failed (not a pointer/struct): fail fast rather than return 0
|
||||
self.Gen.TypeGenErr.fatal_error(len_at.value, "len() 参数类型推断失败(非指针/结构体)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(len_at.value, "len() argument type inference failed (not a pointer/struct)", "TypeError")
|
||||
i64_ty_len: mlirlite.LLVMType* = mlirlite.Int64(pool)
|
||||
# Must use const_int64, not ConstInt(...,"0"): ConstInt's name is emitted as IR text,
|
||||
# so GEP would index 0 (__data__) instead of 1 (__count__).
|
||||
@@ -786,7 +786,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
len_struct_ty: mlirlite.LLVMType* = self.Gen.StructGen.get_struct_type_from_value(len_val)
|
||||
if len_struct_ty is not None:
|
||||
len_cls_nm: str = self.Gen.StructGen.get_class_name_by_type(pool, len_struct_ty)
|
||||
if len_cls_nm is None: self.Gen.TypeGenErr.fatal_error(len_arg_node, "len() 参数类型推断失败(结构体类名未知)", "TypeError")
|
||||
if len_cls_nm is None: self.Gen.TypeGenErr.fatal_error(len_arg_node, "len() argument type inference failed (unknown struct class name)", "TypeError")
|
||||
# list builtin __len__: read __count__ (GEP offset 1, i64). Narrow len_arg_node
|
||||
# to ast.Call* explicitly, since passing a base pointer to a derived param is banned.
|
||||
len_arg_cl: ast.Call* = ast.Call*(len_arg_node)
|
||||
@@ -832,7 +832,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
return mlirlite.build_call(builder, len_mangled_x, len_self_x, 1, len_ret_x, 0)
|
||||
# fail-fast: the class has no __len__ (compile-time error, matching TPC
|
||||
# HandlesExprBuiltin._FailFastLenUnsupported wording).
|
||||
self.Gen.TypeGenErr.fatal_error(len_arg_node, f"len() 参数类型 '{len_cls_nm}' 没有 __len__ 方法。len() 只支持定长数组/数组指针(t.CArray[T, N])、i8*(str/bytes)或带 __len__ 的结构体;非 i8 裸指针/标量指针没有长度语义:字符串请用 str/bytes,需要元素个数请自行记录长度,或改用 t.CPtr[元素] 并显式维护元素计数", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(len_arg_node, f"len() argument type '{len_cls_nm}' has no __len__ method. len() only supports fixed-size arrays/array pointers (t.CArray[T, N]), i8* (str/bytes), or structs with __len__; non-i8 bare pointers/scalar pointers have no length semantics: use str/bytes for strings, record the length yourself when the element count is needed, or use t.CPtr[Element] and maintain the element count explicitly", "TypeError")
|
||||
# Non-struct: str (Ptr(Int8)) uses strlen; other types fail fast
|
||||
len_arg_ty: mlirlite.LLVMType* = mlirlite.value_get_ty(len_val)
|
||||
len_is_str: int = 0
|
||||
@@ -865,7 +865,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
return mlirlite.build_call(builder, "strlen", len_coerced, 1, i64_ty_ln2, 0)
|
||||
# fail-fast: not a string/array/object, so length is unavailable (matching TPC
|
||||
# HandlesExprBuiltin._FailFastLenUnsupported wording).
|
||||
self.Gen.TypeGenErr.fatal_error(len_arg_node, "len() 参数类型不支持(非字符串/数组/对象)。len() 只支持定长数组/数组指针(t.CArray[T, N])、i8*(str/bytes)或带 __len__ 的结构体;非 i8 裸指针/标量指针没有长度语义:字符串请用 str/bytes,需要元素个数请自行记录长度,或改用 t.CPtr[元素] 并显式维护元素计数", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(len_arg_node, "len() argument type not supported (not a string/array/object). len() only supports fixed-size arrays/array pointers (t.CArray[T, N]), i8* (str/bytes), or structs with __len__; non-i8 bare pointers/scalar pointers have no length semantics: use str/bytes for strings, record the length yourself when the element count is needed, or use t.CPtr[Element] and maintain the element count explicitly", "TypeError")
|
||||
|
||||
# Detect isinstance(): runtime vtable subclass-set comparison. obj's head vtable pointer must
|
||||
# be in {Cls and all subclass vtables}; NoVTable targets fall back to a compile-time check.
|
||||
@@ -988,7 +988,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
if rk_val is None:
|
||||
# fail-fast: REnum was determined but the one-level load of a double pointer
|
||||
# produced no value; never skip silently, or .kind() falls into the generic call path.
|
||||
self.Gen.TypeGenErr.fatal_error(cl, f"REnum.kind() 翻译失败:接收者已判定为 REnum(变体表/__tag 判据命中)," f"但接收者指针解一层 load 失败(rk_load={rk_load})", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(cl, f"REnum.kind() translation failed: the receiver was determined to be a REnum (variant table/__tag criterion hit), " f"but loading one level from the receiver pointer failed (rk_load={rk_load})", "TypeError")
|
||||
if hit_box is not None: hit_box[0] = 1
|
||||
# Layer 2: address and load using __tag's field declaration type, no hardcoded i32.
|
||||
# Width coercion is left to coerce_to_type on the assignment side.
|
||||
@@ -1359,7 +1359,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
if lm_obj.Ty is None or self.Gen.ExprGenBase.is_ptr_type(lm_obj.Ty) == 0:
|
||||
# translate_value type inference failed (target is not a pointer): fail fast,
|
||||
# never swallow it silently.
|
||||
self.Gen.TypeGenErr.fatal_error(lm_at.value, f"list 方法 '{lm_name}' 目标对象非指针", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(lm_at.value, f"list method '{lm_name}': target object is not a pointer", "TypeError")
|
||||
# Confirm the object really is a list (the branch matches by method name only, and
|
||||
# get/set are not list-specific); skip otherwise to avoid wrong GEP offsets.
|
||||
lm_conf_ty: mlirlite.LLVMType* = self.Gen.StructGen.get_struct_type_from_value(lm_obj)
|
||||
@@ -1471,7 +1471,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
if ap_sha1 is None:
|
||||
# Dependency module not compiled (_list not in the chain): fail fast, never
|
||||
# silently skip append (elements would never be added).
|
||||
self.Gen.TypeGenErr.fatal_error(cl, "list.append: 找不到 _list 模块 SHA1(依赖模块未编译)", "InternalCompilerError")
|
||||
self.Gen.TypeGenErr.fatal_error(cl, "list.append: _list module SHA1 not found (dependency module not compiled)", "InternalCompilerError")
|
||||
if ap_sha1 is not None:
|
||||
# The append symbol is {sha1}.list[AST*].append (specialized name), not
|
||||
# {sha1}.list.append; derive the specialized name from lm_obj's type.
|
||||
|
||||
@@ -203,11 +203,11 @@ novirtual class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
|
||||
"""isinstance(obj, Cls): runtime vtable subclass-set comparison; returns i1"""
|
||||
if obj_node is None or cls_node is None:
|
||||
# missing args is a call error: fail fast, never hide it by returning True
|
||||
self.Gen.TypeGenErr.fatal_error(cls_node, "isinstance() 参数类型推断失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(cls_node, "isinstance() argument type inference failed", "TypeError")
|
||||
obj_val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, obj_node, None, 0, trans)
|
||||
if obj_val is None or obj_val.Ty is None:
|
||||
# obj type inference failed: fail fast, never hide it by returning True
|
||||
self.Gen.TypeGenErr.fatal_error(cls_node, "isinstance() 参数类型推断失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(cls_node, "isinstance() argument type inference failed", "TypeError")
|
||||
# normalize the object pointer: load through a pointer-to-pointer (var alloca / Class*)
|
||||
obj_ptr: mlirlite.Value* = obj_val
|
||||
match obj_val.Ty:
|
||||
@@ -229,7 +229,7 @@ novirtual class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
|
||||
cls_names: sizet* = self._extract_isinstance_class_names(pool, cls_node)
|
||||
if cls_names is None:
|
||||
# class-name extraction failed: fail fast, never hide it by returning True
|
||||
self.Gen.TypeGenErr.fatal_error(cls_node, "isinstance() 参数类型推断失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(cls_node, "isinstance() argument type inference failed", "TypeError")
|
||||
ci: int = 0
|
||||
while cls_names[ci] != 0:
|
||||
cn: str = rawptr(cls_names[ci])
|
||||
@@ -263,7 +263,7 @@ novirtual class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
|
||||
ci += 1
|
||||
if res is None:
|
||||
# no comparison produced (obj non-pointer, all classes CVTable): fail fast
|
||||
self.Gen.TypeGenErr.fatal_error(cls_node, "isinstance() 参数类型推断失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(cls_node, "isinstance() argument type inference failed", "TypeError")
|
||||
return res
|
||||
|
||||
|
||||
@@ -542,16 +542,16 @@ novirtual class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
|
||||
if typed_buf[0] != '\0': ret_str = typed_buf
|
||||
msg_buf: str = pool.alloc(1024)
|
||||
if msg_buf is not None:
|
||||
viperlib.snprintf(msg_buf, 1024, "函数指针签名表登记失败:变量 '%s'(返回类型 %s)——%s。" "当前上限 MAX_FUNC_PTR_SIGS=%d,已登记 %d 条。" "同名同返回类型的重复登记已做原地命中、不占新槽位;" "若确实需要更多函数指针变量,请上调 CallGenBase.vp 的 " "MAX_FUNC_PTR_SIGS(全仓唯一来源,改此一处即全仓生效)", name, ret_str, reason, cap, self.FuncptrCount)
|
||||
viperlib.snprintf(msg_buf, 1024, "Function pointer signature table registration failed: variable '%s' (return type %s) -- %s. " "Current limit MAX_FUNC_PTR_SIGS=%d, %d entries registered. " "Duplicate registration with the same name and return type hits in place and does not occupy a new slot; " "if more function pointer variables are really needed, raise the " "MAX_FUNC_PTR_SIGS (the single repo-wide source; changing this one place takes effect everywhere)", name, ret_str, reason, cap, self.FuncptrCount)
|
||||
self.Gen.TypeGenErr.fatal_error(node, msg_buf, "TypeError")
|
||||
return
|
||||
self.Gen.TypeGenErr.fatal_error(node, "函数指针签名表登记失败(签名表已满或变量名冲突)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, "Function pointer signature table registration failed (table full or variable name conflict)", "TypeError")
|
||||
|
||||
def register_func_ptr_sig(self, pool: memhub.MemBuddy*, name: str, ret_ty: mlirlite.LLVMType*, node: ast.AST* = None) -> int:
|
||||
"""Register a function-pointer variable's return type; 0 = success, 1 = failed (already reported)"""
|
||||
if name is None or ret_ty is None: return 1
|
||||
if self._ensure_funcptr_sigs() == 0:
|
||||
self._func_ptr_sig_fatal(pool, node, name, ret_ty, "签名表分配失败(PermPool 内存不足)")
|
||||
self._func_ptr_sig_fatal(pool, node, name, ret_ty, "Signature table allocation failed (PermPool out of memory)")
|
||||
return 1
|
||||
# idempotence/conflict check: linear scan of registered bare names (cap 64, cheap)
|
||||
i: sizet
|
||||
@@ -560,10 +560,10 @@ novirtual class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
|
||||
if string.strcmp(self.FuncptrNames + idx_hit, name) == 0:
|
||||
prev_ret: mlirlite.LLVMType* = (mlirlite.LLVMType*)(self.FuncptrRets[i])
|
||||
if prev_ret is not None and self.Gen.AssignGen._stg_ty_equal(pool, prev_ret, ret_ty) != 0: return 0
|
||||
self._func_ptr_sig_fatal(pool, node, name, ret_ty, "该名字已按另一种返回类型登记过")
|
||||
self._func_ptr_sig_fatal(pool, node, name, ret_ty, "This name is already registered with a different return type")
|
||||
return 1
|
||||
if self.FuncptrCount >= CallGenBase.MAX_FUNC_PTR_SIGS:
|
||||
self._func_ptr_sig_fatal(pool, node, name, ret_ty, "签名表已满")
|
||||
self._func_ptr_sig_fatal(pool, node, name, ret_ty, "Signature table is full")
|
||||
return 1
|
||||
idx: sizet = sizet(self.FuncptrCount) * 64
|
||||
# slot is 64 bytes fixed; use strncpy clamping like register_closure_name
|
||||
@@ -616,7 +616,7 @@ novirtual class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
|
||||
# 3. build the signature from arg types + registered ret type (missing = fail fast)
|
||||
ret_ty: mlirlite.LLVMType* = self.lookup_func_ptr_ret(func_name)
|
||||
if ret_ty is None:
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"函数指针变量 '{func_name}' 的返回类型未注册(t.Callable 注解缺失)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"Return type of function pointer variable '{func_name}' is not registered (t.Callable annotation missing)", "TypeError")
|
||||
ret_ty = i32_ty
|
||||
fp_first: mlirlite.ParamNode* = None
|
||||
fp_prev: mlirlite.ParamNode* = None
|
||||
@@ -715,8 +715,8 @@ novirtual class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
|
||||
if arg_val is None or arg_val.Ty is None:
|
||||
# fail fast: a failed print-arg translation must abort, never write a
|
||||
# misleading format string that hides a compiler bug as a data problem.
|
||||
VLogger.error(f"print 参数翻译失败(表达式返回 None): [arg={ai}]", "PRINT")
|
||||
self.Gen.TypeGenErr.fatal_error(arg, "print 参数翻译失败(表达式返回 None)", "TypeError")
|
||||
VLogger.error(f"print argument translation failed (expression returned None): [arg={ai}]", "PRINT")
|
||||
self.Gen.TypeGenErr.fatal_error(arg, "print argument translation failed (expression returned None)", "TypeError")
|
||||
return
|
||||
|
||||
# object defines __str__ -> print its i8* return via %s (TPC-aligned)
|
||||
|
||||
@@ -383,7 +383,7 @@ novirtual class CallGenLib(CallGenBase.CallGenBase):
|
||||
return mlirlite.Ptr(pool, mlirlite.Int8(pool))
|
||||
|
||||
# Default i32 placeholder: fatal_if_unknown=1 fails fast; =0 (Phase A mid-pass) stays silent.
|
||||
if fatal_if_unknown != 0: self.Gen.TypeGenErr.fatal_error(node, f"外部函数返回类型未登记且无法收敛推断(默认 i32 会截断指针/i64,需提供 stub 声明或加入白名单): {func_name}", "TypeError")
|
||||
if fatal_if_unknown != 0: self.Gen.TypeGenErr.fatal_error(node, f"external function return type is unregistered and cannot be inferred conclusively (defaulting to i32 would truncate pointers/i64; provide a stub declaration or add it to the whitelist): {func_name}", "TypeError")
|
||||
return mlirlite.Int32(pool)
|
||||
def _get_external_func_param_ty(self, pool: memhub.MemBuddy*, func_name: str, param_idx: int) -> mlirlite.LLVMType*:
|
||||
"""Return the expected type of an external function's param_idx-th parameter, or None (fallback only)"""
|
||||
@@ -552,7 +552,7 @@ novirtual class CallGenLib(CallGenBase.CallGenBase):
|
||||
if arg_val is None:
|
||||
kw_node: ast.AST* = None
|
||||
if keywords is not None and kw_count > 0: kw_node = keywords.get(0)
|
||||
self.Gen.TypeGenErr.fatal_error(kw_node, f"调用 '{func_name}' 的某个形参既未按位置/关键字传入," f"定义处也无默认值可填充(拒绝静默漏参/填零)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(kw_node, f"a parameter of call '{func_name}' is passed neither positionally nor by keyword, " f"and the definition has no default value to fill in (refusing to silently drop/zero a parameter)", "TypeError")
|
||||
|
||||
if arg_val is not None:
|
||||
# Coerce by parameter type (via accessor)
|
||||
|
||||
@@ -56,7 +56,7 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
if sc_sha1 is None: return 0
|
||||
if string.strncmp(sc_sha1, trans.ModuleSha1, 16) == 0: return 0
|
||||
if self.Gen.CallGenBase.IsStaticSymbol(sc_sha1, sc_at.attr) == 0: return 0
|
||||
self.Gen.TypeGenErr.fatal_error(cl, f"'{sc_mod}.{sc_at.attr}' 是 static 符号,禁止跨模块使用(static 仅限定义模块内可见)", "NameError")
|
||||
self.Gen.TypeGenErr.fatal_error(cl, f"'{sc_mod}.{sc_at.attr}' is a static symbol; cross-module use is forbidden (static is visible only inside its defining module)", "NameError")
|
||||
return 0
|
||||
|
||||
|
||||
@@ -135,9 +135,9 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
# Generic class template not found: the defining module may not be imported.
|
||||
gt_err: str = pool.alloc(256)
|
||||
if gt_err is not None:
|
||||
viperlib.snprintf(gt_err, 256, "泛型类 '%s' 未找到模板,可能未 import 定义模块", gen_class_name)
|
||||
viperlib.snprintf(gt_err, 256, "Generic class '%s': template not found; the defining module may not be imported", gen_class_name)
|
||||
self.Gen.TypeGenErr.fatal_error(gen_nm_node, gt_err)
|
||||
self.Gen.TypeGenErr.fatal_error(gen_nm_node, "泛型类模板未找到")
|
||||
self.Gen.TypeGenErr.fatal_error(gen_nm_node, "Generic class template not found")
|
||||
if func_name is None:
|
||||
# BinOp as the Call func: a union-type annotation used as a type cast, (A*)(value).
|
||||
if cl.func is not None and cl.func.kind() == ast.ASTKind.BinOp and trans is not None:
|
||||
@@ -339,7 +339,7 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
# [C1] The annotation already gives type args (e.g. s: Stack[int] = Stack()): specialize with them.
|
||||
ta_bare = ctx_args_bare.get(tpi_bare)
|
||||
if ta_bare is None:
|
||||
self.Gen.TypeGenErr.fatal_error(cl, f"无法从实参推断泛型类 '{func_name}' 的第 {tpi_bare + 1} 个类型实参," f"禁止静默默认 int(会产生 list[int] 等错误特化 → 元素按 4 字节/i32 处理 → 指针截断崩溃);" f"请为该实参标注类型或显式标注如 {func_name}[类型](...)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(cl, f"Cannot infer type argument {tpi_bare + 1} of generic class '{func_name}' from the arguments, " f"silent default to int is forbidden (it produces wrong specializations such as list[int] -> elements treated as 4 bytes/i32 -> pointer truncation crash); " f"annotate the argument type or annotate explicitly, e.g. {func_name}[Type](...)", "TypeError")
|
||||
inferred_args_bare.append(ta_bare)
|
||||
spec_name_bare: str = self.Gen.ClassGenGeneric._specialize_generic_class(trans, func_name, inferred_args_bare)
|
||||
if spec_name_bare is not None: return self.Gen.CallGenCtor._translate_generic_ctor_call(pool, builder, mod, spec_name_bare, cl, trans, func_name)
|
||||
@@ -359,7 +359,7 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
rc_tag: int = self.Gen.ClassGenEnum._lookup_renum_variant_in_class(rc_cls_name, func_name)
|
||||
if rc_tag < 0:
|
||||
# [D32 fail-fast] It is an REnum but the variant is missing: the table is incomplete; report it here.
|
||||
self.Gen.TypeGenErr.fatal_error(cl, f"REnum 类 '{rc_cls_name}' 的变体 '{func_name}' 未在变体表中找到" f"({self.Gen.ClassGenEnum.RenumTableDump()});" f"变体表未注册或变体名不匹配", "NameError")
|
||||
self.Gen.TypeGenErr.fatal_error(cl, f"REnum class '{rc_cls_name}': variant '{func_name}' not found in the variant table" f" ({self.Gen.ClassGenEnum.RenumTableDump()}); " f"the variant table is not registered or the variant name does not match", "NameError")
|
||||
if rc_tag >= 0: return self.Gen.CallGenCtor._translate_renum_construct(pool, builder, mod, rc_cls_name, func_name, rc_tag, cargs, can, trans, cl.IsVolatile)
|
||||
elif rc_at.value is not None and rc_at.value.kind() == ast.ASTKind.Attribute:
|
||||
# Module-qualified REnum variant: mod.Class.Variant(args...), e.g. mlirlite.LLVMType.Struct(...).
|
||||
@@ -758,7 +758,7 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
fp = mlirlite.param_get_next(fp)
|
||||
fpi += 1
|
||||
if fp is not None: fpty = mlirlite.param_get_ty(fp)
|
||||
arg_val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, arg, None, 0, trans, fpty, "形参")
|
||||
arg_val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, arg, None, 0, trans, fpty, "param")
|
||||
if arg_val is not None:
|
||||
# Arg promotion: when found_func is None (stub not injected), infer the expected type from
|
||||
# the external signature and promote literals (e.g. i32->i64) to avoid declare/call mismatches.
|
||||
@@ -978,9 +978,9 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
if is_xmod_imported == 0:
|
||||
err_ni: str = pool.alloc(256)
|
||||
if err_ni is not None:
|
||||
viperlib.snprintf(err_ni, 256, "跨模块调用 '%s.%s':模块 '%s' 未导入(请先 import %s)", xmod_path, func_name, xmod_path, xmod_path)
|
||||
viperlib.snprintf(err_ni, 256, "Cross-module call '%s.%s': module '%s' not imported (import %s first)", xmod_path, func_name, xmod_path, xmod_path)
|
||||
self.Gen.TypeGenErr.fatal_error(xmod_at, err_ni)
|
||||
self.Gen.TypeGenErr.fatal_error(xmod_at, "跨模块调用:模块未导入")
|
||||
self.Gen.TypeGenErr.fatal_error(xmod_at, "Cross-module call: module not imported")
|
||||
# Check whether it is a re-export function (e.g. ast._lexer_init actually defined in ast.lexer).
|
||||
reexport_src: str = self.Gen.ImportsGen.lookup_reexport(mod_sha1, func_name)
|
||||
if reexport_src is None:
|
||||
@@ -1069,9 +1069,9 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
# Imported module but SHA1 unregistered: the module was not compiled, so error out immediately.
|
||||
err_msg_imp: str = pool.alloc(256)
|
||||
if err_msg_imp is not None:
|
||||
viperlib.snprintf(err_msg_imp, 256, "模块 '%s' 已导入但 SHA1 未注册(该模块未被编译)", xmod_path)
|
||||
viperlib.snprintf(err_msg_imp, 256, "Module '%s' is imported but its SHA1 is not registered (the module was not compiled)", xmod_path)
|
||||
self.Gen.TypeGenErr.fatal_error(xmod_at, err_msg_imp)
|
||||
self.Gen.TypeGenErr.fatal_error(xmod_at, "已导入模块 SHA1 未注册")
|
||||
self.Gen.TypeGenErr.fatal_error(xmod_at, "Imported module SHA1 not registered")
|
||||
else:
|
||||
# Check whether it is a from-import name (e.g. from .__types import LLVMType): LLVMType is a
|
||||
# class, not a module, but Ptr is a module-level function of __types; disable star-import fallback.
|
||||
@@ -1089,9 +1089,9 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
else:
|
||||
err_msg2: str = pool.alloc(256)
|
||||
if err_msg2 is not None:
|
||||
viperlib.snprintf(err_msg2, 256, "跨模块调用 '%s.%s' 找不到模块 SHA1", xmod_path, func_name)
|
||||
viperlib.snprintf(err_msg2, 256, "Cross-module call '%s.%s': module SHA1 not found", xmod_path, func_name)
|
||||
self.Gen.TypeGenErr.fatal_error(xmod_at, err_msg2)
|
||||
self.Gen.TypeGenErr.fatal_error(xmod_at, "跨模块调用找不到模块 SHA1")
|
||||
self.Gen.TypeGenErr.fatal_error(xmod_at, "Cross-module call: module SHA1 not found")
|
||||
else:
|
||||
# Bare-name call (not Attribute): check from_imports. Star-import fallback is disabled for calls
|
||||
# (star import is for types/constants); a missed function then fails fast at compile time instead of linking wrong.
|
||||
@@ -1134,15 +1134,15 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
else:
|
||||
err_msg3: str = pool.alloc(256)
|
||||
if err_msg3 is not None:
|
||||
viperlib.snprintf(err_msg3, 256, "裸名调用 '%s' 未定义且未导入", func_name)
|
||||
viperlib.snprintf(err_msg3, 256, "Bare-name call '%s' is undefined and not imported", func_name)
|
||||
self.Gen.TypeGenErr.fatal_error(node, err_msg3)
|
||||
self.Gen.TypeGenErr.fatal_error(node, "裸名调用未定义且未导入")
|
||||
self.Gen.TypeGenErr.fatal_error(node, "Bare-name call undefined and not imported")
|
||||
else:
|
||||
err_msg4: str = pool.alloc(256)
|
||||
if err_msg4 is not None:
|
||||
viperlib.snprintf(err_msg4, 256, "裸名调用 '%s' 未定义且未导入", func_name)
|
||||
viperlib.snprintf(err_msg4, 256, "Bare-name call '%s' is undefined and not imported", func_name)
|
||||
self.Gen.TypeGenErr.fatal_error(node, err_msg4)
|
||||
self.Gen.TypeGenErr.fatal_error(node, "裸名调用未定义且未导入")
|
||||
self.Gen.TypeGenErr.fatal_error(node, "Bare-name call undefined and not imported")
|
||||
|
||||
# Direct call. memcpy -> @llvm.memcpy intrinsic (avoids a missing cross-module @memcpy declaration during monomorphization).
|
||||
if string.strcmp(func_name, "memcpy") == 0 and can >= 3: return self.Gen.CallGenLib._emit_llvm_memcpy_intrinsic(pool, builder, mod, mc_dst2, mc_src2, mc_num2)
|
||||
@@ -1184,7 +1184,7 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
else:
|
||||
# Dependency text.ll does not exist (module not yet translated): Phase A translates files
|
||||
# in order (main.vp before its imported mbuddytest.vp), so keep the default type without fail-fast.
|
||||
if self._dep_text_ll_exists(pool, cf_sha1) != 0: self.Gen.TypeGenErr.fatal_error(node, f"跨模块函数返回类型无法精确获取(vpi/text.ll 均未命中),默认 i32 会截断指针: {call_name}", "TypeError")
|
||||
if self._dep_text_ll_exists(pool, cf_sha1) != 0: self.Gen.TypeGenErr.fatal_error(node, f"Cannot obtain the cross-module function return type precisely (neither vpi nor text.ll hit); the default i32 will truncate pointers: {call_name}", "TypeError")
|
||||
stdlib.free(cf_sha1)
|
||||
stdlib.free(cf_bare)
|
||||
# Bare C library function (string.memset -> @memset): promote args to the standard signature
|
||||
|
||||
@@ -282,7 +282,7 @@ novirtual class CallGenProp(CallGenBase.CallGenBase):
|
||||
if self.Gen.ClassGenGeneric._find_generic_template(base_nm) is None: return None
|
||||
if lb is not None: return short_nm
|
||||
# Bare generic base (no type args): element type unknown -> fail-fast (D25)
|
||||
self.Gen.TypeGenErr.fatal_error(cl, f"方法 '{method_name}' 的接收者实际结构体类型是裸泛型基类 " f"'{short_nm}*'(丢失类型实参),元素类型未知;" f"禁止静默按默认元素类型处理(元素按 i32 处理会截断指针)," f"请让该变量的注解/类型带上实参(如 list[ast.AST*])", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(cl, f"the actual struct type of the receiver of method '{method_name}' is a bare generic base " f"'{short_nm}*' (type arguments lost), so the element type is unknown; " f"silently using the default element type is forbidden (treating elements as i32 would truncate pointers); " f"make the variable annotation/type carry type arguments (e.g. list[ast.AST*])", "TypeError")
|
||||
return None
|
||||
|
||||
# _is_list_builtin_receiver - test list builtin methods from the receiver's actual type.
|
||||
|
||||
@@ -35,7 +35,7 @@ novirtual class CallGenVa(CallGenBase.CallGenBase):
|
||||
resolved: mlirlite.LLVMType* = self.Gen.TypeGenResolve.resolve_annotation_type(pool, type_node, trans._imported_modules, trans._from_imports, trans, 0)
|
||||
if resolved is not None: return resolved
|
||||
# Type node present but unresolvable: fail-fast, never fall back to i32 (would read the vararg slot at the wrong width)
|
||||
self.Gen.TypeGenErr.fatal_error(type_node, "va_arg 类型解析失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(type_node, "va_arg type resolution failed", "TypeError")
|
||||
return mlirlite.Int32(pool)
|
||||
def _translate_va_arg_sugar(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cl: ast.Call*, cargs: list[ast.AST*]*, can: sizet, funcs_ptr: t.CPtr, func_count: int, trans: HT.Translator*) -> mlirlite.Value*:
|
||||
"""Emit a va_arg instruction reading the next variadic argument from the va_list."""
|
||||
|
||||
@@ -31,8 +31,8 @@ novirtual class ClassGenDef(ClassGenBase.ClassGenBase):
|
||||
|
||||
if trans.ModuleSha1 is None:
|
||||
# fail-fast: ModuleSha1 missing while translating a class (namespace isolation depends on it)
|
||||
VLogger.error("翻译类时 ModuleSha1 缺失", "CLASS")
|
||||
self.Gen.TypeGenErr.fatal_error(cd, "翻译类时 ModuleSha1 缺失", "TypeError")
|
||||
VLogger.error("ModuleSha1 missing while translating a class", "CLASS")
|
||||
self.Gen.TypeGenErr.fatal_error(cd, "ModuleSha1 missing while translating a class", "TypeError")
|
||||
|
||||
# Namespace isolation: mark as visible in the current file. Must precede
|
||||
# the existing check, or Phase B's early return would never mark it.
|
||||
@@ -45,7 +45,7 @@ novirtual class ClassGenDef(ClassGenBase.ClassGenBase):
|
||||
# takes priority over CEnum/CUnion, whose semantics are mutually exclusive.
|
||||
if self.Gen.ClassGenBase._is_enum_class(cd, trans) == 1:
|
||||
if self.Gen.ClassGenBase._is_renum_class(cd, trans) == 1:
|
||||
self.Gen.TypeGenErr.fatal_error(cd, f"类 '{class_name}' 同时被判定为 CEnum 与 REnum(分派歧义)," f"REnum 变体表将无法注册", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(cd, f"class '{class_name}' is classified as both CEnum and REnum (dispatch ambiguity), " f"the REnum variant table cannot be registered", "TypeError")
|
||||
return self.Gen.ClassGenEnum._translate_enum_def(trans, cd)
|
||||
|
||||
# Union class: handled by the union path
|
||||
@@ -275,7 +275,7 @@ novirtual class ClassGenDef(ClassGenBase.ClassGenBase):
|
||||
field_ty: mlirlite.LLVMType* = self.Gen.TypeGenResolve.resolve_annotation_type(pool, aa.annotation, trans._imported_modules, trans._from_imports, trans, 0)
|
||||
# void is not a valid field type (only for `void*` and opaque typedefs); letting
|
||||
# it through builds an illegal layout, so fail-fast at compile time here.
|
||||
if field_ty is not None and self.Gen.StmtGenDecl._is_void_type(field_ty) != 0: self.Gen.TypeGenErr.fatal_error(aa, f"字段 '{tgt.id}' 不能是 void 类型(void 只能用于 void* 与 typedef 别名)", "TypeError")
|
||||
if field_ty is not None and self.Gen.StmtGenDecl._is_void_type(field_ty) != 0: self.Gen.TypeGenErr.fatal_error(aa, f"field '{tgt.id}' cannot be void type (void is only allowed for void* and typedef aliases)", "TypeError")
|
||||
# Single-arg t.CArray[elem] with a list literal -> static array [N x elem] (like
|
||||
# local AnnAssign); otherwise it stays Ptr(elem) and for-in iterates pointers wrongly.
|
||||
if field_ty is not None: field_ty = self.Gen.AssignGen._infer_static_array_ty_from_literal(pool, aa.annotation, aa.value, field_ty)
|
||||
|
||||
@@ -36,7 +36,7 @@ novirtual class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
at: ast.Attribute* = ast.Attribute*(ann_node)
|
||||
if at.attr is None:
|
||||
# [S4 fail-fast] Attribute missing the member name (corrupt AST); no silent i32 fallback
|
||||
self.Gen.TypeGenErr.fatal_error(ann_node, "枚举成员类型注解 Attribute 缺失成员名", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(ann_node, "enum member type annotation Attribute is missing the member name", "TypeError")
|
||||
return mlirlite.Int32(pool) # unreachable (fatal_error already exited)
|
||||
# t.State -> default i32
|
||||
if string.strcmp(at.attr, "State") == 0: return mlirlite.Int32(pool)
|
||||
@@ -47,7 +47,7 @@ novirtual class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
ty: mlirlite.LLVMType* = self.Gen.TypeGenResolve.resolve_typedef_or_map(pool, at.attr, imported_modules, from_imports)
|
||||
if ty is not None: return ty
|
||||
# [S4 fail-fast] annotated but unresolvable -> no silent i32 fallback
|
||||
self.Gen.TypeGenErr.fatal_error(ann_node, f"枚举成员类型注解解析失败: t.{at.attr}", "NameError")
|
||||
self.Gen.TypeGenErr.fatal_error(ann_node, f"failed to resolve enum member type annotation: t.{at.attr}", "NameError")
|
||||
return mlirlite.Int32(pool) # unreachable (fatal_error already exited)
|
||||
|
||||
# Name node: from-import form (State / CInt)
|
||||
@@ -55,7 +55,7 @@ novirtual class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
nm: ast.Name* = ast.Name*(ann_node)
|
||||
if nm.id is None:
|
||||
# [S4 fail-fast] Name missing the identifier (corrupt AST); no silent i32 fallback
|
||||
self.Gen.TypeGenErr.fatal_error(ann_node, "枚举成员类型注解 Name 缺失标识符", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(ann_node, "enum member type annotation Name is missing the identifier", "TypeError")
|
||||
return mlirlite.Int32(pool) # unreachable (fatal_error already exited)
|
||||
if string.strcmp(nm.id, "State") == 0: return mlirlite.Int32(pool)
|
||||
# Builtin bare integer types (same rule as resolve_annotation_type's Name branch): enum members are
|
||||
@@ -69,7 +69,7 @@ novirtual class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
ty2: mlirlite.LLVMType* = self.Gen.TypeGenResolve.resolve_typedef_or_map(pool, nm.id, imported_modules, from_imports)
|
||||
if ty2 is not None: return ty2
|
||||
# [S4 fail-fast] annotated but unresolvable -> no silent i32 fallback
|
||||
self.Gen.TypeGenErr.fatal_error(ann_node, f"枚举成员类型注解解析失败: {nm.id}", "NameError")
|
||||
self.Gen.TypeGenErr.fatal_error(ann_node, f"failed to resolve enum member type annotation: {nm.id}", "NameError")
|
||||
return mlirlite.Int32(pool) # unreachable (fatal_error already exited)
|
||||
|
||||
# BinOp node: t.State | int8 (recurse to find the concrete type)
|
||||
@@ -87,11 +87,11 @@ novirtual class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
if left_bits >= right_bits: return left_ty
|
||||
return right_ty
|
||||
# fail-fast: BinOp but not BitOr (unknown union op); no silent i32 fallback
|
||||
self.Gen.TypeGenErr.fatal_error(ann_node, f"枚举成员类型注解解析失败: {self.Gen.TypeGenResolve.annotation_to_str(ann_node)}", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(ann_node, f"failed to resolve enum member type annotation: {self.Gen.TypeGenResolve.annotation_to_str(ann_node)}", "TypeError")
|
||||
return mlirlite.Int32(pool) # unreachable (fatal_error already exited)
|
||||
|
||||
# fail-fast: unknown annotation node kind; no silent i32 fallback
|
||||
self.Gen.TypeGenErr.fatal_error(ann_node, f"枚举成员类型注解解析失败: {self.Gen.TypeGenResolve.annotation_to_str(ann_node)}", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(ann_node, f"failed to resolve enum member type annotation: {self.Gen.TypeGenResolve.annotation_to_str(ann_node)}", "TypeError")
|
||||
return mlirlite.Int32(pool) # unreachable (fatal_error already exited)
|
||||
def _is_state_annotation(self, node: ast.AST*) -> int:
|
||||
"""Check whether an annotation node is t.State, 1=yes / 0=no"""
|
||||
@@ -268,7 +268,7 @@ novirtual class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
# [enum spec fail-fast] Members may not be pointer types: t.CPtr / CNeedPtr /
|
||||
# CAutoPtr / rawptr[...] / str / bytes and unions carrying a pointer. Checked before type resolution.
|
||||
if self._enum_member_annotation_is_ptr(aa.annotation) == 1:
|
||||
self.Gen.TypeGenErr.fatal_error(aa, f"枚举成员 '{tgt.id}' 不能是指针类型(枚举值只支持整数成员类型)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(aa, f"enum member '{tgt.id}' cannot be a pointer type (enum values only support integer member types)", "TypeError")
|
||||
return 0 # unreachable (fatal_error already exited)
|
||||
|
||||
# Resolve the member type
|
||||
@@ -278,7 +278,7 @@ novirtual class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
# width 0 and cannot drive "enum width = widest member"; no silent downgrade.
|
||||
member_bits: int = self.Gen.TypeGenErr.get_llvm_type_bits(member_ty)
|
||||
if member_bits <= 0:
|
||||
self.Gen.TypeGenErr.fatal_error(aa, f"枚举成员 '{tgt.id}' 的类型必须为整数类型(不允许指针/浮点/void/结构体/数组),无法推导枚举宽度", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(aa, f"the type of enum member '{tgt.id}' must be an integer type (pointers/floats/void/structs/arrays are not allowed), cannot infer enum width", "TypeError")
|
||||
return 0 # unreachable (fatal_error already exited)
|
||||
|
||||
# Resolve the member value
|
||||
@@ -335,9 +335,9 @@ novirtual class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
if visible_count != member_count:
|
||||
diff_count: int = visible_count - member_count
|
||||
bad: ast.AST* = self._enum_first_unregistered_node(children)
|
||||
bad_desc: str = "(无法定位到具体语句,请检查枚举体)"
|
||||
bad_desc: str = "(cannot locate the specific statement, check the enum body)"
|
||||
if bad is not None: bad_desc = bad.type_name()
|
||||
self.Gen.TypeGenErr.fatal_error(bad if bad is not None else cd, f"枚举 '{class_name}' 成员登记数不一致:源码里可见的成员名 {visible_count} 个," f"实际只登记 {member_count} 个(差额 {diff_count} 个会被静默丢弃)。" f"未识别的成员写法(首个): {bad_desc} 形态的语句——如逗号组带值 `A, B = 1`、" f"逗号组带注解 `A, B: T`、单名尾随逗号 `A,`。" f"期望形态: 每行一个 `Name` / `Name: T` / `Name = 值`," f"或多个简单标识符用逗号分隔(`A, B, C`,可带尾随逗号)。" f"修法: 把该行改写为逐个成员一行,或改写为纯标识符逗号组(去掉 `= 值` / `: T`)。" f"(本判据在注册处比对『可见名数 vs 登记数』,任何未识别形态都会命中," f"不再静默丢成员)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(bad if bad is not None else cd, f"enum '{class_name}' member registration count mismatch: {visible_count} member names visible in source, " f"but only {member_count} registered ({diff_count} difference would be silently dropped). " f"first unrecognized member form: a statement of shape {bad_desc} -- e.g. comma group with value `A, B = 1`, " f"comma group with annotation `A, B: T`, single name with trailing comma `A,`. " f"expected forms: one `Name` / `Name: T` / `Name = value` per line, " f"or multiple simple identifiers separated by commas (`A, B, C`, trailing comma allowed). " f"fix: rewrite that line as one member per line, or as a plain identifier comma group (remove `= value` / `: T`). " f"(this check compares the number of visible names vs registered names at the registrar, so any unrecognized form hits it, " f"no more members are silently dropped)", "TypeError")
|
||||
return 0
|
||||
|
||||
if member_count == 0:
|
||||
@@ -650,7 +650,7 @@ novirtual class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
if children is None:
|
||||
# [D32 fail-fast] Previously only warned and returned: the variant table was silently unregistered,
|
||||
# so _is_renum_class_name stayed 0 and variant construction lost its tag. No silent skip here.
|
||||
self.Gen.TypeGenErr.fatal_error(cd, f"REnum 类 '{class_name}' 缺少类体(children 为 None),无法注册变体表", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(cd, f"REnum class '{class_name}' has no class body (children is None), cannot register the variant table", "TypeError")
|
||||
return 0
|
||||
|
||||
cn: sizet = len(children)
|
||||
@@ -718,7 +718,7 @@ novirtual class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
if variant_count == 0:
|
||||
# [D32 fail-fast] Same as above: variant_count 0 previously returned silently, skipping registration.
|
||||
# For `class X(t.REnum)` the count must be > 0; 0 means the AST variant classes were lost.
|
||||
self.Gen.TypeGenErr.fatal_error(cd, f"REnum 类 '{class_name}' 的变体数为 0(嵌套变体类丢失),无法注册变体表", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(cd, f"REnum class '{class_name}' has 0 variants (nested variant classes lost), cannot register the variant table", "TypeError")
|
||||
return 0
|
||||
|
||||
# Compute the max field size for each position.
|
||||
@@ -881,7 +881,7 @@ novirtual class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
# A None table means the perm-pool request failed; returning here left the table empty while the
|
||||
# caller still reported "registered", so every REnum case in match dispatch was silently lost.
|
||||
self.RenumClassNames = None
|
||||
self.Gen.TypeGenErr.fatal_error(cd, f"REnum 变体表分配失败(class='{class_name}'):PermPool 返回 NULL,变体表不可用", "InternalCompilerError")
|
||||
self.Gen.TypeGenErr.fatal_error(cd, f"failed to allocate REnum variant table (class='{class_name}'): PermPool returned NULL, variant table unavailable", "InternalCompilerError")
|
||||
return
|
||||
string.memset(self.RenumClassNames, 0, 8 * RENUM_CLASS_MAX)
|
||||
string.memset(self.RenumClassVariantCounts, 0, 8 * RENUM_CLASS_MAX)
|
||||
@@ -908,7 +908,7 @@ novirtual class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
if self.RenumClassCount >= RENUM_CLASS_MAX:
|
||||
# Silently dropping the class made its later `match` lose every case; a
|
||||
# real limit breach must be reported instead.
|
||||
self.Gen.TypeGenErr.fatal_error(cd, f"REnum 类数超过上限 {RENUM_CLASS_MAX}:无法注册 class='{class_name}'", "InternalCompilerError")
|
||||
self.Gen.TypeGenErr.fatal_error(cd, f"REnum class count exceeds the limit {RENUM_CLASS_MAX}: cannot register class='{class_name}'", "InternalCompilerError")
|
||||
return
|
||||
|
||||
# Register the class name (strcpy into perm_pool: after each file's 1a reset the AST raw pointer
|
||||
@@ -917,7 +917,7 @@ novirtual class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
cn_len_rv: sizet = string.strlen(class_name)
|
||||
cn_buf_rv: str = CompilerFactory.factory.PermPool.alloc(cn_len_rv + 1)
|
||||
if cn_buf_rv is None:
|
||||
self.Gen.TypeGenErr.fatal_error(cd, f"REnum 类名副本分配失败(class='{class_name}'):PermPool 返回 NULL", "InternalCompilerError")
|
||||
self.Gen.TypeGenErr.fatal_error(cd, f"failed to allocate REnum class name copy (class='{class_name}'): PermPool returned NULL", "InternalCompilerError")
|
||||
return
|
||||
string.strcpy(cn_buf_rv, class_name)
|
||||
self.RenumClassNames[idx] = sizet(cn_buf_rv)
|
||||
@@ -950,7 +950,7 @@ novirtual class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
if slot >= variant_count: break
|
||||
if slot >= RENUM_VARIANT_PER_CLASS:
|
||||
# Fixed 32 slots per class: exceeding it would overflow into the next class's slots; report fail-fast
|
||||
VLogger.error(f"REnum 变体数超过上限 {RENUM_VARIANT_PER_CLASS}: {class_name}", "RENUM")
|
||||
VLogger.error(f"REnum variant count exceeds the limit {RENUM_VARIANT_PER_CLASS}: {class_name}", "RENUM")
|
||||
break
|
||||
stmt: ast.AST* = children.get(ci)
|
||||
if stmt is None: continue
|
||||
@@ -989,7 +989,7 @@ novirtual class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
if vn_buf_rv is None:
|
||||
# Breaking here registered a partial variant table: the class would
|
||||
# keep some variants and silently lose every later one.
|
||||
self.Gen.TypeGenErr.fatal_error(cd, f"REnum 变体名副本分配失败(class='{class_name}'):PermPool 返回 NULL", "InternalCompilerError")
|
||||
self.Gen.TypeGenErr.fatal_error(cd, f"failed to allocate REnum variant name copy (class='{class_name}'): PermPool returned NULL", "InternalCompilerError")
|
||||
break
|
||||
string.strcpy(vn_buf_rv, vname_src)
|
||||
self.RenumVariantNames[name_offset] = sizet(vn_buf_rv)
|
||||
@@ -1074,7 +1074,7 @@ novirtual class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
# Same as the variant table: a silent bail left the alias table empty,
|
||||
# so match bindings later failed with an unrelated NameError.
|
||||
self.RenumAliasClass = None
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"REnum 字段别名表分配失败(class='{class_name}'):PermPool 返回 NULL", "InternalCompilerError")
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"failed to allocate REnum field alias table (class='{class_name}'): PermPool returned NULL", "InternalCompilerError")
|
||||
return
|
||||
string.memset(self.RenumAliasClass, 0, 8 * RENUM_ALIAS_MAX)
|
||||
string.memset(self.RenumAliasField, 0, 8 * RENUM_ALIAS_MAX)
|
||||
@@ -1093,7 +1093,7 @@ novirtual class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
if self.RenumAliasCount >= RENUM_ALIAS_MAX:
|
||||
# Dropping the record silently made the variant field bind to a wrong-typed
|
||||
# slot (or fail with NameError) instead of reporting the limit breach.
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"REnum 字段别名数超过上限 {RENUM_ALIAS_MAX}:无法注册 {class_name}.{field_name}", "InternalCompilerError")
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"REnum field alias count exceeds the limit {RENUM_ALIAS_MAX}: cannot register {class_name}.{field_name}", "InternalCompilerError")
|
||||
return
|
||||
|
||||
# Dedupe check (pointer-free): the class slot holds a perm_pool string copy compared with strcmp,
|
||||
|
||||
@@ -416,7 +416,7 @@ novirtual class ClassGenGeneric(ClassGenBase.ClassGenBase):
|
||||
"""Specialize a generic function and return its mangled name."""
|
||||
if trans is None or template_key is None or type_args is None: return None
|
||||
self.GenericSpecDepth += 1
|
||||
if self.GenericSpecDepth > GENERIC_SPEC_MAX_DEPTH: self.Gen.TypeGenErr.fatal_error(None, "泛型函数特化递归过深(疑似泛型循环套用)", "InternalCompilerError")
|
||||
if self.GenericSpecDepth > GENERIC_SPEC_MAX_DEPTH: self.Gen.TypeGenErr.fatal_error(None, "generic function specialization recursion too deep (suspected generic loop)", "InternalCompilerError")
|
||||
pool: memhub.MemBuddy* = trans.Pool
|
||||
template_fd: ast.FunctionDef* = self._find_generic_func_template(template_key)
|
||||
if template_fd is None:
|
||||
@@ -443,14 +443,14 @@ novirtual class ClassGenGeneric(ClassGenBase.ClassGenBase):
|
||||
if len(tp_names) != len(type_args):
|
||||
err_tp: str = pool.alloc(256)
|
||||
if err_tp is not None:
|
||||
viperlib.snprintf(err_tp, 256, "泛型函数 '%s' 类型实参个数不匹配(需要 %d,给定 %d)", template_fd.name, len(tp_names), len(type_args))
|
||||
viperlib.snprintf(err_tp, 256, "generic function '%s' type argument count mismatch (expected %d, given %d)", template_fd.name, len(tp_names), len(type_args))
|
||||
self.Gen.TypeGenErr.fatal_error(None, err_tp, "TypeError")
|
||||
self.GenericSpecDepth -= 1
|
||||
return None
|
||||
# Generic functions with CExport/CExtern/State markers are unsupported (specialized names bypass bare-name export)
|
||||
if template_fd.returns is not None:
|
||||
if self.Gen.TypeGenErr.has_decorator_marker(template_fd.returns, "CExport", 0) != 0 or self.Gen.TypeGenErr.has_decorator_marker(template_fd.returns, "CExtern", 0) != 0 or self.Gen.TypeGenErr.has_decorator_marker(template_fd.returns, "State", 0) != 0:
|
||||
self.Gen.TypeGenErr.fatal_error(template_fd, "泛型函数暂不支持 t.CExport/t.CExtern/t.State 存储标记", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(template_fd, "generic functions do not yet support t.CExport/t.CExtern/t.State storage markers", "TypeError")
|
||||
# Generate the specialized name (the single generator normalizes each arg so bare/prefixed forms converge)
|
||||
spec_base: str = self._mangle_generic_class_name(pool, template_fd.name, type_args, trans._from_imports)
|
||||
if spec_base is None:
|
||||
@@ -821,7 +821,7 @@ novirtual class ClassGenGeneric(ClassGenBase.ClassGenBase):
|
||||
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")
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"generic class template '{class_name}' is missing type param names (GenericClassTpParams slot is empty, " f"and the template node has no type_params) -- refusing to specialize with an empty generic context", "InternalCompilerError")
|
||||
return None
|
||||
|
||||
def _specialize_generic_class(self, trans: HT.Translator*, class_name: str, type_args: list[str]*) -> str:
|
||||
@@ -836,9 +836,9 @@ novirtual class ClassGenGeneric(ClassGenBase.ClassGenBase):
|
||||
if self.GenericSpecDepth > GENERIC_SPEC_MAX_DEPTH:
|
||||
err_spec: str = trans.Pool.alloc(256)
|
||||
if err_spec is not None:
|
||||
viperlib.snprintf(err_spec, 256, "泛型特化递归过深(疑似泛型循环套用),类: %s 深度=%d", class_name, self.GenericSpecDepth)
|
||||
viperlib.snprintf(err_spec, 256, "generic specialization recursion too deep (suspected generic loop), class: %s depth=%d", class_name, self.GenericSpecDepth)
|
||||
self.Gen.TypeGenErr.fatal_error(None, err_spec, "InternalCompilerError")
|
||||
self.Gen.TypeGenErr.fatal_error(None, "泛型特化递归过深(疑似泛型循环套用)", "InternalCompilerError")
|
||||
self.Gen.TypeGenErr.fatal_error(None, "generic specialization recursion too deep (suspected generic loop)", "InternalCompilerError")
|
||||
# Defensive: unresolved type-parameter names (e.g. "T") left in type_args are replaced with the
|
||||
# concrete type name to avoid ndarray[T] double-recursion crashes; in-place edits are side-effect free.
|
||||
ta_cnt_g: sizet = len(type_args)
|
||||
@@ -960,11 +960,11 @@ novirtual class ClassGenGeneric(ClassGenBase.ClassGenBase):
|
||||
tp_n_c: sizet = len(tp_names) if tp_names is not None else 0
|
||||
ta_n_c: sizet = len(type_args) if type_args is not None else 0
|
||||
if tp_n_c == 0 or ta_n_c != tp_n_c:
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"泛型类 '{class_name}' 的类型实参个数({ta_n_c})与模板类型形参个数({tp_n_c})不匹配," f"无法建立特化上下文(特化键 {spec_key})", "InternalCompilerError")
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"generic class '{class_name}' type argument count ({ta_n_c}) does not match the template type param count ({tp_n_c}), " f"cannot build the specialization context (spec key {spec_key})", "InternalCompilerError")
|
||||
probe_tp: str = tp_names.get(0)
|
||||
if probe_tp is not None:
|
||||
if string.strcmp(self.Gen.TypeGenBase.resolve_generic_type_name(probe_tp), probe_tp) == 0:
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"泛型类 '{class_name}' 的特化上下文装不上:类型形参 '{probe_tp}' 解析不到具体类型" f"(特化键 {spec_key})——类型实参缺失/为空", "InternalCompilerError")
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"cannot install the specialization context of generic class '{class_name}': type param '{probe_tp}' does not resolve to a concrete type" f"(spec key {spec_key}) -- type args missing/empty", "InternalCompilerError")
|
||||
|
||||
# 7. Translate the specialized class: switch trans.ModuleSha1 to the template-defining module so
|
||||
# struct type names and method symbols use its SHA1 prefix; also merge its imports.
|
||||
@@ -1009,8 +1009,8 @@ novirtual class ClassGenGeneric(ClassGenBase.ClassGenBase):
|
||||
if rfe is not None:
|
||||
rfn: str = self.Gen.StructGen.get_field_name_ptr(rfe)
|
||||
if rfn is None:
|
||||
VLogger.error("SPEC 字段名缺失(字段表损坏)", "SPEC")
|
||||
self.Gen.TypeGenErr.fatal_error(None, "SPEC 字段名缺失(字段表损坏)", "TypeError")
|
||||
VLogger.error("SPEC field name missing (field table corrupted)", "SPEC")
|
||||
self.Gen.TypeGenErr.fatal_error(None, "SPEC field name missing (field table corrupted)", "TypeError")
|
||||
|
||||
self._record_spec_trigger(pool, spec_name, spec_trigger_sha1)
|
||||
self.GenericSpecDepth -= 1
|
||||
|
||||
@@ -277,7 +277,7 @@ novirtual class ClassGenVTable(ClassGenBase.ClassGenBase):
|
||||
continue
|
||||
func_ty_buf[0] = '\0'
|
||||
if ge is None or ge.Spec is None or TSpec.SpecToLLVMText(ge.Spec, func_ty_buf, 1024) != 0:
|
||||
self.Gen.TypeGenErr.fatal_error(cd, f"vtable 方法 '{full_name}' 找不到函数类型", "InternalCompilerError")
|
||||
self.Gen.TypeGenErr.fatal_error(cd, f"vtable method '{full_name}' has no function type", "InternalCompilerError")
|
||||
continue
|
||||
|
||||
# Build the bitcast string: i8* bitcast (func_ty* @mangled to i8*).
|
||||
@@ -434,8 +434,8 @@ novirtual class ClassGenVTable(ClassGenBase.ClassGenBase):
|
||||
method_name: str = fd.name
|
||||
if method_name is None:
|
||||
# fail-fast: method name is missing (the parser cannot produce a nameless def).
|
||||
VLogger.error("方法名缺失(fd.name is None)", "OOP")
|
||||
self.Gen.TypeGenErr.fatal_error(fd, "方法名缺失(fd.name is None)", "TypeError")
|
||||
VLogger.error("method name missing (fd.name is None)", "OOP")
|
||||
self.Gen.TypeGenErr.fatal_error(fd, "method name missing (fd.name is None)", "TypeError")
|
||||
|
||||
# Extract decorator metadata (@property/@staticmethod/@classmethod/@x.setter/@x.deleter).
|
||||
func_meta: int = self.Gen.ClassGenBase._extract_func_meta(fd.decorator_list)
|
||||
@@ -478,7 +478,7 @@ novirtual class ClassGenVTable(ClassGenBase.ClassGenBase):
|
||||
ret_ty = mlirlite.Void(pool)
|
||||
else:
|
||||
# [S4 fail-fast] return annotation failed to resolve: do not fall back to infer_return_type (silent mismatch).
|
||||
self.Gen.TypeGenErr.fatal_error(fd, f"方法 '{class_name}.{method_name}' 返回类型注解解析失败", "NameError")
|
||||
self.Gen.TypeGenErr.fatal_error(fd, f"method '{class_name}.{method_name}' return type annotation failed to resolve", "NameError")
|
||||
return 0
|
||||
if ret_ty is None:
|
||||
# __init__ and __before_init__ return void.
|
||||
@@ -564,7 +564,7 @@ novirtual class ClassGenVTable(ClassGenBase.ClassGenBase):
|
||||
resolved: mlirlite.LLVMType* = self.Gen.TypeGenResolve.resolve_annotation_type(pool, arg.annotation, imported_modules, from_imports, trans, 0)
|
||||
if resolved is None:
|
||||
# [S4 fail-fast] annotation present but failed to resolve: no silent i32 (signature/call/impl mismatch).
|
||||
self.Gen.TypeGenErr.fatal_error(arg, f"方法 '{class_name}.{method_name}' 形参 '{arg.arg}' 类型注解解析失败", "NameError")
|
||||
self.Gen.TypeGenErr.fatal_error(arg, f"method '{class_name}.{method_name}' param '{arg.arg}' type annotation failed to resolve", "NameError")
|
||||
return 0
|
||||
# Bare-class param -> Ptr(struct) (objects are pointers; by-value would dangle after append).
|
||||
# CArray param -> element pointer ty* (C array decay, same as function params).
|
||||
@@ -572,7 +572,7 @@ novirtual class ClassGenVTable(ClassGenBase.ClassGenBase):
|
||||
case mlirlite.LLVMType.Void():
|
||||
# void is not a legal param type (only void* and typedef opaque structs); void*
|
||||
# is already merged into i8* upstream, so fail fast at compile time instead of emitting invalid IR.
|
||||
self.Gen.TypeGenErr.fatal_error(arg, f"方法 '{class_name}.{method_name}' 形参 '{arg.arg}' 不能是 void 类型(void 只能用于 void* 与 typedef 别名)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(arg, f"method '{class_name}.{method_name}' param '{arg.arg}' cannot be void type (void is only allowed for void* and typedef aliases)", "TypeError")
|
||||
return 0
|
||||
case mlirlite.LLVMType.Struct(_, _, _):
|
||||
param_ty = mlirlite.Ptr(pool, resolved)
|
||||
@@ -697,14 +697,14 @@ novirtual class ClassGenVTable(ClassGenBase.ClassGenBase):
|
||||
resolved2: mlirlite.LLVMType* = self.Gen.TypeGenResolve.resolve_annotation_type(pool, arg2.annotation, imported_modules, from_imports, trans, 0)
|
||||
if resolved2 is None:
|
||||
# fail-fast: param has an annotation but type resolution failed; no silent i32.
|
||||
self.Gen.TypeGenErr.fatal_error(arg2, f"方法 '{class_name}.{method_name}' 参数 '{arg2.arg}' 类型解析失败", "NameError")
|
||||
self.Gen.TypeGenErr.fatal_error(arg2, f"method '{class_name}.{method_name}' argument '{arg2.arg}' failed to resolve type", "NameError")
|
||||
resolved2 = i32_ty # Unreachable (fatal_error already exits).
|
||||
if resolved2 is not None:
|
||||
# Keep in sync with add_param: bare class -> Ptr(struct) (objects are pointers); CArray -> element pointer ty*.
|
||||
match resolved2:
|
||||
case mlirlite.LLVMType.Void():
|
||||
# void is not a legal param type (same rule as above).
|
||||
self.Gen.TypeGenErr.fatal_error(arg2, f"方法 '{class_name}.{method_name}' 形参 '{arg2.arg}' 不能是 void 类型(void 只能用于 void* 与 typedef 别名)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(arg2, f"method '{class_name}.{method_name}' param '{arg2.arg}' cannot be void type (void is only allowed for void* and typedef aliases)", "TypeError")
|
||||
return 0
|
||||
case mlirlite.LLVMType.Struct(_, _, _):
|
||||
param_ty2 = mlirlite.Ptr(pool, resolved2)
|
||||
@@ -811,8 +811,8 @@ novirtual class ClassGenVTable(ClassGenBase.ClassGenBase):
|
||||
if ret_ty is not None:
|
||||
_m_zero_val: mlirlite.Value* = mlirlite.ConstZero(pool, ret_ty)
|
||||
if _m_zero_val is not None: mlirlite.build_ret(func_builder, _m_zero_val)
|
||||
else: self.Gen.TypeGenErr.fatal_error(fd, "方法流程掉出末尾但未显式 return", "TypeError")
|
||||
else: self.Gen.TypeGenErr.fatal_error(fd, "方法流程掉出末尾但未显式 return", "TypeError")
|
||||
else: self.Gen.TypeGenErr.fatal_error(fd, "method flow falls off the end without an explicit return", "TypeError")
|
||||
else: self.Gen.TypeGenErr.fatal_error(fd, "method flow falls off the end without an explicit return", "TypeError")
|
||||
else:
|
||||
# fail-fast: has a -> annotation but control truly falls off the end (traceback-style).
|
||||
if ret_ty is not None:
|
||||
@@ -822,10 +822,10 @@ novirtual class ClassGenVTable(ClassGenBase.ClassGenBase):
|
||||
if rt_name_m[0] == '\0': rt_name_m = "?"
|
||||
err_fn_m: str = pool.alloc(256)
|
||||
if err_fn_m is not None:
|
||||
viperlib.snprintf(err_fn_m, 256, "方法 '%s' 流程掉出末尾但未显式 return(返回类型 %s),请补显式 return(如 return 0 / return null)", method_name, rt_name_m)
|
||||
viperlib.snprintf(err_fn_m, 256, "method '%s' flow falls off the end without an explicit return (return type %s), please add an explicit return (e.g. return 0 / return null)", method_name, rt_name_m)
|
||||
self.Gen.TypeGenErr.fatal_error(fd, err_fn_m, "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(fd, "方法流程掉出末尾但未显式 return", "TypeError")
|
||||
else: self.Gen.TypeGenErr.fatal_error(fd, "方法流程掉出末尾但未显式 return", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(fd, "method flow falls off the end without an explicit return", "TypeError")
|
||||
else: self.Gen.TypeGenErr.fatal_error(fd, "method flow falls off the end without an explicit return", "TypeError")
|
||||
|
||||
# Restore the module-level scope.
|
||||
self.Gen.VarGen.exit_scope(trans.SymTab)
|
||||
@@ -982,7 +982,7 @@ novirtual class ClassGenVTable(ClassGenBase.ClassGenBase):
|
||||
if arr_ctx is not None:
|
||||
fname_dbg_v: str = fe.Name
|
||||
if fname_dbg_v is None: fname_dbg_v = "?"
|
||||
viperlib.snprintf(arr_ctx, 192, "类 %s 字段 %s:", class_name, fname_dbg_v)
|
||||
viperlib.snprintf(arr_ctx, 192, "class %s field %s: ", class_name, fname_dbg_v)
|
||||
self.Gen.AssignGen._init_global_array_from_list(func_builder, pool, mod, field_ptr_arr, fe.DefaultVal, trans, arr_ctx)
|
||||
continue
|
||||
# Translate the default-value expression.
|
||||
|
||||
@@ -68,7 +68,7 @@ def _EnsureStorage() -> int:
|
||||
rbuf: bytes = stdlib.malloc(DBG_LOC_SLOTS * 8)
|
||||
ubuf: bytes = stdlib.malloc(DBG_LOC_SLOTS)
|
||||
if sbuf1 is None or sbuf2 is None or sbuf3 is None or kbuf is None or rbuf is None or ubuf is None:
|
||||
VLogger.error("--traceback: DWARF 元数据缓冲分配失败,终止编译", "DWARF")
|
||||
VLogger.error("--traceback: failed to allocate DWARF metadata buffer, aborting compilation", "DWARF")
|
||||
return 1
|
||||
string.memset(sbuf1, 0, DBG_STACK_MAX * 8)
|
||||
string.memset(sbuf2, 0, DBG_STACK_MAX * 8)
|
||||
@@ -132,7 +132,7 @@ def _EnsureModuleNodes(pool: memhub.MemBuddy*) -> int:
|
||||
cap_n: sizet = slen + 4112
|
||||
nbuf: str = pool.alloc(cap_n)
|
||||
if nbuf is None:
|
||||
VLogger.error("--traceback: DIFile 路径缓冲分配失败,终止编译", "DWARF")
|
||||
VLogger.error("--traceback: failed to allocate DIFile path buffer, aborting compilation", "DWARF")
|
||||
return 1
|
||||
if slen > 0: string.strncpy(nbuf, src, slen)
|
||||
nbuf[slen] = '\0'
|
||||
@@ -167,38 +167,38 @@ def _EnsureModuleNodes(pool: memhub.MemBuddy*) -> int:
|
||||
dsize: sizet = string.strlen(fname) + string.strlen(directory) + 96
|
||||
dbuf: str = pool.alloc(dsize)
|
||||
if dbuf is None:
|
||||
VLogger.error("--traceback: DIFile 节点缓冲分配失败,终止编译", "DWARF")
|
||||
VLogger.error("--traceback: failed to allocate DIFile node buffer, aborting compilation", "DWARF")
|
||||
return 1
|
||||
viperlib.snprintf(dbuf, dsize, "!DIFile(filename: \"%s\", directory: \"%s\")", fname, directory)
|
||||
fid: int = mlirlite.module_add_di_node(mod, pool, dbuf)
|
||||
if fid < 0:
|
||||
VLogger.error("--traceback: DIFile 元数据节点分配失败,终止编译", "DWARF")
|
||||
VLogger.error("--traceback: failed to allocate DIFile metadata node, aborting compilation", "DWARF")
|
||||
return 1
|
||||
_g_file_id = fid
|
||||
# types: !{ null } placeholder list, then DISubroutineType referencing it
|
||||
nid: int = mlirlite.module_add_di_node(mod, pool, "!{ null }")
|
||||
if nid < 0:
|
||||
VLogger.error("--traceback: DISubroutineType 类型表分配失败,终止编译", "DWARF")
|
||||
VLogger.error("--traceback: failed to allocate DISubroutineType type table, aborting compilation", "DWARF")
|
||||
return 1
|
||||
_g_null_id = nid
|
||||
tbuf: str = pool.alloc(64)
|
||||
if tbuf is None:
|
||||
VLogger.error("--traceback: DISubroutineType 缓冲分配失败,终止编译", "DWARF")
|
||||
VLogger.error("--traceback: failed to allocate DISubroutineType buffer, aborting compilation", "DWARF")
|
||||
return 1
|
||||
viperlib.snprintf(tbuf, 64, "!DISubroutineType(types: !%d)", _g_null_id)
|
||||
tid: int = mlirlite.module_add_di_node(mod, pool, tbuf)
|
||||
if tid < 0:
|
||||
VLogger.error("--traceback: DISubroutineType 元数据节点分配失败,终止编译", "DWARF")
|
||||
VLogger.error("--traceback: failed to allocate DISubroutineType metadata node, aborting compilation", "DWARF")
|
||||
return 1
|
||||
_g_subtype_id = tid
|
||||
cbuf: str = pool.alloc(256)
|
||||
if cbuf is None:
|
||||
VLogger.error("--traceback: DICompileUnit 缓冲分配失败,终止编译", "DWARF")
|
||||
VLogger.error("--traceback: failed to allocate DICompileUnit buffer, aborting compilation", "DWARF")
|
||||
return 1
|
||||
viperlib.snprintf(cbuf, 256, "distinct !DICompileUnit(language: DW_LANG_C99, file: !%d, producer: \"TPC\", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug)", _g_file_id)
|
||||
cid: int = mlirlite.module_add_di_node(mod, pool, cbuf)
|
||||
if cid < 0:
|
||||
VLogger.error("--traceback: DICompileUnit 元数据节点分配失败,终止编译", "DWARF")
|
||||
VLogger.error("--traceback: failed to allocate DICompileUnit metadata node, aborting compilation", "DWARF")
|
||||
return 1
|
||||
_g_cu_id = cid
|
||||
return 0
|
||||
@@ -230,11 +230,11 @@ def _EnsureLocation(pool: memhub.MemBuddy*, sp: int, line: int, col: int) -> str
|
||||
viperlib.snprintf(lbuf, 96, "!DILocation(line: %d, column: %d, scope: !%d)", line, c, sp)
|
||||
lid: int = mlirlite.module_add_di_node(_g_mod, pool, lbuf)
|
||||
if lid < 0:
|
||||
VLogger.error("--traceback: DILocation 元数据节点分配失败,终止编译", "DWARF")
|
||||
VLogger.error("--traceback: failed to allocate DILocation metadata node, aborting compilation", "DWARF")
|
||||
return None
|
||||
lref: str = _RefOf(pool, lid)
|
||||
if lref is None:
|
||||
VLogger.error("--traceback: DILocation 引用缓冲分配失败,终止编译", "DWARF")
|
||||
VLogger.error("--traceback: failed to allocate DILocation reference buffer, aborting compilation", "DWARF")
|
||||
return None
|
||||
if pi < DBG_LOC_PROBE:
|
||||
slot2: int = int((h + uint64(pi)) & uint64(DBG_LOC_SLOTS - 1))
|
||||
@@ -255,12 +255,12 @@ def PushFunction(pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, func: mli
|
||||
if _g_enabled == 0: return 0
|
||||
if pool is None or builder is None or func is None or _g_mod is None: return 0
|
||||
if _g_depth >= DBG_STACK_MAX:
|
||||
VLogger.error("--traceback: DWARF 函数嵌套深度超上限,终止编译", "DWARF")
|
||||
VLogger.error("--traceback: DWARF function nesting depth exceeds the limit, aborting compilation", "DWARF")
|
||||
return 0
|
||||
if _EnsureModuleNodes(pool) != 0: return 0
|
||||
name: str = mlirlite.function_get_name(func)
|
||||
if name is None:
|
||||
VLogger.error("--traceback: 函数名为空,无法发射 DISubprogram,终止编译", "DWARF")
|
||||
VLogger.error("--traceback: function name is empty, cannot emit DISubprogram, aborting compilation", "DWARF")
|
||||
return 0
|
||||
dline: int = line
|
||||
if dline <= 0: dline = 1
|
||||
@@ -269,16 +269,16 @@ def PushFunction(pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, func: mli
|
||||
ssize: sizet = string.strlen(name) + 320
|
||||
spbuf: str = pool.alloc(ssize)
|
||||
if spbuf is None:
|
||||
VLogger.error("--traceback: DISubprogram 缓冲分配失败,终止编译", "DWARF")
|
||||
VLogger.error("--traceback: failed to allocate DISubprogram buffer, aborting compilation", "DWARF")
|
||||
return 0
|
||||
viperlib.snprintf(spbuf, ssize, "distinct !DISubprogram(name: \"%s\", scope: !%d, file: !%d, type: !%d, line: %d, scopeLine: %d, unit: !%d, spFlags: DISPFlagDefinition)", name, _g_file_id, _g_file_id, _g_subtype_id, dline, dline, _g_cu_id)
|
||||
sp_id: int = mlirlite.module_add_di_node(_g_mod, pool, spbuf)
|
||||
if sp_id < 0:
|
||||
VLogger.error("--traceback: DISubprogram 元数据节点分配失败,终止编译", "DWARF")
|
||||
VLogger.error("--traceback: failed to allocate DISubprogram metadata node, aborting compilation", "DWARF")
|
||||
return 0
|
||||
sp_ref: str = _RefOf(pool, sp_id)
|
||||
if sp_ref is None:
|
||||
VLogger.error("--traceback: DISubprogram 引用缓冲分配失败,终止编译", "DWARF")
|
||||
VLogger.error("--traceback: failed to allocate DISubprogram reference buffer, aborting compilation", "DWARF")
|
||||
return 0
|
||||
mlirlite.function_set_dbg(func, sp_ref)
|
||||
# save the enclosing function's DI context (LIFO), then switch to this one
|
||||
@@ -292,7 +292,7 @@ def PushFunction(pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, func: mli
|
||||
_g_cur_builder = builder
|
||||
entry_ref: str = _EnsureLocation(pool, sp_id, dline, dcol)
|
||||
if entry_ref is None:
|
||||
VLogger.error("--traceback: 入口 DILocation 生成失败,终止编译", "DWARF")
|
||||
VLogger.error("--traceback: failed to generate entry DILocation, aborting compilation", "DWARF")
|
||||
return 0
|
||||
_g_cur_entry_ref = entry_ref
|
||||
mlirlite.builder_set_debug_location(builder, entry_ref)
|
||||
@@ -355,25 +355,25 @@ def Finalize(pool: memhub.MemBuddy*) -> int:
|
||||
_g_finalized = 1
|
||||
# Self-check (mirrors TPC Phase2Translator.py:3444): a module that emits a
|
||||
# define but carries no DI at all loses line info for its frames.
|
||||
if mod.DIMetaCount == 0 and _ModuleHasDefine(mod) != 0: VLogger.warning("--traceback: 本模块发射了 define 但 IR 未携带 DWARF (!llvm.dbg.cu)——该模块帧在 Ctrl+C 栈里将只显示地址", "DWARF")
|
||||
if mod.DIMetaCount == 0 and _ModuleHasDefine(mod) != 0: VLogger.warning("--traceback: this module emits a define but its IR carries no DWARF (!llvm.dbg.cu); its frames will show only addresses in the Ctrl+C stack", "DWARF")
|
||||
if _g_cu_id < 0: return 0
|
||||
cu_ref: str = _RefOf(pool, _g_cu_id)
|
||||
if cu_ref is None:
|
||||
VLogger.error("--traceback: DICompileUnit 引用缓冲分配失败,终止编译", "DWARF")
|
||||
VLogger.error("--traceback: failed to allocate DICompileUnit reference buffer, aborting compilation", "DWARF")
|
||||
return 1
|
||||
mlirlite.module_add_named_metadata(mod, pool, "llvm.dbg.cu", cu_ref)
|
||||
fbuf: str = pool.alloc(64)
|
||||
if fbuf is None:
|
||||
VLogger.error("--traceback: 模块级调试标志缓冲分配失败,终止编译", "DWARF")
|
||||
VLogger.error("--traceback: failed to allocate module-level debug flags buffer, aborting compilation", "DWARF")
|
||||
return 1
|
||||
viperlib.snprintf(fbuf, 64, "!{i32 2, !\"Debug Info Version\", i32 3}")
|
||||
flags_id: int = mlirlite.module_add_di_node(mod, pool, fbuf)
|
||||
if flags_id < 0:
|
||||
VLogger.error("--traceback: llvm.module.flags 元数据节点分配失败,终止编译", "DWARF")
|
||||
VLogger.error("--traceback: failed to allocate llvm.module.flags metadata node, aborting compilation", "DWARF")
|
||||
return 1
|
||||
fl_ref: str = _RefOf(pool, flags_id)
|
||||
if fl_ref is None:
|
||||
VLogger.error("--traceback: llvm.module.flags 引用缓冲分配失败,终止编译", "DWARF")
|
||||
VLogger.error("--traceback: failed to allocate llvm.module.flags reference buffer, aborting compilation", "DWARF")
|
||||
return 1
|
||||
mlirlite.module_add_named_metadata(mod, pool, "llvm.module.flags", fl_ref)
|
||||
return 0
|
||||
@@ -152,7 +152,7 @@ novirtual class ExprGenAttr(ExprGenBase.ExprGenBase):
|
||||
if cs_sha1 is None: return 0
|
||||
if string.strncmp(cs_sha1, trans.ModuleSha1, 16) == 0: return 0
|
||||
if self.Gen.CallGenBase.IsStaticSymbol(cs_sha1, at.attr) == 0: return 0
|
||||
self.Gen.TypeGenErr.fatal_error(at, f"'{cs_path}.{at.attr}' 是 static 符号,禁止跨模块使用(static 仅限定义模块内可见)", "NameError")
|
||||
self.Gen.TypeGenErr.fatal_error(at, f"'{cs_path}.{at.attr}' is a static symbol, cross-module use is forbidden (static is only visible inside its defining module)", "NameError")
|
||||
return 0
|
||||
def _resolve_module_attribute_global(self, pool: memhub.MemBuddy*, mod: mlirlite.LLVMModule*, trans: HT.Translator*, at: ast.Attribute*, ty_hint: mlirlite.LLVMType*) -> mlirlite.Value*:
|
||||
"""Resolve a module attribute access to a global variable reference for cross-module use."""
|
||||
@@ -272,7 +272,7 @@ novirtual class ExprGenAttr(ExprGenBase.ExprGenBase):
|
||||
if at is not None:
|
||||
if at.value is None: missing_an = "value"
|
||||
elif at.attr is None: missing_an = "attr"
|
||||
viperlib.snprintf(diag_buf_an, 256, "属性访问失败: AST 节点字段缺失 (%s sha1=%s:%d)", missing_an, trans.ModuleSha1 if trans is not None and trans.ModuleSha1 is not None else "?", at.lineno if at is not None and at.lineno is not None else 0)
|
||||
viperlib.snprintf(diag_buf_an, 256, "attribute access failed: AST node field missing (%s sha1=%s:%d)", missing_an, trans.ModuleSha1 if trans is not None and trans.ModuleSha1 is not None else "?", at.lineno if at is not None and at.lineno is not None else 0)
|
||||
VLogger.error(diag_buf_an, "ATTR")
|
||||
return None
|
||||
|
||||
@@ -318,7 +318,7 @@ novirtual class ExprGenAttr(ExprGenBase.ExprGenBase):
|
||||
return mlirlite.ConstInt(pool, base_ty, member.Value, name_buf)
|
||||
return mlirlite.const_int32(pool, member.Value)
|
||||
# fast-fail: enum member not found
|
||||
VLogger.error(f"枚举成员未找到: {enum_nm.id}.{at.attr}", "ATTR")
|
||||
VLogger.error(f"enum member not found: {enum_nm.id}.{at.attr}", "ATTR")
|
||||
return None
|
||||
|
||||
# nested enum member access: Module.EnumName.MemberName → constant, when value is an Attribute at any
|
||||
@@ -339,7 +339,7 @@ novirtual class ExprGenAttr(ExprGenBase.ExprGenBase):
|
||||
dbg_ee: GenTypes.EnumEntry* = self.Gen.StmtGenDecl.find_enum(inner_at_e.attr)
|
||||
dbg_mc: int = -1
|
||||
if dbg_ee is not None: dbg_mc = dbg_ee.MemberCount
|
||||
VLogger.error(f"嵌套枚举成员未找到: {inner_at_e.attr}.{at.attr} (enum_members={dbg_mc})", "ATTR")
|
||||
VLogger.error(f"nested enum member not found: {inner_at_e.attr}.{at.attr} (enum_members={dbg_mc})", "ATTR")
|
||||
return None
|
||||
|
||||
# REnum variant reference as a value: ClassName.Variant / Module.ClassName.Variant → the variant tag
|
||||
@@ -461,7 +461,7 @@ novirtual class ExprGenAttr(ExprGenBase.ExprGenBase):
|
||||
# module defines a same-named global (e.g. PA_DEPS_MAX_STR); else fail-fast (undefined value).
|
||||
if self.Gen.ExprGenCdef._is_cdefine_name_pattern(at.attr) != 0:
|
||||
if self.find_global_in_module(mod, at.attr) is None:
|
||||
self.Gen.TypeGenErr.fatal_error(at, f"跨模块 CDefine 未找到: '{nm_ma.id}.{at.attr}'(CDefine cross-module lookup failed)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(at, f"cross-module CDefine not found: '{nm_ma.id}.{at.attr}' (CDefine cross-module lookup failed)", "TypeError")
|
||||
# hit a cross-module global → fall through to the cross-module global load path
|
||||
# not a CDefine: use i8* as the type hint (module-level variables usually hold pointers)
|
||||
i8_ptr_hint: mlirlite.LLVMType* = mlirlite.Ptr(pool, mlirlite.Int8(pool))
|
||||
@@ -538,7 +538,7 @@ novirtual class ExprGenAttr(ExprGenBase.ExprGenBase):
|
||||
# CDefine not found: fail-fast and stop compiling (no more undefined global
|
||||
# references, which would make llc report "use of undefined value").
|
||||
if self.Gen.ExprGenCdef._is_cdefine_name_pattern(at.attr) != 0:
|
||||
self.Gen.TypeGenErr.fatal_error(at, f"嵌套属性跨模块 CDefine 未找到: '{qual_buf}.{at.attr}'(CDefine cross-module lookup failed)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(at, f"nested attribute cross-module CDefine not found: '{qual_buf}.{at.attr}' (CDefine cross-module lookup failed)", "TypeError")
|
||||
return None
|
||||
|
||||
# for a Name obj, look up the alloca directly (no struct load); nonlocal variables (hoisted
|
||||
@@ -734,7 +734,7 @@ novirtual class ExprGenAttr(ExprGenBase.ExprGenBase):
|
||||
if dbg_bp is not None: diag_base_txt = dbg_bp
|
||||
sha1_attr: str = "?"
|
||||
if trans.ModuleSha1 is not None: sha1_attr = trans.ModuleSha1
|
||||
self.Gen.TypeGenErr.fatal_error(at, f"属性访问失败: .{at.attr} (var={diag_var_txt} annot={diag_annot_txt} base={diag_base_txt} sha1={sha1_attr})", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(at, f"attribute access failed: .{at.attr} (var={diag_var_txt} annot={diag_annot_txt} base={diag_base_txt} sha1={sha1_attr})", "TypeError")
|
||||
return None
|
||||
case _:
|
||||
# fast-fail: attribute access on a non-pointer type (e.g. i32.x) aborts immediately via a
|
||||
@@ -745,7 +745,7 @@ novirtual class ExprGenAttr(ExprGenBase.ExprGenBase):
|
||||
if trans is not None and trans.ModuleSha1 is not None: sha1_ap = trans.ModuleSha1
|
||||
ln_ap: int = 0
|
||||
if at is not None and at.lineno is not None: ln_ap = at.lineno
|
||||
self.Gen.TypeGenErr.fatal_error(at, f"属性访问失败: .{attr_nm_ap} (base=非指针类型,无法做属性访问 sha1={sha1_ap}:{ln_ap})", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(at, f"attribute access failed: .{attr_nm_ap} (base=non-pointer type, cannot do attribute access sha1={sha1_ap}:{ln_ap})", "TypeError")
|
||||
# explicit return after fatal_error: the final match arm must be terminated, else falling off
|
||||
# the end is misjudged by the function tail as fail-fast
|
||||
return None
|
||||
@@ -1075,7 +1075,7 @@ novirtual class ExprGenAttr(ExprGenBase.ExprGenBase):
|
||||
if dbg_bp_g is not None: diag_base_txt_g = dbg_bp_g
|
||||
sha1_attr_g: str = "?"
|
||||
if trans.ModuleSha1 is not None: sha1_attr_g = trans.ModuleSha1
|
||||
self.Gen.TypeGenErr.fatal_error(at, f"属性写入失败: .{at.attr} (var={diag_var_txt_g} annot={diag_annot_txt_g} base={diag_base_txt_g} sha1={sha1_attr_g})", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(at, f"attribute write failed: .{at.attr} (var={diag_var_txt_g} annot={diag_annot_txt_g} base={diag_base_txt_g} sha1={sha1_attr_g})", "TypeError")
|
||||
return None
|
||||
case _:
|
||||
# fast-fail: attribute write on a non-pointer type (e.g. i32.x = ...) aborts immediately via a
|
||||
@@ -1086,6 +1086,6 @@ novirtual class ExprGenAttr(ExprGenBase.ExprGenBase):
|
||||
if trans is not None and trans.ModuleSha1 is not None: sha1_gp = trans.ModuleSha1
|
||||
ln_gp: int = 0
|
||||
if at is not None and at.lineno is not None: ln_gp = at.lineno
|
||||
self.Gen.TypeGenErr.fatal_error(at, f"属性写入失败: .{attr_nm_gp} (base=非指针类型,无法做属性写入 sha1={sha1_gp}:{ln_gp})", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(at, f"attribute write failed: .{attr_nm_gp} (base=non-pointer type, cannot do attribute write sha1={sha1_gp}:{ln_gp})", "TypeError")
|
||||
# explicit return after fatal_error: the final match arm must be terminated
|
||||
return None
|
||||
@@ -301,7 +301,7 @@ novirtual class ExprGenBase:
|
||||
"""Fail fast (return 1) when a bare str/bytes annotation holds an aggregate pointer."""
|
||||
if annot_is_str == 0 or val is None or val.Ty is None: return 0
|
||||
if self._str_rejects_ptr_kind(val) == 0: return 0
|
||||
self.Gen.TypeGenErr.fatal_error(self._value_node_of(node), "str/bytes 不接受指向非基本类型(结构体/类/非字符数组/函数)的指针:两者在 IR 层" "同为 i8*,但语义不同(str/bytes 不是通用指针通配)。若确需传递指针," "请改用 t.CPtr/rawptr 形参,或显式转换(如 t.CPtr(p))", "CastError")
|
||||
self.Gen.TypeGenErr.fatal_error(self._value_node_of(node), "str/bytes does not accept a pointer to a non-basic type (struct/class/non-char array/function): both are" "i8* at the IR level, but with different semantics (str/bytes is not a general pointer wildcard). If a pointer must be passed, " "use a t.CPtr/rawptr parameter instead, or cast explicitly (e.g. t.CPtr(p))", "CastError")
|
||||
return 1
|
||||
def fail_if_str_annot_ast_agg_ptr(self, val: mlirlite.Value*, annot: ast.AST*, node: ast.AST* = None) -> int:
|
||||
"""AST-annotation entry: fail fast when a bare str/bytes annotation holds an aggregate pointer."""
|
||||
@@ -421,13 +421,13 @@ novirtual class ExprGenBase:
|
||||
# Names the level and why, plus source/target types; result is heap-copied.
|
||||
def _ptr_cast_reason_text(self, code: int, pool: memhub.MemBuddy*, src_ty: mlirlite.LLVMType*, dst_ty: mlirlite.LLVMType*) -> str:
|
||||
"""Human-readable reason for a forbidden ptr -> ptr cast (includes source/target types)."""
|
||||
why: str = "原因未知"
|
||||
if code == PC_DEPTH: why = f"指针层数不同(源 {self.get_ptr_level(src_ty)} 级 → 目标 {self.get_ptr_level(dst_ty)} 级)"
|
||||
elif code == PC_NONBASIC: why = "被指类型是非基本类型(结构体/类/联合/数组等):非基本类型与其指针之间、以及不同非基本类型的指针之间一律不允许隐式转换"
|
||||
elif code == PC_LOSSY: why = "被指类型之间的转换有损(整数→浮点位宽不足 / 浮点→整数)"
|
||||
why: str = "unknown reason"
|
||||
if code == PC_DEPTH: why = f"pointer level differs (source level {self.get_ptr_level(src_ty)} -> target level {self.get_ptr_level(dst_ty)})"
|
||||
elif code == PC_NONBASIC: why = "the pointee type is a non-basic type (struct/class/union/array etc.): implicit conversion is never allowed between a non-basic type and its pointer, or between pointers of different non-basic types"
|
||||
elif code == PC_LOSSY: why = "conversion between the pointee types is lossy (int -> float with insufficient width / float -> int)"
|
||||
s_txt: str = self._type_text(pool, src_ty)
|
||||
d_txt: str = self._type_text(pool, dst_ty)
|
||||
return GenApi.escape_fstring_copy(f"指针隐式转指针已禁止:{why};源类型 {s_txt} → 目标类型 {d_txt}")
|
||||
return GenApi.escape_fstring_copy(f"implicit pointer-to-pointer conversion is forbidden: {why}; source type {s_txt} -> target type {d_txt}")
|
||||
# _ctor_call_agg_ty - aggregate type if node is a class/struct constructor call.
|
||||
# The only exception to rule 3 ("construction materialization"); else None.
|
||||
def _ctor_call_agg_ty(self, node: ast.AST*) -> mlirlite.LLVMType*:
|
||||
@@ -478,7 +478,7 @@ novirtual class ExprGenBase:
|
||||
# fails fast instead of emitting illegal IR (load void / bitcast void).
|
||||
if self.Gen.StmtGenDecl._is_void_type(val.Ty) != 0:
|
||||
if self.Gen.StmtGenDecl._is_void_type(target_ty) == 0:
|
||||
self.Gen.TypeGenErr.fatal_error(self._value_node_of(node), "void 类型的值不能参与任何操作(void 只能用于 void* 与 typedef 别名)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(self._value_node_of(node), "a void value cannot take part in any operation (void is only allowed for void* and typedef aliases)", "TypeError")
|
||||
return val
|
||||
# func -> ptr: bitcast (function Values have Func type, handled before
|
||||
# the integer/float conversions).
|
||||
@@ -497,13 +497,13 @@ novirtual class ExprGenBase:
|
||||
# [FIX 2026-08-31] C null pointer constant exemption: compile-time 0
|
||||
# assigned to a pointer becomes a null pointer (widen to i64, then 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))才能把整数赋给指针类型"
|
||||
m_i2p: str = "implicit integer-to-pointer conversion is forbidden: an explicit cast to pointer (e.g. t.CPtr(x)) is required to assign an integer to a pointer type"
|
||||
self.Gen.TypeGenErr.fatal_error(self._value_node_of(node), m_i2p, "CastError")
|
||||
return val
|
||||
# Pointer -> integer: rejected (symmetric with the int -> ptr rule above).
|
||||
# An explicit cast is required; the old code silently did ptrtoint.
|
||||
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) / int64(p) / int(p))才能把指针赋给整数类型"
|
||||
m_p2i: str = "implicit pointer-to-integer conversion is forbidden: an explicit cast (e.g. uint64(p) / int64(p) / int(p)) is required to assign a pointer to an integer type"
|
||||
self.Gen.TypeGenErr.fatal_error(self._value_node_of(node), m_p2i, "CastError")
|
||||
return val
|
||||
if val_bits != 0 and target_bits != 0:
|
||||
@@ -524,7 +524,7 @@ novirtual class ExprGenBase:
|
||||
target_max_u: uint64 = (uint64(1) << target_bits) - 1
|
||||
if uint64(val.IntVal) > target_max_u:
|
||||
max_print: int64 = int64(target_max_u)
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"窄化截断溢出:常量 {val.IntVal} 超出目标类型 {target_bits} 位范围 [0, {max_print}],赋值将被静默截断", "OverflowError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"narrowing truncation overflow: constant {val.IntVal} exceeds the {target_bits}-bit range [0, {max_print}] of the target type, the assignment would be silently truncated", "OverflowError")
|
||||
return mlirlite.build_trunc(builder, val, target_ty)
|
||||
# Float conversion.
|
||||
val_fbits: int = self.get_llvm_float_bits(val.Ty)
|
||||
@@ -550,8 +550,8 @@ novirtual class ExprGenBase:
|
||||
# forbidden, except "construction materialization" (see _ctor_call_agg_ty).
|
||||
ctor_v2p: mlirlite.LLVMType* = self._ctor_call_agg_ty(node)
|
||||
if self._same_agg_ty(builder.Pool, ctor_v2p, val.Ty) == 0:
|
||||
m_v2p: str = "非基本类型的值/指针隐式转换已禁止(构造物化除外):不能把非基本类型值隐式转为指针(Foo → Foo*),如需取址请显式 c.addr(...) / &v,或显式强转"
|
||||
v2p_txt: str = GenApi.escape_fstring_copy(f";源值类型 {self._type_text(builder.Pool, val.Ty)} → 目标类型 {self._type_text(builder.Pool, target_ty)}")
|
||||
m_v2p: str = "implicit value/pointer conversion for non-basic types is forbidden (except construction materialization): a non-basic value cannot be implicitly converted to a pointer (Foo -> Foo*); to take its address use c.addr(...) / &v explicitly, or cast explicitly"
|
||||
v2p_txt: str = GenApi.escape_fstring_copy(f"; source value type {self._type_text(builder.Pool, val.Ty)} -> target type {self._type_text(builder.Pool, target_ty)}")
|
||||
self.Gen.TypeGenErr.fatal_error(self._value_node_of(node), f"{m_v2p}{v2p_txt}", "CastError")
|
||||
return val
|
||||
tmp_agg: mlirlite.Value* = self.Gen.VarGen._alloca_at_entry(builder, val.Ty)
|
||||
@@ -574,12 +574,12 @@ novirtual class ExprGenBase:
|
||||
# forbidden, except "construction materialization" (see _ctor_call_agg_ty).
|
||||
ctor_p2v: mlirlite.LLVMType* = self._ctor_call_agg_ty(node)
|
||||
if self._same_agg_ty(builder.Pool, ctor_p2v, target_ty) == 0:
|
||||
m_p2v: str = "非基本类型的值/指针隐式转换已禁止(构造物化除外):不能把指针类型隐式转为非基本类型值(Foo* → Foo),如需解引用请显式 c.deref(p) / *p,或显式强转"
|
||||
p2v_txt: str = GenApi.escape_fstring_copy(f";源类型 {self._type_text(builder.Pool, val.Ty)} → 目标值类型 {self._type_text(builder.Pool, target_ty)}")
|
||||
m_p2v: str = "implicit value/pointer conversion for non-basic types is forbidden (except construction materialization): a pointer type cannot be implicitly converted to a non-basic value (Foo* -> Foo); to dereference use c.deref(p) / *p explicitly, or cast explicitly"
|
||||
p2v_txt: str = GenApi.escape_fstring_copy(f"; source type {self._type_text(builder.Pool, val.Ty)} -> target value type {self._type_text(builder.Pool, target_ty)}")
|
||||
self.Gen.TypeGenErr.fatal_error(self._value_node_of(node), f"{m_p2v}{p2v_txt}", "CastError")
|
||||
return val
|
||||
return mlirlite.build_load(builder, target_ty, val)
|
||||
self.Gen.TypeGenErr.fatal_error(self._value_node_of(node), f"指针隐式转非指针值已禁止:必须显式解引用(*p / *p)或显式强转(uint64(p))", "CastError")
|
||||
self.Gen.TypeGenErr.fatal_error(self._value_node_of(node), f"implicit pointer-to-non-pointer-value conversion is forbidden: an explicit dereference (*p / *p) or explicit cast (uint64(p)) is required", "CastError")
|
||||
return val
|
||||
# ptr -> ptr: implicit conversion must satisfy the new rules (see
|
||||
# _ptr_cast_reason); violators fail fast with a CastError.
|
||||
|
||||
@@ -104,9 +104,9 @@ novirtual class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
if depth > 32:
|
||||
err_buf: str = pool.alloc(256)
|
||||
if err_buf is not None:
|
||||
viperlib.snprintf(err_buf, 256, "跨模块 CDefine 查找递归过深(疑似模块循环 import/re-export): %s (depth=%d fi=%s)", name, depth, from_imports if from_imports is not None else "(nil)")
|
||||
viperlib.snprintf(err_buf, 256, "cross-module CDefine lookup recursion too deep (suspected module import/re-export cycle): %s (depth=%d fi=%s)", name, depth, from_imports if from_imports is not None else "(nil)")
|
||||
self.Gen.TypeGenErr.fatal_error(node, err_buf, "InternalCompilerError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, "跨模块 CDefine 查找递归过深(疑似模块循环 import/re-export)", "InternalCompilerError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, "cross-module CDefine lookup recursion too deep (suspected module import/re-export cycle)", "InternalCompilerError")
|
||||
# clear the found flag at entry so every early return reports "not found",
|
||||
# avoiding a stale success flag left over from a previous recursive call.
|
||||
self.Gen.TypeGenCDef.set_cdefine_found(0)
|
||||
@@ -262,7 +262,7 @@ novirtual class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
# report and abort instead of silently returning -1 (avoids bad @UNDEFINED refs).
|
||||
err_buf: str = pool.alloc(512)
|
||||
if err_buf is not None:
|
||||
viperlib.snprintf(err_buf, 512, "跨模块 CDefine 查找失败:SHA1 %s 不在存储器中(base_mod=%s name=%s)。" "Phase1/Phase2 未正确填充 PopulateSha1MapStore/AppendToSha1MapStore", sha1, base_mod, name)
|
||||
viperlib.snprintf(err_buf, 512, "cross-module CDefine lookup failed: SHA1 %s is not in the store (base_mod=%s name=%s). " "Phase1/Phase2 did not correctly populate PopulateSha1MapStore/AppendToSha1MapStore", sha1, base_mod, name)
|
||||
VLogger.error(err_buf, "XMOD-CD")
|
||||
stdlib.free(pyi_buf)
|
||||
return -1
|
||||
@@ -861,7 +861,7 @@ novirtual class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
if use_ctx is not None:
|
||||
# this language's str is i8* with no `str + str`: `+` degrades to pointer add.
|
||||
# Build strings with f-string interpolation / string.strcat / viperlib.snprintf.
|
||||
ctx = f"({use_ctx})"
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"[TPV] define 常量使用处宽度不足: 常量 '{name}' 的实际值 {value} " f"需要至少 {wmin} 位(最小可容纳宽度 W_min)," f"但使用处{ctx}只提供 {bits} 位" f"(该位宽按有符号/无符号两种解释可接受的范围: {lo}..{hi})。" f"禁止静默截断/降级,已终止编译。" f"修法: 把使用处{ctx}的类型加宽到至少 {wmin} 位" f"(如 int{wmin}T / CUInt{wmin}T 及更宽类型),或改用更小的常量值。", "TypeError")
|
||||
ctx = f"({use_ctx})"
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"[TPV] define constant use site width insufficient: constant '{name}' actual value {value} " f"needs at least {wmin} bits (minimum representable width W_min), " f"but the use site{ctx} provides only {bits} bits " f"(the acceptable range for this bit width under both signed/unsigned interpretation: {lo}..{hi}). " f"silent truncation/downgrade is forbidden, compilation aborted. " f"fix: widen the type of the use site{ctx} to at least {wmin} bits " f"(e.g. int{wmin}T / CUInt{wmin}T or wider types), or use a smaller constant value.", "TypeError")
|
||||
return None
|
||||
return mlirlite.const_int(pool, bits, self._cdefine_bits_value(value, bits))
|
||||
@@ -188,11 +188,11 @@ novirtual class ExprGenConst(ExprGenBase.ExprGenBase):
|
||||
first_elem_val = self.Gen.ExprGen.translate_value(builder, pool, mod, first_elem_node, None, 0, trans)
|
||||
if first_elem_val is None or first_elem_val.Ty is None:
|
||||
# fail-fast: first-element translation failed/Value type missing -> abort now (surface root cause)
|
||||
self.Gen.TypeGenErr.fatal_error(first_elem_node, "list 字面量元素类型推断失败(Value 类型缺失)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(first_elem_node, "list literal element type inference failed (Value type missing)", "TypeError")
|
||||
inferred_type_name = self._infer_elem_type_from_value(pool, first_elem_val)
|
||||
if inferred_type_name is None:
|
||||
# fail-fast: first-element Value type cannot map to a list element type -> abort now
|
||||
self.Gen.TypeGenErr.fatal_error(first_elem_node, "list 字面量元素类型推断失败(Value 类型缺失)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(first_elem_node, "list literal element type inference failed (Value type missing)", "TypeError")
|
||||
else:
|
||||
# Empty list has no element to infer, keep default str (list[str])
|
||||
inferred_type_name = "str"
|
||||
|
||||
@@ -52,7 +52,7 @@ novirtual class ExprGenFstr(ExprGenBase.ExprGenBase):
|
||||
val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, fv.value, None, 0, trans)
|
||||
if val is None:
|
||||
# fail-fast: a failed formatted-value translation must abort compilation
|
||||
self.Gen.TypeGenErr.fatal_error(fv.value, "f-string 格式化值翻译失败(表达式返回 None)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(fv.value, "f-string formatted value translation failed (expression returned None)", "TypeError")
|
||||
continue
|
||||
# Object defines __str__ and no format is given -> use its returned string (like TPC)
|
||||
if fv.format_spec is None:
|
||||
@@ -64,7 +64,7 @@ novirtual class ExprGenFstr(ExprGenBase.ExprGenBase):
|
||||
if c_fmt is None: c_fmt = self._fstr_infer_c_fmt(pool, val, fv.value, trans)
|
||||
if c_fmt is None:
|
||||
# fail-fast: cannot infer the f-string format (missing value type); abort
|
||||
self.Gen.TypeGenErr.fatal_error(fv.value, "f-string 格式无法推断(值类型缺失)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(fv.value, "f-string format cannot be inferred (value type missing)", "TypeError")
|
||||
# Append the format specifier
|
||||
if string.strlen(fmt_buf) + string.strlen(c_fmt) < FSTR_BUF_SIZE - 1: string.strcat(fmt_buf, c_fmt)
|
||||
# Convert the argument type (i8/i16->i32, bool->i32, f32->f64)
|
||||
@@ -91,7 +91,7 @@ novirtual class ExprGenFstr(ExprGenBase.ExprGenBase):
|
||||
val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, fv.value, None, 0, trans)
|
||||
if val is None:
|
||||
# fail-fast: a failed bare FormattedValue translation must abort compilation
|
||||
self.Gen.TypeGenErr.fatal_error(fv.value, "f-string 格式化值翻译失败(表达式返回 None)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(fv.value, "f-string formatted value translation failed (expression returned None)", "TypeError")
|
||||
else:
|
||||
# Object defines __str__ and no format is given -> use its returned string (like TPC)
|
||||
if fv.format_spec is None:
|
||||
@@ -102,7 +102,7 @@ novirtual class ExprGenFstr(ExprGenBase.ExprGenBase):
|
||||
if c_fmt is None: c_fmt = self._fstr_infer_c_fmt(pool, val, fv.value, trans)
|
||||
if c_fmt is None:
|
||||
# fail-fast: cannot infer the f-string format (missing value type); abort
|
||||
self.Gen.TypeGenErr.fatal_error(fv.value, "f-string 格式无法推断(值类型缺失)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(fv.value, "f-string format cannot be inferred (value type missing)", "TypeError")
|
||||
if string.strlen(fmt_buf) + string.strlen(c_fmt) < FSTR_BUF_SIZE - 1: string.strcat(fmt_buf, c_fmt)
|
||||
cast_val: mlirlite.Value* = self._fstr_cast_value(builder, pool, val, c_fmt, fv.value, trans)
|
||||
if cast_val is None: cast_val = val
|
||||
@@ -343,7 +343,7 @@ novirtual class ExprGenFstr(ExprGenBase.ExprGenBase):
|
||||
if fbits != 0: return "%f"
|
||||
if self.Gen.ExprGenBase.is_ptr_type(val.Ty) != 0: return "%s"
|
||||
# fail-fast: missing value type (not int/float/pointer); cannot infer the C format
|
||||
self.Gen.TypeGenErr.fatal_error(arg_node, "f-string 格式无法推断(值类型缺失)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(arg_node, "f-string format cannot be inferred (value type missing)", "TypeError")
|
||||
return None
|
||||
def _fstr_cast_value(self, builder: mlirlite.IRBuilder*, pool: memhub.MemBuddy*, val: mlirlite.Value*, c_fmt: str, arg_node: ast.AST*, trans: HT.Translator*) -> mlirlite.Value*:
|
||||
"""Cast the value to the type required by the C format specifier."""
|
||||
|
||||
@@ -32,7 +32,7 @@ novirtual class ExprGenMixin(ExprGenBase.ExprGenBase):
|
||||
"""Translate a value expression to an LLVM Value (depth-guard wrapper; see _translate_value_impl).
|
||||
target_ty = assignment/parameter type context; use_ctx = real call site for CDefine width checks."""
|
||||
if trans is not None:
|
||||
if trans.TranslateDepth >= HT.TRANSLATE_MAX_DEPTH: self.Gen.TypeGenErr.fatal_error(node, "表达式翻译嵌套过深(疑似 AST 自引用环或翻译 bug)", "RecursionError")
|
||||
if trans.TranslateDepth >= HT.TRANSLATE_MAX_DEPTH: self.Gen.TypeGenErr.fatal_error(node, "expression translation nested too deep (suspected AST self-reference cycle or translation bug)", "RecursionError")
|
||||
trans.TranslateDepth += 1
|
||||
rv: mlirlite.Value* = self._translate_value_impl(builder, pool, mod, node, funcs_ptr, func_count, trans, target_ty, use_ctx)
|
||||
if trans is not None: trans.TranslateDepth -= 1
|
||||
|
||||
@@ -49,7 +49,7 @@ novirtual class ExprGenName(ExprGenBase.ExprGenBase):
|
||||
# string (i8*) for `return ZLIB_VERSION`.
|
||||
cdef_sv: str = self.Gen.TypeGenCDef.lookup_cdefine_string(nm_id)
|
||||
if cdef_sv is not None: return self.Gen.ExprGenConst.create_global_string(builder, pool, mod, cdef_sv, trans)
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"CDefine 字符串值缺失: {nm_id}", "InternalCompilerError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"CDefine string value missing: {nm_id}", "InternalCompilerError")
|
||||
if self.Gen.TypeGenCDef.is_cdefine_double() != 0: return mlirlite.ConstFloat(pool, mlirlite.Double(pool), cdef_val_d)
|
||||
# Integer CDefine: re-look-up the full 64-bit value (a double round-trip loses
|
||||
# precision and would generate a wrong constant).
|
||||
@@ -72,7 +72,7 @@ novirtual class ExprGenName(ExprGenBase.ExprGenBase):
|
||||
if self.Gen.TypeGenCDef.is_cdefine_str() != 0:
|
||||
cdef_sv2: str = self.Gen.TypeGenCDef.lookup_cdefine_string(nm_id)
|
||||
if cdef_sv2 is not None: return self.Gen.ExprGenConst.create_global_string(builder, pool, mod, cdef_sv2, trans)
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"CDefine 字符串值缺失: {nm_id}", "InternalCompilerError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"CDefine string value missing: {nm_id}", "InternalCompilerError")
|
||||
# Cross-module float CDefine is cached as double; return a float constant
|
||||
# rather than a truncated integer.
|
||||
dchk_nm: double = self.Gen.TypeGenCDef.lookup_cdefine_double(nm_id)
|
||||
@@ -115,7 +115,7 @@ novirtual class ExprGenName(ExprGenBase.ExprGenBase):
|
||||
if mod_alloca.Ty is not None: load_ty = mod_alloca.Ty.Pointee
|
||||
if load_ty is None:
|
||||
# fail-fast: a global with a missing storage type aborts compilation
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"变量 '{nm_id}' 存储类型缺失", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"variable '{nm_id}' storage type missing", "TypeError")
|
||||
# Global arrays decay to the base address per C semantics; otherwise a loaded
|
||||
# array value passed as i8* loses writes (test_pyzlib "error message is empty").
|
||||
match load_ty:
|
||||
@@ -147,7 +147,7 @@ novirtual class ExprGenName(ExprGenBase.ExprGenBase):
|
||||
if alloca.Ty is not None: load_ty = alloca.Ty.Pointee
|
||||
if load_ty is None:
|
||||
# fail-fast: a local with a missing storage type aborts compilation
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"变量 '{nm_id}' 存储类型缺失", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"variable '{nm_id}' storage type missing", "TypeError")
|
||||
# Struct-value variable (alloca of Struct): rvalues return its address by default;
|
||||
# a value is loaded only when the use site demands a same-type struct value.
|
||||
match load_ty:
|
||||
@@ -195,7 +195,7 @@ novirtual class ExprGenName(ExprGenBase.ExprGenBase):
|
||||
fn_ret_ty: mlirlite.LLVMType* = mlirlite.function_get_ret_ty(fn_ref)
|
||||
if fn_ret_ty is None:
|
||||
# fail-fast: a missing function return type prevents building the function pointer
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"函数 '{nm_id}' 返回类型缺失,无法构造函数指针", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"function '{nm_id}' return type missing, cannot build the function pointer", "TypeError")
|
||||
fn_pp: mlirlite.Param* = mlirlite.function_get_param_head(fn_ref)
|
||||
fn_first_node: mlirlite.ParamNode* = None
|
||||
fn_prev_node: mlirlite.ParamNode* = None
|
||||
@@ -278,8 +278,8 @@ novirtual class ExprGenName(ExprGenBase.ExprGenBase):
|
||||
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")
|
||||
ctx_txt = f"(current generic context: {ctp_n} type params / {cta_n} type args)"
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"undefined name '{nm_id}'{ctx_txt}", "NameError")
|
||||
return None
|
||||
# list_getitem_inline - inline list[T] __getitem__; returns the element address (i8*).
|
||||
# Layout (6 fields x 8 bytes): __data__(0) __count__(8) __capacity__(16) __pool__(24) __elem_size__(32) __iter_index__(40).
|
||||
|
||||
@@ -57,7 +57,7 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase):
|
||||
then_blk_for_phi: mlirlite.BasicBlock* = trans._cur_builder.CurBlock
|
||||
if body_val is None:
|
||||
# fail-fast: ternary then-branch translation failed; abort compilation (expose the upstream root cause)
|
||||
self.Gen.TypeGenErr.fatal_error(ie.body, "三元表达式分支翻译失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(ie.body, "ternary expression branch translation failed", "TypeError")
|
||||
# Do not br yet; br after type alignment
|
||||
|
||||
# 5. else branch. When the then-branch is a pointer, pass its type as the else target-type context: a single-quoted
|
||||
@@ -69,7 +69,7 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase):
|
||||
else_blk_for_phi: mlirlite.BasicBlock* = trans._cur_builder.CurBlock
|
||||
if orelse_val is None:
|
||||
# fail-fast: ternary else-branch translation failed; abort compilation (expose the upstream root cause)
|
||||
self.Gen.TypeGenErr.fatal_error(ie.orelse, "三元表达式分支翻译失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(ie.orelse, "ternary expression branch translation failed", "TypeError")
|
||||
# Do not br yet; br after type alignment
|
||||
|
||||
# Type alignment (the two branches may differ): coerce_to_type must run inside each branch so the merge block's
|
||||
@@ -110,7 +110,7 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase):
|
||||
phi_ty: mlirlite.LLVMType* = body_val.Ty
|
||||
if phi_ty is None:
|
||||
# fail-fast: ternary branch type missing; abort compilation (expose the upstream root cause)
|
||||
self.Gen.TypeGenErr.fatal_error(node, "三元表达式分支类型缺失", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, "ternary expression branch type missing", "TypeError")
|
||||
|
||||
inc1: mlirlite.PhiIncoming* = mlirlite.new_phi_incoming(pool, body_val, then_blk_for_phi)
|
||||
inc2: mlirlite.PhiIncoming* = mlirlite.new_phi_incoming(pool, orelse_val, else_blk_for_phi)
|
||||
@@ -438,7 +438,7 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase):
|
||||
elif rhs_ptr_level != 0 and lhs_ptr_level == 0: rhs = mlirlite.build_ptrtoint(builder, rhs, lhs.Ty)
|
||||
else:
|
||||
# Different-level pointers (1 vs 2 etc.) -> forbidden (fail-fast)
|
||||
self.Gen.TypeGenErr.fatal_error(cmp, f"比较类型不匹配: 不同级指针比较 (lhs 层级={lhs_ptr_level}, rhs 层级={rhs_ptr_level})", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(cmp, f"comparison type mismatch: pointers of different levels compared (lhs level={lhs_ptr_level}, rhs level={rhs_ptr_level})", "TypeError")
|
||||
else:
|
||||
# None comparison: the None side is implicitly 0/null, its form decided by the other side.
|
||||
# pointer -> same-type null pointer (icmp eq/ne); integer -> 0 (x == 0); struct value -> never None (== false, != true).
|
||||
@@ -576,7 +576,7 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase):
|
||||
d_pointee: mlirlite.LLVMType* = operand.Ty.Pointee
|
||||
if d_pointee is not None: return mlirlite.build_load(builder, d_pointee, operand)
|
||||
# Non-pointer means type inference degraded: fail-fast, never fall back to reading as i8
|
||||
self.Gen.TypeGenErr.fatal_error(node, "单目 '*' 解引用的操作数必须是指针类型(类型推断退化)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, "the operand of unary '*' dereference must be a pointer type (type inference degraded)", "TypeError")
|
||||
return None
|
||||
elif uo.op == ast.OpKind.AddrOf:
|
||||
# &x -> lvalue address (no load): Name alloca / module global / module function / Attribute field GEP / Subscript element address.
|
||||
@@ -649,7 +649,7 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase):
|
||||
# a ctor call would re-run __before_init__/__init__). See _addrof_of_call.
|
||||
ac_ao: mlirlite.Value* = self._addrof_of_call(builder, pool, operand)
|
||||
if ac_ao is not None: return ac_ao
|
||||
self.Gen.TypeGenErr.fatal_error(node, "单目 '&' 取地址的操作数必须是左值(Name/Attribute/Subscript)或构造调用/函数调用结果", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, "the operand of unary '&' address-of must be an lvalue (Name/Attribute/Subscript) or a constructor/function call result", "TypeError")
|
||||
return None
|
||||
return operand
|
||||
|
||||
@@ -1055,7 +1055,7 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase):
|
||||
if is_aug != 0:
|
||||
# Augmented assignment: build the "+=" form with an f-string (this language's str has no `+` concatenation).
|
||||
op_lbl = f"{op_ch}="
|
||||
aug_note = "(增量赋值)"
|
||||
aug_note = "(augmented assignment)"
|
||||
lty_buf: str = pool.alloc(512)
|
||||
rty_buf: str = pool.alloc(512)
|
||||
lty_lbl: str = "?"
|
||||
@@ -1070,7 +1070,7 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase):
|
||||
if string.strcmp(rty_buf, "i8*") == 0: rty_lbl = "str(i8*)"
|
||||
col_s: int = 0
|
||||
if node is not None: col_s = node.col_offset + 1
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"[TPV] 双指针运算类型非法: op = '{op_lbl}'{aug_note}," f"左操作数类型 = {lty_lbl},右操作数类型 = {rty_lbl}。" f"本语言的 str 是 i8*,没有 `+` 拼接语义(`str + str` 与指针 ± 指针" f"都会退化成裸指针 add/sub ⇒ 非法 IR: opt 报 " f"invalid operand type for instruction)。" f"禁止静默降级,已终止编译。" f"修法: 用 f-string 插值、string.strcat 或 viperlib.snprintf 构建字符串。", "TypeError", col_s, col_s)
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"[TPV] illegal double-pointer arithmetic type: op = '{op_lbl}'{aug_note}, " f"left operand type = {lty_lbl}, right operand type = {rty_lbl}. " f"in this language str is i8*, with no `+` concatenation semantics (`str + str` and pointer +/- pointer " f"both degrade to raw pointer add/sub => illegal IR: opt reports " f"invalid operand type for instruction). " f"silent degradation is forbidden, compilation aborted. " f"fix: build strings with f-string interpolation, string.strcat, or viperlib.snprintf.", "TypeError", col_s, col_s)
|
||||
return 1
|
||||
# translate_binop - binary operations with automatic type promotion
|
||||
# ============================================================
|
||||
@@ -1179,7 +1179,7 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase):
|
||||
if lhs_bits == 0 and rhs_bits == 0:
|
||||
if op == ast.OpKind.BitOr or op == ast.OpKind.BitAnd or op == ast.OpKind.BitXor or op == ast.OpKind.LShift or op == ast.OpKind.RShift:
|
||||
# fail-fast: illegal bitwise operand types; abort compilation (expose the upstream root cause)
|
||||
self.Gen.TypeGenErr.fatal_error(node, "位运算操作数类型非法: lhs/rhs 均为非整数类型(指针或结构体),无法执行位运算", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, "illegal bitwise operand types: both lhs/rhs are non-integer types (pointer or struct), cannot perform bitwise operations", "TypeError")
|
||||
|
||||
if op == ast.OpKind.Add: return mlirlite.build_add(builder, lhs, rhs)
|
||||
elif op == ast.OpKind.Sub: return mlirlite.build_sub(builder, lhs, rhs)
|
||||
|
||||
@@ -251,7 +251,7 @@ novirtual class FuncGenBase(CallGenBase.CallGenBase):
|
||||
elif rcr_deco.kind() == ast.ASTKind.Attribute: rcr_attr = ast.Attribute*(rcr_deco)
|
||||
if rcr_attr is None or rcr_attr.attr is None: continue
|
||||
if string.strcmp(rcr_attr.attr, "CReturn") == 0:
|
||||
self.Gen.TypeGenErr.fatal_error(node, "`@c.CReturn` 已移除:请改用返回注解 `-> tuple[ty1, ty2, ...]`(多返回值打包为 struct 返回)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, "`@c.CReturn` removed: use a return annotation `-> tuple[ty1, ty2, ...]` instead (multiple return values are packed into a struct return)", "TypeError")
|
||||
return 1
|
||||
return 0
|
||||
# Create LLVM function (simple version, declaration only)
|
||||
@@ -282,7 +282,7 @@ novirtual class FuncGenBase(CallGenBase.CallGenBase):
|
||||
if resolved is None:
|
||||
# [S4 fail-fast] Annotation present but unresolvable: no silent i32 fallback.
|
||||
# This fn lacks trans/imports context, so failure surfaces upstream.
|
||||
self.Gen.TypeGenErr.fatal_error(arg, f"函数 '{name}' 形参 '{arg.arg}' 类型注解解析失败", "NameError")
|
||||
self.Gen.TypeGenErr.fatal_error(arg, f"function '{name}' param '{arg.arg}' type annotation failed to resolve", "NameError")
|
||||
return None
|
||||
param_ty = resolved
|
||||
pname: str = pool.alloc(32)
|
||||
|
||||
@@ -93,7 +93,7 @@ novirtual class FuncGenDef(CallGenBase.CallGenBase):
|
||||
if ret_ty is None and fd.returns is not None:
|
||||
# Return annotation present but unresolvable: compile-time error, no silent i32 fallback
|
||||
# (that forced return i32 and misaligned cross-module return types). No annotation keeps i32.
|
||||
self.Gen.TypeGenErr.fatal_error(fd, "函数返回类型解析失败:注解不可解析", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(fd, "function return type resolution failed: annotation is not resolvable", "TypeError")
|
||||
return 0
|
||||
if ret_ty is None: ret_ty = i32_ty
|
||||
|
||||
@@ -178,7 +178,7 @@ novirtual class FuncGenDef(CallGenBase.CallGenBase):
|
||||
if resolved is None:
|
||||
# [S4 fail-fast] Annotation present but unresolvable: no silent i32
|
||||
# (declare/define signature mismatch -> ABI misalignment, runtime reads garbage from the stack)
|
||||
self.Gen.TypeGenErr.fatal_error(arg, f"前向声明形参 '{arg.arg}' 类型注解解析失败", "NameError")
|
||||
self.Gen.TypeGenErr.fatal_error(arg, f"forward declaration param '{arg.arg}' type annotation failed to resolve", "NameError")
|
||||
return 0
|
||||
# Bare class param -> Ptr(struct) (object is a pointer); CArray param -> element pointer ty* (C array decay).
|
||||
# Exception (keep in sync in 3 places): C ABI extern bare struct params pass by value %Struct with a full definition.
|
||||
@@ -186,7 +186,7 @@ novirtual class FuncGenDef(CallGenBase.CallGenBase):
|
||||
case mlirlite.LLVMType.Void():
|
||||
# void is not a legal param type (void is only for void* and typedef of an opaque struct);
|
||||
# fail-fast at compile time instead of emitting invalid IR. `void*` is already i8* upstream.
|
||||
self.Gen.TypeGenErr.fatal_error(arg, f"形参 '{arg.arg}' 不能是 void 类型(void 只能用于 void* 与 typedef 别名)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(arg, f"param '{arg.arg}' cannot be void type (void is only allowed for void* and typedef aliases)", "TypeError")
|
||||
return 0
|
||||
case mlirlite.LLVMType.Struct(_, _, _):
|
||||
if is_extern_decl != 0 and self.Gen.StructGen.find_struct_by_type(resolved) is not None:
|
||||
@@ -268,10 +268,10 @@ novirtual class FuncGenDef(CallGenBase.CallGenBase):
|
||||
if self.Gen.TypeGenErr.body_has_value_return(pool, fd.children) != 0:
|
||||
rtn_err: str = pool.alloc(256)
|
||||
if rtn_err is not None:
|
||||
viperlib.snprintf(rtn_err, 256, "函数 '%s' 无返回类型注解却返回了非 None 值,请添加显式返回类型注解(如 -> int)", fd.name)
|
||||
viperlib.snprintf(rtn_err, 256, "function '%s' has no return type annotation but returns a non-None value, add an explicit return type annotation (e.g. -> int)", fd.name)
|
||||
self.Gen.TypeGenErr.fatal_error(fd, rtn_err, "TypeError")
|
||||
return 0
|
||||
self.Gen.TypeGenErr.fatal_error(fd, "函数无返回类型注解却返回了非 None 值", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(fd, "function has no return type annotation but returns a non-None value", "TypeError")
|
||||
return 0
|
||||
param_types_str: str = self.Gen.TypeGenErr.build_param_types_str(pool, fd.args)
|
||||
ret_ty = self.Gen.TypeGenErr.infer_return_type(pool, fd.children, param_types_str)
|
||||
@@ -375,7 +375,7 @@ novirtual class FuncGenDef(CallGenBase.CallGenBase):
|
||||
if resolved_e is None:
|
||||
# fail-fast: extern function param has an annotation but is unresolvable; no silent i32
|
||||
# (a wrong declare signature shows up at the ABI layer)
|
||||
self.Gen.TypeGenErr.fatal_error(arg_e, f"参数 '{arg_e.arg}' 类型解析失败: {self.Gen.TypeGenResolve.annotation_to_str(arg_e.annotation)}", "NameError")
|
||||
self.Gen.TypeGenErr.fatal_error(arg_e, f"argument '{arg_e.arg}' failed to resolve type: {self.Gen.TypeGenResolve.annotation_to_str(arg_e.annotation)}", "NameError")
|
||||
resolved_e = i32_ty # unreachable (fatal_error already exited)
|
||||
if resolved_e is not None:
|
||||
# Bare class param -> Ptr(struct); CArray param -> element pointer ty* (C decay). This branch is
|
||||
@@ -383,7 +383,7 @@ novirtual class FuncGenDef(CallGenBase.CallGenBase):
|
||||
match resolved_e:
|
||||
case mlirlite.LLVMType.Void():
|
||||
# void is not a legal param type (see the same rule above)
|
||||
self.Gen.TypeGenErr.fatal_error(arg_e, f"形参 '{arg_e.arg}' 不能是 void 类型(void 只能用于 void* 与 typedef 别名)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(arg_e, f"param '{arg_e.arg}' cannot be void type (void is only allowed for void* and typedef aliases)", "TypeError")
|
||||
case mlirlite.LLVMType.Struct(_, _, _):
|
||||
if self.Gen.StructGen.find_struct_by_type(resolved_e) is not None:
|
||||
self.Gen.StructGen.ensure_struct_def_in_module(pool, mod, resolved_e)
|
||||
@@ -473,14 +473,14 @@ novirtual class FuncGenDef(CallGenBase.CallGenBase):
|
||||
if resolved is None:
|
||||
# [S4 fail-fast] Annotation present but unresolvable: no silent i32
|
||||
# (wrong param type -> ABI misalignment / wrong field access)
|
||||
self.Gen.TypeGenErr.fatal_error(arg, f"形参 '{arg.arg}' 类型注解解析失败", "NameError")
|
||||
self.Gen.TypeGenErr.fatal_error(arg, f"param '{arg.arg}' type annotation failed to resolve", "NameError")
|
||||
return 0
|
||||
# Bare class param -> Ptr(struct); CArray param -> element pointer ty* (C array decay). Passing
|
||||
# Ptr(array) would make out[i]'s GEP stride by the whole array (garbage summary root cause).
|
||||
match resolved:
|
||||
case mlirlite.LLVMType.Void():
|
||||
# void is not a legal param type (see the same rule above)
|
||||
self.Gen.TypeGenErr.fatal_error(arg, f"形参 '{arg.arg}' 不能是 void 类型(void 只能用于 void* 与 typedef 别名)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(arg, f"param '{arg.arg}' cannot be void type (void is only allowed for void* and typedef aliases)", "TypeError")
|
||||
return 0
|
||||
case mlirlite.LLVMType.Struct(_, _, _):
|
||||
param_ty = mlirlite.Ptr(pool, resolved)
|
||||
@@ -596,7 +596,7 @@ novirtual class FuncGenDef(CallGenBase.CallGenBase):
|
||||
resolved2: mlirlite.LLVMType* = self.Gen.TypeGenResolve.resolve_annotation_type(pool, arg2.annotation, imported_modules, from_imports, trans, 0)
|
||||
if resolved2 is None:
|
||||
# fail-fast: param has an annotation but is unresolvable; no silent i32
|
||||
self.Gen.TypeGenErr.fatal_error(arg2, f"参数 '{arg2.arg}' 类型解析失败: {self.Gen.TypeGenResolve.annotation_to_str(arg2.annotation)}", "NameError")
|
||||
self.Gen.TypeGenErr.fatal_error(arg2, f"argument '{arg2.arg}' failed to resolve type: {self.Gen.TypeGenResolve.annotation_to_str(arg2.annotation)}", "NameError")
|
||||
resolved2 = i32_ty # unreachable (fatal_error already exited)
|
||||
if resolved2 is not None:
|
||||
# Consistent with add_param: bare class param -> Ptr(struct); CArray param -> element pointer ty*
|
||||
@@ -604,7 +604,7 @@ novirtual class FuncGenDef(CallGenBase.CallGenBase):
|
||||
match resolved2:
|
||||
case mlirlite.LLVMType.Void():
|
||||
# void is not a legal param type (see the same rule above)
|
||||
self.Gen.TypeGenErr.fatal_error(arg2, f"形参 '{arg2.arg}' 不能是 void 类型(void 只能用于 void* 与 typedef 别名)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(arg2, f"param '{arg2.arg}' cannot be void type (void is only allowed for void* and typedef aliases)", "TypeError")
|
||||
return 0
|
||||
case mlirlite.LLVMType.Struct(_, _, _):
|
||||
param_ty2 = mlirlite.Ptr(pool, resolved2)
|
||||
@@ -781,8 +781,8 @@ novirtual class FuncGenDef(CallGenBase.CallGenBase):
|
||||
if ret_ty is not None:
|
||||
zero_val: mlirlite.Value* = mlirlite.ConstZero(pool, ret_ty)
|
||||
if zero_val is not None: mlirlite.build_ret(func_builder, zero_val)
|
||||
else: self.Gen.TypeGenErr.fatal_error(node, "函数流程掉出末尾但未显式 return", "TypeError")
|
||||
else: self.Gen.TypeGenErr.fatal_error(node, "函数流程掉出末尾但未显式 return", "TypeError")
|
||||
else: self.Gen.TypeGenErr.fatal_error(node, "function flow falls off the end without an explicit return", "TypeError")
|
||||
else: self.Gen.TypeGenErr.fatal_error(node, "function flow falls off the end without an explicit return", "TypeError")
|
||||
else:
|
||||
# fail-fast: has a -> annotation but the flow falls off the end (pointing at the function definition
|
||||
# node; fatal_error prints a traceback-style error).
|
||||
@@ -795,10 +795,10 @@ novirtual class FuncGenDef(CallGenBase.CallGenBase):
|
||||
if rt_name[0] == '\0': rt_name = "?"
|
||||
err_fn: str = pool.alloc(256)
|
||||
if err_fn is not None:
|
||||
viperlib.snprintf(err_fn, 256, "函数 '%s' 流程掉出函数末尾但未显式 return(返回类型 %s),请补显式 return(如 return 0 / return null)", fd.name, rt_name)
|
||||
viperlib.snprintf(err_fn, 256, "function '%s' flow falls off the end of the function without an explicit return (return type %s), please add an explicit return (e.g. return 0 / return null)", fd.name, rt_name)
|
||||
self.Gen.TypeGenErr.fatal_error(node, err_fn, "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, "函数流程掉出末尾但未显式 return", "TypeError")
|
||||
else: self.Gen.TypeGenErr.fatal_error(node, "函数流程掉出末尾但未显式 return", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, "function flow falls off the end without an explicit return", "TypeError")
|
||||
else: self.Gen.TypeGenErr.fatal_error(node, "function flow falls off the end without an explicit return", "TypeError")
|
||||
|
||||
# Restore module-level scope (exit the function scope)
|
||||
self.Gen.VarGen.exit_scope(trans.SymTab)
|
||||
|
||||
@@ -674,7 +674,7 @@ novirtual class FuncGenMixin(CallGenBase.CallGenBase):
|
||||
"""Compute an LLVM type's byte size recursively"""
|
||||
if ty is None:
|
||||
# [S4 fail-fast] Missing type -> no longer assume 8 bytes (under-allocation overruns neighbors)
|
||||
self.Gen.TypeGenErr.fatal_error(None, "nonlocal 共享存储:类型缺失,无法计算尺寸", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(None, "nonlocal shared storage: type missing, cannot compute size", "TypeError")
|
||||
return 0
|
||||
match ty:
|
||||
case mlirlite.LLVMType.Int(bits):
|
||||
@@ -869,7 +869,7 @@ novirtual class FuncGenMixin(CallGenBase.CallGenBase):
|
||||
resolved: mlirlite.LLVMType* = self.Gen.TypeGenResolve.resolve_annotation_type(pool, arg_n.annotation, trans._imported_modules, trans._from_imports, trans, 0)
|
||||
if resolved is None:
|
||||
# fail-fast: annotated lambda param failed to resolve; do not silently keep i32
|
||||
self.Gen.TypeGenErr.fatal_error(arg_n, f"参数 '{arg_n.arg}' 类型解析失败: {self.Gen.TypeGenResolve.annotation_to_str(arg_n.annotation)}", "NameError")
|
||||
self.Gen.TypeGenErr.fatal_error(arg_n, f"argument '{arg_n.arg}' failed to resolve type: {self.Gen.TypeGenResolve.annotation_to_str(arg_n.annotation)}", "NameError")
|
||||
resolved = i32_ty # unreachable (fatal_error already exited)
|
||||
if resolved is not None:
|
||||
match resolved:
|
||||
@@ -980,7 +980,7 @@ novirtual class FuncGenMixin(CallGenBase.CallGenBase):
|
||||
p_ty3: mlirlite.LLVMType* = (mlirlite.LLVMType*)(ty_slot4[0])
|
||||
if p_ty3 is None:
|
||||
# fail-fast: lambda param type slot missing (inconsistent state); do not keep i32
|
||||
self.Gen.TypeGenErr.fatal_error(lam, f"lambda 参数 '{param_names + pi3 * 32}' 类型信息缺失", "InternalCompilerError")
|
||||
self.Gen.TypeGenErr.fatal_error(lam, f"lambda param '{param_names + pi3 * 32}' type info missing", "InternalCompilerError")
|
||||
p_ty3 = i32_ty # unreachable (fatal_error already exited)
|
||||
pname_ref: str = pool.alloc(32)
|
||||
if pname_ref is not None:
|
||||
@@ -1000,10 +1000,10 @@ novirtual class FuncGenMixin(CallGenBase.CallGenBase):
|
||||
if ret_val is not None: mlirlite.build_ret(func_builder, ret_val)
|
||||
else:
|
||||
# fail-fast: lambda body coercion failed; do not silently return 0
|
||||
self.Gen.TypeGenErr.fatal_error(lam.body, "lambda 体表达式翻译失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(lam.body, "lambda body expression translation failed", "TypeError")
|
||||
else:
|
||||
# fail-fast: lambda body translation failed; do not silently return 0
|
||||
self.Gen.TypeGenErr.fatal_error(lam.body, "lambda 体表达式翻译失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(lam.body, "lambda body expression translation failed", "TypeError")
|
||||
|
||||
# 12. Leave the lambda scope and restore the parent state
|
||||
self.Gen.VarGen.exit_scope(trans.SymTab)
|
||||
|
||||
@@ -443,7 +443,7 @@ def fail_if_fstring_escape(node: ast.AST*, where: str) -> int:
|
||||
break
|
||||
if hit == 0: return 0
|
||||
if _g_gen is not None:
|
||||
_g_gen.TypeGenErr.fatal_error(node, f"f-string 结果不能用于{where}(逃逸):f-string 指向**当前函数的栈缓冲**," f"函数返回即失效,把这个指针带出函数会读到已弹栈的帧" f"(历史事故:ASan stack-buffer-underflow in vsnprintf)。" f"需要带出函数时显式分配后拷贝:" f"tmp: str = f\"...\";out: str = GenApi.escape_fstring_copy(tmp);return out。", "TypeError")
|
||||
_g_gen.TypeGenErr.fatal_error(node, f"f-string result cannot be used in {where} (escape): f-string points at **the stack buffer of the current function**, " f"which becomes invalid once the function returns; carrying this pointer out of the function reads an already-popped frame" f"(historical incident: ASan stack-buffer-underflow in vsnprintf). " f"when the value must outlive the function, allocate and copy explicitly: " f"tmp: str = f\"...\"; out: str = GenApi.escape_fstring_copy(tmp); return out.", "TypeError")
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
@@ -401,7 +401,7 @@ novirtual class ImportsGenMixin:
|
||||
# Truncate at the last '.'
|
||||
new_pkg: str = pool.alloc(last_dot + 1)
|
||||
if new_pkg is None:
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"相对导入解析失败:level={level} module='{module}'", "ImportError")
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"relative import resolution failed: level={level} module='{module}'", "ImportError")
|
||||
return module
|
||||
string.strncpy(new_pkg, pkg, last_dot)
|
||||
new_pkg[last_dot] = '\0'
|
||||
@@ -419,7 +419,7 @@ novirtual class ImportsGenMixin:
|
||||
mod_len: sizet = string.strlen(module)
|
||||
buf: str = pool.alloc(pkg_len2 + 1 + mod_len + 1)
|
||||
if buf is None:
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"相对导入解析失败:level={level} module='{module}'", "ImportError")
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"relative import resolution failed: level={level} module='{module}'", "ImportError")
|
||||
return module
|
||||
string.strcpy(buf, pkg)
|
||||
buf[pkg_len2] = '.'
|
||||
@@ -549,9 +549,9 @@ novirtual class ImportsGenMixin:
|
||||
if self._is_local_module_file(mod_name) != 0: return 1
|
||||
err_buf: str = stdlib.malloc(256)
|
||||
if err_buf is not None:
|
||||
viperlib.snprintf(err_buf, 256, "模块 '%s' 未注册 SHA1(includes 扫描未找到该模块,请检查 project.json 的 includes 路径配置)", mod_name)
|
||||
viperlib.snprintf(err_buf, 256, "module '%s' has no registered SHA1 (the includes scan did not find this module; check the includes path configuration in project.json)", mod_name)
|
||||
self._report_import_error(node, err_buf)
|
||||
else: self._report_import_error(node, "导入模块 SHA1 未注册(includes 扫描未找到该模块)")
|
||||
else: self._report_import_error(node, "imported module SHA1 not registered (the includes scan did not find this module)")
|
||||
return 1
|
||||
|
||||
# translate_import - handle import statements and update trans._imported_modules
|
||||
@@ -623,7 +623,7 @@ novirtual class ImportsGenMixin:
|
||||
if sf_sha1 is None: return 0
|
||||
if string.strncmp(sf_sha1, trans.ModuleSha1, 16) == 0: return 0
|
||||
if self.Gen.CallGenBase.IsStaticSymbol(sf_sha1, orig_name) == 0: return 0
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"'{fi_target}.{orig_name}' 是 static 符号,禁止跨模块使用(static 仅限定义模块内可见)", "NameError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"'{fi_target}.{orig_name}' is a static symbol; cross-module use is forbidden (static is visible only within the defining module)", "NameError")
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ novirtual class MatchGenMixin:
|
||||
def translate_match(self, trans: HT.Translator*, node: ast.AST*) -> int:
|
||||
"""Translate one match statement; wraps _translate_match_impl with a depth guard."""
|
||||
if trans is not None:
|
||||
if trans.MatchTranslateDepth >= MATCH_TRANSLATE_MAX_DEPTH: self.Gen.TypeGenErr.fatal_error(node, "match 翻译嵌套过深(疑似 AST 自引用环或翻译 bug)", "RecursionError")
|
||||
if trans.MatchTranslateDepth >= MATCH_TRANSLATE_MAX_DEPTH: self.Gen.TypeGenErr.fatal_error(node, "match translation nested too deeply (suspected AST self-reference cycle or translation bug)", "RecursionError")
|
||||
trans.MatchTranslateDepth += 1
|
||||
mret: int = self._translate_match_impl(trans, node)
|
||||
if trans is not None: trans.MatchTranslateDepth -= 1
|
||||
@@ -91,11 +91,11 @@ novirtual class MatchGenMixin:
|
||||
if dcase2 is not None and dcase2.kind() == ast.ASTKind.MatchCase:
|
||||
dpat2: ast.AST* = ast.MatchCase*(dcase2).pattern
|
||||
if self._case_label_same(dpat, dpat2) != 0:
|
||||
self.Gen.TypeGenErr.fatal_error(dcase2, f"match 出现重名 case:第 {dci} 与第 {dcj} 个 case 的标签相同(match 不允许重复 case 标签)", "SyntaxError")
|
||||
self.Gen.TypeGenErr.fatal_error(dcase2, f"match has duplicate case names: case {dci} and case {dcj} carry the same label (match does not allow duplicate case labels)", "SyntaxError")
|
||||
dcj = dcj + 1
|
||||
dci = dci + 1
|
||||
if default_cnt > 1:
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"{kind_label} 出现 {default_cnt} 个{default_label}(无 guard 的通配/default 只允许一个;带 guard 的 `case _ if ...` / `default if ...` 可有多个)", "SyntaxError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"{kind_label} has {default_cnt} {default_label} arms (only one guardless wildcard/default is allowed; guarded `case _ if ...` / `default if ...` may appear multiple times)", "SyntaxError")
|
||||
|
||||
# 1. Evaluate the subject.
|
||||
subject_node: ast.AST* = m_node.subject
|
||||
@@ -106,7 +106,7 @@ novirtual class MatchGenMixin:
|
||||
subject_val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, subject_node, trans._funcs, trans._func_count, trans)
|
||||
if subject_val is None:
|
||||
# fail-fast: match subject translation failed.
|
||||
self.Gen.TypeGenErr.fatal_error(subject_node, "match subject 翻译失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(subject_node, "match subject translation failed", "TypeError")
|
||||
|
||||
# 2. Detect whether this is a REnum match.
|
||||
is_renum: int = 0
|
||||
@@ -280,7 +280,7 @@ novirtual class MatchGenMixin:
|
||||
rn_case: ast.AST* = rn_cases.get(rn_i)
|
||||
if rn_case is not None and rn_case.kind() == ast.ASTKind.MatchCase:
|
||||
if ast.MatchCase*(rn_case).guard is not None:
|
||||
self.Gen.TypeGenErr.fatal_error(rn_case, "REnum match 暂不支持 guard 守卫(该臂会被 switch(tag) 静默忽略);请改为普通 match 或去掉 guard", "NotImplementedError")
|
||||
self.Gen.TypeGenErr.fatal_error(rn_case, "REnum match does not yet support a guard (that arm would be silently ignored by switch(tag)); use a plain match or remove the guard", "NotImplementedError")
|
||||
rn_i = rn_i + 1
|
||||
|
||||
# 0. Normalize subject_ptr to a pointer to the REnum struct (aligns TPC HandlesMatch.py:238-259 _HandleRenumMatchLlvm).
|
||||
@@ -297,7 +297,7 @@ novirtual class MatchGenMixin:
|
||||
if renum_se is not None: renum_sty = renum_se.Ty
|
||||
if renum_sty is None:
|
||||
# fail-fast: REnum struct not registered, cannot construct.
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REnum 结构体 '{renum_name}' 未注册", "NameError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REnum struct '{renum_name}' not registered", "NameError")
|
||||
i64_ty0: mlirlite.LLVMType* = mlirlite.Int64(pool)
|
||||
int_val: mlirlite.Value* = subject_ptr
|
||||
# Widen/truncate non-i64 integers to i64 (inttoptr requires equal width); only when subj_ty is a known integer type.
|
||||
@@ -319,11 +319,11 @@ novirtual class MatchGenMixin:
|
||||
tag_ptr: mlirlite.Value* = mlirlite.build_bitcast(builder, subject_ptr, tag_ptr_ty)
|
||||
if tag_ptr is None:
|
||||
# fail-fast: REnum tag pointer cast failed.
|
||||
self.Gen.TypeGenErr.fatal_error(node, "REnum tag 指针转换失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, "REnum tag pointer cast failed", "TypeError")
|
||||
tag_val: mlirlite.Value* = mlirlite.build_load(builder, tag_ty, tag_ptr)
|
||||
if tag_val is None:
|
||||
# fail-fast: REnum tag load failed.
|
||||
self.Gen.TypeGenErr.fatal_error(node, "REnum tag 读取失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, "REnum tag read failed", "TypeError")
|
||||
|
||||
# 2. Create the default/end BBs.
|
||||
cnt: int = trans._label_counter
|
||||
@@ -331,7 +331,7 @@ novirtual class MatchGenMixin:
|
||||
name_buf: str = pool.alloc(32)
|
||||
if name_buf is None:
|
||||
# fail-fast: label buffer allocation failed.
|
||||
self.Gen.TypeGenErr.fatal_error(node, "标签缓冲区分配失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, "label buffer allocation failed", "TypeError")
|
||||
viperlib.snprintf(name_buf, 32, "match.default.%d", cnt)
|
||||
default_bb: mlirlite.BasicBlock* = mlirlite.create_block(pool, func, name_buf)
|
||||
viperlib.snprintf(name_buf, 32, "match.end.%d", cnt)
|
||||
@@ -341,7 +341,7 @@ novirtual class MatchGenMixin:
|
||||
cases_list: list[ast.AST*]* = node.cases
|
||||
if cases_list is None:
|
||||
# fail-fast: match cases missing.
|
||||
self.Gen.TypeGenErr.fatal_error(node, "match cases 缺失", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, "match cases missing", "TypeError")
|
||||
case_count: sizet = len(cases_list)
|
||||
|
||||
# BB pointer array, case-value pointer array, default-flag array, nobreak-flag array.
|
||||
@@ -353,7 +353,7 @@ novirtual class MatchGenMixin:
|
||||
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 or mc_arr is None:
|
||||
# fail-fast: match dispatch array allocation failed.
|
||||
self.Gen.TypeGenErr.fatal_error(node, "match 分派数组分配失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, "match dispatch array allocation failed", "TypeError")
|
||||
|
||||
collected: int = 0
|
||||
has_default: int = 0
|
||||
@@ -372,7 +372,7 @@ novirtual class MatchGenMixin:
|
||||
diag_tmp: str = pool.alloc(128)
|
||||
if miss_buf is None or diag_tmp is None:
|
||||
# fail-fast: diagnostics buffer allocation failed (same handling as name_buf above).
|
||||
self.Gen.TypeGenErr.fatal_error(node, "match 诊断缓冲区分配失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, "match diagnostics buffer allocation failed", "TypeError")
|
||||
miss_buf[0] = '\0'
|
||||
miss_cnt: int = 0
|
||||
# The variant table registers bare class names (ClassDef.name) while renum_name comes from the annotation form (Spec.SourceName; an Attribute may carry a module prefix like "mod.LLVMType"), so an exact strcmp would always miss and silently drop the arm. Strip the module prefix first.
|
||||
@@ -478,7 +478,7 @@ novirtual class MatchGenMixin:
|
||||
|
||||
# 5. Emit the switch. No silent case dropping: the number of must-submit arms (non-default MatchClass/MatchValue) must equal sw_count; a mismatch fail-fasts with class/lookup name/expected/actual and each missing arm's index(variant,tag).
|
||||
if need_case != sw_count:
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REnum match 分派丢失 case:class='{renum_name}'(查表名='{tag_cls_bare}')应提交 {need_case} 个 case,实际提交 {sw_count} 个;未取到值的臂:{miss_buf}", "InternalCompilerError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REnum match dispatch dropped cases: class='{renum_name}' (lookup name='{tag_cls_bare}') should submit {need_case} cases, actually submitted {sw_count}; arms with no value: {miss_buf}", "InternalCompilerError")
|
||||
mlirlite.build_switch(builder, tag_val, default_bb, sw_head, sw_count)
|
||||
|
||||
# 6. Find the REnum struct type (for variant-field GEP). Fall back to the bare class name because renum_name may carry a module prefix, and scan for an entry with a valid Ty since find_struct may hit a neutralized old entry (Ty=None).
|
||||
@@ -542,7 +542,7 @@ novirtual class MatchGenMixin:
|
||||
ent_fc = renum_entry.FieldCount
|
||||
ty_present: int = 0
|
||||
if renum_ty is not None: ty_present = 1
|
||||
self.Gen.TypeGenErr.fatal_error(pat, f"REnum match 变体字段绑定失败:class='{tag_cls_bare}'(查表名='{renum_name}')" f" entry='{ent_nm}' FieldCount={ent_fc} ty_present={ty_present};" f"变体表已登记该类,说明结构体条目或 Ty 缺失(已不再静默跳过绑定," f"否则绑定名未定义只会在下游报 NameError)", "InternalCompilerError")
|
||||
self.Gen.TypeGenErr.fatal_error(pat, f"REnum match variant field binding failed: class='{tag_cls_bare}' (lookup name='{renum_name}')" f" entry='{ent_nm}' FieldCount={ent_fc} ty_present={ty_present}; " f"the variant table has registered this class, so the struct entry or its Ty is missing (binding is no longer silently skipped, " f"otherwise an undefined binding name would only surface as a NameError downstream)", "InternalCompilerError")
|
||||
|
||||
# Translate the case body.
|
||||
body_list: list[ast.AST*]* = mc.children
|
||||
@@ -647,19 +647,19 @@ novirtual class MatchGenMixin:
|
||||
else:
|
||||
# fail-fast: payload out of range and alias lookup failed.
|
||||
# (node is not available here; locate via sub_pat. Under TPC Python an undefined name errors only at runtime, but TPV lazily compiling the method body raises NameError immediately.)
|
||||
self.Gen.TypeGenErr.fatal_error(sub_pat, f"REnum 变体字段 '{bind_name}' 在结构体 '{renum_name}' 中越界且别名查找失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(sub_pat, f"REnum variant field '{bind_name}' is out of range in struct '{renum_name}' and alias lookup failed", "TypeError")
|
||||
# Get the field type.
|
||||
fe: GenTypes.FieldEntry* = (self.Gen.StructGen._get_field_entry(renum_entry, payload_idx))
|
||||
field_ty: mlirlite.LLVMType* = None
|
||||
if fe is not None: field_ty = fe.Ty
|
||||
if field_ty is None:
|
||||
# fail-fast: variant field type missing; no i8 fallback allowed.
|
||||
self.Gen.TypeGenErr.fatal_error(sub_pat, f"REnum 变体字段类型缺失: {bind_name}", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(sub_pat, f"REnum variant field type missing: {bind_name}", "TypeError")
|
||||
# GEP to the field address.
|
||||
elem_ptr: mlirlite.Value* = mlirlite.build_gep_struct(builder, renum_ty, field_ty,casted_ptr, payload_idx)
|
||||
if elem_ptr is None:
|
||||
# fail-fast: variant field address computation failed.
|
||||
self.Gen.TypeGenErr.fatal_error(sub_pat, f"REnum 变体字段 '{bind_name}' 地址计算失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(sub_pat, f"REnum variant field '{bind_name}' address computation failed", "TypeError")
|
||||
# Actual variant-member type (aligns TPC class_members): the alias table stores the annotation-resolved member type, used to bitcast the slot address to Ptr(member type) so the binding reads the payload as the member type (otherwise i64 slot reads break is-comparison/index/strlen).
|
||||
# Must be located by (class, variant name, position): a MatchAs name is a local variable name, not a field name, so field-name lookup never matches, and the same payload position differs across variants. Falls back to the slot type when a self-referential type fails to resolve.
|
||||
mem_ty_m: mlirlite.LLVMType* = None
|
||||
@@ -721,7 +721,7 @@ novirtual class MatchGenMixin:
|
||||
elts_inl: list[ast.AST*]* = elts
|
||||
elt: ast.AST* = elts_inl.get(ei)
|
||||
sv: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, elt, trans._funcs, trans._func_count, trans)
|
||||
if sv is None: self.Gen.TypeGenErr.fatal_error(elt, f"match 序列元素 {ei} 翻译失败", "TypeError")
|
||||
if sv is None: self.Gen.TypeGenErr.fatal_error(elt, f"match sequence element {ei} translation failed", "TypeError")
|
||||
subj_vals[ei] = sizet(sv)
|
||||
|
||||
# 2. Create the default/end BBs.
|
||||
@@ -754,7 +754,7 @@ novirtual class MatchGenMixin:
|
||||
# Capacity guard (aligns the `collected < MAX_MATCH_CASES` check in the match-list paths): the default (case _) branch must also validate collected before writing check_arr/body_arr/def_arr/nb_arr/guard_arr, else too many cases overflow into adjacent pool blocks.
|
||||
# Over-limit fail-fasts, never silently dropping a case.
|
||||
if collected >= MAX_MATCH_CASES:
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"match case 数量超过上限 MAX_MATCH_CASES={MAX_MATCH_CASES}", "OverflowError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"match case count exceeds the limit MAX_MATCH_CASES={MAX_MATCH_CASES}", "OverflowError")
|
||||
break
|
||||
case_node: ast.AST* = cases_list.get(i)
|
||||
if case_node is None or case_node.kind() != ast.ASTKind.MatchCase:
|
||||
@@ -770,11 +770,11 @@ novirtual class MatchGenMixin:
|
||||
if ma0.pattern is None:
|
||||
# A top-level `case _ if <cond>`: this sequence path treats `_` as default (always true) and would silently ignore the guard; fail-fast before any IR is produced.
|
||||
if mc.guard is not None:
|
||||
self.Gen.TypeGenErr.fatal_error(pat, "序列匹配的顶层 `case _ if <cond>` 暂不支持 guard 守卫", "NotImplementedError")
|
||||
self.Gen.TypeGenErr.fatal_error(pat, "the top-level `case _ if <cond>` of a sequence match does not yet support a guard", "NotImplementedError")
|
||||
is_def = 1
|
||||
elif pk != ast.ASTKind.MatchSequence:
|
||||
# fail-fast: sequence matching accepts only MatchSequence / a top-level `_` wildcard.
|
||||
self.Gen.TypeGenErr.fatal_error(pat, "序列匹配 case 只支持 (元素) 或 _ 模式", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(pat, "a sequence-match case supports only an (element) or _ pattern", "TypeError")
|
||||
if is_def == 1:
|
||||
has_default = 1
|
||||
default_case_node = case_node
|
||||
@@ -836,10 +836,10 @@ novirtual class MatchGenMixin:
|
||||
if pk1 == ast.ASTKind.MatchValue:
|
||||
mv: ast.MatchValue* = (ast.MatchValue*)(pat1)
|
||||
pv: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, mv.value, trans._funcs, trans._func_count, trans)
|
||||
if pv is None: self.Gen.TypeGenErr.fatal_error(pat1, f"序列模式元素 {pi} 翻译失败", "TypeError")
|
||||
if pv is None: self.Gen.TypeGenErr.fatal_error(pat1, f"sequence pattern element {pi} translation failed", "TypeError")
|
||||
sv1: mlirlite.Value* = mlirlite.Value*(subj_vals[pi])
|
||||
c1: mlirlite.Value* = self._seq_cmp_eq(trans, builder, sv1, pv)
|
||||
if c1 is None: self.Gen.TypeGenErr.fatal_error(pat1, "序列模式元素比较失败", "TypeError")
|
||||
if c1 is None: self.Gen.TypeGenErr.fatal_error(pat1, "sequence pattern element comparison failed", "TypeError")
|
||||
if cond is None: cond = c1
|
||||
else: cond = mlirlite.build_and(builder, cond, c1)
|
||||
elif pk1 == ast.ASTKind.MatchAs:
|
||||
@@ -848,16 +848,16 @@ novirtual class MatchGenMixin:
|
||||
continue # `_` wildcard: always true
|
||||
if ma2.name is not None:
|
||||
# fail-fast: sequence-pattern variable binding not supported.
|
||||
self.Gen.TypeGenErr.fatal_error(pat1, "序列模式变量绑定暂不支持", "NotImplementedError")
|
||||
self.Gen.TypeGenErr.fatal_error(pat1, "sequence-pattern variable binding is not yet supported", "NotImplementedError")
|
||||
elif pk1 == ast.ASTKind.MatchStar:
|
||||
continue # remaining elements wildcard: always true
|
||||
else: self.Gen.TypeGenErr.fatal_error(pat1, "序列模式不支持的 pattern 类型", "TypeError")
|
||||
else: self.Gen.TypeGenErr.fatal_error(pat1, "unsupported pattern type in a sequence pattern", "TypeError")
|
||||
# guard (if any): match holds and guard is non-zero.
|
||||
g_addr: sizet = guard_arr[ci]
|
||||
if g_addr != 0:
|
||||
gnode: ast.AST* = (ast.AST*)(g_addr)
|
||||
gv: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, gnode, trans._funcs, trans._func_count, trans)
|
||||
if gv is None: self.Gen.TypeGenErr.fatal_error(gnode, "match guard 翻译失败", "TypeError")
|
||||
if gv is None: self.Gen.TypeGenErr.fatal_error(gnode, "match guard translation failed", "TypeError")
|
||||
gbits: int = self.Gen.ExprGenBase.get_llvm_type_bits(gv.Ty)
|
||||
if gbits == 1: g1: mlirlite.Value* = gv
|
||||
else:
|
||||
@@ -979,7 +979,7 @@ novirtual class MatchGenMixin:
|
||||
subj_val = mlirlite.build_ptrtoint(builder, subject_val, i32_ty)
|
||||
if subj_val is None:
|
||||
# fail-fast: subject-to-i32 conversion failed.
|
||||
self.Gen.TypeGenErr.fatal_error(node, "match subject 转换为 i32 失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, "match subject conversion to i32 failed", "TypeError")
|
||||
|
||||
# 1b. Guard pre-scan: any guarded arm switches to the in-order if-else chain (_handle_guarded_simple_match, Python match semantics).
|
||||
# Without guards, the existing switch path below stays byte-identical (no behavior change).
|
||||
@@ -1001,7 +1001,7 @@ novirtual class MatchGenMixin:
|
||||
name_buf: str = pool.alloc(32)
|
||||
if name_buf is None:
|
||||
# fail-fast: label buffer allocation failed.
|
||||
self.Gen.TypeGenErr.fatal_error(node, "标签缓冲区分配失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, "label buffer allocation failed", "TypeError")
|
||||
viperlib.snprintf(name_buf, 32, "match.default.%d", cnt)
|
||||
default_bb: mlirlite.BasicBlock* = mlirlite.create_block(pool, func, name_buf)
|
||||
viperlib.snprintf(name_buf, 32, "match.end.%d", cnt)
|
||||
@@ -1011,7 +1011,7 @@ novirtual class MatchGenMixin:
|
||||
cases_list: list[ast.AST*]* = node.cases
|
||||
if cases_list is None:
|
||||
# fail-fast: match cases missing.
|
||||
self.Gen.TypeGenErr.fatal_error(node, "match cases 缺失", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, "match cases missing", "TypeError")
|
||||
case_count: sizet = len(cases_list)
|
||||
|
||||
bb_arr: sizet* = pool.alloc(8 * MAX_MATCH_CASES)
|
||||
@@ -1022,7 +1022,7 @@ novirtual class MatchGenMixin:
|
||||
mo_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 or mo_arr is None:
|
||||
# fail-fast: match dispatch array allocation failed.
|
||||
self.Gen.TypeGenErr.fatal_error(node, "match 分派数组分配失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, "match dispatch array allocation failed", "TypeError")
|
||||
|
||||
collected: int = 0
|
||||
has_default: int = 0
|
||||
@@ -1073,7 +1073,7 @@ novirtual class MatchGenMixin:
|
||||
# If the class-pattern actually points to a registered REnum, REnum dispatch mismatched; fail-fast instead of silently dropping the case.
|
||||
rnm_nr: str = self._extract_renum_name_from_cls(pat)
|
||||
if rnm_nr is not None and (self.Gen.ClassGenEnum._is_renum_class_name(rnm_nr) != 0 or self.Gen.ClassGenEnum._is_renum_by_entry(rnm_nr) != 0):
|
||||
self.Gen.TypeGenErr.fatal_error(pat, f"非 REnum 路径收到 REnum 变体模式 'case {rnm_nr}.*':case 值无法产出,该臂会被静默丢弃(REnum 分派失配)", "InternalCompilerError")
|
||||
self.Gen.TypeGenErr.fatal_error(pat, f"the non-REnum path received a REnum variant pattern 'case {rnm_nr}.*': no case value can be produced, so the arm would be silently dropped (REnum dispatch mismatch)", "InternalCompilerError")
|
||||
|
||||
if is_def == 0:
|
||||
if collected >= MAX_MATCH_CASES: break
|
||||
@@ -1100,7 +1100,7 @@ novirtual class MatchGenMixin:
|
||||
# MatchOr arm: emit one case value per alternative, all pointing to the same bb (equivalent to C `case 1: case 2:` sharing a body); non-MatchValue/MatchSingleton alternatives fail-fast.
|
||||
mo2: ast.MatchOr* = (ast.MatchOr*)(mo_addr)
|
||||
pats2: list[ast.AST*]* = mo2.patterns
|
||||
if pats2 is None or len(pats2) == 0: self.Gen.TypeGenErr.fatal_error(pat, "switch OR 模式无备选子模式", "TypeError")
|
||||
if pats2 is None or len(pats2) == 0: self.Gen.TypeGenErr.fatal_error(pat, "switch OR pattern has no alternative sub-patterns", "TypeError")
|
||||
pats2_n: sizet = len(pats2)
|
||||
pats2_i: int = 0
|
||||
while pats2_i < pats2_n:
|
||||
@@ -1113,7 +1113,7 @@ novirtual class MatchGenMixin:
|
||||
elif alt_pat.kind() == ast.ASTKind.MatchSingleton:
|
||||
# None -> 0 (same as the single-value/guard paths).
|
||||
alt_cv = mlirlite.const_int32(pool, 0)
|
||||
else: self.Gen.TypeGenErr.fatal_error(alt_pat, "switch OR 模式备选不是值模式", "TypeError")
|
||||
else: self.Gen.TypeGenErr.fatal_error(alt_pat, "a switch OR pattern alternative is not a value pattern", "TypeError")
|
||||
if alt_cv is not None:
|
||||
sc2: mlirlite.SwitchCase* = mlirlite.new_switch_case(pool, alt_cv, bb)
|
||||
if sc2 is not None:
|
||||
@@ -1254,7 +1254,7 @@ novirtual class MatchGenMixin:
|
||||
cnt: int = trans._label_counter
|
||||
trans._label_counter = cnt + 1
|
||||
name_buf: str = pool.alloc(32)
|
||||
if name_buf is None: self.Gen.TypeGenErr.fatal_error(node, "标签缓冲区分配失败", "TypeError")
|
||||
if name_buf is None: self.Gen.TypeGenErr.fatal_error(node, "label buffer allocation failed", "TypeError")
|
||||
viperlib.snprintf(name_buf, 32, "match.guard.default.%d", cnt)
|
||||
default_bb: mlirlite.BasicBlock* = mlirlite.create_block(pool, func, name_buf)
|
||||
viperlib.snprintf(name_buf, 32, "match.guard.end.%d", cnt)
|
||||
@@ -1262,7 +1262,7 @@ novirtual class MatchGenMixin:
|
||||
|
||||
# 2. Collect case info (check/body BBs, default flag, nobreak, mc, cv).
|
||||
cases_list: list[ast.AST*]* = node.cases
|
||||
if cases_list is None: self.Gen.TypeGenErr.fatal_error(node, "match cases 缺失", "TypeError")
|
||||
if cases_list is None: self.Gen.TypeGenErr.fatal_error(node, "match cases missing", "TypeError")
|
||||
case_count: sizet = len(cases_list)
|
||||
check_arr: sizet* = pool.alloc(8 * MAX_MATCH_CASES)
|
||||
body_arr: sizet* = pool.alloc(8 * MAX_MATCH_CASES)
|
||||
@@ -1273,7 +1273,7 @@ novirtual class MatchGenMixin:
|
||||
# MatchOr node pointer per collected arm (0 = not MatchOr): the check chain turns `case 1 | 2` into an OR of subj_val == cv_i per alternative, so record the node and expand alternatives when emitting checks; non-MatchOr stays 0 on the single-cv path.
|
||||
or_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 mc_arr is None or cv_arr is None or or_arr is None:
|
||||
self.Gen.TypeGenErr.fatal_error(node, "match 分派数组分配失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, "match dispatch array allocation failed", "TypeError")
|
||||
collected: int = 0
|
||||
has_default: int = 0
|
||||
# The single guardless wildcard arm (default): its body is default_bb, the fall-through when all checks miss.
|
||||
@@ -1283,7 +1283,7 @@ novirtual class MatchGenMixin:
|
||||
i: int = 0
|
||||
while i < case_count:
|
||||
if collected >= MAX_MATCH_CASES:
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"match case 数量超过上限 MAX_MATCH_CASES={MAX_MATCH_CASES}", "OverflowError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"match case count exceeds the limit MAX_MATCH_CASES={MAX_MATCH_CASES}", "OverflowError")
|
||||
break
|
||||
case_node: ast.AST* = cases_list.get(i)
|
||||
if case_node is None or case_node.kind() != ast.ASTKind.MatchCase:
|
||||
@@ -1315,7 +1315,7 @@ novirtual class MatchGenMixin:
|
||||
or_node = pat
|
||||
else:
|
||||
# No silent fallback: the guard branch only supports value/None/wildcard/OR patterns.
|
||||
self.Gen.TypeGenErr.fatal_error(pat, "guard 分支不支持的 case 模式", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(pat, "unsupported case pattern in the guard branch", "TypeError")
|
||||
if is_def == 1:
|
||||
has_default = 1
|
||||
default_case_node = case_node
|
||||
@@ -1364,7 +1364,7 @@ novirtual class MatchGenMixin:
|
||||
# MatchOr arm: cond = (subj_val == cv_0) OR (subj_val == cv_1) OR ...; each alternative is compared then ORed (non-MatchValue/MatchSingleton alternatives cannot produce a value -> fail-fast).
|
||||
mo4: ast.MatchOr* = (ast.MatchOr*)(or_addr)
|
||||
pats4: list[ast.AST*]* = mo4.patterns
|
||||
if pats4 is None or len(pats4) == 0: self.Gen.TypeGenErr.fatal_error(node, "guard OR 模式无备选子模式", "TypeError")
|
||||
if pats4 is None or len(pats4) == 0: self.Gen.TypeGenErr.fatal_error(node, "guard OR pattern has no alternative sub-patterns", "TypeError")
|
||||
pats4_n: sizet = len(pats4)
|
||||
pats4_i: int = 0
|
||||
while pats4_i < pats4_n:
|
||||
@@ -1377,25 +1377,25 @@ novirtual class MatchGenMixin:
|
||||
elif alt_pat2.kind() == ast.ASTKind.MatchSingleton:
|
||||
# None -> 0 (same as the single-value path).
|
||||
alt_cv2 = mlirlite.const_int32(pool, 0)
|
||||
else: self.Gen.TypeGenErr.fatal_error(alt_pat2, "guard OR 模式备选不是值模式", "TypeError")
|
||||
else: self.Gen.TypeGenErr.fatal_error(alt_pat2, "a guard OR pattern alternative is not a value pattern", "TypeError")
|
||||
if alt_cv2 is not None:
|
||||
cc: mlirlite.Value* = self._seq_cmp_eq(trans, builder, subj_val, alt_cv2)
|
||||
if cc is None: self.Gen.TypeGenErr.fatal_error(node, "match OR 备选值比较失败", "TypeError")
|
||||
if cc is None: self.Gen.TypeGenErr.fatal_error(node, "match OR alternative value comparison failed", "TypeError")
|
||||
if cond is None: cond = cc
|
||||
else: cond = mlirlite.build_or(builder, cond, cc)
|
||||
pats4_i = pats4_i + 1
|
||||
if cond is None: self.Gen.TypeGenErr.fatal_error(node, "guard OR 模式未能产出任何比较条件", "TypeError")
|
||||
if cond is None: self.Gen.TypeGenErr.fatal_error(node, "the guard OR pattern produced no comparison condition", "TypeError")
|
||||
elif cv_addr != 0:
|
||||
cv2: mlirlite.Value* = (mlirlite.Value*)(cv_addr)
|
||||
c1: mlirlite.Value* = self._seq_cmp_eq(trans, builder, subj_val, cv2)
|
||||
if c1 is None: self.Gen.TypeGenErr.fatal_error(node, "match case 值比较失败", "TypeError")
|
||||
if c1 is None: self.Gen.TypeGenErr.fatal_error(node, "match case value comparison failed", "TypeError")
|
||||
cond = c1
|
||||
# guard (if any): match holds and guard is non-zero (normalized to i1, same as the sequence path).
|
||||
g_addr: sizet = sizet(mc2.guard)
|
||||
if g_addr != 0:
|
||||
gnode: ast.AST* = (ast.AST*)(g_addr)
|
||||
gv: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, gnode, trans._funcs, trans._func_count, trans)
|
||||
if gv is None: self.Gen.TypeGenErr.fatal_error(gnode, "match guard 翻译失败", "TypeError")
|
||||
if gv is None: self.Gen.TypeGenErr.fatal_error(gnode, "match guard translation failed", "TypeError")
|
||||
gbits: int = self.Gen.ExprGenBase.get_llvm_type_bits(gv.Ty)
|
||||
if gbits == 1: g1: mlirlite.Value* = gv
|
||||
else:
|
||||
|
||||
@@ -365,7 +365,7 @@ novirtual class StmtGenCifMixin:
|
||||
if rt.value is not None:
|
||||
# f-string escape (return f"..."): its buffer lives on this frame's stack and dies on
|
||||
# return; copy it out explicitly (GenApi.escape_fstring_copy) before returning it.
|
||||
GenApi.fail_if_fstring_escape(rt.value, "函数返回值")
|
||||
GenApi.fail_if_fstring_escape(rt.value, "function return value")
|
||||
# return a, b → pack an anonymous struct value (multi-return, return type tuple[T1,T2])
|
||||
if rt.value.kind() == ast.ASTKind.Tuple:
|
||||
rtp: ast.Tuple* = ast.Tuple*(rt.value)
|
||||
@@ -439,7 +439,7 @@ novirtual class StmtGenCifMixin:
|
||||
# [C1] return-annotation context: record this return's direct value node so a bare
|
||||
# generic ctor (`return Stack()` in `-> Stack[int]`) specializes via CurFuncRetAnnot.
|
||||
trans.CurRetNode = rt.value
|
||||
val = self.Gen.ExprGen.translate_value(builder, pool, mod, rt.value, trans._funcs, trans._func_count, trans, ret_val_ty, "返回注解")
|
||||
val = self.Gen.ExprGen.translate_value(builder, pool, mod, rt.value, trans._funcs, trans._func_count, trans, ret_val_ty, "return annotation")
|
||||
trans.CurRetNode = None
|
||||
|
||||
# val is None (bare return): emit per the function return type - void→ret void,
|
||||
@@ -473,11 +473,11 @@ novirtual class StmtGenCifMixin:
|
||||
return 0
|
||||
if ret_ty is None:
|
||||
# fail-fast: bare return with unknown return type; no hard-coded i32 fallback
|
||||
self.Gen.TypeGenErr.fatal_error(rt, "函数返回类型无法确定", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(rt, "cannot determine the function return type", "TypeError")
|
||||
val = mlirlite.ConstZero(pool, ret_ty)
|
||||
if val is None:
|
||||
# fail-fast: cannot build a zero value for the return type
|
||||
self.Gen.TypeGenErr.fatal_error(rt, "函数返回类型无法确定", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(rt, "cannot determine the function return type", "TypeError")
|
||||
|
||||
# coerce val to the function return type: i1→i8 etc. use zext (bool semantics, 1 stays 1);
|
||||
# int→ptr must use inttoptr even at equal bit width, else llc rejects the return type.
|
||||
@@ -587,7 +587,7 @@ novirtual class StmtGenCifMixin:
|
||||
# 2. coerce to i1 (prefer __bool__; Compare/Not already return i1)
|
||||
if cond_val is None:
|
||||
# fail-fast: if condition expression failed to translate
|
||||
self.Gen.TypeGenErr.fatal_error(if_node.test, "if 条件表达式翻译失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(if_node.test, "failed to translate the if condition expression", "TypeError")
|
||||
cond_i1: mlirlite.Value* = self.Gen.ExprGenOps.coerce_cond_to_bool(pool, builder, trans.Module, cond_val, trans)
|
||||
|
||||
# 3. create blocks (unique labels from trans._label_counter, not shared with SSA names)
|
||||
@@ -738,7 +738,7 @@ novirtual class StmtGenCifMixin:
|
||||
cond_val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, while_node.test, trans._funcs, trans._func_count, trans)
|
||||
if cond_val is None:
|
||||
# fail-fast: while condition expression failed to translate
|
||||
self.Gen.TypeGenErr.fatal_error(while_node.test, "while 条件表达式翻译失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(while_node.test, "failed to translate the while condition expression", "TypeError")
|
||||
|
||||
# coerce to i1 (prefer __bool__; Compare/Not already return i1)
|
||||
cond_i1: mlirlite.Value* = self.Gen.ExprGenOps.coerce_cond_to_bool(pool, builder, trans.Module, cond_val, trans)
|
||||
@@ -857,9 +857,9 @@ novirtual class StmtGenCifMixin:
|
||||
else:
|
||||
err_msg: str = pool.alloc(256)
|
||||
if err_msg is not None:
|
||||
viperlib.snprintf(err_msg, 256, "仅支持 range()/enumerate()/zip() 或指针迭代,got call '%s'", fn_pre)
|
||||
viperlib.snprintf(err_msg, 256, "only range()/enumerate()/zip() or pointer iteration is supported, got call '%s'", fn_pre)
|
||||
self.Gen.TypeGenErr.fatal_error(iter_node, err_msg)
|
||||
self.Gen.TypeGenErr.fatal_error(iter_node, "仅支持 range()/enumerate()/zip() 或指针迭代")
|
||||
self.Gen.TypeGenErr.fatal_error(iter_node, "only range()/enumerate()/zip() or pointer iteration is supported")
|
||||
|
||||
# non-range iteration: pointer / array / list-literal / container / multi-var paths
|
||||
if is_range_iter == 0:
|
||||
@@ -870,24 +870,24 @@ novirtual class StmtGenCifMixin:
|
||||
call_mi: ast.Call* = ast.Call*(iter_node)
|
||||
fn_mi: str = self.Gen.ExprGenBase.get_func_name(call_mi.func)
|
||||
if fn_mi is not None and string.strcmp(fn_mi, "enumerate") == 0:
|
||||
if tk != ast.ASTKind.Tuple: self.Gen.TypeGenErr.fatal_error(iter_node, "enumerate 迭代需要两个循环变量 (for i, v in enumerate(x))")
|
||||
if tk != ast.ASTKind.Tuple: self.Gen.TypeGenErr.fatal_error(iter_node, "enumerate iteration requires two loop variables (for i, v in enumerate(x))")
|
||||
tup_ie: ast.Tuple* = ast.Tuple*(target)
|
||||
t1_buf_ie: bytes = pool.alloc(128)
|
||||
t2_buf_ie: bytes = pool.alloc(128)
|
||||
if t1_buf_ie is None or t2_buf_ie is None: return 0
|
||||
t1_buf_ie[0] = '\0'
|
||||
t2_buf_ie[0] = '\0'
|
||||
if self._extract_tuple_names(tup_ie, t1_buf_ie, t2_buf_ie) == 0: self.Gen.TypeGenErr.fatal_error(iter_node, "enumerate 迭代变量必须是简单名称")
|
||||
if self._extract_tuple_names(tup_ie, t1_buf_ie, t2_buf_ie) == 0: self.Gen.TypeGenErr.fatal_error(iter_node, "enumerate iteration variables must be simple names")
|
||||
return self._handle_enumerate_iter(trans, for_node, t1_buf_ie, t2_buf_ie, call_mi)
|
||||
if fn_mi is not None and string.strcmp(fn_mi, "zip") == 0:
|
||||
if tk != ast.ASTKind.Tuple: self.Gen.TypeGenErr.fatal_error(iter_node, "zip 迭代需要两个循环变量 (for a, b in zip(...))")
|
||||
if tk != ast.ASTKind.Tuple: self.Gen.TypeGenErr.fatal_error(iter_node, "zip iteration requires two loop variables (for a, b in zip(...))")
|
||||
tup_iz: ast.Tuple* = ast.Tuple*(target)
|
||||
t1_buf_iz: bytes = pool.alloc(128)
|
||||
t2_buf_iz: bytes = pool.alloc(128)
|
||||
if t1_buf_iz is None or t2_buf_iz is None: return 0
|
||||
t1_buf_iz[0] = '\0'
|
||||
t2_buf_iz[0] = '\0'
|
||||
if self._extract_tuple_names(tup_iz, t1_buf_iz, t2_buf_iz) == 0: self.Gen.TypeGenErr.fatal_error(iter_node, "zip 迭代变量必须是简单名称")
|
||||
if self._extract_tuple_names(tup_iz, t1_buf_iz, t2_buf_iz) == 0: self.Gen.TypeGenErr.fatal_error(iter_node, "zip iteration variables must be simple names")
|
||||
return self._handle_zip_iter(trans, for_node, t1_buf_iz, t2_buf_iz, call_mi)
|
||||
# list[T] container variable: iterate by dynamic __count__
|
||||
if iter_node.kind() == ast.ASTKind.Name and trans is not None:
|
||||
@@ -929,9 +929,9 @@ novirtual class StmtGenCifMixin:
|
||||
ik: int = iter_node.kind()
|
||||
if ik == ast.ASTKind.Constant:
|
||||
cn_ik: ast.Constant* = ast.Constant*(iter_node)
|
||||
if cn_ik.const_kind != ast.CONST_STR: self.Gen.TypeGenErr.fatal_error(iter_node, "for 迭代不支持该常量(仅支持字符串、数组、列表字面量、range())")
|
||||
if cn_ik.const_kind != ast.CONST_STR: self.Gen.TypeGenErr.fatal_error(iter_node, "for iteration does not support this constant (only strings, arrays, list literals, range())")
|
||||
elif ik == ast.ASTKind.Dict or ik == ast.ASTKind.Set or ik == ast.ASTKind.Tuple or ik == ast.ASTKind.SetComp or ik == ast.ASTKind.DictComp:
|
||||
self.Gen.TypeGenErr.fatal_error(iter_node, "for 迭代不支持字典/集合/元组字面量,请使用 range()、t.CArray 数组或列表字面量")
|
||||
self.Gen.TypeGenErr.fatal_error(iter_node, "for iteration does not support dict/set/tuple literals; use range(), a t.CArray array, or a list literal")
|
||||
return self._handle_ptr_iter(trans, for_node, var_name)
|
||||
|
||||
call: ast.Call* = ast.Call*(iter_node)
|
||||
@@ -948,26 +948,26 @@ novirtual class StmtGenCifMixin:
|
||||
|
||||
if arg_count == 0:
|
||||
# fail-fast: range needs at least one argument
|
||||
self.Gen.TypeGenErr.fatal_error(call, "range 需要至少一个参数", "SyntaxError")
|
||||
self.Gen.TypeGenErr.fatal_error(call, "range requires at least one argument", "SyntaxError")
|
||||
elif arg_count == 1:
|
||||
stop_val = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, args.get(0), trans._funcs, trans._func_count, trans)
|
||||
if stop_val is None:
|
||||
# fail-fast: range argument failed to translate
|
||||
self.Gen.TypeGenErr.fatal_error(args.get(0), "range 参数翻译失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(args.get(0), "failed to translate the range argument", "TypeError")
|
||||
elif arg_count >= 2:
|
||||
start_val = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, args.get(0), trans._funcs, trans._func_count, trans)
|
||||
if start_val is None:
|
||||
# fail-fast: range argument failed to translate
|
||||
self.Gen.TypeGenErr.fatal_error(args.get(0), "range 参数翻译失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(args.get(0), "failed to translate the range argument", "TypeError")
|
||||
stop_val = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, args.get(1), trans._funcs, trans._func_count, trans)
|
||||
if stop_val is None:
|
||||
# fail-fast: range argument failed to translate
|
||||
self.Gen.TypeGenErr.fatal_error(args.get(1), "range 参数翻译失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(args.get(1), "failed to translate the range argument", "TypeError")
|
||||
if arg_count >= 3:
|
||||
step_val = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, args.get(2), trans._funcs, trans._func_count, trans)
|
||||
if step_val is None:
|
||||
# fail-fast: range argument failed to translate
|
||||
self.Gen.TypeGenErr.fatal_error(args.get(2), "range 参数翻译失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(args.get(2), "failed to translate the range argument", "TypeError")
|
||||
# a negative literal step inverts the loop test (TPC HandlesFor.py L86-94): range(a,b,-1)
|
||||
# uses i > stop. Only negative literals are detected; variable steps default to positive.
|
||||
step_neg_const: int = 0
|
||||
@@ -1208,7 +1208,7 @@ novirtual class StmtGenCifMixin:
|
||||
|
||||
# ---- source 1 setup ----
|
||||
kind1: int = self._seq_kind(trans, src1)
|
||||
if kind1 == 0: self.Gen.TypeGenErr.fatal_error(for_node, "序列迭代: 源 1 类型不支持")
|
||||
if kind1 == 0: self.Gen.TypeGenErr.fatal_error(for_node, "sequence iteration: source 1 type is not supported")
|
||||
r1_start: mlirlite.Value* = None
|
||||
r1_stop: mlirlite.Value* = None
|
||||
r1_step: mlirlite.Value* = None
|
||||
@@ -1231,28 +1231,28 @@ novirtual class StmtGenCifMixin:
|
||||
sv: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, cargs1.get(0), trans._funcs, trans._func_count, trans)
|
||||
if sv is None:
|
||||
# fail-fast: range argument failed to translate
|
||||
self.Gen.TypeGenErr.fatal_error(cargs1.get(0), "range 参数翻译失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(cargs1.get(0), "failed to translate the range argument", "TypeError")
|
||||
r1_stop = self.Gen.ExprGenBase.coerce_to_type(builder, sv, i64_ty, cargs1.get(0))
|
||||
if n1 >= 2:
|
||||
sv2: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, cargs1.get(1), trans._funcs, trans._func_count, trans)
|
||||
if sv2 is None:
|
||||
# fail-fast: range argument failed to translate
|
||||
self.Gen.TypeGenErr.fatal_error(cargs1.get(1), "range 参数翻译失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(cargs1.get(1), "failed to translate the range argument", "TypeError")
|
||||
r1_start = self.Gen.ExprGenBase.coerce_to_type(builder, sv2, i64_ty, cargs1.get(1))
|
||||
if n1 >= 3:
|
||||
sv3: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, cargs1.get(2), trans._funcs, trans._func_count, trans)
|
||||
if sv3 is None:
|
||||
# fail-fast: range argument failed to translate
|
||||
self.Gen.TypeGenErr.fatal_error(cargs1.get(2), "range 参数翻译失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(cargs1.get(2), "failed to translate the range argument", "TypeError")
|
||||
r1_step = self.Gen.ExprGenBase.coerce_to_type(builder, sv3, i64_ty, cargs1.get(2))
|
||||
elif kind1 == GenTypes.SEQ_KIND_STR:
|
||||
elem1_ty = i8_ty
|
||||
s1_ptr = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, src1, trans._funcs, trans._func_count, trans)
|
||||
if s1_ptr is None: self.Gen.TypeGenErr.fatal_error(for_node, "序列迭代: 字符串源翻译失败")
|
||||
if s1_ptr is None: self.Gen.TypeGenErr.fatal_error(for_node, "sequence iteration: failed to translate the string source")
|
||||
elif kind1 == GenTypes.SEQ_KIND_LIST:
|
||||
elem1_ty = i8_ptr_ty
|
||||
l1_obj: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, src1, trans._funcs, trans._func_count, trans)
|
||||
if l1_obj is None or l1_obj.Ty is None or self.Gen.ExprGenBase.is_ptr_type(l1_obj.Ty) == 0: self.Gen.TypeGenErr.fatal_error(for_node, "序列迭代: list 源不是指针类型")
|
||||
if l1_obj is None or l1_obj.Ty is None or self.Gen.ExprGenBase.is_ptr_type(l1_obj.Ty) == 0: self.Gen.TypeGenErr.fatal_error(for_node, "sequence iteration: list source is not a pointer type")
|
||||
l1_count = mlirlite.build_load(builder, i64_ty, mlirlite.build_gep(builder, i64_ty, l1_obj, mlirlite.const_int64(pool, 1)))
|
||||
l1_data = mlirlite.build_load(builder, i8_ptr_ty, mlirlite.build_gep(builder, i64_ty, l1_obj, mlirlite.const_int64(pool, 0)))
|
||||
l1_esize = mlirlite.build_load(builder, i64_ty, mlirlite.build_gep(builder, i64_ty, l1_obj, mlirlite.const_int64(pool, 4)))
|
||||
@@ -1269,7 +1269,7 @@ novirtual class StmtGenCifMixin:
|
||||
r2_step: mlirlite.Value* = None
|
||||
if n_srcs >= 2:
|
||||
kind2 = self._seq_kind(trans, src2)
|
||||
if kind2 == 0: self.Gen.TypeGenErr.fatal_error(for_node, "序列迭代: 源 2 类型不支持")
|
||||
if kind2 == 0: self.Gen.TypeGenErr.fatal_error(for_node, "sequence iteration: source 2 type is not supported")
|
||||
if kind2 == GenTypes.SEQ_KIND_RANGE:
|
||||
elem2_ty = i32_ty
|
||||
r2_start = mlirlite.const_int64(pool, 0)
|
||||
@@ -1284,28 +1284,28 @@ novirtual class StmtGenCifMixin:
|
||||
svz: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, cargs2.get(0), trans._funcs, trans._func_count, trans)
|
||||
if svz is None:
|
||||
# fail-fast: range argument failed to translate
|
||||
self.Gen.TypeGenErr.fatal_error(cargs2.get(0), "range 参数翻译失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(cargs2.get(0), "failed to translate the range argument", "TypeError")
|
||||
r2_stop = self.Gen.ExprGenBase.coerce_to_type(builder, svz, i64_ty, cargs2.get(0))
|
||||
if n2 >= 2:
|
||||
svz2: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, cargs2.get(1), trans._funcs, trans._func_count, trans)
|
||||
if svz2 is None:
|
||||
# fail-fast: range argument failed to translate
|
||||
self.Gen.TypeGenErr.fatal_error(cargs2.get(1), "range 参数翻译失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(cargs2.get(1), "failed to translate the range argument", "TypeError")
|
||||
r2_start = self.Gen.ExprGenBase.coerce_to_type(builder, svz2, i64_ty, cargs2.get(1))
|
||||
if n2 >= 3:
|
||||
svz3: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, cargs2.get(2), trans._funcs, trans._func_count, trans)
|
||||
if svz3 is None:
|
||||
# fail-fast: range argument failed to translate
|
||||
self.Gen.TypeGenErr.fatal_error(cargs2.get(2), "range 参数翻译失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(cargs2.get(2), "failed to translate the range argument", "TypeError")
|
||||
r2_step = self.Gen.ExprGenBase.coerce_to_type(builder, svz3, i64_ty, cargs2.get(2))
|
||||
elif kind2 == GenTypes.SEQ_KIND_STR:
|
||||
elem2_ty = i8_ty
|
||||
s2_ptr = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, src2, trans._funcs, trans._func_count, trans)
|
||||
if s2_ptr is None: self.Gen.TypeGenErr.fatal_error(for_node, "序列迭代: 字符串源 2 翻译失败")
|
||||
if s2_ptr is None: self.Gen.TypeGenErr.fatal_error(for_node, "sequence iteration: failed to translate string source 2")
|
||||
elif kind2 == GenTypes.SEQ_KIND_LIST:
|
||||
elem2_ty = i8_ptr_ty
|
||||
l2_obj: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, src2, trans._funcs, trans._func_count, trans)
|
||||
if l2_obj is None or l2_obj.Ty is None or self.Gen.ExprGenBase.is_ptr_type(l2_obj.Ty) == 0: self.Gen.TypeGenErr.fatal_error(for_node, "序列迭代: list 源 2 不是指针类型")
|
||||
if l2_obj is None or l2_obj.Ty is None or self.Gen.ExprGenBase.is_ptr_type(l2_obj.Ty) == 0: self.Gen.TypeGenErr.fatal_error(for_node, "sequence iteration: list source 2 is not a pointer type")
|
||||
l2_count = mlirlite.build_load(builder, i64_ty, mlirlite.build_gep(builder, i64_ty, l2_obj, mlirlite.const_int64(pool, 1)))
|
||||
l2_data = mlirlite.build_load(builder, i8_ptr_ty, mlirlite.build_gep(builder, i64_ty, l2_obj, mlirlite.const_int64(pool, 0)))
|
||||
l2_esize = mlirlite.build_load(builder, i64_ty, mlirlite.build_gep(builder, i64_ty, l2_obj, mlirlite.const_int64(pool, 4)))
|
||||
@@ -1465,17 +1465,17 @@ novirtual class StmtGenCifMixin:
|
||||
|
||||
# translate the iterator expression to get the pointer value
|
||||
ptr_val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, for_node.iter, trans._funcs, trans._func_count, trans)
|
||||
if ptr_val is None: self.Gen.TypeGenErr.fatal_error(for_node, "指针迭代: 无法翻译迭代器表达式")
|
||||
if ptr_val is None: self.Gen.TypeGenErr.fatal_error(for_node, "pointer iteration: failed to translate the iterator expression")
|
||||
|
||||
# check the iterator type
|
||||
if self.Gen.ExprGenBase.is_ptr_type(ptr_val.Ty) == 0:
|
||||
# array iteration: for k in arr (fixed length, elements of any type)
|
||||
if self.Gen.ExprGenBase.is_array_type(ptr_val.Ty) != 0: return self._handle_array_iter(trans, for_node, var_name, ptr_val)
|
||||
self.Gen.TypeGenErr.fatal_error(for_node, "指针迭代: 迭代器不是指针类型")
|
||||
self.Gen.TypeGenErr.fatal_error(for_node, "pointer iteration: iterator is not a pointer type")
|
||||
|
||||
# get the element type
|
||||
elem_ty: mlirlite.LLVMType* = ptr_val.Ty.Pointee
|
||||
if elem_ty is None: self.Gen.TypeGenErr.fatal_error(for_node, "指针迭代: 无法获取元素类型")
|
||||
if elem_ty is None: self.Gen.TypeGenErr.fatal_error(for_node, "pointer iteration: failed to get the element type")
|
||||
|
||||
# element type is an array (Ptr([N x T]), e.g. a decayed t.CArray): load it and iterate by length (no null terminator)
|
||||
if self.Gen.ExprGenBase.is_array_type(elem_ty) != 0:
|
||||
@@ -1487,7 +1487,7 @@ novirtual class StmtGenCifMixin:
|
||||
elem_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(elem_ty)
|
||||
elem_is_ptr2: int = self.Gen.ExprGenBase.is_ptr_type(elem_ty)
|
||||
elem_fbits2: int = self.Gen.ExprGenBase.get_llvm_float_bits(elem_ty)
|
||||
if elem_bits == 0 and elem_is_ptr2 == 0 and elem_fbits2 == 0: self.Gen.TypeGenErr.fatal_error(for_node, "指针迭代: 元素类型不是整数/指针/浮点,无法检查空终止符")
|
||||
if elem_bits == 0 and elem_is_ptr2 == 0 and elem_fbits2 == 0: self.Gen.TypeGenErr.fatal_error(for_node, "pointer iteration: element type is not integer/pointer/float; cannot check the null terminator")
|
||||
|
||||
i32_ty: mlirlite.LLVMType* = mlirlite.Int32(pool)
|
||||
|
||||
@@ -1597,12 +1597,12 @@ novirtual class StmtGenCifMixin:
|
||||
case mlirlite.LLVMType.Array(et, n):
|
||||
elem_ty = et
|
||||
elem_count = n
|
||||
if elem_ty is None or elem_count <= 0: self.Gen.TypeGenErr.fatal_error(for_node, "数组迭代: 无法解析数组类型")
|
||||
if elem_ty is None or elem_count <= 0: self.Gen.TypeGenErr.fatal_error(for_node, "array iteration: failed to resolve the array type")
|
||||
|
||||
# array value → temp alloca (arrays are not pointers, copy then GEP-iterate); it must live
|
||||
# in the entry block, else LLVM treats it as dynamic alloca and deep stacks can fault.
|
||||
arr_tmp: mlirlite.Value* = self.Gen.VarGen._alloca_at_entry(builder, arr_ty)
|
||||
if arr_tmp is None: self.Gen.TypeGenErr.fatal_error(for_node, "数组迭代: 临时存储分配失败")
|
||||
if arr_tmp is None: self.Gen.TypeGenErr.fatal_error(for_node, "array iteration: failed to allocate temporary storage")
|
||||
mlirlite.build_store(builder, array_val, arr_tmp)
|
||||
|
||||
i32_ty: mlirlite.LLVMType* = mlirlite.Int32(pool)
|
||||
@@ -1717,30 +1717,30 @@ novirtual class StmtGenCifMixin:
|
||||
builder: mlirlite.IRBuilder* = trans._cur_builder
|
||||
|
||||
lst: ast.List* = ast.List*(list_node)
|
||||
if lst is None or lst.elts is None: self.Gen.TypeGenErr.fatal_error(for_node, "列表字面量迭代: 空列表")
|
||||
if lst is None or lst.elts is None: self.Gen.TypeGenErr.fatal_error(for_node, "list literal iteration: empty list")
|
||||
elts: list[ast.AST*]* = lst.elts
|
||||
elts_count: sizet = len(elts)
|
||||
if elts_count <= 0: self.Gen.TypeGenErr.fatal_error(for_node, "列表字面量迭代: 空列表")
|
||||
if elts_count <= 0: self.Gen.TypeGenErr.fatal_error(for_node, "list literal iteration: empty list")
|
||||
|
||||
# translate the first element to determine the element type
|
||||
first_el: ast.AST* = elts.get(0)
|
||||
# explicit null check (repo convention: pointer null tests always use `is None`): a list
|
||||
# element count above the actual fill means a bare 0 slot, i.e. an empty AST element upstream.
|
||||
if first_el is None:
|
||||
self.Gen.TypeGenErr.fatal_error(for_node, f"列表字面量迭代遇到空 AST 元素:第 0 个元素为裸空指针(0)," f"但元素计数为 {elts_count}(元素与计数不一致);上层某处产生了空 AST 元素,已终止编译。", "ValueError")
|
||||
self.Gen.TypeGenErr.fatal_error(for_node, f"list literal iteration encountered an empty AST element: element 0 is a bare null pointer (0), " f"but the element count is {elts_count} (element and count mismatch); something upstream produced an empty AST element, compilation aborted.", "ValueError")
|
||||
# validate the object (vptr non-zero, see AssignGenMixin.vp:1174-1183): for @t.CVTable class
|
||||
# objects the first word is the vptr; if 0, any later virtual call reads address 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};" f"上层某处产生了「未初始化 vptr 的 AST 节点」(典型源:深拷贝只搬字段未搬 vptr),已终止编译。", "ValueError")
|
||||
self.Gen.TypeGenErr.fatal_error(for_node, f"list literal iteration encountered an [INVALID OBJECT] AST element (vptr is 0): element 0 pointer is nonzero" f"(address {uint64(first_el)}) but the first word of its object (vtable pointer) is 0, element count {elts_count};" f"something upstream produced an [uninitialized vptr AST node] (typical source: a deep copy that moved fields but not the vptr), compilation aborted.", "ValueError")
|
||||
first_val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, first_el, trans._funcs, trans._func_count, trans)
|
||||
if first_val is None or first_val.Ty is None: self.Gen.TypeGenErr.fatal_error(first_el, "列表字面量迭代: 无法确定元素类型")
|
||||
if first_val is None or first_val.Ty is None: self.Gen.TypeGenErr.fatal_error(first_el, "list literal iteration: failed to determine the element type")
|
||||
elem_ty: mlirlite.LLVMType* = first_val.Ty
|
||||
|
||||
# build an [N x elem_ty] array value: write elements into a temp alloca then load it; this
|
||||
# too must live in the entry block to avoid a dynamic alloca (see _handle_array_iter).
|
||||
arr_ty: mlirlite.LLVMType* = mlirlite.Array(pool, elem_ty, elts_count)
|
||||
tmp_alloca: mlirlite.Value* = self.Gen.VarGen._alloca_at_entry(builder, arr_ty)
|
||||
if tmp_alloca is None: self.Gen.TypeGenErr.fatal_error(for_node, "列表字面量迭代: 临时数组分配失败")
|
||||
if tmp_alloca is None: self.Gen.TypeGenErr.fatal_error(for_node, "list literal iteration: failed to allocate the temporary array")
|
||||
first_ptr: mlirlite.Value* = mlirlite.build_gep_array(builder, arr_ty, elem_ty, tmp_alloca, mlirlite.const_int32(pool, 0))
|
||||
if first_ptr is not None: mlirlite.build_store(builder, first_val, first_ptr)
|
||||
# write the remaining elements (coerce to elem_ty)
|
||||
@@ -1749,10 +1749,10 @@ novirtual class StmtGenCifMixin:
|
||||
el_node: ast.AST* = elts.get(i)
|
||||
# explicit null check (as above, `is None`): never let the translate_value guard swallow it
|
||||
if el_node is None:
|
||||
self.Gen.TypeGenErr.fatal_error(for_node, f"列表字面量迭代遇到空 AST 元素:第 {i} 个元素为裸空指针(0)," f"但元素计数为 {elts_count}(元素与计数不一致);上层某处产生了空 AST 元素,已终止编译。", "ValueError")
|
||||
self.Gen.TypeGenErr.fatal_error(for_node, f"list literal iteration encountered an empty AST element: element {i} is a bare null pointer (0), " f"but the element count is {elts_count} (element and count mismatch); something upstream produced an empty AST element, compilation aborted.", "ValueError")
|
||||
# object validity check (vptr non-zero), same as element 0: same "take element then use" path
|
||||
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};" f"上层某处产生了「未初始化 vptr 的 AST 节点」(典型源:深拷贝只搬字段未搬 vptr),已终止编译。", "ValueError")
|
||||
self.Gen.TypeGenErr.fatal_error(for_node, f"list literal iteration encountered an [INVALID OBJECT] AST element (vptr is 0): element {i} pointer is nonzero" f"(address {uint64(el_node)}) but the first word of its object (vtable pointer) is 0, element count {elts_count};" f"something upstream produced an [uninitialized vptr AST node] (typical source: a deep copy that moved fields but not the vptr), compilation aborted.", "ValueError")
|
||||
el_val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, el_node, trans._funcs, trans._func_count, trans)
|
||||
if el_val is not None:
|
||||
el_val = self.Gen.ExprGenBase.coerce_to_type(builder, el_val, elem_ty, el_node)
|
||||
@@ -1761,7 +1761,7 @@ novirtual class StmtGenCifMixin:
|
||||
i += 1
|
||||
# load the array value back and reuse array iteration
|
||||
arr_val: mlirlite.Value* = mlirlite.build_load(builder, arr_ty, tmp_alloca)
|
||||
if arr_val is None: self.Gen.TypeGenErr.fatal_error(for_node, "列表字面量迭代: 数组加载失败")
|
||||
if arr_val is None: self.Gen.TypeGenErr.fatal_error(for_node, "list literal iteration: failed to load the array")
|
||||
return self._handle_array_iter(trans, for_node, var_name, arr_val)
|
||||
|
||||
# _handle_list_iter - list[T] container iteration `for v in lst:` (migrated from ForHandleIter):
|
||||
@@ -1778,7 +1778,7 @@ novirtual class StmtGenCifMixin:
|
||||
|
||||
# read __count__ (offset 8, GEP index 1)
|
||||
cnt_ptr: mlirlite.Value* = mlirlite.build_gep(builder, i64_ty, list_val, mlirlite.const_int64(pool, 1))
|
||||
if cnt_ptr is None: self.Gen.TypeGenErr.fatal_error(for_node, "list 迭代: 无法定位 __count__")
|
||||
if cnt_ptr is None: self.Gen.TypeGenErr.fatal_error(for_node, "list iteration: failed to locate __count__")
|
||||
count_val: mlirlite.Value* = mlirlite.build_load(builder, i64_ty, cnt_ptr)
|
||||
|
||||
# loop-var alloca (element type i8*, matching inline list.get)
|
||||
@@ -1876,7 +1876,7 @@ novirtual class StmtGenCifMixin:
|
||||
|
||||
# read __count__ (slot 2, byte offset 16)
|
||||
cnt_ptr: mlirlite.Value* = mlirlite.build_gep(builder, i64_ty, dict_val, mlirlite.const_int64(pool, 2))
|
||||
if cnt_ptr is None: self.Gen.TypeGenErr.fatal_error(for_node, "dict 迭代: 无法定位 __count__")
|
||||
if cnt_ptr is None: self.Gen.TypeGenErr.fatal_error(for_node, "dict iteration: failed to locate __count__")
|
||||
count_val: mlirlite.Value* = mlirlite.build_load(builder, i64_ty, cnt_ptr)
|
||||
|
||||
# loop-var alloca (element type i8*, matching dict.__next__ returning str)
|
||||
@@ -1971,15 +1971,15 @@ novirtual class StmtGenCifMixin:
|
||||
mod: mlirlite.LLVMModule* = trans.Module
|
||||
|
||||
if builder is None or func is None or mod is None: return 0
|
||||
if obj_val is None or obj_val.Ty is None: self.Gen.TypeGenErr.fatal_error(for_node, "OOP 迭代: 迭代源对象类型未知")
|
||||
if self.Gen.ExprGenBase.is_ptr_type(obj_val.Ty) == 0: self.Gen.TypeGenErr.fatal_error(for_node, "OOP 迭代: 迭代源对象不是指针类型")
|
||||
if obj_val is None or obj_val.Ty is None: self.Gen.TypeGenErr.fatal_error(for_node, "OOP iteration: the iteration source object type is unknown")
|
||||
if self.Gen.ExprGenBase.is_ptr_type(obj_val.Ty) == 0: self.Gen.TypeGenErr.fatal_error(for_node, "OOP iteration: the iteration source object is not a pointer type")
|
||||
|
||||
# 1. find {Class}.__iter__ and call it to get the iterator
|
||||
iter_lookup: str = pool.alloc(128)
|
||||
if iter_lookup is None: return 0
|
||||
viperlib.snprintf(iter_lookup, 128, "%s.__iter__", class_name)
|
||||
iter_fn: mlirlite.Function* = self.Gen.CallGenBase.find_func_in_module(mod, iter_lookup)
|
||||
if iter_fn is None: self.Gen.TypeGenErr.fatal_error(for_node, f"OOP 迭代: 类 '{class_name}' 没有 __iter__ 方法")
|
||||
if iter_fn is None: self.Gen.TypeGenErr.fatal_error(for_node, f"OOP iteration: class {class_name} has no __iter__ method")
|
||||
iter_ret_ty: mlirlite.LLVMType* = mlirlite.function_get_ret_ty(iter_fn)
|
||||
iter_fn_name: str = mlirlite.function_get_name(iter_fn)
|
||||
if iter_ret_ty is None or iter_fn_name is None: return 0
|
||||
@@ -1999,7 +1999,7 @@ novirtual class StmtGenCifMixin:
|
||||
if next_lookup is None: return 0
|
||||
viperlib.snprintf(next_lookup, 128, "%s.__next__", class_name)
|
||||
next_fn: mlirlite.Function* = self.Gen.CallGenBase.find_func_in_module(mod, next_lookup)
|
||||
if next_fn is None: self.Gen.TypeGenErr.fatal_error(for_node, f"OOP 迭代: 类 '{class_name}' 没有 __next__ 方法")
|
||||
if next_fn is None: self.Gen.TypeGenErr.fatal_error(for_node, f"OOP iteration: class {class_name} has no __next__ method")
|
||||
next_ret_ty: mlirlite.LLVMType* = mlirlite.function_get_ret_ty(next_fn)
|
||||
next_fn_name: str = mlirlite.function_get_name(next_fn)
|
||||
if next_ret_ty is None or next_fn_name is None: return 0
|
||||
@@ -2092,16 +2092,16 @@ novirtual class StmtGenCifMixin:
|
||||
"""Iterate enumerate(x) as for i, v in enumerate(x)."""
|
||||
if call is None or call.args is None: return 0
|
||||
cargs: list[ast.AST*]* = call.args
|
||||
if len(cargs) < 1: self.Gen.TypeGenErr.fatal_error(for_node, "enumerate 需要至少一个参数")
|
||||
if len(cargs) < 1: self.Gen.TypeGenErr.fatal_error(for_node, "enumerate requires at least one argument")
|
||||
return self._build_seq_loop(trans, for_node, t1, t2, cargs.get(0), None, 1)
|
||||
|
||||
def _handle_zip_iter(self, trans: HT.Translator*, for_node: ast.For*, t1: str, t2: str, call: ast.Call*) -> int:
|
||||
"""Iterate zip(x, y) as for a, b in zip(x, y)."""
|
||||
if call is None or call.args is None:
|
||||
# fail-fast: zip argument missing
|
||||
self.Gen.TypeGenErr.fatal_error(call, "zip 参数缺失", "SyntaxError")
|
||||
self.Gen.TypeGenErr.fatal_error(call, "zip arguments are missing", "SyntaxError")
|
||||
cargs: list[ast.AST*]* = call.args
|
||||
if len(cargs) < 2: self.Gen.TypeGenErr.fatal_error(for_node, "zip 需要至少两个参数")
|
||||
if len(cargs) < 2: self.Gen.TypeGenErr.fatal_error(for_node, "zip requires at least two arguments")
|
||||
return self._build_seq_loop(trans, for_node, t1, t2, cargs.get(0), cargs.get(1), 2)
|
||||
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ novirtual class StmtGenDeclMixin(StmtGenCifMixin.StmtGenCifMixin):
|
||||
if var_ty is not None:
|
||||
match var_ty:
|
||||
case mlirlite.LLVMType.Void():
|
||||
self.Gen.TypeGenErr.fatal_error(nm_node, f"nonlocal 变量 '{nm.id}' 类型无效(Void/无法解析)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(nm_node, f"nonlocal variable {nm.id} has an invalid type (Void/unresolvable)", "TypeError")
|
||||
case _:
|
||||
pass
|
||||
GenApi.add_nonlocal_name(trans, nm.id, var_ty)
|
||||
@@ -92,7 +92,7 @@ novirtual class StmtGenDeclMixin(StmtGenCifMixin.StmtGenCifMixin):
|
||||
func_name: str = self.Gen.ExprGenBase.get_func_name(func_node)
|
||||
if func_name is None:
|
||||
# Function name resolution failed: report and abort (fail-fast)
|
||||
self.Gen.TypeGenErr.fatal_error(call_node, "表达式语句的函数名解析失败", "SyntaxError")
|
||||
self.Gen.TypeGenErr.fatal_error(call_node, "failed to resolve the function name of the expression statement", "SyntaxError")
|
||||
|
||||
# printf / print take special paths (print is type-aware formatting, not mapped to printf)
|
||||
if string.strcmp(func_name, "printf") == 0: self.Gen.CallGenLeafKit.translate_printf_call(trans.Pool, trans._cur_builder, trans.Module, cl, trans)
|
||||
@@ -204,7 +204,7 @@ novirtual class StmtGenDeclMixin(StmtGenCifMixin.StmtGenCifMixin):
|
||||
# Emit br to the break target (_break_bb set by the loop / switch / match case side)
|
||||
if trans._break_bb is None:
|
||||
# fail-fast: with no loop / switch / match there is nowhere to jump; never silently no-op
|
||||
self.Gen.TypeGenErr.fatal_error(node, "break 只能用在循环或 switch/match 的 case 体内(当前没有可跳出的目标)", "SyntaxError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, "break is only allowed inside a loop or a switch/match case body (there is no target to break out of)", "SyntaxError")
|
||||
if mlirlite.builder_cur_block_is_terminated(builder) == 0: mlirlite.build_br(builder, trans._break_bb)
|
||||
|
||||
# Create a dead-code BB for following statements (code after break is unreachable)
|
||||
@@ -220,7 +220,7 @@ novirtual class StmtGenDeclMixin(StmtGenCifMixin.StmtGenCifMixin):
|
||||
"""Translate a fallthrough statement: emits no IR, consumed by the switch side"""
|
||||
if trans is None: return 0
|
||||
if trans._in_switch_case == 0:
|
||||
self.Gen.TypeGenErr.fatal_error(node, "fallthrough 只能用在 switch 的 case 体内(match 完全禁止 fallthrough," "语义是落到下一个 case)", "SyntaxError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, "fallthrough is only allowed inside a switch case body (fallthrough is completely forbidden in match; " "the semantics are falling through to the next case)", "SyntaxError")
|
||||
return 0
|
||||
|
||||
def translate_continue(self, trans: HT.Translator*, node: ast.AST*) -> int:
|
||||
@@ -234,7 +234,7 @@ novirtual class StmtGenDeclMixin(StmtGenCifMixin.StmtGenCifMixin):
|
||||
# Emit br to the continue target
|
||||
if trans._continue_bb is None:
|
||||
# fail-fast: a continue outside a loop has nowhere to jump; never silently no-op
|
||||
self.Gen.TypeGenErr.fatal_error(node, "continue 只能用在循环体内(当前没有可继续的循环)", "SyntaxError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, "continue is only allowed inside a loop body (there is no enclosing loop to continue)", "SyntaxError")
|
||||
if mlirlite.builder_cur_block_is_terminated(builder) == 0: mlirlite.build_br(builder, trans._continue_bb)
|
||||
|
||||
# Create a dead-code BB for following statements
|
||||
@@ -316,7 +316,7 @@ novirtual class StmtGenDeclMixin(StmtGenCifMixin.StmtGenCifMixin):
|
||||
var_ty: mlirlite.LLVMType* = GenApi.get_nonlocal_type(trans, name)
|
||||
if var_ty is None or self._is_void_type(var_ty) != 0:
|
||||
# fail-fast on a missing/invalid type, avoiding illegal IR like "load void, void*"
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"nonlocal 变量 '{name}' 类型缺失,无法 load", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"nonlocal variable {name} is missing its type; cannot load", "TypeError")
|
||||
|
||||
# bitcast raw i8* to var_ty*
|
||||
var_ptr_ty: mlirlite.LLVMType* = mlirlite.Ptr(pool, var_ty)
|
||||
@@ -336,7 +336,7 @@ novirtual class StmtGenDeclMixin(StmtGenCifMixin.StmtGenCifMixin):
|
||||
var_ty: mlirlite.LLVMType* = GenApi.get_nonlocal_type(trans, name)
|
||||
if var_ty is None or self._is_void_type(var_ty) != 0:
|
||||
# Missing/invalid type aborts (fail-fast) to avoid illegal "bitcast ... to void*" IR
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"nonlocal 变量 '{name}' 类型缺失,无法 load", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"nonlocal variable {name} is missing its type; cannot load", "TypeError")
|
||||
|
||||
# bitcast raw i8* to var_ty*
|
||||
var_ptr_ty: mlirlite.LLVMType* = mlirlite.Ptr(pool, var_ty)
|
||||
|
||||
@@ -32,7 +32,7 @@ novirtual class StmtGenMixin(StmtGenDeclMixin.StmtGenDeclMixin):
|
||||
# define). Every instruction then carries ", !dbg !N".
|
||||
if node is not None and trans._cur_builder is not None:
|
||||
DebugInfoGen.SetStatement(trans.Pool, trans._cur_builder, node.lineno, node.col_offset + 1)
|
||||
if trans.TranslateDepth >= HT.TRANSLATE_MAX_DEPTH: self.Gen.TypeGenErr.fatal_error(node, "语句翻译嵌套过深(疑似 AST 自引用环或翻译 bug)", "RecursionError")
|
||||
if trans.TranslateDepth >= HT.TRANSLATE_MAX_DEPTH: self.Gen.TypeGenErr.fatal_error(node, "statement translation nested too deeply (likely an AST self-reference cycle or a translation bug)", "RecursionError")
|
||||
trans.TranslateDepth += 1
|
||||
mret: int = self._translate_stmt_impl(trans, node)
|
||||
if trans is not None: trans.TranslateDepth -= 1
|
||||
@@ -71,7 +71,7 @@ novirtual class StmtGenMixin(StmtGenDeclMixin.StmtGenDeclMixin):
|
||||
elif k == ast.ASTKind.Try: return self.translate_try(trans, node)
|
||||
elif k == ast.ASTKind.With: return self.translate_with(trans, node)
|
||||
# unknown statement type: fail-fast to expose an upstream parse problem
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"未知语句类型 kind={k}", "SyntaxError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"unknown statement type kind={k}", "SyntaxError")
|
||||
return 0
|
||||
|
||||
def translate_delete(self, trans: HT.Translator*, node: ast.AST*) -> int:
|
||||
|
||||
@@ -681,11 +681,11 @@ novirtual class StructGenMixin:
|
||||
# Explicit null check (repo hard rule: null-check pointers with `is None`). An earlier revision compared `elem_src_l == 0` and noted it was equivalent to `is None`: the IR fact was right but the conclusion misleading.
|
||||
# A null element in the source list means the producer is corrupted (count > actual fill) -> fail loudly, never backfill 0.
|
||||
if elem_src_l is None:
|
||||
self.Gen.TypeGenErr.fatal_error(default_val, f"字段默认值深拷贝:列表字面量第 {li_l} 个元素为空 AST 元素(指针为 0)。" f"上层某处产生了空 AST 元素(元素计数与实际填充不一致)," f"拒绝静默补 0 生成残缺的默认值;已终止编译。", "ValueError")
|
||||
self.Gen.TypeGenErr.fatal_error(default_val, f"field default deep copy: element {li_l} of the list literal is an empty AST element (pointer is 0). " f"Something upstream produced an empty AST element (element count and actual fill disagree); " f"refusing to silently backfill 0 and generate a broken default; compilation aborted.", "ValueError")
|
||||
return None
|
||||
elem_dst_l: ast.AST* = self._deep_copy_default_ast(pool, elem_src_l)
|
||||
if elem_dst_l is None:
|
||||
self.Gen.TypeGenErr.fatal_error(elem_src_l, f"字段默认值深拷贝:列表字面量第 {li_l} 个元素(kind={elem_src_l.kind()})" f"既非 Constant 也非 List,无法深拷贝到永久池。若在此静默跳过该槽," f"会形成【计数 > 实际填充数】的空槽(后续 elts.get 读到裸 0 崩溃);" f"若静默截短计数则会改变数组初始化长度。两者都是静默降级,故响亮失败。", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(elem_src_l, f"field default deep copy: element {li_l} of the list literal (kind={elem_src_l.kind()})" f" is neither Constant nor List, so it cannot be deep-copied into the permanent pool. Silently skipping this slot" f" would create an empty slot [count > actual fill] (a later elts.get reads a raw 0 and crashes);" f" silently shortening the count would change the array initializer length. Both are silent degradation, so fail loudly.", "TypeError")
|
||||
return None
|
||||
# The slot element type must be a pointer: `ast.AST*`'s `[0]` is the object `ast.AST` (48 bytes), so `slot[0] = <pointer>` would silently compile as a 48-byte load + 48-byte store and overrun each cnt_l*elem_sz_l slot by 40 bytes, writing over this block's canary and the next free block's first word (root cause of three generations of [FREEFRAME] crashes).
|
||||
# Per the repo merge rule (hashtable.vp:82-85) `X*` = Ptr(resolve(X)), so indexing yields a pointer element -> an 8-byte pointer store matching the allocation width.
|
||||
@@ -730,7 +730,7 @@ novirtual class StructGenMixin:
|
||||
# Pass 1: exact match.
|
||||
# StructCount sanity guard (memory corruption can yield a huge value -> index loop false hang).
|
||||
if self.StructCount < 0 or self.StructCount > 200000:
|
||||
VLogger.error(f"StructCount 异常: {self.StructCount} (find_struct)", "STRUCT")
|
||||
VLogger.error(f"abnormal StructCount: {self.StructCount} (find_struct)", "STRUCT")
|
||||
stdlib.exit(1)
|
||||
# Name-index fast path: a hit gives the first registration index (semantics = the original exact-match scan's first hit).
|
||||
fi: int = self._struct_name_idx_find(name)
|
||||
@@ -805,7 +805,7 @@ novirtual class StructGenMixin:
|
||||
if name is None or self.StructTable is None: return None
|
||||
# StructCount sanity guard (memory corruption can yield a huge value -> index loop false hang).
|
||||
if self.StructCount < 0 or self.StructCount > 200000:
|
||||
VLogger.error(f"StructCount 异常: {self.StructCount} (find_struct_by_module)", "STRUCT")
|
||||
VLogger.error(f"abnormal StructCount: {self.StructCount} (find_struct_by_module)", "STRUCT")
|
||||
stdlib.exit(1)
|
||||
if sha1 is not None:
|
||||
# Name-index fast path: same-named entries all lie at or after the first same-name index, so scan name+sha1 from that index (equivalent to the original full scan's "first name with sha1 hit").
|
||||
@@ -830,7 +830,7 @@ novirtual class StructGenMixin:
|
||||
"""Clear MethodsEmitted for classes registered by the given module sha1."""
|
||||
if sha1 is None or self.StructTable is None: return 0
|
||||
if self.StructCount < 0 or self.StructCount > 200000:
|
||||
VLogger.error(f"StructCount 异常: {self.StructCount} (reset_module_methods_emitted)", "STRUCT")
|
||||
VLogger.error(f"abnormal StructCount: {self.StructCount} (reset_module_methods_emitted)", "STRUCT")
|
||||
return 0
|
||||
reset_count: int = 0
|
||||
for i in range(self.StructCount):
|
||||
@@ -854,7 +854,7 @@ novirtual class StructGenMixin:
|
||||
if struct_ty is None or self.StructTable is None: return None
|
||||
# StructCount sanity guard (memory corruption can yield a huge value -> index loop false hang).
|
||||
if self.StructCount < 0 or self.StructCount > 200000:
|
||||
VLogger.error(f"StructCount 异常: {self.StructCount} (find_struct_by_type)", "STRUCT")
|
||||
VLogger.error(f"abnormal StructCount: {self.StructCount} (find_struct_by_type)", "STRUCT")
|
||||
stdlib.exit(1)
|
||||
st_val: uint64 = uint64(struct_ty)
|
||||
# The Ty index is entirely disabled here (its structure is still maintained by _struct_idx_add but not used): an entry's Ty may be rewritten to a new pointer by deep copy (ClassGenDef), leaving the slot keyed by the registration-time Ty value out of sync.
|
||||
@@ -887,7 +887,7 @@ novirtual class StructGenMixin:
|
||||
fcount: int = mlirlite.get_struct_fcount(struct_ty)
|
||||
if fcount <= 0: return 0
|
||||
if entry.FieldCount != fcount:
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"结构体 '{entry.Name}' 的字段表条数({entry.FieldCount})与 LLVM 槽位数({fcount})不一致:" f"字段条目与结构体布局由两条路径产生,错位会让字段访问按错误下标算 GEP" f"(实证:ast.Name.id 落到 ctx 槽 ⇒ 指针被读成整数 1 ⇒ strlen(0x1) 崩溃)。", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"struct '{entry.Name}' field table count ({entry.FieldCount}) disagrees with the LLVM slot count ({fcount}): " f"field entries and struct layout come from two paths, and a mismatch makes field access compute GEP with a wrong index" f" (evidence: ast.Name.id landing in the ctx slot => the pointer is read as the integer 1 => strlen(0x1) crashes).", "TypeError")
|
||||
return 0
|
||||
node: mlirlite.ParamNode* = mlirlite.get_struct_fields(struct_ty)
|
||||
i: int = 0
|
||||
@@ -902,7 +902,7 @@ novirtual class StructGenMixin:
|
||||
fbits_f: int = self.Gen.ExprGenBase.get_llvm_float_bits(fe.Ty)
|
||||
fbits_s: int = self.Gen.ExprGenBase.get_llvm_float_bits(slot_ty)
|
||||
if ptr_f != ptr_s or bits_f != bits_s or fbits_f != fbits_s:
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"结构体 '{entry.Name}' 的字段 '{fe.Name}'(条目下标 {i})与其槽位类型不同类:" f"条目 指针性={ptr_f}/整数位宽={bits_f}/浮点位宽={fbits_f}," f"槽位 指针性={ptr_s}/整数位宽={bits_s}/浮点位宽={fbits_s}。" f"字段条目与结构体布局错位(实证:id 落到 ctx 槽 ⇒ 指针被读成整数 1 ⇒ strlen(0x1) 崩溃)。", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"field '{fe.Name}' of struct '{entry.Name}' (entry index {i}) is not the same kind as its slot type: " f"entry ptr-ness={ptr_f}/int width={bits_f}/float width={fbits_f}; " f"slot ptr-ness={ptr_s}/int width={bits_s}/float width={fbits_s}. " f"field entries and struct layout are misaligned (evidence: id landing in the ctx slot => the pointer is read as the integer 1 => strlen(0x1) crashes).", "TypeError")
|
||||
return 0
|
||||
node = mlirlite.paramnode_get_next(node)
|
||||
i += 1
|
||||
@@ -1046,15 +1046,15 @@ novirtual class StructGenMixin:
|
||||
stdlib.free(mod_buf_q)
|
||||
return rn_fe_q
|
||||
# Class hit but field not found: readable error (traceback format).
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"lookup_field_by_class: 类 '{class_name}' 已按模块归属解析(ModuleSha1={mod_sha1_q}, FieldCount={mod_entry_q.FieldCount})但字段 '{field_name}' 未找到", "AttributeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"lookup_field_by_class: class '{class_name}' was resolved by module ownership (ModuleSha1={mod_sha1_q}, FieldCount={mod_entry_q.FieldCount}) but field '{field_name}' was not found", "AttributeError")
|
||||
stdlib.free(mod_buf_q)
|
||||
return None
|
||||
# Module resolvable but class not registered: fail-fast (exposes vpi injection/registration defects; no bare-name cross-library grab of another module's same-named class).
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"lookup_field_by_class: 类 '{class_name}' 未找到(模块 '{mod_buf_q}' 可解析 sha1={mod_sha1_q},但无同名注册类;请检查 vpi stub 注入或编译顺序)", "AttributeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"lookup_field_by_class: class '{class_name}' was not found (module '{mod_buf_q}' resolves to sha1={mod_sha1_q}, but no class of that name is registered; check vpi stub injection or compilation order)", "AttributeError")
|
||||
stdlib.free(mod_buf_q)
|
||||
return None
|
||||
# Module name not registered: fail-fast (no more bare-name cross-library fallback).
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"lookup_field_by_class: 类 '{class_name}' 的模块 '{mod_buf_q}' 无法解析(sha1 映射表未登记,请检查 import 与编译顺序)", "AttributeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"lookup_field_by_class: module '{mod_buf_q}' of class '{class_name}' cannot be resolved (not registered in the sha1 map; check the imports and compilation order)", "AttributeError")
|
||||
stdlib.free(mod_buf_q)
|
||||
return None
|
||||
stdlib.free(mod_buf_q)
|
||||
@@ -1063,7 +1063,7 @@ novirtual class StructGenMixin:
|
||||
entry = self.find_struct(class_name)
|
||||
if entry is None:
|
||||
# Diagnostic: target class not registered (Python traceback style; terminate compilation immediately).
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"lookup_field_by_class: 类 '{class_name}' 未注册 (struct_count={self.StructCount})", "AttributeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"lookup_field_by_class: class '{class_name}' is not registered (struct_count={self.StructCount})", "AttributeError")
|
||||
return None
|
||||
# Dependencies-not-ready tolerance: the caller expects a specific module (sha1 non-None) but the bare-name fallback hit an empty FieldCount==0 stub class (vpi injection without fields / defining module not compiled).
|
||||
# Return None so the caller marks _deps_pending and retranslates (the real definition overrides the stub once the source module compiles). SECURITY_ATTRIBUTES FieldCount=0 root cause (subprocess.vp sa.nLength).
|
||||
@@ -1102,16 +1102,16 @@ novirtual class StructGenMixin:
|
||||
err: str
|
||||
if rn_is_renum_l != 0:
|
||||
# Friendly error: for a REnum class state that variant field alias lookup failed, including entry.Name and the alias slot result, so it is clear whether the alias is unregistered (slot=-1) or the class_name pointer is not unified.
|
||||
err = f"lookup_field_by_class: 类 '{class_name}' 是 REnum 类(FieldCount={entry.FieldCount}),变体字段 '{field_name}' 别名查找失败(entry.Name='{rn_cls_l}',别名槽位={rn_alias_l},请检查该变体字段是否已注册别名,或 class_name 指针是否统一)"
|
||||
err = f"lookup_field_by_class: class '{class_name}' is a REnum class (FieldCount={entry.FieldCount}), variant field '{field_name}' alias lookup failed (entry.Name='{rn_cls_l}', alias slot={rn_alias_l}; check whether this variant field has a registered alias, or whether the class_name pointer is unified)"
|
||||
else:
|
||||
# Readability: include entry.Name/ModuleSha1 (cross-module same-name location) + the registered field list + the expected sha1 (caller), to distinguish "cross-module same-named class mismatch" from "incomplete vpi stub injection" from "class definition and access site disagree".
|
||||
sha1_txt: str = "?"
|
||||
if entry.ModuleSha1 is not None: sha1_txt = entry.ModuleSha1
|
||||
want_sha1_txt: str = "?"
|
||||
if sha1 is not None: want_sha1_txt = sha1
|
||||
fld_lst_txt: str = "(无)"
|
||||
fld_lst_txt: str = "(none)"
|
||||
if fb_flds_lst is not None and string.strlen(fb_flds_lst) > 0: fld_lst_txt = fb_flds_lst
|
||||
err = f"lookup_field_by_class: 类 '{class_name}' 已注册 (FieldCount={entry.FieldCount}, " f"entry.Name='{entry.Name}', ModuleSha1={sha1_txt}, 调用方期望 sha1={want_sha1_txt}) " f"但字段 '{field_name}' 未找到;注册字段: [{fld_lst_txt}]。可能原因: 跨模块同名类" f"被误匹配 / vpi stub 注入字段不全 / 类定义与访问处不一致"
|
||||
err = f"lookup_field_by_class: class '{class_name}' is registered (FieldCount={entry.FieldCount}, " f"entry.Name='{entry.Name}', ModuleSha1={sha1_txt}, caller expects sha1={want_sha1_txt}) " f"but field '{field_name}' was not found; registered fields: [{fld_lst_txt}]. Possible causes: cross-module same-named class" f" mis-matched / incomplete vpi stub injection / class definition and access site disagree"
|
||||
# Output in Python traceback style (traceback frame + file:line + error type) and terminate compilation immediately (same semantics as VLogger.error, format aligned with fatal_error).
|
||||
self.Gen.TypeGenErr.fatal_error(node, err, "AttributeError")
|
||||
if fb_flds_lst is not None: stdlib.free(fb_flds_lst)
|
||||
@@ -1537,7 +1537,7 @@ novirtual class StructGenMixin:
|
||||
# Step guard: a cyclic field list (memory corruption) would loop forever (G3 LinkedNode.prepend hang candidate); over the limit, report and abort immediately.
|
||||
cnt_ef += 1
|
||||
if cnt_ef > 100000:
|
||||
VLogger.error("字段链表疑似成环(_ensure_field_types_in_module),强制终止", "STRUCT")
|
||||
VLogger.error("field list is likely cyclic (_ensure_field_types_in_module), forcing termination", "STRUCT")
|
||||
stdlib.exit(1)
|
||||
if fld.Ty is not None:
|
||||
# Value-type sub-structs (e.g. FILETIME) need a full definition.
|
||||
|
||||
@@ -850,32 +850,32 @@ def InjectTracebackInstallCtor(tr: Translator*) -> int:
|
||||
if tr._declare_only != 0: return 0
|
||||
pool: memhub.MemBuddy* = tr.Pool
|
||||
if pool is None:
|
||||
VLogger.error("--traceback: 内存池未初始化,无法注入 Install 构造器", "TRACEBACK")
|
||||
VLogger.error("--traceback: memory pool is not initialized, cannot inject the Install constructor", "TRACEBACK")
|
||||
return 1
|
||||
mod: mlirlite.LLVMModule* = tr.Module
|
||||
if _tb_module_has_global_ctors(mod) != 0:
|
||||
VLogger.error("--traceback: 模块内已存在 @llvm.global_ctors,无法注入 traceback 启动期构造器(不静默降级)", "TRACEBACK")
|
||||
VLogger.error("--traceback: @llvm.global_ctors already exists in the module, cannot inject the traceback startup constructor (no silent fallback)", "TRACEBACK")
|
||||
return 1
|
||||
install_fn: mlirlite.Function* = _tb_find_install_function(mod)
|
||||
if install_fn is None:
|
||||
VLogger.error("--traceback: 在 traceback 模块内找不到 Install() 函数,无法注入启动期构造器(不静默降级)", "TRACEBACK")
|
||||
VLogger.error("--traceback: Install() function not found in the traceback module, cannot inject the startup constructor (no silent fallback)", "TRACEBACK")
|
||||
return 1
|
||||
|
||||
# 1) ctor: entry { call <ret> @Install(); ret void }
|
||||
void_ty: mlirlite.LLVMType* = mlirlite.Void(pool)
|
||||
ctor: mlirlite.Function* = mlirlite.new_function(pool, "__traceback_install_ctor", void_ty)
|
||||
if ctor is None:
|
||||
VLogger.error("--traceback: 构造器函数分配失败", "TRACEBACK")
|
||||
VLogger.error("--traceback: failed to allocate the constructor function", "TRACEBACK")
|
||||
return 1
|
||||
blk: mlirlite.BasicBlock* = mlirlite.new_basic_block(pool, "entry")
|
||||
if blk is None:
|
||||
VLogger.error("--traceback: 构造器基本块分配失败", "TRACEBACK")
|
||||
VLogger.error("--traceback: failed to allocate the constructor basic block", "TRACEBACK")
|
||||
return 1
|
||||
mlirlite.function_add_block(ctor, blk)
|
||||
mlirlite.module_add_function(mod, ctor)
|
||||
builder: mlirlite.IRBuilder* = mlirlite.new_builder(pool, ctor)
|
||||
if builder is None:
|
||||
VLogger.error("--traceback: 构造器 IRBuilder 分配失败", "TRACEBACK")
|
||||
VLogger.error("--traceback: failed to allocate the constructor IRBuilder", "TRACEBACK")
|
||||
return 1
|
||||
mlirlite.position_at_end(builder, blk)
|
||||
iname: str = mlirlite.function_get_name(install_fn)
|
||||
@@ -893,23 +893,23 @@ def InjectTracebackInstallCtor(tr: Translator*) -> int:
|
||||
f2: mlirlite.ParamNode* = mlirlite.new_param_node(pool, fnp_ty)
|
||||
f3: mlirlite.ParamNode* = mlirlite.new_param_node(pool, i8p_ty)
|
||||
if f1 is None or f2 is None or f3 is None:
|
||||
VLogger.error("--traceback: global_ctors 结构体字段分配失败", "TRACEBACK")
|
||||
VLogger.error("--traceback: failed to allocate global_ctors struct fields", "TRACEBACK")
|
||||
return 1
|
||||
mlirlite.paramnode_set_next(f1, f2)
|
||||
mlirlite.paramnode_set_next(f2, f3)
|
||||
elem_ty: mlirlite.LLVMType* = mlirlite.Struct(pool, f1, 3, None)
|
||||
arr_ty: mlirlite.LLVMType* = mlirlite.Array(pool, elem_ty, 1)
|
||||
if elem_ty is None or arr_ty is None:
|
||||
VLogger.error("--traceback: global_ctors 类型构造失败", "TRACEBACK")
|
||||
VLogger.error("--traceback: failed to build the global_ctors type", "TRACEBACK")
|
||||
return 1
|
||||
gv: mlirlite.GlobalVariable* = mlirlite.new_global_variable(pool, "llvm.global_ctors", arr_ty)
|
||||
if gv is None:
|
||||
VLogger.error("--traceback: @llvm.global_ctors 全局变量分配失败", "TRACEBACK")
|
||||
VLogger.error("--traceback: failed to allocate the @llvm.global_ctors global variable", "TRACEBACK")
|
||||
return 1
|
||||
mlirlite.global_set_linkage(gv, "appending")
|
||||
gv.Initializer = "[{ i32, void ()*, i8* } { i32 65535, void ()* @__traceback_install_ctor, i8* null }]"
|
||||
mlirlite.module_add_global(mod, gv)
|
||||
VLogger.info("--traceback: 已注入启动期 Install() 构造器(@llvm.global_ctors)", "TRACEBACK")
|
||||
VLogger.info("--traceback: injected the startup Install() constructor (@llvm.global_ctors)", "TRACEBACK")
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
@@ -159,7 +159,7 @@ novirtual class TranslatorGenMixin:
|
||||
|
||||
# More elements than the declared length -> fail-fast (never silently truncate or drop).
|
||||
if sizet(arr_count) < elts_count:
|
||||
self.Gen.TypeGenErr.fatal_error(list_node, f"数组初始化元素数 {elts_count} 超过数组声明长度 {arr_count},不允许静默截断", "OverflowError")
|
||||
self.Gen.TypeGenErr.fatal_error(list_node, f"array initializer has {elts_count} elements, exceeding the declared array length {arr_count}; silent truncation is not allowed", "OverflowError")
|
||||
return None
|
||||
|
||||
# Non-integer element types (aggregates): only an all-zero list yields the whole
|
||||
@@ -433,7 +433,7 @@ novirtual class TranslatorGenMixin:
|
||||
if hit is None: return None
|
||||
sec_val: str = self.Gen.FuncGenBase._get_attr_call_arg_str(hit)
|
||||
if sec_val is None or sec_val[0] == 0:
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"模块级变量 '{var_name}' 的 t.attr.section(...) 段名缺失或为空", "ValueError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"section name of t.attr.section(...) for module-level variable '{var_name}' is missing or empty", "ValueError")
|
||||
return None
|
||||
return sec_val
|
||||
def _extract_global_attr_aligned(self, node: ast.AST*, var_name: str) -> int:
|
||||
@@ -442,7 +442,7 @@ novirtual class TranslatorGenMixin:
|
||||
if hit is None: return 0
|
||||
al_val: int = self.Gen.ClassGenBase._tattr_aligned_int(hit)
|
||||
if al_val <= 0:
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"模块级变量 '{var_name}' 的 t.attr.aligned(N) 需要正整数字面量 N", "ValueError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"t.attr.aligned(N) for module-level variable '{var_name}' requires a positive integer literal N", "ValueError")
|
||||
return 0
|
||||
return al_val
|
||||
def _extract_global_attr_weak(self, node: ast.AST*) -> int:
|
||||
@@ -512,7 +512,7 @@ novirtual class TranslatorGenMixin:
|
||||
annot_node = aa.annotation
|
||||
# f-string escape: a module-level initial value is global, but the f-string result
|
||||
# points into the current function's stack buffer -> fail-fast (use escape_fstring_copy).
|
||||
GenApi.fail_if_fstring_escape(aa.value, "全局变量初始化")
|
||||
GenApi.fail_if_fstring_escape(aa.value, "global variable initialization")
|
||||
# t.CStatic vars (no cross-module use) are registered as (name, def module SHA1);
|
||||
# the logic stays inside _RegisterStaticModuleVar to avoid disturbing type inference.
|
||||
self._RegisterStaticModuleVar(trans, annot_node, var_name)
|
||||
@@ -551,7 +551,7 @@ novirtual class TranslatorGenMixin:
|
||||
else:
|
||||
# [S4 fail-fast] An annotated module var that fails to resolve errors out instead
|
||||
# of silently using i32 (a wrong type corrupts storage size/field access/ABI).
|
||||
self.Gen.TypeGenErr.fatal_error(aa.annotation, f"模块级变量 '{var_name}' 类型注解解析失败", "NameError")
|
||||
self.Gen.TypeGenErr.fatal_error(aa.annotation, f"failed to resolve the type annotation of module-level variable '{var_name}'", "NameError")
|
||||
return 0
|
||||
# Parse the initial value (integer, negative literal, list literal, string literal)
|
||||
if aa.value is not None:
|
||||
@@ -630,10 +630,10 @@ novirtual class TranslatorGenMixin:
|
||||
case _:
|
||||
pass
|
||||
if is_fty_g == 0:
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"模块级变量 '{var_name}' 用浮点字面量初始化,但注解不是浮点类型", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"module-level variable '{var_name}' is initialized with a float literal, but its annotation is not a float type", "TypeError")
|
||||
return 0
|
||||
if self.Gen.AssignGen._recover_float_literal(var_name, &init_fval, 0) != 1:
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"模块级浮点变量 '{var_name}' 初始化值源文件恢复失败", "InternalCompilerError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"failed to recover the initializer value of module-level float variable '{var_name}' from the source file", "InternalCompilerError")
|
||||
return 0
|
||||
|
||||
# Check whether it is already registered
|
||||
@@ -703,7 +703,7 @@ novirtual class TranslatorGenMixin:
|
||||
if arr_init is not None: gv.Initializer = arr_init
|
||||
else:
|
||||
# Initializer build failed: error out (fail-fast) instead of falling back to zeroinitializer
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"模块级变量 '{var_name}' 初始化器构建失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"failed to build the initializer of module-level variable '{var_name}'", "TypeError")
|
||||
elif init_kind == 3:
|
||||
# String literal initializer: for array types (t.CArray[char, N]) use a byte-array
|
||||
# initializer (content + zero padding); a string-pointer GEP initializer would mismatch.
|
||||
@@ -716,19 +716,19 @@ novirtual class TranslatorGenMixin:
|
||||
if is_arr_g != 0:
|
||||
arr_str_init: str = self._build_string_array_initializer_text(pool, var_ty, init_str_val)
|
||||
if arr_str_init is not None: gv.Initializer = arr_str_init
|
||||
else: self.Gen.TypeGenErr.fatal_error(node, f"模块级数组变量 '{var_name}' 字符串初始化器构建失败", "TypeError")
|
||||
else: self.Gen.TypeGenErr.fatal_error(node, f"failed to build the string initializer of module-level array variable '{var_name}'", "TypeError")
|
||||
else:
|
||||
# Pointer type (e.g. b64_tab: t.CArray[char, None] = "ABC..."): create an internal
|
||||
# string constant global and reference it via a GEP initializer.
|
||||
str_init: str = self._build_string_ptr_initializer(pool, mod, var_name, init_str_val)
|
||||
if str_init is not None: gv.Initializer = str_init
|
||||
else: self.Gen.TypeGenErr.fatal_error(node, f"模块级变量 '{var_name}' 初始化器构建失败", "TypeError")
|
||||
else: self.Gen.TypeGenErr.fatal_error(node, f"failed to build the initializer of module-level variable '{var_name}'", "TypeError")
|
||||
elif init_kind == 4:
|
||||
# Float initializer: LLVM float constants must be written as bit-pattern text
|
||||
# (0x%016llx / 0x%08x); decimal text has ulp errors, and omitting this zeroes the global.
|
||||
fc_g: mlirlite.Value* = mlirlite.ConstFloat(pool, var_ty, init_fval)
|
||||
if fc_g is not None and fc_g.Name is not None: gv.Initializer = fc_g.Name
|
||||
else: self.Gen.TypeGenErr.fatal_error(node, f"模块级变量 '{var_name}' 浮点初始化器构建失败", "TypeError")
|
||||
else: self.Gen.TypeGenErr.fatal_error(node, f"failed to build the float initializer of module-level variable '{var_name}'", "TypeError")
|
||||
else:
|
||||
# Use zeroinitializer (valid for pointer/integer/aggregate types). Object-class globals
|
||||
# with storage get &@storage below; `= None` lazy globals still need it to stay complete.
|
||||
@@ -930,9 +930,9 @@ novirtual class TranslatorGenMixin:
|
||||
err_buf: str = None
|
||||
if pool_err is not None: err_buf = pool_err.alloc(256)
|
||||
if err_buf is not None:
|
||||
viperlib.snprintf(err_buf, 256, "global 变量数量超过上限 MAX_GLOBAL_NAMES=%d,请减少 global 声明或增大 MAX_GLOBAL_NAMES", HT.MAX_GLOBAL_NAMES)
|
||||
viperlib.snprintf(err_buf, 256, "the number of global variables exceeds the limit MAX_GLOBAL_NAMES=%d; reduce global declarations or increase MAX_GLOBAL_NAMES", HT.MAX_GLOBAL_NAMES)
|
||||
VLogger.error(err_buf, "ScopeDecl")
|
||||
else: VLogger.error("global 变量数量超过上限,请减少 global 声明或增大 MAX_GLOBAL_NAMES", "ScopeDecl")
|
||||
else: VLogger.error("the number of global variables exceeds the limit; reduce global declarations or increase MAX_GLOBAL_NAMES", "ScopeDecl")
|
||||
return
|
||||
entry_addr: uint64 = uint64(trans._global_names) + trans._global_name_count * 8
|
||||
slot_ptr: str* = (str*)(entry_addr)
|
||||
@@ -969,9 +969,9 @@ novirtual class TranslatorGenMixin:
|
||||
err_buf_nl: str = None
|
||||
if pool_err_nl is not None: err_buf_nl = pool_err_nl.alloc(256)
|
||||
if err_buf_nl is not None:
|
||||
viperlib.snprintf(err_buf_nl, 256, "nonlocal 变量数量超过上限 MAX_GLOBAL_NAMES=%d,请减少 nonlocal 声明或增大 MAX_GLOBAL_NAMES", HT.MAX_GLOBAL_NAMES)
|
||||
viperlib.snprintf(err_buf_nl, 256, "the number of nonlocal variables exceeds the limit MAX_GLOBAL_NAMES=%d; reduce nonlocal declarations or increase MAX_GLOBAL_NAMES", HT.MAX_GLOBAL_NAMES)
|
||||
VLogger.error(err_buf_nl, "ScopeDecl")
|
||||
else: VLogger.error("nonlocal 变量数量超过上限,请减少 nonlocal 声明或增大 MAX_GLOBAL_NAMES", "ScopeDecl")
|
||||
else: VLogger.error("the number of nonlocal variables exceeds the limit; reduce nonlocal declarations or increase MAX_GLOBAL_NAMES", "ScopeDecl")
|
||||
return
|
||||
entry_addr: uint64 = uint64(trans._nonlocal_names) + trans._nonlocal_name_count * 8
|
||||
slot_ptr: str* = (str*)(entry_addr)
|
||||
@@ -983,7 +983,7 @@ novirtual class TranslatorGenMixin:
|
||||
# A None var_ty errors out (fail-fast) instead of defaulting to i32
|
||||
stored_ty: mlirlite.LLVMType* = var_ty
|
||||
if stored_ty is None:
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"nonlocal 变量 '{name}' 类型缺失,无法注册", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"nonlocal variable '{name}' has no type, cannot register", "TypeError")
|
||||
return
|
||||
ty_slot2[0] = stored_ty
|
||||
trans._nonlocal_name_count += 1
|
||||
|
||||
@@ -113,7 +113,7 @@ novirtual class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
# Table build failed (pool unusable/exhausted): report and return, never let the
|
||||
# append below hit None or an uninitialized address (would write NULL/0xCD).
|
||||
if tn is None or tv is None or td is None or tsf is None:
|
||||
self.Gen.TypeGenErr.fatal_error(None, "CDefine 表分配失败(表本体池不可用或耗尽)", "MemoryError")
|
||||
self.Gen.TypeGenErr.fatal_error(None, "CDefine table allocation failed (table body pool unavailable or exhausted)", "MemoryError")
|
||||
return
|
||||
self.CDefineNames = tn
|
||||
self.CDefineValues = tv
|
||||
@@ -123,11 +123,11 @@ novirtual class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
# Table-ready guard: missing/half-initialized body -> fail-fast, no garbage writes
|
||||
# (assert non-null before append).
|
||||
if self.CDefineNames is None or self.CDefineValues is None or self.CDefineDoubleFlags is None or self.CDefineStrFlags is None:
|
||||
self.Gen.TypeGenErr.fatal_error(None, "CDefine 表未就绪(CDefineNames/Values/Flags 为空)", "MemoryError")
|
||||
self.Gen.TypeGenErr.fatal_error(None, "CDefine table not ready (CDefineNames/Values/Flags is empty)", "MemoryError")
|
||||
return
|
||||
name_copy: str = pool.alloc(string.strlen(name) + 1)
|
||||
if name_copy is None:
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"CDefine '{name}' 名称缓冲区分配失败", "MemoryError")
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"CDefine '{name}' name buffer allocation failed", "MemoryError")
|
||||
return
|
||||
string.strcpy(name_copy, name)
|
||||
self.CDefineNames.append(name_copy)
|
||||
@@ -139,7 +139,7 @@ novirtual class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
else: self.CDefineValues.append("0")
|
||||
# fail-fast: a failed CDefine value buffer must abort compilation
|
||||
# (consistent with the double/string branches; do not silently write "0").
|
||||
if val_buf is None: self.Gen.TypeGenErr.fatal_error(None, f"CDefine '{name}' 值缓冲区分配失败", "MemoryError")
|
||||
if val_buf is None: self.Gen.TypeGenErr.fatal_error(None, f"CDefine '{name}' value buffer allocation failed", "MemoryError")
|
||||
if self.CDefineDoubleFlags is not None: self.CDefineDoubleFlags.append(0)
|
||||
if self.CDefineStrFlags is not None: self.CDefineStrFlags.append(0)
|
||||
def register_cdefine_double(self, pool: memhub.MemBuddy*, name: str, value: double) -> None:
|
||||
@@ -152,7 +152,7 @@ novirtual class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
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")
|
||||
self.Gen.TypeGenErr.fatal_error(None, "CDefine float table allocation failed (table body pool unavailable or exhausted)", "MemoryError")
|
||||
return
|
||||
self.CDefineNames = tn
|
||||
self.CDefineValues = tv
|
||||
@@ -161,11 +161,11 @@ novirtual class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
self._cdef_idx_init(tp)
|
||||
# Table-ready guard (same as register_cdefine_constant): assert non-null before append
|
||||
if self.CDefineNames is None or self.CDefineValues is None or self.CDefineDoubleFlags is None or self.CDefineStrFlags is None:
|
||||
self.Gen.TypeGenErr.fatal_error(None, "CDefine 浮点表未就绪(CDefineNames/Values/Flags 为空)", "MemoryError")
|
||||
self.Gen.TypeGenErr.fatal_error(None, "CDefine float table not ready (CDefineNames/Values/Flags is empty)", "MemoryError")
|
||||
return
|
||||
name_copy_d: str = pool.alloc(string.strlen(name) + 1)
|
||||
if name_copy_d is None:
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"CDefine 浮点 '{name}' 名称缓冲区分配失败", "MemoryError")
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"CDefine float '{name}' name buffer allocation failed", "MemoryError")
|
||||
return
|
||||
string.strcpy(name_copy_d, name)
|
||||
self.CDefineNames.append(name_copy_d)
|
||||
@@ -181,13 +181,13 @@ novirtual class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
if self.CDefineStrFlags is not None: self.CDefineStrFlags.append(0)
|
||||
# fail-fast: a failed CDefine value buffer must abort compilation
|
||||
if val_buf is None:
|
||||
VLogger.error("CDefine 浮点值缓冲区分配失败", "CDEF-DBG")
|
||||
self.Gen.TypeGenErr.fatal_error(None, "CDefine 浮点值缓冲区分配失败", "MemoryError")
|
||||
VLogger.error("CDefine float value buffer allocation failed", "CDEF-DBG")
|
||||
self.Gen.TypeGenErr.fatal_error(None, "CDefine float value buffer allocation failed", "MemoryError")
|
||||
def register_cdefine_string(self, pool: memhub.MemBuddy*, name: str, value: str) -> None:
|
||||
"""Register a string CDefine constant, deep-copying name and value into pool."""
|
||||
if pool is None or name is None: return
|
||||
if value is None:
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"CDefine 字符串值缺失: {name}", "InternalCompilerError")
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"CDefine string value missing: {name}", "InternalCompilerError")
|
||||
return
|
||||
if self.CDefineNames is None:
|
||||
tp: memhub.MemBuddy* = self._cdefine_table_pool(pool)
|
||||
@@ -196,7 +196,7 @@ novirtual class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
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")
|
||||
self.Gen.TypeGenErr.fatal_error(None, "CDefine string table allocation failed (table body pool unavailable or exhausted)", "MemoryError")
|
||||
return
|
||||
self.CDefineNames = tn
|
||||
self.CDefineValues = tv
|
||||
@@ -205,11 +205,11 @@ novirtual class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
self._cdef_idx_init(tp)
|
||||
# Table-ready guard (same as register_cdefine_constant): assert non-null before append
|
||||
if self.CDefineNames is None or self.CDefineValues is None or self.CDefineDoubleFlags is None or self.CDefineStrFlags is None:
|
||||
self.Gen.TypeGenErr.fatal_error(None, "CDefine 字符串表未就绪(CDefineNames/Values/Flags 为空)", "MemoryError")
|
||||
self.Gen.TypeGenErr.fatal_error(None, "CDefine string table not ready (CDefineNames/Values/Flags is empty)", "MemoryError")
|
||||
return
|
||||
ncopy_s: str = pool.alloc(string.strlen(name) + 1)
|
||||
if ncopy_s is None:
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"CDefine 字符串 '{name}' 名称缓冲区分配失败", "MemoryError")
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"CDefine string '{name}' name buffer allocation failed", "MemoryError")
|
||||
return
|
||||
string.strcpy(ncopy_s, name)
|
||||
self.CDefineNames.append(ncopy_s)
|
||||
@@ -217,7 +217,7 @@ novirtual class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
vlen: sizet = string.strlen(value)
|
||||
vcopy: str = pool.alloc(vlen + 1)
|
||||
if vcopy is None:
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"CDefine 字符串值分配失败: {name}", "MemoryError")
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"CDefine string value allocation failed: {name}", "MemoryError")
|
||||
return
|
||||
string.strcpy(vcopy, value)
|
||||
self.CDefineValues.append(vcopy)
|
||||
|
||||
@@ -131,7 +131,7 @@ class TypeGenCType(TypeGenBase.TypeGenBase):
|
||||
# Table creation failure: report and return; never let append write to
|
||||
# None or uninitialized memory (the old code crashed writing 0xCDCD).
|
||||
if tn is None or ts is None:
|
||||
VLogger.error("CTypedef 表分配失败(表本体池不可用或耗尽)", "TypeGen")
|
||||
VLogger.error("CTypedef table allocation failed (table body pool unavailable or exhausted)", "TypeGen")
|
||||
return
|
||||
self.CTypedefNames = tn
|
||||
self.CTypedefTypeStrs = ts
|
||||
@@ -139,7 +139,7 @@ class TypeGenCType(TypeGenBase.TypeGenBase):
|
||||
self._ctypedef_idx_init(tp)
|
||||
# table-ready guard: fail-fast when the table is missing rather than write garbage
|
||||
if self.CTypedefNames is None or self.CTypedefTypeStrs is None:
|
||||
VLogger.error("CTypedef 表未就绪(CTypedefNames/CTypedefTypeStrs 为空)", "TypeGen")
|
||||
VLogger.error("CTypedef table not ready (CTypedefNames/CTypedefTypeStrs is empty)", "TypeGen")
|
||||
return
|
||||
# dedup: if a same-named CTypedef exists, update its type string
|
||||
exist_n: sizet = len(self.CTypedefNames)
|
||||
@@ -442,7 +442,7 @@ class TypeGenCType(TypeGenBase.TypeGenBase):
|
||||
self.ConstEvalOk = 0
|
||||
return 0
|
||||
# Recursion depth guard: a cyclic BinOp would recurse forever; fail-fast abort.
|
||||
if depth > 64: self.Gen.TypeGenErr.fatal_type_error(node, "常量表达式递归过深(AST 环或嵌套超过 64 层)")
|
||||
if depth > 64: self.Gen.TypeGenErr.fatal_type_error(node, "constant expression recursion too deep (AST cycle or nesting over 64 levels)")
|
||||
k: int = node.kind()
|
||||
|
||||
# Constant: integer literal
|
||||
|
||||
@@ -89,7 +89,7 @@ novirtual class TypeGenErr(TypeGenBase.TypeGenBase):
|
||||
stdio.printf("^\n")
|
||||
stdlib.free(src)
|
||||
else: stdio.printf(' File "%s"\n', file_path)
|
||||
if err_msg is None or err_msg[0] == 0: err_msg = "语法错误"
|
||||
if err_msg is None or err_msg[0] == 0: err_msg = "syntax error"
|
||||
stdio.printf("SyntaxError: %s\n", err_msg)
|
||||
def fatal_error(self, node: ast.AST*, msg: str, err_type: str = "SyntaxError", col_start: int = 0, col_end: int = 0):
|
||||
"""Report an error in Python style and exit (supports multiple frames, error type, column range)."""
|
||||
@@ -129,7 +129,7 @@ novirtual class TypeGenErr(TypeGenBase.TypeGenBase):
|
||||
src_line = self._read_source_line(file_name, lineno)
|
||||
if src_line is None: line_ok = 0
|
||||
if line_ok == 0:
|
||||
stdio.printf(' File "%s", line %d (!! 无法读取该行源码:文件不存在或行号超出范围,错误可能来自被复用的 AST 树,请以错误消息为准)\n', file_name, lineno)
|
||||
stdio.printf(' File "%s", line %d (!! cannot read that source line: file does not exist or line number out of range; the error may come from a reused AST tree, rely on the error message)\n', file_name, lineno)
|
||||
else:
|
||||
stdio.printf(' File "%s", line %d\n', file_name, lineno)
|
||||
if src_line is not None:
|
||||
@@ -175,7 +175,7 @@ novirtual class TypeGenErr(TypeGenBase.TypeGenBase):
|
||||
if node is None or marker_name is None: return 0
|
||||
# Recursion depth guard: vpi stub injection calls this for every function's returns, and
|
||||
# deep vpi nodes may be corrupted into back-pointing cycles (VpiReader L810-813); fail fast.
|
||||
if depth > 128: self.fatal_type_error(node, "装饰器标记检测递归过深(AST 环或嵌套超过 128 层)")
|
||||
if depth > 128: self.fatal_type_error(node, "decorator marker detection recursion too deep (AST cycle or nesting over 128 levels)")
|
||||
|
||||
k: int = node.kind()
|
||||
|
||||
|
||||
@@ -140,7 +140,7 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
es3: str = self._subscript_slice_to_str(pool, e3)
|
||||
if es3 is None:
|
||||
# Missing type name: error out immediately (a silent drop builds a wrong type string)
|
||||
self.Gen.TypeGenErr.fatal_error(e3, "类型注解的元素无法解析为类型名(列表/元组注解)", "NameError")
|
||||
self.Gen.TypeGenErr.fatal_error(e3, "Type annotation element cannot be resolved to a type name (list/tuple annotation)", "NameError")
|
||||
return None
|
||||
cnt3 += 1
|
||||
total3 += string.strlen(es3)
|
||||
@@ -319,7 +319,7 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
# [FIX] Out-of-range type-name pointer (garbage from pool overwrite): fail-fast
|
||||
# before dereferencing instead of segfaulting silently in strlen.
|
||||
if uint64(type_name) > 0x00007FFFFFFFFFFF:
|
||||
VLogger.error(f"_norm_type_arg_name 类型名指针越界 (ptr={uint64(type_name)}),疑似 pool 越界写破坏类型名指针", "TypeGen")
|
||||
VLogger.error(f"_norm_type_arg_name type name pointer out of range (ptr={uint64(type_name)}); a pool out-of-bounds write likely corrupted the type name pointer", "TypeGen")
|
||||
stdlib.exit(1)
|
||||
# [FIX] Generic-arg split leaves a leading space on the second arg (" 4"); leading
|
||||
# whitespace is dirty data as a type name / table key, so skip it before normalizing.
|
||||
@@ -612,7 +612,7 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
_w_buf[0] = '\0'
|
||||
mlirlite.TypePrint(_w_buf, 512, _bare_entry.Ty, pool)
|
||||
if _w_buf[0] != '\0': _w_ty = _w_buf
|
||||
VLogger.error(f"[类型实参归属] 裸类名 '{type_name}' 本次保留裸名(可能与带前缀形式分裂):" f"entry_present={_w_ep} entry.Ty={_w_ty} cur_def_mod={_w_mod} cur_def_cls={_w_cls} " f"is_module_class={_w_imc} find_struct_by_module={_w_fbm} " f"from_imports={_w_fi} file={_w_file}", "TypeGen")
|
||||
VLogger.error(f"[TypeArgOwnership] bare class name '{type_name}' keeps the bare name this time (may split from the prefixed form):" f"entry_present={_w_ep} entry.Ty={_w_ty} cur_def_mod={_w_mod} cur_def_cls={_w_cls} " f"is_module_class={_w_imc} find_struct_by_module={_w_fbm} " f"from_imports={_w_fi} file={_w_file}", "TypeGen")
|
||||
# ---- 6. not found: keep as-is (builtin type names etc.) ----
|
||||
return type_name
|
||||
|
||||
@@ -1858,14 +1858,14 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
# gen_mangled; re-query using spec_name_chk, the authoritative name.
|
||||
if gen_spec_ty is None: gen_spec_ty = self.Gen.StructGen.get_struct_type(spec_name_chk)
|
||||
if gen_spec_ty is not None: return gen_spec_ty
|
||||
else: VLogger.info(f"[GENERIC-DBG] 特化失败(返回 None): {gen_cls_name}[{gen_mangled}]", "Phase1")
|
||||
else: VLogger.info(f"[GENERIC-DBG] 类型实参提取失败: {gen_cls_name}", "Phase1")
|
||||
else: VLogger.info(f"[GENERIC-DBG] 模板未注册: {gen_cls_name}", "Phase1")
|
||||
else: VLogger.info(f"[GENERIC-DBG] trans 为 None: {gen_cls_name}", "Phase1")
|
||||
else: VLogger.info(f"[GENERIC-DBG] specialization failed (returned None): {gen_cls_name}[{gen_mangled}]", "Phase1")
|
||||
else: VLogger.info(f"[GENERIC-DBG] type argument extraction failed: {gen_cls_name}", "Phase1")
|
||||
else: VLogger.info(f"[GENERIC-DBG] template not registered: {gen_cls_name}", "Phase1")
|
||||
else: VLogger.info(f"[GENERIC-DBG] trans is None: {gen_cls_name}", "Phase1")
|
||||
# In Phase B full translation, if a generic template subscript still cannot resolve,
|
||||
# the annotation would silently degrade and crash; report it instead (template names only).
|
||||
if trans is not None and trans._declare_only == 0 and self.Gen.ClassGenGeneric._find_generic_template(gen_cls_name) is not None:
|
||||
self.Gen.TypeGenErr.fatal_error(sub, f"泛型下标 '{gen_mangled}' 未解析出特化结构体(泛型模板='{gen_cls_name}');" f"该注解将退化为裸基类/i8* → 后续 .get() 按错误元素类型分派并截断指针", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(sub, f"Generic subscript '{gen_mangled}' did not resolve to a specialized struct (generic template='{gen_cls_name}'); " f"the annotation will degrade to a bare base class/i8* -> later .get() dispatches on the wrong element type and truncates pointers", "TypeError")
|
||||
# [REPL session] includes generic templates are unregistered, so build an opaque
|
||||
# placeholder "%{template module sha1}.{mangled}" using the registered owner sha1.
|
||||
if trans is not None and trans.ReplCtx is not None:
|
||||
@@ -1893,14 +1893,14 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
if base_nm is None: return 0
|
||||
# Only treat it as a bare generic annotation if the base name is a registered template
|
||||
if self.Gen.ClassGenGeneric._find_generic_template(base_nm) is None: return 0
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"泛型类 '{base_nm}' 的注解必须带类型实参(如 {base_nm}[T]);" f"裸名会被当作无实参的裸泛型基类,元素类型丢失后方法调用会按错误元素" f"类型特化并截断指针。正确写法示例:vector.Vector[CInt]、GSList[G5Node]。", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"The annotation of generic class '{base_nm}' must carry type arguments (e.g. {base_nm}[T]); " f"a bare name is treated as a bare generic base class without arguments, and once the element type is lost, method calls specialize on the wrong element " f"type and truncate pointers. Correct examples: vector.Vector[CInt], GSList[G5Node].", "TypeError")
|
||||
return 0
|
||||
def resolve_annotation_type(self, pool: memhub.MemBuddy*, node: ast.AST*, imported_modules: str, from_imports: str, trans: HT.Translator* = None, depth: int = 0) -> mlirlite.LLVMType*:
|
||||
"""Resolve a type-annotation node into an LLVMType."""
|
||||
if node is None: return None
|
||||
# Recursion-depth guard: a corrupted self-referential AST would recurse until stack
|
||||
# exhaustion; fail-fast beyond 128 levels instead of silently falling back.
|
||||
if depth > 128: self.Gen.TypeGenErr.fatal_type_error(node, "类型注解递归过深(AST 环或嵌套超过 128 层)")
|
||||
if depth > 128: self.Gen.TypeGenErr.fatal_type_error(node, "Type annotation recursion too deep (AST cycle or nesting beyond 128 levels)")
|
||||
|
||||
# Bare generic annotation fail-fast (see _check_bare_generic_annotation): abort when a
|
||||
# registered generic template name appears without type args.
|
||||
@@ -1924,7 +1924,7 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
# Builtin fixed-array constructor array is a soft keyword: only active as
|
||||
# array[E, N] in type/annotation positions; a bare use there is a fail-fast misuse.
|
||||
if string.strcmp(nm.id, "array") == 0:
|
||||
self.Gen.TypeGenErr.fatal_type_error(nm, "裸用内建定长数组构造子 'array'(缺少下标与参数):'array' 只在类型/注解位置生效,必须写成 array[E, N](元素类型在前、长度在后)。正确示例:state: array[uint32, 4]")
|
||||
self.Gen.TypeGenErr.fatal_type_error(nm, "Bare use of the built-in fixed-size array constructor 'array' (missing subscript and arguments): 'array' only takes effect in type/annotation position and must be written as array[E, N] (element type first, length second). Correct example: state: array[uint32, 4]")
|
||||
# Generic parameter T substitution: replace T with the concrete type in specialization
|
||||
tpn_g: list[str]* = self.Gen.TypeGenBase.GenericTpNames
|
||||
tpa_g: list[str]* = self.Gen.TypeGenBase.GenericTypeArgs
|
||||
@@ -1941,7 +1941,7 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
if string.strcmp(gp_ta, gp_tpn) == 0:
|
||||
# Generic param self-map (T->T): report a compile error rather
|
||||
# than silently degrade (which causes hard-to-locate runtime corruption).
|
||||
self.Gen.TypeGenErr.fatal_error(nm, f"泛型类型实参污染:类型参数 '{gp_tpn}' 自映射(实参='{gp_ta}'),无法特化", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(nm, f"Generic type argument pollution: type parameter '{gp_tpn}' maps to itself (argument='{gp_ta}'); cannot specialize", "TypeError")
|
||||
polluted: int = 0
|
||||
gp_j: sizet
|
||||
for gp_j in range(gp_n):
|
||||
@@ -1954,7 +1954,7 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
if polluted != 0:
|
||||
# Arg string contains a type-param name (e.g. "T*"/"list[T]"): it
|
||||
# would recurse forever, so report a compile error (was a silent None).
|
||||
self.Gen.TypeGenErr.fatal_error(nm, f"泛型类型实参污染:实参 '{gp_ta}' 包含类型参数名,无法特化", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(nm, f"Generic type argument pollution: argument '{gp_ta}' contains a type parameter name; cannot specialize", "TypeError")
|
||||
# Recurse using the concrete type name (supports BinOp/Attribute args)
|
||||
gp_sub_node: ast.AST* = self._parse_type_string(pool, gp_ta, nm.ctx)
|
||||
if gp_sub_node is not None: return self.resolve_annotation_type(pool, gp_sub_node, imported_modules, from_imports, trans, depth + 1)
|
||||
@@ -2417,10 +2417,10 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
# list[int] -> specialized struct type. value is Attribute(Name('t'),'CArray') or Name('list').
|
||||
if k == ast.ASTKind.Subscript:
|
||||
sub: ast.Subscript* = ast.Subscript*(node)
|
||||
if sub.value is None: self.Gen.TypeGenErr.fatal_type_error(node, "Subscript 节点缺少 value")
|
||||
if sub.value is None: self.Gen.TypeGenErr.fatal_type_error(node, "Subscript node missing value")
|
||||
# An empty subscript (t.Callable[]) has slice None: allowed only for unsigned function
|
||||
# pointers (handled as i8* below); other types still require a slice.
|
||||
if sub.slice is None and self._IsCallableSubscriptValue(sub.value) == 0: self.Gen.TypeGenErr.fatal_type_error(node, "Subscript 节点缺少 value 或 slice")
|
||||
if sub.slice is None and self._IsCallableSubscriptValue(sub.value) == 0: self.Gen.TypeGenErr.fatal_type_error(node, "Subscript node missing value or slice")
|
||||
# Function pointers (bare callable / Callable) equal t.Callable point-for-point and
|
||||
# map to i8*; must be checked before the Name path (generic/CArray/builtins fallback).
|
||||
if sub.value.kind() == ast.ASTKind.Name and self._IsCallableSubscriptValue(sub.value) != 0: return mlirlite.Ptr(pool, mlirlite.Int8(pool))
|
||||
@@ -2432,22 +2432,22 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
# active only in type positions; only exactly two args with a positive length.
|
||||
if string.strcmp(gen_nm.id, "array") == 0:
|
||||
if sub.slice.kind() != ast.ASTKind.Tuple:
|
||||
self.Gen.TypeGenErr.fatal_type_error(node, "内建定长数组构造子 'array' 缺少长度参数(当前仅 1 个参数):必须写成 array[E, N](E=元素类型,N=长度)。正确示例:state: array[uint32, 4]")
|
||||
self.Gen.TypeGenErr.fatal_type_error(node, "Built-in fixed-size array constructor 'array' missing length argument (currently only 1 argument): must be written as array[E, N] (E=element type, N=length). Correct example: state: array[uint32, 4]")
|
||||
tup_arr: ast.Tuple* = ast.Tuple*(sub.slice)
|
||||
if tup_arr.elts is None or len(tup_arr.elts) != 2: self.Gen.TypeGenErr.fatal_type_error(node, "内建定长数组构造子 'array' 参数个数错误(期望 2 个):只接受 array[E, N]。正确示例:state: array[uint32, 4]")
|
||||
if tup_arr.elts is None or len(tup_arr.elts) != 2: self.Gen.TypeGenErr.fatal_type_error(node, "Built-in fixed-size array constructor 'array' has a wrong argument count (expected 2): only array[E, N] is accepted. Correct example: state: array[uint32, 4]")
|
||||
elem_node_arr: ast.AST* = tup_arr.elts.get(0)
|
||||
count_node_arr: ast.AST* = tup_arr.elts.get(1)
|
||||
if elem_node_arr is None or count_node_arr is None: self.Gen.TypeGenErr.fatal_type_error(node, "内建定长数组构造子 'array' 的元素类型或长度为空:只接受 array[E, N]。正确示例:state: array[uint32, 4]")
|
||||
if elem_node_arr is None or count_node_arr is None: self.Gen.TypeGenErr.fatal_type_error(node, "Built-in fixed-size array constructor 'array' has an empty element type or length: only array[E, N] is accepted. Correct example: state: array[uint32, 4]")
|
||||
if count_node_arr.kind() == ast.ASTKind.Constant:
|
||||
cnt_arr0: ast.Constant* = ast.Constant*(count_node_arr)
|
||||
if cnt_arr0.const_kind == ast.CONST_NONE:
|
||||
self.Gen.TypeGenErr.fatal_type_error(count_node_arr, "内建定长数组构造子 'array' 的长度必须是正整型常量(>0),不允许 None(长度自动推导请改用 t.CArray[E])。正确示例:state: array[uint32, 4]")
|
||||
self.Gen.TypeGenErr.fatal_type_error(count_node_arr, "Built-in fixed-size array constructor 'array' length must be a positive integer constant (>0); None is not allowed (use t.CArray[E] for automatic length inference). Correct example: state: array[uint32, 4]")
|
||||
elem_ty_arr: mlirlite.LLVMType* = self.resolve_annotation_type(pool, elem_node_arr, imported_modules, from_imports, trans, depth + 1)
|
||||
if elem_ty_arr is None: return None
|
||||
count_arr: int = self.Gen.TypeGenCType._eval_const_int_expr(count_node_arr, pool, from_imports, imported_modules)
|
||||
if self.Gen.TypeGenCType.ConstEvalOk == 0:
|
||||
self.Gen.TypeGenErr.fatal_type_error(count_node_arr, "内建定长数组构造子 'array' 的长度必须是整型常量表达式(字面量 / CDefine 常量名 / 常量算术表达式)。正确示例:state: array[uint8, MAX_LEN]")
|
||||
if count_arr <= 0: self.Gen.TypeGenErr.fatal_type_error(count_node_arr, "内建定长数组构造子 'array' 的长度必须为正数。正确示例:state: array[uint32, 4]")
|
||||
self.Gen.TypeGenErr.fatal_type_error(count_node_arr, "Built-in fixed-size array constructor 'array' length must be an integer constant expression (literal / CDefine constant name / constant arithmetic expression). Correct example: state: array[uint8, MAX_LEN]")
|
||||
if count_arr <= 0: self.Gen.TypeGenErr.fatal_type_error(count_node_arr, "Built-in fixed-size array constructor 'array' length must be positive. Correct example: state: array[uint32, 4]")
|
||||
return mlirlite.Array(pool, elem_ty_arr, count_arr)
|
||||
# Bare CArray (from t import *): equivalent to t.CArray; otherwise generic
|
||||
# lookup fails, the field type degrades to Ptr(i8), and linking fails.
|
||||
@@ -2505,29 +2505,29 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
if fb_ty is not None: return fb_ty
|
||||
return None
|
||||
# Check whether value is an Attribute (t.CArray / t.Callable / module-qualified generic like numpy.ndarray[T])
|
||||
if sub.value.kind() != ast.ASTKind.Attribute: self.Gen.TypeGenErr.fatal_type_error(node, "不支持的 Subscript 类型注解(仅支持 t.CArray / t.Callable)")
|
||||
if sub.value.kind() != ast.ASTKind.Attribute: self.Gen.TypeGenErr.fatal_type_error(node, "Unsupported Subscript type annotation (only t.CArray / t.Callable are supported)")
|
||||
arr_at: ast.Attribute* = ast.Attribute*(sub.value)
|
||||
if arr_at.attr is None: self.Gen.TypeGenErr.fatal_type_error(node, "Subscript Attribute 缺少 attr")
|
||||
if arr_at.attr is None: self.Gen.TypeGenErr.fatal_type_error(node, "Subscript Attribute missing attr")
|
||||
# Module-qualified generic class: numpy.ndarray[t.CDouble] -> use the bare class name
|
||||
# ndarray for specialization (before the t.CArray / t.Callable checks).
|
||||
if trans is not None:
|
||||
if self.Gen.ClassGenGeneric._find_generic_template(arr_at.attr) is not None:
|
||||
return self._resolve_generic_subscript_ty(pool, sub, arr_at.attr, trans, imported_modules, from_imports, depth + 1)
|
||||
if arr_at.value is None or arr_at.value.kind() != ast.ASTKind.Name: self.Gen.TypeGenErr.fatal_type_error(node, "t.CArray / t.Callable 必须通过模块名限定")
|
||||
if arr_at.value is None or arr_at.value.kind() != ast.ASTKind.Name: self.Gen.TypeGenErr.fatal_type_error(node, "t.CArray / t.Callable must be qualified by the module name")
|
||||
arr_val_name: ast.Name* = ast.Name*(arr_at.value)
|
||||
if arr_val_name.id is None: self.Gen.TypeGenErr.fatal_type_error(node, "Subscript 模块名为 None")
|
||||
if arr_val_name.id is None: self.Gen.TypeGenErr.fatal_type_error(node, "Subscript module name is None")
|
||||
# Function pointer type: t.Callable[[A, B], Ret] -> i8* (function values are bitcast to
|
||||
# i8* for storage and the signature is rebuilt at calls, matching TPV convention).
|
||||
if string.strcmp(arr_at.attr, "Callable") == 0:
|
||||
# t/c are builtin namespaces (not compiled, not in imported_modules); no import check needed
|
||||
if string.strcmp(arr_val_name.id, "t") != 0 and string.strcmp(arr_val_name.id, "c") != 0 and self.Gen.ImportsGen.is_module_imported(imported_modules, arr_val_name.id) == 0:
|
||||
self.Gen.TypeGenErr.fatal_type_error(node, "t.Callable 模块未导入")
|
||||
self.Gen.TypeGenErr.fatal_type_error(node, "t.Callable module not imported")
|
||||
return mlirlite.Ptr(pool, mlirlite.Int8(pool))
|
||||
# Pointer type: t.CPtr[T] -> Ptr(T); always appends exactly 1 layer, no exceptions
|
||||
# (`t.CPtr[T]` == `T*`). The old "absorb a layer" compensation is removed.
|
||||
if string.strcmp(arr_at.attr, "CPtr") == 0:
|
||||
if string.strcmp(arr_val_name.id, "t") != 0 and string.strcmp(arr_val_name.id, "c") != 0 and self.Gen.ImportsGen.is_module_imported(imported_modules, arr_val_name.id) == 0:
|
||||
self.Gen.TypeGenErr.fatal_type_error(node, "t.CPtr 模块未导入")
|
||||
self.Gen.TypeGenErr.fatal_type_error(node, "t.CPtr module not imported")
|
||||
inner_cptr_ty: mlirlite.LLVMType* = self.resolve_annotation_type(pool, sub.slice, imported_modules, from_imports, trans, depth + 1)
|
||||
if inner_cptr_ty is None:
|
||||
# Element type not ready (class not yet registered): prefer a forward declaration
|
||||
@@ -2536,9 +2536,9 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
if _fwd_cptr_ty is not None: return _fwd_cptr_ty
|
||||
return None
|
||||
return mlirlite.Ptr(pool, inner_cptr_ty)
|
||||
if string.strcmp(arr_at.attr, "CArray") != 0: self.Gen.TypeGenErr.fatal_type_error(node, "不支持的 Subscript 类型注解(仅支持 t.CArray / t.Callable)")
|
||||
if string.strcmp(arr_at.attr, "CArray") != 0: self.Gen.TypeGenErr.fatal_type_error(node, "Unsupported Subscript type annotation (only t.CArray / t.Callable are supported)")
|
||||
if string.strcmp(arr_val_name.id, "t") != 0 and string.strcmp(arr_val_name.id, "c") != 0 and self.Gen.ImportsGen.is_module_imported(imported_modules, arr_val_name.id) == 0:
|
||||
self.Gen.TypeGenErr.fatal_type_error(node, "t.CArray 模块未导入")
|
||||
self.Gen.TypeGenErr.fatal_type_error(node, "t.CArray module not imported")
|
||||
# Single-arg form: t.CArray[elem_ty] -> Ptr(elem_ty), equivalent to
|
||||
# t.CArray[elem_ty, None] (statically inferred length array).
|
||||
if sub.slice.kind() != ast.ASTKind.Tuple:
|
||||
@@ -2549,13 +2549,13 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
return mlirlite.Ptr(pool, elem_ty_single)
|
||||
# Two-arg form: t.CArray[elem_ty, count] -> [count x elem_ty]
|
||||
tup: ast.Tuple* = ast.Tuple*(sub.slice)
|
||||
if tup.elts is None: self.Gen.TypeGenErr.fatal_type_error(node, "t.CArray Tuple 缺少 elts")
|
||||
if tup.elts is None: self.Gen.TypeGenErr.fatal_type_error(node, "t.CArray Tuple missing elts")
|
||||
elts_list: list[ast.AST*]* = tup.elts
|
||||
elts_n: sizet = len(elts_list)
|
||||
if elts_n < 2: self.Gen.TypeGenErr.fatal_type_error(node, "t.CArray Tuple 元素不足")
|
||||
if elts_n < 2: self.Gen.TypeGenErr.fatal_type_error(node, "t.CArray Tuple has too few elements")
|
||||
elem_node: ast.AST* = elts_list.get(0)
|
||||
count_node: ast.AST* = elts_list.get(1)
|
||||
if elem_node is None or count_node is None: self.Gen.TypeGenErr.fatal_type_error(node, "t.CArray Tuple 元素为 None")
|
||||
if elem_node is None or count_node is None: self.Gen.TypeGenErr.fatal_type_error(node, "t.CArray Tuple element is None")
|
||||
# Recursively resolve the element type
|
||||
elem_ty: mlirlite.LLVMType* = self.resolve_annotation_type(pool, elem_node, imported_modules, from_imports, trans, depth + 1)
|
||||
if elem_ty is None:
|
||||
@@ -2571,14 +2571,14 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
# Use _eval_const_int_expr for the constant integer expression (Constant/Name/BinOp);
|
||||
# pool/from_imports/imported_modules enable cross-module CDefine lookup.
|
||||
count_val = self.Gen.TypeGenCType._eval_const_int_expr(count_node, pool, from_imports, imported_modules)
|
||||
if self.Gen.TypeGenCType.ConstEvalOk == 0: self.Gen.TypeGenErr.fatal_type_error(count_node, "t.CArray count 必须是整数常量、None、CDefine 常量名或常量表达式")
|
||||
if count_val <= 0: self.Gen.TypeGenErr.fatal_type_error(count_node, "t.CArray count 必须为正数")
|
||||
if self.Gen.TypeGenCType.ConstEvalOk == 0: self.Gen.TypeGenErr.fatal_type_error(count_node, "t.CArray count must be an integer constant, None, a CDefine constant name, or a constant expression")
|
||||
if count_val <= 0: self.Gen.TypeGenErr.fatal_type_error(count_node, "t.CArray count must be positive")
|
||||
# Create the ArrayType (no Ptr wrapping), so build_alloca allocates the array
|
||||
# and alloca returns [N x elem_ty]*.
|
||||
return mlirlite.Array(pool, elem_ty, count_val)
|
||||
|
||||
# Unknown AST kind: fail-fast instead of leniently returning None
|
||||
self.Gen.TypeGenErr.fatal_type_error(node, "不支持的类型注解语法")
|
||||
self.Gen.TypeGenErr.fatal_type_error(node, "Unsupported type annotation syntax")
|
||||
# Append an explicit return after fatal_type_error (unreachable at runtime) so the
|
||||
# method's final block is properly terminated without a noreturn whitelist.
|
||||
return None
|
||||
@@ -627,7 +627,7 @@ def InternSpec(arena: TypeSpecArena*, sp: TypeSpec*) -> TypeSpec*:
|
||||
# Miss: append. Table full = fail-fast (never return None, which would silently
|
||||
# lose type info up the call chain and corrupt signedness -> zext/sext direction).
|
||||
if arena.Count >= arena.Cap:
|
||||
GenApi.fatal_error(None, f"TypeSpec 驻留表已满(上限 {arena.Cap} 条),无法登记新类型", "InternalCompilerError")
|
||||
GenApi.fatal_error(None, f"TypeSpec intern table is full (limit {arena.Cap} entries), cannot register a new type", "InternalCompilerError")
|
||||
# Reachable only when fatal_error is a no-op: degrade to "no interning but return a
|
||||
# complete instance", keeping the never-return-None guarantee.
|
||||
return sp
|
||||
|
||||
@@ -114,7 +114,7 @@ novirtual class VarGenMixin:
|
||||
# A ptr-element variable's alloca is Ptr(Ptr(Int8)), so its value type implies Spec PtrLevel>=1.
|
||||
# Violation means an upstream type error; fail-fast, since a silent pass would mis-index by 1 byte.
|
||||
if entry.Spec is None or entry.Spec.PtrLevel < 1:
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"变量 '{name}' 标记为 ptr-element,但其 Spec 不可承载指针语义", "InternalCompilerError")
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"variable '{name}' is marked as ptr-element, but its Spec cannot carry pointer semantics", "InternalCompilerError")
|
||||
return 1
|
||||
entry.Spec = TSpec.SpecWithElemBits(entry.Spec, 64)
|
||||
return 0
|
||||
@@ -367,7 +367,7 @@ novirtual class VarGenMixin:
|
||||
if existing is not None: return existing
|
||||
alloca: mlirlite.Value* = self._alloca_at_entry(builder, ty)
|
||||
if alloca is None: return None
|
||||
if self.define_var(symtab, name, alloca) != 0: self.Gen.TypeGenErr.fatal_error(None, f"变量 '{name}' 注册失败(作用域变量数超过上限 MAX_VARS)", "InternalCompilerError")
|
||||
if self.define_var(symtab, name, alloca) != 0: self.Gen.TypeGenErr.fatal_error(None, f"failed to register variable '{name}' (scope variable count exceeds the limit MAX_VARS)", "InternalCompilerError")
|
||||
return alloca
|
||||
|
||||
# REPL mode (M2) - session variable slot read/write; entered only when trans.ReplCtx != None (slots hold the value at ctx + x.Offset).
|
||||
@@ -404,7 +404,7 @@ novirtual class VarGenMixin:
|
||||
symtab: GenTypes.SymbolTable* = trans.SymTab
|
||||
param_alloca: mlirlite.Value* = self.lookup_var(symtab, ctx.CtxParam)
|
||||
if param_alloca is None or param_alloca.Ty is None or param_alloca.Ty.Pointee == 0:
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: 片段函数缺少 ctx 形参 '{ctx.CtxParam}'(包裹模板与 M2 调用约定不一致)", "InternalCompilerError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: snippet function is missing the ctx parameter '{ctx.CtxParam}' (wrapper template and M2 calling convention disagree)", "InternalCompilerError")
|
||||
return None
|
||||
return mlirlite.build_load(trans._cur_builder, param_alloca.Ty.Pointee, param_alloca)
|
||||
|
||||
@@ -464,10 +464,10 @@ novirtual class VarGenMixin:
|
||||
if self.repl_in_frag_scope(trans.SymTab) == 0: return None
|
||||
hit[0] = 1
|
||||
if kw_count != 0:
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: 会话函数 '{func_name}' 不支持关键字实参(M3 仅支持位置实参)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: session function '{func_name}' does not support keyword arguments (M3 supports positional arguments only)", "TypeError")
|
||||
return None
|
||||
if can != entry.ParamCount:
|
||||
self.Gen.TypeGenErr.fatal_error( node, f"REPL: 会话函数 '{func_name}' 期待 {entry.ParamCount} 个位置实参,调用处给了 {can} 个(M3 不支持默认参数/缺省补全)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error( node, f"REPL: session function '{func_name}' expects {entry.ParamCount} positional arguments, but the call site passed {can} (M3 does not support default arguments or default completion)", "TypeError")
|
||||
return None
|
||||
ctx_val: mlirlite.Value* = self.repl_ctx_ptr(trans, ctx, node)
|
||||
if ctx_val is None: return None
|
||||
@@ -476,11 +476,11 @@ novirtual class VarGenMixin:
|
||||
# (1) Load the function address from the slot: the slot is i8** (Ptr(i8*)); load yields i8*
|
||||
slot: mlirlite.Value* = self.repl_slot_ptr(pool, builder, ctx_val, entry.SlotOff, i8_ptr_ty)
|
||||
if slot is None:
|
||||
self.Gen.TypeGenErr.fatal_error(node, "REPL: 会话函数指针槽地址生成失败", "InternalCompilerError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, "REPL: failed to generate the session function pointer slot address", "InternalCompilerError")
|
||||
return None
|
||||
fn_i8: mlirlite.Value* = mlirlite.build_load(builder, i8_ptr_ty, slot)
|
||||
if fn_i8 is None:
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: 会话函数 '{func_name}' 的地址读取失败", "InternalCompilerError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: failed to read the address of session function '{func_name}'", "InternalCompilerError")
|
||||
return None
|
||||
# (2) Resolve param types before building the signature (token -> LLVM type; unsupported -> error)
|
||||
ptypes: t.CPtr = pool.alloc(8 * GenTypes.REPL_FUNC_PARAM_MAX)
|
||||
@@ -490,7 +490,7 @@ novirtual class VarGenMixin:
|
||||
for ai_chk in range(entry.ParamCount):
|
||||
pty_chk: mlirlite.LLVMType* = self.repl_func_ty(pool, int(entry.ParamTags[ai_chk]), int(entry.ParamBits[ai_chk]))
|
||||
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")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: type token of parameter {ai_chk + 1} of session function '{func_name}' is not supported (M3 supports iN/float/double/i8*)", "TypeError")
|
||||
return None
|
||||
pty_slot: str* = (str*)(uint64(ptypes) + ai_chk * 8)
|
||||
pty_slot[0] = pty_chk
|
||||
@@ -503,17 +503,17 @@ novirtual class VarGenMixin:
|
||||
for ai in range(entry.ParamCount):
|
||||
arg: ast.AST* = cargs.get(ai)
|
||||
if arg is None:
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: 会话函数 '{func_name}' 的第 {ai + 1} 个实参缺失", "SyntaxError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: argument {ai + 1} of session function '{func_name}' is missing", "SyntaxError")
|
||||
return None
|
||||
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:
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: 会话函数 '{func_name}' 的第 {ai + 1} 个实参翻译失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: failed to translate argument {ai + 1} of session function '{func_name}'", "TypeError")
|
||||
return None
|
||||
coerced: mlirlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val, pty, arg, trans)
|
||||
if coerced is None:
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: 会话函数 '{func_name}' 的第 {ai + 1} 个实参与签名类型不兼容", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: argument {ai + 1} of session function '{func_name}' is incompatible with the signature type", "TypeError")
|
||||
return None
|
||||
coerced.Next = None
|
||||
tail.Next = coerced
|
||||
@@ -525,7 +525,7 @@ novirtual class VarGenMixin:
|
||||
if entry.RetTag != GenTypes.REPL_TY_VOID:
|
||||
ret_ty = self.repl_func_ty(pool, entry.RetTag, entry.RetBits)
|
||||
if ret_ty is None:
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: 会话函数 '{func_name}' 的返回类型 token 不受支持(M3 支持 void/iN/float/double/i8*)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: return type token of session function '{func_name}' is not supported (M3 supports void/iN/float/double/i8*)", "TypeError")
|
||||
return None
|
||||
# Param list nodes are mlirlite.ParamNode (new_param_node returns rawptr[ParamNode], and
|
||||
# paramnode_set_next / Func params are rawptr[ParamNode] too) - previously mistyped as Function*.
|
||||
@@ -547,7 +547,7 @@ novirtual class VarGenMixin:
|
||||
func_ptr_ty: mlirlite.LLVMType* = mlirlite.Ptr(pool, func_ty)
|
||||
fn_typed: mlirlite.Value* = mlirlite.build_bitcast(builder, fn_i8, func_ptr_ty)
|
||||
if fn_typed is None:
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: 会话函数 '{func_name}' 的地址转换失败", "InternalCompilerError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: failed to convert the address of session function '{func_name}'", "InternalCompilerError")
|
||||
return None
|
||||
return mlirlite.build_call_indirect(builder, fn_typed, head, arg_count, ret_ty)
|
||||
|
||||
@@ -696,7 +696,7 @@ novirtual class VarGenMixin:
|
||||
if trans is None or entry is None or val_ty is None: return 1
|
||||
perm: memhub.MemBuddy* = self.repl_perm_pool(trans)
|
||||
if perm is None:
|
||||
self.Gen.TypeGenErr.fatal_error(node, "REPL: 会话永久池不可用(宿主未注入)", "InternalCompilerError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, "REPL: session permanent pool is unavailable (not injected by the host)", "InternalCompilerError")
|
||||
return 1
|
||||
tag: int = 0
|
||||
bits: int = 0
|
||||
@@ -740,17 +740,17 @@ novirtual class VarGenMixin:
|
||||
sz: int = self.repl_type_size(val_ty)
|
||||
al: int = self.repl_type_align(val_ty)
|
||||
if sz <= 0 or al <= 0:
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: 会话变量 '{entry.Name}' 的结构体值 '{sname}' 尺寸/对齐未知" f"(无法判定能否放入 {GenTypes.REPL_SLOT_SIZE} 字节槽)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: size/alignment of the struct value '{sname}' of session variable '{entry.Name}' is unknown" f" (cannot determine whether it fits in a {GenTypes.REPL_SLOT_SIZE} byte slot)", "TypeError")
|
||||
return 1
|
||||
if sz > GenTypes.REPL_SLOT_SIZE or al > GenTypes.REPL_SLOT_SIZE:
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: 会话变量 '{entry.Name}' 的结构体值 '{sname}' 体积 {sz} 字节、" f"对齐 {al} 字节,无法放入 {GenTypes.REPL_SLOT_SIZE} 字节槽" f"(M2 结构体值须内联进槽;大对象请改用对象指针/堆分配)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: struct value '{sname}' of session variable '{entry.Name}' is {sz} bytes and " f"aligned to {al} bytes, so it cannot fit in a {GenTypes.REPL_SLOT_SIZE} byte slot" f" (M2 struct values must be inlined into the slot; use an object pointer or heap allocation for large objects)", "TypeError")
|
||||
return 1
|
||||
tag = GenTypes.REPL_TY_STRUCT
|
||||
bits = sz * 8
|
||||
kind = GenTypes.REPL_KIND_SCALAR
|
||||
tname = sname
|
||||
else:
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: 会话变量 '{entry.Name}' 的类型暂不支持" f"(M2 支持 int/bool/浮点/str/bytes/指针/结构体值)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: the type of session variable '{entry.Name}' is not supported yet" f" (M2 supports int/bool/float/str/bytes/pointer/struct value)", "TypeError")
|
||||
return 1
|
||||
if entry.Kind == GenTypes.REPL_KIND_UNTYPED:
|
||||
entry.Kind = kind
|
||||
@@ -760,7 +760,7 @@ novirtual class VarGenMixin:
|
||||
if tname is not None: entry.TyName = self.repl_perm_strdup(perm, tname)
|
||||
return 0
|
||||
if entry.Kind != kind or entry.TyTag != tag:
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: 会话变量 '{entry.Name}' 已定型为 {self.repl_tag_label(entry.TyTag, entry.Bits)}," f"不能再赋成 {self.repl_tag_label(tag, bits)}(如需换型请重启会话)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: session variable '{entry.Name}' is already typed as {self.repl_tag_label(entry.TyTag, entry.Bits)} and " f"cannot be assigned {self.repl_tag_label(tag, bits)} (restart the session to change its type)", "TypeError")
|
||||
return 1
|
||||
if tname is not None and entry.TyName is None: entry.TyName = self.repl_perm_strdup(perm, tname)
|
||||
return 0
|
||||
@@ -804,18 +804,18 @@ novirtual class VarGenMixin:
|
||||
hit: GenTypes.ReplVarEntry* = self.repl_find_entry(ctx, name)
|
||||
if hit is not None: return hit
|
||||
if ctx.Table is None or ctx.Cap <= 0:
|
||||
self.Gen.TypeGenErr.fatal_error(node, "REPL: 会话变量表未初始化(宿主未建 ctx)", "InternalCompilerError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, "REPL: session variable table is not initialized (host did not create ctx)", "InternalCompilerError")
|
||||
return None
|
||||
if ctx.Count >= ctx.Cap:
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: 会话变量已达上限 {ctx.Cap} 个(ctx 槽位用尽)," f"无法为 '{name}' 再分配槽位;请重启会话", "ResourceError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: session variables have reached the limit of {ctx.Cap} (ctx slots exhausted); " f"cannot allocate another slot for '{name}'; restart the session", "ResourceError")
|
||||
return None
|
||||
perm: memhub.MemBuddy* = self.repl_perm_pool(trans)
|
||||
if perm is None:
|
||||
self.Gen.TypeGenErr.fatal_error(node, "REPL: 会话永久池不可用(宿主未注入)", "InternalCompilerError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, "REPL: session permanent pool is unavailable (not injected by the host)", "InternalCompilerError")
|
||||
return None
|
||||
name_copy: str = self.repl_perm_strdup(perm, name)
|
||||
if name_copy is None:
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: 会话变量 '{name}' 的名字深拷贝失败", "InternalCompilerError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: failed to deep-copy the name of session variable '{name}'", "InternalCompilerError")
|
||||
return None
|
||||
entry_size: sizet = GenTypes.ReplVarEntry.__sizeof__()
|
||||
entry: GenTypes.ReplVarEntry* = GenTypes.ReplVarEntry*(uint64(ctx.Table) + uint64(ctx.Count) * uint64(entry_size))
|
||||
@@ -918,18 +918,18 @@ novirtual class VarGenMixin:
|
||||
if entry is None: return None
|
||||
if self.repl_in_frag_scope(trans.SymTab) == 0: return None
|
||||
if entry.Kind == GenTypes.REPL_KIND_UNTYPED:
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: 会话变量 '{name}' 尚未赋值(未定型,先执行一条 'x = ...' 或 'x: int = ...')", "NameError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: session variable '{name}' has not been assigned yet (untyped; first run a 'x = ...' or 'x: int = ...')", "NameError")
|
||||
return None
|
||||
pool: memhub.MemBuddy* = trans.Pool
|
||||
slot_ty: mlirlite.LLVMType* = self.repl_slot_ty(pool, entry)
|
||||
if slot_ty is None:
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: 会话变量 '{name}' 的类型 " f"{self.repl_tag_label(entry.TyTag, entry.Bits)} 在当前片段不可用" f"(跨片段类型可见性属 M4)", "NameError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: the type " f"{self.repl_tag_label(entry.TyTag, entry.Bits)} of session variable '{name}' is not available in the current snippet" f" (cross-snippet type visibility belongs to M4)", "NameError")
|
||||
return None
|
||||
ctx_val: mlirlite.Value* = self.repl_ctx_ptr(trans, trans.ReplCtx, node)
|
||||
if ctx_val is None: return None
|
||||
slot: mlirlite.Value* = self.repl_slot_ptr(pool, trans._cur_builder, ctx_val, entry.Offset, slot_ty)
|
||||
if slot is None:
|
||||
self.Gen.TypeGenErr.fatal_error(node, "REPL: 会话槽地址生成失败", "InternalCompilerError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, "REPL: failed to generate the session slot address", "InternalCompilerError")
|
||||
return None
|
||||
return mlirlite.build_load(trans._cur_builder, slot_ty, slot)
|
||||
|
||||
@@ -941,18 +941,18 @@ novirtual class VarGenMixin:
|
||||
if entry is None: return None
|
||||
if self.repl_in_frag_scope(trans.SymTab) == 0: return None
|
||||
if entry.Kind == GenTypes.REPL_KIND_UNTYPED:
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: 会话变量 '{name}' 尚未赋值(未定型),无法取址(c.Addr)", "NameError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: session variable '{name}' has not been assigned yet (untyped), cannot take its address (c.Addr)", "NameError")
|
||||
return None
|
||||
pool: memhub.MemBuddy* = trans.Pool
|
||||
slot_ty: mlirlite.LLVMType* = self.repl_slot_ty(pool, entry)
|
||||
if slot_ty is None:
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: 会话变量 '{name}' 的类型在当前片段不可用(跨片段类型可见性属 M4)", "NameError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: the type of session variable '{name}' is not available in the current snippet (cross-snippet type visibility belongs to M4)", "NameError")
|
||||
return None
|
||||
ctx_val: mlirlite.Value* = self.repl_ctx_ptr(trans, trans.ReplCtx, node)
|
||||
if ctx_val is None: return None
|
||||
slot: mlirlite.Value* = self.repl_slot_ptr(pool, trans._cur_builder, ctx_val, entry.Offset, slot_ty)
|
||||
if slot is None:
|
||||
self.Gen.TypeGenErr.fatal_error(node, "REPL: 会话槽地址生成失败", "InternalCompilerError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, "REPL: failed to generate the session slot address", "InternalCompilerError")
|
||||
return None
|
||||
# The value is inlined in the slot (no boxing indirection), so the slot address is the value address
|
||||
return slot
|
||||
@@ -965,22 +965,22 @@ novirtual class VarGenMixin:
|
||||
builder: mlirlite.IRBuilder* = trans._cur_builder
|
||||
slot_ty: mlirlite.LLVMType* = self.repl_slot_ty(pool, entry)
|
||||
if slot_ty is None:
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: 会话变量 '{entry.Name}' 的槽类型不可用" f"(类型在当前片段不可解析,或结构体值体积超出槽容量)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: the slot type of session variable '{entry.Name}' is not available" f" (the type is unresolvable in the current snippet, or the struct value exceeds the slot capacity)", "TypeError")
|
||||
return 1
|
||||
store_val: mlirlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, rhs_val, slot_ty, node, trans)
|
||||
if store_val is None:
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: 会话变量 '{entry.Name}' 无法把右侧值转换为" f" {self.repl_tag_label(entry.TyTag, entry.Bits)}", "CastError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: cannot convert the right-hand value of session variable '{entry.Name}' to" f" {self.repl_tag_label(entry.TyTag, entry.Bits)}", "CastError")
|
||||
return 1
|
||||
if self.Gen.ExprGenBase.is_ptr_type(slot_ty) != 0 and store_val.Ty is not None and self.Gen.ExprGenBase.is_ptr_type(store_val.Ty) != 0 and self.Gen.AssignGen._stg_ty_equal(pool, store_val.Ty, slot_ty) == 0:
|
||||
# Pointer same-typing (the slot type and the RHS pointer may be different type instances but the same width).
|
||||
# Skip when types are equal (including both i8*) - LLVM rejects same-type bitcast.
|
||||
store_val = mlirlite.build_bitcast(builder, store_val, slot_ty)
|
||||
if store_val is None:
|
||||
self.Gen.TypeGenErr.fatal_error(node, "REPL: 会话槽指针同型化失败", "CastError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, "REPL: failed to unify the type of the session slot pointer", "CastError")
|
||||
return 1
|
||||
slot: mlirlite.Value* = self.repl_slot_ptr(pool, builder, ctx_val, entry.Offset, slot_ty)
|
||||
if slot is None:
|
||||
self.Gen.TypeGenErr.fatal_error(node, "REPL: 会话槽写入失败", "InternalCompilerError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, "REPL: failed to write the session slot", "InternalCompilerError")
|
||||
return 1
|
||||
mlirlite.build_store(builder, store_val, slot)
|
||||
self.repl_emit_result(trans, ctx_val, store_val, entry.TyTag, entry.Bits, node)
|
||||
@@ -994,7 +994,7 @@ novirtual class VarGenMixin:
|
||||
if entry is None: return 0
|
||||
if self.repl_in_frag_entry_scope(trans) == 0: return 0
|
||||
if rhs_val.Ty is None:
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: 会话变量 '{name}' 的赋值右侧类型未知", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: the right-hand type of the assignment to session variable '{name}' is unknown", "TypeError")
|
||||
return 1
|
||||
if self.repl_seal(trans, entry, rhs_val.Ty, rhs_node) != 0: return 1
|
||||
ctx_val: mlirlite.Value* = self.repl_ctx_ptr(trans, trans.ReplCtx, node)
|
||||
@@ -1012,14 +1012,14 @@ novirtual class VarGenMixin:
|
||||
pool: memhub.MemBuddy* = trans.Pool
|
||||
builder: mlirlite.IRBuilder* = trans._cur_builder
|
||||
if annot_node is None:
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: 会话变量 '{name}' 的注解缺失", "SyntaxError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: session variable '{name}' is missing an annotation", "SyntaxError")
|
||||
return 1
|
||||
# Same rule as ordinary AnnAssign: pre-register the generic specialization first so list[X] does not
|
||||
# degrade to a bare base class (a bare list* makes later .get() misdispatch and truncate pointers).
|
||||
self.Gen.AssignGen._prespecialize_generic_annotation(trans, pool, annot_node)
|
||||
annot_ty: mlirlite.LLVMType* = self.Gen.TypeGenResolve.resolve_annotation_type(pool, annot_node, trans._imported_modules, trans._from_imports, trans, 0)
|
||||
if annot_ty is None:
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: 会话变量 '{name}' 的类型注解解析失败" f"(片段无 import;仅内建名 int/str/bytes/bool/float/double/char 等可解析)", "NameError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: failed to resolve the type annotation of session variable '{name}'" f" (the snippet has no import; only built-in names such as int/str/bytes/bool/float/double/char can be resolved)", "NameError")
|
||||
return 1
|
||||
if self.repl_seal(trans, entry, annot_ty, node) != 0: return 1
|
||||
if value_node is None:
|
||||
@@ -1033,7 +1033,7 @@ novirtual class VarGenMixin:
|
||||
trans.CurAssignAnnot = None
|
||||
trans.CurAssignNode = None
|
||||
if rhs_val is None:
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: 会话变量 '{name}' 的初值翻译失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: failed to translate the initial value of session variable '{name}'", "TypeError")
|
||||
return 1
|
||||
ctx_val: mlirlite.Value* = self.repl_ctx_ptr(trans, trans.ReplCtx, node)
|
||||
if ctx_val is None: return 1
|
||||
@@ -1050,17 +1050,17 @@ novirtual class VarGenMixin:
|
||||
pool: memhub.MemBuddy* = trans.Pool
|
||||
builder: mlirlite.IRBuilder* = trans._cur_builder
|
||||
if entry.TyTag == GenTypes.REPL_TY_STRUCT:
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: 会话变量 '{name}' 是结构体值,不支持增强赋值", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: session variable '{name}' is a struct value, augmented assignment is not supported", "TypeError")
|
||||
return 1
|
||||
cur_val: mlirlite.Value* = self.repl_try_read(trans, name, node)
|
||||
if cur_val is None: return 1
|
||||
rhs_val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, rhs_node, None, 0, trans)
|
||||
if rhs_val is None:
|
||||
self.Gen.TypeGenErr.fatal_error(node, "REPL: 增强赋值右侧翻译失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, "REPL: failed to translate the right-hand side of the augmented assignment", "TypeError")
|
||||
return 1
|
||||
result: mlirlite.Value* = self.Gen.AssignGen._apply_aug_op(pool, builder, op, cur_val, rhs_val, node, trans, node)
|
||||
if result is None:
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: 会话变量 '{name}' 的增强赋值运算失败 op={op}", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"REPL: augmented assignment on session variable '{name}' failed op={op}", "TypeError")
|
||||
return 1
|
||||
# Write back to the slot (reuses the assignment path: typing already exists, so only convert and store)
|
||||
return self.repl_try_assign(trans, name, result, node, node)
|
||||
@@ -1073,14 +1073,14 @@ novirtual class VarGenMixin:
|
||||
builder: mlirlite.IRBuilder* = trans._cur_builder
|
||||
val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, value_node, None, 0, trans)
|
||||
if val is None or val.Ty is None:
|
||||
self.Gen.TypeGenErr.fatal_error(value_node, "REPL: 表达式片段求值失败", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(value_node, "REPL: failed to evaluate the expression snippet", "TypeError")
|
||||
return 1
|
||||
ctx_val: mlirlite.Value* = self.repl_ctx_ptr(trans, trans.ReplCtx, value_node)
|
||||
if ctx_val is None: return 1
|
||||
# Type classification uses the host's scratch entry (occupies no session slot, not in the table); reset to untyped each time
|
||||
sh: GenTypes.ReplVarEntry* = trans.ReplCtx.Scratch
|
||||
if sh is None:
|
||||
self.Gen.TypeGenErr.fatal_error(value_node, "REPL: 会话缺少影子条目(宿主未初始化)", "InternalCompilerError")
|
||||
self.Gen.TypeGenErr.fatal_error(value_node, "REPL: session is missing the shadow entry (host not initialized)", "InternalCompilerError")
|
||||
return 1
|
||||
sh.Kind = GenTypes.REPL_KIND_UNTYPED
|
||||
sh.TyTag = 0
|
||||
|
||||
@@ -232,14 +232,14 @@ def scan_directory_recursive(pool: memhub.MemBuddy*, root_dir: str, rel_prefix:
|
||||
sha1: str = compute_file_sha1(pool, full_path)
|
||||
if sha1 is not None:
|
||||
add_file_entry(result, pool, full_path, rel_path, sha1, inc_dir)
|
||||
VLogger.debug(f"扫描: {rel_path} -> {sha1}", "scan")
|
||||
else: VLogger.warning(f"SHA1 计算失败: {full_path}", "scan")
|
||||
VLogger.debug(f"scan: {rel_path} -> {sha1}", "scan")
|
||||
else: VLogger.warning(f"SHA1 computation failed: {full_path}", "scan")
|
||||
|
||||
# continue to the next file
|
||||
if win32file.FindNextFileA(handle, find_data) == 0: break
|
||||
|
||||
win32file.FindClose(handle)
|
||||
if subdir_failed > 0: VLogger.error(f"子目录扫描失败 {subdir_failed} 个", "scan")
|
||||
if subdir_failed > 0: VLogger.error(f"subdirectory scan failed for {subdir_failed} entries", "scan")
|
||||
|
||||
return 0
|
||||
|
||||
@@ -263,7 +263,7 @@ def scan_includes(pool: memhub.MemBuddy*, includes_dirs: str) -> ScanResult*:
|
||||
d_len: sizet = d_i - d_start
|
||||
if d_len == 0: continue
|
||||
dir_buf: bytes = stdlib.malloc(d_len + 1)
|
||||
if dir_buf is None: VLogger.error("includes 目录分配失败,终止扫描", "scan")
|
||||
if dir_buf is None: VLogger.error("failed to allocate the includes directory; aborting scan", "scan")
|
||||
string.strncpy(dir_buf, includes_dirs + d_start, d_len)
|
||||
dir_buf[d_len] = '\0'
|
||||
scan_directory_recursive(pool, dir_buf, None, result, dir_buf)
|
||||
|
||||
+96
-96
@@ -171,7 +171,7 @@ def ReplFindProject(Out: bytes, Cap: int, Diag: bytes, DiagCap: int) -> int:
|
||||
stdlib.free(c1)
|
||||
stdlib.free(c2)
|
||||
return 1
|
||||
else: string.strcpy(c1, "(GetCurrentDirectoryA 失败)")
|
||||
else: string.strcpy(c1, "(GetCurrentDirectoryA failed)")
|
||||
# 2) exe-dir/repl.vpj (GetModuleFileNameA(NULL) returns our own full path).
|
||||
n_exe: ULONG = w32file.GetModuleFileNameA(None, c2, ULONG(Cap))
|
||||
if n_exe > 0:
|
||||
@@ -197,9 +197,9 @@ def ReplFindProject(Out: bytes, Cap: int, Diag: bytes, DiagCap: int) -> int:
|
||||
stdlib.free(c1)
|
||||
stdlib.free(c2)
|
||||
return 1
|
||||
else: string.strcpy(c2, "(GetModuleFileNameA 失败)")
|
||||
else: string.strcpy(c2, "(GetModuleFileNameA failed)")
|
||||
# Not found in either place: emit diagnostics (needs --project + both searched paths).
|
||||
viperlib.snprintf(Diag, DiagCap, " 已查找(1): %s\n" " 已查找(2): %s\n" " 需要 --project: 未找到 repl.vpj 时 REPL 拿不到工程配置," "请用 --project <path/to/repl.vpj> 指定\n" " 模板位置: 仓库 TransPyV/repl.vpj;拷到 TransPyV.exe 同目录" "或当前工作目录即可被自动找到\n", c1, c2)
|
||||
viperlib.snprintf(Diag, DiagCap, " Searched(1): %s\n" " Searched(2): %s\n" " --project needed: without repl.vpj the REPL cannot get the project config; " "specify it with --project <path/to/repl.vpj>\n" " Template location: TransPyV/repl.vpj in the repo; copy it next to TransPyV.exe" "or into the current working directory to be found automatically\n", c1, c2)
|
||||
stdlib.free(c1)
|
||||
stdlib.free(c2)
|
||||
return 0
|
||||
@@ -484,7 +484,7 @@ def _repl_echo_result(frag_name: str, res: GenTypes.ReplResult*) -> int:
|
||||
# REPL_RES_OBJ: result_a != 0 means a non-string pointer (print address); result_a == 0
|
||||
# means an inline struct value (no address; type name needs the cross-fragment table, M4).
|
||||
if res.A == 0:
|
||||
stdio.printf("%s => <struct 值>\n", frag_name)
|
||||
stdio.printf("%s => <struct value>\n", frag_name)
|
||||
return 0
|
||||
stdio.printf("%s => <obj @ 0x%llX>\n", frag_name, res.A)
|
||||
return 0
|
||||
@@ -699,7 +699,7 @@ def ReplInitIncludesClasses(mb: memhub.MemBuddy*, sr: IncludesScanner.ScanResult
|
||||
budget_hit = 1
|
||||
break
|
||||
if GenApi.get_struct_count() >= _REPL_INC_CLS_STRUCT_GUARD:
|
||||
stdio.printf("includes 类注册: 结构体表已达 %d 条(上限附近)," "停止注册;未注册的类在会话里不可用(import 其模块" "仍可按需注册)\n", GenApi.get_struct_count())
|
||||
stdio.printf("includes class registration: struct table reached %d entries (near the limit); " "stopping registration; unregistered classes are unavailable in the session (importing their module " "can still register on demand)\n", GenApi.get_struct_count())
|
||||
stdio.fflush(None)
|
||||
return 0
|
||||
ent: IncludesScanner.FileEntry* = IncludesScanner.FileEntry*(uint64(sr.Entries) + uint64(i) * uint64(es))
|
||||
@@ -719,7 +719,7 @@ def ReplInitIncludesClasses(mb: memhub.MemBuddy*, sr: IncludesScanner.ScanResult
|
||||
# are unavailable, but the session continues (import degrades the same way).
|
||||
ReplIncClsMissing += 1
|
||||
if warn_left > 0:
|
||||
stdio.printf("includes 类注册: 模块 %s 无 .vpi 存根 —— 其类在" "会话中不可用(不影响其它模块;先按 project.vpj " "构建一次宿主可生成全部存根)\n", ent.Sha1)
|
||||
stdio.printf("includes class registration: module %s has no .vpi stub -- its classes are " "unavailable in the session (other modules unaffected; build the host once with project.vpj " "to generate all stubs)\n", ent.Sha1)
|
||||
warn_left -= 1
|
||||
else: warn_dropped += 1
|
||||
stdlib.free(vpi_path)
|
||||
@@ -735,7 +735,7 @@ def ReplInitIncludesClasses(mb: memhub.MemBuddy*, sr: IncludesScanner.ScanResult
|
||||
if rc_m != 0:
|
||||
ReplIncClsFail += 1
|
||||
if warn_left > 0:
|
||||
stdio.printf("includes 类注册: 模块 %d 的 .vpi 注入中断" "(其类可能不完整;会话继续)\n", i)
|
||||
stdio.printf("includes class registration: injection of module %d's .vpi interrupted " "(its classes may be incomplete; session continues)\n", i)
|
||||
warn_left -= 1
|
||||
else: warn_dropped += 1
|
||||
mb.reset_to(vm)
|
||||
@@ -748,7 +748,7 @@ def ReplInitIncludesClasses(mb: memhub.MemBuddy*, sr: IncludesScanner.ScanResult
|
||||
else:
|
||||
ReplIncClsFail += 1
|
||||
if warn_left > 0:
|
||||
stdio.printf("includes 类注册: 模块 %s 的 .vpi 注入失败" "(该模块的类不完整/不可用;会话继续)\n", ent.Sha1)
|
||||
stdio.printf("includes class registration: injection of module %s's .vpi failed " "(that module's classes are incomplete/unavailable; session continues)\n", ent.Sha1)
|
||||
warn_left -= 1
|
||||
else: warn_dropped += 1
|
||||
stdlib.free(vpi_path)
|
||||
@@ -760,9 +760,9 @@ def ReplInitIncludesClasses(mb: memhub.MemBuddy*, sr: IncludesScanner.ScanResult
|
||||
si: int
|
||||
for si in range(n_mod):
|
||||
if int(st[si]) == 0: skip_cnt += 1
|
||||
stdio.printf("includes 类: 已注册 %d 个模块的 vpi 类(失败 %d,缺存根 %d," "未尝试/待重试 %d,省略告警 %d)\n", ReplIncClsMods, ReplIncClsFail, ReplIncClsMissing, skip_cnt, warn_dropped)
|
||||
stdio.printf("includes classes: registered vpi classes for %d modules (failed %d, missing stub %d, " "not attempted/to retry %d, warnings dropped %d)\n", ReplIncClsMods, ReplIncClsFail, ReplIncClsMissing, skip_cnt, warn_dropped)
|
||||
if budget_hit != 0:
|
||||
stdio.printf("includes 类: 启动预算 %d ms 用尽,已停止启动期注册(剩余 %d 个" "模块的类在会话里不可用;片段 `import` 该模块时仍按需注册)\n", _REPL_INC_CLS_BUDGET_MS, skip_cnt)
|
||||
stdio.printf("includes classes: startup budget of %d ms exhausted, stopped startup registration (classes of the remaining %d " "modules are unavailable in the session; a fragment that `import`s such a module still registers on demand)\n", _REPL_INC_CLS_BUDGET_MS, skip_cnt)
|
||||
stdio.fflush(None)
|
||||
return 0
|
||||
|
||||
@@ -1010,37 +1010,37 @@ def ReplInitIncludes(mb: memhub.MemBuddy*) -> int:
|
||||
if mb is None: return 1
|
||||
inc_dirs: str = Config.IncludesDirs
|
||||
if inc_dirs is None or string.strlen(inc_dirs) == 0:
|
||||
stdio.printf("REPL: 工程未配置 includes 目录(project.vpj 的 includes)," "跳过 includes 初始化;import includes 模块会报未注册 SHA1\n")
|
||||
stdio.printf("REPL: project has no includes dir configured (project.vpj's includes); " "skipping includes init; importing includes modules will report an unregistered SHA1\n")
|
||||
return 1
|
||||
# .vpi dir matches the fragment side: prefer the project temp dir, else the session dir.
|
||||
vpi_dir: str = Config.TempDir
|
||||
if vpi_dir is None: vpi_dir = ReplTmpDir
|
||||
if vpi_dir is None:
|
||||
stdio.printf("REPL: 无可用 .vpi 目录(Config.TempDir 与会话目录均为空)," "跳过 includes 初始化\n")
|
||||
stdio.printf("REPL: no usable .vpi dir (both Config.TempDir and the session dir are empty); " "skipping includes init\n")
|
||||
return 1
|
||||
# 1) Scan includes (no reachability: REPL has no SourceDir/deps graph, so scan all).
|
||||
t0: uint64 = win32base.GetTickCount64()
|
||||
sr: IncludesScanner.ScanResult* = IncludesScanner.scan_includes(mb, inc_dirs)
|
||||
if sr is None:
|
||||
stdio.printf("REPL: includes 扫描失败(目录: %s);" "import includes 模块会报未注册 SHA1\n", inc_dirs)
|
||||
stdio.printf("REPL: includes scan failed (dir: %s); " "importing includes modules will report an unregistered SHA1\n", inc_dirs)
|
||||
return 1
|
||||
# 2) Register "module -> SHA1" (same StubMerger global table batch consumers use).
|
||||
n: int = StubMergerStore.PopulateSha1MapStore(sr)
|
||||
ReplIncMs = int(win32base.GetTickCount64() - t0)
|
||||
if n <= 0:
|
||||
stdio.printf("REPL: includes 扫描未注册任何模块(目录: %s):" "请检查 includes 路径与 .vp 文件\n", inc_dirs)
|
||||
stdio.printf("REPL: includes scan registered no modules (dir: %s): " "check the includes path and the .vp files\n", inc_dirs)
|
||||
return 1
|
||||
ReplIncMods = n
|
||||
# 3) Pre-generate .vpi stubs (count failures, do not abort the session).
|
||||
_repl_gen_includes_vpi(mb, sr, vpi_dir)
|
||||
stdio.printf("includes: 已注册 %d 个模块(扫描耗时 %d ms);" "存根 新生成 %d / 复用 %d / 失败 %d\n", n, ReplIncMs, ReplIncVpiNew, ReplIncVpiReuse, ReplIncVpiFail)
|
||||
stdio.printf("includes: registered %d modules (scan took %d ms); " "stubs new %d / reused %d / failed %d\n", n, ReplIncMs, ReplIncVpiNew, ReplIncVpiReuse, ReplIncVpiFail)
|
||||
# 3'') Register session generic templates for real: reuse includes sources to register
|
||||
# generic class templates (list/dict/Vector...) so annotations like list[...] specialize.
|
||||
cur_file_saved: str = GenApi.get_current_file()
|
||||
n_gen_tpl: int = Phase1Scan._PreRegisterAllGenericTemplates(mb, sr)
|
||||
if cur_file_saved is not None: GenApi.set_current_file_type(cur_file_saved)
|
||||
if n_gen_tpl <= 0:
|
||||
stdio.printf("includes 泛型模板: 0 个 —— 注解里的 list[...]/dict[...] 只能按" "\"仅类型\"占位解析(元素布局与方法不可用)\n")
|
||||
stdio.printf("includes generic templates: 0 -- list[...]/dict[...] in annotations can only be parsed as " "\"type-only\" placeholders (element layout and methods unavailable)\n")
|
||||
# 3') M4.2: enable stub-layout recovery so vpi injection verifies and registers includes
|
||||
# class layouts/vtable indices; also reset the generic-owner table for re-registration.
|
||||
StubMergerStore.ResetGenericOwners()
|
||||
@@ -1118,15 +1118,15 @@ def _repl_lift_add_name(name: str) -> int:
|
||||
pfx: str = GenTypes.REPL_ENTRY_PREFIX
|
||||
pl: int = int(string.strlen(pfx))
|
||||
if string.strncmp(name, pfx, sizet(pl)) == 0:
|
||||
stdio.printf("M3: 会话函数名不能以保留前缀 '%s' 开头:%s\n", pfx, name)
|
||||
stdio.printf("M3: session function name cannot start with the reserved prefix '%s': %s\n", pfx, name)
|
||||
return 1
|
||||
i: int
|
||||
for i in range(ReplLiftNameCount):
|
||||
if string.strcmp(ReplLiftNames + i * _REPL_FN_NAME_MAX, name) == 0:
|
||||
stdio.printf("M3: 同一片段内重复定义会话函数 '%s'(请只定义一次)\n", name)
|
||||
stdio.printf("M3: session function '%s' defined twice in the same fragment (define it only once)\n", name)
|
||||
return 1
|
||||
if ReplLiftNameCount >= _REPL_LIFT_MAX:
|
||||
stdio.printf("M3: 单个片段最多提升 %d 个会话函数(本片段已提升 %d 个)\n", _REPL_LIFT_MAX, ReplLiftNameCount)
|
||||
stdio.printf("M3: a fragment can lift at most %d session functions (this fragment lifted %d)\n", _REPL_LIFT_MAX, ReplLiftNameCount)
|
||||
return 1
|
||||
string.strcpy(ReplLiftNames + ReplLiftNameCount * _REPL_FN_NAME_MAX, name)
|
||||
ReplLiftNameCount += 1
|
||||
@@ -1149,10 +1149,10 @@ def _repl_lift_def_header(line: bytes, n: int, name_out: bytes, name_cap: int) -
|
||||
p += 1
|
||||
nlen: int = p - ns
|
||||
if nlen <= 0:
|
||||
stdio.printf("M3: def 头缺少函数名:%s\n", _repl_show_line(line, n))
|
||||
stdio.printf("M3: def header is missing the function name: %s\n", _repl_show_line(line, n))
|
||||
return 1
|
||||
if nlen >= name_cap:
|
||||
stdio.printf("M3: 会话函数名过长(上限 %d 字节):%s\n", name_cap - 1, _repl_show_line(line, n))
|
||||
stdio.printf("M3: session function name too long (limit %d bytes): %s\n", name_cap - 1, _repl_show_line(line, n))
|
||||
return 1
|
||||
string.memcpy(name_out, line + ns, sizet(nlen))
|
||||
name_out[nlen] = 0
|
||||
@@ -1168,10 +1168,10 @@ def _repl_lift_def_header(line: bytes, n: int, name_out: bytes, name_cap: int) -
|
||||
break
|
||||
p += 1
|
||||
if d != 0:
|
||||
stdio.printf("M3: def 头的泛型参数方括号不闭合:%s\n", _repl_show_line(line, n))
|
||||
stdio.printf("M3: unclosed generic-parameter bracket in def header: %s\n", _repl_show_line(line, n))
|
||||
return 1
|
||||
if p >= n or line[p] != '(':
|
||||
stdio.printf("M3: def 头在函数名之后缺少 '(':%s\n", _repl_show_line(line, n))
|
||||
stdio.printf("M3: def header is missing '(' after the function name: %s\n", _repl_show_line(line, n))
|
||||
return 1
|
||||
lp: int = p
|
||||
# Matching ')'.
|
||||
@@ -1188,7 +1188,7 @@ def _repl_lift_def_header(line: bytes, n: int, name_out: bytes, name_cap: int) -
|
||||
break
|
||||
q += 1
|
||||
if rp < 0:
|
||||
stdio.printf("M3: def 头的 ')' 缺失(签名必须写在一行内):%s\n", _repl_show_line(line, n))
|
||||
stdio.printf("M3: def header is missing ')' (the signature must be on one line): %s\n", _repl_show_line(line, n))
|
||||
return 1
|
||||
# ':' must be on the same line (as must the return annotation).
|
||||
has_colon: int = 0
|
||||
@@ -1199,7 +1199,7 @@ def _repl_lift_def_header(line: bytes, n: int, name_out: bytes, name_cap: int) -
|
||||
break
|
||||
q2 += 1
|
||||
if has_colon == 0:
|
||||
stdio.printf("M3: def 头的 ':' 不在同一行(签名必须写在一行内):%s\n", _repl_show_line(line, n))
|
||||
stdio.printf("M3: def header ':' is not on the same line (the signature must be on one line): %s\n", _repl_show_line(line, n))
|
||||
return 1
|
||||
# Whether the parameter list is empty.
|
||||
empty: int = 1
|
||||
@@ -1214,7 +1214,7 @@ def _repl_lift_def_header(line: bytes, n: int, name_out: bytes, name_cap: int) -
|
||||
seg: int = lp + 1
|
||||
while seg + 12 <= rp:
|
||||
if line[seg] == '_' and string.strncmp(line + seg, GenTypes.REPL_CTX_PARAM, sizet(12)) == 0:
|
||||
stdio.printf("M3: 会话函数 '%s' 不能自定义 %s 形参" "(提升时自动注入为第一个形参)\n", name_out, GenTypes.REPL_CTX_PARAM)
|
||||
stdio.printf("M3: session function '%s' cannot declare the %s parameter " "(it is auto-injected as the first parameter when lifting)\n", name_out, GenTypes.REPL_CTX_PARAM)
|
||||
return 1
|
||||
seg += 1
|
||||
# Emit: "export " + original header [0,lp] + injection + original header [lp+1,n) + '\n'.
|
||||
@@ -1226,7 +1226,7 @@ def _repl_lift_def_header(line: bytes, n: int, name_out: bytes, name_cap: int) -
|
||||
pos = _repl_cat(ReplLiftBuf, _REPL_LIFT_CAP, pos, line + lp + 1, n - lp - 1)
|
||||
pos = _repl_cat_str(ReplLiftBuf, _REPL_LIFT_CAP, pos, "\n")
|
||||
if pos < 0:
|
||||
stdio.printf("M3: 提升源码缓冲(%d 字节)不足\n", _REPL_LIFT_CAP)
|
||||
stdio.printf("M3: lift source buffer too small (%d bytes)\n", _REPL_LIFT_CAP)
|
||||
return 2
|
||||
return 0
|
||||
|
||||
@@ -1259,10 +1259,10 @@ def _repl_split_body(body: bytes) -> int:
|
||||
continue
|
||||
if ind > 0:
|
||||
if need_header != 0:
|
||||
stdio.printf("M3: 装饰器之后必须紧跟 def 头行:%s\n", _repl_show_line(body + i, n))
|
||||
stdio.printf("M3: a def header must immediately follow the decorator: %s\n", _repl_show_line(body + i, n))
|
||||
return 1
|
||||
if in_body != 0 and _repl_line_has_kw(body + i, n, ind, "raise") != 0:
|
||||
stdio.printf("M3: 会话函数 '%s' 的函数体含 raise:%s\n" " M3 不支持跨片段异常传播(raise 会给函数追加 " "__eh_msg_out__/__eh_code_out__ 出参," "而经函数指针的间接调用不会补这些实参)——该片段整体不执行\n", name_buf, _repl_show_line(body + i, n))
|
||||
stdio.printf("M3: session function '%s' has raise in its body: %s\n" " M3 does not support cross-fragment exception propagation (raise appends the " "__eh_msg_out__/__eh_code_out__ out params to the function, " "but indirect calls through the function pointer do not pass them) -- the whole fragment is skipped\n", name_buf, _repl_show_line(body + i, n))
|
||||
return 1
|
||||
lp1: int = int(string.strlen(ReplLiftBuf))
|
||||
lp1 = _repl_cat(ReplLiftBuf, _REPL_LIFT_CAP, lp1, body + i, n)
|
||||
@@ -1304,7 +1304,7 @@ def _repl_split_body(body: bytes) -> int:
|
||||
i += n + 1
|
||||
continue
|
||||
if _repl_line_has_kw(body + i, n, 0, "async") != 0 and _repl_line_has_kw(body + i, n, 6, "def") != 0:
|
||||
stdio.printf("M3: 不支持 async def 会话函数(协程 ABI 与 M3 签名 token " "不相容,请改写成普通 def):%s\n", _repl_show_line(body + i, n))
|
||||
stdio.printf("M3: async def session functions are not supported (coroutine ABI is incompatible with " "the M3 signature token; rewrite as a plain def): %s\n", _repl_show_line(body + i, n))
|
||||
return 1
|
||||
pos = _repl_cat_str(ReplSrcBuf, _REPL_FRAG_SRC_CAP, pos, " ")
|
||||
pos = _repl_cat(ReplSrcBuf, _REPL_FRAG_SRC_CAP, pos, body + i, n)
|
||||
@@ -1312,7 +1312,7 @@ def _repl_split_body(body: bytes) -> int:
|
||||
if pos < 0: return 2
|
||||
i += n + 1
|
||||
if need_header != 0:
|
||||
stdio.printf("M3: 装饰器之后缺少 def 头行(片段末尾)\n")
|
||||
stdio.printf("M3: missing def header after decorator (end of fragment)\n")
|
||||
return 1
|
||||
ReplWrapPos = pos
|
||||
return 0
|
||||
@@ -1391,7 +1391,7 @@ def _repl_sig_to_text(tag: int, bits: int, pc: int) -> str:
|
||||
def _repl_precheck_session_funcs(mod: mlirlite.LLVMModule*) -> int:
|
||||
if ReplLiftNameCount <= 0: return 0
|
||||
if ReplCtxObj is None or ReplCtxObj.FuncTable is None or ReplSigResult is None:
|
||||
stdio.printf("M3: 会话函数表/签名缓冲未初始化(会话初始化失败)\n")
|
||||
stdio.printf("M3: session function table/signature buffer not initialized (session init failed)\n")
|
||||
return 1
|
||||
new_cnt: int = 0
|
||||
idx: int
|
||||
@@ -1400,22 +1400,22 @@ def _repl_precheck_session_funcs(mod: mlirlite.LLVMModule*) -> int:
|
||||
if nm is None: return 1
|
||||
rc: int = _repl_model_func_sig(mod, nm, ReplSigResult)
|
||||
if rc == 1:
|
||||
stdio.printf("M3: 定义片段模型里找不到函数 '%s'(提升未生效?)\n", nm)
|
||||
stdio.printf("M3: function '%s' not found in the defining fragment's model (lift not effective?)\n", nm)
|
||||
return 1
|
||||
if rc == 2:
|
||||
stdio.printf("M3: 会话函数 '%s' 的签名含不受支持的类型 '%s'\n" " M3 支持 void / i1 / i8 / i16 / i32 / i64 / float / double / " "i8*(str、bytes、rawptr);结构体值/数组/多级指针请改用指针参数" "或等 M4\n", nm, ReplSigResult.BadType)
|
||||
stdio.printf("M3: session function '%s' signature has an unsupported type '%s'\n" " M3 supports void / i1 / i8 / i16 / i32 / i64 / float / double / " "i8* (str, bytes, rawptr); for struct values/arrays/multi-level pointers use pointer params " "or wait for M4\n", nm, ReplSigResult.BadType)
|
||||
return 1
|
||||
if rc == 3:
|
||||
stdio.printf("M3: 会话函数 '%s' 的签名含异常出参(%%__eh_msg_out__/" "%%__eh_code_out__)——其函数体含 raise\n" " M3 不支持跨片段异常传播:经函数指针的间接调用不会补这两个实参" "(arity 不匹配);该片段整体不执行\n", nm)
|
||||
stdio.printf("M3: session function '%s' signature has EH out params (%%__eh_msg_out__/" "%%__eh_code_out__) -- its body contains raise\n" " M3 does not support cross-fragment exception propagation: indirect calls through the function pointer do not pass these two args " "(arity mismatch); the whole fragment is skipped\n", nm)
|
||||
return 1
|
||||
if rc == 4:
|
||||
stdio.printf("M3: 会话函数 '%s' 的 define 首形参不是 %s(提升模板与调用约定" "不一致)\n", nm, GenTypes.REPL_CTX_PARAM)
|
||||
stdio.printf("M3: session function '%s' define's first param is not %s (lift template and calling convention " "disagree)\n", nm, GenTypes.REPL_CTX_PARAM)
|
||||
return 1
|
||||
if rc == 5:
|
||||
stdio.printf("M3: 会话函数 '%s' 的形参超过 %d 个\n", nm, GenTypes.REPL_FUNC_PARAM_MAX)
|
||||
stdio.printf("M3: session function '%s' has more than %d params\n", nm, GenTypes.REPL_FUNC_PARAM_MAX)
|
||||
return 1
|
||||
if rc != 0:
|
||||
stdio.printf("M3: 会话函数 '%s' 的签名解析失败(rc=%d)\n", nm, rc)
|
||||
stdio.printf("M3: failed to parse session function '%s' signature (rc=%d)\n", nm, rc)
|
||||
return 1
|
||||
old: GenTypes.ReplFuncEntry* = _repl_func_entry_find(nm)
|
||||
if old is None:
|
||||
@@ -1431,10 +1431,10 @@ def _repl_precheck_session_funcs(mod: mlirlite.LLVMModule*) -> int:
|
||||
sig_same = 0
|
||||
break
|
||||
if sig_same == 0:
|
||||
stdio.printf("M3: 会话函数 '%s' 重定义签名不一致(旧 %s,新 %s)\n" " M3 允许同签名覆盖(只换地址);换签名会让先前片段里已编好的" "调用点按旧 ABI 调新代码 —— 该片段整体不执行,请换名字\n", nm, _repl_entry_sig_text(old), _repl_sig_to_text(ReplSigResult.RetTag, ReplSigResult.RetBits, ReplSigResult.ParamCount))
|
||||
stdio.printf("M3: redefinition of session function '%s' has a different signature (old %s, new %s)\n" " M3 allows a same-signature overwrite (address only); a different signature would make call " "sites already compiled in earlier fragments call new code with the old ABI -- the whole fragment is skipped; use another name\n", nm, _repl_entry_sig_text(old), _repl_sig_to_text(ReplSigResult.RetTag, ReplSigResult.RetBits, ReplSigResult.ParamCount))
|
||||
return 1
|
||||
if ReplCtxObj.FuncCount + new_cnt > ReplCtxObj.FuncCap:
|
||||
stdio.printf("M3: 会话函数已达上限 %d 个(ctx 函数指针槽用尽),本次新增 %d 个;" "请重启会话或减少会话函数\n", ReplCtxObj.FuncCap, new_cnt)
|
||||
stdio.printf("M3: session function limit of %d reached (ctx function pointer slots exhausted); %d added this time; " "restart the session or use fewer session functions\n", ReplCtxObj.FuncCap, new_cnt)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
@@ -1457,7 +1457,7 @@ def _repl_entry_sig_text(e: GenTypes.ReplFuncEntry*) -> str:
|
||||
def _repl_register_session_funcs(h_lib: win32base.HANDLE, frag_no: int, mod: mlirlite.LLVMModule*) -> int:
|
||||
if ReplLiftNameCount <= 0: return 0
|
||||
if ReplCtxObj is None or ReplCtxObj.FuncTable is None or ReplCtxBuf is None:
|
||||
stdio.printf("M3: 会话函数表/ctx 未初始化\n")
|
||||
stdio.printf("M3: session function table/ctx not initialized\n")
|
||||
return 1
|
||||
idx: int
|
||||
for idx in range(ReplLiftNameCount):
|
||||
@@ -1467,14 +1467,14 @@ def _repl_register_session_funcs(h_lib: win32base.HANDLE, frag_no: int, mod: mli
|
||||
# and -shared without a DEF file exports all symbols automatically.
|
||||
addr: VOIDPTR = win32base.GetProcAddress(h_lib, nm)
|
||||
if addr is None:
|
||||
stdio.printf("M3: 会话函数 '%s' 未出现在片段 DLL 的导出表" "(GetProcAddress 返回空;本片段不执行)\n", nm)
|
||||
stdio.printf("M3: session function '%s' is absent from the fragment DLL's export table " "(GetProcAddress returned null; this fragment is skipped)\n", nm)
|
||||
return 1
|
||||
ent: GenTypes.ReplFuncEntry* = _repl_func_entry_find(nm)
|
||||
if ent is None:
|
||||
# New entry (signature already validated; re-parse to recover the scratch tokens).
|
||||
rc: int = _repl_model_func_sig(mod, nm, ReplSigResult)
|
||||
if rc != 0:
|
||||
stdio.printf("M3: 会话函数 '%s' 的签名重新解析失败(rc=%d)\n", nm, rc)
|
||||
stdio.printf("M3: failed to re-parse session function '%s' signature (rc=%d)\n", nm, rc)
|
||||
return 1
|
||||
j: int = ReplCtxObj.FuncCount
|
||||
es: sizet = GenTypes.ReplFuncEntry.__sizeof__()
|
||||
@@ -1484,7 +1484,7 @@ def _repl_register_session_funcs(h_lib: win32base.HANDLE, frag_no: int, mod: mli
|
||||
tags_b: bytes = _perm_pool.alloc(GenTypes.REPL_FUNC_PARAM_MAX)
|
||||
bits_b: bytes = _perm_pool.alloc(GenTypes.REPL_FUNC_PARAM_MAX)
|
||||
if nm_c is None or nm_s is None or tags_b is None or bits_b is None:
|
||||
stdio.printf("M3: 会话函数条目内存分配失败('%s')\n", nm)
|
||||
stdio.printf("M3: failed to allocate the session function entry ('%s')\n", nm)
|
||||
return 1
|
||||
string.memset(tags_b, 0, GenTypes.REPL_FUNC_PARAM_MAX)
|
||||
string.memset(bits_b, 0, GenTypes.REPL_FUNC_PARAM_MAX)
|
||||
@@ -1507,7 +1507,7 @@ def _repl_register_session_funcs(h_lib: win32base.HANDLE, frag_no: int, mod: mli
|
||||
sv: ReplFuncSlotView* = ReplFuncSlotView*(uint64(ReplCtxBuf) + uint64(ent.SlotOff))
|
||||
sv.Addr = addr
|
||||
sv.Reserved = None
|
||||
stdio.printf("会话函数 %s: 导出符号 %s → ctx 槽 +%d(定义片段 %d,签名 %s)\n", nm, nm, ent.SlotOff, frag_no, _repl_entry_sig_text(ent))
|
||||
stdio.printf("session function %s: export symbol %s -> ctx slot +%d (defining fragment %d, signature %s)\n", nm, nm, ent.SlotOff, frag_no, _repl_entry_sig_text(ent))
|
||||
return 0
|
||||
|
||||
|
||||
@@ -1663,11 +1663,11 @@ def _exec_repl_src(mb: memhub.MemBuddy*, src: str) -> int:
|
||||
el: int = ast.get_parse_err_line()
|
||||
ec: int = ast.get_parse_err_col()
|
||||
em: str = ast.get_parse_err_msg()
|
||||
if em is None: em = "(未知)"
|
||||
stdio.printf("ParseError: 第 %d 行第 %d 列: %s\n", el, ec, em)
|
||||
if em is None: em = "(unknown)"
|
||||
stdio.printf("ParseError: line %d column %d: %s\n", el, ec, em)
|
||||
return 0
|
||||
if _count_top_stmts(tree) <= 0:
|
||||
stdio.printf("已解析: 0 个顶层语句(跳过)\n")
|
||||
stdio.printf("Parsed: 0 top-level statements (skipping)\n")
|
||||
return 0
|
||||
# M2/M3 execution path: whole block/line runs as one fragment function body; failures only
|
||||
# print the reason (or longjmp back to the recovery point), never kill the process.
|
||||
@@ -1692,13 +1692,13 @@ def ReplExecFragment(mb: memhub.MemBuddy*, src: str) -> int:
|
||||
global ReplSavedCDefineCount, ReplSavedCTypedefCount
|
||||
if mb is None or src is None: return 1
|
||||
if ReplTmpDir is None or ReplNameBuf is None or ReplSrcBuf is None:
|
||||
stdio.printf("REPL: 会话缓冲未初始化\n")
|
||||
stdio.printf("REPL: session buffer not initialized\n")
|
||||
return 1
|
||||
if ReplSrcPath is None or ReplIrBuf is None or ReplNeedleBuf is None:
|
||||
stdio.printf("REPL: 会话缓冲未初始化\n")
|
||||
stdio.printf("REPL: session buffer not initialized\n")
|
||||
return 1
|
||||
if ReplCtxBuf is None or ReplCtxObj is None or ReplVarTable is None:
|
||||
stdio.printf("REPL: ctx 会话内存未初始化\n")
|
||||
stdio.printf("REPL: ctx session memory not initialized\n")
|
||||
return 1
|
||||
|
||||
# 0) Re-arm the recovery point and snapshot session table watermarks so a failed fragment's
|
||||
@@ -1726,7 +1726,7 @@ def ReplExecFragment(mb: memhub.MemBuddy*, src: str) -> int:
|
||||
# template; multi-line lifts top-level defs. Returns 0=ok/1=rejected/2=buffer full.
|
||||
rc_build: int = _build_frag_src(ReplNameBuf, body)
|
||||
if rc_build == 2:
|
||||
stdio.printf("片段 %s: 包裹源码装配失败(缓冲 %d 字节不足)\n", ReplNameBuf, _REPL_FRAG_SRC_CAP)
|
||||
stdio.printf("fragment %s: failed to assemble the wrapped source (buffer too small, %d bytes)\n", ReplNameBuf, _REPL_FRAG_SRC_CAP)
|
||||
return 1
|
||||
if rc_build != 0:
|
||||
# Lift rule rejection (async def / raise / duplicate / non-single-line signature / own
|
||||
@@ -1773,15 +1773,15 @@ def ReplExecFragment(mb: memhub.MemBuddy*, src: str) -> int:
|
||||
el: int = ast.get_parse_err_line()
|
||||
ec: int = ast.get_parse_err_col()
|
||||
em: str = ast.get_parse_err_msg()
|
||||
if em is None: em = "(未知)"
|
||||
stdio.printf("片段 %s: 包裹源码解析失败(第 %d 行第 %d 列: %s)\n", ReplNameBuf, el, ec, em)
|
||||
if em is None: em = "(unknown)"
|
||||
stdio.printf("fragment %s: failed to parse the wrapped source (line %d column %d: %s)\n", ReplNameBuf, el, ec, em)
|
||||
return 1
|
||||
|
||||
# 7) Translate to full module IR. ModuleSha1 = session sha1 (types are "<sha1>.<Type>");
|
||||
# ReplCtx enables REPL mode and is cleared after translation.
|
||||
tr: HandlesTranslator.Translator* = mb.alloc(HandlesTranslator.Translator.__sizeof__())
|
||||
if tr is None:
|
||||
stdio.printf("片段 %s: Translator 分配失败\n", ReplNameBuf)
|
||||
stdio.printf("fragment %s: Translator allocation failed\n", ReplNameBuf)
|
||||
return 1
|
||||
tr.__before_init__()
|
||||
tr.__init__()
|
||||
@@ -1791,7 +1791,7 @@ def ReplExecFragment(mb: memhub.MemBuddy*, src: str) -> int:
|
||||
rc_tr: int = tr.translate(tree)
|
||||
tr.ReplCtx = None
|
||||
if rc_tr != 0:
|
||||
stdio.printf("片段 %s: 翻译失败\n", ReplNameBuf)
|
||||
stdio.printf("fragment %s: translation failed\n", ReplNameBuf)
|
||||
return 1
|
||||
tr.dump_ir(ReplIrBuf, _REPL_IR_CAP, mlirlite.OUTPUT_FULL)
|
||||
|
||||
@@ -1806,7 +1806,7 @@ def ReplExecFragment(mb: memhub.MemBuddy*, src: str) -> int:
|
||||
# the wrapper/calling convention is wrong (or raise added EH params), so abort.
|
||||
viperlib.snprintf(ReplNeedleBuf, _REPL_NEEDLE_CAP, "llvm.func @%s(%%%s: !llvm.ptr) -> i32", ReplNameBuf, GenTypes.REPL_CTX_PARAM)
|
||||
if string.strstr(ReplIrBuf, ReplNeedleBuf) is None:
|
||||
stdio.printf("片段 %s: 未生成约定的导出函数(期望 `llvm.func @%s(%%__repl_ctx__: !llvm.ptr) -> i32`);" "含 raise 的片段会追加异常出参,M2 不支持\n", ReplNameBuf, ReplNameBuf)
|
||||
stdio.printf("fragment %s: expected export function was not generated (expected `llvm.func @%s(%%__repl_ctx__: !llvm.ptr) -> i32`); " "fragments with raise append EH out params, which M2 does not support\n", ReplNameBuf, ReplNameBuf)
|
||||
return 1
|
||||
|
||||
# 8') Session function signature check (M3), before llc/load: any failure skips the whole
|
||||
@@ -1816,11 +1816,11 @@ def ReplExecFragment(mb: memhub.MemBuddy*, src: str) -> int:
|
||||
# 9) Write .ll (reusing BuildPipeline: sliced path + ensure_dir).
|
||||
ir_len: sizet = string.strlen(ReplIrBuf)
|
||||
if BuildPipeline.write_ir_to_file(ReplIrBuf, ir_len, ReplTmpDir, ReplNameBuf) != 0:
|
||||
stdio.printf("片段 %s: 写 .ll 失败(目录 %s)\n", ReplNameBuf, ReplTmpDir)
|
||||
stdio.printf("fragment %s: failed to write .ll (dir %s)\n", ReplNameBuf, ReplTmpDir)
|
||||
return 1
|
||||
ir_path: str = BuildPipeline.build_sliced_path(ReplTmpDir, ReplNameBuf, "ll")
|
||||
if ir_path is None:
|
||||
stdio.printf("片段 %s: .ll 路径构造失败\n", ReplNameBuf)
|
||||
stdio.printf("fragment %s: failed to build the .ll path\n", ReplNameBuf)
|
||||
return 1
|
||||
|
||||
# 10) llc -> .obj (reusing existing machinery; VLogger.error longjmps on failure).
|
||||
@@ -1831,7 +1831,7 @@ def ReplExecFragment(mb: memhub.MemBuddy*, src: str) -> int:
|
||||
if BuildPipeline.compile_ll_to_obj(ir_path, ReplTmpDir, ReplNameBuf, cc_cmd, cc_flags) != 0:
|
||||
# This branch is only reached on compile_ll_to_obj's internal allocation failure (real llc
|
||||
# failures longjmp), so print a note instead of silently returning to the prompt.
|
||||
stdio.printf("片段 %s: llc 编译 .obj 失败(命令/路径缓冲分配失败,见上方诊断)\n", ReplNameBuf)
|
||||
stdio.printf("fragment %s: llc failed to compile .obj (command/path buffer allocation failed; see diagnostics above)\n", ReplNameBuf)
|
||||
return 1
|
||||
|
||||
# 11) clang++ -shared -> .dll (command shape matches BuildPipeline.link_obj_to_exe; process
|
||||
@@ -1839,19 +1839,19 @@ def ReplExecFragment(mb: memhub.MemBuddy*, src: str) -> int:
|
||||
obj_path: str = BuildPipeline.build_sliced_path(ReplTmpDir, ReplNameBuf, "obj")
|
||||
dll_path: str = BuildPipeline.build_sliced_path(ReplTmpDir, ReplNameBuf, "dll")
|
||||
if obj_path is None or dll_path is None:
|
||||
stdio.printf("片段 %s: .obj/.dll 路径构造失败\n", ReplNameBuf)
|
||||
stdio.printf("fragment %s: failed to build the .obj/.dll path\n", ReplNameBuf)
|
||||
return 1
|
||||
linker_cmd: str = Config.LinkerCmd
|
||||
if linker_cmd is None: linker_cmd = "clang++"
|
||||
cmd: bytes = mb.alloc(_REPL_CMD_CAP)
|
||||
if cmd is None:
|
||||
stdio.printf("片段 %s: 命令行缓冲分配失败\n", ReplNameBuf)
|
||||
stdio.printf("fragment %s: command-line buffer allocation failed\n", ReplNameBuf)
|
||||
return 1
|
||||
# Cross-module symbols come from the host exe, so add the host import lib (if any) to the link
|
||||
# line; M4 also adds this fragment's --out-implib and prior fragments' import libs.
|
||||
implib_path: str = mb.alloc(_REPL_PATH_CAP)
|
||||
if implib_path is None:
|
||||
stdio.printf("片段 %s: import lib 路径缓冲分配失败\n", ReplNameBuf)
|
||||
stdio.printf("fragment %s: import lib path buffer allocation failed\n", ReplNameBuf)
|
||||
return 1
|
||||
viperlib.snprintf(implib_path, _REPL_PATH_CAP, "%s.dll.a", dll_path)
|
||||
pos_c: int = _repl_cat_str(cmd, _REPL_CMD_CAP, 0, linker_cmd)
|
||||
@@ -1867,35 +1867,35 @@ def ReplExecFragment(mb: memhub.MemBuddy*, src: str) -> int:
|
||||
pos_c = _repl_cat_str(cmd, _REPL_CMD_CAP, pos_c, " -Wl,--out-implib=")
|
||||
pos_c = _repl_cat_str(cmd, _REPL_CMD_CAP, pos_c, implib_path)
|
||||
if pos_c < 0:
|
||||
stdio.printf("片段 %s: 链接命令行超过 %d 字节(已登记的片段 import lib 共 %d " "个)——本片段不执行;可重启会话减少片段数\n", ReplNameBuf, _REPL_CMD_CAP, ReplFragImplibCount)
|
||||
stdio.printf("fragment %s: link command line exceeds %d bytes (%d registered fragment import libs " "in total) -- this fragment is skipped; restart the session to reduce the fragment count\n", ReplNameBuf, _REPL_CMD_CAP, ReplFragImplibCount)
|
||||
return 1
|
||||
link_rc: int = BuildPipeline._run_cmd_wait(cmd)
|
||||
if link_rc != 0:
|
||||
stdio.printf("片段 %s: 生成 .dll 失败 (exit=%d)\n 命令: %s\n", ReplNameBuf, link_rc, cmd)
|
||||
stdio.printf("fragment %s: failed to generate .dll (exit=%d)\n command: %s\n", ReplNameBuf, link_rc, cmd)
|
||||
if ReplHostImplib is None:
|
||||
stdio.printf(" 原因提示: 未找到宿主 import lib(<exe 名>.dll.a)——" "跨模块符号(形如 <16位hex>.<函数名>)无法解析;" "宿主需按 TransPyV/project.vpj 构建(含 -Wl,--export-all-symbols)," "且 <exe 名>.dll.a 与 exe 同目录\n")
|
||||
stdio.printf(" Hint: host import lib (<exe name>.dll.a) not found -- " "cross-module symbols (of the form <16-hex>.<func name>) cannot be resolved; " "build the host with TransPyV/project.vpj (including -Wl,--export-all-symbols), " "and keep <exe name>.dll.a in the same dir as the exe\n")
|
||||
else:
|
||||
stdio.printf(" 原因提示: 若输出含 undefined symbol 且形如 <16位hex>.<名>," "则该符号未被宿主定义/导出(宿主构建时未链入对应 includes 模块);" "若该函数在源码里是 `export def`(CExport,裸名定义)却仍带前缀," "多为 include 存根 .vpi 缺失(见会话开头的 includes 扫描行)\n")
|
||||
stdio.printf(" Hint: if the output contains undefined symbol of the form <16-hex>.<name>, " "that symbol is not defined/exported by the host (the corresponding includes module was not linked when building the host); " "if the function is `export def` in source (CExport, bare-name definition) yet still carries a prefix, " "the include stub .vpi is probably missing (see the includes scan line at session start)\n")
|
||||
return 1
|
||||
|
||||
# 11') M4: record this fragment's import lib (if it defined session-prefixed symbols) so later
|
||||
# fragments resolve its class/method symbols; recording failure only warns.
|
||||
if needs_implib != 0:
|
||||
if _is_file(implib_path) != 0 and ReplFragImplibRecord(implib_path) != 0:
|
||||
stdio.printf("片段 %s: 已登记片段 import lib(后续片段可解析本片段定义的" "类型/方法符号): %s\n", ReplNameBuf, implib_path)
|
||||
stdio.printf("fragment %s: registered fragment import lib (later fragments can resolve types/method " "symbols defined by this fragment): %s\n", ReplNameBuf, implib_path)
|
||||
else:
|
||||
stdio.printf("片段 %s: 片段 import lib 未登记(已登记 %d 个,上限 %d;或文件" "缺失)——更晚的片段可能解析不到本片段定义的类型/方法符号\n", ReplNameBuf, ReplFragImplibCount, _REPL_FRAG_IMPLIB_MAX)
|
||||
stdio.printf("fragment %s: fragment import lib not registered (%d registered, limit %d; or the file " "is missing) -- later fragments may fail to resolve types/method symbols defined here\n", ReplNameBuf, ReplFragImplibCount, _REPL_FRAG_IMPLIB_MAX)
|
||||
|
||||
# 12) Dynamic load + address lookup (LoadLibraryA/GetProcAddress).
|
||||
h_lib: win32base.HANDLE = win32base.LoadLibraryA(dll_path)
|
||||
if h_lib is None:
|
||||
stdio.printf("片段 %s: LoadLibraryA 失败: %s\n", ReplNameBuf, dll_path)
|
||||
stdio.printf("fragment %s: LoadLibraryA failed: %s\n", ReplNameBuf, dll_path)
|
||||
if ReplHostImplib is not None:
|
||||
stdio.printf(" 原因提示: 片段 DLL 的导入表指向宿主 exe(%s);" "若 GetLastError 是 127(找不到指定过程)/ 加载器 0xC0000139," "多为宿主与该 import lib 非同一次构建产物、或宿主缺该导出;" "进程镜像名(%s)与 import lib 记录名不一致时同样会失败\n", ReplHostImplib, dll_path)
|
||||
stdio.printf(" Hint: the fragment DLL import table points to the host exe (%s); " "if GetLastError is 127 (procedure not found) / loader 0xC0000139, " "the host and this import lib are usually from different builds, or the host lacks that export; " "it also fails when the process image name (%s) differs from the recorded import lib name\n", ReplHostImplib, dll_path)
|
||||
return 1
|
||||
fp_addr: VOIDPTR = win32base.GetProcAddress(h_lib, ReplNameBuf)
|
||||
if fp_addr is None:
|
||||
stdio.printf("片段 %s: GetProcAddress 返回空(导出表中无该符号): %s\n", ReplNameBuf, dll_path)
|
||||
stdio.printf("fragment %s: GetProcAddress returned null (symbol absent from the export table): %s\n", ReplNameBuf, dll_path)
|
||||
return 1
|
||||
|
||||
# 12') Session function registration (M3), before calling the entry so a failure skips this
|
||||
@@ -1917,9 +1917,9 @@ def ReplExecFragment(mb: memhub.MemBuddy*, src: str) -> int:
|
||||
|
||||
# 14) Read back from the ctx result area and echo (the fragment return is only a status code).
|
||||
if _repl_echo_result(ReplNameBuf, head) != 0:
|
||||
stdio.printf("片段 %s: 结果区读取失败\n", ReplNameBuf)
|
||||
stdio.printf("fragment %s: failed to read the result area\n", ReplNameBuf)
|
||||
return 1
|
||||
if r_rc != 0: stdio.printf("片段 %s: 片段返回非零状态码 %d\n", ReplNameBuf, r_rc)
|
||||
if r_rc != 0: stdio.printf("fragment %s: fragment returned non-zero status %d\n", ReplNameBuf, r_rc)
|
||||
# 14') M4: on success, merge this fragment's new CDefine/CTypedef entries into the session
|
||||
# baseline; failure paths skip this, so the baseline never holds a failed fragment's leftovers.
|
||||
ReplBaselineCapture()
|
||||
@@ -1932,7 +1932,7 @@ def run(mb: memhub.MemBuddy*) -> int:
|
||||
"""M2/M3 REPL: read a line/block, parse, compile to a DLL and call it (session vars via ctx slots), then echo; errors never kill the process."""
|
||||
global ReplJmpBuf, ReplSavedVarCount, ReplSavedFuncCount, ReplInBlock, ReplBlockLen
|
||||
if mb is None or _perm_pool is None:
|
||||
stdio.printf("REPL: 需要主池与 PermPool(由 main 注入 _perm_pool)\n")
|
||||
stdio.printf("REPL: need the main pool and PermPool (main injects _perm_pool)\n")
|
||||
return 1
|
||||
|
||||
# Parse tables (keywords/operators) go in PermPool: they are ast module-level globals built
|
||||
@@ -1941,7 +1941,7 @@ def run(mb: memhub.MemBuddy*) -> int:
|
||||
|
||||
jb: rawptr = _perm_pool.alloc(_REPL_JMPBUF_SIZE)
|
||||
if jb is None:
|
||||
stdio.printf("REPL: jmp_buf 分配失败\n")
|
||||
stdio.printf("REPL: jmp_buf allocation failed\n")
|
||||
return 1
|
||||
# Session-level registration: ReplJmpBuf is re-registered per fragment; the VLogger side is set
|
||||
# once and cleared only on run exit (that is what covers the whole pipeline).
|
||||
@@ -1956,7 +1956,7 @@ def run(mb: memhub.MemBuddy*) -> int:
|
||||
# un-armed jmp_buf would be UB; init is the only stage that must succeed, so exit on failure.
|
||||
rc_init: int = _setjmp(jb, None)
|
||||
if rc_init != 0:
|
||||
stdio.printf("REPL: 会话初始化中断(诊断见上)—— 无常驻缓冲/ctx,REPL 无法启动\n")
|
||||
stdio.printf("REPL: session init interrupted (see diagnostics above) -- no resident buffers/ctx, REPL cannot start\n")
|
||||
stdio.fflush(None)
|
||||
ReplJmpBuf = None
|
||||
VLogger.clear_repl_jmpbuf()
|
||||
@@ -1965,7 +1965,7 @@ def run(mb: memhub.MemBuddy*) -> int:
|
||||
|
||||
# Session init: temp dir + permanent buffers + ctx (all PermPool; see ReplInitSession).
|
||||
if ReplInitSession() != 0:
|
||||
stdio.printf("REPL: 会话初始化失败(临时目录/常驻缓冲/ctx)\n")
|
||||
stdio.printf("REPL: session init failed (temp dir/resident buffers/ctx)\n")
|
||||
ReplJmpBuf = None
|
||||
VLogger.clear_repl_jmpbuf()
|
||||
if lg is not None: lg.set_jit_flag(False)
|
||||
@@ -1974,23 +1974,23 @@ def run(mb: memhub.MemBuddy*) -> int:
|
||||
h_in: win32base.HANDLE = w32file.GetStdHandle(w32file.STD_INPUT_HANDLE)
|
||||
line: bytes = stdlib.malloc(_REPL_LINE_CAP)
|
||||
if line is None:
|
||||
stdio.printf("REPL: 行缓冲分配失败\n")
|
||||
stdio.printf("REPL: line buffer allocation failed\n")
|
||||
ReplJmpBuf = None
|
||||
VLogger.clear_repl_jmpbuf()
|
||||
if lg is not None: lg.set_jit_flag(False)
|
||||
return 1
|
||||
|
||||
stdio.printf("TransPyV REPL (M2/M3/M4) - 会话变量 + 会话函数(跨片段)+ ctx 回传结果;\n")
|
||||
stdio.printf(" 支持表达式(1+2)、定义(x = 1 / x: int = 5)、引用(x + 1)、\n")
|
||||
stdio.printf(" 增强赋值(x += 2)、取址(p = &x)等;空行跳过,Ctrl+Z 或 EOF 退出\n")
|
||||
stdio.printf(" 多行块:行尾 ':' 进入续行(提示符 ...),空行结束并整块执行一次\n")
|
||||
stdio.printf(" 跨片段函数:块里顶格的 def 会被提升为片段模块的 export def(裸名导出),\n")
|
||||
stdio.printf(" 后续片段可直接调用(如 def f(x: int) -> int: 换行 +4 空格 return x + 1);\n")
|
||||
stdio.printf(" 限制:签名须单行、不支持 async def、函数体内不支持 raise、不支持偏函数\n")
|
||||
stdio.printf(" 跨片段类型(M4):块里的 class 会被翻译进会话(类型名 %s.<类名>),\n", ReplSessionSha1)
|
||||
stdio.printf(" 后续片段可实例化、读写字段、调用方法;import 的 includes 模块\n")
|
||||
stdio.printf(" 其类同样注册进会话(缺 .vpi 存根时该模块的类不可用,会话继续)\n")
|
||||
stdio.printf(" 片段临时目录: %s\n", ReplTmpDir)
|
||||
stdio.printf("TransPyV REPL (M2/M3/M4) - session variables + session functions (cross-fragment) + ctx result echo;\n")
|
||||
stdio.printf(" Supports expressions (1+2), definitions (x = 1 / x: int = 5), references (x + 1),\n")
|
||||
stdio.printf(" augmented assignment (x += 2), address-of (p = &x), etc.; blank lines are skipped, Ctrl+Z or EOF exits\n")
|
||||
stdio.printf(" Multi-line block: a trailing ':' enters continuation (prompt ...), a blank line ends it and runs the block once\n")
|
||||
stdio.printf(" Cross-fragment functions: a top-level def in a block is lifted to the fragment module's export def (bare-name export),\n")
|
||||
stdio.printf(" later fragments can call it directly (e.g. def f(x: int) -> int: newline + 4 spaces return x + 1);\n")
|
||||
stdio.printf(" Restrictions: signature must be one line, async def is unsupported, raise in the body is unsupported, partial functions are unsupported\n")
|
||||
stdio.printf(" Cross-fragment types (M4): a class in a block is translated into the session (type name %s.<class name>),\n", ReplSessionSha1)
|
||||
stdio.printf(" later fragments can instantiate it, read/write fields and call methods; imported includes modules\n")
|
||||
stdio.printf(" have their classes registered into the session too (when the .vpi stub is missing that module's classes are unavailable; the session continues)\n")
|
||||
stdio.printf(" Fragment temp dir: %s\n", ReplTmpDir)
|
||||
stdio.fflush(None)
|
||||
|
||||
# === Session-level includes init (once; all failures only degrade includes classes) ===
|
||||
@@ -1998,7 +1998,7 @@ def run(mb: memhub.MemBuddy*) -> int:
|
||||
inc_mark: sizet = mb.mark()
|
||||
rc_inc: int = _setjmp(jb, None)
|
||||
if rc_inc != 0:
|
||||
stdio.printf("REPL: includes 初始化中断(已注册 %d 个模块、存根 %d 个):" "import includes 模块可能失败,其余片段不受影响\n", ReplIncMods, ReplIncVpiNew)
|
||||
stdio.printf("REPL: includes init interrupted (%d modules registered, %d stubs): " "importing includes modules may fail; other fragments are unaffected\n", ReplIncMods, ReplIncVpiNew)
|
||||
mb.reset_to(inc_mark)
|
||||
else:
|
||||
# Scan results/registry live in stdlib, so mb allocations can be reclaimed after this call,
|
||||
@@ -2009,7 +2009,7 @@ def run(mb: memhub.MemBuddy*) -> int:
|
||||
# calling frame); this puts the finish step and read loop back under this frame's point.
|
||||
rc_arm: int = _setjmp(jb, None)
|
||||
if rc_arm != 0:
|
||||
stdio.printf("REPL: includes 类布局收尾中断(诊断见上):布局注册可能不完整," "会话继续\n")
|
||||
stdio.printf("REPL: includes class layout finish interrupted (see diagnostics above): layout registration may be incomplete; " "session continues\n")
|
||||
else:
|
||||
# Finish: converge classes whose parents became ready in later passes + per-class warnings.
|
||||
# Done after re-arming so any longjmp lands in this frame (the dead-frame issue above).
|
||||
@@ -2021,14 +2021,14 @@ def run(mb: memhub.MemBuddy*) -> int:
|
||||
# === Host export symbols: locate the host exe import lib ===
|
||||
# If found, fragment link lines include it; otherwise warn and continue (calls may fail to link).
|
||||
if ReplFindHostImplib() != 0:
|
||||
stdio.printf("宿主符号导入库: %s(片段可跨模块调用 includes 函数/全局)\n", ReplHostImplib)
|
||||
stdio.printf("Host symbol import lib: %s (fragments can call includes functions/globals across modules)\n", ReplHostImplib)
|
||||
else:
|
||||
stdio.printf("宿主符号导入库: 未找到 <exe 名>.dll.a;片段调用 includes 模块级" "函数会在链接期报 undefined symbol(会话不终止)。请用 " "TransPyV/project.vpj(已声明 -Wl,--export-all-symbols)构建宿主," "并让 exe 与 .dll.a 同目录\n")
|
||||
stdio.printf("Host symbol import lib: <exe name>.dll.a not found; fragment calls to includes module-level " "functions will report undefined symbol at link time (the session does not terminate). Build the host with " "TransPyV/project.vpj (which declares -Wl,--export-all-symbols), " "and keep the exe and .dll.a in the same dir\n")
|
||||
stdio.fflush(None)
|
||||
|
||||
# === Read loop: single-line fragments + block continuation ===
|
||||
# All init failures were absorbed, so the prompt is guaranteed to appear from here on.
|
||||
stdio.printf("REPL: 初始化完成,进入读行循环\n")
|
||||
stdio.printf("REPL: init complete, entering the read loop\n")
|
||||
stdio.fflush(None)
|
||||
# Block state is zeroed after every block end/failure/EOF/overflow, so a stale block cannot
|
||||
# pollute the next line (the next append overwrites from index 0).
|
||||
@@ -2080,7 +2080,7 @@ def run(mb: memhub.MemBuddy*) -> int:
|
||||
continue
|
||||
# In continuation: every line is buffered; no state flips on ':' and no indent analysis.
|
||||
if _block_append(line, n) != 0:
|
||||
stdio.printf("REPL: 块输入超过块缓冲上界 %d 字节:本块已丢弃," "回到 >>> 继续(可减少块体积或分块执行)\n", _REPL_BLOCK_CAP)
|
||||
stdio.printf("REPL: block input exceeds the block buffer cap of %d bytes: this block was discarded, " "returning to >>> (reduce the block size or run it in chunks)\n", _REPL_BLOCK_CAP)
|
||||
ReplInBlock = 0
|
||||
ReplBlockLen = 0
|
||||
mb.reset_to(mark)
|
||||
|
||||
@@ -158,26 +158,26 @@ novirtual class Logger:
|
||||
def compile_error(self, msg: str, file: str = "", line: int = 0) -> int:
|
||||
"""Format a compile error with a red-background header, location and message."""
|
||||
self._set_color(BACKGROUND_RED | FOREGROUND_WHITE | FOREGROUND_INTENSITY)
|
||||
stdio.printf(" 编译错误 ")
|
||||
stdio.printf(" COMPILE ERROR ")
|
||||
self._set_color(FOREGROUND_RED | FOREGROUND_INTENSITY)
|
||||
stdio.printf("\n")
|
||||
if file is not None:
|
||||
if file[0] != 0 and line > 0: stdio.printf(" 位置: %s:%d\n", file, line)
|
||||
elif file[0] != 0: stdio.printf(" 文件: %s\n", file)
|
||||
stdio.printf(" 错误: %s\n", msg)
|
||||
if file[0] != 0 and line > 0: stdio.printf(" location: %s:%d\n", file, line)
|
||||
elif file[0] != 0: stdio.printf(" file: %s\n", file)
|
||||
stdio.printf(" error: %s\n", msg)
|
||||
self._reset_color()
|
||||
return 0
|
||||
|
||||
def compile_warning(self, msg: str, file: str = "", line: int = 0) -> int:
|
||||
"""Format a compile warning with a yellow background, location and message."""
|
||||
self._set_color(BACKGROUND_RED | BACKGROUND_GREEN | FOREGROUND_INTENSITY)
|
||||
stdio.printf(" 编译警告 ")
|
||||
stdio.printf(" COMPILE WARNING ")
|
||||
self._set_color(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY)
|
||||
stdio.printf("\n")
|
||||
if file is not None:
|
||||
if file[0] != 0 and line > 0: stdio.printf(" 位置: %s:%d\n", file, line)
|
||||
elif file[0] != 0: stdio.printf(" 文件: %s\n", file)
|
||||
stdio.printf(" 警告: %s\n", msg)
|
||||
if file[0] != 0 and line > 0: stdio.printf(" location: %s:%d\n", file, line)
|
||||
elif file[0] != 0: stdio.printf(" file: %s\n", file)
|
||||
stdio.printf(" warning: %s\n", msg)
|
||||
self._reset_color()
|
||||
return 0
|
||||
|
||||
|
||||
@@ -473,16 +473,16 @@ def _ApplyCtorArgs(cl: ast.Call*) -> int:
|
||||
if cl.args is not None:
|
||||
an: sizet = cl.args.__len__()
|
||||
if an > 2:
|
||||
VLogger.error("viperbuild: Project(...) 位置参数最多 2 个(name, version)", "viperbuild")
|
||||
VLogger.error("viperbuild: Project(...) accepts at most 2 positional arguments (name, version)", "viperbuild")
|
||||
return 1
|
||||
if an >= 1:
|
||||
if _EvalStr(cl.args.get(0)) == 0:
|
||||
VLogger.error("viperbuild: Project(name) 必须是字符串常量", "viperbuild")
|
||||
VLogger.error("viperbuild: Project(name) must be a string constant", "viperbuild")
|
||||
return 1
|
||||
_c_name = _DupStd(_g_out_str)
|
||||
if an >= 2:
|
||||
if _EvalStr(cl.args.get(1)) == 0:
|
||||
VLogger.error("viperbuild: Project(version) 必须是字符串常量", "viperbuild")
|
||||
VLogger.error("viperbuild: Project(version) must be a string constant", "viperbuild")
|
||||
return 1
|
||||
_c_version = _DupStd(_g_out_str)
|
||||
if cl.keywords is None: return 0
|
||||
@@ -492,16 +492,16 @@ def _ApplyCtorArgs(cl: ast.Call*) -> int:
|
||||
if kw is not None and kw.arg is not None and kw.value is not None:
|
||||
if string.strcmp(kw.arg, "name") == 0:
|
||||
if _EvalStr(kw.value) == 0:
|
||||
VLogger.error("viperbuild: Project(name=...) 必须是字符串常量", "viperbuild")
|
||||
VLogger.error("viperbuild: Project(name=...) must be a string constant", "viperbuild")
|
||||
return 1
|
||||
_c_name = _DupStd(_g_out_str)
|
||||
elif string.strcmp(kw.arg, "version") == 0:
|
||||
if _EvalStr(kw.value) == 0:
|
||||
VLogger.error("viperbuild: Project(version=...) 必须是字符串常量", "viperbuild")
|
||||
VLogger.error("viperbuild: Project(version=...) must be a string constant", "viperbuild")
|
||||
return 1
|
||||
_c_version = _DupStd(_g_out_str)
|
||||
else:
|
||||
VLogger.error(f"viperbuild: Project(...) 不支持的关键字 {kw.arg}", "viperbuild")
|
||||
VLogger.error(f"viperbuild: unsupported keyword {kw.arg} for Project(...)", "viperbuild")
|
||||
return 1
|
||||
return 0
|
||||
|
||||
@@ -514,31 +514,31 @@ def _SetField(fname: str, vnode: ast.AST*) -> int:
|
||||
# ---- String fields ----
|
||||
if string.strcmp(fname, "source") == 0:
|
||||
if _EvalStr(vnode) == 0:
|
||||
VLogger.error("viperbuild: source 必须是字符串常量表达式", "viperbuild")
|
||||
VLogger.error("viperbuild: source must be a string constant expression", "viperbuild")
|
||||
return 1
|
||||
_c_source = _DupStd(_g_out_str)
|
||||
return 0
|
||||
if string.strcmp(fname, "buildroot") == 0:
|
||||
if _EvalStr(vnode) == 0:
|
||||
VLogger.error("viperbuild: buildroot 必须是字符串常量表达式", "viperbuild")
|
||||
VLogger.error("viperbuild: buildroot must be a string constant expression", "viperbuild")
|
||||
return 1
|
||||
_c_buildroot = _DupStd(_g_out_str)
|
||||
return 0
|
||||
if string.strcmp(fname, "output") == 0:
|
||||
if _EvalStr(vnode) == 0:
|
||||
VLogger.error("viperbuild: output 必须是字符串常量表达式", "viperbuild")
|
||||
VLogger.error("viperbuild: output must be a string constant expression", "viperbuild")
|
||||
return 1
|
||||
_c_output = _DupStd(_g_out_str)
|
||||
return 0
|
||||
if string.strcmp(fname, "name") == 0:
|
||||
if _EvalStr(vnode) == 0:
|
||||
VLogger.error("viperbuild: name 必须是字符串常量表达式", "viperbuild")
|
||||
VLogger.error("viperbuild: name must be a string constant expression", "viperbuild")
|
||||
return 1
|
||||
_c_name = _DupStd(_g_out_str)
|
||||
return 0
|
||||
if string.strcmp(fname, "version") == 0:
|
||||
if _EvalStr(vnode) == 0:
|
||||
VLogger.error("viperbuild: version 必须是字符串常量表达式", "viperbuild")
|
||||
VLogger.error("viperbuild: version must be a string constant expression", "viperbuild")
|
||||
return 1
|
||||
_c_version = _DupStd(_g_out_str)
|
||||
return 0
|
||||
@@ -548,7 +548,7 @@ def _SetField(fname: str, vnode: ast.AST*) -> int:
|
||||
if string.strcmp(fname, "linker") == 0: return _SetListField(2, vnode)
|
||||
if string.strcmp(fname, "static_libs") == 0: return _SetListField(3, vnode)
|
||||
if string.strcmp(fname, "dynamic_libs") == 0: return _SetListField(4, vnode)
|
||||
VLogger.error(f"viperbuild: 未知字段 proj.{fname}", "viperbuild")
|
||||
VLogger.error(f"viperbuild: unknown field proj.{fname}", "viperbuild")
|
||||
return 1
|
||||
|
||||
|
||||
@@ -559,7 +559,7 @@ def _SetListField(slot: int, vnode: ast.AST*) -> int:
|
||||
tmp: list[str]* = list[str](_scratch, 8)
|
||||
if tmp is None: return 1
|
||||
if _EvalList(vnode, tmp) == 0:
|
||||
VLogger.error("viperbuild: 列表字段必须是 list[str] 常量表达式", "viperbuild")
|
||||
VLogger.error("viperbuild: list fields must be list[str] constant expressions", "viperbuild")
|
||||
return 1
|
||||
joined: str = _JoinSpace(tmp)
|
||||
if slot == 0: _c_includes = joined
|
||||
@@ -595,12 +595,12 @@ def _HandleNameBind(tgt: ast.Name*, vnode: ast.AST*) -> int:
|
||||
if tgt is None or vnode is None or tgt.id is None: return 0
|
||||
# Reading a Project macro object on the RHS is fatal (reading forbidden)
|
||||
if _IsProjRef(vnode) != 0:
|
||||
VLogger.error(f"viperbuild: 禁止读取 Project 宏对象({tgt.id} = proj ...)", "viperbuild")
|
||||
VLogger.error(f"viperbuild: reading the Project macro object is forbidden ({tgt.id} = proj ...)", "viperbuild")
|
||||
return 1
|
||||
# Project instance binding
|
||||
if _IsProjectCtor(vnode) != 0:
|
||||
if _c_has_project != 0:
|
||||
VLogger.error("viperbuild: 一个依赖闭包内只允许一个 Project 对象", "viperbuild")
|
||||
VLogger.error("viperbuild: only one Project object is allowed per dependency closure", "viperbuild")
|
||||
return 1
|
||||
_c_has_project = 1
|
||||
_proj_vars.append(_DupScratch(tgt.id))
|
||||
@@ -631,7 +631,7 @@ def _HandleAttrAssign(tgt: ast.Attribute*, vnode: ast.AST*) -> int:
|
||||
if bn is None or bn.id is None: return 0
|
||||
if _FindInList(_proj_vars, bn.id) < 0: return 0
|
||||
if _IsProjRef(vnode) != 0:
|
||||
VLogger.error("viperbuild: 禁止读取 Project 宏对象", "viperbuild")
|
||||
VLogger.error("viperbuild: reading the Project macro object is forbidden", "viperbuild")
|
||||
return 1
|
||||
return _SetField(tgt.attr, vnode)
|
||||
|
||||
@@ -652,7 +652,7 @@ def _HandleBuildCall(cl: ast.Call*) -> int:
|
||||
global _c_triple, _c_datalayout, _c_selfmachine, _c_has_build
|
||||
if cl is None: return 1
|
||||
if _c_has_build != 0:
|
||||
VLogger.error("viperbuild: proj.build() 只能调用一次", "viperbuild")
|
||||
VLogger.error("viperbuild: proj.build() may be called only once", "viperbuild")
|
||||
return 1
|
||||
_c_has_build = 1
|
||||
if cl.keywords is None: return 0
|
||||
@@ -662,22 +662,22 @@ def _HandleBuildCall(cl: ast.Call*) -> int:
|
||||
if kw is not None and kw.arg is not None and kw.value is not None:
|
||||
if string.strcmp(kw.arg, "triple") == 0:
|
||||
if _EvalStr(kw.value) == 0:
|
||||
VLogger.error("viperbuild: build(triple=...) 必须是字符串常量", "viperbuild")
|
||||
VLogger.error("viperbuild: build(triple=...) must be a string constant", "viperbuild")
|
||||
return 1
|
||||
_c_triple = _DupStd(_g_out_str)
|
||||
elif string.strcmp(kw.arg, "datalayout") == 0:
|
||||
if _EvalStr(kw.value) == 0:
|
||||
VLogger.error("viperbuild: build(datalayout=...) 必须是字符串常量", "viperbuild")
|
||||
VLogger.error("viperbuild: build(datalayout=...) must be a string constant", "viperbuild")
|
||||
return 1
|
||||
_c_datalayout = _DupStd(_g_out_str)
|
||||
elif string.strcmp(kw.arg, "selfmachine") == 0:
|
||||
b: int = _EvalBool(kw.value)
|
||||
if b < 0:
|
||||
VLogger.error("viperbuild: build(selfmachine=...) 必须是布尔常量", "viperbuild")
|
||||
VLogger.error("viperbuild: build(selfmachine=...) must be a boolean constant", "viperbuild")
|
||||
return 1
|
||||
_c_selfmachine = b
|
||||
else:
|
||||
VLogger.error(f"viperbuild: build(...) 不支持的关键字 {kw.arg}", "viperbuild")
|
||||
VLogger.error(f"viperbuild: unsupported keyword {kw.arg} for build(...)", "viperbuild")
|
||||
return 1
|
||||
return 0
|
||||
|
||||
@@ -708,26 +708,26 @@ def _HandleExprStmt(stmt: ast.Expr*) -> int:
|
||||
# Non-Project method call: if an argument reads the macro object -> fatal (reading forbidden)
|
||||
if cl.func.kind() != ast.ASTKind.Attribute:
|
||||
if _CallArgsHaveProjRef(cl) != 0:
|
||||
VLogger.error("viperbuild: 禁止读取 Project 宏对象", "viperbuild")
|
||||
VLogger.error("viperbuild: reading the Project macro object is forbidden", "viperbuild")
|
||||
return 1
|
||||
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:
|
||||
if _CallArgsHaveProjRef(cl) != 0:
|
||||
VLogger.error("viperbuild: 禁止读取 Project 宏对象", "viperbuild")
|
||||
VLogger.error("viperbuild: reading the Project macro object is forbidden", "viperbuild")
|
||||
return 1
|
||||
return 0
|
||||
bn: ast.Name* = ast.Name*(at.value)
|
||||
if bn is None or bn.id is None: return 0
|
||||
if _FindInList(_proj_vars, bn.id) < 0:
|
||||
if _CallArgsHaveProjRef(cl) != 0:
|
||||
VLogger.error("viperbuild: 禁止读取 Project 宏对象", "viperbuild")
|
||||
VLogger.error("viperbuild: reading the Project macro object is forbidden", "viperbuild")
|
||||
return 1
|
||||
return 0
|
||||
if string.strcmp(at.attr, "config") == 0: return _HandleConfigCall(cl)
|
||||
if string.strcmp(at.attr, "build") == 0: return _HandleBuildCall(cl)
|
||||
VLogger.error(f"viperbuild: Project 对象不支持的方法 {at.attr}()", "viperbuild")
|
||||
VLogger.error(f"viperbuild: unsupported method {at.attr}() on Project object", "viperbuild")
|
||||
return 1
|
||||
|
||||
|
||||
@@ -742,12 +742,12 @@ def _ScanFile(pool: memhub.MemBuddy*, path: str) -> int:
|
||||
|
||||
src_buf: bytes = Utils.read_file_to_buf(path, VB_SRC_CAP)
|
||||
if src_buf is None:
|
||||
VLogger.warning(f"viperbuild: 无法读取依赖文件 {path}", "viperbuild")
|
||||
VLogger.warning(f"viperbuild: cannot read dependency file {path}", "viperbuild")
|
||||
return 2
|
||||
|
||||
if _ResetFileTables(pool) != 0:
|
||||
stdlib.free(src_buf)
|
||||
VLogger.error("viperbuild: 常量表分配失败", "viperbuild")
|
||||
VLogger.error("viperbuild: constant table allocation failed", "viperbuild")
|
||||
return 1
|
||||
|
||||
mark: sizet = pool.mark()
|
||||
@@ -755,20 +755,20 @@ def _ScanFile(pool: memhub.MemBuddy*, path: str) -> int:
|
||||
if lx is None:
|
||||
pool.reset_to(mark)
|
||||
stdlib.free(src_buf)
|
||||
VLogger.error("viperbuild: lexer 分配失败", "viperbuild")
|
||||
VLogger.error("viperbuild: lexer allocation failed", "viperbuild")
|
||||
return 1
|
||||
ast._lexer_init(lx, src_buf, pool)
|
||||
tokens: ast.Token* = ast.tokenize(lx)
|
||||
if tokens is None:
|
||||
pool.reset_to(mark)
|
||||
stdlib.free(src_buf)
|
||||
VLogger.error(f"viperbuild: 词法失败 {path}", "viperbuild")
|
||||
VLogger.error(f"viperbuild: tokenization failed {path}", "viperbuild")
|
||||
return 1
|
||||
tree: ast.AST* = ast.parse_tokens(pool, tokens)
|
||||
if tree is None:
|
||||
pool.reset_to(mark)
|
||||
stdlib.free(src_buf)
|
||||
VLogger.error(f"viperbuild: 语法失败 {path}", "viperbuild")
|
||||
VLogger.error(f"viperbuild: parsing failed {path}", "viperbuild")
|
||||
return 1
|
||||
|
||||
body: list[ast.AST*]* = tree.children
|
||||
@@ -841,13 +841,13 @@ def _RunBfs(pool: memhub.MemBuddy*, entry_path: str) -> int:
|
||||
if cur is None: continue
|
||||
if _FindInList(_visited, cur) >= 0: continue
|
||||
if _visited.__len__() >= VB_MAX_VISIT:
|
||||
VLogger.error(f"viperbuild: 依赖闭包超过 {VB_MAX_VISIT} 个文件,疑似成环", "viperbuild")
|
||||
VLogger.error(f"viperbuild: dependency closure exceeds {VB_MAX_VISIT} files, likely a cycle", "viperbuild")
|
||||
return 1
|
||||
_visited.append(_DupScratch(cur))
|
||||
|
||||
_pending = list[str](_scratch, 8)
|
||||
if _pending is None:
|
||||
VLogger.error("viperbuild: BFS 队列分配失败", "viperbuild")
|
||||
VLogger.error("viperbuild: BFS queue allocation failed", "viperbuild")
|
||||
return 1
|
||||
rc: int = _ScanFile(pool, cur)
|
||||
if rc == 1: return 1
|
||||
@@ -867,13 +867,13 @@ def _DetectHost() -> int:
|
||||
global _c_triple, _c_datalayout
|
||||
buf: CHARPTR = stdlib.malloc(64)
|
||||
if buf is None:
|
||||
VLogger.error("viperbuild: selfmachine 探测缓冲分配失败", "viperbuild")
|
||||
VLogger.error("viperbuild: selfmachine probe buffer allocation failed", "viperbuild")
|
||||
return 1
|
||||
buf[0] = char(0)
|
||||
n: DWORD = GetEnvironmentVariableA("PROCESSOR_ARCHITECTURE", buf, DWORD(64))
|
||||
if n == 0 or n >= DWORD(64):
|
||||
stdlib.free(buf)
|
||||
VLogger.error("viperbuild: selfmachine 探测失败(PROCESSOR_ARCHITECTURE 不可用)", "viperbuild")
|
||||
VLogger.error("viperbuild: selfmachine probe failed (PROCESSOR_ARCHITECTURE unavailable)", "viperbuild")
|
||||
return 1
|
||||
buf[int(n)] = char(0)
|
||||
# "AMD64\0" (A=65 M=77 D=68 6=54 4=52)
|
||||
@@ -885,7 +885,7 @@ def _DetectHost() -> int:
|
||||
stdlib.free(buf)
|
||||
return 0
|
||||
stdlib.free(buf)
|
||||
VLogger.error("viperbuild: selfmachine 暂不支持本机架构(当前仅支持 AMD64)", "viperbuild")
|
||||
VLogger.error("viperbuild: selfmachine does not support the host architecture yet (currently only AMD64)", "viperbuild")
|
||||
return 1
|
||||
|
||||
|
||||
@@ -941,10 +941,10 @@ def _FinalizeCfg(entry_path: str) -> int:
|
||||
global _c_selfmachine
|
||||
|
||||
if _c_has_project == 0:
|
||||
VLogger.error("viperbuild: 依赖闭包内未找到 vb.Project(...) 定义", "viperbuild")
|
||||
VLogger.error("viperbuild: no vb.Project(...) definition found in the dependency closure", "viperbuild")
|
||||
return 1
|
||||
if _c_has_build == 0:
|
||||
VLogger.error("viperbuild: 未调用 proj.build(...),无法确定构建目标", "viperbuild")
|
||||
VLogger.error("viperbuild: proj.build(...) was not called, cannot determine the build target", "viperbuild")
|
||||
return 1
|
||||
|
||||
# ---- Defaults ----
|
||||
@@ -953,7 +953,7 @@ def _FinalizeCfg(entry_path: str) -> int:
|
||||
if _c_includes is None:
|
||||
probed: str = _ProbeIncludes()
|
||||
if probed is None:
|
||||
VLogger.error("viperbuild: 未能探测到 includes 目录(exe 目录向上 0..3 层均无 includes)", "viperbuild")
|
||||
VLogger.error("viperbuild: could not probe an includes directory (no includes up to 0..3 levels above the exe directory)", "viperbuild")
|
||||
return 1
|
||||
_c_includes = probed
|
||||
if _c_compiler is None: _c_compiler = _DupStd("llc -filetype=obj -relocation-model=pic")
|
||||
@@ -965,18 +965,18 @@ def _FinalizeCfg(entry_path: str) -> int:
|
||||
|
||||
# ---- Entry file must be under source ----
|
||||
if _HasPrefix(entry_path, _c_source) == 0:
|
||||
VLogger.error(f"viperbuild: 入口文件不在 source 目录之下\n 入口: {entry_path}\n source: {_c_source}", "viperbuild")
|
||||
VLogger.error(f"viperbuild: entry file is not under the source directory\n entry: {entry_path}\n source: {_c_source}", "viperbuild")
|
||||
return 1
|
||||
|
||||
# ---- Target platform ----
|
||||
explicit_triple: int = 0
|
||||
if _c_triple is not None or _c_datalayout is not None: explicit_triple = 1
|
||||
if _c_selfmachine != 0 and explicit_triple != 0:
|
||||
VLogger.error("viperbuild: build(selfmachine=True) 与显式 triple/datalayout 互斥", "viperbuild")
|
||||
VLogger.error("viperbuild: build(selfmachine=True) is mutually exclusive with an explicit triple/datalayout", "viperbuild")
|
||||
return 1
|
||||
if explicit_triple != 0:
|
||||
if _c_triple is None or _c_datalayout is None:
|
||||
VLogger.error("viperbuild: build() 的 triple 与 datalayout 必须成对给出", "viperbuild")
|
||||
VLogger.error("viperbuild: build() triple and datalayout must be given as a pair", "viperbuild")
|
||||
return 1
|
||||
else:
|
||||
# Neither given, or selfmachine=True: detect the host at runtime
|
||||
@@ -1065,7 +1065,7 @@ def DiscoverAndApply(mb: memhub.MemBuddy*, entry_path: str) -> int:
|
||||
global _search_dirs
|
||||
|
||||
if mb is None or entry_path is None:
|
||||
VLogger.error("viperbuild: 参数为空", "viperbuild")
|
||||
VLogger.error("viperbuild: argument is null", "viperbuild")
|
||||
return 1
|
||||
|
||||
_ResetAll()
|
||||
@@ -1073,7 +1073,7 @@ def DiscoverAndApply(mb: memhub.MemBuddy*, entry_path: str) -> int:
|
||||
# Entry dir (default source + closure search root)
|
||||
_entry_dir = _DirOf(entry_path)
|
||||
if _entry_dir is None:
|
||||
VLogger.error(f"viperbuild: 无法解析入口文件目录 {entry_path}", "viperbuild")
|
||||
VLogger.error(f"viperbuild: cannot resolve the entry file directory {entry_path}", "viperbuild")
|
||||
return 1
|
||||
# Bare filename (no separator) -> _DirOf returns ""; must normalize to ".", otherwise
|
||||
# ResolveModuleToPath("") tries no candidate and same-dir deps (often the viperbuild config) never resolve.
|
||||
@@ -1084,11 +1084,11 @@ def DiscoverAndApply(mb: memhub.MemBuddy*, entry_path: str) -> int:
|
||||
# Scratch pool (BFS working set; not affected by main-pool reset)
|
||||
arena: bytes = stdlib.malloc(VB_SCRATCH)
|
||||
if arena is None:
|
||||
VLogger.error("viperbuild: scratch 内存分配失败", "viperbuild")
|
||||
VLogger.error("viperbuild: scratch memory allocation failed", "viperbuild")
|
||||
return 1
|
||||
_scratch = memhub.MemBuddy(arena, VB_SCRATCH, 0, 0)
|
||||
if _scratch is None:
|
||||
VLogger.error("viperbuild: scratch 池初始化失败", "viperbuild")
|
||||
VLogger.error("viperbuild: scratch pool initialization failed", "viperbuild")
|
||||
return 1
|
||||
|
||||
_work = list[str](_scratch, 8)
|
||||
@@ -1096,7 +1096,7 @@ def DiscoverAndApply(mb: memhub.MemBuddy*, entry_path: str) -> int:
|
||||
_pending = list[str](_scratch, 8)
|
||||
_proj_vars = list[str](_scratch, 8)
|
||||
if _work is None or _visited is None or _pending is None or _proj_vars is None:
|
||||
VLogger.error("viperbuild: 工作集分配失败", "viperbuild")
|
||||
VLogger.error("viperbuild: working set allocation failed", "viperbuild")
|
||||
return 1
|
||||
|
||||
# Keyword/operator tables must be built before the main-pool reset window (else freed -> dangling crash)
|
||||
@@ -1105,8 +1105,8 @@ def DiscoverAndApply(mb: memhub.MemBuddy*, entry_path: str) -> int:
|
||||
if _RunBfs(mb, entry_path) != 0: return 1
|
||||
|
||||
if _proj_vars.__len__() == 0:
|
||||
if _saw_viperbuild == 0: VLogger.error(f"viperbuild: 入口文件依赖闭包内未找到 `import viperbuild`(入口: {entry_path};已扫描 {_visited.__len__()} 个文件)", "viperbuild")
|
||||
else: VLogger.error(f"viperbuild: 找到 `import viperbuild` 但依赖闭包内没有 `proj = vb.Project(...)` 绑定(入口: {entry_path})", "viperbuild")
|
||||
if _saw_viperbuild == 0: VLogger.error(f"viperbuild: `import viperbuild` not found in the entry file dependency closure (entry: {entry_path}; scanned {_visited.__len__()} files)", "viperbuild")
|
||||
else: VLogger.error(f"viperbuild: found `import viperbuild` but the dependency closure has no `proj = vb.Project(...)` binding (entry: {entry_path})", "viperbuild")
|
||||
return 1
|
||||
|
||||
if _FinalizeCfg(entry_path) != 0: return 1
|
||||
|
||||
Reference in new issue
Block a user