增加 JIT REPL
This commit is contained in:
1 parent
9910e05760
commit
a5ceb3d4eb
56 files changed
+7602
-565
No files matched your search
@@ -115,7 +115,10 @@ def TranslateFileGetTrans(mb: rawptr[memhub.MemBuddy], file_path: str,
|
||||
pyi_buf: bytes = stdlib.malloc(PYI_BUF_SIZE)
|
||||
if pyi_buf is not None:
|
||||
pyi_buf[0] = 0
|
||||
pyi_pos: sizet = StubConverter._GeneratePyiFromAst(mb, tree, None, pyi_buf, PYI_BUF_SIZE)
|
||||
# rel_path 传 file_path(本文件绝对路径):vpi 生成期间 fatal_error
|
||||
# 的报错归因需指向本源文件(Phase A 预注册/翻译时 file_path 已可用),
|
||||
# 且绝对路径可被 fatal_error 的 _read_source_line 直接打开打印源码行。
|
||||
pyi_pos: sizet = StubConverter._GeneratePyiFromAst(mb, tree, file_path, pyi_buf, PYI_BUF_SIZE)
|
||||
if pyi_pos > 0:
|
||||
# 写入 {sha1}.vpi 到 temp_dir(切片路径)
|
||||
td_len_vpi: sizet = len(temp_dir)
|
||||
@@ -709,6 +712,37 @@ def collect_obj_files(includes_binary_dir: str, out_buf: bytes, out_size: sizet)
|
||||
return out_pos
|
||||
|
||||
|
||||
def _append_host_export_implib(linker_flags: str, implib_path: str) -> str:
|
||||
"""宿主导出模式:为链接参数追加 `--out-implib=<绝对路径>`(REPL 片段导入宿主用)
|
||||
|
||||
触发条件 = linker_flags 显式含 "--export-all-symbols"(工程级开关,宿主的
|
||||
project.vpj 里声明)。此时 exe 会带导出表,REPL 片段 DLL 需要一份 import lib
|
||||
才能把 IR 里的跨模块引用(形如 `<16位hex>.<函数名>`,见 .text.ll 的
|
||||
`define i32 @"<sha1>.utf8_is_valid"`)解析到宿主的导出符号。
|
||||
|
||||
为什么路径由本层计算而不写进 project.vpj:Config 对 linker.flags 既不做
|
||||
%VAR% 展开、也不按 project_dir 解析(Config.vpj:180-230 的 _join_flags_array
|
||||
只做拼接;:570-632 只重写 -T 后的脚本路径;env 展开只发生在 static_libs/
|
||||
dynamic_libs/includes/build_dir 等字段),而 out-implib 的值是相对
|
||||
clang 进程 cwd 解析的 ⇒ 只有本层能从 output_dir + linker_output 算出绝对路径。
|
||||
|
||||
未开启工程的 linker_flags 不含该标志 ⇒ 原样返回,链接命令逐字节不变。
|
||||
"""
|
||||
if linker_flags is None or implib_path is None:
|
||||
return linker_flags
|
||||
if string.strstr(linker_flags, "--export-all-symbols") is None:
|
||||
return linker_flags
|
||||
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")
|
||||
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")
|
||||
return buf
|
||||
|
||||
|
||||
def link_obj_to_exe(output_dir: str, module_name: str, linker_cmd: str, linker_flags: str, linker_output: str,
|
||||
includes_binary_dir: str, linker_static_libs: str = None, linker_dynamic_libs: str = None) -> int:
|
||||
"""调用 clang++ 链接 .obj 为 .exe
|
||||
@@ -734,6 +768,16 @@ def link_obj_to_exe(output_dir: str, module_name: str, linker_cmd: str, linker_f
|
||||
if obj_path is None:
|
||||
return 1
|
||||
|
||||
# 宿主 exe 导出(工程 linker.flags 含 --export-all-symbols 时)同步产出 import lib:
|
||||
# {output_dir}/{linker_output}.dll.a —— REPL 片段链接时把它加进命令行即可导入
|
||||
# 宿主(同一进程/同一份 includes 代码与数据)。未开启的工程不受影响。
|
||||
if linker_output is not None:
|
||||
implib_len: sizet = string.strlen(output_dir) + string.strlen(linker_output) + 8
|
||||
implib_path: str = _mbuddy.alloc(implib_len)
|
||||
if implib_path is not None:
|
||||
viperlib.snprintf(implib_path, implib_len, "%s/%s.dll.a", output_dir, linker_output)
|
||||
linker_flags = _append_host_export_implib(linker_flags, implib_path)
|
||||
|
||||
# 收集 includes.binary 的 .obj 文件路径
|
||||
EXTRA_BUF_SIZE: sizet = 32768
|
||||
extra_objs: bytes = _mbuddy.alloc(EXTRA_BUF_SIZE)
|
||||
@@ -988,6 +1032,13 @@ def link_objs_to_exe(obj_paths: str, obj_paths_len: sizet,
|
||||
# 构造命令: clang++ obj_paths extra_objs -o linker_output linker_flags
|
||||
# ASan 运行库同样不再由 TPV 注入(在 link_obj_to_exe 里已有说明):
|
||||
# 由 project.vpj 声明,--asan 下由 main.vp 校验。
|
||||
# 宿主导出:linker_output 是完整输出路径 ⇒ import lib 取名 <linker_output>.dll.a
|
||||
if linker_output is not None:
|
||||
implib_len2: sizet = string.strlen(linker_output) + 8
|
||||
implib_path2: str = _mbuddy.alloc(implib_len2)
|
||||
if implib_path2 is not None:
|
||||
viperlib.snprintf(implib_path2, implib_len2, "%s.dll.a", linker_output)
|
||||
linker_flags = _append_host_export_implib(linker_flags, implib_path2)
|
||||
use_flags: str = linker_flags
|
||||
static_libs2: str = linker_static_libs
|
||||
if static_libs2 is None:
|
||||
|
||||
@@ -1007,7 +1007,7 @@ def RunPhase1(mb: rawptr[memhub.MemBuddy], includes_dir: str, temp_dir: str,
|
||||
pyi_buf: bytes = stdlib.malloc(Phase1.PYI_BUF_SIZE)
|
||||
if pyi_buf is not None:
|
||||
pyi_pos: sizet = StubConverter._GeneratePyiFromAst(
|
||||
mb, tree, entry.RelPath, pyi_buf, Phase1.PYI_BUF_SIZE)
|
||||
mb, tree, entry.Path, pyi_buf, Phase1.PYI_BUF_SIZE)
|
||||
if pyi_pos > 0:
|
||||
pf_1b: rawptr[fileio.File] = fileio.File(vpi_path_1b, fileio.MODE.W)
|
||||
if not pf_1b.closed:
|
||||
|
||||
@@ -133,7 +133,7 @@ def _ScanClassInheritance(mb: rawptr[memhub.MemBuddy],
|
||||
continue
|
||||
|
||||
# 遍历 AST 顶层节点,收集 ClassDef
|
||||
ch: rawptr[list[rawptr[ast.AST]]] = tree.children
|
||||
ch: list[ast.AST*]* = tree.children
|
||||
if ch is not None:
|
||||
cn: sizet = len(ch)
|
||||
for ci in range(cn):
|
||||
@@ -305,7 +305,7 @@ def _PreRegisterAllGenericTemplates(mb: rawptr[memhub.MemBuddy],
|
||||
stdlib.free(src_buf_pg)
|
||||
continue
|
||||
# 遍历顶层 ClassDef,注册泛型模板(type_params 非 None)
|
||||
ch_pg: rawptr[list[rawptr[ast.AST]]] = tree_pg.children
|
||||
ch_pg: list[ast.AST*]* = tree_pg.children
|
||||
if ch_pg is not None:
|
||||
cn_pg: sizet = len(ch_pg)
|
||||
for ci_pg in range(cn_pg):
|
||||
@@ -405,13 +405,13 @@ def _ScanTreeForContainers(node: rawptr[ast.AST],
|
||||
elif k_s == ast.ASTKind.Call:
|
||||
cl_s2: rawptr[ast.Call] = rawptr[ast.Call](node)
|
||||
_ScanTreeForContainers(cl_s2.func, need_list_box, need_dict_box, depth + 1)
|
||||
cl_args_s: rawptr[list[rawptr[ast.AST]]] = cl_s2.args
|
||||
cl_args_s: list[ast.AST*]* = cl_s2.args
|
||||
if cl_args_s is not None:
|
||||
na_s: sizet = len(cl_args_s)
|
||||
i_a2: sizet
|
||||
for i_a2 in range(na_s):
|
||||
_ScanTreeForContainers(cl_args_s.get(i_a2), need_list_box, need_dict_box, depth + 1)
|
||||
cl_kws_s: rawptr[list[rawptr[ast.AST]]] = cl_s2.keywords
|
||||
cl_kws_s: list[ast.AST*]* = cl_s2.keywords
|
||||
if cl_kws_s is not None:
|
||||
nk_s: sizet = len(cl_kws_s)
|
||||
i_k2: sizet
|
||||
@@ -422,7 +422,7 @@ def _ScanTreeForContainers(node: rawptr[ast.AST],
|
||||
elif k_s == ast.ASTKind.Assign:
|
||||
asn_s: rawptr[ast.Assign] = rawptr[ast.Assign](node)
|
||||
_ScanTreeForContainers(asn_s.value, need_list_box, need_dict_box, depth + 1)
|
||||
tgts_s: rawptr[list[rawptr[ast.AST]]] = asn_s.targets
|
||||
tgts_s: list[ast.AST*]* = asn_s.targets
|
||||
if tgts_s is not None:
|
||||
nt_s: sizet = len(tgts_s)
|
||||
i_t2: sizet
|
||||
@@ -437,7 +437,7 @@ def _ScanTreeForContainers(node: rawptr[ast.AST],
|
||||
_ScanTreeForContainers(fn_s.returns, need_list_box, need_dict_box, depth + 1)
|
||||
fn_args_s: rawptr[ast.Arguments] = rawptr[ast.Arguments](fn_s.args)
|
||||
if fn_args_s is not None:
|
||||
fa_s: rawptr[list[rawptr[ast.AST]]] = fn_args_s.args
|
||||
fa_s: list[ast.AST*]* = fn_args_s.args
|
||||
if fa_s is not None:
|
||||
nf_s: sizet = len(fa_s)
|
||||
i_f2: sizet
|
||||
@@ -447,7 +447,7 @@ def _ScanTreeForContainers(node: rawptr[ast.AST],
|
||||
_ScanTreeForContainers(arg_s.annotation, need_list_box, need_dict_box, depth + 1)
|
||||
elif k_s == ast.ASTKind.ClassDef:
|
||||
cd_s: rawptr[ast.ClassDef] = rawptr[ast.ClassDef](node)
|
||||
bases_s: rawptr[list[rawptr[ast.AST]]] = cd_s.bases
|
||||
bases_s: list[ast.AST*]* = cd_s.bases
|
||||
if bases_s is not None:
|
||||
nb_s: sizet = len(bases_s)
|
||||
i_b2: sizet
|
||||
@@ -458,7 +458,7 @@ def _ScanTreeForContainers(node: rawptr[ast.AST],
|
||||
_ScanTreeForContainers(at_s.value, need_list_box, need_dict_box, depth + 1)
|
||||
elif k_s == ast.ASTKind.Tuple:
|
||||
tu_s: rawptr[ast.Tuple] = rawptr[ast.Tuple](node)
|
||||
elts_s: rawptr[list[rawptr[ast.AST]]] = tu_s.elts
|
||||
elts_s: list[ast.AST*]* = tu_s.elts
|
||||
if elts_s is not None:
|
||||
ne_s: sizet = len(elts_s)
|
||||
i_e2: sizet
|
||||
@@ -476,7 +476,7 @@ def _ScanTreeForContainers(node: rawptr[ast.AST],
|
||||
elif k_s == ast.ASTKind.Compare:
|
||||
cp_s: rawptr[ast.Compare] = rawptr[ast.Compare](node)
|
||||
_ScanTreeForContainers(cp_s.left, need_list_box, need_dict_box, depth + 1)
|
||||
cps_s: rawptr[list[rawptr[ast.AST]]] = cp_s.comparators
|
||||
cps_s: list[ast.AST*]* = cp_s.comparators
|
||||
if cps_s is not None:
|
||||
nc_s: sizet = len(cps_s)
|
||||
i_c2: sizet
|
||||
@@ -484,7 +484,7 @@ def _ScanTreeForContainers(node: rawptr[ast.AST],
|
||||
_ScanTreeForContainers(cps_s.get(i_c2), need_list_box, need_dict_box, depth + 1)
|
||||
elif k_s == ast.ASTKind.BoolOp:
|
||||
bo_s: rawptr[ast.BoolOp] = rawptr[ast.BoolOp](node)
|
||||
bvs_s: rawptr[list[rawptr[ast.AST]]] = bo_s.values
|
||||
bvs_s: list[ast.AST*]* = bo_s.values
|
||||
if bvs_s is not None:
|
||||
nv_s: sizet = len(bvs_s)
|
||||
i_v2: sizet
|
||||
@@ -498,7 +498,7 @@ def _ScanTreeForContainers(node: rawptr[ast.AST],
|
||||
# need_dict_box[0] = 1
|
||||
# 递归语句块子节点
|
||||
if node.children is not None:
|
||||
ch_s: rawptr[list[rawptr[ast.AST]]] = node.children
|
||||
ch_s: list[ast.AST*]* = node.children
|
||||
n_s: sizet = len(ch_s)
|
||||
ci_s: sizet
|
||||
for ci_s in range(n_s):
|
||||
|
||||
@@ -304,7 +304,7 @@ def _PreRegisterAppGenericTemplates(mb: rawptr[memhub.MemBuddy],
|
||||
stdlib.free(src_buf_pa)
|
||||
continue
|
||||
# 遍历顶层 ClassDef,注册泛型模板(type_params 非 None)
|
||||
ch_pa: rawptr[list[rawptr[ast.AST]]] = tree_pa.children
|
||||
ch_pa: list[ast.AST*]* = tree_pa.children
|
||||
if ch_pa is not None:
|
||||
cn_pa: sizet = len(ch_pa)
|
||||
for ci_pa in range(cn_pa):
|
||||
@@ -765,7 +765,8 @@ def RunMultiFileProject(mb: rawptr[memhub.MemBuddy],
|
||||
continue
|
||||
stdlib.free(vpi_path_vp2)
|
||||
# 读取源文件 → 解析 AST → 生成 vpi
|
||||
# (rel_path 传 None:与 TranslateFileGetTrans 后续覆盖写的内容一致)
|
||||
# (rel_path 传 ent_vp2.Path:vpi 内容不依赖它——与 TranslateFileGetTrans
|
||||
# 后续覆盖写的内容一致;此处仅用于 fatal_error 的报错归因,指向本源文件)
|
||||
f_vp2: rawptr[fileio.File] = fileio.File(ent_vp2.Path, fileio.MODE.R)
|
||||
if f_vp2.closed:
|
||||
vpi_failed_p2 += 1
|
||||
@@ -812,7 +813,7 @@ def RunMultiFileProject(mb: rawptr[memhub.MemBuddy],
|
||||
pyi_buf_vp2: bytes = stdlib.malloc(PYI_BUF_SIZE_P2)
|
||||
if pyi_buf_vp2 is not None:
|
||||
pyi_pos_vp2: sizet = StubConverter._GeneratePyiFromAst(
|
||||
mb, tree_vp2, None, pyi_buf_vp2, PYI_BUF_SIZE_P2)
|
||||
mb, tree_vp2, ent_vp2.Path, pyi_buf_vp2, PYI_BUF_SIZE_P2)
|
||||
if pyi_pos_vp2 > 0:
|
||||
pyi_path_vp2: str = StubMergerCollect._sliced_path(temp_dir, td_len_vpa, ent_vp2.Sha1, "vpi")
|
||||
if pyi_path_vp2 is not None:
|
||||
|
||||
@@ -241,9 +241,20 @@ def _join_path(rel: str, project_dir: str) -> str:
|
||||
|
||||
拼接结果经 _normalize_path 规范化:./Test/../includes → ./includes,
|
||||
消除 .. 段,保证路径显示干净且相对寻址正确。
|
||||
|
||||
含 %VAR% 的路径(如 repl.vpj 的 build_dir = %temp%/viperepl/.tpv_build)
|
||||
先经 fileio 路径层展开为实路径:TempDir/OutputDir 等由 BuildDir 派生,
|
||||
且后续消费者不止文件打开(ensure_dir 直接调 CreateDirectoryA、
|
||||
collect_obj_files 调 FindFirstFileA、命令串走 CreateProcessA),
|
||||
故展开必须发生在**配置路径设置层**而不是逐个调用点。
|
||||
"""
|
||||
if rel is None:
|
||||
return None
|
||||
# 环境变量展开:仅在含 '%' 时生效(fileio.ExpandEnvironmentPath 自带
|
||||
# "失败/无 '%' 返回 None" 契约),展开失败时保持原串不变
|
||||
ep: str = fileio.ExpandEnvironmentPath(rel)
|
||||
if ep is not None:
|
||||
rel = ep
|
||||
# 绝对路径(以 / 或 \ 开头)保持不变
|
||||
if rel[0] == '/' or rel[0] == '\\':
|
||||
return rel
|
||||
|
||||
@@ -202,11 +202,41 @@ def _PyiIndent(buf: bytes, buf_size: sizet, pos: sizet,
|
||||
return pos
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _PyiBinOpOpText - 输出二元运算符两侧的分隔文本
|
||||
#
|
||||
# 与 TPC StubGen/_GetTypeString 的 BinOp 运算符表逐字节一致(" | " / " + " /
|
||||
# " - " / " * " / " / " / " % " / " & " / " >> ")。支持集必须两侧相同,否则
|
||||
# 同一份源码写出的 .vpi 注解文本不同——旧实现恒写 " | ",使
|
||||
# zhuff.vp `t.CArray[zhuff_decode_node, 2 * ZHUFF_MAX_CODES]` 写成
|
||||
# `2 | ZHUFF_MAX_CODES`(读回端按位或算成 15,正确值 30 → 数组长度错)。
|
||||
# 表外运算符 fail-fast:静默写错运算符会生成错误的类型/长度文本,
|
||||
# 让下游按错误结果解析(与 TPC 落到未知节点 fail-fast 同语义)。
|
||||
# ============================================================
|
||||
def _PyiBinOpOpText(buf: bytes, buf_size: sizet, pos: sizet,
|
||||
op: int, node: rawptr[ast.AST]) -> sizet:
|
||||
"""按运算符种类输出 " OP " 文本,表外运算符 fail-fast"""
|
||||
if op == ast.OpKind.BitOr: return _PyiEmit(buf, buf_size, pos, " | ")
|
||||
if op == ast.OpKind.Add: return _PyiEmit(buf, buf_size, pos, " + ")
|
||||
if op == ast.OpKind.Sub: return _PyiEmit(buf, buf_size, pos, " - ")
|
||||
if op == ast.OpKind.Mult: return _PyiEmit(buf, buf_size, pos, " * ")
|
||||
if op == ast.OpKind.Div: return _PyiEmit(buf, buf_size, pos, " / ")
|
||||
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")
|
||||
return pos # 不可达(fatal_error 已退出)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _PyiTypeStr - 递归生成类型注解字符串
|
||||
#
|
||||
# 将 AST 类型注解节点转换为字符串表示,写入 buf 的 pos 位置。
|
||||
# 支持: Name, Attribute, Subscript, BinOp(|), Constant(前向引用), Tuple
|
||||
# 支持集与 TPC StubGen/_GetTypeString 等价:
|
||||
# Name, Attribute, Subscript, Tuple, BinOp, UnaryOp, Compare, BoolOp,
|
||||
# Constant, List, Call
|
||||
# 差异项:TPV 额外支持裸 Tuple(TPC 仅在 Subscript.slice 位置接受 Tuple);
|
||||
# TPC 额外有 Index 分支(vast 遗留类,解析器不产出该节点)。
|
||||
# ============================================================
|
||||
def _PyiTypeStr(buf: bytes, buf_size: sizet, pos: sizet,
|
||||
annot: rawptr[ast.AST],
|
||||
@@ -248,14 +278,77 @@ def _PyiTypeStr(buf: bytes, buf_size: sizet, pos: sizet,
|
||||
pos = _PyiEmit(buf, buf_size, pos, "]")
|
||||
return pos
|
||||
|
||||
# BinOp: 联合类型 (如 int | str, File | t.CPtr)
|
||||
# BinOp: 二元运算 (联合类型 int | str;CArray 计数表达式 MAX_ORDER + 1、
|
||||
# 2 * ZHUFF_MAX_CODES;条件宏实参 MASK_BYTE & 0x0F)。
|
||||
# 运算符文本按 _PyiBinOpOpText 输出,与 TPC 的运算符表逐字节一致。
|
||||
if k == ast.ASTKind.BinOp:
|
||||
bop: rawptr[ast.BinOp] = rawptr[ast.BinOp](annot)
|
||||
pos = _PyiTypeStr(buf, buf_size, pos, bop.left, depth + 1)
|
||||
pos = _PyiEmit(buf, buf_size, pos, " | ")
|
||||
pos = _PyiBinOpOpText(buf, buf_size, pos, bop.op, annot)
|
||||
pos = _PyiTypeStr(buf, buf_size, pos, bop.right, depth + 1)
|
||||
return pos
|
||||
|
||||
# UnaryOp: 一元运算 (计数表达式 -1 / ~0;条件宏实参 not ct.isptr(x))。
|
||||
# 输出与 TPC 的 UnaryOp 分支逐字节一致:Not → "not "、Invert → "~"、
|
||||
# USub → "-";其余一元运算符两侧都不支持 → fail-fast(不静默写错符号)。
|
||||
if k == ast.ASTKind.UnaryOp:
|
||||
uop_t: rawptr[ast.UnaryOp] = rawptr[ast.UnaryOp](annot)
|
||||
if uop_t.op == ast.OpKind.Not:
|
||||
pos = _PyiEmit(buf, buf_size, pos, "not ")
|
||||
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")
|
||||
return pos # 不可达(fatal_error 已退出)
|
||||
return _PyiTypeStr(buf, buf_size, pos, uop_t.operand, depth + 1)
|
||||
|
||||
# Compare: 比较表达式 (条件宏实参 MAX_SIZE > 512 / val == 1)。
|
||||
# 运算符文本与 TPC 的 Compare 分支逐字节一致:== != < <= > >=;
|
||||
# 表外运算符(is/in 等)两侧一致输出 " ? "。
|
||||
if k == ast.ASTKind.Compare:
|
||||
cmp_t: rawptr[ast.Compare] = rawptr[ast.Compare](annot)
|
||||
pos = _PyiTypeStr(buf, buf_size, pos, cmp_t.left, depth + 1)
|
||||
ops_ct: list[int] | t.CPtr = (list[int] | t.CPtr)(cmp_t.ops)
|
||||
cmps_ct: list[ast.AST*]* = cmp_t.comparators
|
||||
if ops_ct is not None:
|
||||
on_ct: sizet = len(ops_ct)
|
||||
oi_ct: sizet = 0
|
||||
while oi_ct < on_ct:
|
||||
oid_ct: int = ops_ct.get(oi_ct)
|
||||
if oid_ct == ast.OpKind.Eq: pos = _PyiEmit(buf, buf_size, pos, " == ")
|
||||
elif oid_ct == ast.OpKind.Ne: pos = _PyiEmit(buf, buf_size, pos, " != ")
|
||||
elif oid_ct == ast.OpKind.Lt: pos = _PyiEmit(buf, buf_size, pos, " < ")
|
||||
elif oid_ct == ast.OpKind.Le: pos = _PyiEmit(buf, buf_size, pos, " <= ")
|
||||
elif oid_ct == ast.OpKind.Gt: pos = _PyiEmit(buf, buf_size, pos, " > ")
|
||||
elif oid_ct == ast.OpKind.Ge: pos = _PyiEmit(buf, buf_size, pos, " >= ")
|
||||
else: pos = _PyiEmit(buf, buf_size, pos, " ? ")
|
||||
# TPC 按 ops 的下标取 comparators[i];此处加长度守卫,
|
||||
# 畸形 AST(ops/comparators 不等长)不越界。
|
||||
if cmps_ct is not None and oi_ct < len(cmps_ct):
|
||||
pos = _PyiTypeStr(buf, buf_size, pos, cmps_ct.get(oi_ct), depth + 1)
|
||||
oi_ct += 1
|
||||
return pos
|
||||
|
||||
# BoolOp: 布尔运算 (条件宏实参 ENABLED and MAX_SIZE > 0 / A or B)。
|
||||
# 与 TPC 的 BoolOp 分支一致:and → " and "、or → " or "。
|
||||
if k == ast.ASTKind.BoolOp:
|
||||
bool_t: rawptr[ast.BoolOp] = rawptr[ast.BoolOp](annot)
|
||||
vals_bt: list[ast.AST*]* = bool_t.values
|
||||
if vals_bt is not None:
|
||||
vn_bt: sizet = len(vals_bt)
|
||||
vi_bt: sizet = 0
|
||||
while vi_bt < vn_bt:
|
||||
if vi_bt > 0:
|
||||
if bool_t.op == ast.OpKind.Or:
|
||||
pos = _PyiEmit(buf, buf_size, pos, " or ")
|
||||
else:
|
||||
pos = _PyiEmit(buf, buf_size, pos, " and ")
|
||||
pos = _PyiTypeStr(buf, buf_size, pos, vals_bt.get(vi_bt), depth + 1)
|
||||
vi_bt += 1
|
||||
return pos
|
||||
|
||||
# Constant: 字符串前向引用 (如 'MyClass')、None 或数字常量(CArray count)
|
||||
if k == ast.ASTKind.Constant:
|
||||
cn: rawptr[ast.Constant] = rawptr[ast.Constant](annot)
|
||||
@@ -280,11 +373,31 @@ def _PyiTypeStr(buf: bytes, buf_size: sizet, pos: sizet,
|
||||
return pos
|
||||
return _PyiEmit(buf, buf_size, pos, "int")
|
||||
|
||||
# List: 函数指针参数表 (如 t.Callable[[t.CPtr, ULONG], BOOL] 的内层
|
||||
# [t.CPtr, ULONG];t.Callable[[], int] 的空表)。TPV 的 AST 把 Callable
|
||||
# 的参数表成型为 List(TypeGenResolve 的类型名提取同样按 List 递归),
|
||||
# 故必须输出 "[a, b]" 形式——缺失该分支时该节点落入未知类型 fail-fast。
|
||||
if k == ast.ASTKind.List:
|
||||
lst: rawptr[ast.List] = rawptr[ast.List](annot)
|
||||
pos = _PyiEmit(buf, buf_size, pos, "[")
|
||||
if lst.elts is not None:
|
||||
lst_elts: list[ast.AST*]* = lst.elts
|
||||
ln: sizet = len(lst_elts)
|
||||
li: sizet = 0
|
||||
while li < ln:
|
||||
if li > 0:
|
||||
pos = _PyiEmit(buf, buf_size, pos, ", ")
|
||||
le: rawptr[ast.AST] = lst_elts.get(li)
|
||||
pos = _PyiTypeStr(buf, buf_size, pos, le, depth + 1)
|
||||
li += 1
|
||||
pos = _PyiEmit(buf, buf_size, pos, "]")
|
||||
return pos
|
||||
|
||||
# Tuple: 多参数下标 (如 Dict[str, int])
|
||||
if k == ast.ASTKind.Tuple:
|
||||
tup: rawptr[ast.Tuple] = rawptr[ast.Tuple](annot)
|
||||
if tup.elts is not None:
|
||||
tup_elts: rawptr[list[rawptr[ast.AST]]] = tup.elts
|
||||
tup_elts: list[ast.AST*]* = tup.elts
|
||||
tn: sizet = len(tup_elts)
|
||||
ti: sizet = 0
|
||||
while ti < tn:
|
||||
@@ -301,7 +414,7 @@ def _PyiTypeStr(buf: bytes, buf_size: sizet, pos: sizet,
|
||||
pos = _PyiTypeStr(buf, buf_size, pos, cl.func, depth + 1)
|
||||
pos = _PyiEmit(buf, buf_size, pos, "(")
|
||||
if cl.args is not None:
|
||||
cl_args: rawptr[list[rawptr[ast.AST]]] = cl.args
|
||||
cl_args: list[ast.AST*]* = cl.args
|
||||
can: sizet = len(cl_args)
|
||||
cai: sizet = 0
|
||||
while cai < can:
|
||||
@@ -395,7 +508,7 @@ def _PyiDefaultStr(buf: bytes, buf_size: sizet, pos: sizet,
|
||||
# 据此合成 `-> tuple[a, b, c]`(tuple 分支同样打包成 Struct),使 stub declare 与 define 的返回类型一致。
|
||||
# 返回 None = 装饰器列表里没有 CReturn。
|
||||
# ============================================================
|
||||
def _PyiCreturnArgs(decorators: rawptr[list[rawptr[ast.AST]]]) -> rawptr[list[rawptr[ast.AST]]]:
|
||||
def _PyiCreturnArgs(decorators: list[ast.AST*]*) -> list[ast.AST*]*:
|
||||
"""在装饰器列表里找 @c.CReturn(...),返回其实参列表;未找到返回 None"""
|
||||
if decorators is None:
|
||||
return None
|
||||
@@ -426,7 +539,7 @@ def _PyiFunction(buf: bytes, buf_size: sizet, pos: sizet,
|
||||
"""生成函数签名到 buf,返回新的 pos"""
|
||||
# 装饰器
|
||||
if fn.decorator_list is not None:
|
||||
fn_decorator_list: rawptr[list[rawptr[ast.AST]]] = fn.decorator_list
|
||||
fn_decorator_list: list[ast.AST*]* = fn.decorator_list
|
||||
dn: sizet = len(fn_decorator_list)
|
||||
di: sizet = 0
|
||||
while di < dn:
|
||||
@@ -452,12 +565,12 @@ def _PyiFunction(buf: bytes, buf_size: sizet, pos: sizet,
|
||||
|
||||
# 位置参数
|
||||
if args.args is not None:
|
||||
args_args: rawptr[list[rawptr[ast.AST]]] = args.args
|
||||
args_args: list[ast.AST*]* = args.args
|
||||
an: sizet = len(args_args)
|
||||
# 默认值右对齐到 args 尾部:defaults[i] 对应 args[an - dn + i]。
|
||||
# 必须输出 '= <default>',否则 VpiReader 解析出的默认参数表无条目,跨模块缺参调用(如 depth=0)读到栈垃圾。
|
||||
# arg_defaults 必须内联声明:联合接收者的 .get 会被误分派,预声明 + 重赋值会解析成 list[int].get 返回 i32 截断指针而崩溃。
|
||||
arg_defaults: rawptr[list[rawptr[ast.AST]]] = args.defaults
|
||||
arg_defaults: list[ast.AST*]* = args.defaults
|
||||
dn: sizet = 0
|
||||
if arg_defaults is not None:
|
||||
dn = len(arg_defaults)
|
||||
@@ -508,7 +621,7 @@ def _PyiFunction(buf: bytes, buf_size: sizet, pos: sizet,
|
||||
pos = _PyiTypeStr(buf, buf_size, pos, fn.returns)
|
||||
else:
|
||||
# 无 `->` 注解但带 @c.CReturn(...):合成 " -> tuple[a, b, c]"(N11)
|
||||
cre_args: rawptr[list[rawptr[ast.AST]]] = _PyiCreturnArgs(fn.decorator_list)
|
||||
cre_args: list[ast.AST*]* = _PyiCreturnArgs(fn.decorator_list)
|
||||
if cre_args is not None:
|
||||
cre_n: sizet = len(cre_args)
|
||||
if cre_n > 0:
|
||||
@@ -538,7 +651,7 @@ def _PyiClass(buf: bytes, buf_size: sizet, pos: sizet,
|
||||
"""生成类定义到 buf,返回新的 pos"""
|
||||
# 装饰器
|
||||
if cls.decorator_list is not None:
|
||||
cls_decorator_list: rawptr[list[rawptr[ast.AST]]] = cls.decorator_list
|
||||
cls_decorator_list: list[ast.AST*]* = cls.decorator_list
|
||||
dcn: sizet = len(cls_decorator_list)
|
||||
dci: sizet = 0
|
||||
while dci < dcn:
|
||||
@@ -557,7 +670,7 @@ def _PyiClass(buf: bytes, buf_size: sizet, pos: sizet,
|
||||
|
||||
# PEP 695 类型参数 (class Foo[T]:)
|
||||
if cls.type_params is not None:
|
||||
cls_type_params: rawptr[list[rawptr[ast.AST]]] = cls.type_params
|
||||
cls_type_params: list[ast.AST*]* = cls.type_params
|
||||
tpn: sizet = len(cls_type_params)
|
||||
if tpn > 0:
|
||||
pos = _PyiEmit(buf, buf_size, pos, "[")
|
||||
@@ -573,7 +686,7 @@ def _PyiClass(buf: bytes, buf_size: sizet, pos: sizet,
|
||||
|
||||
# 基类
|
||||
if cls.bases is not None:
|
||||
cls_bases: rawptr[list[rawptr[ast.AST]]] = cls.bases
|
||||
cls_bases: list[ast.AST*]* = cls.bases
|
||||
bn: sizet = len(cls_bases)
|
||||
if bn > 0:
|
||||
pos = _PyiEmit(buf, buf_size, pos, "(")
|
||||
@@ -592,7 +705,7 @@ def _PyiClass(buf: bytes, buf_size: sizet, pos: sizet,
|
||||
has_member: int = 0
|
||||
|
||||
if cls.children is not None:
|
||||
cls_children: rawptr[list[rawptr[ast.AST]]] = cls.children
|
||||
cls_children: list[ast.AST*]* = cls.children
|
||||
cn: sizet = len(cls_children)
|
||||
ci: sizet = 0
|
||||
while ci < cn:
|
||||
@@ -606,7 +719,7 @@ def _PyiClass(buf: bytes, buf_size: sizet, pos: sizet,
|
||||
# __init__ 方法:先提取 self.x: Type 属性
|
||||
if mfn.name is not None and string.strcmp(mfn.name, "__init__") == 0:
|
||||
if mfn.children is not None:
|
||||
mfn_children: rawptr[list[rawptr[ast.AST]]] = mfn.children
|
||||
mfn_children: list[ast.AST*]* = mfn.children
|
||||
icn: sizet = len(mfn_children)
|
||||
ici: sizet = 0
|
||||
while ici < icn:
|
||||
@@ -663,7 +776,7 @@ def _PyiClass(buf: bytes, buf_size: sizet, pos: sizet,
|
||||
# ============================================================
|
||||
# _GeneratePyiFromAst - 遍历 AST Module 节点,提取函数签名/类定义/变量声明/import 语句,生成 .vpi 存根文件内容到 buf
|
||||
#
|
||||
# Args: mb 内存池(保留以符合调用约定,实际未使用);tree AST Module 根节点;rel_path 相对路径(用于模块名,当前未使用);buf 输出缓冲区;buf_size 缓冲区大小
|
||||
# Args: mb 内存池(保留以符合调用约定,实际未使用);tree AST Module 根节点;rel_path 源文件路径(仅用于报错归因的"当前文件",应传绝对路径以便 fatal_error 读取源码行);buf 输出缓冲区;buf_size 缓冲区大小
|
||||
# Returns: 写入的字节数(0 表示失败)
|
||||
# ============================================================
|
||||
def _GeneratePyiFromAst(mb: rawptr[memhub.MemBuddy], tree: rawptr[ast.AST],
|
||||
@@ -673,13 +786,25 @@ def _GeneratePyiFromAst(mb: rawptr[memhub.MemBuddy], tree: rawptr[ast.AST],
|
||||
if tree is None or buf is None or buf_size == 0:
|
||||
return 0
|
||||
|
||||
# 错误归因:把"当前文件"指向正在生成 stub 的这份(rel_path 非 None 时)。
|
||||
# 本函数内触发的 fatal_error(如 L227/L303/L430 的注解节点类型未知)应指向
|
||||
# 本源文件,而非上一次 set_current_file 的残留文件。
|
||||
# 调用侧必须传**绝对路径**:fatal_error 的 _read_source_line 直接用该路径
|
||||
# 打开文件读取行,传相对路径会打不开 ⇒ 误报"无法读取该行源码"。
|
||||
# 放在函数入口而非各分支:全函数共用同一套遍历/报错路径,逐分支设置会漏掉
|
||||
# 中途新增的分支;入口设一次覆盖全部(含后续所有 fatal_error / push_trace)。
|
||||
# rel_path 为 None 时不改写 CurrentFile(保持上一次设置值):调用侧确实拿不到
|
||||
# 路径时,宁可沿用"上一次设置的文件"也不要把归因抹成 None。
|
||||
if rel_path is not None:
|
||||
GenApi.set_current_file_type(rel_path)
|
||||
|
||||
pos: sizet = 0
|
||||
|
||||
# 预处理:按声明顺序注册本文件 CDefine 到 _g_pyi 缓存(vpi 生成早于翻译阶段注册,直接查全局表为空会使 BinOp 内 Name 引用退化为 0,跨模块读回错误常量)。
|
||||
# 必须带 global 声明:TPV 语义下函数内对模块级变量赋值无 global 时会创建局部变量,_lookup_cdefine_for_pyi 读到的仍是模块级 None,缓存永不命中。
|
||||
global _g_pyi_cdef_names, _g_pyi_cdef_vals, _g_pyi_cdef_count
|
||||
if tree.children is not None:
|
||||
pre_children: rawptr[list[rawptr[ast.AST]]] = tree.children
|
||||
pre_children: list[ast.AST*]* = tree.children
|
||||
pcn: sizet = len(pre_children)
|
||||
# 第一遍:数本文件 t.CDefine 声明数(C 数组需先定长分配)
|
||||
_g_pyi_cdef_count = 0
|
||||
@@ -724,7 +849,7 @@ def _GeneratePyiFromAst(mb: rawptr[memhub.MemBuddy], tree: rawptr[ast.AST],
|
||||
buf[pos] = 0
|
||||
return pos
|
||||
|
||||
tree_children: rawptr[list[rawptr[ast.AST]]] = tree.children
|
||||
tree_children: list[ast.AST*]* = tree.children
|
||||
n: sizet = len(tree_children)
|
||||
|
||||
# 第一遍扫描:检测 import t/c
|
||||
@@ -735,7 +860,7 @@ def _GeneratePyiFromAst(mb: rawptr[memhub.MemBuddy], tree: rawptr[ast.AST],
|
||||
if stmt is not None and stmt.kind() == ast.ASTKind.Import:
|
||||
imp: rawptr[ast.Import] = rawptr[ast.Import](stmt)
|
||||
if imp.names is not None:
|
||||
imp_names: rawptr[list[rawptr[ast.AST]]] = imp.names
|
||||
imp_names: list[ast.AST*]* = imp.names
|
||||
an: sizet = len(imp_names)
|
||||
for ai in range(an):
|
||||
al: rawptr[ast.Alias] = rawptr[ast.Alias](imp_names.get(ai))
|
||||
@@ -766,7 +891,7 @@ def _GeneratePyiFromAst(mb: rawptr[memhub.MemBuddy], tree: rawptr[ast.AST],
|
||||
imp2: rawptr[ast.Import] = rawptr[ast.Import](stmt)
|
||||
pos = _PyiEmit(buf, buf_size, pos, "import ")
|
||||
if imp2.names is not None:
|
||||
imp2_names: rawptr[list[rawptr[ast.AST]]] = imp2.names
|
||||
imp2_names: list[ast.AST*]* = imp2.names
|
||||
an2: sizet = len(imp2_names)
|
||||
ai2: sizet = 0
|
||||
while ai2 < an2:
|
||||
@@ -793,7 +918,7 @@ def _GeneratePyiFromAst(mb: rawptr[memhub.MemBuddy], tree: rawptr[ast.AST],
|
||||
pos = _PyiEmit(buf, buf_size, pos, ifr.module)
|
||||
pos = _PyiEmit(buf, buf_size, pos, " import ")
|
||||
if ifr.names is not None:
|
||||
ifr_names: rawptr[list[rawptr[ast.AST]]] = ifr.names
|
||||
ifr_names: list[ast.AST*]* = ifr.names
|
||||
an3: sizet = len(ifr_names)
|
||||
ai3: sizet = 0
|
||||
while ai3 < an3:
|
||||
@@ -884,7 +1009,7 @@ def _GeneratePyiFromAst(mb: rawptr[memhub.MemBuddy], tree: rawptr[ast.AST],
|
||||
# 提取第一个参数的整数值并输出
|
||||
call_cv: rawptr[ast.Call] = rawptr[ast.Call](aa.value)
|
||||
if call_cv.args is not None:
|
||||
call_args_cv: rawptr[list[rawptr[ast.AST]]] = call_cv.args
|
||||
call_args_cv: list[ast.AST*]* = call_cv.args
|
||||
if len(call_args_cv) > 0:
|
||||
first_arg: rawptr[ast.AST] = call_args_cv.get(0)
|
||||
if first_arg is not None:
|
||||
@@ -952,7 +1077,7 @@ def _GeneratePyiFromAst(mb: rawptr[memhub.MemBuddy], tree: rawptr[ast.AST],
|
||||
elif k == ast.ASTKind.Assign:
|
||||
asg: rawptr[ast.Assign] = rawptr[ast.Assign](stmt)
|
||||
if asg.targets is not None and asg.value is not None:
|
||||
asg_targets: rawptr[list[rawptr[ast.AST]]] = asg.targets
|
||||
asg_targets: list[ast.AST*]* = asg.targets
|
||||
atn: sizet = len(asg_targets)
|
||||
if atn == 1:
|
||||
atg: rawptr[ast.AST] = asg_targets.get(0)
|
||||
|
||||
+1163
-15
File diff suppressed because it is too large.
Load diff
@@ -269,6 +269,83 @@ def GetSha1StoreCount() -> int:
|
||||
def LookupSha1ByModName(mod_name: str) -> str:
|
||||
"""从模块名查找 SHA1(精确匹配 + 包名回退),委托通用实现 _FindSha1ByModName"""
|
||||
return StubMergerIR._FindSha1ByModName(StubMerger._sha1_store_arr, StubMerger._sha1_store_mod, StubMerger._sha1_store_count, mod_name)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 泛型类归属表(泛型类名 → 定义模块 SHA1)——仅 REPL 会话登记/查询
|
||||
#
|
||||
# 为什么需要:REPL 的 includes 会话初始化只注入 `.vpi` 的类(泛型类被跳过),
|
||||
# 不跑批处理的 _PreRegister*GenericTemplates ⇒ 会话内泛型模板表为空 ⇒ 注解里的
|
||||
# `list[rawptr[AST]]` 等泛型下标解析(`TypeGenResolve._resolve_generic_subscript_ty`)
|
||||
# 恒 miss。会话侧的最后兜底要按**定义侧特化命名** "%{模板模块 sha1}.{mangled}"
|
||||
# 造 opaque 具名类型(实证:`%"b56d2f995104690d.list[rawptr[AST]]"`),因此需要
|
||||
# "泛型类定义在哪个模块"这一事实——由注入期扫 `.vpi` 的 ClassDef 登记(见
|
||||
# VpiReader._repl_stub_collect_module)。
|
||||
#
|
||||
# 归属模块 sha1 无法从类名反推(模块名取自文件路径,class list ← _list.vp;用户
|
||||
# 泛型类更是名字与模块名无关),故必须显式登记,不做"按名字猜"。
|
||||
# 批处理不登记(表恒空 ⇒ 查询恒 None ⇒ 批处理路径一字不改)。
|
||||
# 容量:includes 现有 6 个泛型类定义(list/dict 系 + Vector/GSList/ndarray),取 32 槽。
|
||||
# ============================================================
|
||||
GENERIC_OWNER_MAX: t.CDefine = 32
|
||||
_generic_owner_names: bytes = None
|
||||
_generic_owner_sha1s: bytes = None
|
||||
_generic_owner_count: int = 0
|
||||
|
||||
|
||||
def ResetGenericOwners() -> None:
|
||||
"""清空泛型类归属表(REPL 会话初始化开始时调用一次)"""
|
||||
global _generic_owner_names, _generic_owner_sha1s, _generic_owner_count
|
||||
if _generic_owner_names is not None:
|
||||
stdlib.free(_generic_owner_names)
|
||||
_generic_owner_names = None
|
||||
if _generic_owner_sha1s is not None:
|
||||
stdlib.free(_generic_owner_sha1s)
|
||||
_generic_owner_sha1s = None
|
||||
_generic_owner_count = 0
|
||||
|
||||
|
||||
def RegisterGenericOwner(cls_name: str, mod_sha1: str) -> int:
|
||||
"""登记"泛型类名 → 定义模块 SHA1";1=已登记(含重复)/ 0=失败(参数/满/同名异 sha1)
|
||||
|
||||
同名异 sha1(跨模块同名泛型类)保留首个,与泛型模板表按类名去重的口径一致。
|
||||
"""
|
||||
global _generic_owner_names, _generic_owner_sha1s, _generic_owner_count
|
||||
if cls_name is None or mod_sha1 is None:
|
||||
return 0
|
||||
if cls_name[0] == '\0' or mod_sha1[0] == '\0':
|
||||
return 0
|
||||
if _generic_owner_names is None:
|
||||
_generic_owner_names = stdlib.malloc(GENERIC_OWNER_MAX * 64)
|
||||
_generic_owner_sha1s = stdlib.malloc(GENERIC_OWNER_MAX * 17)
|
||||
if _generic_owner_names is None or _generic_owner_sha1s is None:
|
||||
return 0
|
||||
string.memset(_generic_owner_names, 0, GENERIC_OWNER_MAX * 64)
|
||||
string.memset(_generic_owner_sha1s, 0, GENERIC_OWNER_MAX * 17)
|
||||
_generic_owner_count = 0
|
||||
i_go: int
|
||||
for i_go in range(_generic_owner_count):
|
||||
if string.strcmp(_generic_owner_names + sizet(i_go) * 64, cls_name) == 0:
|
||||
if string.strcmp(_generic_owner_sha1s + sizet(i_go) * 17, mod_sha1) == 0:
|
||||
return 1
|
||||
return 0
|
||||
if _generic_owner_count >= GENERIC_OWNER_MAX:
|
||||
return 0
|
||||
string.strncpy(_generic_owner_names + sizet(_generic_owner_count) * 64, cls_name, 63)
|
||||
string.strncpy(_generic_owner_sha1s + sizet(_generic_owner_count) * 17, mod_sha1, 16)
|
||||
_generic_owner_count += 1
|
||||
return 1
|
||||
|
||||
|
||||
def LookupGenericOwnerSha1(cls_name: str) -> str:
|
||||
"""按泛型类名取定义模块 SHA1(返回内部指针,无需释放;未登记 None)"""
|
||||
if cls_name is None or _generic_owner_names is None:
|
||||
return None
|
||||
i_lg: int
|
||||
for i_lg in range(_generic_owner_count):
|
||||
if string.strcmp(_generic_owner_names + sizet(i_lg) * 64, cls_name) == 0:
|
||||
return _generic_owner_sha1s + sizet(i_lg) * 17
|
||||
return None
|
||||
# ============================================================
|
||||
# LookupSha1ByModNameSuffix - 后缀匹配查找模块 SHA1(用于 from .X import Y:impf.module 是 ".X",而映射表键是 "pkg.X")
|
||||
#
|
||||
|
||||
@@ -125,7 +125,7 @@ class AssignGenMixin:
|
||||
cl: rawptr[ast.Call] = rawptr[ast.Call](val_node)
|
||||
# 必须先把属性赋给显式类型为 list[...] | t.CPtr 的局部变量再调用 __len__(),
|
||||
# 否则编译器无法识别属性返回的 list 类型,GEP base 会变成 i32 0 导致 llc 报错
|
||||
cl_args_list: rawptr[list[rawptr[ast.AST]]] = cl.args
|
||||
cl_args_list: list[ast.AST*]* = cl.args
|
||||
if cl_args_list is not None and len(cl_args_list) > 0:
|
||||
first_arg: rawptr[ast.AST] = cl_args_list.get(0)
|
||||
arg_val: int64 = self.extract_cdefine_int_value(first_arg)
|
||||
@@ -167,7 +167,7 @@ class AssignGenMixin:
|
||||
if val_node is not None and val_node.kind() == ast.ASTKind.Call:
|
||||
cl_cd: rawptr[ast.Call] = rawptr[ast.Call](val_node)
|
||||
if cl_cd is not None and cl_cd.args is not None:
|
||||
cl_args_cd: rawptr[list[rawptr[ast.AST]]] = cl_cd.args
|
||||
cl_args_cd: list[ast.AST*]* = cl_cd.args
|
||||
if len(cl_args_cd) > 0:
|
||||
first_arg_cd: rawptr[ast.AST] = cl_args_cd.get(0)
|
||||
if first_arg_cd is not None and first_arg_cd.kind() == ast.ASTKind.Constant:
|
||||
@@ -640,7 +640,7 @@ class AssignGenMixin:
|
||||
lst: rawptr[ast.List] = rawptr[ast.List](list_node)
|
||||
if lst is None or lst.elts is None:
|
||||
return 1
|
||||
elts: rawptr[list[rawptr[ast.AST]]] = lst.elts
|
||||
elts: list[ast.AST*]* = lst.elts
|
||||
elts_count: sizet = len(elts)
|
||||
|
||||
# 特例:单个字符串字面量初始化字符数组([N x i8],N = strlen+1)
|
||||
@@ -839,8 +839,17 @@ class AssignGenMixin:
|
||||
if target_ty is None:
|
||||
# fail-fast: 字段类型信息缺失,禁止兜底 i32
|
||||
self.Gen.TypeGenErr.fatal_error(target, "字段类型信息缺失", "TypeError")
|
||||
# t.CVolatile 字段:+= 的 load 与 store 均带 volatile 限定符
|
||||
vol_fa: int = self.Gen.ExprGenAttr.attr_field_is_volatile(pool, trans, target)
|
||||
# rawptr[t.CVolatile|T] 基址(volatile 指针指向物):经其访问的
|
||||
# 字段 += 的 load/store 亦带 volatile(两来源取或)。
|
||||
at_aug: rawptr[ast.Attribute] = rawptr[ast.Attribute](target)
|
||||
if at_aug is not None:
|
||||
if self.Gen.ExprGenAttr.base_pointee_is_volatile(
|
||||
pool, trans, at_aug.value) != 0:
|
||||
vol_fa = 1
|
||||
cur_val: rawptr[llvmlite.Value] = llvmlite.build_load(
|
||||
builder, target_ty, field_ptr)
|
||||
builder, target_ty, field_ptr, vol_fa)
|
||||
if cur_val is None:
|
||||
# fail-fast: 属性当前值加载失败
|
||||
self.Gen.TypeGenErr.fatal_error(target, "无法加载 attribute 当前值", "TypeError")
|
||||
@@ -864,7 +873,7 @@ class AssignGenMixin:
|
||||
if result is None:
|
||||
# fail-fast: 类型对齐失败
|
||||
self.Gen.TypeGenErr.fatal_error(target, "类型对齐失败", "TypeError")
|
||||
llvmlite.build_store(builder, result, field_ptr)
|
||||
llvmlite.build_store(builder, result, field_ptr, vol_fa)
|
||||
return 0
|
||||
|
||||
# Subscript 目标: self.state[i] += x / arr[i] += x
|
||||
@@ -888,8 +897,15 @@ class AssignGenMixin:
|
||||
if target_ty is None:
|
||||
# fail-fast: 元素类型信息缺失,禁止兜底 i32
|
||||
self.Gen.TypeGenErr.fatal_error(target, "元素类型信息缺失", "TypeError")
|
||||
# rawptr[t.CVolatile|T] 基址(volatile 指针指向物):p[i] += 的
|
||||
# load/store 均带 volatile。仅基址可解析到 VarEntry/FieldEntry 时为 1。
|
||||
vol_sa: int = 0
|
||||
sub_aug: rawptr[ast.Subscript] = rawptr[ast.Subscript](target)
|
||||
if sub_aug is not None:
|
||||
vol_sa = self.Gen.ExprGenAttr.base_pointee_is_volatile(
|
||||
pool, trans, sub_aug.value)
|
||||
cur_val: rawptr[llvmlite.Value] = llvmlite.build_load(
|
||||
builder, target_ty, elem_ptr)
|
||||
builder, target_ty, elem_ptr, vol_sa)
|
||||
if cur_val is None:
|
||||
# fail-fast: 元素当前值加载失败
|
||||
self.Gen.TypeGenErr.fatal_error(target, "无法加载 subscript 元素当前值", "TypeError")
|
||||
@@ -913,7 +929,7 @@ class AssignGenMixin:
|
||||
if result is None:
|
||||
# fail-fast: 类型对齐失败
|
||||
self.Gen.TypeGenErr.fatal_error(target, "类型对齐失败", "TypeError")
|
||||
llvmlite.build_store(builder, result, elem_ptr)
|
||||
llvmlite.build_store(builder, result, elem_ptr, vol_sa)
|
||||
return 0
|
||||
|
||||
if tk != ast.ASTKind.Name:
|
||||
@@ -925,6 +941,17 @@ class AssignGenMixin:
|
||||
if nm is None or nm.id is None:
|
||||
return 0
|
||||
|
||||
# REPL 模式(M2/M3)会话变量增强赋值:读槽 → 二元运算 → 写槽 → 写结果区。
|
||||
# 未登记的会话名返回 0(继续原路径 → 明确的"无法加载…当前值"报错)。
|
||||
# 守卫 trans.ReplCtx:非 REPL 恒 None ⇒ 本分支整体不经过。
|
||||
# 作用域用 repl_in_frag_entry_scope(M3):被提升的会话函数体内 `x += 1`
|
||||
# 按普通局部变量路径处理(不写会话槽)。
|
||||
if trans.ReplCtx is not None \
|
||||
and self.Gen.VarGen.repl_in_frag_entry_scope(trans) != 0:
|
||||
if self.Gen.VarGen.repl_try_augassign(
|
||||
trans, nm.id, aug.op, aug.value, node) != 0:
|
||||
return 0
|
||||
|
||||
pool: rawptr[memhub.MemBuddy] = trans.Pool
|
||||
builder: rawptr[llvmlite.IRBuilder] = trans._cur_builder
|
||||
mod: rawptr[llvmlite.LLVMModule] = trans.Module
|
||||
@@ -936,6 +963,10 @@ class AssignGenMixin:
|
||||
elif GenApi.is_nonlocal_name(trans, nm.id) != 0:
|
||||
scope_type = 2
|
||||
|
||||
# t.CVolatile 变量:+= 的 load 与 store 均带 volatile 限定符
|
||||
vol_aa: int = self.Gen.VarGen.var_is_volatile(
|
||||
self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm.id))
|
||||
|
||||
# 2. 加载当前值
|
||||
cur_val: rawptr[llvmlite.Value] = None
|
||||
target_alloca: rawptr[llvmlite.Value] = None
|
||||
@@ -949,7 +980,7 @@ class AssignGenMixin:
|
||||
# fail-fast: 变量类型信息缺失,禁止兜底 i32
|
||||
self.Gen.TypeGenErr.fatal_error(target, "变量类型信息缺失", "TypeError")
|
||||
target_ty = target_alloca.Ty.Pointee
|
||||
cur_val = llvmlite.build_load(builder, target_ty, target_alloca)
|
||||
cur_val = llvmlite.build_load(builder, target_ty, target_alloca, vol_aa)
|
||||
elif scope_type == 2:
|
||||
# nonlocal 变量(通过闭包 env)
|
||||
cur_val = self.Gen.StmtGenDecl.load_nonlocal_var(trans, nm.id)
|
||||
@@ -963,7 +994,7 @@ class AssignGenMixin:
|
||||
# fail-fast: 变量类型信息缺失,禁止兜底 i32
|
||||
self.Gen.TypeGenErr.fatal_error(target, "变量类型信息缺失", "TypeError")
|
||||
target_ty = target_alloca.Ty.Pointee
|
||||
cur_val = llvmlite.build_load(builder, target_ty, target_alloca)
|
||||
cur_val = llvmlite.build_load(builder, target_ty, target_alloca, vol_aa)
|
||||
|
||||
if cur_val is None:
|
||||
# fail-fast: 目标变量当前值加载失败
|
||||
@@ -996,7 +1027,7 @@ class AssignGenMixin:
|
||||
if scope_type == 1:
|
||||
# global 变量
|
||||
if target_alloca is not None:
|
||||
llvmlite.build_store(builder, result, target_alloca)
|
||||
llvmlite.build_store(builder, result, target_alloca, vol_aa)
|
||||
elif scope_type == 2:
|
||||
# nonlocal 变量
|
||||
nl_ptr: rawptr[llvmlite.Value] = self.Gen.StmtGenDecl.get_nonlocal_var_ptr(
|
||||
@@ -1006,7 +1037,7 @@ class AssignGenMixin:
|
||||
else:
|
||||
# 普通局部变量
|
||||
if target_alloca is not None:
|
||||
llvmlite.build_store(builder, result, target_alloca)
|
||||
llvmlite.build_store(builder, result, target_alloca, vol_aa)
|
||||
|
||||
return 0
|
||||
|
||||
@@ -1176,6 +1207,15 @@ class AssignGenMixin:
|
||||
if self.is_ctypedef_annotation(aa.annotation) != 0:
|
||||
return 0
|
||||
|
||||
# REPL 模式(M2/M3):片段**入口**函数本体内的 AnnAssign 一律走会话槽(见
|
||||
# translate_annassign 的会话分支),此处不得预建局部 alloca——否则局部名
|
||||
# 会遮蔽同名会话变量(此后读 `x` 命中空局部槽,槽值丢失)。
|
||||
# 被提升的会话函数体内不走该分支(那里按普通局部声明预建 alloca)。
|
||||
# CDefine/CTypedef 两个分支在本次返回之前,其行为不变。
|
||||
if trans.ReplCtx is not None \
|
||||
and self.Gen.VarGen.repl_in_frag_entry_scope(trans) != 0:
|
||||
return 0
|
||||
|
||||
# global/nonlocal 变量不需要局部 alloca
|
||||
if GenApi.is_global_name(trans, nm.id) != 0:
|
||||
return 0
|
||||
@@ -1252,6 +1292,18 @@ class AssignGenMixin:
|
||||
if self._is_ptr_element_annotation(annot) != 0:
|
||||
self.Gen.VarGen.set_var_ptr_element(
|
||||
trans.SymTab, nm.id)
|
||||
# t.CVolatile:声明期即标记该变量的 load/store 带 volatile。
|
||||
# 覆盖「无初值声明」`x: t.CVolatile | T`(有初值路径
|
||||
# translate_annassign 亦会登记,幂等)。动机:volatile 禁优化器
|
||||
# 把忙等循环的重复 load 提升/消除,不能依赖优化器保序。
|
||||
if self.Gen.TypeGenErr.has_decorator_marker(
|
||||
annot, "CVolatile", 0) != 0:
|
||||
self.Gen.VarGen.set_var_volatile(trans.SymTab, nm.id)
|
||||
# rawptr[t.CVolatile | T](volatile 指针指向物,等价 C 的
|
||||
# volatile T*):解引用(p[i]/p.field/c.Deref(p))的 load/store
|
||||
# 带 volatile。声明期登记,覆盖「无初值声明」。
|
||||
if self.Gen.TypeGenErr.has_pointee_volatile_marker(annot) != 0:
|
||||
self.Gen.VarGen.set_var_pointee_volatile(trans.SymTab, nm.id)
|
||||
return 0
|
||||
return 0
|
||||
|
||||
@@ -1401,6 +1453,20 @@ class AssignGenMixin:
|
||||
self.Gen.TypeGenCType.register_ctypedef(pool_ct, nm.id, ctd_str)
|
||||
return 0
|
||||
|
||||
# REPL 模式(M2/M3)会话变量:片段**入口**函数本体内的带注解声明/赋值
|
||||
# (`x: int = 5` 定义并定型;`x: int` 仅定型)。注解先解析并定型条目,
|
||||
# 定型后的槽类型再作为 RHS 的 target_ty(与普通 AnnAssign 的 P1-A 同口径)。
|
||||
# 守卫 trans.ReplCtx:非 REPL 恒 None ⇒ 本分支整体不经过。
|
||||
# 被提升的会话函数体内不走该分支(`x: int = 5` 是局部声明,Python 语义)。
|
||||
if trans.ReplCtx is not None \
|
||||
and self.Gen.VarGen.repl_in_frag_entry_scope(trans) != 0:
|
||||
rp_e: rawptr[GenTypes.ReplVarEntry] = \
|
||||
self.Gen.VarGen.repl_ensure_entry(trans, nm.id, aa)
|
||||
if rp_e is not None:
|
||||
self.Gen.VarGen.repl_try_annassign(
|
||||
trans, nm.id, aa.annotation, aa.value, aa)
|
||||
return 0
|
||||
|
||||
pool: rawptr[memhub.MemBuddy] = trans.Pool
|
||||
builder: rawptr[llvmlite.IRBuilder] = trans._cur_builder
|
||||
mod: rawptr[llvmlite.LLVMModule] = trans.Module
|
||||
@@ -1434,7 +1500,12 @@ class AssignGenMixin:
|
||||
callable_ret: rawptr[llvmlite.LLVMType] = self.Gen.TypeGenErr.try_extract_callable_ret(
|
||||
pool, annot, trans._imported_modules, trans._from_imports, trans)
|
||||
if callable_ret is not None:
|
||||
self.Gen.CallGenLeafKit.register_func_ptr_sig(nm.id, callable_ret)
|
||||
# 返回值:0=成功/同名同类型幂等命中;非 0 已在 register_func_ptr_sig
|
||||
# 内部 fatal_error(表满/同名不同类型/表分配失败)终止编译。此处分支
|
||||
# 仅为防御——报错通道异常时不带着未登记的签名继续翻译。
|
||||
if self.Gen.CallGenLeafKit.register_func_ptr_sig(
|
||||
pool, nm.id, callable_ret, aa) != 0:
|
||||
return 0
|
||||
|
||||
# global 变量:写入模块作用域中的全局变量
|
||||
if GenApi.is_global_name(trans, nm.id) != 0:
|
||||
@@ -1447,12 +1518,12 @@ class AssignGenMixin:
|
||||
aa_glob_ty: rawptr[llvmlite.LLVMType] = None
|
||||
if mod_alloca.Ty is not None:
|
||||
aa_glob_ty = mod_alloca.Ty.Pointee
|
||||
# 供 c.Deref(i8*) 推断读取宽度 / 裸名泛型构造从注解推断类型实参:
|
||||
# 与主分支(普通局部变量路径)同一口径——必须在翻译 RHS 之前写入
|
||||
# CurAssignAnnot/CurAssignNode。四处(主分支 / 本 global 分支 /
|
||||
# 下方 mod_glob 分支 / 下方 nonlocal 分支)必须同步,否则
|
||||
# `x: int = c.Deref(p)` 的读取宽度与 `s: Stack[int] = Stack()`
|
||||
# 的类型实参推断都会拿不到注解。
|
||||
# 供裸名泛型构造从注解推断类型实参(消费者见 CallGenCtor.vp 的
|
||||
# CurAssignNode 判定):与主分支(普通局部变量路径)同一口径——
|
||||
# 必须在翻译 RHS 之前写入 CurAssignAnnot/CurAssignNode。四处
|
||||
# (主分支 / 本 global 分支 / 下方 mod_glob 分支 / 下方 nonlocal
|
||||
# 分支)必须同步,否则 `s: Stack[int] = Stack()` 的类型实参推断
|
||||
# 会拿不到注解。
|
||||
trans.CurAssignAnnot = aa.annotation
|
||||
trans.CurAssignNode = aa.value
|
||||
rhs_val: rawptr[llvmlite.Value] = self.Gen.ExprGen.translate_value(
|
||||
@@ -1493,11 +1564,13 @@ class AssignGenMixin:
|
||||
target_ty = mod_alloca.Ty.Pointee
|
||||
if target_ty is not None:
|
||||
rhs_val = self.Gen.ExprGenBase.coerce_to_type(builder, rhs_val, target_ty, node, trans)
|
||||
llvmlite.build_store(builder, rhs_val, mod_alloca)
|
||||
# t.CVolatile(global 声明)全局:初始化 store 带 volatile 限定符
|
||||
vol_gaa: int = self.Gen.VarGen.var_is_volatile(
|
||||
self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm.id))
|
||||
llvmlite.build_store(builder, rhs_val, mod_alloca, vol_gaa)
|
||||
# 清除赋值上下文(防残留):与主分支清空时机同款。四处(主分支 /
|
||||
# 本 global 分支 / 下方 mod_glob 分支 / 下方 nonlocal 分支)必须同步清除,
|
||||
# 否则残留注解会让后续 while 条件/比较等处的 c.Deref 被误判读取宽度
|
||||
# (i8* 按 i32* 读 4 字节),也会污染裸名泛型构造的类型实参推断
|
||||
# 否则残留注解会污染后续语句里裸名泛型构造的类型实参推断
|
||||
trans.CurAssignAnnot = None
|
||||
trans.CurAssignNode = None
|
||||
return 0
|
||||
@@ -1515,12 +1588,11 @@ class AssignGenMixin:
|
||||
nl_target_ty: rawptr[llvmlite.LLVMType] = None
|
||||
if nl_ptr is not None and nl_ptr.Ty is not None:
|
||||
nl_target_ty = nl_ptr.Ty.Pointee
|
||||
# 供 c.Deref(i8*) 推断读取宽度 / 裸名泛型构造从注解推断类型实参:
|
||||
# 与主分支、上方 global 分支、下方 mod_glob 分支同一口径——必须在
|
||||
# 翻译 RHS 之前写入 CurAssignAnnot/CurAssignNode。四处(主分支 /
|
||||
# global / mod_glob / 本 nonlocal 分支)必须同步,否则
|
||||
# `nonlocal x: int = c.Deref(p)` 的读取宽度与
|
||||
# `nonlocal s: Stack[int] = Stack()` 的类型实参推断都会拿不到注解。
|
||||
# 供裸名泛型构造从注解推断类型实参:与主分支、上方 global 分支、
|
||||
# 下方 mod_glob 分支同一口径——必须在翻译 RHS 之前写入
|
||||
# CurAssignAnnot/CurAssignNode。四处(主分支 / global / mod_glob /
|
||||
# 本 nonlocal 分支)必须同步,否则
|
||||
# `nonlocal s: Stack[int] = Stack()` 的类型实参推断会拿不到注解。
|
||||
trans.CurAssignAnnot = aa.annotation
|
||||
trans.CurAssignNode = aa.value
|
||||
rhs_val: rawptr[llvmlite.Value] = self.Gen.ExprGen.translate_value(
|
||||
@@ -1542,9 +1614,8 @@ class AssignGenMixin:
|
||||
builder, rhs_val, nl_target_ty, node)
|
||||
llvmlite.build_store(builder, rhs_coerced, nl_ptr)
|
||||
# 清除赋值上下文(防残留):与主分支清空时机同款。四处(主分支 /
|
||||
# global / mod_glob / 本 nonlocal 分支)必须同步清除,否则残留注解会让
|
||||
# 后续 while 条件/比较等处的 c.Deref 被误判读取宽度(i8* 按 i32* 读 4
|
||||
# 字节),也会污染裸名泛型构造的类型实参推断
|
||||
# global / mod_glob / 本 nonlocal 分支)必须同步清除,否则残留注解会
|
||||
# 污染后续语句里裸名泛型构造的类型实参推断
|
||||
trans.CurAssignAnnot = None
|
||||
trans.CurAssignNode = None
|
||||
return 0
|
||||
@@ -1568,11 +1639,10 @@ class AssignGenMixin:
|
||||
mg_val_ty: rawptr[llvmlite.LLVMType] = None
|
||||
if mod_glob.Ty is not None:
|
||||
mg_val_ty = mod_glob.Ty.Pointee
|
||||
# 供 c.Deref(i8*) 推断读取宽度 / 裸名泛型构造从注解推断类型实参:
|
||||
# 与主分支、上方 global 分支同一口径——翻译 RHS 前写入
|
||||
# CurAssignAnnot/CurAssignNode。模块级 `s: Stack[int] = Stack()`
|
||||
# 走的就是本分支,四处(主分支 / global / 本 mod_glob 分支 /
|
||||
# 上方 nonlocal 分支)必须同步。
|
||||
# 供裸名泛型构造从注解推断类型实参:与主分支、上方 global 分支
|
||||
# 同一口径——翻译 RHS 前写入 CurAssignAnnot/CurAssignNode。
|
||||
# 模块级 `s: Stack[int] = Stack()` 走的就是本分支,四处(主分支 /
|
||||
# global / 本 mod_glob 分支 / 上方 nonlocal 分支)必须同步。
|
||||
trans.CurAssignAnnot = aa.annotation
|
||||
trans.CurAssignNode = aa.value
|
||||
rhs_val_mg: rawptr[llvmlite.Value] = self.Gen.ExprGen.translate_value(
|
||||
@@ -1613,11 +1683,13 @@ class AssignGenMixin:
|
||||
target_ty_mg = mod_glob.Ty.Pointee
|
||||
if target_ty_mg is not None:
|
||||
rhs_val_mg = self.Gen.ExprGenBase.coerce_to_type(builder, rhs_val_mg, target_ty_mg, node)
|
||||
llvmlite.build_store(builder, rhs_val_mg, mod_glob)
|
||||
# t.CVolatile 模块级全局:初始化 store 带 volatile 限定符
|
||||
vol_mga: int = self.Gen.VarGen.var_is_volatile(
|
||||
self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm.id))
|
||||
llvmlite.build_store(builder, rhs_val_mg, mod_glob, vol_mga)
|
||||
# 清除赋值上下文(防残留):与主分支清空时机同款。四处(主分支 /
|
||||
# 上方 global 分支 / 本 mod_glob 分支 / 上方 nonlocal 分支)必须同步清除,
|
||||
# 否则残留注解会让后续语句的 c.Deref 被误判读取宽度,并污染裸名泛型
|
||||
# 构造的类型实参推断
|
||||
# 否则残留注解会污染后续语句里裸名泛型构造的类型实参推断
|
||||
trans.CurAssignAnnot = None
|
||||
trans.CurAssignNode = None
|
||||
return 0
|
||||
@@ -1759,9 +1831,8 @@ class AssignGenMixin:
|
||||
self._init_global_array_from_list(
|
||||
builder, pool, mod, alloca, aa.value, trans)
|
||||
else:
|
||||
# 供 c.Deref(i8*) 推断读取宽度:v: int = c.Deref(p) → 读 i32
|
||||
# CurAssignNode 记录 RHS 节点:translate_c_deref 据此判定 Deref
|
||||
# 是否为赋值直接 RHS(对齐 TPC _infer_deref_target_type)。
|
||||
# 供裸名泛型构造从注解推断类型实参(消费者见 CallGenCtor.vp 的
|
||||
# CurAssignNode 判定:`s: Stack[int] = Stack()` 用注解里的 int 特化)。
|
||||
# 注意:本主分支(普通局部变量)、上方 global 分支、mod_glob 分支、
|
||||
# nonlocal 分支四处的 set/clear 必须同步(模块级 AnnAssign 走
|
||||
# mod_glob;闭包内 AnnAssign 走 nonlocal)。
|
||||
@@ -1854,7 +1925,19 @@ class AssignGenMixin:
|
||||
target_ty = alloca.Ty.Pointee
|
||||
if target_ty is not None:
|
||||
rhs_val = self.Gen.ExprGenBase.coerce_to_type(builder, rhs_val, target_ty, node, trans)
|
||||
llvmlite.build_store(builder, rhs_val, alloca)
|
||||
# t.CVolatile 局部变量:标记 VarEntry 并让本次 store 带 volatile
|
||||
vol_laa: int = 0
|
||||
if aa.annotation is not None and nm.id is not None:
|
||||
if self.Gen.TypeGenErr.has_decorator_marker(
|
||||
aa.annotation, "CVolatile", 0) != 0:
|
||||
self.Gen.VarGen.set_var_volatile(trans.SymTab, nm.id)
|
||||
vol_laa = 1
|
||||
# rawptr[t.CVolatile | T](volatile 指针指向物):登记
|
||||
# PointeeVolatile;本 store 写的是指针变量自身,不影响。
|
||||
if self.Gen.TypeGenErr.has_pointee_volatile_marker(
|
||||
aa.annotation) != 0:
|
||||
self.Gen.VarGen.set_var_pointee_volatile(trans.SymTab, nm.id)
|
||||
llvmlite.build_store(builder, rhs_val, alloca, vol_laa)
|
||||
# FakeDuck: 初始化影子结构体 __data__ 字段 = 初始字符串指针
|
||||
# (对齐 TPC HandlesAnnAssign.py: 仅当有初值时写入 __data__)
|
||||
if fd_str_ty is not None and fd_meta_alloca is not None:
|
||||
@@ -1868,8 +1951,8 @@ class AssignGenMixin:
|
||||
if fd_data_ptr is not None:
|
||||
llvmlite.build_store(builder, rhs_val, fd_data_ptr)
|
||||
# 清除赋值上下文(防残留):CurAssignAnnot/CurAssignNode 只在该
|
||||
# AnnAssign 的 RHS 翻译期间有效,否则后续 while 条件/比较等处的
|
||||
# c.Deref 会被残留注解误判读取宽度(i8* 被 bitcast i32* 读 4 字节)。
|
||||
# AnnAssign 的 RHS 翻译期间有效,否则后续语句里裸名泛型构造的类型
|
||||
# 实参推断会拿到残留注解。
|
||||
# 四处(本主分支 / global / mod_glob / nonlocal)必须同步清除。
|
||||
trans.CurAssignAnnot = None
|
||||
trans.CurAssignNode = None
|
||||
@@ -1911,7 +1994,7 @@ class AssignGenMixin:
|
||||
VLogger.error("cast failed", "ASGN")
|
||||
return 0
|
||||
|
||||
targets: rawptr[list[rawptr[ast.AST]]] = asgn.targets
|
||||
targets: list[ast.AST*]* = asgn.targets
|
||||
if targets is None:
|
||||
VLogger.error("targets is None", "ASGN")
|
||||
return 0
|
||||
@@ -1923,7 +2006,7 @@ class AssignGenMixin:
|
||||
|
||||
# 翻译 RHS 值
|
||||
# 无注解赋值无目标类型可推断,清空 CurAssignAnnot/CurAssignNode
|
||||
# (防残留误判 c.Deref 宽度)
|
||||
# (防残留污染裸名泛型构造的类型实参推断)
|
||||
trans.CurAssignAnnot = None
|
||||
trans.CurAssignNode = None
|
||||
# P1-A(上下文位宽传播):单 Name 目标且其存储类型已知时,把存储类型作为
|
||||
@@ -1943,6 +2026,16 @@ class AssignGenMixin:
|
||||
trans.SymTab, asg_nm0.id)
|
||||
if asg_slot is not None and asg_slot.Ty is not None:
|
||||
asg_target_ty = asg_slot.Ty.Pointee
|
||||
elif trans.ReplCtx is not None \
|
||||
and self.Gen.VarGen.repl_in_frag_entry_scope(trans) != 0:
|
||||
# REPL 模式(M2/M3):已定型的会话变量也用槽类型做 target_ty
|
||||
# (与 P1-A 同口径;未定型则维持 None,由 RHS 类型定型)。
|
||||
# 只在片段入口函数生效(被提升的会话函数体内同名赋值是局部变量)
|
||||
asg_re: rawptr[GenTypes.ReplVarEntry] = \
|
||||
self.Gen.VarGen.repl_find_entry(trans.ReplCtx, asg_nm0.id)
|
||||
if asg_re is not None \
|
||||
and asg_re.Kind != GenTypes.REPL_KIND_UNTYPED:
|
||||
asg_target_ty = self.Gen.VarGen.repl_slot_ty(pool, asg_re)
|
||||
rhs_val: rawptr[llvmlite.Value] = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, asgn.value, None, 0, trans, asg_target_ty)
|
||||
if rhs_val is None:
|
||||
@@ -2008,7 +2101,7 @@ class AssignGenMixin:
|
||||
# store + GEP 逐字段 load → store 到各 Name 目标。
|
||||
if tk == ast.ASTKind.Tuple:
|
||||
tgt_tup: rawptr[ast.Tuple] = rawptr[ast.Tuple](target)
|
||||
tgt_elts: rawptr[list[rawptr[ast.AST]]] = tgt_tup.elts
|
||||
tgt_elts: list[ast.AST*]* = tgt_tup.elts
|
||||
# 守卫:rhs 不是 struct(tuple 打包)时跳过本 target
|
||||
if tgt_elts is None or rhs_val is None or rhs_val.Ty is None:
|
||||
continue
|
||||
@@ -2084,7 +2177,14 @@ class AssignGenMixin:
|
||||
if elem_ptr.Ty is not None and elem_ptr.Ty.Pointee is not None:
|
||||
store_val = self.Gen.ExprGenBase.coerce_to_type(
|
||||
builder, rhs_val, elem_ptr.Ty.Pointee, node, trans)
|
||||
llvmlite.build_store(builder, store_val, elem_ptr)
|
||||
# rawptr[t.CVolatile|T] 基址(volatile 指针指向物):p[i] = v
|
||||
# 的 store 带 volatile。仅基址可解析到条目时为 1(否则文本不变)。
|
||||
vol_sw: int = 0
|
||||
sub_wr: rawptr[ast.Subscript] = rawptr[ast.Subscript](target)
|
||||
if sub_wr is not None:
|
||||
vol_sw = self.Gen.ExprGenAttr.base_pointee_is_volatile(
|
||||
pool, trans, sub_wr.value)
|
||||
llvmlite.build_store(builder, store_val, elem_ptr, vol_sw)
|
||||
continue
|
||||
# get_subscript_ptr 返回 None: 尝试 __setitem__ 运算符重载
|
||||
# 适用于自定义类(如 hashtable[key]=val → hashtable.__setitem__(key, val))
|
||||
@@ -2262,7 +2362,17 @@ class AssignGenMixin:
|
||||
if field_ptr.Ty is not None and field_ptr.Ty.Pointee is not None:
|
||||
store_val = self.Gen.ExprGenBase.coerce_to_type(
|
||||
builder, rhs_val, field_ptr.Ty.Pointee, node, trans)
|
||||
llvmlite.build_store(builder, store_val, field_ptr)
|
||||
# t.CVolatile 字段:store 带 volatile 限定符
|
||||
vol_fw: int = self.Gen.ExprGenAttr.attr_field_is_volatile(
|
||||
pool, trans, target)
|
||||
# rawptr[t.CVolatile|T] 基址(volatile 指针指向物):p.field = v
|
||||
# 的 store 亦带 volatile(两来源取或)。
|
||||
at_wr: rawptr[ast.Attribute] = rawptr[ast.Attribute](target)
|
||||
if at_wr is not None:
|
||||
if self.Gen.ExprGenAttr.base_pointee_is_volatile(
|
||||
pool, trans, at_wr.value) != 0:
|
||||
vol_fw = 1
|
||||
llvmlite.build_store(builder, store_val, field_ptr, vol_fw)
|
||||
continue
|
||||
# 守卫:field_ptr 为 None → 构造详细错误信息
|
||||
attr_node: rawptr[ast.Attribute] = rawptr[ast.Attribute](target)
|
||||
@@ -2333,7 +2443,12 @@ class AssignGenMixin:
|
||||
target_ty = mod_alloca.Ty.Pointee
|
||||
if target_ty is not None:
|
||||
rhs_val = self.Gen.ExprGenBase.coerce_to_type(builder, rhs_val, target_ty, node, trans)
|
||||
llvmlite.build_store(builder, rhs_val, mod_alloca)
|
||||
# t.CVolatile 全局:store 带 volatile 限定符
|
||||
vol_gas: int = 0
|
||||
if nm.id is not None:
|
||||
vol_gas = self.Gen.VarGen.var_is_volatile(
|
||||
self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm.id))
|
||||
llvmlite.build_store(builder, rhs_val, mod_alloca, vol_gas)
|
||||
continue
|
||||
|
||||
# nonlocal 变量:通过闭包 env 写入
|
||||
@@ -2362,6 +2477,20 @@ class AssignGenMixin:
|
||||
llvmlite.build_store(builder, rhs_coerced, nl_ptr)
|
||||
continue
|
||||
|
||||
# REPL 模式(M2/M3)会话变量:片段**入口**函数本体内的 Name 目标即
|
||||
# 会话变量(首次出现=定义:申请槽位 + 按 RHS 定型 + 写槽 + 写结果区)。
|
||||
# 守卫 trans.ReplCtx(非 REPL 恒 None ⇒ 本分支整体不经过);
|
||||
# repl_in_frag_entry_scope 排除被提升的会话函数体与片段内嵌套函数体
|
||||
# (那些仍用普通局部 alloca:Python 局部语义 + 防形参同名串味)。
|
||||
if trans.ReplCtx is not None \
|
||||
and self.Gen.VarGen.repl_in_frag_entry_scope(trans) != 0:
|
||||
rp_entry: rawptr[GenTypes.ReplVarEntry] = \
|
||||
self.Gen.VarGen.repl_ensure_entry(trans, nm.id, target)
|
||||
if rp_entry is not None:
|
||||
self.Gen.VarGen.repl_try_assign(
|
||||
trans, nm.id, rhs_val, asgn.value, node)
|
||||
continue
|
||||
|
||||
# 拦截:函数内对模块级全局变量赋值但没 global 声明
|
||||
# 否则静默创建局部变量遮蔽全局,全局保持 null 导致运行时崩溃
|
||||
# (_mbuddy = mb 缺 global 声明即此类 bug:Int32 解引用 null 崩溃)
|
||||
@@ -2387,7 +2516,10 @@ class AssignGenMixin:
|
||||
if alloca.Ty is not None and alloca.Ty.Pointee is not None:
|
||||
store_val = self.Gen.ExprGenBase.coerce_to_type(
|
||||
builder, rhs_val, alloca.Ty.Pointee, node, trans)
|
||||
llvmlite.build_store(builder, store_val, alloca)
|
||||
# t.CVolatile 局部变量:store 带 volatile 限定符
|
||||
vol_las: int = self.Gen.VarGen.var_is_volatile(
|
||||
self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm.id))
|
||||
llvmlite.build_store(builder, store_val, alloca, vol_las)
|
||||
# lambda 表达式赋给变量:注册为闭包变量名,
|
||||
# 调用分派(is_closure_name)才走闭包间接调用路径;
|
||||
# 否则 i8** alloca 被 _is_func_ptr_alloca 误判为
|
||||
|
||||
@@ -198,7 +198,7 @@ class AsyncGenMixin(CallGenBase.CallGenBase):
|
||||
self._scan_sleep_stmts(trans, fd.children)
|
||||
|
||||
def _scan_sleep_stmts(self, trans: rawptr[HT.Translator],
|
||||
stmts: rawptr[list[rawptr[ast.AST]]]):
|
||||
stmts: list[ast.AST*]*):
|
||||
if stmts is None or trans._coro_uses_sleep != 0:
|
||||
return
|
||||
bn: sizet = len(stmts)
|
||||
@@ -332,7 +332,7 @@ class AsyncGenMixin(CallGenBase.CallGenBase):
|
||||
|
||||
# ---------- 第二遍:填额外槽表 + 状态号计数 ----------
|
||||
def _scan_stmts(self, trans: rawptr[HT.Translator],
|
||||
stmts: rawptr[list[rawptr[ast.AST]]]):
|
||||
stmts: list[ast.AST*]*):
|
||||
if stmts is None:
|
||||
return
|
||||
bn: sizet = len(stmts)
|
||||
@@ -578,7 +578,7 @@ class AsyncGenMixin(CallGenBase.CallGenBase):
|
||||
return self._stmts_deep_await(tr3.finalbody)
|
||||
return self._stmt_has_await(stmt)
|
||||
|
||||
def _stmts_deep_await(self, stmts: rawptr[list[rawptr[ast.AST]]]) -> int:
|
||||
def _stmts_deep_await(self, stmts: list[ast.AST*]*) -> int:
|
||||
if stmts is None:
|
||||
return 0
|
||||
bn6: sizet = len(stmts)
|
||||
@@ -633,7 +633,7 @@ class AsyncGenMixin(CallGenBase.CallGenBase):
|
||||
return trans._coro_local_count
|
||||
|
||||
def _collect_locals_stmts(self, trans: rawptr[HT.Translator],
|
||||
stmts: rawptr[list[rawptr[ast.AST]]]):
|
||||
stmts: list[ast.AST*]*):
|
||||
if stmts is None:
|
||||
return
|
||||
bn: sizet = len(stmts)
|
||||
@@ -729,8 +729,8 @@ class AsyncGenMixin(CallGenBase.CallGenBase):
|
||||
trans._coro_local_base = 5 + nparams
|
||||
trans._coro_extra_base = trans._coro_local_base + nlocals
|
||||
total: int = 5 + nparams + nlocals + nextra
|
||||
head: rawptr[llvmlite.Function] = None
|
||||
prev: rawptr[llvmlite.Function] = None
|
||||
head: rawptr[llvmlite.ParamNode] = None
|
||||
prev: rawptr[llvmlite.ParamNode] = None
|
||||
fi: int = 0
|
||||
for fi in range(total):
|
||||
fty: rawptr[llvmlite.LLVMType] = i32_ty
|
||||
@@ -1205,7 +1205,7 @@ class AsyncGenMixin(CallGenBase.CallGenBase):
|
||||
builder: rawptr[llvmlite.IRBuilder],
|
||||
pool: rawptr[memhub.MemBuddy],
|
||||
mod: rawptr[llvmlite.LLVMModule],
|
||||
stmts: rawptr[list[rawptr[ast.AST]]]):
|
||||
stmts: list[ast.AST*]*):
|
||||
"""递归翻译协程体语句。builder 当前块 = 活跃执行块(state0 或某恢复块)。"""
|
||||
if stmts is None:
|
||||
return
|
||||
@@ -2001,7 +2001,7 @@ class AsyncGenMixin(CallGenBase.CallGenBase):
|
||||
for hi in range(nhandlers):
|
||||
h_node2: rawptr[ast.AST] = tr.handlers.get(hi)
|
||||
handler_bb2: rawptr[llvmlite.BasicBlock] = (
|
||||
rawptr[llvmlite.BasicBlock])(handler_bbs[hi], t.CPtr)
|
||||
rawptr[llvmlite.BasicBlock])(handler_bbs[hi])
|
||||
llvmlite.position_at_end(builder, handler_bb2)
|
||||
if h_node2 is not None:
|
||||
hd2: rawptr[ast.ExceptHandler] = rawptr[ast.ExceptHandler](h_node2)
|
||||
|
||||
@@ -29,8 +29,17 @@ import lib.Stub.StubGen.VpiReader as VpiReader
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 常量(与 HandlesExprCall 保持一致,本地副本避免跨模块 CDefine 查找 bug)
|
||||
# 常量(Gen 层各处容量上限)
|
||||
#
|
||||
# GLOBAL_FUNC_MAX / GLOBAL_DEFAULTS_MAX / MAX_CLOSURE_NAMES /
|
||||
# MAX_FUNC_PTR_SIGS / ISINSTANCE_CLASS_MAX 五个容量上限以本文件为**全仓唯一
|
||||
# 来源**,消费方 CallGenLeafKit.vp 在函数体内以 CallGenBase.<NAME> 取值:
|
||||
# 跨模块整型 t.CDefine 在函数体内可读(与 GenTypes.FIELD_MAX /
|
||||
# StubMerger.MAX_INCLUDES 走同一条 ExprGenAttr 跨模块 CDefine 查找路径),
|
||||
# 限制仅在「模块级 t.CDefine 初始化式里引用跨模块常量」。改此一处即全仓生效。
|
||||
# ============================================================
|
||||
# 全局函数表 / 默认参数表容量(消费方:CallGenLeafKit._init_global_func_table /
|
||||
# _register_global_func / _init_global_defaults_table / _register_global_defaults)
|
||||
GLOBAL_FUNC_MAX: t.CDefine = 8192
|
||||
GLOBAL_DEFAULTS_MAX: t.CDefine = 4096
|
||||
_CEXPORT_MAX: t.CDefine = 256
|
||||
@@ -41,11 +50,12 @@ ASM_ARGS_BUF_SIZE: t.CDefine = 512
|
||||
ASM_LINE_BUF_SIZE: t.CDefine = 4096
|
||||
LLVMIR_MAX_OPS: t.CDefine = 16
|
||||
LLVMIR_TEMPLATE_BUF: t.CDefine = 512
|
||||
# 闭包名表大小(原 HandlesExprCall 模块级常量)
|
||||
# 闭包名表大小(消费方:CallGenLeafKit._ensure_closure_names/register_closure_name)
|
||||
MAX_CLOSURE_NAMES: t.CDefine = 128
|
||||
# 函数指针签名表大小(原 HandlesExprCall 模块级常量)
|
||||
# 函数指针签名表大小(消费方:CallGenLeafKit._ensure_funcptr_sigs/register_func_ptr_sig)
|
||||
MAX_FUNC_PTR_SIGS: t.CDefine = 64
|
||||
# isinstance 子类收集上限(防数组越界;t.CDefine 注解由 TPC 解析为 i32)
|
||||
# isinstance 子类收集上限(防数组越界;t.CDefine 注解由 TPC 解析为 i32。
|
||||
# 消费方:CallGenLeafKit._collect_subclass_vtable_classes)
|
||||
ISINSTANCE_CLASS_MAX: t.CDefine = 64
|
||||
|
||||
|
||||
@@ -603,7 +613,8 @@ class CallGenBase:
|
||||
existing_steps += 1
|
||||
if existing_steps > DECLARE_CHAIN_LIMIT:
|
||||
stdio.printf("[CALLGEN] 链表异常: module funcs(call_name=%s,遍历超限,终止)\n", call_name)
|
||||
stdlib.exit(1)
|
||||
# 终止点收敛:REPL 会话内 longjmp 回 REPL 循环(诊断已打印)
|
||||
VLogger.repl_abort()
|
||||
if existing.Name is not None:
|
||||
# 快速路径:strcmp 判等蕴含首字符相等,首字符不同者跳过 strcmp
|
||||
if existing.Name[0] == call_name[0] \
|
||||
@@ -622,7 +633,8 @@ class CallGenBase:
|
||||
cur_count += 1
|
||||
if cur_count > DECLARE_CHAIN_LIMIT:
|
||||
stdio.printf("[CALLGEN] 链表异常: func params(call_name=%s,参数链遍历超限,终止)\n", call_name)
|
||||
stdlib.exit(1)
|
||||
# 终止点收敛:REPL 会话内 longjmp 回 REPL 循环(诊断已打印)
|
||||
VLogger.repl_abort()
|
||||
cur_p = cur_p.Next
|
||||
# 只追加缺失的参数(cur_count < param_count 时)
|
||||
if cur_count < param_count:
|
||||
|
||||
@@ -17,42 +17,12 @@ from . import CallGenBase
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _IsTypeExpr / _IsCastWrappingDeref - c.Deref 加载宽度推断的转换包裹判定
|
||||
# (镜像 TPC HandlesSpecialCall:转换链包裹 Deref 时允许从赋值注解推断
|
||||
# 加载宽度;ifexp/binop 包裹不放行,避免 i8* 错 bitcast 成其他位宽读)
|
||||
# 常量(与 TPC 侧 HandlesExprCall 保持一致)
|
||||
#
|
||||
# GLOBAL_FUNC_MAX / GLOBAL_DEFAULTS_MAX / MAX_CLOSURE_NAMES /
|
||||
# MAX_FUNC_PTR_SIGS / ISINSTANCE_CLASS_MAX:唯一来源在 CallGenBase.vp
|
||||
# (本文件不使用,故不留副本;消费方 CallGenLeafKit.vp 经 CallGenBase.<NAME> 引用)。
|
||||
# ============================================================
|
||||
def _IsTypeExpr(node: rawptr[ast.AST]) -> int:
|
||||
"""节点是否为类型表达式(Name/Attribute/Subscript/BinOp|)"""
|
||||
if node is None:
|
||||
return 0
|
||||
k: int = node.kind()
|
||||
if k == ast.ASTKind.Name or k == ast.ASTKind.Attribute or k == ast.ASTKind.Subscript:
|
||||
return 1
|
||||
if k == ast.ASTKind.BinOp:
|
||||
bop: rawptr[ast.BinOp] = rawptr[ast.BinOp](node)
|
||||
if bop.op == ast.OpKind.BitOr:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
def _IsCastWrappingDeref(rhs: rawptr[ast.AST], deref_node: rawptr[ast.AST]) -> int:
|
||||
"""rhs 是否为"类型转换链包裹 c.Deref"(如 (T | t.CPtr)(t.CPtr(c.Deref(p))))"""
|
||||
if rhs is None:
|
||||
return 0
|
||||
if uint64(rhs) == uint64(deref_node):
|
||||
return 1
|
||||
if rhs.kind() == ast.ASTKind.Call:
|
||||
cl: rawptr[ast.Call] = rawptr[ast.Call](rhs)
|
||||
if cl.args is not None and len(cl.args) == 1 and _IsTypeExpr(cl.func) != 0:
|
||||
return _IsCastWrappingDeref(cl.args.get(0), deref_node)
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 常量(与 HandlesExprCall 保持一致,本地副本避免跨模块 CDefine 查找 bug)
|
||||
# ============================================================
|
||||
GLOBAL_FUNC_MAX: t.CDefine = 8192
|
||||
GLOBAL_DEFAULTS_MAX: t.CDefine = 4096
|
||||
_CEXPORT_MAX: t.CDefine = 256
|
||||
ASM_MAX_OPERANDS: t.CDefine = 16
|
||||
# clobber(~{...})容量独立于操作数上限:vipersimd ×8 内核单条 c.Asm
|
||||
@@ -66,12 +36,6 @@ ASM_ARGS_BUF_SIZE: t.CDefine = 512
|
||||
ASM_LINE_BUF_SIZE: t.CDefine = 4096
|
||||
LLVMIR_MAX_OPS: t.CDefine = 16
|
||||
LLVMIR_TEMPLATE_BUF: t.CDefine = 512
|
||||
# 闭包名表大小(原 HandlesExprCall 模块级常量)
|
||||
MAX_CLOSURE_NAMES: t.CDefine = 128
|
||||
# 函数指针签名表大小(原 HandlesExprCall 模块级常量)
|
||||
MAX_FUNC_PTR_SIGS: t.CDefine = 64
|
||||
# isinstance 子类收集上限(防数组越界;t.CDefine 注解由 TPC 解析为 i32)
|
||||
ISINSTANCE_CLASS_MAX: t.CDefine = 64
|
||||
|
||||
|
||||
# ============================================================
|
||||
@@ -87,10 +51,16 @@ class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
mod: rawptr[llvmlite.LLVMModule],
|
||||
cl: rawptr[ast.Call],
|
||||
trans: rawptr[HT.Translator] = None) -> rawptr[llvmlite.Value]:
|
||||
"""c.Deref(ptr) → load 按 ptr 的 pointee 类型"""
|
||||
"""c.Deref(ptr) → load,宽度只由 ptr 的 pointee 类型决定
|
||||
|
||||
pointee 是 i8(t.CPtr / void* / str / bytes)恒读 1 字节;不再按赋值
|
||||
目标注解(CurAssignAnnot)反推宽度——那会让同一处 c.Deref(i8*) 的读取
|
||||
宽度取决于它是否恰好出现在带注解赋值的 RHS 里。需要按更宽类型读时,
|
||||
由调用点显式给出元素类型指针后再解引用(见下方读取分支注释)。
|
||||
"""
|
||||
if cl is None:
|
||||
return None
|
||||
cargs: rawptr[list[rawptr[ast.AST]]] = cl.args
|
||||
cargs: list[ast.AST*]* = cl.args
|
||||
if cargs is None or len(cargs) < 1:
|
||||
return None
|
||||
|
||||
@@ -99,53 +69,22 @@ class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
if ptr_val is None:
|
||||
return None
|
||||
|
||||
# 按 pointee 类型读取;非指针参数默认按 i8(保持向后兼容)
|
||||
# rawptr[t.CVolatile | T] 实参(volatile 指针指向物):c.Deref(p) 的
|
||||
# 解引用 load 带 volatile。仅当实参可解析到 VarEntry(Name)/ FieldEntry
|
||||
# (Attribute)时为 1;其余(函数返回/调用/复杂表达式)为 0(明确不支持)。
|
||||
vol_deref: int = self.Gen.ExprGenAttr.base_pointee_is_volatile(
|
||||
pool, trans, cargs.get(0))
|
||||
|
||||
# 读取宽度只由指针类型决定:按 pointee 类型 load 一个元素。
|
||||
# pointee 是 i8(t.CPtr / void* / str / bytes)即恒读 1 字节。
|
||||
# 需要 4/8 字节等更宽读取时,必须在调用点把指针显式变成有元素类型的
|
||||
# 指针再解引用(c.Deref((rawptr[T])(p)) / c.Deref((T | t.CPtr)(x))),
|
||||
# 不再由赋值目标注解反推——否则同一处 c.Deref(i8*) 的宽度会随上下文
|
||||
# (是否带注解赋值的 RHS)而变。
|
||||
if self.Gen.ExprGenBase.is_ptr_type(ptr_val.Ty) != 0:
|
||||
pointee: rawptr[llvmlite.LLVMType] = ptr_val.Ty.Pointee
|
||||
if pointee is not None:
|
||||
# i8*(void*)时按赋值目标类型推断读取宽度(对齐 TPC
|
||||
# HandlesSpecialCall._infer_deref_target_type):
|
||||
# v: int = c.Deref(p) → bitcast i32* 后 load 4 字节。
|
||||
# 背景:DictTest d3[key5]=500 读出 -12——固定按 i8 读 1 字节 +
|
||||
# sext 截断(0xF4 → 0xFFFFFFF4);Test 1 的小值(10)恰好正确
|
||||
# 掩盖了缺陷。
|
||||
match pointee:
|
||||
case llvmlite.LLVMType.Int(pointee_width):
|
||||
# 允许推断:c.Deref 是赋值语句直接 RHS(v: int = c.Deref(p))
|
||||
# 或处于类型转换链包裹中(如 vt: t.CPtr =
|
||||
# t\.CVoid(c.Deref(p)))。嵌套在 while 条件/比较/binop/
|
||||
# 其他调用中(如 while c.Deref(p) != 0、total +=
|
||||
# int(c.Deref(p)))不推断,否则 i8* 会被残留
|
||||
# CurAssignAnnot 误判为 i32* 读 4 字节 → StringIterTest
|
||||
# ASCII sum/manual strcmp 失败。
|
||||
allow_infer: int = 0
|
||||
if trans is not None and trans.CurAssignNode is not None:
|
||||
if uint64(cl) == uint64(trans.CurAssignNode):
|
||||
allow_infer = 1
|
||||
elif _IsCastWrappingDeref(trans.CurAssignNode, cl) != 0:
|
||||
allow_infer = 1
|
||||
if pointee_width == 8 and allow_infer != 0 \
|
||||
and trans is not None and trans.CurAssignAnnot is not None:
|
||||
dref_ty: rawptr[llvmlite.LLVMType] = self.Gen.TypeGenResolve.resolve_annotation_type(
|
||||
trans.Pool, trans.CurAssignAnnot,
|
||||
trans._imported_modules, trans._from_imports, trans, 0)
|
||||
if dref_ty is not None:
|
||||
dref_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(dref_ty)
|
||||
dref_fbits: int = self.Gen.ExprGenBase.get_llvm_float_bits(dref_ty)
|
||||
dref_is_ptr: int = self.Gen.ExprGenBase.is_ptr_type(dref_ty)
|
||||
# 整数/浮点/指针目标均推断(指针 → bitcast 后
|
||||
# load 8 字节;struct 值目标不推断,保持 i8 读)
|
||||
dref_ptr: rawptr[llvmlite.Value] = None
|
||||
if (dref_bits != 0 or dref_fbits != 0 or dref_is_ptr != 0) \
|
||||
and dref_bits != 8:
|
||||
dref_ptr_ty: rawptr[llvmlite.LLVMType] = llvmlite.Ptr(pool, dref_ty)
|
||||
dref_ptr = llvmlite.build_bitcast(
|
||||
builder, ptr_val, dref_ptr_ty)
|
||||
if dref_ptr is not None:
|
||||
return llvmlite.build_load(builder, dref_ty, dref_ptr)
|
||||
case _:
|
||||
pass
|
||||
return llvmlite.build_load(builder, pointee, ptr_val)
|
||||
return llvmlite.build_load(builder, pointee, ptr_val, vol_deref)
|
||||
# 非指针参数即类型推断退化:fail-fast,绝不按 i8 兜底读取(会读到垃圾宽度)
|
||||
self.Gen.TypeGenErr.fatal_error(cl, "c.Deref 参数不是指针类型(类型推断退化)", "TypeError")
|
||||
return None
|
||||
@@ -161,14 +100,15 @@ class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
"""
|
||||
if cl is None:
|
||||
return None
|
||||
cargs: rawptr[list[rawptr[ast.AST]]] = cl.args
|
||||
cargs: list[ast.AST*]* = cl.args
|
||||
if cargs is None or len(cargs) < 1:
|
||||
return None
|
||||
# 单参形式:deref 读(paging.vp save_pt_range L263
|
||||
# saved = c.DerefAs(save_count)、restore_pt_range L277-278
|
||||
# c.DerefAs(entry_ptr) 根因——此前 len<2 直接 return None →
|
||||
# 跌落跨模块函数调用生成 call @DerefAs → ld.lld undefined symbol:
|
||||
# DerefAs。复用 translate_c_deref 的类型推断读取逻辑。
|
||||
# DerefAs。读取宽度与 c.Deref 同口径(只认 pointee 类型),
|
||||
# 故直接复用 translate_c_deref。
|
||||
if len(cargs) < 2:
|
||||
return self.translate_c_deref(pool, builder, mod, cl, trans)
|
||||
|
||||
@@ -221,7 +161,7 @@ class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
"""c.Set(a, b) → a = b(赋值语义,a 为左值)"""
|
||||
if cl is None:
|
||||
return None
|
||||
cargs: rawptr[list[rawptr[ast.AST]]] = cl.args
|
||||
cargs: list[ast.AST*]* = cl.args
|
||||
if cargs is None or len(cargs) < 2:
|
||||
return None
|
||||
a_node: rawptr[ast.AST] = cargs.get(0)
|
||||
@@ -236,7 +176,7 @@ class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
if d_call.func is not None and d_call.func.kind() == ast.ASTKind.Attribute:
|
||||
d_at: rawptr[ast.Attribute] = rawptr[ast.Attribute](d_call.func)
|
||||
if d_at.attr is not None and string.strcmp(d_at.attr, "Deref") == 0:
|
||||
d_args: rawptr[list[rawptr[ast.AST]]] = d_call.args
|
||||
d_args: list[ast.AST*]* = d_call.args
|
||||
if d_args is not None and len(d_args) >= 1:
|
||||
ptr_val: rawptr[llvmlite.Value] = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, d_args.get(0), None, 0, trans)
|
||||
@@ -345,7 +285,7 @@ class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
"""c.Addr(var) → 返回变量的 alloca 指针(不 load)"""
|
||||
if cl is None:
|
||||
return None
|
||||
cargs: rawptr[list[rawptr[ast.AST]]] = cl.args
|
||||
cargs: list[ast.AST*]* = cl.args
|
||||
if cargs is None or len(cargs) < 1:
|
||||
return None
|
||||
|
||||
@@ -385,6 +325,14 @@ class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
if nl_addr is not None:
|
||||
return nl_addr
|
||||
return_var: rawptr[llvmlite.Value] = self.Gen.VarGen.lookup_var(trans.SymTab, nm.id)
|
||||
# REPL 模式(M2)会话变量取址:c.Addr(x) → ctx 内该槽的地址(地址同一性)。
|
||||
# 位置在局部查找之后(片段自己声明的局部名优先,与读路径同序)、
|
||||
# 模块全局/函数引用之前。守卫 trans.ReplCtx:非 REPL 恒 None ⇒ 不变。
|
||||
if return_var is None and trans is not None and trans.ReplCtx is not None:
|
||||
sess_addr: rawptr[llvmlite.Value] = self.Gen.VarGen.repl_try_addr(
|
||||
trans, nm.id, arg0)
|
||||
if sess_addr is not None:
|
||||
return sess_addr
|
||||
if return_var is None and mod is not None:
|
||||
# 模块全局变量 c.Addr(模块全局) → 返回全局变量指针:必须经 make_global_ref 转成带引号的 Ptr(Ty) 引用(直接返回 GlobalVariable 节点时其 Ty 是 pointee、Name 无 @ 引号,参与 ptrtoint 会渲染成 "ptrtoint void to i64")
|
||||
gv_ref_nm: rawptr[llvmlite.GlobalVariable] = self.Gen.ExprGenAttr.find_global_in_module(mod, nm.id)
|
||||
@@ -646,7 +594,7 @@ class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
"""c.Load(a, b) → *a = *b(加载 b 的值,存储到 a)"""
|
||||
if cl is None:
|
||||
return None
|
||||
cargs: rawptr[list[rawptr[ast.AST]]] = cl.args
|
||||
cargs: list[ast.AST*]* = cl.args
|
||||
if cargs is None or len(cargs) < 2:
|
||||
return None
|
||||
|
||||
@@ -1061,7 +1009,7 @@ class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
if cl is None:
|
||||
return None
|
||||
|
||||
cargs: rawptr[list[rawptr[ast.AST]]] = cl.args
|
||||
cargs: list[ast.AST*]* = cl.args
|
||||
if cargs is None or len(cargs) < 1:
|
||||
return None
|
||||
|
||||
@@ -1117,7 +1065,7 @@ class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
|
||||
if tk == ast.ASTKind.JoinedStr:
|
||||
js: rawptr[ast.JoinedStr] = rawptr[ast.JoinedStr](tmpl_node)
|
||||
jvalues: rawptr[list[rawptr[ast.AST]]] = js.values
|
||||
jvalues: list[ast.AST*]* = js.values
|
||||
if jvalues is not None:
|
||||
jvlen: sizet = len(jvalues)
|
||||
for vi in range(jvlen):
|
||||
@@ -1144,7 +1092,7 @@ class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
else:
|
||||
continue
|
||||
|
||||
fargs: rawptr[list[rawptr[ast.AST]]] = fcall.args
|
||||
fargs: list[ast.AST*]* = fcall.args
|
||||
if fargs is None or len(fargs) < 1:
|
||||
continue
|
||||
|
||||
@@ -1237,7 +1185,7 @@ class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
# ============================================================
|
||||
# 2. 解析关键字参数 out=/inp=/op=/clobber=
|
||||
# ============================================================
|
||||
keywords: rawptr[list[rawptr[ast.AST]]] = cl.keywords
|
||||
keywords: list[ast.AST*]* = cl.keywords
|
||||
if keywords is not None:
|
||||
kwlen: sizet = len(keywords)
|
||||
for ki in range(kwlen):
|
||||
@@ -1251,7 +1199,7 @@ class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
if kwk != ast.ASTKind.List:
|
||||
continue
|
||||
out_lst: rawptr[ast.List] = rawptr[ast.List](kw.value)
|
||||
out_elts: rawptr[list[rawptr[ast.AST]]] = out_lst.elts
|
||||
out_elts: list[ast.AST*]* = out_lst.elts
|
||||
if out_elts is None:
|
||||
continue
|
||||
oelen: sizet = len(out_elts)
|
||||
@@ -1263,7 +1211,7 @@ class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
oattr: str = self._asm_is_c_call(ocall)
|
||||
if oattr is None or string.strcmp(oattr, "AsmOut") != 0:
|
||||
continue
|
||||
oargs: rawptr[list[rawptr[ast.AST]]] = ocall.args
|
||||
oargs: list[ast.AST*]* = ocall.args
|
||||
if oargs is None or len(oargs) < 1:
|
||||
continue
|
||||
oval_node: rawptr[ast.AST] = oargs.get(0)
|
||||
@@ -1294,7 +1242,7 @@ class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
if kwk != ast.ASTKind.List:
|
||||
continue
|
||||
in_lst: rawptr[ast.List] = rawptr[ast.List](kw.value)
|
||||
in_elts: rawptr[list[rawptr[ast.AST]]] = in_lst.elts
|
||||
in_elts: list[ast.AST*]* = in_lst.elts
|
||||
if in_elts is None:
|
||||
continue
|
||||
ielen: sizet = len(in_elts)
|
||||
@@ -1306,7 +1254,7 @@ class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
iattr: str = self._asm_is_c_call(icall)
|
||||
if iattr is None or string.strcmp(iattr, "AsmInp") != 0:
|
||||
continue
|
||||
iargs: rawptr[list[rawptr[ast.AST]]] = icall.args
|
||||
iargs: list[ast.AST*]* = icall.args
|
||||
if iargs is None or len(iargs) < 1:
|
||||
continue
|
||||
ival_node: rawptr[ast.AST] = iargs.get(0)
|
||||
@@ -1325,7 +1273,7 @@ class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
if kwk != ast.ASTKind.List:
|
||||
continue
|
||||
cl_lst: rawptr[ast.List] = rawptr[ast.List](kw.value)
|
||||
cl_elts: rawptr[list[rawptr[ast.AST]]] = cl_lst.elts
|
||||
cl_elts: list[ast.AST*]* = cl_lst.elts
|
||||
if cl_elts is None:
|
||||
continue
|
||||
clen: sizet = len(cl_elts)
|
||||
@@ -1349,7 +1297,7 @@ class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
pos_node: rawptr[ast.AST] = cargs.get(1)
|
||||
if pos_node is not None and pos_node.kind() == ast.ASTKind.List:
|
||||
pos_lst: rawptr[ast.List] = rawptr[ast.List](pos_node)
|
||||
pos_elts: rawptr[list[rawptr[ast.AST]]] = pos_lst.elts
|
||||
pos_elts: list[ast.AST*]* = pos_lst.elts
|
||||
if pos_elts is not None:
|
||||
plen: sizet = len(pos_elts)
|
||||
for pi in range(plen):
|
||||
@@ -1501,7 +1449,7 @@ class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
tk2: int = tmpl_node.kind()
|
||||
if tk2 == ast.ASTKind.JoinedStr:
|
||||
js2: rawptr[ast.JoinedStr] = rawptr[ast.JoinedStr](tmpl_node)
|
||||
jvalues2: rawptr[list[rawptr[ast.AST]]] = js2.values
|
||||
jvalues2: list[ast.AST*]* = js2.values
|
||||
if jvalues2 is not None:
|
||||
jvlen2: sizet = len(jvalues2)
|
||||
fv_fi: int = 0
|
||||
@@ -1696,7 +1644,7 @@ class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
if cl is None or builder is None or pool is None or trans is None:
|
||||
return None
|
||||
|
||||
cargs: rawptr[list[rawptr[ast.AST]]] = cl.args
|
||||
cargs: list[ast.AST*]* = cl.args
|
||||
if cargs is None or len(cargs) < 1:
|
||||
self.Gen.TypeGenErr.fatal_error(cl, "c.LLVMIR 缺少模板参数", "TypeError")
|
||||
|
||||
@@ -1726,7 +1674,7 @@ class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
|
||||
if tk == ast.ASTKind.JoinedStr:
|
||||
js: rawptr[ast.JoinedStr] = rawptr[ast.JoinedStr](first_arg)
|
||||
jvalues: rawptr[list[rawptr[ast.AST]]] = js.values
|
||||
jvalues: list[ast.AST*]* = js.values
|
||||
if jvalues is not None:
|
||||
jvlen: sizet = len(jvalues)
|
||||
for vi in range(jvlen):
|
||||
@@ -1751,7 +1699,7 @@ class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
fcall: rawptr[ast.Call] = rawptr[ast.Call](fexpr)
|
||||
attr_nm: str = self._asm_is_c_call(fcall)
|
||||
if attr_nm is not None:
|
||||
fargs: rawptr[list[rawptr[ast.AST]]] = fcall.args
|
||||
fargs: list[ast.AST*]* = fcall.args
|
||||
if fargs is None or len(fargs) < 1:
|
||||
continue
|
||||
val_node: rawptr[ast.AST] = fargs.get(0)
|
||||
|
||||
@@ -724,7 +724,7 @@ class CallGenCall(CallGenBase.CallGenBase):
|
||||
case _:
|
||||
pass
|
||||
if lb_obj is not None:
|
||||
lb_cargs: rawptr[list[rawptr[ast.AST]]] = cl.args
|
||||
lb_cargs: list[ast.AST*]* = cl.args
|
||||
lb_can: sizet = 0
|
||||
if lb_cargs is not None:
|
||||
lb_can = len(lb_cargs)
|
||||
@@ -1191,11 +1191,11 @@ class CallGenCall(CallGenBase.CallGenBase):
|
||||
"TypeError")
|
||||
|
||||
# 翻译调用参数
|
||||
cargs: rawptr[list[rawptr[ast.AST]]] = cl.args
|
||||
cargs: list[ast.AST*]* = cl.args
|
||||
can: sizet = 0
|
||||
if cargs is not None:
|
||||
can = len(cargs)
|
||||
kw_calls: rawptr[list[rawptr[ast.AST]]] = cl.keywords
|
||||
kw_calls: list[ast.AST*]* = cl.keywords
|
||||
kwc: sizet = 0
|
||||
if kw_calls is not None:
|
||||
kwc = len(kw_calls)
|
||||
@@ -1689,7 +1689,7 @@ class CallGenCall(CallGenBase.CallGenBase):
|
||||
cl: rawptr[ast.Call],
|
||||
lm_name: str,
|
||||
lm_obj: rawptr[llvmlite.Value],
|
||||
cargs: rawptr[list[rawptr[ast.AST]]],
|
||||
cargs: list[ast.AST*]*,
|
||||
can: sizet,
|
||||
trans: rawptr[HT.Translator]) -> rawptr[llvmlite.Value]:
|
||||
"""翻译 list 内置方法调用,返回 call 结果 Value(void 方法返回 None)"""
|
||||
@@ -2033,7 +2033,7 @@ class CallGenCall(CallGenBase.CallGenBase):
|
||||
if mangled_sp is not None:
|
||||
call_name = mangled_sp
|
||||
# 5. 翻译参数 + 按形参 coerce(self 是形参 0,第 ai 个实参对应形参 ai+1)
|
||||
cargs_sp: rawptr[list[rawptr[ast.AST]]] = cl.args
|
||||
cargs_sp: list[ast.AST*]* = cl.args
|
||||
can_sp: sizet = 0
|
||||
if cargs_sp is not None:
|
||||
can_sp = len(cargs_sp)
|
||||
|
||||
@@ -111,7 +111,7 @@ class CallGenCtor(CallGenBase.CallGenBase):
|
||||
mod: rawptr[llvmlite.LLVMModule],
|
||||
struct_ty: rawptr[llvmlite.LLVMType],
|
||||
class_name: str,
|
||||
cargs: rawptr[list[rawptr[ast.AST]]],
|
||||
cargs: list[ast.AST*]*,
|
||||
can: sizet,
|
||||
trans: rawptr[HT.Translator]) -> rawptr[llvmlite.Value]:
|
||||
"""结构体构造函数:按字段顺序 store 参数值,返回结构体值
|
||||
@@ -361,7 +361,7 @@ class CallGenCtor(CallGenBase.CallGenBase):
|
||||
class_name: str,
|
||||
variant_name: str,
|
||||
tag_value: int,
|
||||
cargs: rawptr[list[rawptr[ast.AST]]],
|
||||
cargs: list[ast.AST*]*,
|
||||
can: sizet,
|
||||
trans: rawptr[HT.Translator]) -> rawptr[llvmlite.Value]:
|
||||
"""构造 REnum 变体实例,返回指向 alloca 的指针
|
||||
@@ -462,9 +462,9 @@ class CallGenCtor(CallGenBase.CallGenBase):
|
||||
mod: rawptr[llvmlite.LLVMModule],
|
||||
struct_ty: rawptr[llvmlite.LLVMType],
|
||||
class_name: str,
|
||||
cargs: rawptr[list[rawptr[ast.AST]]],
|
||||
cargs: list[ast.AST*]*,
|
||||
can: sizet,
|
||||
keywords: rawptr[list[rawptr[ast.AST]]],
|
||||
keywords: list[ast.AST*]*,
|
||||
kw_count: sizet,
|
||||
trans: rawptr[HT.Translator]) -> rawptr[llvmlite.Value]:
|
||||
"""结构体构造函数(关键字参数版本)"""
|
||||
@@ -791,7 +791,7 @@ class CallGenCtor(CallGenBase.CallGenBase):
|
||||
tn: str = None
|
||||
if k == ast.ASTKind.Tuple:
|
||||
tp: rawptr[ast.Tuple] = rawptr[ast.Tuple](slice_node)
|
||||
elts: rawptr[list[rawptr[ast.AST]]] = tp.elts
|
||||
elts: list[ast.AST*]* = tp.elts
|
||||
if elts is not None:
|
||||
n: sizet = len(elts)
|
||||
i: sizet
|
||||
@@ -922,7 +922,7 @@ class CallGenCtor(CallGenBase.CallGenBase):
|
||||
return self._annotation_refers_type_param(bop_a.right, tp_name)
|
||||
return 0
|
||||
|
||||
def _get_ctor_init_params(self, class_name: str) -> rawptr[list[rawptr[ast.AST]]]:
|
||||
def _get_ctor_init_params(self, class_name: str) -> list[ast.AST*]*:
|
||||
"""取泛型类模板 __init__ 的形参列表(含 self,形参 0)
|
||||
|
||||
模板不存在 / 无 __init__ / args 形态不可用 → None。
|
||||
@@ -937,7 +937,7 @@ class CallGenCtor(CallGenBase.CallGenBase):
|
||||
template_cd: rawptr[ast.ClassDef] = self.Gen.ClassGenGeneric._find_generic_template(class_name)
|
||||
if template_cd is None or template_cd.children is None:
|
||||
return None
|
||||
children: rawptr[list[rawptr[ast.AST]]] = template_cd.children
|
||||
children: list[ast.AST*]* = template_cd.children
|
||||
cn: sizet = len(children)
|
||||
ci: sizet
|
||||
for ci in range(cn):
|
||||
@@ -967,7 +967,7 @@ class CallGenCtor(CallGenBase.CallGenBase):
|
||||
"""
|
||||
if class_name is None or tp_name is None:
|
||||
return -1
|
||||
plist: rawptr[list[rawptr[ast.AST]]] = self._get_ctor_init_params(class_name)
|
||||
plist: list[ast.AST*]* = self._get_ctor_init_params(class_name)
|
||||
if plist is None:
|
||||
return -1
|
||||
pn: sizet = len(plist)
|
||||
@@ -1011,7 +1011,7 @@ class CallGenCtor(CallGenBase.CallGenBase):
|
||||
"""
|
||||
if class_name is None or kw_name is None:
|
||||
return -1
|
||||
plist_sb: rawptr[list[rawptr[ast.AST]]] = self._get_ctor_init_params(class_name)
|
||||
plist_sb: list[ast.AST*]* = self._get_ctor_init_params(class_name)
|
||||
if plist_sb is None:
|
||||
return -1
|
||||
pn_sb: sizet = len(plist_sb)
|
||||
@@ -1029,7 +1029,7 @@ class CallGenCtor(CallGenBase.CallGenBase):
|
||||
|
||||
def _find_ctor_type_param_kw_arg_index(self, class_name: str,
|
||||
tp_name: str,
|
||||
keywords: rawptr[list[rawptr[ast.AST]]],
|
||||
keywords: list[ast.AST*]*,
|
||||
kw_count: sizet,
|
||||
pos_count: int) -> int:
|
||||
"""仅关键字实参的泛型构造:类型形参 tp_name 对应的关键字实参下标
|
||||
@@ -1051,7 +1051,7 @@ class CallGenCtor(CallGenBase.CallGenBase):
|
||||
return -1 # 未找到,或落在 self 位(0 不是实参)
|
||||
if pi_kw - 1 < pos_count:
|
||||
return -1 # 该形参位已被位置实参占用
|
||||
plist_kw: rawptr[list[rawptr[ast.AST]]] = self._get_ctor_init_params(class_name)
|
||||
plist_kw: list[ast.AST*]* = self._get_ctor_init_params(class_name)
|
||||
if plist_kw is None:
|
||||
return -1
|
||||
pa_kw: rawptr[ast.AST] = plist_kw.get(sizet(pi_kw))
|
||||
@@ -1079,10 +1079,11 @@ class CallGenCtor(CallGenBase.CallGenBase):
|
||||
场景:`s: Stack[int] = Stack()`(__init__ 无参 ⇒ 实参推断不到 T)、
|
||||
`def f() -> Stack[int]: return Stack()`。注解里已显式写出 T,必须按它
|
||||
特化——这不是"取不到就默认 int"的兜底,而是用户显式写下的类型实参。
|
||||
来源(两者都要求本次 Call 是注解语句的**直接值**,identity 判定先例:
|
||||
CallGenCBuiltin 的 CurAssignNode 判定 L122-125):
|
||||
来源(两者都要求本次 Call 是注解语句的**直接值**,判据即下方 ① 的
|
||||
identity 比较):
|
||||
① trans.CurAssignAnnot:AnnAssign 赋值目标注解(AssignGenMixin 在
|
||||
翻译 RHS 前写入,L1760)+ trans.CurAssignNode 为本次 Call;
|
||||
翻译 RHS 前写入,四处 set:主分支 / global / mod_glob / nonlocal)
|
||||
+ trans.CurAssignNode 为本次 Call;
|
||||
② trans.CurFuncRetAnnot:当前函数返回注解(FuncGenDef 进入函数体时
|
||||
写入)+ trans.CurRetNode 为本次 Call。
|
||||
注解 → 类型实参的解析复用 _extract_type_args_from_slice(与
|
||||
@@ -1162,11 +1163,11 @@ class CallGenCtor(CallGenBase.CallGenBase):
|
||||
return None
|
||||
|
||||
# 翻译实参为参数指针数组(extra_args[slot] = Value 指针):位置实参 → 槽 0..can-1;关键字实参 → 按 __init__ 形参名定位槽位(与 _find_ctor_type_param_kw_arg_index 共用同一套形参遍历)。位置实参优先,关键字不可按出现顺序追加——乱序会串位
|
||||
cargs: rawptr[list[rawptr[ast.AST]]] = cl.args
|
||||
cargs: list[ast.AST*]* = cl.args
|
||||
can: sizet = 0
|
||||
if cargs is not None:
|
||||
can = len(cargs)
|
||||
keywords: rawptr[list[rawptr[ast.AST]]] = cl.keywords
|
||||
keywords: list[ast.AST*]* = cl.keywords
|
||||
kw_count: sizet = 0
|
||||
if keywords is not None:
|
||||
kw_count = len(keywords)
|
||||
|
||||
@@ -41,7 +41,7 @@ class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
func_count: int,
|
||||
trans: rawptr[HT.Translator],
|
||||
func_name: str,
|
||||
cargs: rawptr[list[rawptr[ast.AST]]],
|
||||
cargs: list[ast.AST*]*,
|
||||
can: sizet,
|
||||
hit_box: t.CPtr = None) -> rawptr[llvmlite.Value]:
|
||||
"""super()/ctraits 编译期检测(未命中返回 None)
|
||||
@@ -77,7 +77,7 @@ class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
ct_nm: rawptr[ast.Name] = rawptr[ast.Name](ct_at.value)
|
||||
if ct_nm.id is not None and string.strcmp(ct_nm.id, "ctraits") == 0 \
|
||||
and string.strcmp(func_name, "isptr") == 0:
|
||||
ct_args: rawptr[list[rawptr[ast.AST]]] = cl.args
|
||||
ct_args: list[ast.AST*]* = cl.args
|
||||
if ct_args is not None and len(ct_args) >= 1:
|
||||
ct_arg0: rawptr[ast.AST] = ct_args.get(0)
|
||||
if ct_arg0 is not None and ct_arg0.kind() == ast.ASTKind.Name:
|
||||
@@ -97,7 +97,7 @@ class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
func_count: int,
|
||||
trans: rawptr[HT.Translator],
|
||||
func_name: str,
|
||||
cargs: rawptr[list[rawptr[ast.AST]]],
|
||||
cargs: list[ast.AST*]*,
|
||||
can: sizet,
|
||||
hit_box: t.CPtr = None) -> rawptr[llvmlite.Value]:
|
||||
"""c.Deref/Asm/LLVMIR 等特殊调用(未命中返回 None)
|
||||
@@ -146,7 +146,7 @@ class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
elif string.strcmp(func_name, "CIf") == 0:
|
||||
# 运行时 c.CIf(expr)(编译期求值失败回退):expr 与 0 比较得到 i1
|
||||
# 对齐 TPC HandlesExprCall.py L2434-2444
|
||||
cif_args: rawptr[list[rawptr[ast.AST]]] = cl.args
|
||||
cif_args: list[ast.AST*]* = cl.args
|
||||
if cif_args is not None and len(cif_args) >= 1:
|
||||
cif_arg_val: rawptr[llvmlite.Value] = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, cif_args.get(0), funcs_ptr, func_count, trans)
|
||||
@@ -201,7 +201,7 @@ class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
func_count: int,
|
||||
trans: rawptr[HT.Translator],
|
||||
func_name: str,
|
||||
cargs: rawptr[list[rawptr[ast.AST]]],
|
||||
cargs: list[ast.AST*]*,
|
||||
can: sizet) -> rawptr[llvmlite.Value]:
|
||||
"""stdarg 糖 + str/int/bool 内置强转(未命中返回 None)"""
|
||||
# stdarg 糖函数处理: va_arg / arg / va_start / va_end
|
||||
@@ -290,7 +290,7 @@ class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
func_count: int,
|
||||
trans: rawptr[HT.Translator],
|
||||
func_name: str,
|
||||
cargs: rawptr[list[rawptr[ast.AST]]],
|
||||
cargs: list[ast.AST*]*,
|
||||
can: sizet) -> rawptr[llvmlite.Value]:
|
||||
"""t.XXX / typedef 类型转换(未命中返回 None)"""
|
||||
# 检测 t.XXX 类型转换: uint64(ptr), t.CPtr(val), int(val) 等
|
||||
@@ -558,7 +558,7 @@ class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
func_count: int,
|
||||
trans: rawptr[HT.Translator],
|
||||
func_name: str,
|
||||
cargs: rawptr[list[rawptr[ast.AST]]],
|
||||
cargs: list[ast.AST*]*,
|
||||
can: sizet) -> rawptr[llvmlite.Value]:
|
||||
"""__sizeof__/len/isinstance 内置(未命中返回 None)"""
|
||||
# 检测 ClassName.__sizeof__() — 返回结构体大小常量(i64)
|
||||
@@ -1010,7 +1010,7 @@ class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
func_count: int,
|
||||
trans: rawptr[HT.Translator],
|
||||
func_name: str,
|
||||
cargs: rawptr[list[rawptr[ast.AST]]],
|
||||
cargs: list[ast.AST*]*,
|
||||
can: sizet,
|
||||
hit_box: t.CPtr = None) -> rawptr[llvmlite.Value]:
|
||||
"""静态类/方法调用/表达式接收者/self.field/list 内置(未命中返回 None)
|
||||
@@ -1151,6 +1151,50 @@ class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
if st_res2 is not None:
|
||||
return st_res2
|
||||
|
||||
# [M4·REPL 专用分支] 会话变量接收者的方法调用:`obj.m(args)` 的 obj 是**会话
|
||||
# 变量**时,其值在 ctx 槽里、不在 SymTab ⇒ 上面的 lookup_var 分支恒不命中
|
||||
# (本次之前:整个分派都靠 SymTab,跨片段的 `p.get()` 直接落空)。此处按
|
||||
# 会话表判定:命中即取接收者(PTR 条目取槽内指针值;STRUCT 条目取**槽地址**
|
||||
# = 对象自身地址,正是 self 需要的形态),再用接收者类型的类名走同一条
|
||||
# `_translate_method_call`(符号 <sha1>.<类>.<方法>、返回类型经 text.ll/vpi)。
|
||||
# 守卫 trans.ReplCtx is not None ⇒ 非 REPL 编译路径一行不经过(逐字不变)。
|
||||
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute \
|
||||
and trans is not None and trans.ReplCtx is not None and pool is not None:
|
||||
rp_at: rawptr[ast.Attribute] = rawptr[ast.Attribute](cl.func)
|
||||
if rp_at is not None and rp_at.value is not None and rp_at.attr is not None:
|
||||
if rp_at.value.kind() == ast.ASTKind.Name:
|
||||
rp_nm: rawptr[ast.Name] = rawptr[ast.Name](rp_at.value)
|
||||
if rp_nm.id is not None:
|
||||
rp_ent: rawptr[GenTypes.ReplVarEntry] = \
|
||||
self.Gen.VarGen.repl_find_entry(trans.ReplCtx, rp_nm.id)
|
||||
if rp_ent is not None:
|
||||
rp_val: rawptr[llvmlite.Value] = None
|
||||
if rp_ent.TyTag == GenTypes.REPL_TY_STRUCT:
|
||||
# 结构体值内联在槽里:槽地址即对象地址(self)
|
||||
rp_val = self.Gen.VarGen.repl_try_addr(trans, rp_nm.id, cl)
|
||||
else:
|
||||
rp_val = self.Gen.VarGen.repl_try_read(trans, rp_nm.id, cl)
|
||||
rp_cls: str = None
|
||||
if rp_val is not None and rp_val.Ty is not None:
|
||||
rp_sty: rawptr[llvmlite.LLVMType] = \
|
||||
self.Gen.StructGen.get_struct_type_from_value(rp_val)
|
||||
if rp_sty is not None:
|
||||
rp_cls = self.Gen.StructGen.get_class_name_by_type(
|
||||
pool, rp_sty)
|
||||
if rp_cls is not None:
|
||||
rp_obj: rawptr[llvmlite.Value] = rp_val
|
||||
if self.Gen.ExprGenBase.is_ptr_type(rp_val.Ty) != 0 \
|
||||
and rp_val.Ty.Pointee is not None \
|
||||
and self.Gen.ExprGenBase.is_ptr_type(rp_val.Ty.Pointee) != 0:
|
||||
rp_obj = llvmlite.build_load(builder, rp_val.Ty, rp_val)
|
||||
if rp_obj is not None:
|
||||
if hit_box is not None:
|
||||
hit_box[0] = 1
|
||||
return self.Gen.CallGenCall._translate_method_call(
|
||||
pool, builder, mod, rp_cls, rp_at.attr, rp_obj, cl, trans)
|
||||
# 会话变量命中但接收者不是结构体类(如 int/str/其它指针):
|
||||
# 不拦截、不置 hit,交给下方既有分支(list 内置/FakeDuck 等)
|
||||
|
||||
# 检测方法调用: obj.method(args)
|
||||
# 当 cl.func 是 Attribute 且 obj 是已注册的结构体变量时,翻译为方法调用
|
||||
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
|
||||
|
||||
@@ -132,7 +132,7 @@ class CallGenFd(CallGenBase.CallGenBase):
|
||||
llvmlite.value_set_next(fd_self, None)
|
||||
fd_head: rawptr[llvmlite.Value] = fd_self
|
||||
fd_tail: rawptr[llvmlite.Value] = fd_self
|
||||
fd_args: rawptr[list[rawptr[ast.AST]]] = cl.args
|
||||
fd_args: list[ast.AST*]* = cl.args
|
||||
fd_can: int = 0
|
||||
if fd_args is not None:
|
||||
fd_can = len(fd_args)
|
||||
|
||||
@@ -14,6 +14,7 @@ import lib.core.CompilerFactory as CompilerFactory
|
||||
import lib.core.Gen.Type.TypeSpec as TSpec
|
||||
|
||||
from . import CallGenCBuiltin
|
||||
from . import CallGenBase
|
||||
|
||||
|
||||
# ============================================================
|
||||
@@ -28,10 +29,12 @@ from . import CallGenCBuiltin
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 常量(与 HandlesExprCall 保持一致,本地副本避免跨模块 CDefine 查找 bug)
|
||||
# 常量(与 TPC 侧 HandlesExprCall 保持一致)
|
||||
#
|
||||
# GLOBAL_FUNC_MAX / GLOBAL_DEFAULTS_MAX / MAX_CLOSURE_NAMES /
|
||||
# MAX_FUNC_PTR_SIGS / ISINSTANCE_CLASS_MAX:唯一来源在 CallGenBase.vp
|
||||
# (本文件是唯一消费方,经 CallGenBase.<NAME> 取值,本地不再保留副本)。
|
||||
# ============================================================
|
||||
GLOBAL_FUNC_MAX: t.CDefine = 8192
|
||||
GLOBAL_DEFAULTS_MAX: t.CDefine = 4096
|
||||
_CEXPORT_MAX: t.CDefine = 256
|
||||
ASM_MAX_OPERANDS: t.CDefine = 16
|
||||
ASM_TEXT_BUF_SIZE: t.CDefine = 2048
|
||||
@@ -40,17 +43,13 @@ ASM_ARGS_BUF_SIZE: t.CDefine = 512
|
||||
ASM_LINE_BUF_SIZE: t.CDefine = 4096
|
||||
LLVMIR_MAX_OPS: t.CDefine = 16
|
||||
LLVMIR_TEMPLATE_BUF: t.CDefine = 512
|
||||
# 闭包名表大小(原 HandlesExprCall 模块级常量)
|
||||
MAX_CLOSURE_NAMES: t.CDefine = 128
|
||||
# 函数指针签名表大小(原 HandlesExprCall 模块级常量)
|
||||
MAX_FUNC_PTR_SIGS: t.CDefine = 64
|
||||
# isinstance 子类收集上限(防数组越界;t.CDefine 注解由 TPC 解析为 i32)
|
||||
ISINSTANCE_CLASS_MAX: t.CDefine = 64
|
||||
|
||||
# ============================================================
|
||||
# 全局函数表名索引(名 → 槽下标,开放寻址 | 线性探测)
|
||||
#
|
||||
# 槽数 = 2 * GLOBAL_FUNC_MAX(2 的幂,负载 < 0.5,线性探测必然终止)。
|
||||
# 槽数 = 2 * CallGenBase.GLOBAL_FUNC_MAX(2 的幂,负载 < 0.5,线性探测必然终止)。
|
||||
# 值写成字面量 16384:模块级 t.CDefine 初始化式不能引用跨模块常量
|
||||
# (跨模块 t.CDefine 只能在函数体内读),故与 CallGenBase.GLOBAL_FUNC_MAX 手工保持 2 倍关系。
|
||||
# 槽存槽下标 + 1(0=空槽)。GlobalFuncs 在 PermPool 定长分配、只追加不重排、
|
||||
# 从不 reset ⇒ 槽下标稳定;Built == GlobalFuncCount 才可信。
|
||||
# ============================================================
|
||||
@@ -402,7 +401,7 @@ class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
|
||||
arr[0] = sizet(at.attr)
|
||||
elif k == ast.ASTKind.Tuple:
|
||||
tp: rawptr[ast.Tuple] = rawptr[ast.Tuple](node)
|
||||
elts: rawptr[list[rawptr[ast.AST]]] = tp.elts
|
||||
elts: list[ast.AST*]* = tp.elts
|
||||
if elts is not None:
|
||||
n: sizet = len(elts)
|
||||
for i in range(n):
|
||||
@@ -431,14 +430,14 @@ class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
|
||||
"""反向 BFS 收集目标类及全部子类(含自身,仅 HasVTable==1),返回 0 结尾数组"""
|
||||
if class_name is None:
|
||||
return None
|
||||
names: sizet | t.CPtr = pool.alloc(8 * (ISINSTANCE_CLASS_MAX + 1))
|
||||
queue: sizet | t.CPtr = pool.alloc(8 * ISINSTANCE_CLASS_MAX)
|
||||
visited: sizet | t.CPtr = pool.alloc(8 * ISINSTANCE_CLASS_MAX)
|
||||
names: sizet | t.CPtr = pool.alloc(8 * (CallGenBase.ISINSTANCE_CLASS_MAX + 1))
|
||||
queue: sizet | t.CPtr = pool.alloc(8 * CallGenBase.ISINSTANCE_CLASS_MAX)
|
||||
visited: sizet | t.CPtr = pool.alloc(8 * CallGenBase.ISINSTANCE_CLASS_MAX)
|
||||
if names is None or queue is None or visited is None:
|
||||
return None
|
||||
string.memset(names, 0, 8 * (ISINSTANCE_CLASS_MAX + 1))
|
||||
string.memset(queue, 0, 8 * ISINSTANCE_CLASS_MAX)
|
||||
string.memset(visited, 0, 8 * ISINSTANCE_CLASS_MAX)
|
||||
string.memset(names, 0, 8 * (CallGenBase.ISINSTANCE_CLASS_MAX + 1))
|
||||
string.memset(queue, 0, 8 * CallGenBase.ISINSTANCE_CLASS_MAX)
|
||||
string.memset(visited, 0, 8 * CallGenBase.ISINSTANCE_CLASS_MAX)
|
||||
qcount: int = 1
|
||||
outcount: int = 0
|
||||
vcount: int = 0
|
||||
@@ -459,12 +458,12 @@ class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
|
||||
break
|
||||
if dup != 0:
|
||||
continue
|
||||
if vcount < ISINSTANCE_CLASS_MAX:
|
||||
if vcount < CallGenBase.ISINSTANCE_CLASS_MAX:
|
||||
visited[vcount] = sizet(cur)
|
||||
vcount += 1
|
||||
centry: rawptr[GenTypes.StructEntry] = self.Gen.StructGen.find_struct(cur)
|
||||
if centry is not None and centry.HasVTable != 0:
|
||||
if outcount < ISINSTANCE_CLASS_MAX:
|
||||
if outcount < CallGenBase.ISINSTANCE_CLASS_MAX:
|
||||
names[outcount] = sizet(cur)
|
||||
outcount += 1
|
||||
# 子类入队:遍历全部已注册 struct,ParentNames 含 cur 者
|
||||
@@ -483,7 +482,7 @@ class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
|
||||
if pa != 0:
|
||||
pn: str = (str | t.CPtr)(pa)
|
||||
if pn is not None and string.strcmp(pn, cur) == 0:
|
||||
if qcount < ISINSTANCE_CLASS_MAX:
|
||||
if qcount < CallGenBase.ISINSTANCE_CLASS_MAX:
|
||||
queue[qcount] = sizet(e2.Name)
|
||||
qcount += 1
|
||||
break
|
||||
@@ -574,7 +573,7 @@ class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
|
||||
builder: rawptr[llvmlite.IRBuilder],
|
||||
mod: rawptr[llvmlite.LLVMModule],
|
||||
closure_alloca: rawptr[llvmlite.Value],
|
||||
cargs: rawptr[list[rawptr[ast.AST]]],
|
||||
cargs: list[ast.AST*]*,
|
||||
can: sizet,
|
||||
trans: rawptr[HT.Translator] = None) -> rawptr[llvmlite.Value]:
|
||||
"""通过闭包指针间接调用(支持带参 lambda:i32(i8*, args...))"""
|
||||
@@ -663,9 +662,9 @@ class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
|
||||
def _ensure_closure_names(self) -> int:
|
||||
"""确保闭包名表已分配,0 失败"""
|
||||
if self.ClosureNames is not None: return 1
|
||||
self.ClosureNames = CompilerFactory.factory.PermPool.alloc(64 * MAX_CLOSURE_NAMES)
|
||||
self.ClosureNames = CompilerFactory.factory.PermPool.alloc(64 * CallGenBase.MAX_CLOSURE_NAMES)
|
||||
if self.ClosureNames is None: return 0
|
||||
string.memset(self.ClosureNames, 0, 64 * MAX_CLOSURE_NAMES)
|
||||
string.memset(self.ClosureNames, 0, 64 * CallGenBase.MAX_CLOSURE_NAMES)
|
||||
return 1
|
||||
|
||||
|
||||
@@ -673,7 +672,7 @@ class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
|
||||
"""注册嵌套函数(闭包变量)名,0 成功"""
|
||||
if name is None: return 1
|
||||
if self._ensure_closure_names() == 0: return 1
|
||||
if self.ClosureCount >= MAX_CLOSURE_NAMES: return 1
|
||||
if self.ClosureCount >= CallGenBase.MAX_CLOSURE_NAMES: return 1
|
||||
idx: sizet = sizet(self.ClosureCount) * 64
|
||||
string.strncpy(self.ClosureNames + idx, name, 63)
|
||||
self.ClosureCount += 1
|
||||
@@ -695,22 +694,84 @@ class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
|
||||
"""确保函数指针签名表已分配(stdlib.malloc,懒初始化)"""
|
||||
if self.FuncptrNames is not None:
|
||||
return 1
|
||||
self.FuncptrNames = CompilerFactory.factory.PermPool.alloc(64 * MAX_FUNC_PTR_SIGS)
|
||||
self.FuncptrRets = CompilerFactory.factory.PermPool.alloc(8 * MAX_FUNC_PTR_SIGS)
|
||||
self.FuncptrNames = CompilerFactory.factory.PermPool.alloc(64 * CallGenBase.MAX_FUNC_PTR_SIGS)
|
||||
self.FuncptrRets = CompilerFactory.factory.PermPool.alloc(8 * CallGenBase.MAX_FUNC_PTR_SIGS)
|
||||
if self.FuncptrNames is None or self.FuncptrRets is None:
|
||||
return 0
|
||||
string.memset(self.FuncptrNames, 0, 64 * MAX_FUNC_PTR_SIGS)
|
||||
string.memset(self.FuncptrNames, 0, 64 * CallGenBase.MAX_FUNC_PTR_SIGS)
|
||||
return 1
|
||||
|
||||
|
||||
def register_func_ptr_sig(self, name: str,
|
||||
ret_ty: rawptr[llvmlite.LLVMType]) -> int:
|
||||
"""注册函数指针变量的返回类型签名,0 成功"""
|
||||
def _func_ptr_sig_fatal(self, pool: rawptr[memhub.MemBuddy],
|
||||
node: rawptr[ast.AST], name: str,
|
||||
ret_ty: rawptr[llvmlite.LLVMType],
|
||||
reason: str) -> None:
|
||||
"""函数指针签名登记失败 → 编译期报错(文案含变量名/返回类型/上限/处置建议)
|
||||
|
||||
原实现满表时静默 return 1:登记被丢弃后,调用点才以
|
||||
"函数指针变量 'X' 的返回类型未注册(t.Callable 注解缺失)"
|
||||
(下方 _translate_func_ptr_call:843-850)报错,定位到调用行而非登记处,
|
||||
掩盖真因(表满/重名冲突)。此处统一在登记点 fail-fast。
|
||||
fatal_error 终止编译、不返回,故调用方的返回值分支仅为防御性写法。
|
||||
"""
|
||||
cap: int = CallGenBase.MAX_FUNC_PTR_SIGS
|
||||
ret_str: str = "?"
|
||||
if ret_ty is not None:
|
||||
typed_buf: str = pool.alloc(96)
|
||||
if typed_buf is not None:
|
||||
llvmlite.TypePrint(typed_buf, 96, ret_ty, pool)
|
||||
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)
|
||||
self.Gen.TypeGenErr.fatal_error(node, msg_buf, "TypeError")
|
||||
return
|
||||
self.Gen.TypeGenErr.fatal_error(
|
||||
node, "函数指针签名表登记失败(签名表已满或变量名冲突)", "TypeError")
|
||||
|
||||
def register_func_ptr_sig(self, pool: rawptr[memhub.MemBuddy], name: str,
|
||||
ret_ty: rawptr[llvmlite.LLVMType],
|
||||
node: rawptr[ast.AST] = None) -> int:
|
||||
"""注册函数指针变量的返回类型签名,0=成功(含幂等命中)/ 1=失败(已报错终止)
|
||||
|
||||
表按**裸变量名**全局共享(PermPool,跨文件/跨阶段存活),同一变量可能被
|
||||
多轮登记(模块级:Translator.vp:568-575 的预注册遍与 translate_children
|
||||
TranslatorGenMixin.vp:130-136 各见同一 AnnAssign 一次):
|
||||
* 同名同返回类型 → 原地命中、不新增槽位(否则重复登记把表撑爆);
|
||||
* 同名不同返回类型 → 报错。既不能静默丢弃(查找返回先登记值:先翻译
|
||||
模块已按旧值生成间接调用,后登记模块却按新值,同一名字两种 ABI),
|
||||
也不能静默覆盖(先翻译模块的调用点已按旧值生成)——两者都是无声误编译;
|
||||
* 满表 → 报错(原实现静默丢弃)。
|
||||
"""
|
||||
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 内存不足)")
|
||||
return 1
|
||||
if self.FuncptrCount >= MAX_FUNC_PTR_SIGS:
|
||||
# 幂等/冲突检查:线性扫已登记裸名(FuncptrCount 上限 64,代价可忽略)
|
||||
i: sizet
|
||||
for i in range(self.FuncptrCount):
|
||||
idx_hit: sizet = sizet(i) * 64
|
||||
if string.strcmp(self.FuncptrNames + idx_hit, name) == 0:
|
||||
prev_ret: rawptr[llvmlite.LLVMType] = (
|
||||
rawptr[llvmlite.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,
|
||||
"该名字已按另一种返回类型登记过")
|
||||
return 1
|
||||
if self.FuncptrCount >= CallGenBase.MAX_FUNC_PTR_SIGS:
|
||||
self._func_ptr_sig_fatal(pool, node, name, ret_ty, "签名表已满")
|
||||
return 1
|
||||
idx: sizet = sizet(self.FuncptrCount) * 64
|
||||
# 槽位定长 64 字节,与 register_closure_name 一致用 strncpy 钳制防越界
|
||||
@@ -743,7 +804,7 @@ class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
|
||||
mod: rawptr[llvmlite.LLVMModule],
|
||||
fp_alloca: rawptr[llvmlite.Value],
|
||||
func_name: str,
|
||||
cargs: rawptr[list[rawptr[ast.AST]]],
|
||||
cargs: list[ast.AST*]*,
|
||||
can: sizet,
|
||||
trans: rawptr[HT.Translator]) -> rawptr[llvmlite.Value]:
|
||||
"""函数指针变量间接调用,返回结果 Value"""
|
||||
@@ -819,7 +880,7 @@ class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
|
||||
cl: rawptr[ast.Call],
|
||||
trans: rawptr[HT.Translator] = None) -> None:
|
||||
"""翻译 printf 调用(特殊处理格式字符串)"""
|
||||
cargs: rawptr[list[rawptr[ast.AST]]] = cl.args
|
||||
cargs: list[ast.AST*]* = cl.args
|
||||
if cargs is None:
|
||||
return
|
||||
can: sizet = len(cargs)
|
||||
@@ -880,7 +941,7 @@ class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
|
||||
cl: rawptr[ast.Call],
|
||||
trans: rawptr[HT.Translator] = None) -> None:
|
||||
"""翻译 print 调用(类型感知格式化 + 默认换行)"""
|
||||
cargs: rawptr[list[rawptr[ast.AST]]] = cl.args
|
||||
cargs: list[ast.AST*]* = cl.args
|
||||
if cargs is None:
|
||||
return
|
||||
|
||||
@@ -1119,7 +1180,7 @@ class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
|
||||
"""初始化全局函数表(用 stdlib.malloc 分配,生命周期=整个程序)"""
|
||||
if self.GlobalFuncs is not None:
|
||||
return 1
|
||||
size: sizet = GLOBAL_FUNC_MAX * GenTypes.FuncEntry.__sizeof__()
|
||||
size: sizet = CallGenBase.GLOBAL_FUNC_MAX * GenTypes.FuncEntry.__sizeof__()
|
||||
self.GlobalFuncs = CompilerFactory.factory.PermPool.alloc(size)
|
||||
if self.GlobalFuncs is None:
|
||||
return 0
|
||||
@@ -1154,7 +1215,7 @@ class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
|
||||
# 已存在则跳过(避免重复)
|
||||
if self.find_func_in_table(self.GlobalFuncs, self.GlobalFuncCount, name) is not None:
|
||||
return 0
|
||||
if self.GlobalFuncCount >= GLOBAL_FUNC_MAX:
|
||||
if self.GlobalFuncCount >= CallGenBase.GLOBAL_FUNC_MAX:
|
||||
return 1
|
||||
# 直接写入全局表(不调用 add_func_to_table,避免递归)
|
||||
entry_size: sizet = GenTypes.FuncEntry.__sizeof__()
|
||||
@@ -1281,7 +1342,7 @@ class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
|
||||
"""初始化全局默认参数表"""
|
||||
if self.GlobalDefaults is not None:
|
||||
return 1
|
||||
size: sizet = GLOBAL_DEFAULTS_MAX * GenTypes.FuncDefaultsEntry.__sizeof__()
|
||||
size: sizet = CallGenBase.GLOBAL_DEFAULTS_MAX * GenTypes.FuncDefaultsEntry.__sizeof__()
|
||||
self.GlobalDefaults = CompilerFactory.factory.PermPool.alloc(size)
|
||||
if self.GlobalDefaults is None:
|
||||
return 0
|
||||
@@ -1321,7 +1382,7 @@ class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
|
||||
# 同模块同名已存在则跳过
|
||||
if self.find_func_defaults(name, cur_sha) is not None:
|
||||
return 0
|
||||
if self.GlobalDefaultsCount >= GLOBAL_DEFAULTS_MAX:
|
||||
if self.GlobalDefaultsCount >= CallGenBase.GLOBAL_DEFAULTS_MAX:
|
||||
return 1
|
||||
entry_size: sizet = GenTypes.FuncDefaultsEntry.__sizeof__()
|
||||
entry_addr: uint64 = uint64(self.GlobalDefaults) + self.GlobalDefaultsCount * entry_size
|
||||
@@ -1359,7 +1420,7 @@ class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
|
||||
string.memset(kinds, 0, default_count * 4)
|
||||
string.memset(ints, 0, default_count * 8)
|
||||
string.memset(strs, 0, default_count * 8)
|
||||
dl: rawptr[list[rawptr[ast.AST]]] = rawptr[list[rawptr[ast.AST]]](uint64(defaults))
|
||||
dl: list[ast.AST*]* = (list[ast.AST*] | t.CPtr)(uint64(defaults))
|
||||
di: int
|
||||
for di in range(default_count):
|
||||
dnode: rawptr[ast.AST] = dl.get(di)
|
||||
|
||||
@@ -193,7 +193,7 @@ class CallGenLib(CallGenBase.CallGenBase):
|
||||
call_name: str,
|
||||
head: rawptr[llvmlite.Value],
|
||||
count: int,
|
||||
cargs: rawptr[list[rawptr[ast.AST]]] = None,
|
||||
cargs: list[ast.AST*]* = None,
|
||||
self_off: int = 0,
|
||||
trans: rawptr[HT.Translator] = None) -> rawptr[llvmlite.Value]:
|
||||
"""把跨模块调用实参 coerce 到 vpi 定义侧形参类型,返回重建的实参链
|
||||
@@ -738,9 +738,9 @@ class CallGenLib(CallGenBase.CallGenBase):
|
||||
mod: rawptr[llvmlite.LLVMModule],
|
||||
func_name: str,
|
||||
found_func: rawptr[llvmlite.Function],
|
||||
cargs: rawptr[list[rawptr[ast.AST]]],
|
||||
cargs: list[ast.AST*]*,
|
||||
can: sizet,
|
||||
keywords: rawptr[list[rawptr[ast.AST]]],
|
||||
keywords: list[ast.AST*]*,
|
||||
kw_count: sizet,
|
||||
trans: rawptr[HT.Translator]) -> rawptr[llvmlite.Value]:
|
||||
"""带关键字参数的函数调用,按参数顺序构建调用链表
|
||||
|
||||
@@ -31,10 +31,12 @@ import lib.core.Gen.GenApi as GenApi
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 常量(与 HandlesExprCall 保持一致,本地副本避免跨模块 CDefine 查找 bug)
|
||||
# 常量(与 TPC 侧 HandlesExprCall 保持一致)
|
||||
#
|
||||
# GLOBAL_FUNC_MAX / GLOBAL_DEFAULTS_MAX / MAX_CLOSURE_NAMES /
|
||||
# MAX_FUNC_PTR_SIGS / ISINSTANCE_CLASS_MAX:唯一来源在 CallGenBase.vp
|
||||
# (本文件不使用,故不留副本;消费方 CallGenLeafKit.vp 经 CallGenBase.<NAME> 引用)。
|
||||
# ============================================================
|
||||
GLOBAL_FUNC_MAX: t.CDefine = 8192
|
||||
GLOBAL_DEFAULTS_MAX: t.CDefine = 4096
|
||||
_CEXPORT_MAX: t.CDefine = 256
|
||||
ASM_MAX_OPERANDS: t.CDefine = 16
|
||||
ASM_TEXT_BUF_SIZE: t.CDefine = 2048
|
||||
@@ -43,12 +45,6 @@ ASM_ARGS_BUF_SIZE: t.CDefine = 512
|
||||
ASM_LINE_BUF_SIZE: t.CDefine = 4096
|
||||
LLVMIR_MAX_OPS: t.CDefine = 16
|
||||
LLVMIR_TEMPLATE_BUF: t.CDefine = 512
|
||||
# 闭包名表大小(原 HandlesExprCall 模块级常量)
|
||||
MAX_CLOSURE_NAMES: t.CDefine = 128
|
||||
# 函数指针签名表大小(原 HandlesExprCall 模块级常量)
|
||||
MAX_FUNC_PTR_SIGS: t.CDefine = 64
|
||||
# isinstance 子类收集上限(防数组越界;t.CDefine 注解由 TPC 解析为 i32)
|
||||
ISINSTANCE_CLASS_MAX: t.CDefine = 64
|
||||
|
||||
|
||||
# ============================================================
|
||||
@@ -75,7 +71,7 @@ class CallGenMixin(CallGenBase.CallGenBase):
|
||||
|
||||
func_name: str = self.Gen.ExprGenBase.get_func_name(cl.func)
|
||||
|
||||
cargs: rawptr[list[rawptr[ast.AST]]] = cl.args
|
||||
cargs: list[ast.AST*]* = cl.args
|
||||
can: sizet = 0
|
||||
if cargs is not None:
|
||||
can = len(cargs)
|
||||
@@ -159,7 +155,7 @@ class CallGenMixin(CallGenBase.CallGenBase):
|
||||
binop_ty: rawptr[llvmlite.LLVMType] = self.Gen.TypeGenResolve.resolve_annotation_type(
|
||||
pool, cl.func, trans._imported_modules, trans._from_imports, trans, 0)
|
||||
if binop_ty is not None:
|
||||
binop_args: rawptr[list[rawptr[ast.AST]]] = cl.args
|
||||
binop_args: list[ast.AST*]* = cl.args
|
||||
if binop_args is not None and len(binop_args) == 1:
|
||||
binop_arg_val: rawptr[llvmlite.Value] = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, binop_args.get(0), funcs_ptr, func_count, trans)
|
||||
@@ -223,7 +219,7 @@ class CallGenMixin(CallGenBase.CallGenBase):
|
||||
return None
|
||||
|
||||
# 获取关键字参数
|
||||
keywords: rawptr[list[rawptr[ast.AST]]] = cl.keywords
|
||||
keywords: list[ast.AST*]* = cl.keywords
|
||||
kw_count: sizet = 0
|
||||
if keywords is not None:
|
||||
kw_count = len(keywords)
|
||||
@@ -931,6 +927,17 @@ class CallGenMixin(CallGenBase.CallGenBase):
|
||||
if trans is not None and trans._from_imports is not None:
|
||||
if self._lookup_mod_sha1(pool, trans._from_imports, func_name, 0) is not None:
|
||||
bare_resolvable = 1
|
||||
# M3 会话函数(跨片段):名字命中会话函数表 ⇒ 同样按"可解析"占位,
|
||||
# 不 fail-fast。返回类型由下方 found_func==None 分支的
|
||||
# repl_try_session_func_call 按表内签名(宿主从定义片段 IR 解析)构造,
|
||||
# 与 _infer_external_func_ret_ty 的白名单无关;此处的 call_ret_ty 只是
|
||||
# 占位(命中后立即 return,不会用到)。
|
||||
# 守卫 trans.ReplCtx:非 REPL 恒 None ⇒ 不经过;且限定裸名(Name)——
|
||||
# 会话函数只以裸名导出,模块限定调用(mod.f)不走本表。
|
||||
if trans is not None and trans.ReplCtx is not None \
|
||||
and cl.func is not None and cl.func.kind() == ast.ASTKind.Name \
|
||||
and self.Gen.VarGen.repl_find_func_entry(trans.ReplCtx, func_name) is not None:
|
||||
bare_resolvable = 1
|
||||
call_ret_ty = self.Gen.CallGenLib._infer_external_func_ret_ty(
|
||||
pool, func_name, node, 1 - bare_resolvable)
|
||||
|
||||
@@ -991,6 +998,31 @@ class CallGenMixin(CallGenBase.CallGenBase):
|
||||
# 其他 i8* 变量按闭包调用路径处理
|
||||
return self.Gen.CallGenLeafKit.translate_closure_call(pool, builder, mod, fp_alloca,
|
||||
cargs, can, trans)
|
||||
# ---- M3:会话函数表命中 → ctx 函数指针槽取址 + 间接调用 ----
|
||||
# 位置(为什么在这里):本步位于 `if found_func is None:` 块**末尾**——
|
||||
# ① found_func 为 None ⇒ 本片段的 LLVM 模块里没有该函数的定义/前向声明
|
||||
# (会话函数定义在**先前片段**的 DLL 里,代码不在本模块内);
|
||||
# ② 放在闭包名/局部函数指针变量分支**之后** ⇒ 局部名与闭包正确地**遮蔽**
|
||||
# 会话函数(Python 的局部优先),只有"既非本模块函数/声明、又非局部/
|
||||
# 闭包/函数指针变量"的裸名才查会话函数表;
|
||||
# ③ 仍先于 from_imports 解析与"裸名调用未定义且未导入"的 fail-fast。
|
||||
# 命中后从 ctx 的函数指针槽 load 地址、按表内签名间接调用:函数代码只在
|
||||
# 定义片段里一份(不复制/不重编译),调用点只持指针。
|
||||
sfn_box: t.CPtr = None
|
||||
if trans is not None and trans.ReplCtx is not None \
|
||||
and (cl.func is None or cl.func.kind() == ast.ASTKind.Name):
|
||||
sfn_box = stdlib.malloc(4)
|
||||
if sfn_box is not None:
|
||||
sfn_box[0] = 0
|
||||
sfn_val: rawptr[llvmlite.Value] = self.Gen.VarGen.repl_try_session_func_call(
|
||||
trans, pool, builder, mod, func_name, cargs, int(can),
|
||||
int(kw_count), node, sfn_box)
|
||||
sfn_handled: int = int(sfn_box[0])
|
||||
stdlib.free(sfn_box)
|
||||
if sfn_handled != 0:
|
||||
# 命中(含命中但按 M3 规则明确报错的情形):不再走任何
|
||||
# "未定义/未导入"路径。void 会话函数返回 None 属预期。
|
||||
return sfn_val
|
||||
|
||||
# 翻译参数并链接
|
||||
# 有关键字参数且找到函数定义时,按参数名匹配
|
||||
@@ -1139,7 +1171,26 @@ class CallGenMixin(CallGenBase.CallGenBase):
|
||||
# 否则下方 _build_const_from_snapshot 读到未初始化栈垃圾指针崩溃。
|
||||
# 与 _translate_method_call 的 mdf_gd 无条件查询(L2677)保持一致。
|
||||
gd_entry: rawptr[GenTypes.FuncDefaultsEntry] = self.Gen.CallGenLeafKit.find_func_defaults(func_name, dfx_callee_sha)
|
||||
if df_defaults is None and gd_entry is not None:
|
||||
# 包重导出补查(如 json.write 实际定义在 includes/json/__writer.vp):
|
||||
# AST 侧模块名 'json' 只能解析到包 __init__ 的 SHA1,而默认参数表按
|
||||
# **定义该函数的模块 SHA1** 登记(_register_global_defaults),于是直接
|
||||
# 查不到 → 缺参填充整体跳过 → call 实参数 < declare/define 形参数 →
|
||||
# 被调函数读寄存器/栈残留垃圾(VET `json.write(pool, val, False)` 的
|
||||
# 缺省 cap 读成指针量级 → pool.alloc(巨量) → [OOM] 根因)。
|
||||
# 与下方 L1473-1480 调用名重定向同一套 re-export 解析:命中后用
|
||||
# **定义模块 SHA1** 复查默认参数表(SHA1 已校验,不会跨模块串味)。
|
||||
if gd_entry is None and dfx_callee_sha is not None:
|
||||
rr_src_dx: str = self.Gen.ImportsGen.lookup_reexport(dfx_callee_sha, func_name)
|
||||
if rr_src_dx is None:
|
||||
rr_src_dx = self._lookup_reexport_from_vpi(pool, dfx_callee_sha, func_name)
|
||||
if rr_src_dx is not None:
|
||||
rr_sha_dx: str = self._lookup_module_sha1(rr_src_dx)
|
||||
if rr_sha_dx is not None:
|
||||
gd_entry = self.Gen.CallGenLeafKit.find_func_defaults(func_name, rr_sha_dx)
|
||||
# 覆盖条件含 df_default_count<=0:调用方函数表可能命中一条同名条目但
|
||||
# Defaults 为空/默认值为 0 条(VpiReader 注入的 declare 条目),
|
||||
# 此时必须用全局默认参数表的真实条目覆盖,否则缺参填充整体不触发。
|
||||
if gd_entry is not None and (df_defaults is None or df_default_count <= 0):
|
||||
df_defaults = gd_entry.Defaults
|
||||
df_default_count = gd_entry.DefaultCount
|
||||
df_param_count = gd_entry.ParamCount
|
||||
@@ -1162,7 +1213,7 @@ class CallGenMixin(CallGenBase.CallGenBase):
|
||||
df_default_count = 0
|
||||
df_param_count = 0
|
||||
# 填充缺失参数
|
||||
if df_defaults is not None and df_default_count > 0 and can < df_param_count:
|
||||
if df_default_count > 0 and can < df_param_count and (df_defaults is not None or gd_entry is not None):
|
||||
df_offset: int = df_param_count - df_default_count
|
||||
for df_di in range(df_default_count):
|
||||
df_param_idx: int = df_offset + df_di
|
||||
@@ -1172,8 +1223,8 @@ class CallGenMixin(CallGenBase.CallGenBase):
|
||||
if gd_entry is not None:
|
||||
df_arg_val = self.Gen.CallGenLeafKit._build_const_from_snapshot(
|
||||
pool, mod, gd_entry, df_di, trans, builder)
|
||||
if df_arg_val is None:
|
||||
df_defaults_list: rawptr[list[rawptr[ast.AST]]] = rawptr[list[rawptr[ast.AST]]](uint64(df_defaults))
|
||||
if df_arg_val is None and df_defaults is not None:
|
||||
df_defaults_list: list[ast.AST*]* = (list[ast.AST*] | t.CPtr)(uint64(df_defaults))
|
||||
df_default_node: rawptr[ast.AST] = df_defaults_list.get(df_di)
|
||||
if df_default_node is not None:
|
||||
df_arg_val = self.Gen.ExprGen.translate_value(
|
||||
@@ -1185,6 +1236,12 @@ class CallGenMixin(CallGenBase.CallGenBase):
|
||||
else:
|
||||
tail.Next = df_arg_val
|
||||
tail = df_arg_val
|
||||
# 追加的默认实参必须计入实参数:下方
|
||||
# _coerce_args_to_def_params/_ensure_method_declare 等
|
||||
# 均以 can 为界重建/校验实参链,count 不增会把补齐的
|
||||
# 尾随默认实参整体截断丢弃(VET json.write 缺省 cap
|
||||
# 丢失 → 被调方读寄存器垃圾 → pool.alloc 巨量 OOM 根因)。
|
||||
can += 1
|
||||
elif found_func is not None:
|
||||
# 默认参数缺失/表信息不全时的零值兜底:函数表有参数数但无默认值记录、或调用方先于定义文件编译导致查不到默认值时,用 found_func 实际参数数(stub declare,与 define 一致)兜底并缺参填零值(对齐 TPC _fill_default_args 语义)。注意排除 EH 输出参数(%__eh_msg_out__/%__eh_code_out__),否则会与 _emit_eh_guarded_call 追加的真实 EH 实参重复导致 ABI 错位
|
||||
fc_cnt: int = 0
|
||||
@@ -1213,6 +1270,7 @@ class CallGenMixin(CallGenBase.CallGenBase):
|
||||
else:
|
||||
tail.Next = zero_val_z
|
||||
tail = zero_val_z
|
||||
can += 1 # 零值兜底实参同样计入实参数(同默认实参)
|
||||
fp_z = llvmlite.param_get_next(fp_z)
|
||||
fpi_z += 1
|
||||
|
||||
|
||||
@@ -353,7 +353,7 @@ class CallGenProp(CallGenBase.CallGenBase):
|
||||
total_count = 1
|
||||
|
||||
# 翻译调用参数
|
||||
cargs: rawptr[list[rawptr[ast.AST]]] = cl.args
|
||||
cargs: list[ast.AST*]* = cl.args
|
||||
can: sizet = 0
|
||||
if cargs is not None:
|
||||
can = len(cargs)
|
||||
|
||||
@@ -78,7 +78,7 @@ class CallGenVa(CallGenBase.CallGenBase):
|
||||
builder: rawptr[llvmlite.IRBuilder],
|
||||
mod: rawptr[llvmlite.LLVMModule],
|
||||
cl: rawptr[ast.Call],
|
||||
cargs: rawptr[list[rawptr[ast.AST]]],
|
||||
cargs: list[ast.AST*]*,
|
||||
can: sizet,
|
||||
funcs_ptr: t.CPtr,
|
||||
func_count: int,
|
||||
@@ -126,7 +126,7 @@ class CallGenVa(CallGenBase.CallGenBase):
|
||||
builder: rawptr[llvmlite.IRBuilder],
|
||||
mod: rawptr[llvmlite.LLVMModule],
|
||||
cl: rawptr[ast.Call],
|
||||
cargs: rawptr[list[rawptr[ast.AST]]],
|
||||
cargs: list[ast.AST*]*,
|
||||
can: sizet,
|
||||
funcs_ptr: t.CPtr,
|
||||
func_count: int,
|
||||
@@ -161,7 +161,7 @@ class CallGenVa(CallGenBase.CallGenBase):
|
||||
def _translate_va_start_sugar(self, pool: rawptr[memhub.MemBuddy],
|
||||
builder: rawptr[llvmlite.IRBuilder],
|
||||
mod: rawptr[llvmlite.LLVMModule],
|
||||
cargs: rawptr[list[rawptr[ast.AST]]],
|
||||
cargs: list[ast.AST*]*,
|
||||
can: sizet,
|
||||
funcs_ptr: t.CPtr,
|
||||
func_count: int,
|
||||
@@ -193,7 +193,7 @@ class CallGenVa(CallGenBase.CallGenBase):
|
||||
def _translate_va_end_sugar(self, pool: rawptr[memhub.MemBuddy],
|
||||
builder: rawptr[llvmlite.IRBuilder],
|
||||
mod: rawptr[llvmlite.LLVMModule],
|
||||
cargs: rawptr[list[rawptr[ast.AST]]],
|
||||
cargs: list[ast.AST*]*,
|
||||
can: sizet,
|
||||
funcs_ptr: t.CPtr,
|
||||
func_count: int,
|
||||
@@ -282,7 +282,7 @@ class CallGenVa(CallGenBase.CallGenBase):
|
||||
call_name: str,
|
||||
head: rawptr[llvmlite.Value],
|
||||
can: sizet,
|
||||
arg_nodes: rawptr[list[rawptr[ast.AST]]] = None,
|
||||
arg_nodes: list[ast.AST*]* = None,
|
||||
self_offset: int = 0,
|
||||
trans: rawptr[HT.Translator] = None) -> int:
|
||||
"""检查被调用函数是否为变长函数,若是则对变长参数进行 C ABI 提升
|
||||
|
||||
@@ -192,7 +192,7 @@ class ClassGenBase:
|
||||
return 1
|
||||
if cd.bases is None:
|
||||
return 0
|
||||
bases: rawptr[list[rawptr[ast.AST]]] = cd.bases
|
||||
bases: list[ast.AST*]* = cd.bases
|
||||
bn: sizet = len(bases)
|
||||
if bn == 0:
|
||||
return 0
|
||||
@@ -245,7 +245,7 @@ class ClassGenBase:
|
||||
return 1
|
||||
if cd.bases is None:
|
||||
return 0
|
||||
bases: rawptr[list[rawptr[ast.AST]]] = cd.bases
|
||||
bases: list[ast.AST*]* = cd.bases
|
||||
bn: sizet = len(bases)
|
||||
if bn == 0:
|
||||
return 0
|
||||
@@ -298,7 +298,7 @@ class ClassGenBase:
|
||||
return 1
|
||||
if cd.bases is None:
|
||||
return 0
|
||||
bases: rawptr[list[rawptr[ast.AST]]] = cd.bases
|
||||
bases: list[ast.AST*]* = cd.bases
|
||||
bn: sizet = len(bases)
|
||||
if bn == 0:
|
||||
return 0
|
||||
@@ -309,7 +309,7 @@ class ClassGenBase:
|
||||
if self._is_crenum_base(base_node, trans) == 1:
|
||||
return 1
|
||||
return 0
|
||||
def _has_decorator(self, decorator_list: rawptr[list[rawptr[ast.AST]]],
|
||||
def _has_decorator(self, decorator_list: list[ast.AST*]*,
|
||||
deco_name: str) -> int:
|
||||
"""检查 decorator_list 中是否有指定装饰器名"""
|
||||
if decorator_list is None:
|
||||
@@ -356,7 +356,7 @@ class ClassGenBase:
|
||||
return 0
|
||||
return 1 if string.strcmp(at2.attr, attr_name) == 0 else 0
|
||||
return 0
|
||||
def _class_has_tattr(self, decorator_list: rawptr[list[rawptr[ast.AST]]],
|
||||
def _class_has_tattr(self, decorator_list: list[ast.AST*]*,
|
||||
attr_name: str) -> int:
|
||||
"""检查装饰器列表是否含 t.attr.<attr_name>(@c.Attribute(t.attr.xxx) 或 @t.attr.xxx)。
|
||||
|
||||
@@ -413,7 +413,7 @@ class ClassGenBase:
|
||||
return 0
|
||||
return int(cn.int_val)
|
||||
return 0
|
||||
def _class_aligned_value(self, decorator_list: rawptr[list[rawptr[ast.AST]]]) -> int:
|
||||
def _class_aligned_value(self, decorator_list: list[ast.AST*]*) -> int:
|
||||
"""取 @c.Attribute(t.attr.aligned(N)) 的对齐字节数,无 aligned 返回 0"""
|
||||
if decorator_list is None:
|
||||
return 0
|
||||
@@ -445,7 +445,7 @@ class ClassGenBase:
|
||||
if av2 > 0:
|
||||
return av2
|
||||
return 0
|
||||
def _extract_func_meta(self, decorator_list: rawptr[list[rawptr[ast.AST]]]) -> int:
|
||||
def _extract_func_meta(self, decorator_list: list[ast.AST*]*) -> int:
|
||||
"""从装饰器列表提取元数据位掩码,返回 0=无装饰器元数据"""
|
||||
meta: int = 0
|
||||
if decorator_list is None:
|
||||
@@ -734,7 +734,7 @@ class ClassGenBase:
|
||||
"""类定义是否是异常类:基类是 Exception 或已注册异常类(1=是)"""
|
||||
if cd is None or cd.bases is None:
|
||||
return 0
|
||||
bases_e: rawptr[list[rawptr[ast.AST]]] = cd.bases
|
||||
bases_e: list[ast.AST*]* = cd.bases
|
||||
bn_e: sizet = len(bases_e)
|
||||
for bi_e in range(bn_e):
|
||||
base_e: rawptr[ast.AST] = bases_e.get(bi_e)
|
||||
@@ -758,7 +758,7 @@ class ClassGenBase:
|
||||
"""返回异常类定义的真实父类名(第一个非 Exception 的已注册异常类),无则 None"""
|
||||
if cd is None or cd.bases is None:
|
||||
return None
|
||||
bases_e2: rawptr[list[rawptr[ast.AST]]] = cd.bases
|
||||
bases_e2: list[ast.AST*]* = cd.bases
|
||||
bn_e2: sizet = len(bases_e2)
|
||||
for bi_e2 in range(bn_e2):
|
||||
base_e2: rawptr[ast.AST] = bases_e2.get(bi_e2)
|
||||
@@ -795,7 +795,7 @@ class ClassGenBase:
|
||||
lst_rcm: rawptr[ast.List] = rawptr[ast.List](value_node)
|
||||
if lst_rcm.elts is None:
|
||||
return
|
||||
elts_rcm: rawptr[list[rawptr[ast.AST]]] = lst_rcm.elts
|
||||
elts_rcm: list[ast.AST*]* = lst_rcm.elts
|
||||
en_rcm: sizet = len(elts_rcm)
|
||||
for ei_rcm in range(en_rcm):
|
||||
el_rcm: rawptr[ast.AST] = elts_rcm.get(ei_rcm)
|
||||
@@ -960,7 +960,7 @@ class ClassGenBase:
|
||||
pool: rawptr[memhub.MemBuddy] = None
|
||||
if trans is not None:
|
||||
pool = trans.Pool
|
||||
bases: rawptr[list[rawptr[ast.AST]]] = cd.bases
|
||||
bases: list[ast.AST*]* = cd.bases
|
||||
bn: sizet = len(bases)
|
||||
if bn == 0:
|
||||
return None
|
||||
@@ -1012,7 +1012,7 @@ class ClassGenBase:
|
||||
"""收集所有非 marker 父类名到 parents_buf,返回数量"""
|
||||
if pool is None or cd is None or cd.bases is None or parents_buf is None:
|
||||
return 0
|
||||
bases: rawptr[list[rawptr[ast.AST]]] = cd.bases
|
||||
bases: list[ast.AST*]* = cd.bases
|
||||
bn: sizet = len(bases)
|
||||
count: int = 0
|
||||
for bi in range(bn):
|
||||
@@ -1059,7 +1059,7 @@ class ClassGenBase:
|
||||
if trans is None or cd is None or cd.bases is None:
|
||||
return
|
||||
pool: rawptr[memhub.MemBuddy] = trans.Pool
|
||||
bases: rawptr[list[rawptr[ast.AST]]] = cd.bases
|
||||
bases: list[ast.AST*]* = cd.bases
|
||||
bn: sizet = len(bases)
|
||||
if bn == 0:
|
||||
return
|
||||
@@ -1099,7 +1099,7 @@ class ClassGenBase:
|
||||
"""检查类中是否有任何函数标记了 @t.CVTable,返回 1=有 / 0=无"""
|
||||
if cd is None or cd.children is None:
|
||||
return 0
|
||||
children: rawptr[list[rawptr[ast.AST]]] = cd.children
|
||||
children: list[ast.AST*]* = cd.children
|
||||
cn: sizet = len(children)
|
||||
for ci in range(cn):
|
||||
stmt: rawptr[ast.AST] = children.get(ci)
|
||||
|
||||
@@ -200,14 +200,24 @@ class ClassGenDef(ClassGenBase.ClassGenBase):
|
||||
field_types_buf: sizet | t.CPtr = pool.alloc(8 * GenTypes.FIELD_MAX)
|
||||
field_defaults_buf: sizet | t.CPtr = pool.alloc(8 * GenTypes.FIELD_MAX)
|
||||
field_annot_buf: sizet | t.CPtr = pool.alloc(8 * GenTypes.FIELD_MAX)
|
||||
# 字段 volatile 标记缓冲(1=字段注解联合含 t.CVolatile);与 field_annot_buf
|
||||
# 并行,取值 0/1(sizet 数组复用,避免另设类型)。
|
||||
field_volatile_buf: sizet | t.CPtr = pool.alloc(8 * GenTypes.FIELD_MAX)
|
||||
# 字段「所指物 volatile」标记缓冲(1=字段注解为 rawptr[t.CVolatile | T],
|
||||
# 等价 C 的 volatile T*);与 field_volatile_buf 并行,取值 0/1。
|
||||
field_pointee_volatile_buf: sizet | t.CPtr = pool.alloc(8 * GenTypes.FIELD_MAX)
|
||||
if field_names_buf is None or field_types_buf is None or field_defaults_buf is None:
|
||||
return 0
|
||||
if field_annot_buf is None:
|
||||
if field_annot_buf is None or field_volatile_buf is None:
|
||||
return 0
|
||||
if field_pointee_volatile_buf is None:
|
||||
return 0
|
||||
string.memset(field_names_buf, 0, 8 * GenTypes.FIELD_MAX)
|
||||
string.memset(field_types_buf, 0, 8 * GenTypes.FIELD_MAX)
|
||||
string.memset(field_defaults_buf, 0, 8 * GenTypes.FIELD_MAX)
|
||||
string.memset(field_annot_buf, 0, 8 * GenTypes.FIELD_MAX)
|
||||
string.memset(field_volatile_buf, 0, 8 * GenTypes.FIELD_MAX)
|
||||
string.memset(field_pointee_volatile_buf, 0, 8 * GenTypes.FIELD_MAX)
|
||||
|
||||
field_count: int = 0
|
||||
|
||||
@@ -273,9 +283,13 @@ class ClassGenDef(ClassGenBase.ClassGenBase):
|
||||
field_annot_buf[field_count] = stored_val
|
||||
else:
|
||||
field_annot_buf[field_count] = 0
|
||||
# 继承父类字段的 volatile 标记(字段展平后语义不变)
|
||||
field_volatile_buf[field_count] = sizet(pfe.IsVolatile)
|
||||
# 继承父类字段的「所指物 volatile」标记(展平后语义不变)
|
||||
field_pointee_volatile_buf[field_count] = sizet(pfe.PointeeVolatile)
|
||||
field_count += 1
|
||||
|
||||
children: rawptr[list[rawptr[ast.AST]]] = cd.children
|
||||
children: list[ast.AST*]* = cd.children
|
||||
if children is None:
|
||||
return 0
|
||||
|
||||
@@ -412,8 +426,25 @@ class ClassGenDef(ClassGenBase.ClassGenBase):
|
||||
field_annot_buf[field_count] = diag_cn_val
|
||||
else:
|
||||
field_annot_buf[field_count] = 0
|
||||
# t.CVolatile 存储类标记 → 该字段经对象访问的 load/store 带
|
||||
# volatile(如 Spinlock.locked: t.CVolatile | t.CInt)。
|
||||
if self.Gen.TypeGenErr.has_decorator_marker(
|
||||
aa.annotation, "CVolatile", 0) != 0:
|
||||
field_volatile_buf[field_count] = 1
|
||||
else:
|
||||
field_volatile_buf[field_count] = 0
|
||||
# rawptr[t.CVolatile | T](volatile 指针指向物,等价 C 的
|
||||
# volatile T*)→ 经该字段解引用(self.ptr[i]/self.ptr.field)
|
||||
# 的 load/store 带 volatile。
|
||||
if self.Gen.TypeGenErr.has_pointee_volatile_marker(
|
||||
aa.annotation) != 0:
|
||||
field_pointee_volatile_buf[field_count] = 1
|
||||
else:
|
||||
field_pointee_volatile_buf[field_count] = 0
|
||||
else:
|
||||
field_annot_buf[field_count] = 0
|
||||
field_volatile_buf[field_count] = 0
|
||||
field_pointee_volatile_buf[field_count] = 0
|
||||
field_count += 1
|
||||
|
||||
if field_count == 0:
|
||||
@@ -590,7 +621,20 @@ class ClassGenDef(ClassGenBase.ClassGenBase):
|
||||
if fannot_addr != 0:
|
||||
fannot = str(fannot_addr)
|
||||
if fname is not None and fty2 is not None:
|
||||
self.Gen.StructGen.add_field(pool, entry, fname, fty2, fdef, fannot)
|
||||
fidx_add: int = self.Gen.StructGen.add_field(pool, entry, fname, fty2, fdef, fannot)
|
||||
# t.CVolatile 字段标记(field_volatile_buf[fi] 与 add_field 顺序一一对应)
|
||||
if fidx_add >= 0 and field_volatile_buf[fi] != 0:
|
||||
fe_vol: rawptr[GenTypes.FieldEntry] = \
|
||||
self.Gen.StructGen._get_field_entry(entry, fidx_add)
|
||||
if fe_vol is not None:
|
||||
fe_vol.IsVolatile = 1
|
||||
# rawptr[t.CVolatile | T] 字段标记(field_pointee_volatile_buf[fi] 与
|
||||
# add_field 顺序一一对应):经该字段解引用时 load/store 带 volatile。
|
||||
if fidx_add >= 0 and field_pointee_volatile_buf[fi] != 0:
|
||||
fe_pv: rawptr[GenTypes.FieldEntry] = \
|
||||
self.Gen.StructGen._get_field_entry(entry, fidx_add)
|
||||
if fe_pv is not None:
|
||||
fe_pv.PointeeVolatile = 1
|
||||
|
||||
# Phase 1a 声明模式:只注册 struct + 设置 OOP 标志,不翻译方法体
|
||||
if trans._declare_only == 1:
|
||||
|
||||
@@ -159,7 +159,7 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
# 成员缺失(FR_OK 找不到)。register_enum 幂等返回已有 entry,
|
||||
# add_enum_member 成员名去重,重复处理安全合并。
|
||||
|
||||
children: rawptr[list[rawptr[ast.AST]]] = cd.children
|
||||
children: list[ast.AST*]* = cd.children
|
||||
if children is None:
|
||||
VLogger.warning(f"{class_name} has no body", "ENUM")
|
||||
return 0
|
||||
@@ -226,7 +226,7 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
ag: rawptr[ast.Assign] = rawptr[ast.Assign](stmt)
|
||||
if ag is None or ag.targets is None:
|
||||
continue
|
||||
tgts: rawptr[list[rawptr[ast.AST]]] = ag.targets
|
||||
tgts: list[ast.AST*]* = ag.targets
|
||||
tn: sizet = len(tgts)
|
||||
if tn == 0:
|
||||
continue
|
||||
@@ -412,7 +412,7 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
# SHA1 已在 register_struct 时设置,无需再补
|
||||
return 0
|
||||
|
||||
children: rawptr[list[rawptr[ast.AST]]] = cd.children
|
||||
children: list[ast.AST*]* = cd.children
|
||||
if children is None:
|
||||
VLogger.warning("{class_name} has no body", "UNION")
|
||||
return 0
|
||||
@@ -646,7 +646,7 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
existing.Ty = None
|
||||
existing.FieldCount = 0
|
||||
|
||||
children: rawptr[list[rawptr[ast.AST]]] = cd.children
|
||||
children: list[ast.AST*]* = cd.children
|
||||
if children is None:
|
||||
# [D32 fail-fast] 此前只 warning + return 0:变体表**静默不注册** →
|
||||
# _is_renum_class_name 恒 0、变体构造拿不到 tag(__types.vp L703
|
||||
@@ -680,7 +680,7 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
if variant_cd is None or variant_cd.children is None:
|
||||
variant_count += 1
|
||||
continue
|
||||
variant_children: rawptr[list[rawptr[ast.AST]]] = variant_cd.children
|
||||
variant_children: list[ast.AST*]* = variant_cd.children
|
||||
vcn: sizet = len(variant_children)
|
||||
field_idx: int = 0
|
||||
for vi in range(vcn):
|
||||
@@ -732,7 +732,7 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
ag_v: rawptr[ast.Assign] = rawptr[ast.Assign](stmt)
|
||||
if ag_v is None or ag_v.targets is None:
|
||||
continue
|
||||
tgts_v: rawptr[list[rawptr[ast.AST]]] = ag_v.targets
|
||||
tgts_v: list[ast.AST*]* = ag_v.targets
|
||||
if len(tgts_v) == 0:
|
||||
continue
|
||||
t0_v: rawptr[ast.AST] = tgts_v.get(0)
|
||||
@@ -886,7 +886,7 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
"""
|
||||
if trans is None or pool is None or class_name is None or cd is None:
|
||||
return
|
||||
children: rawptr[list[rawptr[ast.AST]]] = cd.children
|
||||
children: list[ast.AST*]* = cd.children
|
||||
if children is None:
|
||||
return
|
||||
cn: sizet = len(children)
|
||||
@@ -898,7 +898,7 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
if variant_cd is None or variant_cd.name is None \
|
||||
or variant_cd.children is None:
|
||||
continue
|
||||
vchildren: rawptr[list[rawptr[ast.AST]]] = variant_cd.children
|
||||
vchildren: list[ast.AST*]* = variant_cd.children
|
||||
vcn: sizet = len(vchildren)
|
||||
field_idx: int = 0
|
||||
for vi in range(vcn):
|
||||
@@ -938,7 +938,7 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
return
|
||||
if variant_count == 0:
|
||||
return
|
||||
children: rawptr[list[rawptr[ast.AST]]] = cd.children
|
||||
children: list[ast.AST*]* = cd.children
|
||||
if children is None:
|
||||
return
|
||||
|
||||
@@ -1011,7 +1011,7 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
ag_p: rawptr[ast.Assign] = rawptr[ast.Assign](stmt_p)
|
||||
if ag_p is None or ag_p.targets is None or ag_p.value is None:
|
||||
continue
|
||||
tgts_p: rawptr[list[rawptr[ast.AST]]] = ag_p.targets
|
||||
tgts_p: list[ast.AST*]* = ag_p.targets
|
||||
if len(tgts_p) == 0:
|
||||
continue
|
||||
t0_p: rawptr[ast.AST] = tgts_p.get(0)
|
||||
@@ -1054,7 +1054,7 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
ag_rv: rawptr[ast.Assign] = rawptr[ast.Assign](stmt)
|
||||
if ag_rv is None or ag_rv.targets is None:
|
||||
continue
|
||||
tgts_rv: rawptr[list[rawptr[ast.AST]]] = ag_rv.targets
|
||||
tgts_rv: list[ast.AST*]* = ag_rv.targets
|
||||
if len(tgts_rv) == 0:
|
||||
continue
|
||||
t0_rv: rawptr[ast.AST] = tgts_rv.get(0)
|
||||
|
||||
@@ -52,17 +52,61 @@ class ClassGenGeneric(ClassGenBase.ClassGenBase):
|
||||
if tp is None:
|
||||
return 0
|
||||
return 1
|
||||
def _dup_perm_str(self, s: str) -> str:
|
||||
"""深拷贝字符串到永久池(无永久池/分配失败时原样返回入参)"""
|
||||
if s is None:
|
||||
return None
|
||||
perm: rawptr[memhub.MemBuddy] = CompilerFactory.factory.PermPool
|
||||
if perm is None:
|
||||
return s
|
||||
n: sizet = string.strlen(s)
|
||||
b: str = perm.alloc(n + 1)
|
||||
if b is None:
|
||||
return s
|
||||
string.strcpy(b, s)
|
||||
return b
|
||||
def _register_generic_template(self, pool: rawptr[memhub.MemBuddy],
|
||||
cd: rawptr[ast.ClassDef],
|
||||
module_sha1: str) -> None:
|
||||
"""注册泛型类模板(类名 + ClassDef 节点 + 来源模块 SHA1)"""
|
||||
"""注册泛型类模板(类名 + ClassDef 节点 + 来源模块 SHA1)
|
||||
|
||||
[池归属修复] 这四张表 + GenericClassTpParams 的语义都是**永久表**:
|
||||
批量编译下要在 Phase1 的 reset_to(mark1) 与 Phase2 的 reset_to(mark2) 之后
|
||||
继续可读(读点见 _find_generic_template/_find_generic_template_sha1/
|
||||
_find_generic_template_file/_find_generic_template_tp_params,均有"遍历
|
||||
悬空内存 strcmp 即崩溃"的记录),REPL 下还要跨片段存活。但注册点有三个:
|
||||
- Phase1Scan.vp:322 → perm(永久池);
|
||||
- Phase2/__init__.vp:321 → perm(永久池);
|
||||
- ClassGenDef.vp:78 → trans.Pool(**会被 reset_to 回收的池**)。
|
||||
于是"表在哪个池"取决于哪条路径先注册到表:批量编译里两遍预注册
|
||||
(_PreRegisterAllGenericTemplates / _PreRegisterAppGenericTemplates)在前,
|
||||
表被建在永久池 ⇒ 第三条路径只是追加;而两遍预注册都没建成表时(例如
|
||||
includes 的泛型 marker 文本预筛未命中),第三条路径把表建在 trans.Pool 上,
|
||||
随 mark 回收 ⇒ 后续 _find_generic_template 遍历悬空表(UAF)。REPL 从不跑
|
||||
Phase1/Phase2,第三条路径是**唯一**注册点 ⇒ 表必然落在会被每片段 reset 的
|
||||
池上,M4 一旦在片段里定义泛型类就是必现 UAF。
|
||||
故此处统一:表体一律用永久池(无永久池时退回入参池,即旧行为),并把
|
||||
调用方池里的三个串(类名/SHA1/来源文件)深拷贝进永久池——它们同样会随
|
||||
调用方池回收而悬空(挂名 strcmp 即读悬空内存)。
|
||||
批量编译不变量:变更只影响"表与串分配在哪个池",写入的**内容**逐字不变
|
||||
(同样的类名/节点/ SHA1/文件路径,同样的插入顺序与查重),发射的 IR 与
|
||||
符号名不受池选择影响 ⇒ 逐字不变。
|
||||
"""
|
||||
if cd is None or cd.name is None:
|
||||
return
|
||||
perm: rawptr[memhub.MemBuddy] = CompilerFactory.factory.PermPool
|
||||
table_pool: rawptr[memhub.MemBuddy] = perm
|
||||
if table_pool is None:
|
||||
table_pool = pool
|
||||
if self.GenericClassNames is None:
|
||||
self.GenericClassNames = list[str](pool, 8)
|
||||
self.GenericClassNodes = list[rawptr[ast.ClassDef]](pool, 8)
|
||||
self.GenericClassSha1s = list[str](pool, 8)
|
||||
self.GenericClassFiles = list[str](pool, 8)
|
||||
self.GenericClassNames = list[str](table_pool, 8)
|
||||
self.GenericClassNodes = list[rawptr[ast.ClassDef]](table_pool, 8)
|
||||
self.GenericClassSha1s = list[str](table_pool, 8)
|
||||
self.GenericClassFiles = list[str](table_pool, 8)
|
||||
if self.GenericClassTpParams is None:
|
||||
self.GenericClassTpParams = CompilerFactory.factory.PermPool.alloc(GENERIC_TEMPLATE_MAX * 8)
|
||||
if perm is None:
|
||||
return
|
||||
self.GenericClassTpParams = perm.alloc(GENERIC_TEMPLATE_MAX * 8)
|
||||
if self.GenericClassTpParams is None:
|
||||
return
|
||||
string.memset(self.GenericClassTpParams, 0, GENERIC_TEMPLATE_MAX * 8)
|
||||
@@ -76,11 +120,12 @@ class ClassGenGeneric(ClassGenBase.ClassGenBase):
|
||||
return
|
||||
# type_params stdlib 深拷贝:模板节点的 type_params 是 pool 分配的
|
||||
tp_names_buf: str = self._copy_type_params_stdlib(cd.type_params)
|
||||
self.GenericClassNames.append(cd.name)
|
||||
self.GenericClassNames.append(self._dup_perm_str(cd.name))
|
||||
self.GenericClassNodes.append(cd)
|
||||
self.GenericClassSha1s.append(module_sha1)
|
||||
self.GenericClassSha1s.append(self._dup_perm_str(module_sha1))
|
||||
# 同时保存模板来源文件路径(错误定位用,见字段注释)
|
||||
self.GenericClassFiles.append(self.Gen.TypeGenResolve.get_current_file())
|
||||
self.GenericClassFiles.append(
|
||||
self._dup_perm_str(self.Gen.TypeGenResolve.get_current_file()))
|
||||
if tp_names_buf is not None and cn < GENERIC_TEMPLATE_MAX:
|
||||
self.GenericClassTpParams[cn] = sizet(tp_names_buf)
|
||||
def _copy_type_params_stdlib(self, tp: list[str] | t.CPtr) -> str:
|
||||
@@ -298,9 +343,9 @@ class ClassGenGeneric(ClassGenBase.ClassGenBase):
|
||||
# Tuple: (T, int) 等
|
||||
if k == ast.ASTKind.Tuple:
|
||||
tup: rawptr[ast.Tuple] = rawptr[ast.Tuple](node)
|
||||
new_elts: rawptr[list[rawptr[ast.AST]]] = list[rawptr[ast.AST]](pool, 8)
|
||||
new_elts: list[ast.AST*]* = list[rawptr[ast.AST]](pool, 8)
|
||||
if tup.elts is not None:
|
||||
tup_elts: rawptr[list[rawptr[ast.AST]]] = tup.elts
|
||||
tup_elts: list[ast.AST*]* = tup.elts
|
||||
en: sizet = len(tup_elts)
|
||||
ei: sizet
|
||||
for ei in range(en):
|
||||
@@ -329,9 +374,9 @@ class ClassGenGeneric(ClassGenBase.ClassGenBase):
|
||||
return args
|
||||
old_args: rawptr[ast.Arguments] = rawptr[ast.Arguments](args)
|
||||
# 拷贝 args 列表,替换每个 Arg 的 annotation
|
||||
new_arg_list: rawptr[list[rawptr[ast.AST]]] = list[rawptr[ast.AST]](pool, 8)
|
||||
new_arg_list: list[ast.AST*]* = list[rawptr[ast.AST]](pool, 8)
|
||||
if old_args.args is not None:
|
||||
old_arg_list: rawptr[list[rawptr[ast.AST]]] = old_args.args
|
||||
old_arg_list: list[ast.AST*]* = old_args.args
|
||||
an: sizet = len(old_arg_list)
|
||||
ai: sizet
|
||||
for ai in range(an):
|
||||
@@ -364,7 +409,7 @@ class ClassGenGeneric(ClassGenBase.ClassGenBase):
|
||||
cd.decorator_list, None)
|
||||
# 拷贝 children
|
||||
if cd.children is not None:
|
||||
cd_children: rawptr[list[rawptr[ast.AST]]] = cd.children
|
||||
cd_children: list[ast.AST*]* = cd.children
|
||||
cn: sizet = len(cd_children)
|
||||
ci: sizet
|
||||
for ci in range(cn):
|
||||
@@ -389,7 +434,7 @@ class ClassGenGeneric(ClassGenBase.ClassGenBase):
|
||||
fd.decorator_list, new_returns2, 0)
|
||||
# 方法体直接引用原始节点
|
||||
if fd.children is not None:
|
||||
fd_children: rawptr[list[rawptr[ast.AST]]] = fd.children
|
||||
fd_children: list[ast.AST*]* = fd.children
|
||||
bcn: sizet = len(fd_children)
|
||||
bci: sizet
|
||||
for bci in range(bcn):
|
||||
|
||||
@@ -87,7 +87,7 @@ class ClassGenVTable(ClassGenBase.ClassGenBase):
|
||||
pool: rawptr[memhub.MemBuddy] = trans.Pool
|
||||
mod: rawptr[llvmlite.LLVMModule] = trans.Module
|
||||
|
||||
children: rawptr[list[rawptr[ast.AST]]] = cd.children
|
||||
children: list[ast.AST*]* = cd.children
|
||||
if children is None:
|
||||
return 0
|
||||
cn: sizet = len(children)
|
||||
@@ -444,7 +444,7 @@ class ClassGenVTable(ClassGenBase.ClassGenBase):
|
||||
if trans is None or cd is None or struct_ty is None or class_name is None:
|
||||
return 0
|
||||
|
||||
children: rawptr[list[rawptr[ast.AST]]] = cd.children
|
||||
children: list[ast.AST*]* = cd.children
|
||||
if children is None:
|
||||
return 0
|
||||
|
||||
@@ -681,13 +681,13 @@ class ClassGenVTable(ClassGenBase.ClassGenBase):
|
||||
if md_args_node is not None:
|
||||
md_ags: rawptr[ast.Arguments] = rawptr[ast.Arguments](md_args_node)
|
||||
if md_ags.args is not None:
|
||||
md_alist: rawptr[list[rawptr[ast.AST]]] = md_ags.args
|
||||
md_alist: list[ast.AST*]* = md_ags.args
|
||||
if is_static_m != 0:
|
||||
md_param_count = len(md_alist)
|
||||
else:
|
||||
md_param_count = len(md_alist) - 1
|
||||
if md_ags.defaults is not None:
|
||||
md_dlist: rawptr[list[rawptr[ast.AST]]] = md_ags.defaults
|
||||
md_dlist: list[ast.AST*]* = md_ags.defaults
|
||||
md_defaults = md_dlist
|
||||
md_default_count = len(md_dlist)
|
||||
|
||||
@@ -718,7 +718,7 @@ class ClassGenVTable(ClassGenBase.ClassGenBase):
|
||||
if args_node is not None:
|
||||
ags: rawptr[ast.Arguments] = rawptr[ast.Arguments](args_node)
|
||||
if ags.args is not None:
|
||||
alist: rawptr[list[rawptr[ast.AST]]] = ags.args
|
||||
alist: list[ast.AST*]* = ags.args
|
||||
an: sizet = len(alist)
|
||||
start_idx: int = 0
|
||||
if is_static_m == 0:
|
||||
@@ -868,7 +868,7 @@ class ClassGenVTable(ClassGenBase.ClassGenBase):
|
||||
if args_node is not None:
|
||||
ags2: rawptr[ast.Arguments] = rawptr[ast.Arguments](args_node)
|
||||
if ags2.args is not None:
|
||||
alist2: rawptr[list[rawptr[ast.AST]]] = ags2.args
|
||||
alist2: list[ast.AST*]* = ags2.args
|
||||
an2: sizet = len(alist2)
|
||||
start_idx2: int = 0
|
||||
if is_static_m == 0:
|
||||
@@ -948,7 +948,7 @@ class ClassGenVTable(ClassGenBase.ClassGenBase):
|
||||
# 否则 `global BootInfo` 未注册时 prescan 把 BootInfo 当局部创建 alloca,
|
||||
# 后续翻译 is_global_name 为真又写全局 → 局部 alloca 永不写入 → 读全 0
|
||||
# (main.vp __init__ BootInfo memmap 全 0 根因)。
|
||||
body: rawptr[list[rawptr[ast.AST]]] = fd.children
|
||||
body: list[ast.AST*]* = fd.children
|
||||
if body is not None:
|
||||
bn: sizet = len(body)
|
||||
for bi in range(bn):
|
||||
|
||||
@@ -801,6 +801,11 @@ class ExprGenAttr(ExprGenBase.ExprGenBase):
|
||||
# load 解引用获取 Ptr(Struct)
|
||||
obj_ptr = self._deref_if_ptr_ptr(builder, obj_ptr)
|
||||
|
||||
# rawptr[t.CVolatile | T] 基址(volatile 指针指向物):经该指针访问
|
||||
# 字段(p.field)的 load 带 volatile。仅当基址可解析到 VarEntry
|
||||
# (Name)/ FieldEntry(Attribute)时为 1;解析失败为 0(文本不变)。
|
||||
vol_ba_rd: int = self.base_pointee_is_volatile(pool, trans, at.value)
|
||||
|
||||
# 查找结构体类型信息
|
||||
# obj_ptr 类型应该是 Ptr(Struct(...))
|
||||
match obj_ptr.Ty:
|
||||
@@ -839,7 +844,7 @@ class ExprGenAttr(ExprGenBase.ExprGenBase):
|
||||
llvmlite.build_bitcast(builder, alias_ptr, decl_ptr_rn)
|
||||
if cast_ptr_rn is not None:
|
||||
return llvmlite.build_load(builder, decl_ty_rn, cast_ptr_rn)
|
||||
return llvmlite.build_load(builder, alias_fe.Ty, alias_ptr)
|
||||
return llvmlite.build_load(builder, alias_fe.Ty, alias_ptr, vol_ba_rd)
|
||||
# property getter 回退: obj.attr 是 @property/@x.getter 方法时生成调用
|
||||
# (字段未找到时先尝试,避免报误导性的"字段未找到"错误)
|
||||
if field_info is None and at.value is not None and trans is not None:
|
||||
@@ -904,13 +909,19 @@ class ExprGenAttr(ExprGenBase.ExprGenBase):
|
||||
pool, mod, annot_se.Ty)
|
||||
if field_info is not None:
|
||||
field_ty: rawptr[llvmlite.LLVMType] = field_info.Ty
|
||||
# t.CVolatile 字段:经对象访问的 load 带 volatile 限定符
|
||||
field_vol_rd: int = self.Gen.StructGen.field_is_volatile(field_info)
|
||||
# 合并"字段所指物 volatile"(基址是 rawptr[t.CVolatile|T] 时,
|
||||
# 经其访问的字段 load 亦须 volatile;两者取或)
|
||||
if vol_ba_rd != 0:
|
||||
field_vol_rd = 1
|
||||
# 联合体:bitcast obj_ptr 到 field_ty* 后 load
|
||||
if self.Gen.StructGen.is_union_by_type(struct_ty) == 1:
|
||||
field_ptr_ty: rawptr[llvmlite.LLVMType] = llvmlite.Ptr(pool, field_ty)
|
||||
casted: rawptr[llvmlite.Value] = llvmlite.build_bitcast(
|
||||
builder, obj_ptr, field_ptr_ty)
|
||||
if casted is not None:
|
||||
return llvmlite.build_load(builder, field_ty, casted)
|
||||
return llvmlite.build_load(builder, field_ty, casted, field_vol_rd)
|
||||
return None
|
||||
# 普通结构体:GEP + load
|
||||
field_idx: int = field_info.Index
|
||||
@@ -935,12 +946,12 @@ class ExprGenAttr(ExprGenBase.ExprGenBase):
|
||||
cast_ptr_rd: rawptr[llvmlite.Value] = llvmlite.build_bitcast(
|
||||
builder, field_ptr, decl_ptr_rd)
|
||||
if cast_ptr_rd is not None:
|
||||
return llvmlite.build_load(builder, decl_ty_rd, cast_ptr_rd)
|
||||
return llvmlite.build_load(builder, decl_ty_rd, cast_ptr_rd, field_vol_rd)
|
||||
# 数组类型字段不能 load 为 SSA value,直接返回字段指针
|
||||
# 用于后续下标访问: self.state[0] → GEP state 字段 → GEP 数组元素
|
||||
if self.is_array_type(field_ty) != 0:
|
||||
return field_ptr
|
||||
loaded_val: rawptr[llvmlite.Value] = llvmlite.build_load(builder, field_ty, field_ptr)
|
||||
loaded_val: rawptr[llvmlite.Value] = llvmlite.build_load(builder, field_ty, field_ptr, field_vol_rd)
|
||||
# 联合类型字段(如 Token | t.CPtr)被编译为 i8*,
|
||||
# 若 AnnotClassName 指示了具体结构体类型,bitcast 为正确的结构体指针。
|
||||
# 注意:仅当字段类型本身是指针时才 bitcast(指针→指针);
|
||||
@@ -1063,6 +1074,131 @@ class ExprGenAttr(ExprGenBase.ExprGenBase):
|
||||
if fe is None:
|
||||
return None
|
||||
return self.Gen.StructGen.get_field_annot_class_name(fe)
|
||||
|
||||
def attr_field_is_volatile(self, pool: rawptr[memhub.MemBuddy],
|
||||
trans: rawptr[HT.Translator],
|
||||
attr_node: rawptr[ast.AST]) -> int:
|
||||
"""obj.field 访问的字段是否 volatile(1=是 / 0=否)
|
||||
|
||||
仅解析一层属性:先定基座(Name 变量注解名 / 属性链字段注解名)得到父类,
|
||||
再按名查字段取 FieldEntry.IsVolatile。查不到(vtable 方法、影子字段、
|
||||
依赖未就绪等)返回 0,不影响既有行为(写路径退回非 volatile store)。
|
||||
"""
|
||||
if attr_node is None or trans is None:
|
||||
return 0
|
||||
if attr_node.kind() != ast.ASTKind.Attribute:
|
||||
return 0
|
||||
at: rawptr[ast.Attribute] = rawptr[ast.Attribute](attr_node)
|
||||
if at is None or at.attr is None or at.value is None:
|
||||
return 0
|
||||
parent_class: str = None
|
||||
if at.value.kind() == ast.ASTKind.Name:
|
||||
nm: rawptr[ast.Name] = rawptr[ast.Name](at.value)
|
||||
if nm.id is None:
|
||||
return 0
|
||||
ve: rawptr[GenTypes.VarEntry] = self.Gen.VarGen.lookup_var_entry(
|
||||
trans.SymTab, nm.id)
|
||||
if ve is None:
|
||||
return 0
|
||||
parent_class = self.Gen.VarGen.var_annot_class_name(ve)
|
||||
elif at.value.kind() == ast.ASTKind.Attribute:
|
||||
parent_class = self._resolve_attr_field_class(pool, trans, at.value)
|
||||
if parent_class is None:
|
||||
return 0
|
||||
fe: rawptr[GenTypes.FieldEntry] = self.Gen.StructGen.lookup_field_by_class(
|
||||
parent_class, at.attr, trans.ModuleSha1, at, trans._from_imports)
|
||||
return self.Gen.StructGen.field_is_volatile(fe)
|
||||
|
||||
# ============================================================
|
||||
# 指针指向物 volatile(rawptr[t.CVolatile | T],等价 C 的 volatile T*)
|
||||
# 基址→VarEntry/FieldEntry 解析与消费点。仅在基址能解析到具体条目时生效,
|
||||
# 其余(函数返回/复杂表达式等)返回 0(明确不支持,见限制清单)。
|
||||
# ============================================================
|
||||
def _resolve_attr_field_entry(self, pool: rawptr[memhub.MemBuddy],
|
||||
trans: rawptr[HT.Translator],
|
||||
attr_node: rawptr[ast.AST]) -> rawptr[GenTypes.FieldEntry]:
|
||||
"""obj.field 访问的 FieldEntry(**非 fatal 只读解析**,失败返回 None)
|
||||
|
||||
与 attr_field_is_volatile 的区别:后者走 lookup_field_by_class(模块限定名
|
||||
分支会 fatal_error),仅用于写路径;本函数要能在读路径无条件调用,故
|
||||
对齐 ExprGenOps._node_type_unsigned 的字段遍历——解析基座类名后 find_struct
|
||||
取裸结构体、自遍历字段,未命中一律返回 None,绝不 fatal,不改变既有报错行为。
|
||||
仅支持单层基座(基座是 Name,如 self.ptr);基座是属性链/调用/下标等返回 None。
|
||||
"""
|
||||
if attr_node is None or trans is None:
|
||||
return None
|
||||
if attr_node.kind() != ast.ASTKind.Attribute:
|
||||
return None
|
||||
at: rawptr[ast.Attribute] = rawptr[ast.Attribute](attr_node)
|
||||
if at is None or at.attr is None or at.value is None:
|
||||
return None
|
||||
if at.value.kind() != ast.ASTKind.Name:
|
||||
return None
|
||||
nm: rawptr[ast.Name] = rawptr[ast.Name](at.value)
|
||||
if nm.id is None:
|
||||
return None
|
||||
ve: rawptr[GenTypes.VarEntry] = self.Gen.VarGen.lookup_var_entry(
|
||||
trans.SymTab, nm.id)
|
||||
if ve is None:
|
||||
return None
|
||||
cls_nm: str = self.Gen.VarGen.var_annot_class_name(ve)
|
||||
if cls_nm is None:
|
||||
return None
|
||||
# 取裸类名(点前部分):只做裸名结构体查找,避免模块限定名解析 fatal
|
||||
bare: str = cls_nm
|
||||
dot: str = self.Gen.StructGen._last_dot_outside_brackets(cls_nm)
|
||||
if dot is not None:
|
||||
bare = dot + 1
|
||||
if bare is None:
|
||||
return None
|
||||
st: rawptr[GenTypes.StructEntry] = self.Gen.StructGen.find_struct(bare)
|
||||
if st is None:
|
||||
return None
|
||||
fi: int = 0
|
||||
while fi < st.FieldCount:
|
||||
fe_u: rawptr[GenTypes.FieldEntry] = \
|
||||
self.Gen.StructGen._get_field_entry(st, fi)
|
||||
if fe_u is not None and fe_u.Name is not None \
|
||||
and string.strcmp(fe_u.Name, at.attr) == 0:
|
||||
return fe_u
|
||||
fi += 1
|
||||
return None
|
||||
|
||||
def attr_field_pointee_is_volatile(self, pool: rawptr[memhub.MemBuddy],
|
||||
trans: rawptr[HT.Translator],
|
||||
attr_node: rawptr[ast.AST]) -> int:
|
||||
"""obj.field 字段的**所指物**是否 volatile(1=是 / 0=否)
|
||||
|
||||
即该字段注解是否为 rawptr[t.CVolatile | T](等价 C 的 volatile T*)。
|
||||
消费点:经该字段解引用(self.ptr[i] / self.ptr.field)的 load/store
|
||||
据此加 LLVM volatile 限定符。
|
||||
"""
|
||||
fe: rawptr[GenTypes.FieldEntry] = self._resolve_attr_field_entry(
|
||||
pool, trans, attr_node)
|
||||
return self.Gen.StructGen.field_pointee_is_volatile(fe)
|
||||
|
||||
def base_pointee_is_volatile(self, pool: rawptr[memhub.MemBuddy],
|
||||
trans: rawptr[HT.Translator],
|
||||
base_node: rawptr[ast.AST]) -> int:
|
||||
"""指针基址的所指物是否 volatile(rawptr[t.CVolatile|T] 变量/字段)
|
||||
|
||||
仅当基址可解析到具体 VarEntry(Name)/ FieldEntry(Attribute)时生效;
|
||||
基址是函数返回/下标/调用/更复杂表达式时返回 0(明确不支持)。
|
||||
消费点:p[i] / p.field / c.Deref(p) 的 load/store 据此加 LLVM volatile。
|
||||
"""
|
||||
if base_node is None or trans is None:
|
||||
return 0
|
||||
if base_node.kind() == ast.ASTKind.Name:
|
||||
nm: rawptr[ast.Name] = rawptr[ast.Name](base_node)
|
||||
if nm.id is None:
|
||||
return 0
|
||||
ve: rawptr[GenTypes.VarEntry] = self.Gen.VarGen.lookup_var_entry(
|
||||
trans.SymTab, nm.id)
|
||||
return self.Gen.VarGen.var_pointee_is_volatile(ve)
|
||||
if base_node.kind() == ast.ASTKind.Attribute:
|
||||
return self.attr_field_pointee_is_volatile(pool, trans, base_node)
|
||||
return 0
|
||||
|
||||
def get_attribute_ptr(self, builder: rawptr[llvmlite.IRBuilder],
|
||||
pool: rawptr[memhub.MemBuddy],
|
||||
mod: rawptr[llvmlite.LLVMModule],
|
||||
|
||||
@@ -46,7 +46,7 @@ class ExprGenCls(ExprGenBase.ExprGenBase):
|
||||
# 符号依赖),未命中返回 null。幂等查重,多遍翻译安全。
|
||||
# ============================================================
|
||||
|
||||
def _extract_docstring_from_body(self, body: rawptr[list[rawptr[ast.AST]]]) -> str:
|
||||
def _extract_docstring_from_body(self, body: list[ast.AST*]*) -> str:
|
||||
"""从函数/类体提取 docstring:body[0] 为 Expr(Constant str) 时返回内容"""
|
||||
if body is None or len(body) == 0:
|
||||
return None
|
||||
@@ -111,7 +111,7 @@ class ExprGenCls(ExprGenBase.ExprGenBase):
|
||||
"""扫描模块 AST:登记模块级函数/类/方法的 docstring(幂等)"""
|
||||
if tree is None or module_sha1 is None:
|
||||
return
|
||||
ch: rawptr[list[rawptr[ast.AST]]] = tree.children
|
||||
ch: list[ast.AST*]* = tree.children
|
||||
if ch is None:
|
||||
return
|
||||
cn: sizet = len(ch)
|
||||
@@ -123,7 +123,7 @@ class ExprGenCls(ExprGenBase.ExprGenBase):
|
||||
if kd == ast.ASTKind.FunctionDef:
|
||||
fd: rawptr[ast.FunctionDef] = rawptr[ast.FunctionDef](child)
|
||||
if fd is not None and fd.name is not None:
|
||||
fd_body: rawptr[list[rawptr[ast.AST]]] = fd.children
|
||||
fd_body: list[ast.AST*]* = fd.children
|
||||
fdoc: str = self._extract_docstring_from_body(fd_body)
|
||||
if fdoc is not None:
|
||||
self.register_docstring(module_sha1, fd.name, fdoc)
|
||||
@@ -131,12 +131,12 @@ class ExprGenCls(ExprGenBase.ExprGenBase):
|
||||
cd: rawptr[ast.ClassDef] = rawptr[ast.ClassDef](child)
|
||||
if cd is None or cd.name is None:
|
||||
continue
|
||||
cd_body0: rawptr[list[rawptr[ast.AST]]] = cd.children
|
||||
cd_body0: list[ast.AST*]* = cd.children
|
||||
cdoc: str = self._extract_docstring_from_body(cd_body0)
|
||||
if cdoc is not None:
|
||||
self.register_docstring(module_sha1, cd.name, cdoc)
|
||||
# 类方法 docstring(key="{ClassName}.{method}")
|
||||
cd_body: rawptr[list[rawptr[ast.AST]]] = cd.children
|
||||
cd_body: list[ast.AST*]* = cd.children
|
||||
if cd_body is not None:
|
||||
cbn: sizet = len(cd_body)
|
||||
for mi in range(cbn):
|
||||
|
||||
@@ -262,7 +262,7 @@ class ExprGenConst(ExprGenBase.ExprGenBase):
|
||||
if list_node is None:
|
||||
return None
|
||||
|
||||
elts: rawptr[list[rawptr[ast.AST]]] = list_node.elts
|
||||
elts: list[ast.AST*]* = list_node.elts
|
||||
elts_count: sizet = 0
|
||||
if elts is not None:
|
||||
elts_count = len(elts)
|
||||
|
||||
@@ -58,7 +58,7 @@ class ExprGenFstr(ExprGenBase.ExprGenBase):
|
||||
arg_tail: rawptr[llvmlite.Value] = None
|
||||
arg_count: int = 0
|
||||
|
||||
parts: rawptr[list[rawptr[ast.AST]]] = js.values
|
||||
parts: list[ast.AST*]* = js.values
|
||||
pn: sizet = len(parts)
|
||||
for pi in range(pn):
|
||||
part: rawptr[ast.AST] = parts.get(pi)
|
||||
|
||||
@@ -167,7 +167,13 @@ class ExprGenName(ExprGenBase.ExprGenBase):
|
||||
return mod_alloca
|
||||
case _:
|
||||
pass
|
||||
return llvmlite.build_load(builder, load_ty, mod_alloca)
|
||||
# t.CVolatile 全局:load 带 volatile 限定符(禁优化器消除重复读)
|
||||
vol_g: int = 0
|
||||
if trans is not None:
|
||||
ve_g: rawptr[GenTypes.VarEntry] = self.Gen.VarGen.lookup_var_entry(
|
||||
trans.SymTab, nm_id)
|
||||
vol_g = self.Gen.VarGen.var_is_volatile(ve_g)
|
||||
return llvmlite.build_load(builder, load_ty, mod_alloca, vol_g)
|
||||
|
||||
# nonlocal 变量:通过闭包 env 访问
|
||||
if GenApi.is_nonlocal_name(trans, nm_id) != 0:
|
||||
@@ -206,7 +212,23 @@ class ExprGenName(ExprGenBase.ExprGenBase):
|
||||
# load [N x i8] 值传给 %s 会读到错误数据崩溃
|
||||
# (ClassArrayTest TestCharArray 运行时崩溃根因)。
|
||||
return alloca
|
||||
return llvmlite.build_load(builder, load_ty, alloca)
|
||||
# t.CVolatile 局部变量:load 带 volatile 限定符
|
||||
vol_l: int = 0
|
||||
if trans is not None:
|
||||
ve_l: rawptr[GenTypes.VarEntry] = self.Gen.VarGen.lookup_var_entry(
|
||||
trans.SymTab, nm_id)
|
||||
vol_l = self.Gen.VarGen.var_is_volatile(ve_l)
|
||||
return llvmlite.build_load(builder, load_ty, alloca, vol_l)
|
||||
|
||||
# REPL 模式(M2)会话变量:局部表未命中的名字若是会话变量,从 ctx 槽按类型读回。
|
||||
# 位置在两处:① 局部查找之后(片段自己声明的局部名/参数优先,走原路径);
|
||||
# ② 模块别名/模块函数引用之前(会话名不得被 printf 等本模块 declare 抢走)。
|
||||
# 非 REPL(trans.ReplCtx is None)时 repl_try_read 立即返回 None ⇒ 原路径逐字不变。
|
||||
if trans is not None and trans.ReplCtx is not None:
|
||||
sess_val: rawptr[llvmlite.Value] = self.Gen.VarGen.repl_try_read(
|
||||
trans, nm_id, node)
|
||||
if sess_val is not None:
|
||||
return sess_val
|
||||
|
||||
# 模块别名检查:SymTab 查找失败后才检查
|
||||
# 如果 nm_id 是已导入模块名(如 win32file, fileio)且未被声明为局部变量,
|
||||
@@ -756,6 +778,11 @@ class ExprGenName(ExprGenBase.ExprGenBase):
|
||||
if sub.value is not None and sub.value.kind() == ast.ASTKind.Name:
|
||||
nm: rawptr[ast.Name] = rawptr[ast.Name](sub.value)
|
||||
if nm.id is not None and trans is not None:
|
||||
# rawptr[t.CVolatile | T] 变量(volatile 指针指向物):本分支内
|
||||
# 的**元素 load**(p[i] 解引用)带 volatile;仅读取指针值自身的
|
||||
# load(alloca → 指针值)不带(那是指针变量而非所指物)。
|
||||
vol_sub_rd: int = self.Gen.VarGen.var_pointee_is_volatile(
|
||||
self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm.id))
|
||||
# nonlocal 数组/指针:从 env 读共享堆地址(提升函数内不能
|
||||
# lookup_var 外层 alloca——SSA 编号跨函数错乱崩溃)
|
||||
# 读路径:元素指针 load 出元素值
|
||||
@@ -850,7 +877,8 @@ class ExprGenName(ExprGenBase.ExprGenBase):
|
||||
elem_ptr_pp: rawptr[llvmlite.Value] = llvmlite.build_gep(
|
||||
builder, inner_ty, ptr_val_pp, idx_val)
|
||||
if elem_ptr_pp is not None:
|
||||
return llvmlite.build_load(builder, inner_ty, elem_ptr_pp)
|
||||
# volatile 指针指向物:解引用 load 带 volatile
|
||||
return llvmlite.build_load(builder, inner_ty, elem_ptr_pp, vol_sub_rd)
|
||||
return None
|
||||
# 自定义结构体 (如 HashTable|t.CPtr, JsonValue|t.CPtr):
|
||||
# 仅当类定义了 __getitem__(当前模块定义或跨模块 stub declare 注入)
|
||||
@@ -880,7 +908,8 @@ class ExprGenName(ExprGenBase.ExprGenBase):
|
||||
elem_rd_g: rawptr[llvmlite.Value] = llvmlite.build_gep(
|
||||
builder, inner_ty, ptr_val_rd_g, idx_val)
|
||||
if elem_rd_g is not None:
|
||||
return llvmlite.build_load(builder, inner_ty, elem_rd_g)
|
||||
# volatile 指针指向物:解引用 load 带 volatile
|
||||
return llvmlite.build_load(builder, inner_ty, elem_rd_g, vol_sub_rd)
|
||||
return None
|
||||
# bytes|t.CPtr / str|t.CPtr: alloca 是 i8**,
|
||||
# 直接 GEP 按 i8* 步长(8 字节),load i8*
|
||||
@@ -900,7 +929,8 @@ class ExprGenName(ExprGenBase.ExprGenBase):
|
||||
elem_ptr_ts: rawptr[llvmlite.Value] = llvmlite.build_gep(
|
||||
builder, pointee, ptr_val_pe_ts, idx_val)
|
||||
if elem_ptr_ts is not None:
|
||||
return llvmlite.build_load(builder, pointee, elem_ptr_ts)
|
||||
# volatile 指针指向物:解引用 load 带 volatile
|
||||
return llvmlite.build_load(builder, pointee, elem_ptr_ts, vol_sub_rd)
|
||||
return None
|
||||
# 普通指针遍历: 先 load 指针值,再 GEP
|
||||
ptr_val: rawptr[llvmlite.Value] = llvmlite.build_load(
|
||||
@@ -909,7 +939,8 @@ class ExprGenName(ExprGenBase.ExprGenBase):
|
||||
elem_ptr2: rawptr[llvmlite.Value] = llvmlite.build_gep(
|
||||
builder, inner_ty, ptr_val, idx_val)
|
||||
if elem_ptr2 is not None:
|
||||
return llvmlite.build_load(builder, inner_ty, elem_ptr2)
|
||||
# volatile 指针指向物:解引用 load 带 volatile
|
||||
return llvmlite.build_load(builder, inner_ty, elem_ptr2, vol_sub_rd)
|
||||
return None
|
||||
case _:
|
||||
# 联合类型变量(IsPtrElement=1,如 _list.vp 的
|
||||
@@ -959,7 +990,8 @@ class ExprGenName(ExprGenBase.ExprGenBase):
|
||||
elem_sub_g: rawptr[llvmlite.Value] = llvmlite.build_gep(
|
||||
builder, pointee, ptr_val_sub_g, idx_val)
|
||||
if elem_sub_g is not None:
|
||||
return llvmlite.build_load(builder, pointee, elem_sub_g)
|
||||
# volatile 指针指向物:解引用 load 带 volatile
|
||||
return llvmlite.build_load(builder, pointee, elem_sub_g, vol_sub_rd)
|
||||
return None
|
||||
pass
|
||||
|
||||
@@ -971,6 +1003,11 @@ class ExprGenName(ExprGenBase.ExprGenBase):
|
||||
|
||||
# 检查是否是指针类型
|
||||
if self.is_ptr_type(ptr_val.Ty) != 0:
|
||||
# 通用路径基址(如 self.ptr / 复杂表达式):仅当基址可解析到
|
||||
# VarEntry/FieldEntry 且其为 rawptr[t.CVolatile|T] 时,元素 load 带 volatile;
|
||||
# 其余基址解析返回 0(明确不支持,见限制清单)。守卫为 0 时文本不变。
|
||||
vol_sub_gen: int = self.Gen.ExprGenAttr.base_pointee_is_volatile(
|
||||
pool, trans, sub.value)
|
||||
elem_ty2: rawptr[llvmlite.LLVMType] = ptr_val.Ty.Pointee
|
||||
if elem_ty2 is not None:
|
||||
# 数组类型: 双索引 GEP + load 元素
|
||||
@@ -980,7 +1017,7 @@ class ExprGenName(ExprGenBase.ExprGenBase):
|
||||
builder, elem_ty2, arr_elem_ty2, ptr_val,
|
||||
self._zext_index_to_i32(builder, idx_val))
|
||||
if elem_ptr3 is not None:
|
||||
return llvmlite.build_load(builder, arr_elem_ty2, elem_ptr3)
|
||||
return llvmlite.build_load(builder, arr_elem_ty2, elem_ptr3, vol_sub_gen)
|
||||
return None
|
||||
case _:
|
||||
pass
|
||||
@@ -1014,7 +1051,7 @@ class ExprGenName(ExprGenBase.ExprGenBase):
|
||||
builder, cell_p_u64, i8pp_ty_u64)
|
||||
if cast_cell_u64 is not None:
|
||||
return llvmlite.build_load(
|
||||
builder, i8p_ty_u64, cast_cell_u64)
|
||||
builder, i8p_ty_u64, cast_cell_u64, vol_sub_gen)
|
||||
case _:
|
||||
pass
|
||||
# 自定义结构体 (如 self._ht[key]): 仅当类定义了 __getitem__ 才转发方法调用;
|
||||
@@ -1037,13 +1074,13 @@ class ExprGenName(ExprGenBase.ExprGenBase):
|
||||
elem_ptr_gen: rawptr[llvmlite.Value] = llvmlite.build_gep(
|
||||
builder, elem_ty2, ptr_val, idx_val)
|
||||
if elem_ptr_gen is not None:
|
||||
return llvmlite.build_load(builder, elem_ty2, elem_ptr_gen)
|
||||
return llvmlite.build_load(builder, elem_ty2, elem_ptr_gen, vol_sub_gen)
|
||||
return None
|
||||
# 指针类型: 单索引 GEP + load
|
||||
elem_ptr4: rawptr[llvmlite.Value] = llvmlite.build_gep(
|
||||
builder, elem_ty2, ptr_val, idx_val)
|
||||
if elem_ptr4 is not None:
|
||||
return llvmlite.build_load(builder, elem_ty2, elem_ptr4)
|
||||
return llvmlite.build_load(builder, elem_ty2, elem_ptr4, vol_sub_gen)
|
||||
return None
|
||||
# ============================================================
|
||||
# 获取下标表达式的元素指针(不加载值,用于赋值)
|
||||
|
||||
@@ -479,7 +479,7 @@ class ExprGenOps(ExprGenBase.ExprGenBase):
|
||||
return None
|
||||
op: int = ops_list.get(0)
|
||||
|
||||
comparators: rawptr[list[rawptr[ast.AST]]] = cmp.comparators
|
||||
comparators: list[ast.AST*]* = cmp.comparators
|
||||
if comparators is None or len(comparators) == 0:
|
||||
return None
|
||||
rhs_node: rawptr[ast.AST] = comparators.get(0)
|
||||
@@ -966,7 +966,7 @@ class ExprGenOps(ExprGenBase.ExprGenBase):
|
||||
return None
|
||||
|
||||
op: int = bo.op
|
||||
values: rawptr[list[rawptr[ast.AST]]] = bo.values
|
||||
values: list[ast.AST*]* = bo.values
|
||||
if values is None:
|
||||
return None
|
||||
count: sizet = len(values)
|
||||
|
||||
@@ -32,7 +32,7 @@ class FuncGenBase(CallGenBase.CallGenBase):
|
||||
# 返回 LLVM IR 属性字符串(如 "alwaysinline nounwind"),无属性返回 None
|
||||
# ============================================================
|
||||
def extract_func_attrs(self, pool: rawptr[memhub.MemBuddy],
|
||||
decorator_list: rawptr[list[rawptr[ast.AST]]],
|
||||
decorator_list: list[ast.AST*]*,
|
||||
imported_modules: str) -> str:
|
||||
"""从 decorator_list 提取 c.Attribute 属性,返回 LLVM IR 属性字符串"""
|
||||
if decorator_list is None:
|
||||
@@ -84,7 +84,7 @@ class FuncGenBase(CallGenBase.CallGenBase):
|
||||
# 遍历参数提取属性
|
||||
if call_node.args is None:
|
||||
continue
|
||||
args_list: rawptr[list[rawptr[ast.AST]]] = call_node.args
|
||||
args_list: list[ast.AST*]* = call_node.args
|
||||
an: sizet = len(args_list)
|
||||
for ai in range(an):
|
||||
arg_node: rawptr[ast.AST] = args_list.get(ai)
|
||||
@@ -108,7 +108,7 @@ class FuncGenBase(CallGenBase.CallGenBase):
|
||||
return None
|
||||
return attrs_buf
|
||||
def extract_func_section(self, pool: rawptr[memhub.MemBuddy],
|
||||
decorator_list: rawptr[list[rawptr[ast.AST]]],
|
||||
decorator_list: list[ast.AST*]*,
|
||||
imported_modules: str) -> str:
|
||||
"""提取 @c.Attribute(t.attr.section("xxx")) 为属性组文本 '"section"="xxx"'。
|
||||
|
||||
@@ -133,7 +133,7 @@ class FuncGenBase(CallGenBase.CallGenBase):
|
||||
continue
|
||||
if call_node.args is None:
|
||||
continue
|
||||
args_list: rawptr[list[rawptr[ast.AST]]] = call_node.args
|
||||
args_list: list[ast.AST*]* = call_node.args
|
||||
an: sizet = len(args_list)
|
||||
for ai in range(an):
|
||||
arg_node: rawptr[ast.AST] = args_list.get(ai)
|
||||
@@ -331,7 +331,7 @@ class FuncGenBase(CallGenBase.CallGenBase):
|
||||
"""函数体顶层是否含 raise(非 StopIteration),1=是 / 0=否"""
|
||||
if fd is None or fd.children is None:
|
||||
return 0
|
||||
body_f: rawptr[list[rawptr[ast.AST]]] = fd.children
|
||||
body_f: list[ast.AST*]* = fd.children
|
||||
bn_f: sizet = len(body_f)
|
||||
for bi_f in range(bn_f):
|
||||
stmt_f: rawptr[ast.AST] = body_f.get(bi_f)
|
||||
@@ -388,7 +388,7 @@ class FuncGenBase(CallGenBase.CallGenBase):
|
||||
deco_fa_cr: rawptr[ast.Attribute] = rawptr[ast.Attribute](deco_call_cr.func)
|
||||
if deco_fa_cr.attr is None or string.strcmp(deco_fa_cr.attr, "CReturn") != 0:
|
||||
continue
|
||||
cr_args: rawptr[list[rawptr[ast.AST]]] = deco_call_cr.args
|
||||
cr_args: list[ast.AST*]* = deco_call_cr.args
|
||||
if cr_args is None:
|
||||
continue
|
||||
cr_an: sizet = len(cr_args)
|
||||
@@ -427,7 +427,7 @@ class FuncGenBase(CallGenBase.CallGenBase):
|
||||
if args_node is not None:
|
||||
ags: rawptr[ast.Arguments] = rawptr[ast.Arguments](args_node)
|
||||
if ags.args is not None:
|
||||
alist: rawptr[list[rawptr[ast.AST]]] = ags.args
|
||||
alist: list[ast.AST*]* = ags.args
|
||||
an: sizet = len(alist)
|
||||
i32_ty: rawptr[llvmlite.LLVMType] = llvmlite.Int32(pool)
|
||||
for ai in range(an):
|
||||
|
||||
@@ -49,7 +49,7 @@ class FuncGenDef(CallGenBase.CallGenBase):
|
||||
i8_ty: rawptr[llvmlite.LLVMType] = llvmlite.Int8(pool)
|
||||
i8_ptr_ty: rawptr[llvmlite.LLVMType] = llvmlite.Ptr(pool, i8_ty)
|
||||
|
||||
ch: rawptr[list[rawptr[ast.AST]]] = tree.children
|
||||
ch: list[ast.AST*]* = tree.children
|
||||
if ch is None:
|
||||
return 0
|
||||
|
||||
@@ -210,10 +210,10 @@ class FuncGenDef(CallGenBase.CallGenBase):
|
||||
if fd_args_node is not None:
|
||||
fd_ags: rawptr[ast.Arguments] = rawptr[ast.Arguments](fd_args_node)
|
||||
if fd_ags.args is not None:
|
||||
fd_alist: rawptr[list[rawptr[ast.AST]]] = fd_ags.args
|
||||
fd_alist: list[ast.AST*]* = fd_ags.args
|
||||
fd_param_count = len(fd_alist)
|
||||
if fd_ags.defaults is not None:
|
||||
fd_dlist: rawptr[list[rawptr[ast.AST]]] = fd_ags.defaults
|
||||
fd_dlist: list[ast.AST*]* = fd_ags.defaults
|
||||
fd_defaults = fd_dlist
|
||||
fd_default_count = len(fd_dlist)
|
||||
|
||||
@@ -234,7 +234,7 @@ class FuncGenDef(CallGenBase.CallGenBase):
|
||||
if args_node is not None:
|
||||
ags: rawptr[ast.Arguments] = rawptr[ast.Arguments](args_node)
|
||||
if ags.args is not None:
|
||||
alist: rawptr[list[rawptr[ast.AST]]] = ags.args
|
||||
alist: list[ast.AST*]* = ags.args
|
||||
an: sizet = len(alist)
|
||||
for ai in range(an):
|
||||
arg: rawptr[ast.Arg] = rawptr[ast.Arg](alist.get(ai))
|
||||
@@ -512,7 +512,7 @@ class FuncGenDef(CallGenBase.CallGenBase):
|
||||
if args_node_extern is not None:
|
||||
ags_e: rawptr[ast.Arguments] = rawptr[ast.Arguments](args_node_extern)
|
||||
if ags_e.args is not None:
|
||||
alist_e: rawptr[list[rawptr[ast.AST]]] = ags_e.args
|
||||
alist_e: list[ast.AST*]* = ags_e.args
|
||||
an_e: sizet = len(alist_e)
|
||||
for ai_e in range(an_e):
|
||||
arg_e: rawptr[ast.Arg] = rawptr[ast.Arg](alist_e.get(ai_e))
|
||||
@@ -611,10 +611,10 @@ class FuncGenDef(CallGenBase.CallGenBase):
|
||||
if args_node is not None:
|
||||
tfd_ags: rawptr[ast.Arguments] = rawptr[ast.Arguments](args_node)
|
||||
if tfd_ags.args is not None:
|
||||
tfd_alist: rawptr[list[rawptr[ast.AST]]] = tfd_ags.args
|
||||
tfd_alist: list[ast.AST*]* = tfd_ags.args
|
||||
tfd_param_count = len(tfd_alist)
|
||||
if tfd_ags.defaults is not None:
|
||||
tfd_dlist: rawptr[list[rawptr[ast.AST]]] = tfd_ags.defaults
|
||||
tfd_dlist: list[ast.AST*]* = tfd_ags.defaults
|
||||
tfd_defaults = tfd_dlist
|
||||
tfd_default_count = len(tfd_dlist)
|
||||
|
||||
@@ -629,7 +629,7 @@ class FuncGenDef(CallGenBase.CallGenBase):
|
||||
if args_node is not None:
|
||||
ags: rawptr[ast.Arguments] = rawptr[ast.Arguments](args_node)
|
||||
if ags.args is not None:
|
||||
alist: rawptr[list[rawptr[ast.AST]]] = ags.args
|
||||
alist: list[ast.AST*]* = ags.args
|
||||
an: sizet = len(alist)
|
||||
for ai in range(an):
|
||||
arg: rawptr[ast.Arg] = rawptr[ast.Arg](alist.get(ai))
|
||||
@@ -787,7 +787,7 @@ class FuncGenDef(CallGenBase.CallGenBase):
|
||||
if args_node is not None:
|
||||
ags2: rawptr[ast.Arguments] = rawptr[ast.Arguments](args_node)
|
||||
if ags2.args is not None:
|
||||
alist2: rawptr[list[rawptr[ast.AST]]] = ags2.args
|
||||
alist2: list[ast.AST*]* = ags2.args
|
||||
an2: sizet = len(alist2)
|
||||
for ai2 in range(an2):
|
||||
arg2: rawptr[ast.Arg] = rawptr[ast.Arg](alist2.get(ai2))
|
||||
@@ -829,12 +829,29 @@ class FuncGenDef(CallGenBase.CallGenBase):
|
||||
if cls_nm is not None:
|
||||
self.Gen.VarGen.set_var_annot_class_name(
|
||||
trans.SymTab, arg2.arg, cls_nm)
|
||||
# t.CVolatile 形参:声明期标记,函数体内该参数名的
|
||||
# load/store 带 volatile(volatile 参数对象的读改写不得
|
||||
# 被优化器提升/合并,如自旋等待入参)。
|
||||
if arg2.annotation is not None:
|
||||
if self.Gen.TypeGenErr.has_decorator_marker(
|
||||
arg2.annotation, "CVolatile", 0) != 0:
|
||||
self.Gen.VarGen.set_var_volatile(
|
||||
trans.SymTab, arg2.arg)
|
||||
# rawptr[t.CVolatile | T] 形参(volatile 指针指向物):
|
||||
# 函数体内该参数解引用(p[i]/p.field/c.Deref(p))带 volatile。
|
||||
if self.Gen.TypeGenErr.has_pointee_volatile_marker(
|
||||
arg2.annotation) != 0:
|
||||
self.Gen.VarGen.set_var_pointee_volatile(
|
||||
trans.SymTab, arg2.arg)
|
||||
pname2: str = pool.alloc(32)
|
||||
if pname2 is not None:
|
||||
viperlib.snprintf(pname2, 32, "%%%s", arg2.arg)
|
||||
param_val: rawptr[llvmlite.Value] = llvmlite.SSAValue(
|
||||
pool, param_ty2, pname2)
|
||||
llvmlite.build_store(func_builder, param_val, alloca)
|
||||
vol_p2: int = self.Gen.VarGen.var_is_volatile(
|
||||
self.Gen.VarGen.lookup_var_entry(
|
||||
trans.SymTab, arg2.arg))
|
||||
llvmlite.build_store(func_builder, param_val, alloca, vol_p2)
|
||||
|
||||
# *args 变长参数:创建 va_list 缓冲区 + 调用 va_start + 注册到符号表
|
||||
# 生成 IR:
|
||||
@@ -924,7 +941,7 @@ class FuncGenDef(CallGenBase.CallGenBase):
|
||||
# 1. 先预扫描 Global/Nonlocal 声明(Python 语义:global/nonlocal
|
||||
# 对整个函数作用域生效,与声明位置无关,故须在任何赋值前注册)
|
||||
# 2. 再预扫描 AnnAssign 为局部变量提前创建 alloca
|
||||
body: rawptr[list[rawptr[ast.AST]]] = fd.children
|
||||
body: list[ast.AST*]* = fd.children
|
||||
if body is not None:
|
||||
bn: sizet = len(body)
|
||||
for bi in range(bn):
|
||||
|
||||
@@ -113,7 +113,7 @@ class FuncGenMixin(CallGenBase.CallGenBase):
|
||||
if fd.args is not None:
|
||||
ags_n: rawptr[ast.Arguments] = rawptr[ast.Arguments](fd.args)
|
||||
if ags_n.args is not None:
|
||||
alist_n: rawptr[list[rawptr[ast.AST]]] = ags_n.args
|
||||
alist_n: list[ast.AST*]* = ags_n.args
|
||||
an_n: sizet = len(alist_n)
|
||||
for ai_n in range(an_n):
|
||||
arg_n: rawptr[ast.Arg] = rawptr[ast.Arg](alist_n.get(ai_n))
|
||||
@@ -168,7 +168,7 @@ class FuncGenMixin(CallGenBase.CallGenBase):
|
||||
if fd.args is not None:
|
||||
ags_p: rawptr[ast.Arguments] = rawptr[ast.Arguments](fd.args)
|
||||
if ags_p.args is not None:
|
||||
alist_p: rawptr[list[rawptr[ast.AST]]] = ags_p.args
|
||||
alist_p: list[ast.AST*]* = ags_p.args
|
||||
idx_p: int = 0
|
||||
apn: sizet = len(alist_p)
|
||||
for api in range(apn):
|
||||
@@ -196,11 +196,25 @@ class FuncGenMixin(CallGenBase.CallGenBase):
|
||||
if cls_nm_p is not None:
|
||||
self.Gen.VarGen.set_var_annot_class_name(
|
||||
trans.SymTab, arg_p.arg, cls_nm_p)
|
||||
# t.CVolatile 形参:声明期标记(与 FuncGenDef 主路径同款),
|
||||
# 函数体内该参数名的 load/store 带 volatile。
|
||||
if self.Gen.TypeGenErr.has_decorator_marker(
|
||||
arg_p.annotation, "CVolatile", 0) != 0:
|
||||
self.Gen.VarGen.set_var_volatile(
|
||||
trans.SymTab, arg_p.arg)
|
||||
# rawptr[t.CVolatile | T] 形参(volatile 指针指向物):
|
||||
# 函数体内该参数解引用带 volatile(与 FuncGenDef 主路径同款)。
|
||||
if self.Gen.TypeGenErr.has_pointee_volatile_marker(
|
||||
arg_p.annotation) != 0:
|
||||
self.Gen.VarGen.set_var_pointee_volatile(
|
||||
trans.SymTab, arg_p.arg)
|
||||
pname2_n: str = pool.alloc(32)
|
||||
if pname2_n is not None:
|
||||
viperlib.snprintf(pname2_n, 32, "%%%s", arg_p.arg)
|
||||
p_val: rawptr[llvmlite.Value] = llvmlite.SSAValue(pool, pty2_n, pname2_n)
|
||||
llvmlite.build_store(func_builder, p_val, p_alloca)
|
||||
vol_pn: int = self.Gen.VarGen.var_is_volatile(
|
||||
self.Gen.VarGen.lookup_var_entry(trans.SymTab, arg_p.arg))
|
||||
llvmlite.build_store(func_builder, p_val, p_alloca, vol_pn)
|
||||
idx_p += 1
|
||||
|
||||
# 6. 保存父函数作用域状态(仅非变量表相关)
|
||||
@@ -232,7 +246,7 @@ class FuncGenMixin(CallGenBase.CallGenBase):
|
||||
# 8. 预扫描函数体:
|
||||
# a. 先预扫描 Global/Nonlocal 声明(Python 语义:对整个函数作用域生效)
|
||||
# b. 再预扫描 AnnAssign 为局部变量提前创建 alloca
|
||||
body: rawptr[list[rawptr[ast.AST]]] = fd.children
|
||||
body: list[ast.AST*]* = fd.children
|
||||
if body is not None:
|
||||
bn: sizet = len(body)
|
||||
for bi in range(bn):
|
||||
@@ -951,7 +965,7 @@ class FuncGenMixin(CallGenBase.CallGenBase):
|
||||
fd: rawptr[ast.FunctionDef] = rawptr[ast.FunctionDef](node)
|
||||
if fd is None or fd.children is None:
|
||||
return count
|
||||
ch: rawptr[list[rawptr[ast.AST]]] = fd.children
|
||||
ch: list[ast.AST*]* = fd.children
|
||||
cn: sizet = len(ch)
|
||||
for ci in range(cn):
|
||||
st: rawptr[ast.AST] = ch.get(ci)
|
||||
@@ -963,7 +977,7 @@ class FuncGenMixin(CallGenBase.CallGenBase):
|
||||
elif k == ast.ASTKind.Nonlocal:
|
||||
nl_node: rawptr[ast.Nonlocal] = rawptr[ast.Nonlocal](st)
|
||||
if nl_node is not None and nl_node.names is not None:
|
||||
nl_list: rawptr[list[rawptr[ast.AST]]] = nl_node.names
|
||||
nl_list: list[ast.AST*]* = nl_node.names
|
||||
nn: sizet = len(nl_list)
|
||||
for ni in range(nn):
|
||||
nm_node: rawptr[ast.AST] = nl_list.get(ni)
|
||||
@@ -1137,7 +1151,7 @@ class FuncGenMixin(CallGenBase.CallGenBase):
|
||||
if lam.args is not None:
|
||||
ags: rawptr[ast.Arguments] = rawptr[ast.Arguments](lam.args)
|
||||
if ags.args is not None:
|
||||
alist: rawptr[list[rawptr[ast.AST]]] = ags.args
|
||||
alist: list[ast.AST*]* = ags.args
|
||||
pn: sizet = len(alist)
|
||||
for pi in range(pn):
|
||||
if param_count >= 64:
|
||||
@@ -1482,7 +1496,7 @@ class FuncGenMixin(CallGenBase.CallGenBase):
|
||||
bop2: rawptr[ast.BoolOp] = rawptr[ast.BoolOp](node)
|
||||
cc2: int = cap_count
|
||||
if bop2.values is not None:
|
||||
vs: rawptr[list[rawptr[ast.AST]]] = bop2.values
|
||||
vs: list[ast.AST*]* = bop2.values
|
||||
vn: sizet = len(vs)
|
||||
for vi in range(vn):
|
||||
cc2 = self._lambda_scan_body(trans, vs.get(vi), param_names, param_count,
|
||||
@@ -1493,7 +1507,7 @@ class FuncGenMixin(CallGenBase.CallGenBase):
|
||||
cc3: int = self._lambda_scan_body(trans, cmp.left, param_names, param_count,
|
||||
cap_names, cap_allocas, cap_tys, cap_count)
|
||||
if cmp.comparators is not None:
|
||||
cl: rawptr[list[rawptr[ast.AST]]] = cmp.comparators
|
||||
cl: list[ast.AST*]* = cmp.comparators
|
||||
cn: sizet = len(cl)
|
||||
for cvi in range(cn):
|
||||
cc3 = self._lambda_scan_body(trans, cl.get(cvi), param_names, param_count,
|
||||
@@ -1504,13 +1518,13 @@ class FuncGenMixin(CallGenBase.CallGenBase):
|
||||
cc4: int = self._lambda_scan_body(trans, cal.func, param_names, param_count,
|
||||
cap_names, cap_allocas, cap_tys, cap_count)
|
||||
if cal.args is not None:
|
||||
als: rawptr[list[rawptr[ast.AST]]] = cal.args
|
||||
als: list[ast.AST*]* = cal.args
|
||||
an: sizet = len(als)
|
||||
for ai in range(an):
|
||||
cc4 = self._lambda_scan_body(trans, als.get(ai), param_names, param_count,
|
||||
cap_names, cap_allocas, cap_tys, cc4)
|
||||
if cal.keywords is not None:
|
||||
kws: rawptr[list[rawptr[ast.AST]]] = cal.keywords
|
||||
kws: list[ast.AST*]* = cal.keywords
|
||||
kn: sizet = len(kws)
|
||||
for ki in range(kn):
|
||||
kw: rawptr[ast.Keyword] = rawptr[ast.Keyword](kws.get(ki))
|
||||
@@ -1542,7 +1556,7 @@ class FuncGenMixin(CallGenBase.CallGenBase):
|
||||
ls: rawptr[ast.List] = rawptr[ast.List](node)
|
||||
cc7: int = cap_count
|
||||
if ls.elts is not None:
|
||||
es: rawptr[list[rawptr[ast.AST]]] = ls.elts
|
||||
es: list[ast.AST*]* = ls.elts
|
||||
en: sizet = len(es)
|
||||
for ei in range(en):
|
||||
cc7 = self._lambda_scan_body(trans, es.get(ei), param_names, param_count,
|
||||
|
||||
@@ -37,9 +37,20 @@ def set_current_file_imports(file_path: str) -> None:
|
||||
|
||||
# ---------------- set_current_file_type(委托 TypeGenResolve.set_current_file) ----------------
|
||||
def set_current_file_type(file_path: str) -> None:
|
||||
"""委托到 gen.set_current_file(原 Handles 壳)"""
|
||||
"""委托到 gen.set_current_file —— 报错归因的"当前文件"写入通道(原 Handles 壳)
|
||||
|
||||
与 fatal_error 同因同解:Converter 的 vpi 生成(Phase 1)、Phase A-pre-vpi
|
||||
跑在 BuildPipeline 注入 GenApi._g_gen 之前(BuildPipeline.vp 的
|
||||
_GeneratePyiFromAst 调用点早于 GenApi._g_gen 赋值),此时 _g_gen 为空;
|
||||
写侧若缺兜底会静默 no-op → fatal_error 的 get_current_file 读到的仍是
|
||||
上一个文件(归因错位)。故回退读 Generator 模块单例(main.vp 启动即注入)。
|
||||
"""
|
||||
if _g_gen is not None:
|
||||
_g_gen.TypeGenResolve.set_current_file(file_path)
|
||||
return
|
||||
gg: rawptr[Generator.Generator] = Generator._g_gen
|
||||
if gg is not None:
|
||||
gg.TypeGenResolve.set_current_file(file_path)
|
||||
|
||||
|
||||
# ---------------- set_current_module_sha1(委托 TypeGenBase.set_current_module_sha1) ----------------
|
||||
|
||||
@@ -72,6 +72,15 @@ class VarEntry:
|
||||
# set_var_ptr_element 经 SpecWithElemBits 补「指针元素」语义(原
|
||||
# IsPtrElement 字段已并入 Spec.ElemBits)。
|
||||
Spec: rawptr[TSpec.TypeSpec]
|
||||
# 1=该变量的 load/store 带 LLVM volatile 限定符(注解联合含 t.CVolatile)。
|
||||
# 追加在末尾:既有字段偏移不变,__sizeof__() 自动纳入,条目数组步长同步。
|
||||
IsVolatile: int
|
||||
# 1=该变量是 rawptr[t.CVolatile | T](volatile 指针指向物,等价 C 的
|
||||
# volatile T*):解引用(p[i] / p.field / c.Deref(p))的 load/store 带 LLVM
|
||||
# volatile,禁止优化器重排序/消除对所指对象的每次访问。注意与 IsVolatile
|
||||
# 的区别:IsVolatile 限定"指针变量自身"的读写,本字段限定"指针所指物"。
|
||||
# 追加在末尾:既有字段偏移不变,__sizeof__() 自动纳入,条目数组步长同步。
|
||||
PointeeVolatile: int
|
||||
|
||||
|
||||
# ============================================================
|
||||
@@ -110,6 +119,15 @@ class FieldEntry:
|
||||
# 注解侧再经 SpecWithSign / SpecWithSource 补符号性与注解来源名
|
||||
# (Spec.SourceName,原 AnnotClassName 字段已并入)。
|
||||
Spec: rawptr[TSpec.TypeSpec]
|
||||
# 1=该字段经对象访问的 load/store 带 LLVM volatile 限定符
|
||||
# (字段注解联合含 t.CVolatile,如 Spinlock.locked: t.CVolatile | t.CInt)。
|
||||
# 追加在末尾:既有字段偏移不变,__sizeof__() 自动纳入,字段数组步长同步。
|
||||
IsVolatile: int
|
||||
# 1=该字段是 rawptr[t.CVolatile | T](volatile 指针指向物,等价 C 的
|
||||
# volatile T*):经该字段解引用(self.ptr[i] / self.ptr.field)的 load/store
|
||||
# 带 LLVM volatile。与 IsVolatile 的区别同 VarEntry.PointeeVolatile。
|
||||
# 追加在末尾:既有字段偏移不变,__sizeof__() 自动纳入,字段数组步长同步。
|
||||
PointeeVolatile: int
|
||||
|
||||
|
||||
# ============================================================
|
||||
@@ -207,3 +225,205 @@ class FuncDefaultsEntry:
|
||||
ConstKinds: int | t.CPtr # const_kind 数组(DefaultCount 个 i32)
|
||||
ConstInts: int64 | t.CPtr # int_val 数组(DefaultCount 个 i64)
|
||||
ConstStrs: sizet | t.CPtr # str_val 指针数组(DefaultCount 个 i8*)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# REPL 会话(M2/M3):ctx 缓冲区布局 + 会话表条目 + 结果区头
|
||||
#
|
||||
# ctx 缓冲区由宿主(lib/core/Repl.vp)在 PermPool 一次性分配,片段函数以首形参
|
||||
# 接收(注解 bytes ⇒ i8*),同一进程内宿主与翻译器共享同一块内存。
|
||||
#
|
||||
# 布局(用户拍板子约定;字节全小端,无符号/有符号按位模式):
|
||||
#
|
||||
# 偏移 0 magic(u32 = 'REPL' = 0x5245504C) 4 version(u32 = 2)
|
||||
# 偏移 8 result_kind(i32) 12 保留(0)
|
||||
# 偏移 16 result_a(u64) 24 result_b(u64)
|
||||
# 偏移 32 var_count(i32) 36 last_frag(i32)
|
||||
# 偏移 40..63 保留(0)
|
||||
# 偏移 64 + i*16 第 i 个会话变量的槽(步长 16 字节),i < REPL_VAR_CAP
|
||||
# 偏移 1088 + j*16 第 j 个会话函数的指针槽(步长 16 字节),j < REPL_FUNC_CAP
|
||||
#
|
||||
# 版本与向后兼容(version 1 → 2,**纯尾部追加**):
|
||||
# v1 = 头 64B + 变量槽区 1024B(共 1088B);v2 在 1088 之后追加函数指针槽区
|
||||
# (REPL_FUNC_CAP*REPL_FUNC_SLOT_SIZE)。前 1088 字节的字段偏移/宽度/语义逐字
|
||||
# 未变 ⇒ 按 v1 生成的旧片段 DLL 与 v2 宿主混用仍然正确(旧片段只读写
|
||||
# < 1088 的字节);新片段读函数指针槽时宿主必为 v2 ⇒ 无版本协商需求。
|
||||
# 头 +4 写 2 仅作"含函数指针槽区"的显式标记(片段侧不校验该字段)。
|
||||
#
|
||||
# result_kind:
|
||||
# 0 = none 本片段无结果(声明类片段)
|
||||
# 1 = int/uint result_a = 值(补码位模式,宿主按有符号 64 位回显)
|
||||
# 2 = float64 result_a = IEEE754 double 位模式(宿主重解释后回显)
|
||||
# 3 = str/bytes result_a = 指针;result_b = 长度(0 = 以 NUL 结尾,宿主按
|
||||
# C 字符串处理——片段侧不额外调 strlen,故长度未知时写 0)
|
||||
# 4 = struct/其它 result_a = 值地址(结构体值装箱后的盒子地址 / 非字符串指针)
|
||||
#
|
||||
# 槽内存放形态(ReplVarEntry.Kind):
|
||||
# SCALAR — 标量/指针(≤8 字节)的值直接存槽;
|
||||
# BOX — 结构体值:片段侧 malloc 盒子(值存盒内),槽内存盒子指针。
|
||||
# 槽步长 16 字节(结构体/字符串统一走指针 ⇒ 宿主无需知道类型);负载一律
|
||||
# ≤8 字节且 8 字节对齐即合法(MemBuddy 用户指针实测 8 字节对齐)。
|
||||
# 槽数上限 REPL_VAR_CAP ⇒ 变量区尺寸 = REPL_SLOT_BASE + REPL_VAR_CAP*REPL_SLOT_SIZE。
|
||||
#
|
||||
# 函数指针槽(M3):槽内是会话函数在**定义片段 DLL** 里的入口地址(void*,8 字节;
|
||||
# DLL 常驻不卸载 ⇒ 地址在会话期内有效)。宿主在片段 DLL 加载成功后
|
||||
# GetProcAddress(裸名) 取得地址并写入槽;后续片段的调用点从槽 load 地址后
|
||||
# 间接调用 ⇒ 函数代码只有一份(在定义片段里),调用点不复制代码。
|
||||
# ============================================================
|
||||
REPL_CTX_MARKER: t.CDefine = 1397571916 # 宿主侧对象标记(自比对;非 ctx 头字段)
|
||||
REPL_CTX_MAGIC: t.CDefine = 0x5245504C # 'REPL'(ctx 头 +0,小端字节序为 R E P L)
|
||||
REPL_CTX_VERSION: t.CDefine = 2 # ctx 头 +4(1 → 2:尾部追加函数指针槽区)
|
||||
REPL_SLOT_SIZE: t.CDefine = 16 # 每个会话变量占用字节数(步长)
|
||||
REPL_SLOT_BASE: t.CDefine = 64 # 槽区起点 = 固定头字节数(= +40..63 保留之后)
|
||||
REPL_CTX_PARAM: t.CDefine = "__repl_ctx__" # 包裹模板里 ctx 形参名(与 Repl.vp 同源)
|
||||
REPL_VAR_CAP: t.CDefine = 64 # 会话变量上限(变量区 = 64 + 64*16 = 1088 字节)
|
||||
# 会话函数指针槽区(M3):起点紧跟变量区,步长与变量槽一致(16B,低 8 字节存地址)
|
||||
REPL_FUNC_BASE: t.CDefine = 1088 # = REPL_SLOT_BASE + REPL_VAR_CAP*REPL_SLOT_SIZE
|
||||
REPL_FUNC_SLOT_SIZE: t.CDefine = 16 # 每个会话函数占用字节数(步长)
|
||||
REPL_FUNC_CAP: t.CDefine = 32 # 会话函数上限(函数区 = 32*16 = 512 字节)
|
||||
# ctx 总字节数 = 64 + 64*16 + 32*16 = 1600(宿主 Repl._REPL_CTX_SIZE 必须一致)
|
||||
REPL_CTX_SIZE: t.CDefine = 1600
|
||||
# 会话函数的形参上限(签名 token 数组定长;超出 ⇒ 注册期明确报错)
|
||||
REPL_FUNC_PARAM_MAX: t.CDefine = 8
|
||||
# 片段入口函数名前缀(Repl.vp 生成 "__repl_frag_%d";用于区分"片段入口函数"与
|
||||
# 被提升的会话函数本体——前者是会话变量写入的作用域,后者只读会话槽)
|
||||
REPL_ENTRY_PREFIX: t.CDefine = "__repl_frag_"
|
||||
# 会话模块 SHA1(M4):片段翻译器的 ModuleSha1 取此**稳定**值 ⇒ 片段内定义的类型
|
||||
# 名形如 "<16位hex>.<Type>",且**跨片段逐字一致**——这是"先前片段定义的类在后续
|
||||
# 片段可见/可用"的基础(类型名是跨片段查找的唯一键)。
|
||||
# 派生:sha1("TransPyV-REPL-Session").hexdigest()[:16]
|
||||
# 得 71f67b7cb405f0e4(一次性计算,见 repl-design.md §M4 的可复算命令)。
|
||||
# 形态:16 位小写 hex 与 includes 模块 SHA1 同形 ⇒ 被既有判定
|
||||
# GenApi.is_sha1_hex16 / StructGen.find_struct 的"模块段即 SHA1"分支
|
||||
# 直接当作模块限定名处理(无需新增解析规则)。
|
||||
# 反例(为什么不给每个片段各设一个 sha1):类型名会随片段漂移,先前片段注册的
|
||||
# 结构体/方法在后续片段的 find_struct_by_module 全部落空。
|
||||
# 与裸名约定的关系:`export def`(含片段入口与会话函数)走 has_export 分支取裸名
|
||||
# (FuncGenDef.vp:482-485),**不受**该值影响;受影响的只有类/方法/模块级全局
|
||||
# 等经 _mangle_name/_mangle_name_with_sha1 命名的符号。
|
||||
REPL_SESSION_SHA1: t.CDefine = "71f67b7cb405f0e4"
|
||||
|
||||
# ctx 头字段偏移(与 ReplResult 字段顺序/宽度一一对应)
|
||||
REPL_RES_KIND_OFF: t.CDefine = 8 # i32
|
||||
REPL_RES_A_OFF: t.CDefine = 16 # u64
|
||||
REPL_RES_B_OFF: t.CDefine = 24 # u64
|
||||
REPL_RES_VARCOUNT_OFF: t.CDefine = 32 # i32
|
||||
REPL_RES_LASTFRAG_OFF: t.CDefine = 36 # i32
|
||||
|
||||
# 结果 Kind(宿主按此回显)
|
||||
REPL_RES_NONE: t.CDefine = 0 # 本片段无结果(如仅声明)
|
||||
REPL_RES_INT: t.CDefine = 1 # 整数(读 result_a 位模式)
|
||||
REPL_RES_FLOAT: t.CDefine = 2 # float64(读 result_a 的 double 位模式)
|
||||
REPL_RES_STR: t.CDefine = 3 # str/bytes(读 result_a 指针 + result_b 长度)
|
||||
REPL_RES_OBJ: t.CDefine = 4 # 结构体/其它指针(读 result_a 地址)
|
||||
|
||||
# 会话变量类型标签(ReplVarEntry.TyTag)
|
||||
REPL_TY_INT: t.CDefine = 1
|
||||
REPL_TY_FLOAT: t.CDefine = 2
|
||||
REPL_TY_STR: t.CDefine = 3 # i8*(str/bytes)
|
||||
REPL_TY_PTR: t.CDefine = 4 # 其他指针(Bits=pointee 位宽 / TyName=结构体名)
|
||||
REPL_TY_STRUCT: t.CDefine = 5 # 结构体值(按声明类型内联在槽里;≤ 槽容量)
|
||||
|
||||
# 会话变量存放形态(ReplVarEntry.Kind)
|
||||
REPL_KIND_UNTYPED: t.CDefine = 0 # 已登记槽位但尚未定型(未赋值/无注解)
|
||||
REPL_KIND_SCALAR: t.CDefine = 1 # 值内联存槽(标量/指针/≤16B 结构体值)
|
||||
|
||||
# 会话函数签名的返回类型 token(M3;只用于 ReplFuncEntry.RetTag)
|
||||
REPL_TY_VOID: t.CDefine = 0 # 无返回值(void;不作为形参 token)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ReplVarEntry - REPL 会话变量条目(跨片段存活,表本体在 PermPool)
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class ReplVarEntry:
|
||||
"""REPL 会话变量条目:名字 + ctx 槽偏移 + 定型信息
|
||||
|
||||
Name/TyName 必须是 PermPool 深拷贝——宿主的 AST 名字串属于片段 pool,
|
||||
行末 reset_to 后即失效,直接存指针会读到已回收内存。
|
||||
"""
|
||||
Name: str # 变量名(PermPool 深拷贝,NUL 结尾)
|
||||
TyName: str # 结构体名(TyTag=PTR 且 pointee 为结构体 / TyTag=STRUCT);否则 None
|
||||
Offset: int # ctx 内槽偏移(REPL_SLOT_BASE + i * REPL_SLOT_SIZE)
|
||||
Kind: int # REPL_KIND_*
|
||||
TyTag: int # REPL_TY_*
|
||||
Bits: int # 标量位宽;TyTag=PTR 时是 pointee 位宽(0=未知)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ReplFuncEntry - REPL 会话函数条目(M3;跨片段存活,表本体在 PermPool)
|
||||
#
|
||||
# 语义:片段 N 里 `def f(...)` 被提升为片段模块里的**顶层 export def**(裸名导出),
|
||||
# 该 DLL 加载后宿主 GetProcAddress 取到地址并写入 ctx 的函数指针槽;本条目记录
|
||||
# "名字 → 符号名 + 定义片段号 + 槽偏移 + 签名 token",后续片段的调用点据此
|
||||
# 从槽 load 地址并间接调用(与 M2 的会话变量槽同理:单一真相 + 间接寻址)。
|
||||
#
|
||||
# 签名 token(ParamTags/ParamBits 每形参 1 字节、RetTag/RetBits)与来源:
|
||||
# 定义片段翻译出的 IR 里 `define <ret> @f(i8* %__repl_ctx__, <P1> %p1, ...)`
|
||||
# 是 ABI 的唯一真相(注解 → LLVM 类型由 codegen 解析),宿主在注册前解析该
|
||||
# define 行并**只接受**可往返重建的 token 集合:
|
||||
# REPL_TY_INT(bits=1/8/16/32/64) / REPL_TY_FLOAT(bits=32/64) / REPL_TY_STR(i8*)
|
||||
# 其余类型(结构体值、数组、多级指针等)⇒ 注册期明确报错,绝不静默按 i32 兜底。
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class ReplFuncEntry:
|
||||
"""REPL 会话函数条目:名字 + 导出符号名 + ctx 函数指针槽 + 签名 token"""
|
||||
Name: str # 会话函数名(= 用户写的裸名;PermPool 深拷贝,NUL 结尾)
|
||||
SymName: str # 片段 DLL 里的导出符号名(PermPool 深拷贝;M3 = 裸名)
|
||||
FragNo: int # 定义该函数的片段号(重定义时更新为最新片段号)
|
||||
SlotOff: int # ctx 内函数指针槽偏移(REPL_FUNC_BASE + j*REPL_FUNC_SLOT_SIZE)
|
||||
RetTag: int # REPL_TY_VOID / REPL_TY_INT / REPL_TY_FLOAT / REPL_TY_STR
|
||||
RetBits: int # 对齐 ReplVarEntry.Bits 的口径(VOID 时为 0)
|
||||
ParamCount: int # 形参数(**不含**注入的 ctx 首形参)
|
||||
ParamTags: str # PermPool 字节数组(每形参 1 字节 tag,REPL_FUNC_PARAM_MAX 个)
|
||||
ParamBits: str # PermPool 字节数组(每形参 1 字节 bits,REPL_FUNC_PARAM_MAX 个)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ReplCtx - REPL 会话上下文(宿主建、翻译器读)
|
||||
#
|
||||
# 开关语义:trans.ReplCtx != None ⇒ REPL 模式(仅 Repl.vp 翻译片段前置位,
|
||||
# 翻译后清空)。Gen 侧全部拦截点都以此字段为唯一守卫——普通编译路径下该字段
|
||||
# 恒为 None,逐字走原路径。
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class ReplCtx:
|
||||
"""REPL 模式上下文(宿主持有;翻译器只读)"""
|
||||
Marker: int # REPL_CTX_MARKER(防误传非 ReplCtx 对象)
|
||||
Table: rawptr[ReplVarEntry] # 会话表数组(PermPool,容量 Cap)
|
||||
Count: int # 已登记条目数(= 已分配槽数)
|
||||
Cap: int # 容量(REPL_VAR_CAP)
|
||||
CtxParam: str # 片段函数 ctx 形参名(PermPool 深拷贝)
|
||||
SlotSize: int # 槽步长(REPL_SLOT_SIZE)
|
||||
# 影子条目(宿主建、PermPool):仅供"裸表达式结果"做类型分类用,不占会话槽、
|
||||
# 不进表(Count 不计入),Name 固定为 "<expr>" 以便错误消息可读。
|
||||
Scratch: rawptr[ReplVarEntry]
|
||||
# 宿主提供的永久池:会话表条目名/结构体名等**跨片段存活**的数据必须在此池
|
||||
# 深拷贝(片段的 trans.Pool 行末 reset_to 即回收,直接存其指针会悬垂)。
|
||||
Perm: rawptr[memhub.MemBuddy]
|
||||
# 会话函数表(M3;宿主写、Gen 只读):数组容量 FuncCap,已登记 FuncCount 条。
|
||||
# 条目只在"定义片段 DLL 加载成功且 GetProcAddress 命中"后由宿主追加 ⇒ 片段
|
||||
# 翻译期看到的表恒为"先前片段的已就绪函数"(本片段新定义的同名函数走直接调用)。
|
||||
FuncTable: rawptr[ReplFuncEntry]
|
||||
FuncCount: int
|
||||
FuncCap: int # 容量(REPL_FUNC_CAP)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ReplResult - ctx 头(宿主按字段读;片段按 REPL_RES_*_OFF 字节偏移写)
|
||||
#
|
||||
# 字段顺序/宽度即 ctx 布局:Magic(+0,i32) Version(+4,i32) Kind(+8,i32)
|
||||
# Reserved0(+12,i32) A(+16,i64) B(+24,i64) VarCount(+32,i32) LastFrag(+36,i32)。
|
||||
# 宿主另有"同一头的浮点视图"(把 +16 的 8 字节按 double 读回,见 Repl.vp)。
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class ReplResult:
|
||||
"""ctx 固定头(前 64 字节中的前 40 字节;+40..63 为保留)"""
|
||||
Magic: int # REPL_CTX_MAGIC('REPL')
|
||||
Version: int # REPL_CTX_VERSION
|
||||
Kind: int # REPL_RES_*
|
||||
Reserved0: int # 保留(0)
|
||||
A: t.CInt64T # result_a
|
||||
B: t.CInt64T # result_b
|
||||
VarCount: int # 已分配槽数(宿主写,供检视)
|
||||
LastFrag: int # 最近执行的片段号(宿主写,供检视)
|
||||
@@ -14,6 +14,7 @@ import lib.Stub.StubMerger as StubMerger
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
import lib.core.Gen.Translator as HT
|
||||
import lib.Stub.StubMerger.StubMergerStore as StubMergerStore
|
||||
import lib.core.VLogger as VLogger
|
||||
|
||||
|
||||
# ============================================================
|
||||
@@ -731,7 +732,8 @@ class ImportsGenMixin:
|
||||
stdlib.free(line_buf_err)
|
||||
f_err.close()
|
||||
stdio.printf("ImportError: %s\n", msg)
|
||||
sys.exit(1)
|
||||
# 终止点收敛:REPL 会话内 longjmp 回 REPL 循环(诊断已打印),批处理下终止
|
||||
VLogger.repl_abort()
|
||||
|
||||
# ============================================================
|
||||
# _is_local_module_file - 当前文件同目录存在 {mod_name}.vp/.py
|
||||
@@ -819,7 +821,7 @@ class ImportsGenMixin:
|
||||
imp: rawptr[ast.Import] = rawptr[ast.Import](node)
|
||||
if imp is None:
|
||||
return 0
|
||||
names: rawptr[list[rawptr[ast.AST]]] = imp.names
|
||||
names: list[ast.AST*]* = imp.names
|
||||
if names is None:
|
||||
return 0
|
||||
nn: sizet = len(names)
|
||||
@@ -893,7 +895,7 @@ class ImportsGenMixin:
|
||||
# 否则别名 "syscall" 精确匹配不到包名 "vpsdk" → is_module_imported 返回 0
|
||||
# → syscall._syscall1 / syscall.LOAD_SO 跨模块解析失败。
|
||||
if impf.module is None:
|
||||
names_m: rawptr[list[rawptr[ast.AST]]] = impf.names
|
||||
names_m: list[ast.AST*]* = impf.names
|
||||
if names_m is not None:
|
||||
nn_m: sizet = len(names_m)
|
||||
for ni_m in range(nn_m):
|
||||
@@ -937,7 +939,7 @@ class ImportsGenMixin:
|
||||
trans.Pool, trans.CurrentPackage,
|
||||
impf.level, impf.module)
|
||||
if resolved is not None:
|
||||
names: rawptr[list[rawptr[ast.AST]]] = impf.names
|
||||
names: list[ast.AST*]* = impf.names
|
||||
if names is not None:
|
||||
nn: sizet = len(names)
|
||||
for ni in range(nn):
|
||||
|
||||
@@ -39,7 +39,7 @@ class MatchGenMixin:
|
||||
Gen: rawptr[Generator.Generator]
|
||||
def _case_tail_unreachable(self, trans: rawptr[HT.Translator],
|
||||
builder: rawptr[llvmlite.IRBuilder],
|
||||
body_list: rawptr[list[rawptr[ast.AST]]]) -> int:
|
||||
body_list: list[ast.AST*]*) -> int:
|
||||
if trans is None or builder is None:
|
||||
return 0
|
||||
if llvmlite.builder_cur_block_is_terminated(builder) != 0:
|
||||
@@ -132,7 +132,7 @@ class MatchGenMixin:
|
||||
|
||||
# 2b. 若未确定,遍历 cases 查 MatchClass 变体
|
||||
if is_renum == 0:
|
||||
cases_list: rawptr[list[rawptr[ast.AST]]] = m_node.cases
|
||||
cases_list: list[ast.AST*]* = m_node.cases
|
||||
if cases_list is not None:
|
||||
cn: sizet = len(cases_list)
|
||||
ci: int = 0
|
||||
@@ -227,7 +227,7 @@ class MatchGenMixin:
|
||||
#
|
||||
# 遍历 case body 顶层语句,查找 Expr(Call(Attribute(Name('c'), 'NoBreak')))
|
||||
# ============================================================
|
||||
def _has_no_break(self, body_list: rawptr[list[rawptr[ast.AST]]]) -> int:
|
||||
def _has_no_break(self, body_list: list[ast.AST*]*) -> int:
|
||||
if body_list is None:
|
||||
return 0
|
||||
n: sizet = len(body_list)
|
||||
@@ -352,7 +352,7 @@ class MatchGenMixin:
|
||||
pool, func, name_buf)
|
||||
|
||||
# 3. 准备收集数组(用 CSizeT 数组存指针)
|
||||
cases_list: rawptr[list[rawptr[ast.AST]]] = node.cases
|
||||
cases_list: list[ast.AST*]* = node.cases
|
||||
if cases_list is None:
|
||||
# fail-fast: match cases 缺失
|
||||
self.Gen.TypeGenErr.fatal_error(node, "match cases 缺失", "TypeError")
|
||||
@@ -452,7 +452,7 @@ class MatchGenMixin:
|
||||
elif pk == ast.ASTKind.MatchOr:
|
||||
# MatchOr: 多个值共享一个 BB(取第一个值做 case)
|
||||
mo: rawptr[ast.MatchOr] = rawptr[ast.MatchOr](pat)
|
||||
pats: rawptr[list[rawptr[ast.AST]]] = mo.patterns
|
||||
pats: list[ast.AST*]* = mo.patterns
|
||||
if pats is not None and len(pats) > 0:
|
||||
first_pat: rawptr[ast.AST] = pats.get(0)
|
||||
if first_pat is not None \
|
||||
@@ -474,7 +474,7 @@ class MatchGenMixin:
|
||||
bb = default_bb
|
||||
|
||||
# 检测 NoBreak
|
||||
body_list: rawptr[list[rawptr[ast.AST]]] = mc.children
|
||||
body_list: list[ast.AST*]* = mc.children
|
||||
nb: int = self._has_no_break(body_list)
|
||||
|
||||
# 存入数组
|
||||
@@ -576,7 +576,7 @@ class MatchGenMixin:
|
||||
subject_ptr, trans, pool, builder)
|
||||
|
||||
# 翻译 case body
|
||||
body_list: rawptr[list[rawptr[ast.AST]]] = mc.children
|
||||
body_list: list[ast.AST*]* = mc.children
|
||||
if body_list is not None:
|
||||
bc: sizet = len(body_list)
|
||||
bi: int = 0
|
||||
@@ -614,7 +614,7 @@ class MatchGenMixin:
|
||||
rm_merge_reach = 1
|
||||
else:
|
||||
# 有显式 default:翻译 default case body(找到 is_def==1 的 case)
|
||||
dbody: rawptr[list[rawptr[ast.AST]]] = None
|
||||
dbody: list[ast.AST*]* = None
|
||||
di: int = 0
|
||||
while di < collected:
|
||||
if def_arr[di] == 1:
|
||||
@@ -627,7 +627,7 @@ class MatchGenMixin:
|
||||
# (i32→inttoptr 截断指针 → translate_stmt 读垃圾节点崩溃,
|
||||
# gen1 IR 证据)。用 dbody2 内联声明接收者遍历(对齐
|
||||
# Converter arg_defaults 内联声明规避模式)。
|
||||
dbody2: rawptr[list[rawptr[ast.AST]]] = dmc.children
|
||||
dbody2: list[ast.AST*]* = dmc.children
|
||||
dbody = dbody2
|
||||
if dbody2 is not None:
|
||||
dn: sizet = len(dbody2)
|
||||
@@ -670,7 +670,7 @@ class MatchGenMixin:
|
||||
if pat is None or renum_entry is None or renum_ty is None:
|
||||
return
|
||||
mc: rawptr[ast.MatchClass] = rawptr[ast.MatchClass](pat)
|
||||
pats: rawptr[list[rawptr[ast.AST]]] = mc.patterns
|
||||
pats: list[ast.AST*]* = mc.patterns
|
||||
if pats is None:
|
||||
return
|
||||
# bitcast subject_ptr 到 renum_ptr_ty(确保 GEP 类型匹配)
|
||||
@@ -821,7 +821,7 @@ class MatchGenMixin:
|
||||
sq_merge_reach: int = 0
|
||||
|
||||
# 1. 求值 subject 各元素
|
||||
elts: rawptr[list[rawptr[ast.AST]]] = None
|
||||
elts: list[ast.AST*]* = None
|
||||
if subject_node.kind() == ast.ASTKind.Tuple:
|
||||
st: rawptr[ast.Tuple] = rawptr[ast.Tuple](subject_node)
|
||||
if st is not None:
|
||||
@@ -841,7 +841,7 @@ class MatchGenMixin:
|
||||
for ei in range(ecount):
|
||||
# elts 预声明+重赋值会把 .get 误分派成 list[int].get(i32 截断);
|
||||
# 用内联别名接收者规避(对齐 Converter arg_defaults 内联模式)
|
||||
elts_inl: rawptr[list[rawptr[ast.AST]]] = elts
|
||||
elts_inl: list[ast.AST*]* = elts
|
||||
elt: rawptr[ast.AST] = elts_inl.get(ei)
|
||||
sv: rawptr[llvmlite.Value] = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, trans.Module, elt,
|
||||
@@ -865,7 +865,7 @@ class MatchGenMixin:
|
||||
pool, func, name_buf)
|
||||
|
||||
# 3. 第一遍:收集 case 信息(check/body BB、default 标记、nobreak、guard)
|
||||
cases_list: rawptr[list[rawptr[ast.AST]]] = node.cases
|
||||
cases_list: list[ast.AST*]* = node.cases
|
||||
if cases_list is None:
|
||||
return 0
|
||||
case_count: sizet = len(cases_list)
|
||||
@@ -927,7 +927,7 @@ class MatchGenMixin:
|
||||
body_arr[collected] = sizet(bbb)
|
||||
if first_check < 0:
|
||||
first_check = collected
|
||||
body_list: rawptr[list[rawptr[ast.AST]]] = mc.children
|
||||
body_list: list[ast.AST*]* = mc.children
|
||||
nb: int = self._has_no_break(body_list)
|
||||
def_arr[collected] = is_def
|
||||
nb_arr[collected] = nb
|
||||
@@ -950,8 +950,8 @@ class MatchGenMixin:
|
||||
if def_arr[ci] == 1:
|
||||
ci = ci + 1
|
||||
continue
|
||||
cbb2: rawptr[llvmlite.BasicBlock] = rawptr[llvmlite.BasicBlock](check_arr[ci], t.CPtr)
|
||||
bbb2: rawptr[llvmlite.BasicBlock] = rawptr[llvmlite.BasicBlock](body_arr[ci], t.CPtr)
|
||||
cbb2: rawptr[llvmlite.BasicBlock] = rawptr[llvmlite.BasicBlock](check_arr[ci])
|
||||
bbb2: rawptr[llvmlite.BasicBlock] = rawptr[llvmlite.BasicBlock](body_arr[ci])
|
||||
llvmlite.position_at_end(builder, cbb2)
|
||||
|
||||
# 计算匹配条件(元素比较 && guard)
|
||||
@@ -960,7 +960,7 @@ class MatchGenMixin:
|
||||
mc2: rawptr[ast.MatchCase] = rawptr[ast.MatchCase](cnode)
|
||||
ms: rawptr[ast.MatchSequence] = (
|
||||
rawptr[ast.MatchSequence])(mc2.pattern)
|
||||
pats: rawptr[list[rawptr[ast.AST]]] = None
|
||||
pats: list[ast.AST*]* = None
|
||||
if ms is not None:
|
||||
pats = ms.patterns
|
||||
pcount: sizet = 0
|
||||
@@ -973,7 +973,7 @@ class MatchGenMixin:
|
||||
for pi in range(ecount):
|
||||
# pats 预声明+重赋值会把 .get 误分派成 list[int].get(i32 截断);
|
||||
# 用内联别名接收者规避(对齐 Converter arg_defaults 内联模式)
|
||||
pats_inl: rawptr[list[rawptr[ast.AST]]] = pats
|
||||
pats_inl: list[ast.AST*]* = pats
|
||||
pat1: rawptr[ast.AST] = pats_inl.get(pi)
|
||||
if pat1 is None:
|
||||
continue
|
||||
@@ -987,7 +987,7 @@ class MatchGenMixin:
|
||||
if pv is None:
|
||||
self.Gen.TypeGenErr.fatal_error(
|
||||
pat1, f"序列模式元素 {pi} 翻译失败", "TypeError")
|
||||
sv1: rawptr[llvmlite.Value] = rawptr[llvmlite.Value](subj_vals[pi], t.CPtr)
|
||||
sv1: rawptr[llvmlite.Value] = rawptr[llvmlite.Value](subj_vals[pi])
|
||||
c1: rawptr[llvmlite.Value] = self._seq_cmp_eq(trans, builder, sv1, pv)
|
||||
if c1 is None:
|
||||
self.Gen.TypeGenErr.fatal_error(pat1, "序列模式元素比较失败", "TypeError")
|
||||
@@ -1059,7 +1059,7 @@ class MatchGenMixin:
|
||||
mc3: rawptr[ast.MatchCase] = (
|
||||
rawptr[ast.MatchCase])(cnode2)
|
||||
self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH)
|
||||
body_list2: rawptr[list[rawptr[ast.AST]]] = mc3.children
|
||||
body_list2: list[ast.AST*]* = mc3.children
|
||||
if body_list2 is not None:
|
||||
bc: sizet = len(body_list2)
|
||||
bi: int = 0
|
||||
@@ -1092,7 +1092,7 @@ class MatchGenMixin:
|
||||
|
||||
# 7. default 块
|
||||
llvmlite.position_at_end(builder, default_bb)
|
||||
dbody: rawptr[list[rawptr[ast.AST]]] = None
|
||||
dbody: list[ast.AST*]* = None
|
||||
if has_default == 1:
|
||||
di: int = 0
|
||||
while di < collected:
|
||||
@@ -1106,7 +1106,7 @@ class MatchGenMixin:
|
||||
# (i32→inttoptr 截断指针 → translate_stmt 读垃圾节点崩溃,
|
||||
# gen1 IR 证据)。用 dbody2 内联声明接收者遍历(对齐
|
||||
# Converter arg_defaults 内联声明规避模式)。
|
||||
dbody2: rawptr[list[rawptr[ast.AST]]] = dmc.children
|
||||
dbody2: list[ast.AST*]* = dmc.children
|
||||
dbody = dbody2
|
||||
if dbody2 is not None:
|
||||
dn: sizet = len(dbody2)
|
||||
@@ -1178,7 +1178,7 @@ class MatchGenMixin:
|
||||
pool, func, name_buf)
|
||||
|
||||
# 3. 收集 case 信息
|
||||
cases_list: rawptr[list[rawptr[ast.AST]]] = node.cases
|
||||
cases_list: list[ast.AST*]* = node.cases
|
||||
if cases_list is None:
|
||||
# fail-fast: match cases 缺失
|
||||
self.Gen.TypeGenErr.fatal_error(node, "match cases 缺失", "TypeError")
|
||||
@@ -1233,7 +1233,7 @@ class MatchGenMixin:
|
||||
has_default = 1
|
||||
elif pk == ast.ASTKind.MatchOr:
|
||||
mo: rawptr[ast.MatchOr] = rawptr[ast.MatchOr](pat)
|
||||
pats: rawptr[list[rawptr[ast.AST]]] = mo.patterns
|
||||
pats: list[ast.AST*]* = mo.patterns
|
||||
if pats is not None and len(pats) > 0:
|
||||
first_pat: rawptr[ast.AST] = pats.get(0)
|
||||
if first_pat is not None \
|
||||
@@ -1266,7 +1266,7 @@ class MatchGenMixin:
|
||||
else:
|
||||
bb = default_bb
|
||||
|
||||
body_list: rawptr[list[rawptr[ast.AST]]] = mc.children
|
||||
body_list: list[ast.AST*]* = mc.children
|
||||
nb: int = self._has_no_break(body_list)
|
||||
|
||||
if collected < MAX_MATCH_CASES:
|
||||
@@ -1316,7 +1316,7 @@ class MatchGenMixin:
|
||||
|
||||
self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH)
|
||||
|
||||
body_list: rawptr[list[rawptr[ast.AST]]] = mc.children
|
||||
body_list: list[ast.AST*]* = mc.children
|
||||
if body_list is not None:
|
||||
bc: sizet = len(body_list)
|
||||
bi: int = 0
|
||||
@@ -1346,7 +1346,7 @@ class MatchGenMixin:
|
||||
trans._ctrl_merge_reachable = 1
|
||||
sm_merge_reach = 1
|
||||
else:
|
||||
dbody: rawptr[list[rawptr[ast.AST]]] = None
|
||||
dbody: list[ast.AST*]* = None
|
||||
di: int = 0
|
||||
while di < collected:
|
||||
if def_arr[di] == 1:
|
||||
@@ -1359,7 +1359,7 @@ class MatchGenMixin:
|
||||
# (i32→inttoptr 截断指针 → translate_stmt 读垃圾节点崩溃,
|
||||
# gen1 IR 证据)。用 dbody2 内联声明接收者遍历(对齐
|
||||
# Converter arg_defaults 内联声明规避模式)。
|
||||
dbody2: rawptr[list[rawptr[ast.AST]]] = dmc.children
|
||||
dbody2: list[ast.AST*]* = dmc.children
|
||||
dbody = dbody2
|
||||
if dbody2 is not None:
|
||||
dn: sizet = len(dbody2)
|
||||
|
||||
@@ -238,7 +238,7 @@ class StmtGenCifMixin:
|
||||
return 0
|
||||
if k == ast.ASTKind.BoolOp:
|
||||
bo: rawptr[ast.BoolOp] = rawptr[ast.BoolOp](node)
|
||||
vals: rawptr[list[rawptr[ast.AST]]] = bo.values
|
||||
vals: list[ast.AST*]* = bo.values
|
||||
if vals is None:
|
||||
self.CifEvalOk = 0
|
||||
return 0
|
||||
@@ -267,7 +267,7 @@ class StmtGenCifMixin:
|
||||
if self.CifEvalOk == 0:
|
||||
return 0
|
||||
ops_list: list[int] | t.CPtr = (list[int] | t.CPtr)(cmp.ops)
|
||||
comps: rawptr[list[rawptr[ast.AST]]] = cmp.comparators
|
||||
comps: list[ast.AST*]* = cmp.comparators
|
||||
if ops_list is None or comps is None:
|
||||
self.CifEvalOk = 0
|
||||
return 0
|
||||
@@ -373,7 +373,7 @@ class StmtGenCifMixin:
|
||||
return 0
|
||||
if string.strcmp(vn.id, "ctraits") != 0 or string.strcmp(at.attr, "isptr") != 0:
|
||||
return 0
|
||||
cargs: rawptr[list[rawptr[ast.AST]]] = cl.args
|
||||
cargs: list[ast.AST*]* = cl.args
|
||||
if cargs is None or len(cargs) < 1:
|
||||
self.CifEvalOk = 0
|
||||
return 0
|
||||
@@ -414,7 +414,7 @@ class StmtGenCifMixin:
|
||||
kind = nm.id
|
||||
if kind is None:
|
||||
return 0
|
||||
cargs: rawptr[list[rawptr[ast.AST]]] = cl.args
|
||||
cargs: list[ast.AST*]* = cl.args
|
||||
if cargs is None or len(cargs) < 1:
|
||||
return 0
|
||||
arg0: rawptr[ast.AST] = cargs.get(0)
|
||||
@@ -473,7 +473,7 @@ class StmtGenCifMixin:
|
||||
# return a, b → 打包匿名 struct 值(多返回值,函数返回类型 tuple[T1,T2])
|
||||
if rt.value.kind() == ast.ASTKind.Tuple:
|
||||
rtp: rawptr[ast.Tuple] = rawptr[ast.Tuple](rt.value)
|
||||
rtp_elts: rawptr[list[rawptr[ast.AST]]] = rtp.elts
|
||||
rtp_elts: list[ast.AST*]* = rtp.elts
|
||||
rt_n: sizet = 0
|
||||
if rtp_elts is not None:
|
||||
rt_n = len(rtp_elts)
|
||||
@@ -714,7 +714,7 @@ class StmtGenCifMixin:
|
||||
cif_val: int = self._evaluate_cif_test(pool, trans, if_node.test)
|
||||
if self.CifEvalOk != 0:
|
||||
if cif_val != 0:
|
||||
body_cif: rawptr[list[rawptr[ast.AST]]] = if_node.children
|
||||
body_cif: list[ast.AST*]* = if_node.children
|
||||
if body_cif is not None:
|
||||
bc_cif: sizet = len(body_cif)
|
||||
bi_cif: sizet
|
||||
@@ -723,7 +723,7 @@ class StmtGenCifMixin:
|
||||
if stmt_cif is not None:
|
||||
self.Gen.StmtGen.translate_stmt(trans, stmt_cif)
|
||||
else:
|
||||
orelse_cif: rawptr[list[rawptr[ast.AST]]] = if_node.orelse
|
||||
orelse_cif: list[ast.AST*]* = if_node.orelse
|
||||
if orelse_cif is not None and len(orelse_cif) == 1:
|
||||
sub_cif: rawptr[ast.AST] = orelse_cif.get(0)
|
||||
if sub_cif is not None and sub_cif.kind() == ast.ASTKind.If:
|
||||
@@ -776,7 +776,7 @@ class StmtGenCifMixin:
|
||||
|
||||
# 检查是否有 else 分支
|
||||
has_else: int = 0
|
||||
orelse_list: rawptr[list[rawptr[ast.AST]]] = if_node.orelse
|
||||
orelse_list: list[ast.AST*]* = if_node.orelse
|
||||
if orelse_list is not None:
|
||||
if len(orelse_list) > 0:
|
||||
has_else = 1
|
||||
@@ -798,7 +798,7 @@ class StmtGenCifMixin:
|
||||
# 末句 If 全 return 被 fail-fast 误判"流程掉出末尾"的根因链一环)
|
||||
trans._ctrl_merge_reachable = 1
|
||||
llvmlite.position_at_end(builder, then_bb)
|
||||
body: rawptr[list[rawptr[ast.AST]]] = if_node.children
|
||||
body: list[ast.AST*]* = if_node.children
|
||||
if body is not None:
|
||||
body_count: sizet = len(body)
|
||||
for bi in range(body_count):
|
||||
@@ -929,7 +929,7 @@ class StmtGenCifMixin:
|
||||
trans._break_bb = end_bb
|
||||
trans._continue_bb = cond_bb
|
||||
|
||||
body: rawptr[list[rawptr[ast.AST]]] = while_node.children
|
||||
body: list[ast.AST*]* = while_node.children
|
||||
if body is not None:
|
||||
body_count: sizet = len(body)
|
||||
for bi in range(body_count):
|
||||
@@ -980,7 +980,7 @@ class StmtGenCifMixin:
|
||||
"""递归扫描节点子树(跳过嵌套 While/For 子树),含 Break 返回 1"""
|
||||
if node is None:
|
||||
return 0
|
||||
ch: rawptr[list[rawptr[ast.AST]]] = node.children
|
||||
ch: list[ast.AST*]* = node.children
|
||||
if ch is not None:
|
||||
n: sizet = len(ch)
|
||||
for bi in range(n):
|
||||
@@ -996,7 +996,7 @@ class StmtGenCifMixin:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def _StmtHasBreak(self, body: rawptr[list[rawptr[ast.AST]]]) -> int:
|
||||
def _StmtHasBreak(self, body: list[ast.AST*]*) -> int:
|
||||
"""语句列表是否含本层 break(嵌套循环的 break 归内层)"""
|
||||
if body is None:
|
||||
return 0
|
||||
@@ -1194,7 +1194,7 @@ class StmtGenCifMixin:
|
||||
call: rawptr[ast.Call] = rawptr[ast.Call](iter_node)
|
||||
|
||||
# 3. 解析 range 参数: range(stop) / range(start, stop) / range(start, stop, step)
|
||||
args: rawptr[list[rawptr[ast.AST]]] = call.args
|
||||
args: list[ast.AST*]* = call.args
|
||||
if args is None:
|
||||
return 0
|
||||
arg_count: sizet = len(args)
|
||||
@@ -1429,7 +1429,7 @@ class StmtGenCifMixin:
|
||||
trans._break_bb = end_bb
|
||||
trans._continue_bb = incr_bb
|
||||
|
||||
body: rawptr[list[rawptr[ast.AST]]] = for_node.children
|
||||
body: list[ast.AST*]* = for_node.children
|
||||
if body is not None:
|
||||
body_count: sizet = len(body)
|
||||
for bi in range(body_count):
|
||||
@@ -1479,7 +1479,7 @@ class StmtGenCifMixin:
|
||||
"""从 Tuple target 提取前两个 Name 变量名,写入 out1/out2,成功返回 1"""
|
||||
if tup is None or tup.elts is None or out1 is None or out2 is None:
|
||||
return 0
|
||||
elts: rawptr[list[rawptr[ast.AST]]] = tup.elts
|
||||
elts: list[ast.AST*]* = tup.elts
|
||||
n: sizet = len(elts)
|
||||
if n < 2:
|
||||
return 0
|
||||
@@ -1566,7 +1566,7 @@ class StmtGenCifMixin:
|
||||
r1_stop = llvmlite.const_int64(pool, 0)
|
||||
# 先赋中间变量再取 args(cast 链式属性访问会推断错字段偏移)
|
||||
call_src1: rawptr[ast.Call] = rawptr[ast.Call](src1)
|
||||
cargs1: rawptr[list[rawptr[ast.AST]]] = call_src1.args
|
||||
cargs1: list[ast.AST*]* = call_src1.args
|
||||
if cargs1 is not None:
|
||||
n1: sizet = len(cargs1)
|
||||
if n1 >= 1:
|
||||
@@ -1636,7 +1636,7 @@ class StmtGenCifMixin:
|
||||
r2_stop = llvmlite.const_int64(pool, 0)
|
||||
# 先赋中间变量再取 args(cast 链式属性访问会推断错字段偏移)
|
||||
call_src2: rawptr[ast.Call] = rawptr[ast.Call](src2)
|
||||
cargs2: rawptr[list[rawptr[ast.AST]]] = call_src2.args
|
||||
cargs2: list[ast.AST*]* = call_src2.args
|
||||
if cargs2 is not None:
|
||||
n2: sizet = len(cargs2)
|
||||
if n2 >= 1:
|
||||
@@ -1808,7 +1808,7 @@ class StmtGenCifMixin:
|
||||
trans._break_bb = end_bb
|
||||
trans._continue_bb = incr_bb
|
||||
|
||||
body: rawptr[list[rawptr[ast.AST]]] = for_node.children
|
||||
body: list[ast.AST*]* = for_node.children
|
||||
if body is not None:
|
||||
body_count: sizet = len(body)
|
||||
for bi in range(body_count):
|
||||
@@ -1969,7 +1969,7 @@ class StmtGenCifMixin:
|
||||
trans._break_bb = end_bb
|
||||
trans._continue_bb = incr_bb
|
||||
|
||||
body: rawptr[list[rawptr[ast.AST]]] = for_node.children
|
||||
body: list[ast.AST*]* = for_node.children
|
||||
if body is not None:
|
||||
body_count: sizet = len(body)
|
||||
for bi in range(body_count):
|
||||
@@ -2136,7 +2136,7 @@ class StmtGenCifMixin:
|
||||
trans._break_bb = end_bb
|
||||
trans._continue_bb = incr_bb
|
||||
|
||||
body: rawptr[list[rawptr[ast.AST]]] = for_node.children
|
||||
body: list[ast.AST*]* = for_node.children
|
||||
if body is not None:
|
||||
body_count: sizet = len(body)
|
||||
for bi in range(body_count):
|
||||
@@ -2180,7 +2180,7 @@ class StmtGenCifMixin:
|
||||
lst: rawptr[ast.List] = rawptr[ast.List](list_node)
|
||||
if lst is None or lst.elts is None:
|
||||
self.Gen.TypeGenErr.fatal_error(for_node, "列表字面量迭代: 空列表")
|
||||
elts: rawptr[list[rawptr[ast.AST]]] = lst.elts
|
||||
elts: list[ast.AST*]* = lst.elts
|
||||
elts_count: sizet = len(elts)
|
||||
if elts_count <= 0:
|
||||
self.Gen.TypeGenErr.fatal_error(for_node, "列表字面量迭代: 空列表")
|
||||
@@ -2334,7 +2334,7 @@ class StmtGenCifMixin:
|
||||
trans._break_bb = end_bb
|
||||
trans._continue_bb = incr_bb
|
||||
|
||||
body: rawptr[list[rawptr[ast.AST]]] = for_node.children
|
||||
body: list[ast.AST*]* = for_node.children
|
||||
if body is not None:
|
||||
body_count: sizet = len(body)
|
||||
for bi in range(body_count):
|
||||
@@ -2445,7 +2445,7 @@ class StmtGenCifMixin:
|
||||
trans._break_bb = end_bb
|
||||
trans._continue_bb = incr_bb
|
||||
|
||||
body: rawptr[list[rawptr[ast.AST]]] = for_node.children
|
||||
body: list[ast.AST*]* = for_node.children
|
||||
if body is not None:
|
||||
body_count: sizet = len(body)
|
||||
for bi in range(body_count):
|
||||
@@ -2637,7 +2637,7 @@ class StmtGenCifMixin:
|
||||
old_continue: rawptr[llvmlite.BasicBlock] = trans._continue_bb
|
||||
trans._break_bb = end_bb
|
||||
trans._continue_bb = step_bb
|
||||
body: rawptr[list[rawptr[ast.AST]]] = for_node.children
|
||||
body: list[ast.AST*]* = for_node.children
|
||||
if body is not None:
|
||||
body_count: sizet = len(body)
|
||||
for bi in range(body_count):
|
||||
@@ -2664,7 +2664,7 @@ class StmtGenCifMixin:
|
||||
"""enumerate 迭代: for i, v in enumerate(x)"""
|
||||
if call is None or call.args is None:
|
||||
return 0
|
||||
cargs: rawptr[list[rawptr[ast.AST]]] = call.args
|
||||
cargs: list[ast.AST*]* = call.args
|
||||
if len(cargs) < 1:
|
||||
self.Gen.TypeGenErr.fatal_error(for_node, "enumerate 需要至少一个参数")
|
||||
return self._build_seq_loop(trans, for_node, t1, t2, cargs.get(0), None, 1)
|
||||
@@ -2677,7 +2677,7 @@ class StmtGenCifMixin:
|
||||
if call is None or call.args is None:
|
||||
# fail-fast: zip 参数缺失
|
||||
self.Gen.TypeGenErr.fatal_error(call, "zip 参数缺失", "SyntaxError")
|
||||
cargs: rawptr[list[rawptr[ast.AST]]] = call.args
|
||||
cargs: list[ast.AST*]* = call.args
|
||||
if len(cargs) < 2:
|
||||
self.Gen.TypeGenErr.fatal_error(for_node, "zip 需要至少两个参数")
|
||||
return self._build_seq_loop(trans, for_node, t1, t2, cargs.get(0), cargs.get(1), 2)
|
||||
|
||||
@@ -46,7 +46,7 @@ class StmtGenDeclMixin(StmtGenCifMixin.StmtGenCifMixin):
|
||||
gn: rawptr[ast.Global] = rawptr[ast.Global](node)
|
||||
if gn is None:
|
||||
return 0
|
||||
names: rawptr[list[rawptr[ast.AST]]] = gn.names
|
||||
names: list[ast.AST*]* = gn.names
|
||||
if names is None:
|
||||
return 0
|
||||
n: sizet = len(names)
|
||||
@@ -67,7 +67,7 @@ class StmtGenDeclMixin(StmtGenCifMixin.StmtGenCifMixin):
|
||||
nl: rawptr[ast.Nonlocal] = rawptr[ast.Nonlocal](node)
|
||||
if nl is None:
|
||||
return 0
|
||||
names: rawptr[list[rawptr[ast.AST]]] = nl.names
|
||||
names: list[ast.AST*]* = nl.names
|
||||
if names is None:
|
||||
return 0
|
||||
n: sizet = len(names)
|
||||
@@ -105,6 +105,14 @@ class StmtGenDeclMixin(StmtGenCifMixin.StmtGenCifMixin):
|
||||
return 0
|
||||
ck: int = call_node.kind()
|
||||
if ck != ast.ASTKind.Call:
|
||||
# REPL 模式(M2):片段函数本体内的裸表达式语句(如 1+2 / x / x + 1)
|
||||
# 求值后写入 ctx 结果区,由宿主回显。调用表达式仍走下方原路径
|
||||
# (执行 + 丢弃返回值,同 print/printf 语义)。
|
||||
# 守卫 trans.ReplCtx:非 REPL 恒 None ⇒ "表达式语句除调用外一律忽略"
|
||||
# 的原行为逐字不变。
|
||||
if trans is not None and trans.ReplCtx is not None \
|
||||
and self.Gen.VarGen.repl_in_frag_scope(trans.SymTab) != 0:
|
||||
self.Gen.VarGen.repl_expr_result(trans, call_node)
|
||||
return 0
|
||||
|
||||
cl: rawptr[ast.Call] = rawptr[ast.Call](call_node)
|
||||
@@ -126,6 +134,30 @@ class StmtGenDeclMixin(StmtGenCifMixin.StmtGenCifMixin):
|
||||
trans.Pool, trans._cur_builder, trans.Module, cl, trans)
|
||||
else:
|
||||
# 通用函数调用(返回值丢弃)
|
||||
# M3:裸名调用**会话函数**(跨片段)时额外把返回值写进 ctx 结果区回显
|
||||
# (M2 的限制条目"调用表达式的结果不回显"对会话函数放开——用户在
|
||||
# `>>> f(41)` 后期望看到 `=> 42`)。结果区的类型分类直接用会话函数表里
|
||||
# 记录的返回类型 token(宿主从定义片段 IR 解析而来,是定义端 ABI 真相),
|
||||
# 不用影子条目推断 ⇒ 与调用点签名同源。
|
||||
# 守卫 trans.ReplCtx:非 REPL 恒 None ⇒ 原"执行 + 丢弃返回值"逐字不变;
|
||||
# 仅裸名(Name)且表中登记的会话函数走本分支(printf/print 等在上方已分流)。
|
||||
if trans is not None and trans.ReplCtx is not None \
|
||||
and func_node.kind() == ast.ASTKind.Name \
|
||||
and self.Gen.VarGen.repl_in_frag_scope(trans.SymTab) != 0:
|
||||
sfn_ent: rawptr[GenTypes.ReplFuncEntry] = \
|
||||
self.Gen.VarGen.repl_find_func_entry(trans.ReplCtx, func_name)
|
||||
if sfn_ent is not None and sfn_ent.RetTag != GenTypes.REPL_TY_VOID:
|
||||
sfn_v: rawptr[llvmlite.Value] = self.Gen.CallGen.translate_call(
|
||||
trans.Pool, trans._cur_builder, trans.Module, call_node,
|
||||
trans._funcs, trans._func_count, trans)
|
||||
if sfn_v is not None:
|
||||
ctx_v: rawptr[llvmlite.Value] = self.Gen.VarGen.repl_ctx_ptr(
|
||||
trans, trans.ReplCtx, call_node)
|
||||
if ctx_v is not None:
|
||||
self.Gen.VarGen.repl_emit_result(
|
||||
trans, ctx_v, sfn_v, sfn_ent.RetTag, sfn_ent.RetBits,
|
||||
call_node)
|
||||
return 0
|
||||
self.Gen.CallGen.translate_call(
|
||||
trans.Pool, trans._cur_builder, trans.Module, call_node,
|
||||
trans._funcs, trans._func_count, trans)
|
||||
|
||||
@@ -597,7 +597,7 @@ class StmtGenMixin(StmtGenDeclMixin.StmtGenDeclMixin):
|
||||
mod: rawptr[llvmlite.LLVMModule] = trans.Module
|
||||
if pool is None or builder is None or mod is None:
|
||||
return 0
|
||||
items: rawptr[list[rawptr[ast.AST]]] = wt.items
|
||||
items: list[ast.AST*]* = wt.items
|
||||
if items is None:
|
||||
return 0
|
||||
n: sizet = len(items)
|
||||
@@ -695,7 +695,7 @@ class StmtGenMixin(StmtGenDeclMixin.StmtGenDeclMixin):
|
||||
trans, pool, builder, mod, fd_cls_bare, ctx_val)
|
||||
|
||||
# 2. 翻译 body
|
||||
body: rawptr[list[rawptr[ast.AST]]] = wt.children
|
||||
body: list[ast.AST*]* = wt.children
|
||||
if body is not None:
|
||||
bn: sizet = len(body)
|
||||
for bi in range(bn):
|
||||
|
||||
@@ -684,10 +684,10 @@ class StructGenMixin:
|
||||
dst_l.end_col_offset = src_l.end_col_offset
|
||||
dst_l.ctx = src_l.ctx
|
||||
# 深拷贝 elts:stdlib 手动构造 list[AST | t.CPtr] 容器
|
||||
src_elts_l: rawptr[list[rawptr[ast.AST]]] = src_l.elts
|
||||
src_elts_l: list[ast.AST*]* = src_l.elts
|
||||
if src_elts_l is not None:
|
||||
cnt_l: sizet = len(src_elts_l)
|
||||
lst_copy_l: rawptr[list[rawptr[ast.AST]]] = rawptr[list[rawptr[ast.AST]]](
|
||||
lst_copy_l: list[ast.AST*]* = (list[ast.AST*] | t.CPtr)(
|
||||
pool.alloc(list[rawptr[ast.AST]].__sizeof__()))
|
||||
if lst_copy_l is not None:
|
||||
string.memset(lst_copy_l, 0, list[rawptr[ast.AST]].__sizeof__())
|
||||
@@ -1906,3 +1906,24 @@ class StructGenMixin:
|
||||
if fe is None:
|
||||
return None
|
||||
return TSpec.SpecSourceName(fe.Spec)
|
||||
|
||||
def field_is_volatile(self, fe: rawptr[GenTypes.FieldEntry]) -> int:
|
||||
"""字段是否 volatile(FieldEntry.IsVolatile 承载),1=是 / 0=否
|
||||
|
||||
由 ClassGenDef 收集字段注解时检测 t.CVolatile 写入;消费点(成员读写的
|
||||
load/store)据此加 LLVM volatile 限定符。
|
||||
"""
|
||||
if fe is None:
|
||||
return 0
|
||||
return fe.IsVolatile
|
||||
|
||||
def field_pointee_is_volatile(self, fe: rawptr[GenTypes.FieldEntry]) -> int:
|
||||
"""字段所指物是否 volatile(FieldEntry.PointeeVolatile 承载),1=是 / 0=否
|
||||
|
||||
字段注解为 rawptr[t.CVolatile | T](等价 C 的 volatile T*)时由 ClassGenDef
|
||||
写入;消费点(经该字段解引用 self.ptr[i] / self.ptr.field 的 load/store)
|
||||
据此加 LLVM volatile 限定符。
|
||||
"""
|
||||
if fe is None:
|
||||
return 0
|
||||
return fe.PointeeVolatile
|
||||
@@ -137,16 +137,13 @@ class Translator:
|
||||
_cur_builder: rawptr[llvmlite.IRBuilder]
|
||||
|
||||
# 当前赋值语句的注解节点(AnnAssign 翻译 rhs 前设置,Assign 翻译前清空)。
|
||||
# 供 c.Deref(i8*) 推断读取宽度:v: int = c.Deref(p) → bitcast i32* load
|
||||
# (对齐 TPC HandlesSpecialCall._infer_deref_target_type;否则固定读 1 字节 + sext 截断)。
|
||||
# 供裸名泛型构造从注解推断类型实参:`s: Stack[int] = Stack()` 用注解里的
|
||||
# int 特化(消费者见 CallGenCtor.vp 的 CurAssignNode/CurAssignAnnot 判定)。
|
||||
CurAssignAnnot: rawptr[ast.AST]
|
||||
|
||||
# 当前赋值语句的 RHS 节点(AnnAssign 翻译 rhs 前设置,rhs 翻译后清除)。
|
||||
# 供 c.Deref 判定"是否为赋值直接 RHS":仅 v: int = c.Deref(p) 时用
|
||||
# CurAssignAnnot 推断读取宽度;嵌套在 while 条件/比较/binop/类型转换
|
||||
# 调用中(如 while c.Deref(p) != 0、total += int(c.Deref(p)))不推断,
|
||||
# 否则 i8* 会被残留 CurAssignAnnot 误判为 i32* 读 4 字节(对齐 TPC
|
||||
# _infer_deref_target_type 的直接 RHS 检查)。
|
||||
# 供裸名泛型构造判定"构造调用是否为赋值直接 RHS":仅该 identity 命中时才用
|
||||
# CurAssignAnnot 推断类型实参(对齐 TPC 的直接 RHS 检查)。
|
||||
CurAssignNode: rawptr[ast.AST]
|
||||
|
||||
# 当前函数的返回注解节点(translate_function_def 进入函数体前设置,退出时
|
||||
@@ -254,6 +251,11 @@ class Translator:
|
||||
# 嵌套作用域符号表
|
||||
SymTab: rawptr[GenTypes.SymbolTable]
|
||||
|
||||
# REPL 模式上下文(M2 会话变量):None ⇒ 非 REPL(普通编译路径逐字不变)。
|
||||
# 仅 Repl.vp 在翻译片段前置位、翻译后清空;Gen 侧全部会话槽拦截点以
|
||||
# `trans.ReplCtx is not None` 为唯一守卫。
|
||||
ReplCtx: rawptr[GenTypes.ReplCtx]
|
||||
|
||||
def __init__(self):
|
||||
self.Module = None
|
||||
self.Pool = None
|
||||
@@ -293,6 +295,8 @@ class Translator:
|
||||
self.GenericTypeArgs = None
|
||||
self._declare_only = 0
|
||||
self.SymTab = None
|
||||
# REPL 模式上下文:默认未设置(= 非 REPL,Gen 侧拦截全部旁路)
|
||||
self.ReplCtx = None
|
||||
self._async_funcs = None
|
||||
self._async_func_count = 0
|
||||
self._coro_var_async = None
|
||||
@@ -475,7 +479,7 @@ class Translator:
|
||||
|
||||
# 检查用户是否定义了 main 函数
|
||||
has_user_main: int = 0
|
||||
ch: rawptr[list[rawptr[ast.AST]]] = tree.children
|
||||
ch: list[ast.AST*]* = tree.children
|
||||
if ch is not None:
|
||||
cn_count: sizet = len(ch)
|
||||
for ci in range(cn_count):
|
||||
@@ -523,7 +527,7 @@ class Translator:
|
||||
# (前向声明需要解析类型注解,如 t.CArray[str] 依赖 t 模块已导入)
|
||||
# 记录最后处理的 import 行号,供 vpi 注入错误上下文帧定位
|
||||
cur_imp_lineno: int = 0
|
||||
ch: rawptr[list[rawptr[ast.AST]]] = tree.children
|
||||
ch: list[ast.AST*]* = tree.children
|
||||
if ch is not None:
|
||||
cn_count: sizet = len(ch)
|
||||
for ci in range(cn_count):
|
||||
@@ -711,7 +715,7 @@ class Translator:
|
||||
if fd_s.args is not None:
|
||||
args_s: rawptr[ast.Arguments] = rawptr[ast.Arguments](fd_s.args)
|
||||
if args_s.args is not None:
|
||||
args_list_s: rawptr[list[rawptr[ast.AST]]] = args_s.args
|
||||
args_list_s: list[ast.AST*]* = args_s.args
|
||||
an_s: sizet = len(args_list_s)
|
||||
ai_s: sizet
|
||||
for ai_s in range(an_s):
|
||||
@@ -729,7 +733,7 @@ class Translator:
|
||||
# translate_list_literal 阶段 fail-fast 提示 _list 未注册(需显式注解)。
|
||||
# 递归语句块子节点
|
||||
if node.children is not None:
|
||||
ch_s: rawptr[list[rawptr[ast.AST]]] = node.children
|
||||
ch_s: list[ast.AST*]* = node.children
|
||||
n_s: sizet = len(ch_s)
|
||||
for ci_s in range(n_s):
|
||||
self._scan_container_usage(ch_s.get(ci_s), need_list_box, need_dict_box)
|
||||
|
||||
@@ -83,7 +83,7 @@ class TranslatorGenMixin:
|
||||
Returns:
|
||||
int: 新增的变量数
|
||||
"""
|
||||
ch: rawptr[list[rawptr[ast.AST]]] = tree.children
|
||||
ch: list[ast.AST*]* = tree.children
|
||||
if ch is None:
|
||||
return 0
|
||||
|
||||
@@ -164,7 +164,7 @@ class TranslatorGenMixin:
|
||||
if fd.args is not None:
|
||||
ags: rawptr[ast.Arguments] = rawptr[ast.Arguments](fd.args)
|
||||
if ags.args is not None:
|
||||
al: rawptr[list[rawptr[ast.AST]]] = ags.args
|
||||
al: list[ast.AST*]* = ags.args
|
||||
an: sizet = len(al)
|
||||
ai: sizet
|
||||
for ai in range(an):
|
||||
@@ -220,7 +220,7 @@ class TranslatorGenMixin:
|
||||
is_int_elem = 0
|
||||
|
||||
# 获取列表元素(通过 ln.elts 而非 list_node.elts,确保类型正确识别)
|
||||
elts: rawptr[list[rawptr[ast.AST]]] = ln.elts
|
||||
elts: list[ast.AST*]* = ln.elts
|
||||
if elts is None:
|
||||
return None
|
||||
elts_count: sizet = len(elts)
|
||||
@@ -575,6 +575,81 @@ class TranslatorGenMixin:
|
||||
viperlib.snprintf(buf, body_len + 8, "{ %s }", body)
|
||||
return buf
|
||||
|
||||
# ============================================================
|
||||
# 模块级全局变量 t.attr.* 属性提取
|
||||
#
|
||||
# 语法:属性写在类型注解的联合里(`T | t.attr.section(".x")`),因为
|
||||
# Assign/AnnAssign 节点没有 decorator_list(解析器对 `@c.Attribute(...)`
|
||||
# 后接赋值会直接报 "decorator must be followed by def/class")。
|
||||
# 与函数侧口径差异:函数属性来自 decorator_list,提取为属性组文本
|
||||
# `"section"="xxx"`(LLVM 字符串属性必须带引号,走 attributes #N);
|
||||
# 全局变量属性没有属性组,直接写入 GlobalVariable.Section/Align/Linkage
|
||||
# 字段,打印时由 includes/llvmlite/__module.vp 的 _print_global 补引号
|
||||
# (`, section "xxx"` / `, align N`),故此处 Section 值不带引号。
|
||||
# ============================================================
|
||||
def _scan_global_tattr(self, node: rawptr[ast.AST],
|
||||
want_name: str) -> rawptr[ast.AST]:
|
||||
"""在全局变量类型注解中查找 t.attr.<want_name> 节点。
|
||||
|
||||
注解形态是 BinOp(BitOr) 左深链(`A | B | C` = BinOp(BinOp(A,B),C)),
|
||||
递归左右子节点。命中返回该 t.attr 节点(Call: t.attr.aligned(16) /
|
||||
Attribute: t.attr.weak),未命中返回 None。属性名识别复用类侧
|
||||
ClassGenBase._tattr_name(Call→func→attr / Attribute→attr)。
|
||||
"""
|
||||
if node is None:
|
||||
return None
|
||||
if node.kind() == ast.ASTKind.BinOp:
|
||||
bop: rawptr[ast.BinOp] = rawptr[ast.BinOp](node)
|
||||
if bop.op == ast.OpKind.BitOr:
|
||||
hit_l: rawptr[ast.AST] = self._scan_global_tattr(bop.left, want_name)
|
||||
if hit_l is not None:
|
||||
return hit_l
|
||||
return self._scan_global_tattr(bop.right, want_name)
|
||||
return None
|
||||
if self.Gen.ClassGenBase._tattr_name(node, want_name) != 0:
|
||||
return node
|
||||
return None
|
||||
def _extract_global_attr_section(self, node: rawptr[ast.AST],
|
||||
var_name: str) -> str:
|
||||
"""取 `T | t.attr.section("xxx")` 的段名(不含引号)。
|
||||
|
||||
缺参/空段名属非法值 → fail-fast(与 handle_module_level_var 既有
|
||||
TypeGenErr.fatal_error 风格一致):空段名会生成 `section ""` 这种
|
||||
无意义/非法的 IR,静默忽略只会掩盖拼写错误。
|
||||
"""
|
||||
hit: rawptr[ast.AST] = self._scan_global_tattr(node, "section")
|
||||
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")
|
||||
return None
|
||||
return sec_val
|
||||
def _extract_global_attr_aligned(self, node: rawptr[ast.AST],
|
||||
var_name: str) -> int:
|
||||
"""取 `T | t.attr.aligned(N)` 的对齐字节数(无该属性返回 0)。
|
||||
|
||||
N 必须是正整数字面量:aligned(0)/aligned(-4)/aligned("x") 均属非法值
|
||||
→ fail-fast(llc 亦拒绝 `align 0`,静默忽略会掩盖参数错误)。
|
||||
"""
|
||||
hit: rawptr[ast.AST] = self._scan_global_tattr(node, "aligned")
|
||||
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")
|
||||
return 0
|
||||
return al_val
|
||||
def _extract_global_attr_weak(self, node: rawptr[ast.AST]) -> int:
|
||||
"""检测 `T | t.attr.weak` / `t.attr.weak()`(1=有,0=无)"""
|
||||
if self._scan_global_tattr(node, "weak") is not None:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
# ============================================================
|
||||
# handle_module_level_var - 模块级变量声明 → 创建 LLVM 全局变量
|
||||
#
|
||||
@@ -643,6 +718,28 @@ class TranslatorGenMixin:
|
||||
nm: rawptr[ast.Name] = rawptr[ast.Name](aa.target)
|
||||
var_name = nm.id
|
||||
annot_node = aa.annotation
|
||||
# t.Callable 模块级函数指针:登记 (变量名 → 返回类型) 签名。此路径原先
|
||||
# 只创建全局变量、不登记签名,模块级 t.Callable 变量被间接调用时在
|
||||
# CallGenLeafKit._translate_func_ptr_call 报"返回类型未注册(t.Callable
|
||||
# 注解缺失)"(CallGenLeafKit.vp:843-850)。与函数内 AnnAssign 同一登记函数
|
||||
# (AssignGenMixin.vp:1465-1474),参数形态照抄该处:
|
||||
# (pool, 注解, trans._imported_modules, trans._from_imports, trans)。
|
||||
# 时机:_translate_module_level 在 translate_children 之前先遍历全部模块级
|
||||
# AnnAssign/Assign(Translator.vp:568-575,其后才是 :578 translate_children),
|
||||
# 故登记早于本文件任何函数体翻译;签名表本体与返回类型深拷贝都在 PermPool
|
||||
# (CallGenLeafKit.vp:698-699、:783-788),跨文件查找可见。
|
||||
# t.CDefine/t.CTypedef 等分支已在 :675-689 提前返回,行为不变。
|
||||
if annot_node is not None:
|
||||
ml_callable_ret: rawptr[llvmlite.LLVMType] = (
|
||||
self.Gen.TypeGenErr.try_extract_callable_ret(
|
||||
pool, annot_node, trans._imported_modules,
|
||||
trans._from_imports, trans))
|
||||
if ml_callable_ret is not None:
|
||||
# 返回值:0=成功/同类型幂等命中;非 0 已在 register_func_ptr_sig
|
||||
# 内部 fatal_error 终止编译,此处分支仅防御(见 AssignGenMixin 同处)。
|
||||
if self.Gen.CallGenLeafKit.register_func_ptr_sig(
|
||||
pool, var_name, ml_callable_ret, aa) != 0:
|
||||
return 0
|
||||
# 解析类型
|
||||
if aa.annotation is not None:
|
||||
resolved: rawptr[llvmlite.LLVMType] = self.Gen.TypeGenResolve.resolve_annotation_type(
|
||||
@@ -711,7 +808,7 @@ class TranslatorGenMixin:
|
||||
asgn: rawptr[ast.Assign] = rawptr[ast.Assign](node)
|
||||
if asgn is None or asgn.targets is None:
|
||||
return 0
|
||||
targets: rawptr[list[rawptr[ast.AST]]] = asgn.targets
|
||||
targets: list[ast.AST*]* = asgn.targets
|
||||
if len(targets) < 1:
|
||||
return 0
|
||||
t0: rawptr[ast.AST] = targets.get(0)
|
||||
@@ -807,6 +904,16 @@ class TranslatorGenMixin:
|
||||
if annot_node is not None:
|
||||
is_global_cexport = self.Gen.TypeGenErr.has_decorator_marker(
|
||||
annot_node, "CExport", 0)
|
||||
# 全局变量侧 t.attr.* 属性(`T | t.attr.xxx` 注解联合形态):
|
||||
# section→gv.Section、aligned→gv.Align、weak→gv.Linkage(见下方应用点)。
|
||||
# 仅在 AnnAssign(annot_node 非 None)时存在,与 t.CExport 同一条路。
|
||||
gv_attr_section: str = None
|
||||
gv_attr_align: int = 0
|
||||
gv_attr_weak: int = 0
|
||||
if annot_node is not None:
|
||||
gv_attr_section = self._extract_global_attr_section(annot_node, var_name)
|
||||
gv_attr_align = self._extract_global_attr_aligned(annot_node, var_name)
|
||||
gv_attr_weak = self._extract_global_attr_weak(annot_node)
|
||||
mangled_name: str = var_name
|
||||
if is_global_cexport == 0:
|
||||
mangled_name = self.Gen.FuncGenBase._mangle_name(trans, var_name)
|
||||
@@ -815,8 +922,14 @@ class TranslatorGenMixin:
|
||||
return 0
|
||||
llvmlite.module_add_global(mod, gv)
|
||||
|
||||
# 段名:直接写字段(_print_global 会补 `, section "xxx"` 的引号)。
|
||||
if gv_attr_section is not None:
|
||||
llvmlite.global_set_section(gv, gv_attr_section)
|
||||
|
||||
# B5:@c.Attribute(t.attr.aligned(N)) 类的全局实例施加对齐(如 fpu_context 16 对齐,
|
||||
# FXSAVE 区域要求 16 字节对齐,否则 fxsave/fxrstor #GP)。
|
||||
# 优先级:变量级显式 `T | t.attr.aligned(N)` 比类级(struct entry Align)更具体,
|
||||
# 显式值胜出;无显式属性时沿用类级对齐(既有行为不变)。
|
||||
al_ty: rawptr[llvmlite.LLVMType] = var_ty
|
||||
match var_ty:
|
||||
case llvmlite.LLVMType.Ptr(pointee_al):
|
||||
@@ -826,11 +939,16 @@ class TranslatorGenMixin:
|
||||
al_entry: rawptr[GenTypes.StructEntry] = None
|
||||
if al_ty is not None and al_ty.kind() == llvmlite.LLVMType.Struct:
|
||||
al_entry = self.Gen.StructGen.find_struct_by_type(al_ty)
|
||||
if al_entry is not None and al_entry.Align > 0:
|
||||
if gv_attr_align > 0:
|
||||
gv.Align = gv_attr_align
|
||||
elif al_entry is not None and al_entry.Align > 0:
|
||||
gv.Align = al_entry.Align
|
||||
|
||||
# 设置初始值(有初始值时清除 external linkage,因为 LLVM 22+ 不允许 external global 带初始值)
|
||||
gv.Linkage = None
|
||||
# t.attr.weak → weak linkage(须在 Linkage 清空之后设置)。
|
||||
if gv_attr_weak != 0:
|
||||
llvmlite.global_set_linkage(gv, "weak")
|
||||
if init_kind == 1:
|
||||
# 整数初始值
|
||||
init_buf: str = pool.alloc(48)
|
||||
@@ -1015,6 +1133,17 @@ class TranslatorGenMixin:
|
||||
|
||||
# 注册到模块作用域
|
||||
if self.Gen.VarGen.define_module_var(trans.SymTab, var_name, gv_ref) == 0:
|
||||
# t.CVolatile 存储类标记(注解联合含 t.CVolatile)→ 标记全局变量
|
||||
# volatile:所有 load/store 带 LLVM volatile,禁止优化器把忙等循环
|
||||
# 的重复 load 提升/消除(如 `locked: t.CVolatile | t.CInt`)。
|
||||
if annot_node is not None:
|
||||
if self.Gen.TypeGenErr.has_decorator_marker(annot_node, "CVolatile", 0) != 0:
|
||||
self.Gen.VarGen.set_var_volatile(trans.SymTab, var_name)
|
||||
# rawptr[t.CVolatile | T](volatile 指针指向物):解引用(p[i]/
|
||||
# p.field/c.Deref(p))的 load/store 带 volatile。与上一分支互斥:
|
||||
# 前者是变量自身限定(BinOp 联合),后者是 rawptr 下标实参标记。
|
||||
if self.Gen.TypeGenErr.has_pointee_volatile_marker(annot_node) != 0:
|
||||
self.Gen.VarGen.set_var_pointee_volatile(trans.SymTab, var_name)
|
||||
# 设置 AnnotClassName(联合类型如 Logger|t.CPtr 简化为 Ptr(i8) 时,
|
||||
# 属性访问需要通过 AnnotClassName 回退到类名查找结构体)
|
||||
if k == ast.ASTKind.AnnAssign:
|
||||
@@ -1089,7 +1218,7 @@ class TranslatorGenMixin:
|
||||
# 预处理模块级变量:为 AnnAssign/Assign 创建 LLVM 全局变量
|
||||
# 必须在 pre_scan_allocas 之前执行,否则 PreScan 会创建局部 alloca,
|
||||
# 导致其他函数通过 SSA 编号引用 wrapper main 的局部变量(无效 IR)
|
||||
ch: rawptr[list[rawptr[ast.AST]]] = tree.children
|
||||
ch: list[ast.AST*]* = tree.children
|
||||
if ch is not None:
|
||||
cn_count: sizet = len(ch)
|
||||
for ci in range(cn_count):
|
||||
|
||||
@@ -120,6 +120,28 @@ class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
else:
|
||||
self.CDefineNameIdxBuilt = -1
|
||||
|
||||
# ============================================================
|
||||
# CDefine 表本体的池归一
|
||||
#
|
||||
# 表指针挂在**进程级单例** _g_gen.TypeGenCDef 上,不在任何 pool 的管辖
|
||||
# 范围内;而调用方传进来的 pool 在翻译期是「每文件 reset_to 回收」的瞬时池
|
||||
# (Phase1 1a/1b、Phase2 PhaseA、StubMerger 扫描、Repl 每片段都按 mark/reset
|
||||
# 轮转)。表本体若落在该池:reset 之后表指针**悬空但非 None** ⇒ `is None`
|
||||
# 守卫失效 ⇒ 下一次 register_cdefine_* 的 append 写进已回收内存(堆损坏;
|
||||
# 检测模式下该区被 free 填成 0xCD ⇒ append 的接收者 = 0xcdcdcdcdcdcdcdcd)。
|
||||
# 故表本体(四个 list + 名索引)一律落 PermPool(进程级永久池,从不 reset),
|
||||
# 与"文件级/片段级 reset"彻底解耦。
|
||||
# PermPool 不可用(无 CompilerFactory.factory 的极简单元程序)时退回入参
|
||||
# pool —— 与既有语义一致,只是不再有"表本体跨 reset 存活"的隐式假设。
|
||||
# ============================================================
|
||||
def _cdefine_table_pool(self,
|
||||
pool: rawptr[memhub.MemBuddy]) -> rawptr[memhub.MemBuddy]:
|
||||
"""CDefine 表本体的池:恒取 PermPool(不可用则退回入参 pool)"""
|
||||
if CompilerFactory.factory is not None \
|
||||
and CompilerFactory.factory.PermPool is not None:
|
||||
return CompilerFactory.factory.PermPool
|
||||
return pool
|
||||
|
||||
def register_cdefine_constant(self, pool: rawptr[memhub.MemBuddy],
|
||||
name: str, value: int64) -> None:
|
||||
"""注册 CDefine 编译期常量到本地表
|
||||
@@ -139,11 +161,29 @@ class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
if name is None:
|
||||
return
|
||||
if self.CDefineNames is None:
|
||||
self.CDefineNames = list[str](pool, 64)
|
||||
self.CDefineValues = list[str](pool, 64)
|
||||
self.CDefineDoubleFlags = list[int](pool, 64)
|
||||
self.CDefineStrFlags = list[int](pool, 64)
|
||||
self._cdef_idx_init(pool)
|
||||
tp: rawptr[memhub.MemBuddy] = self._cdefine_table_pool(pool)
|
||||
tn: list[str] | t.CPtr = list[str](tp, 64)
|
||||
tv: list[str] | t.CPtr = list[str](tp, 64)
|
||||
td: list[int] | t.CPtr = list[int](tp, 64)
|
||||
tsf: list[int] | t.CPtr = list[int](tp, 64)
|
||||
# 建表失败(池不可用/耗尽)⇒ 明确报错并返回,绝不让下面的 append
|
||||
# 落到 None 或未初始化地址(原实现无检查 ⇒ append 写进 NULL/0xCD 区崩)
|
||||
if tn is None or tv is None or td is None or tsf is None:
|
||||
self.Gen.TypeGenErr.fatal_error(
|
||||
None, "CDefine 表分配失败(表本体池不可用或耗尽)", "MemoryError")
|
||||
return
|
||||
self.CDefineNames = tn
|
||||
self.CDefineValues = tv
|
||||
self.CDefineDoubleFlags = td
|
||||
self.CDefineStrFlags = tsf
|
||||
self._cdef_idx_init(tp)
|
||||
# 表就绪守卫:表本体缺失/半初始化(建表失败或外部置空)⇒ fail-fast,
|
||||
# 不写垃圾(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")
|
||||
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")
|
||||
@@ -177,11 +217,26 @@ class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
if name is None:
|
||||
return
|
||||
if self.CDefineNames is None:
|
||||
self.CDefineNames = list[str](pool, 64)
|
||||
self.CDefineValues = list[str](pool, 64)
|
||||
self.CDefineDoubleFlags = list[int](pool, 64)
|
||||
self.CDefineStrFlags = list[int](pool, 64)
|
||||
self._cdef_idx_init(pool)
|
||||
tp: rawptr[memhub.MemBuddy] = self._cdefine_table_pool(pool)
|
||||
tn: list[str] | t.CPtr = list[str](tp, 64)
|
||||
tv: list[str] | t.CPtr = list[str](tp, 64)
|
||||
td: list[int] | t.CPtr = list[int](tp, 64)
|
||||
tsf: list[int] | t.CPtr = list[int](tp, 64)
|
||||
if tn is None or tv is None or td is None or tsf is None:
|
||||
self.Gen.TypeGenErr.fatal_error(
|
||||
None, "CDefine 浮点表分配失败(表本体池不可用或耗尽)", "MemoryError")
|
||||
return
|
||||
self.CDefineNames = tn
|
||||
self.CDefineValues = tv
|
||||
self.CDefineDoubleFlags = td
|
||||
self.CDefineStrFlags = tsf
|
||||
self._cdef_idx_init(tp)
|
||||
# 表就绪守卫(同 register_cdefine_constant):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")
|
||||
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")
|
||||
@@ -220,11 +275,26 @@ class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"CDefine 字符串值缺失: {name}", "InternalCompilerError")
|
||||
return
|
||||
if self.CDefineNames is None:
|
||||
self.CDefineNames = list[str](pool, 64)
|
||||
self.CDefineValues = list[str](pool, 64)
|
||||
self.CDefineDoubleFlags = list[int](pool, 64)
|
||||
self.CDefineStrFlags = list[int](pool, 64)
|
||||
self._cdef_idx_init(pool)
|
||||
tp: rawptr[memhub.MemBuddy] = self._cdefine_table_pool(pool)
|
||||
tn: list[str] | t.CPtr = list[str](tp, 64)
|
||||
tv: list[str] | t.CPtr = list[str](tp, 64)
|
||||
td: list[int] | t.CPtr = list[int](tp, 64)
|
||||
tsf: list[int] | t.CPtr = list[int](tp, 64)
|
||||
if tn is None or tv is None or td is None or tsf is None:
|
||||
self.Gen.TypeGenErr.fatal_error(
|
||||
None, "CDefine 字符串表分配失败(表本体池不可用或耗尽)", "MemoryError")
|
||||
return
|
||||
self.CDefineNames = tn
|
||||
self.CDefineValues = tv
|
||||
self.CDefineDoubleFlags = td
|
||||
self.CDefineStrFlags = tsf
|
||||
self._cdef_idx_init(tp)
|
||||
# 表就绪守卫(同 register_cdefine_constant):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")
|
||||
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")
|
||||
@@ -459,12 +529,32 @@ class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
"""设置 cdefine_found 标志(供跨模块查找函数使用)"""
|
||||
self.CDefineFound = val
|
||||
def clear_cdefine_constants(self) -> None:
|
||||
"""清空 CDefine 常量表(模块切换时调用)"""
|
||||
self.CDefineNames = None
|
||||
self.CDefineValues = None
|
||||
self.CDefineDoubleFlags = None
|
||||
self.CDefineStrFlags = None
|
||||
# 名索引随表复位(下次 register 重建);不同步会使 Built 与空表错配
|
||||
"""清空 CDefine 常量表(模块切换时调用)
|
||||
|
||||
表本体自首次创建起常驻 PermPool(见 _cdefine_table_pool)⇒ 此处只
|
||||
**清空内容**、不丢弃表指针:
|
||||
- 丢指针会退回"下一次 register_cdefine_* 按**调用方 pool** 重建",
|
||||
表本体又落回会被 reset_to 回收的瞬时池(冷 temp 下翻译 includes
|
||||
时才走到注册路径 ⇒ 表本体跨 reset 悬空 ⇒ append 写进已回收/未
|
||||
初始化内存的根因);
|
||||
- 空表与既有语义完全等价:lookup 命中空表即"未命中",
|
||||
register 首次 append 即写回第 0 槽。
|
||||
"""
|
||||
if self.CDefineNames is not None:
|
||||
self.CDefineNames.clear()
|
||||
if self.CDefineValues is not None:
|
||||
self.CDefineValues.clear()
|
||||
if self.CDefineDoubleFlags is not None:
|
||||
self.CDefineDoubleFlags.clear()
|
||||
if self.CDefineStrFlags is not None:
|
||||
self.CDefineStrFlags.clear()
|
||||
# 名索引清槽(槽存 index+1,0=空槽)+ Built 归零(空表与索引同步;
|
||||
# 与"新建表后首次 register"的索引状态逐字一致)
|
||||
if self.CDefineNameIdx is not None and self.CDefineNameIdxCap > 0:
|
||||
string.memset(self.CDefineNameIdx, 0,
|
||||
sizet(self.CDefineNameIdxCap) * 8)
|
||||
self.CDefineNameIdxBuilt = 0
|
||||
else:
|
||||
self.CDefineNameIdx = None
|
||||
self.CDefineNameIdxCap = 0
|
||||
self.CDefineNameIdxBuilt = -1
|
||||
|
||||
@@ -121,6 +121,28 @@ class TypeGenCType(TypeGenBase.TypeGenBase):
|
||||
else:
|
||||
self.CTypedefNameIdxBuilt = -1
|
||||
|
||||
# ============================================================
|
||||
# CTypedef 表本体的池归一
|
||||
#
|
||||
# 表指针挂在**进程级单例** _g_gen.TypeGenCType 上,不在任何 pool 的管辖
|
||||
# 范围内;而调用方传进来的 pool 在翻译期是「每文件 reset_to 回收」的瞬时池
|
||||
# (Phase1 1a/1b、Phase2 PhaseA、Repl 每片段/每模块都按 mark/reset 轮转)。
|
||||
# 表本体若落在该池:reset 之后表指针**悬空但非 None** ⇒ `is None` 守卫失效
|
||||
# ⇒ 下一次 register_ctypedef 的 append 写进已回收内存(堆损坏;检测模式下
|
||||
# 该区被 free 填成 0xCD ⇒ append 收到 rdi=0xcdcdcdcdcdcdcdcd 后崩)。
|
||||
# 故表本体(表对象 + 名索引 + visiting 表)一律落 PermPool(进程级永久池,
|
||||
# 从不 reset),与"文件级/片段级 reset"彻底解耦。
|
||||
# PermPool 不可用(无 CompilerFactory.factory 的极简单元程序)时退回入参
|
||||
# pool —— 与既有语义一致,只是不再有"表本体跨 reset 存活"的隐式假设。
|
||||
# ============================================================
|
||||
def _ctypedef_table_pool(self,
|
||||
pool: rawptr[memhub.MemBuddy]) -> rawptr[memhub.MemBuddy]:
|
||||
"""CTypedef 表本体的池:恒取 PermPool(不可用则退回入参 pool)"""
|
||||
if CompilerFactory.factory is not None \
|
||||
and CompilerFactory.factory.PermPool is not None:
|
||||
return CompilerFactory.factory.PermPool
|
||||
return pool
|
||||
|
||||
def register_ctypedef(self, pool: rawptr[memhub.MemBuddy],
|
||||
name: str, type_str: str) -> None:
|
||||
"""注册 CTypedef 到本地表
|
||||
@@ -152,12 +174,23 @@ class TypeGenCType(TypeGenBase.TypeGenBase):
|
||||
return
|
||||
string.strcpy(type_copy, type_str)
|
||||
if self.CTypedefNames is None:
|
||||
self.CTypedefNames = list[str](pool, 64)
|
||||
self.CTypedefTypeStrs = list[str](pool, 64)
|
||||
# 名索引随表创建(同池;分配失败则标记不可信,查找回退线性扫描)
|
||||
self._ctypedef_idx_init(pool)
|
||||
tp: rawptr[memhub.MemBuddy] = self._ctypedef_table_pool(pool)
|
||||
tn: list[str] | t.CPtr = list[str](tp, 64)
|
||||
ts: list[str] | t.CPtr = list[str](tp, 64)
|
||||
# 建表失败(池不可用/耗尽)⇒ 明确报错并返回,绝不让下面的 append
|
||||
# 落到 None 或未初始化地址(原实现无检查 ⇒ 写进 0xCDCD 区崩)
|
||||
if tn is None or ts is None:
|
||||
VLogger.error("CTypedef 表分配失败(表本体池不可用或耗尽)", "TypeGen")
|
||||
return
|
||||
self.CTypedefNames = tn
|
||||
self.CTypedefTypeStrs = ts
|
||||
# 名索引随表创建(同池 = PermPool;分配失败则标记不可信,查找回退线性扫描)
|
||||
self._ctypedef_idx_init(tp)
|
||||
# 表就绪守卫:表本体缺失(建表失败/被外部置空)⇒ fail-fast,不写垃圾
|
||||
if self.CTypedefNames is None or self.CTypedefTypeStrs is None:
|
||||
VLogger.error("CTypedef 表未就绪(CTypedefNames/CTypedefTypeStrs 为空)", "TypeGen")
|
||||
return
|
||||
# 去重:若已存在同名 CTypedef,更新其类型字符串
|
||||
if self.CTypedefNames is not None:
|
||||
exist_n: sizet = len(self.CTypedefNames)
|
||||
ei: sizet
|
||||
for ei in range(exist_n):
|
||||
@@ -387,15 +420,34 @@ class TypeGenCType(TypeGenBase.TypeGenBase):
|
||||
return TSpec.TS_SIGN_UNKNOWN
|
||||
return self._spec_sign_of_span(ts, 0, string.strlen(ts), depth + 1)
|
||||
def clear_ctypedefs(self) -> None:
|
||||
"""清空 CTypedef 表(模块切换时调用)"""
|
||||
self.CTypedefNames = None
|
||||
self.CTypedefTypeStrs = None
|
||||
# 名索引随表复位(下次 register 重建);不同步会使 Built 与空表错配
|
||||
"""清空 CTypedef 表(模块切换时调用)
|
||||
|
||||
表本体自首次创建起常驻 PermPool(见 _ctypedef_table_pool)⇒ 此处只
|
||||
**清空内容**、不丢弃表指针:
|
||||
- 丢指针会退回"下一次 register_ctypedef 按**调用方 pool** 重建",
|
||||
表本体又落回会被 reset_to 回收的瞬时池(冷 temp 下翻译 includes
|
||||
时才走到注册路径 ⇒ 表本体跨 reset 悬空 ⇒ append 写进已回收/未
|
||||
初始化内存的根因);
|
||||
- 空表与既有语义完全等价:lookup 命中空表即"未命中",
|
||||
register 首次 append 即写回第 0 槽。
|
||||
"""
|
||||
if self.CTypedefNames is not None:
|
||||
self.CTypedefNames.clear()
|
||||
if self.CTypedefTypeStrs is not None:
|
||||
self.CTypedefTypeStrs.clear()
|
||||
# 名索引清槽(槽存 index+1,0=空槽)+ Built 归零(空表与索引同步;
|
||||
# 与"新建表后首次 register"的索引状态逐字一致)
|
||||
if self.CTypedefNameIdx is not None and self.CTypedefNameIdxCap > 0:
|
||||
string.memset(self.CTypedefNameIdx, 0,
|
||||
sizet(self.CTypedefNameIdxCap) * 8)
|
||||
self.CTypedefNameIdxBuilt = 0
|
||||
else:
|
||||
self.CTypedefNameIdx = None
|
||||
self.CTypedefNameIdxCap = 0
|
||||
self.CTypedefNameIdxBuilt = -1
|
||||
self.CTypedefResolveDepth = 0
|
||||
self.CTypedefVisiting = None
|
||||
if self.CTypedefVisiting is not None:
|
||||
self.CTypedefVisiting.clear()
|
||||
# builtins 源扫描标记随表清空复位:每文件最多读一次 includes/builtins.vp
|
||||
# (_lookup_builtins_typedef 的"最后匹配"兜底,见 TypeGenResolve)
|
||||
self.BuiltinsTypedefScanned = 0
|
||||
@@ -421,7 +473,10 @@ class TypeGenCType(TypeGenBase.TypeGenBase):
|
||||
if name is None:
|
||||
return 0
|
||||
if self.CTypedefVisiting is None:
|
||||
self.CTypedefVisiting = list[str](pool, 32)
|
||||
# 与 CTypedef 表同池(PermPool):clear_ctypedefs 只清空、指针不丢,
|
||||
# 避免这张表也落在会被 reset_to 回收的调用方池上
|
||||
vp: rawptr[memhub.MemBuddy] = self._ctypedef_table_pool(pool)
|
||||
self.CTypedefVisiting = list[str](vp, 32)
|
||||
if self.CTypedefVisiting is None:
|
||||
return 0
|
||||
vn: sizet = len(self.CTypedefVisiting)
|
||||
@@ -499,7 +554,7 @@ class TypeGenCType(TypeGenBase.TypeGenBase):
|
||||
"""
|
||||
if pool is None or tree is None:
|
||||
return 0
|
||||
ch: rawptr[list[rawptr[ast.AST]]] = tree.children
|
||||
ch: list[ast.AST*]* = tree.children
|
||||
if ch is None:
|
||||
return 0
|
||||
n: sizet = len(ch)
|
||||
|
||||
@@ -83,7 +83,7 @@ class TypeGenErr(TypeGenBase.TypeGenBase):
|
||||
err_line: int = ast.get_parse_err_line()
|
||||
err_col: int = ast.get_parse_err_col()
|
||||
err_msg: str = ast.get_parse_err_msg()
|
||||
stdio.printf("Traceback (most recent call last):\n")
|
||||
stdio.printf("Traceback (most recent call last, compile-time error):\n")
|
||||
if file_path is None or file_path[0] == 0:
|
||||
file_path = "<unknown>"
|
||||
if err_line > 0:
|
||||
@@ -95,8 +95,7 @@ class TypeGenErr(TypeGenBase.TypeGenBase):
|
||||
# 前缀 4 空格 + err_col 个空格后落点恰好是该 token 首字符)
|
||||
if err_col > 0:
|
||||
stdio.printf(" ")
|
||||
c: int
|
||||
for c in range(err_col):
|
||||
for _ in range(err_col):
|
||||
stdio.printf(" ")
|
||||
stdio.printf("^\n")
|
||||
stdlib.free(src)
|
||||
@@ -112,9 +111,8 @@ class TypeGenErr(TypeGenBase.TypeGenBase):
|
||||
|
||||
向后兼容:err_type/col_start/col_end 有默认值,旧调用 fatal_error(node, msg) 仍可用。
|
||||
"""
|
||||
stdio.printf("Traceback (most recent call last):\n")
|
||||
stdio.printf("Traceback (most recent call last, compile-time error):\n")
|
||||
# 输出调用栈帧(从底到顶)
|
||||
i: int
|
||||
for i in range(self.Gen.TypeGenBase.TraceCount):
|
||||
frame: rawptr[GenTypes.TraceFrame] = self.Gen.TypeGenBase._get_trace_frame(i)
|
||||
if frame is not None and frame.file_name is not None:
|
||||
@@ -176,10 +174,12 @@ class TypeGenErr(TypeGenBase.TypeGenBase):
|
||||
if err_type is None or err_type[0] == 0:
|
||||
err_type = "SyntaxError"
|
||||
stdio.printf("%s: %s\n", err_type, msg)
|
||||
# 退出前强制刷出:stdout 重定向到文件时是全缓冲,sys.exit 直接终止进程
|
||||
# 会把整段 traceback 丢掉(实测 2.log 只剩一行 VLogger 输出)。
|
||||
# 退出前强制刷出:stdout 重定向到文件时是全缓冲,直接终止进程会把整段
|
||||
# traceback 丢掉(实测 2.log 只剩一行 VLogger 输出)。
|
||||
stdio.fflush(None)
|
||||
sys.exit(1)
|
||||
# 终止点收敛:REPL 会话内经 VLogger.repl_abort longjmp 回 REPL 循环
|
||||
# (Traceback 已打印,进程存活);批处理下该出口即 sys.exit(1),逐字不变。
|
||||
VLogger.repl_abort()
|
||||
|
||||
def fatal_type_error(self, node: rawptr[ast.AST], msg: str,
|
||||
col_start: int = 0, col_end: int = 0):
|
||||
@@ -241,7 +241,35 @@ class TypeGenErr(TypeGenBase.TypeGenBase):
|
||||
return 0
|
||||
|
||||
return 0
|
||||
def is_pass_body(self, body: rawptr[list[rawptr[ast.AST]]]) -> int:
|
||||
|
||||
def has_pointee_volatile_marker(self, node: rawptr[ast.AST]) -> int:
|
||||
"""检测指针注解 rawptr[...] 的下标实参是否含 t.CVolatile 标记,1=是 / 0=否
|
||||
|
||||
语义:rawptr[t.CVolatile | T] 等价 C 的 volatile T*,即"指针所指对象按
|
||||
volatile 访问"——解引用(p[i] / p.field / c.Deref(p))的 load/store 带
|
||||
LLVM volatile。与 has_decorator_marker 的区别:后者检测变量/字段**自身**
|
||||
的可见性限定(如 `locked: t.CVolatile | t.CInt`),对 Subscript 节点返回 0;
|
||||
本函数专检 rawptr 的 pointee 侧标记(下标实参子树),两者互不串味。
|
||||
标注形态(vast.parse 实证):
|
||||
rawptr[t.CVolatile | t.CInt]
|
||||
→ Subscript(value=Name('rawptr'),
|
||||
slice=BinOp(BitOr, Attribute(t,CVolatile), Attribute(t,CInt)))
|
||||
多级指针 rawptr[rawptr[t.CVolatile|T]] 的 slice 是 Subscript,
|
||||
has_decorator_marker 不递归 Subscript ⇒ 返回 0(明确不支持,见限制清单)。
|
||||
"""
|
||||
if node is None or node.kind() != ast.ASTKind.Subscript:
|
||||
return 0
|
||||
sub: rawptr[ast.Subscript] = rawptr[ast.Subscript](node)
|
||||
if sub.value is None or sub.value.kind() != ast.ASTKind.Name:
|
||||
return 0
|
||||
rp_nm: rawptr[ast.Name] = rawptr[ast.Name](sub.value)
|
||||
if rp_nm.id is None or string.strcmp(rp_nm.id, "rawptr") != 0:
|
||||
return 0
|
||||
if sub.slice is None:
|
||||
return 0
|
||||
return self.has_decorator_marker(sub.slice, "CVolatile", 0)
|
||||
|
||||
def is_pass_body(self, body: list[ast.AST*]*) -> int:
|
||||
"""检测函数体是否为 pass(空体或仅含 pass 语句)"""
|
||||
if body is None:
|
||||
return 1
|
||||
@@ -319,7 +347,7 @@ class TypeGenErr(TypeGenBase.TypeGenBase):
|
||||
|
||||
return llvmlite.Int32(pool)
|
||||
def infer_return_type(self, pool: rawptr[memhub.MemBuddy],
|
||||
body: rawptr[list[rawptr[ast.AST]]],
|
||||
body: list[ast.AST*]*,
|
||||
param_types: str) -> rawptr[llvmlite.LLVMType]:
|
||||
"""扫描函数体中的 return 语句,推断返回类型"""
|
||||
if body is None:
|
||||
@@ -341,7 +369,7 @@ class TypeGenErr(TypeGenBase.TypeGenBase):
|
||||
ret_ty = expr_ty
|
||||
return ret_ty
|
||||
def body_has_value_return(self, pool: rawptr[memhub.MemBuddy],
|
||||
body: rawptr[list[rawptr[ast.AST]]]) -> int:
|
||||
body: list[ast.AST*]*) -> int:
|
||||
"""扫描函数体,判断是否存在返回非 None 值的 return
|
||||
|
||||
递归检查控制流语句(if/while/for/try/with/match)内层 return,但跳过
|
||||
@@ -373,7 +401,7 @@ class TypeGenErr(TypeGenBase.TypeGenBase):
|
||||
elif k == ast.ASTKind.If or k == ast.ASTKind.While or \
|
||||
k == ast.ASTKind.For or k == ast.ASTKind.Try or \
|
||||
k == ast.ASTKind.With or k == ast.ASTKind.Match:
|
||||
sub: rawptr[list[rawptr[ast.AST]]] = stmt.children
|
||||
sub: list[ast.AST*]* = stmt.children
|
||||
if sub is not None and len(sub) > 0:
|
||||
if self.body_has_value_return(pool, sub) != 0:
|
||||
return 1
|
||||
@@ -395,7 +423,7 @@ class TypeGenErr(TypeGenBase.TypeGenBase):
|
||||
ags: rawptr[ast.Arguments] = rawptr[ast.Arguments](args_node)
|
||||
if ags.args is None:
|
||||
return None
|
||||
alist: rawptr[list[rawptr[ast.AST]]] = ags.args
|
||||
alist: list[ast.AST*]* = ags.args
|
||||
an: sizet = len(alist)
|
||||
if an == 0:
|
||||
return None
|
||||
|
||||
@@ -17,6 +17,7 @@ import lib.core.VLogger as VLogger
|
||||
import lib.core.Gen.Translator as HT
|
||||
import lib.Stub.StubMerger as StubMerger
|
||||
import lib.Stub.StubMerger.StubMergerStore as StubMergerStore
|
||||
import lib.Stub.StubGen.VpiReader as VpiReader
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
import lib.Projectrans.Config as Config
|
||||
|
||||
@@ -151,7 +152,7 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
return self._list_elts_to_type_str(pool, tup.elts, "", "")
|
||||
return None
|
||||
def _list_elts_to_type_str(self, pool: rawptr[memhub.MemBuddy],
|
||||
elts: rawptr[list[rawptr[ast.AST]]],
|
||||
elts: list[ast.AST*]*,
|
||||
open_ch: str, close_ch: str) -> str:
|
||||
"""元素列表转逗号分隔字符串(List/Tuple 共用),包上 open/close 括号
|
||||
|
||||
@@ -230,6 +231,42 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
string.strcat(buf, ".")
|
||||
string.strcat(buf, cls_name)
|
||||
return buf
|
||||
def _repl_opaque_class_ty(self, pool: rawptr[memhub.MemBuddy],
|
||||
mod_sha1: str,
|
||||
cls_name: str) -> rawptr[llvmlite.LLVMType]:
|
||||
"""(REPL 会话专用)未登记类别的"仅类型"占位:`%"{sha1}.{类名}"` opaque 具名结构体
|
||||
|
||||
背景:REPL 的 includes 类注册(M4.2)只登记**布局可信**的类;缺 `.stub.ll`
|
||||
的模块其带父类/虚表的类被拒 ⇒ 该类的类型不在会话 StructTable 里。而其它模块
|
||||
的 `.vpi` 一旦在形参/返回/字段注解里引用它(如
|
||||
`def __new__(self, pool: rawptr[memhub.MemManager])`),注入侧的 S4
|
||||
fail-fast(`VpiReader._inject_method_declare` 的"类型注解解析失败")就会
|
||||
中断**整个模块**的 vpi 注入——报错点在该注解,真因是"被引类未登记"。
|
||||
|
||||
本函数按定义侧命名(`{sha1}.{类名}`,与 ClassGenDef / ClassGenVTable 逐字
|
||||
一致)造 opaque 具名结构体:指针引用与宿主签名逐字兼容(`%"{sha1}.{类名}"*`),
|
||||
且**不写 StructTable** ⇒ `lookup_field_by_class`/`find_struct_by_module`
|
||||
仍按"类未注册"明确报错,绝不按(未知的)字段偏移静默访问(M4.2 的
|
||||
"宁可报错"口径不变)。
|
||||
|
||||
调用面严格限定在 `trans.ReplCtx != None`(REPL 会话)且**模块已知**
|
||||
(sha1 已由 `StubMergerStore` 解析出)的路径:批处理 `trans.ReplCtx`
|
||||
恒 None ⇒ 本函数不被调用,批处理逐字不变;模块名未登记时调用方不接受
|
||||
本兜底(那是真实的"未编译/未扫描"错误,仍 fail-fast)。
|
||||
"""
|
||||
if pool is None or mod_sha1 is None or cls_name is None:
|
||||
return None
|
||||
if mod_sha1[0] == '\0' or cls_name[0] == '\0':
|
||||
return None
|
||||
full: str = self._concat_sha1_class(pool, mod_sha1, cls_name)
|
||||
if full is None:
|
||||
return None
|
||||
ex: rawptr[llvmlite.LLVMType] = self.Gen.StructGen.get_struct_type(full)
|
||||
if ex is not None:
|
||||
return ex
|
||||
# fcount=-1 = opaque 哨兵(区别于空结构体 {}:后者 fcount==0 是"完整定义、
|
||||
# 可 alloca");与 llvmlite 的跨模块 opaque 声明同一表示。
|
||||
return llvmlite.Struct(pool, None, -1, full)
|
||||
def _norm_type_arg_name(self, pool: rawptr[memhub.MemBuddy],
|
||||
type_name: str,
|
||||
from_imports: str) -> str:
|
||||
@@ -610,7 +647,7 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
# parse_tokens 成功,故此处用文件级 parse 兜底)
|
||||
tree_s: rawptr[ast.AST] = ast.parse(type_str, pool)
|
||||
if tree_s is not None:
|
||||
ch_s: rawptr[list[rawptr[ast.AST]]] = tree_s.children
|
||||
ch_s: list[ast.AST*]* = tree_s.children
|
||||
if ch_s is not None and len(ch_s) > 0:
|
||||
st0: rawptr[ast.AST] = ch_s.get(0)
|
||||
if st0 is not None and st0.kind() == ast.ASTKind.Expr:
|
||||
@@ -1766,7 +1803,7 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
# Tuple slice: dict[str, int] → "str,int"
|
||||
sub_tup: rawptr[ast.Tuple] = rawptr[ast.Tuple](sub.slice)
|
||||
if sub_tup.elts is not None:
|
||||
tup_elts_sn: rawptr[list[rawptr[ast.AST]]] = sub_tup.elts
|
||||
tup_elts_sn: list[ast.AST*]* = sub_tup.elts
|
||||
tn_sn: sizet = len(tup_elts_sn)
|
||||
# 计算总长度
|
||||
tup_total: sizet = 1
|
||||
@@ -1827,7 +1864,7 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
# 用于函数 `-> tuple[str, t.CUnsignedShort]`(如 binascii.b2a_hqx)
|
||||
# 与调用端 `a, b = f()` 的打包/解包。
|
||||
if string.strcmp(gen_cls_name, "tuple") == 0:
|
||||
tp_elts: rawptr[list[rawptr[ast.AST]]] = None
|
||||
tp_elts: list[ast.AST*]* = None
|
||||
tp_count: sizet = 0
|
||||
if sub.slice.kind() == ast.ASTKind.Tuple:
|
||||
tp_tup: rawptr[ast.Tuple] = rawptr[ast.Tuple](sub.slice)
|
||||
@@ -1837,7 +1874,7 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
else:
|
||||
# [FIX] elem_size=8(rawptr[ast.AST] 指针 8 字节),原传 1 → get 只读
|
||||
# 1 字节拼指针(高 56 位残留)→ tuple 元素解析垃圾
|
||||
tp_single: rawptr[list[rawptr[ast.AST]]] = list[rawptr[ast.AST]](pool, 8)
|
||||
tp_single: list[ast.AST*]* = list[rawptr[ast.AST]](pool, 8)
|
||||
if tp_single is not None:
|
||||
tp_single.append(sub.slice)
|
||||
tp_elts = tp_single
|
||||
@@ -1870,7 +1907,7 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
gen_arg_names: list[str] | t.CPtr = list[str](pool, 8)
|
||||
if sub.slice.kind() == ast.ASTKind.Tuple:
|
||||
gen_tp: rawptr[ast.Tuple] = rawptr[ast.Tuple](sub.slice)
|
||||
gen_elts: rawptr[list[rawptr[ast.AST]]] = gen_tp.elts
|
||||
gen_elts: list[ast.AST*]* = gen_tp.elts
|
||||
if gen_elts is not None:
|
||||
gen_en: sizet = len(gen_elts)
|
||||
gen_ei: sizet
|
||||
@@ -1909,6 +1946,45 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
if gen_atn is not None:
|
||||
string.strcat(gen_mangled, gen_atn)
|
||||
string.strcat(gen_mangled, "]")
|
||||
# [REPL 注入期] 只做类型/签名层面的事,**绝不触发模板体翻译**(特化延后)。
|
||||
#
|
||||
# 现场:Repl 会话初始化先**真注册**了 includes 泛型模板(Repl.vp 步骤③''),
|
||||
# 随后逐模块注入 .vpi(ReplStubLayoutBegin → ReplInitIncludesClasses,逐模块
|
||||
# _setjmp)。注入的只是类字段/方法**签名**,此刻会话 StructTable 只含"已注入
|
||||
# 模块的已注册类":模板体引用的**跨模块**类型(_list.vp 的 memhub.MemManager)
|
||||
# 与**同模块**类型(linkedlist.vp 的 NameEntry)都可能尚未注册(模板是全局
|
||||
# 预注册的,其归属模块未必已注入、同模块兄弟类也未必已注册)。
|
||||
# 故一旦在此特化,_specialize_generic_class 就会 translate_class_def 翻译模板
|
||||
# 类体源码(字段/方法注解解析)⇒ 命中未注册类型 ⇒ lookup_field_by_class /
|
||||
# 形参注解解析失败 fatal ⇒ 该模块整个 .vpi 注入中断(异常被逐模块 _setjmp
|
||||
# 隔离,但该模块的类全部注册不上 + Traceback 刷屏)。
|
||||
# 结论:注入期**不特化**,直接返回**可用的 opaque 特化名**
|
||||
# (`%"{模板模块 sha1}.{mangled}"`,与定义侧特化命名逐字一致)——注解解析
|
||||
# 成功、不触碰任何未注册类型、不写 StructTable(字段访问照旧按"类未注册"
|
||||
# 明确报错)。真正需要布局/方法时在**片段期**走下方既有特化路径:ReplCtx
|
||||
# 仍在但 ReplStubLayoutMode 已归零 ⇒ 本分支不经过,特化照常发生(届时按需
|
||||
# 注册的依赖已就绪;确实缺失则明确报错,落在片段内、不影响启动)。
|
||||
# 批处理 ReplCtx 恒 None 且 ReplStubLayoutMode 恒 0 ⇒ 本分支不经过,逐字不变。
|
||||
if trans is not None and trans.ReplCtx is not None \
|
||||
and VpiReader.ReplStubLayoutMode != 0:
|
||||
# 已登记的特化结构体(会话期先前注册)直接复用:本分支只读、不翻译
|
||||
spec_ty_inj: rawptr[llvmlite.LLVMType] = self.Gen.StructGen.get_struct_type(gen_mangled)
|
||||
if spec_ty_inj is not None:
|
||||
return spec_ty_inj
|
||||
# 归属模块 sha1:优先取**全局模板表**(步骤③'' 已按 includes 全量注册,
|
||||
# 与模块注入顺序无关 ⇒ 跨模块泛型如 GSList 也能拼出定义侧特化名);
|
||||
# 退回注入期逐模块登记的归属表(StubMergerStore.RegisterGenericOwner)。
|
||||
inj_owner: str = self.Gen.ClassGenGeneric._find_generic_template_sha1(gen_cls_name)
|
||||
if inj_owner is None:
|
||||
inj_owner = StubMergerStore.LookupGenericOwnerSha1(gen_cls_name)
|
||||
if inj_owner is not None:
|
||||
ty_inj: rawptr[llvmlite.LLVMType] = self._repl_opaque_class_ty(
|
||||
pool, inj_owner, gen_mangled)
|
||||
if ty_inj is not None:
|
||||
return ty_inj
|
||||
# 归属未知(模板/归属均未登记)⇒ 保持原口径返回 None,由上层按
|
||||
# "注解解析失败"明确报错(不伪造无模块前缀的类名)
|
||||
return None
|
||||
# 查找已特化的 struct(特化由实例化调用 list[int](pool) 触发)
|
||||
gen_spec_ty: rawptr[llvmlite.LLVMType] = self.Gen.StructGen.get_struct_type(gen_mangled)
|
||||
if gen_spec_ty is not None:
|
||||
@@ -1971,6 +2047,26 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
f"泛型下标 '{gen_mangled}' 未解析出特化结构体(泛型模板='{gen_cls_name}');"
|
||||
f"该注解将退化为裸基类/i8* → 后续 .get() 按错误元素类型分派并截断指针",
|
||||
"TypeError")
|
||||
# [REPL 会话] includes 泛型模板(list/dict/Vector/…)在会话里**未注册**:会话
|
||||
# 类注册只注入 `.vpi` 的类(泛型类被跳过),不跑批处理的
|
||||
# _PreRegister*GenericTemplates ⇒ 泛型下标的特化恒 miss。若该注解位于形参/
|
||||
# 返回位置,S4 fail-fast 会中断**整个模块**的 `.vpi` 注入(实测:93da… 的
|
||||
# `targets: rawptr[list[rawptr[AST]]]`;9 个 `.vpi` / 78 条 def 签名行含
|
||||
# list[/dict[,其中 93da… 30 条)。故按定义侧特化命名
|
||||
# "%{模板模块 sha1}.{mangled}" 造 opaque 具名类型占位(实证
|
||||
# `%"b56d2f995104690d.list[rawptr[AST]]"`):方法调用按类名仍可解析(符号在
|
||||
# 宿主里),字段访问按"类未注册/字段未找到"明确报错(不静默按错偏移访问)。
|
||||
# 模板模块 sha1 取**登记事实**(VpiReader 注入期扫 ClassDef 登记,见
|
||||
# StubMergerStore.RegisterGenericOwner),不按名字猜。
|
||||
# 批处理 trans.ReplCtx 恒 None ⇒ 不经过;本分支只在上述**全部**查找(含特化
|
||||
# 触发)失败后到达 ⇒ 不改变任何既有成功路径。
|
||||
if trans is not None and trans.ReplCtx is not None:
|
||||
gowner_sha1: str = StubMergerStore.LookupGenericOwnerSha1(gen_cls_name)
|
||||
if gowner_sha1 is not None:
|
||||
ty_repl_g: rawptr[llvmlite.LLVMType] = self._repl_opaque_class_ty(
|
||||
pool, gowner_sha1, gen_mangled)
|
||||
if ty_repl_g is not None:
|
||||
return ty_repl_g
|
||||
# 未特化:返回 None(不报错,让后续流程处理)
|
||||
return None
|
||||
def resolve_annotation_type(self, pool: rawptr[memhub.MemBuddy],
|
||||
@@ -2134,12 +2230,14 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
# trans.ModuleSha1 是"正在翻译的文件",而注解里的类归属 stub 源模块
|
||||
# (from_imports 即该 stub 的名字→模块映射)。仅靠"当前模块 sha1 + 全局可见性"
|
||||
# 在 App 严格模式下会查不到(如 ast.stmts.Expression 经 ast.__init__.vpi 注入)。
|
||||
fi_sha1_rn: str = None
|
||||
if trans is not None and from_imports is not None:
|
||||
fi_mod: str = StubMergerStore.LookupModNameByAlias(from_imports, nm.id)
|
||||
if fi_mod is not None:
|
||||
fi_sha1: str = StubMergerStore.LookupSha1ByModName(fi_mod)
|
||||
if fi_sha1 is None:
|
||||
fi_sha1 = StubMergerStore.LookupSha1ByModNameSuffix(fi_mod)
|
||||
fi_sha1_rn = fi_sha1
|
||||
stdlib.free(fi_mod)
|
||||
if fi_sha1 is not None:
|
||||
fi_entry: rawptr[GenTypes.StructEntry] = self.Gen.StructGen.find_struct_by_module(nm.id, fi_sha1)
|
||||
@@ -2237,6 +2335,29 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
pool, lib_node_n, imported_modules, from_imports, trans, depth + 1)
|
||||
if lib_ty_n is not None:
|
||||
return lib_ty_n
|
||||
# [REPL 会话] 归属模块已知(from_imports 解析出 sha1;或本模块自身 =
|
||||
# 注入期 trans.ModuleSha1 = 当前 stub 的源模块 sha1)但该类未在会话
|
||||
# StructTable 登记(M4.2 布局不可信被拒 / 字段类型不可解析被跳过)⇒
|
||||
# 用 opaque 具名类型占位,使该注解可解析(不写 StructTable,字段访问
|
||||
# 仍按"类未注册"明确报错)。批处理 trans.ReplCtx 恒 None ⇒ 不经过;
|
||||
# 本分支在上述全部查找失败后才到达 ⇒ 不改变任何既有成功路径。
|
||||
if trans is not None and trans.ReplCtx is not None:
|
||||
own_sha_rn: str = fi_sha1_rn
|
||||
# 本模块裸类名:仅当 trans.ModuleSha1 是"当前 stub 的源模块 sha1"时可用
|
||||
# (REPL 会话初始化注入期由 ReplInitIncludesClasses 逐模块设置)。
|
||||
# 片段翻译期 trans.ModuleSha1 = 会话 sha1(GenTypes.REPL_SESSION_SHA1):
|
||||
# 此刻裸名找不到归属就**不能**拿会话 sha1 当归属(会造出
|
||||
# "%{会话sha1}.{类名}" 这种宿主里不存在的类名 → 方法调用符号名误导),
|
||||
# 故排除该情形,保持原 fail-fast。
|
||||
if own_sha_rn is None:
|
||||
if trans.ModuleSha1 is not None \
|
||||
and string.strcmp(trans.ModuleSha1, GenTypes.REPL_SESSION_SHA1) != 0:
|
||||
own_sha_rn = trans.ModuleSha1
|
||||
if own_sha_rn is not None:
|
||||
ty_repl_n: rawptr[llvmlite.LLVMType] = self._repl_opaque_class_ty(
|
||||
pool, own_sha_rn, nm.id)
|
||||
if ty_repl_n is not None:
|
||||
return ty_repl_n
|
||||
return None
|
||||
|
||||
# Attribute 节点: int, uint64, namespace_defs.PlainStruct 等
|
||||
@@ -2306,9 +2427,14 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
# SHA1 前缀形态优先用完整名 "{sha1}.{Class}" 精确命中定义侧
|
||||
# struct(get_struct_type 类名回退可能命中跨模块同名类)
|
||||
full_attr_ty: rawptr[llvmlite.LLVMType] = None
|
||||
# mod_sha1_rv:把本分支解析出的"模块段 sha1"带到末尾(REPL 会话的
|
||||
# "仅类型"占位兜底要用它;声明在此以覆盖下方 SHA1 前缀形态与枚举/
|
||||
# typedef 尝试都在同一作用域)。
|
||||
mod_sha1_rv: str = None
|
||||
# val_name.id 是模块名段:恰为 16 位小写 hex 才是 SHA1 别名
|
||||
#(判定走唯一真源 GenApi.is_sha1_hex16,C10 收敛)。
|
||||
if is_builtin_attr == 0 and GenApi.is_sha1_hex16(val_name.id) != 0:
|
||||
mod_sha1_rv = val_name.id
|
||||
full_q: str = self._concat_sha1_class(pool, val_name.id, at.attr)
|
||||
if full_q is not None:
|
||||
full_attr_ty = self.Gen.StructGen.get_struct_type(full_q)
|
||||
@@ -2324,6 +2450,7 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
# StructGenMixin._resolve_module_sha1 逐级尝试)
|
||||
mod_sha1_v: str = self.Gen.StructGen._resolve_module_sha1(
|
||||
val_name.id, from_imports)
|
||||
mod_sha1_rv = mod_sha1_v
|
||||
if mod_sha1_v is not None:
|
||||
full_q_v: str = self._concat_sha1_class(pool, mod_sha1_v, at.attr)
|
||||
if full_q_v is not None:
|
||||
@@ -2366,6 +2493,15 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
return mod_td_ty
|
||||
else:
|
||||
self.Gen.TypeGenCType._ctypedef_pop_visiting()
|
||||
# [REPL 会话] 模块限定名(memhub.MemManager 等)的归属模块已知,
|
||||
# 但该类未在会话 StructTable 登记(M4.2 布局不可信被拒 / 字段类型
|
||||
# 不可解析被跳过)⇒ 用 opaque 具名类型占位(不写 StructTable ⇒
|
||||
# 字段访问仍按"类未注册"明确报错)。批处理 trans.ReplCtx 恒 None。
|
||||
if trans is not None and trans.ReplCtx is not None and mod_sha1_rv is not None:
|
||||
ty_repl_a: rawptr[llvmlite.LLVMType] = self._repl_opaque_class_ty(
|
||||
pool, mod_sha1_rv, at.attr)
|
||||
if ty_repl_a is not None:
|
||||
return ty_repl_a
|
||||
return None
|
||||
# 嵌套 Attribute: w32.win32base.SECURITY_ATTRIBUTES 等三级及以上限定名
|
||||
# at.value 是 Attribute 而非 Name,递归提取最终类名(at.attr)查结构体表
|
||||
@@ -2755,7 +2891,7 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
tup: rawptr[ast.Tuple] = rawptr[ast.Tuple](sub.slice)
|
||||
if tup.elts is None:
|
||||
self.Gen.TypeGenErr.fatal_type_error(node, "t.CArray Tuple 缺少 elts")
|
||||
elts_list: rawptr[list[rawptr[ast.AST]]] = tup.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 元素不足")
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
+62
-4
@@ -14,6 +14,53 @@ import w32.win32base as win32base
|
||||
# 输出格式: ├ LEVEL: message / ├ LEVEL[category]: message(与 TPC lib/core/VLogger.py 对齐)
|
||||
# ============================================================
|
||||
|
||||
# 错误恢复(REPL/JIT 模式):error 打印后 longjmp 跳回 REPL 的 setjmp 点。
|
||||
# mingw-w64 x86_64:longjmp 原型为 void longjmp(jmp_buf, int);setjmp 宏展开为
|
||||
# _setjmp(buf, NULL)(jmp_buf 实为 _JBTYPE[16],见 Repl.vp 的 _REPL_JMPBUF_SIZE)。
|
||||
extern def longjmp(buf: t.CPtr, val: int)
|
||||
|
||||
|
||||
# REPL 恢复点指针(由 Repl 在会话开始时注册、会话结束时清除)。
|
||||
# 生命周期 = 整个 REPL 会话:Repl 每轮片段都会重新武装(Repl.run 每轮 _setjmp +
|
||||
# Repl.ReplExecFragment 入口重注册),故它覆盖整条片段流水线(翻译 → 写 .ll →
|
||||
# llc → clang++ → LoadLibrary → GetProcAddress → 调用 → 回显),而不只是翻译期。
|
||||
# 批处理路径从不调用 set_repl_jmpbuf ⇒ 恒为 None ⇒ 所有出口退回 sys.exit(1)。
|
||||
_repl_jmpbuf: t.CPtr = None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# repl_abort - TPV 内"诊断后终止"的唯一出口
|
||||
#
|
||||
# 约定:调用方**已打印**诊断(Traceback / VLogger.error / [OOM] 等),本函数只决定
|
||||
# "跳回 REPL 继续"还是"终止进程":
|
||||
# * REPL 会话(_repl_jmpbuf 已注册):fflush 后 longjmp 回 Repl.run 的恢复点,
|
||||
# 进程存活、提示符继续(宽容 Traceback);
|
||||
# * 批处理 / 未武装:sys.exit(1),与改动前的 fail-fast 行为逐字一致。
|
||||
# 收敛点:Logger.error、模块级 error、TypeGenErr.fatal_error、
|
||||
# ImportsGenMixin._report_import_error、CallGenBase/VpiReader 的链表哨兵。
|
||||
# ============================================================
|
||||
def repl_abort() -> int:
|
||||
"""诊断后的统一出口:已注册恢复点则 longjmp 回 REPL,否则终止进程。"""
|
||||
if _repl_jmpbuf is not None:
|
||||
stdio.fflush(None)
|
||||
longjmp(_repl_jmpbuf, 1)
|
||||
sys.exit(1)
|
||||
return 0
|
||||
|
||||
|
||||
def set_repl_jmpbuf(buf: t.CPtr) -> int:
|
||||
"""注册 REPL 的 jmp_buf(会话开始;每片段入口可幂等重注册)。"""
|
||||
global _repl_jmpbuf
|
||||
_repl_jmpbuf = buf
|
||||
return 0
|
||||
|
||||
|
||||
def clear_repl_jmpbuf() -> int:
|
||||
"""清除已注册的 jmp_buf(REPL 会话结束时调用;中途不清)。"""
|
||||
global _repl_jmpbuf
|
||||
_repl_jmpbuf = None
|
||||
return 0
|
||||
|
||||
# 日志级别
|
||||
class LogLevel(t.CEnum):
|
||||
DEBUG = 0
|
||||
@@ -47,12 +94,14 @@ class Logger:
|
||||
_level: int
|
||||
_console_handle: win32base.HANDLE
|
||||
_use_color: int
|
||||
jit_flag: bool
|
||||
__mbuddy__: rawptr[memhub.MemBuddy]
|
||||
|
||||
def __init__(self, level: int = 1):
|
||||
self._level = level
|
||||
self._console_handle = w32file.GetStdHandle(w32file.STD_OUTPUT_HANDLE)
|
||||
self._use_color = 1
|
||||
self.jit_flag = False
|
||||
self.__mbuddy__ = _mbuddy
|
||||
|
||||
def _set_color(self, attr: WORD) -> int:
|
||||
@@ -108,7 +157,11 @@ class Logger:
|
||||
ret: int = self._log(LogLevel.ERROR, "├", "ERROR", msg,
|
||||
FOREGROUND_RED,
|
||||
FOREGROUND_RED | FOREGROUND_INTENSITY, category)
|
||||
# 错误立即终止进程(避免错误后继续执行导致连锁崩溃)
|
||||
# JIT/REPL 模式:诊断已打印,经统一出口跳回 REPL 循环(未武装时该出口仍终止进程)
|
||||
if self.jit_flag:
|
||||
repl_abort()
|
||||
return ret
|
||||
# 批处理模式:错误立即终止进程(行为与改动前逐字一致)
|
||||
sys.exit(1)
|
||||
return ret
|
||||
|
||||
@@ -128,6 +181,11 @@ class Logger:
|
||||
self._level = level
|
||||
return 0
|
||||
|
||||
def set_jit_flag(self, v: bool) -> int:
|
||||
"""设置 JIT/REPL 模式标志:True 时 error 改为 longjmp 回 REPL 循环。"""
|
||||
self.jit_flag = v
|
||||
return 0
|
||||
|
||||
# ============================================================
|
||||
# 高级日志方法
|
||||
# ============================================================
|
||||
@@ -211,10 +269,10 @@ def warning(msg: str, category: str = "") -> int:
|
||||
|
||||
|
||||
def error(msg: str, category: str = "") -> int:
|
||||
"""输出 ERROR 级别日志并立即终止进程。"""
|
||||
"""输出 ERROR 级别日志:批处理模式终止进程;JIT/REPL 模式 longjmp 回 REPL。"""
|
||||
if log is not None: return log.error(msg, category)
|
||||
# logger 不可用时也直接退出
|
||||
sys.exit(1)
|
||||
# logger 不可用时也走统一出口(REPL 已注册恢复点时仍可恢复)
|
||||
repl_abort()
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
+70
-2
@@ -1,5 +1,6 @@
|
||||
import lib.core.Gen.GenApi as GenApi
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.core.Repl as Repl
|
||||
import lib.core.Gen.Translator as HandlesTranslator
|
||||
import lib.Phase.BuildPipeline as BuildPipeline
|
||||
import lib.core.IncludesScanner as IncludesScanner
|
||||
@@ -41,13 +42,16 @@ CODE_PAGE: t.CDefine = 65001
|
||||
SRC_BUF_SIZE: t.CDefine = 1048576
|
||||
# Version (dev/beta/rc)
|
||||
V_VIPER_VERSION: t.CDefine = "1.0.3-dev.31 2026-07-27 Non-LTS"
|
||||
V_TPV_VERSION: t.CDefine = "0.0.3-dev.428"
|
||||
V_TPV_VERSION: t.CArray[char] | t.attr.section(".PRVERSN") = "0.0.3-dev.428"
|
||||
V_RUNTIME_VERSION: t.CDefine = "0.2.3+19-Non-LTS"
|
||||
V_TPC_COMMIT: t.CDefine = "e376b949c9"
|
||||
V_TPV_COMMIT: t.CDefine = "ab0f37e1a8"
|
||||
V_RUNTIME_COMMIT: t.CDefine = "f087aa88e2"
|
||||
V_TARGET: t.CDefine = "x86_64-w64-windows-gnu"
|
||||
V_LLVM: t.CDefine = "22.1.8"
|
||||
# --repl 模板工程查找缓冲(repl.vpj 命中路径 / 未命中诊断文本)
|
||||
REPL_PROJ_PATH_CAP: t.CDefine = 1024
|
||||
REPL_PROJ_DIAG_CAP: t.CDefine = 2048
|
||||
|
||||
# ============================================================
|
||||
# main: Command-line entry
|
||||
@@ -152,6 +156,7 @@ def main() -> int:
|
||||
# 早于 parse_args,值取自 L70-72 的原始命令行 strstr —— 与 --detection 同范式)
|
||||
parser.add_argument("--detection-deep", None, argparse.BOOL, 0, None, False, argparse.STORE_TRUE, "Deep detection: probe every allocation and enable the periodic full-table scan (implies --detection; extremely slow, diagnostics only)")
|
||||
parser.add_argument("--show-args", None, argparse.BOOL, 0, None, False, argparse.STORE_TRUE, "Show all parsed arguments")
|
||||
parser.add_argument("--repl", None, argparse.BOOL, 0, None, False, argparse.STORE_TRUE, "Start the interactive REPL (M2 session variables + M3 cross-fragment functions: fragment -> DLL -> call)")
|
||||
parser.add_argument("--build-dir", None, argparse.STRING, 0, None, False, argparse.STORE, "Override project.vpj build_dir (default ./.tpv_build; relative paths resolve against the project dir)")
|
||||
parser.add_argument("--no-llvmpeephole", None, argparse.BOOL, 0, None, False, argparse.STORE_TRUE, "Disable all local llvmlite peephole passes (T2 store/load forward & ret-zero, T3 no-op bitcast) in FunctionPrint serialization")
|
||||
parser.add_argument("--version", "-v", argparse.BOOL, 0, None, False, argparse.STORE_TRUE, "Show version and exit")
|
||||
@@ -183,6 +188,37 @@ Target: %s
|
||||
""", V_VIPER_VERSION, V_RUNTIME_VERSION, V_TPV_VERSION, V_TPV_COMMIT, V_TPC_COMMIT, V_RUNTIME_COMMIT, V_TARGET, V_LLVM)
|
||||
return 0
|
||||
|
||||
# === --repl 守卫:与 --phase2command / --asan 互斥 ===
|
||||
# 位置:在下面 --asan / --phase2command 的全局状态设置与清理副作用之前
|
||||
#(--asan 会切 includes 缓存后缀并清空 .binary_asan、--phase2command 会设置
|
||||
# BuildPipeline._phase2_cmd_path),故必须最先判定。
|
||||
# ① --phase2command:_phase2_cmd_path 非空时 compile_ll_to_obj 只把 opt/llc
|
||||
# 命令写进 bat 而**不执行**(BuildPipeline.vp:322-344)⇒ 片段 .obj 不会生成,
|
||||
# Repl 第 ⑩ 步的 clang++ -shared 必然失败(Repl.vp 的 ReplExecFragment)。
|
||||
# ② --asan:会给片段 .ll 先做 opt -passes=asan 插桩
|
||||
# (BuildPipeline.vp:346-361),而片段产物是运行期 LoadLibraryA 载入的 DLL,
|
||||
# 宿主进程并未挂 ASan 运行库,"片段 obj 被插桩"语义不明。
|
||||
repl_flag: bool = args.get_bool("repl")
|
||||
if repl_flag:
|
||||
if args.get_str("phase2command") is not None:
|
||||
stdio.printf("FAIL: --repl 与 --phase2command 互斥\n")
|
||||
stdio.printf(" 原因: --phase2command 下 compile_ll_to_obj 只写 bat 不执行 llc,\n")
|
||||
stdio.printf(" 片段 .obj 不会生成,随后的 clang++ -shared 必然失败\n")
|
||||
stdio.printf(" 处理: 去掉 --phase2command(REPL 需要立即产出并加载片段 DLL)\n")
|
||||
argparse.release(args)
|
||||
return 2
|
||||
if args.get_bool("asan"):
|
||||
stdio.printf("FAIL: --repl 与 --asan 互斥\n")
|
||||
stdio.printf(" 原因: --asan 先对片段 .ll 做 ASan 插桩,而片段产物是运行期\n")
|
||||
stdio.printf(" LoadLibraryA 载入的 DLL,宿主进程未挂 ASan 运行库,插桩语义不明\n")
|
||||
stdio.printf(" 处理: 去掉 --asan(如需排查内存问题,请用工程模式构建 ASan 版 TransPyV)\n")
|
||||
argparse.release(args)
|
||||
return 2
|
||||
|
||||
# === --repl: M1 交互式循环(表达式片段 → DLL → 调用回显)===
|
||||
# 分支位置:见下方"工程配置加载"之后(Repl 需要 Config 的 compiler/linker/target 通道),
|
||||
# 仍在 Phase1/Phase2 之前;该分支直接返回。
|
||||
|
||||
# 打印解析结果
|
||||
# log.banner("TransPyV 参数解析结果")
|
||||
|
||||
@@ -249,9 +285,30 @@ Target: %s
|
||||
llvmlite.G_PeepEnable = 0
|
||||
log.info("--no-llvmpeephole 已启用:关闭 FunctionPrint 本地窥孔(RenumberSSA 保留)", "peep")
|
||||
|
||||
# 加载 project.vpj 配置
|
||||
# === --repl 启动便利:未给 --project 时按 cwd → exe 同目录 查找 repl.vpj ===
|
||||
# 命中后按 --project 等价路径喂给下面既有的 Config.Load_project_config 流程
|
||||
#(不另写一套加载器);两处都没有则 fail-fast,诊断文本含"需要 --project"、
|
||||
# 两个已查位置与模板位置(由 Repl.ReplFindProject 写入 repl_diag_buf)。
|
||||
proj_loaded: int = 0
|
||||
proj_path: str = project
|
||||
if repl_flag and proj_path is None:
|
||||
repl_proj_buf: bytes = stdlib.malloc(REPL_PROJ_PATH_CAP)
|
||||
repl_diag_buf: bytes = stdlib.malloc(REPL_PROJ_DIAG_CAP)
|
||||
if repl_proj_buf is None or repl_diag_buf is None:
|
||||
stdio.printf("FAIL: --repl 查找 repl.vpj 的路径缓冲分配失败\n")
|
||||
argparse.release(args)
|
||||
return 1
|
||||
if Repl.ReplFindProject(repl_proj_buf, REPL_PROJ_PATH_CAP,
|
||||
repl_diag_buf, REPL_PROJ_DIAG_CAP) != 0:
|
||||
proj_path = repl_proj_buf
|
||||
log.info(f"--repl: 未指定 --project,使用查找到的模板工程 {proj_path}", "repl")
|
||||
else:
|
||||
stdio.printf("FAIL: --repl 未找到工程文件 repl.vpj\n")
|
||||
stdio.printf("%s", repl_diag_buf)
|
||||
stdio.printf(" 也可用 --project 显式指定工程文件(如本仓库的 TransPyV/project.vpj)\n")
|
||||
argparse.release(args)
|
||||
return 1
|
||||
# 加载工程配置(显式 --project / --repl 查找到的 repl.vpj)
|
||||
if proj_path is not None:
|
||||
log.banner("工程配置")
|
||||
cfg_ret: int = Config.Load_project_config(proj_path)
|
||||
@@ -290,6 +347,17 @@ Target: %s
|
||||
Config.resolve_paths(proj_dir)
|
||||
Config.print_config()
|
||||
|
||||
# === --repl: M1 交互式循环(表达式片段 → IR → llc → clang++ -shared → DLL → 调用回显)===
|
||||
# 位置:工程配置加载之后(Repl 经 Config 取 compiler/linker 命令与 target triple;
|
||||
# 未加载 project.vpj 时 Repl 退回内置默认 llc/clang++),仍在 Phase1/Phase2 之前。
|
||||
if args.get_bool("repl"):
|
||||
Repl._perm_pool = perm_pool # jmp_buf/解析表/会话缓冲须跨行存活,必须用 PermPool
|
||||
if log is not None:
|
||||
log.set_jit_flag(True) # error 改为 longjmp 回 REPL(Repl.run 退出时复位 False)
|
||||
rc_repl: int = Repl.run(mb)
|
||||
argparse.release(args)
|
||||
return rc_repl
|
||||
|
||||
# --asan 要求工程在 project.vpj 的 linker.static_libs 声明 ASan 运行库(TPV 不硬编码路径),缺失则 fail-fast
|
||||
if BuildPipeline._asan_mode != 0 and Config.asan_runtime_declared() == 0:
|
||||
log.error("启用 --asan 需要在 project.vpj 的 linker.static_libs 里声明 ASan 运行库:", "asan")
|
||||
|
||||
@@ -138,6 +138,7 @@ exe\TransPyV.exe --project TransPyV\Test\project.vpj --clean --run
|
||||
| `--rebuild-includes` | 只删 includes 预编译缓存(`includes.binary`),强制重编 includes |
|
||||
| `--clear-cache` | 只清 temp 缓存(`.vpi` / `.stub.ll` / `.text.ll`),强制重生成 stub |
|
||||
| `--run` | 编译成功后立即执行产物 |
|
||||
| `--repl` | 交互式 REPL(M1:表达式片段 → DLL → 调用回显);未给 `--project` 时按 cwd → `TransPyV.exe` 同目录查找 `repl.vpj` 模板工程(找不到则报错并提示 `--project`);与 `--asan` / `--phase2command` 互斥 |
|
||||
| `--asan` | ASan 模式:先 `opt -passes=asan` 插桩;运行库须由 `project.vpj` 的 `linker.static_libs` 声明,否则 fail-fast |
|
||||
| `--phase2command <bat>` | 不执行 `llc`/链接,只把命令写进指定 `.bat` |
|
||||
| `--nowarn-register` | 抑制 Phase A 依赖类 WARN(跨模块 `text.ll` 未生成,下遍收敛) |
|
||||
@@ -349,6 +350,7 @@ exe\TransPyV.exe --project TransPyV\Test\project.vpj --clean --run
|
||||
| `--rebuild-includes` | delete only the includes cache (`includes.binary`), forcing a full includes rebuild |
|
||||
| `--clear-cache` | clear only temp (`.vpi` / `.stub.ll` / `.text.ll`), forcing stub regeneration |
|
||||
| `--run` | execute the produced binary on success |
|
||||
| `--repl` | interactive REPL (M1: expression fragment → DLL → call and echo); without `--project` it looks for the `repl.vpj` template project in cwd, then next to `TransPyV.exe` (errors out with a `--project` hint if neither exists); mutually exclusive with `--asan` / `--phase2command` |
|
||||
| `--asan` | ASan mode: `opt -passes=asan` first; runtimes must be declared in `project.vpj` `linker.static_libs`, else fail-fast |
|
||||
| `--phase2command <bat>` | do not run `llc`/link; write the commands into the given `.bat` |
|
||||
| `--nowarn-register` | suppress Phase A dependency WARNs (cross-module `text.ll` not yet emitted, converges next pass) |
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
"-Wl,--allow-multiple-definition",
|
||||
"-Wl,--stack,0x1000000",
|
||||
"-Wl,--no-insert-timestamp",
|
||||
"-Wl,--export-all-symbols",
|
||||
"-g"
|
||||
],
|
||||
"static_libs": [
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
|
||||
"name": "viperepl",
|
||||
"version": "1.0.0",
|
||||
"build_dir": "%temp%/viperepl/.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": [
|
||||
"-filetype=obj",
|
||||
"-relocation-model=pic",
|
||||
"-O0"
|
||||
]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "D:/msys64/mingw64/bin/clang++.exe",
|
||||
"flags": [
|
||||
"-fuse-ld=lld",
|
||||
"-lmsvcrt",
|
||||
"-lucrt",
|
||||
"-lpthread",
|
||||
"-lmingwex",
|
||||
"-lkernel32",
|
||||
"-Wl,--allow-multiple-definition",
|
||||
"-Wl,--stack,0x1000000",
|
||||
"-Wl,--no-insert-timestamp",
|
||||
"-g"
|
||||
],
|
||||
"output": "repl.dll"
|
||||
},
|
||||
"includes": [
|
||||
"../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"sha1_slice_level": 1,
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user