feat(lang): 新增 cif/celif/celse 条件编译与值引用注解 &T/&temp T,assert 改译 testcheck.check

cif 三件套:StmtGenCifMixin 负责常量求值(含 defined(模块宏) 的 Attribute 形式),链式错配与含运行时变量一律 fail-fast;删掉 c.CIf 家族。值引用:TypeGenResolve 让 CRef/CTempRef 与 t.CPtr 走同一解析路径(&void 折叠为 i8*,删除 t.CNeedPtr),CallGenBase 在调用点按形参模式自动取址(ref 只接受左值,右值 fail-fast;temp 物化临时栈),跨模块经 VpiReader/StubMergerBuild 传递模式。assert:StmtGenMixin 合成 testcheck.check(cond, None, msg),Translator 检测到 assert 时自动注入 testcheck 导入(带去重与防环),深递归守卫改用 stdio.printf + stdlib.exit(Translator 无 Gen 成员)。
This commit is contained in:
TermiNexus committed 2026-10-07 19:03:16 +08:00
1 parent ce50daa87a
commit 2fb648d68a
22 files changed
+556 -85

No files matched your search

+40 -2
View File
@@ -850,6 +850,41 @@ def _vpi_param_annot_seg_is(src_sha1: str, cls_name: str, method_name: str, seg_
return 1
# _vpi_param_annot_seg_mode - value-reference mode of a param-annotation segment: 0=none / 1=ref / 2=temp.
# The definition side writes `T | t.CRef` / `T | t.CTempRef`; the call side mirrors it (auto-address).
def _vpi_param_annot_seg_mode(prm_annots: str, seg_idx: int) -> int:
"""Return the value-reference mode encoded in a vpi param-annotation segment."""
if prm_annots is None or seg_idx < 0: return 0
cur: sizet = 0
for seg in range(seg_idx):
while prm_annots[cur] != '\0' and prm_annots[cur] != '@': cur += 1
if prm_annots[cur] == '\0': return 0
cur += 1
slen: sizet = 0
while prm_annots[cur + slen] != '\0' and prm_annots[cur + slen] != '@': slen += 1
if slen == 0: return 0
seg_buf: bytes = stdlib.malloc(slen + 1)
if seg_buf is None: return 0
string.strncpy(seg_buf, prm_annots + cur, slen)
seg_buf[slen] = '\0'
mode: int = 0
if string.strstr(seg_buf, "CTempRef") is not None: mode = 2
elif string.strstr(seg_buf, "CRef") is not None: mode = 1
elif seg_buf[0] == '&':
# The stub may carry the union marker (`T | t.CRef`, written by this compiler's StubGen) or
# the source syntax (`&T` / `&temp T`, written by TPC's StubGen). Accept both, else a
# cross-module value-reference call would silently lose its auto-address.
q: sizet = 0
while seg_buf[q] == ' ' or seg_buf[q] == '\t': q += 1
if seg_buf[q] == '&':
q += 1
while seg_buf[q] == ' ' or seg_buf[q] == '\t': q += 1
if slen - q >= 4 and string.strncmp(seg_buf + q, "temp", 4) == 0: mode = 2
else: mode = 1
stdlib.free(seg_buf)
return mode
# _ensure_vpi_param_annot_loaded - lazily load a module's vpi stub param-annotation cache.
# Mirror of the return variant; reads the .vpi file on miss, idempotent.
def _ensure_vpi_param_annot_loaded(src_sha1: str, temp_dir: str) -> int:
@@ -1192,6 +1227,7 @@ def _resolve_vpi_ret_annot_str(pool: memhub.MemBuddy*, ret_annot: str, i32_ty: m
return mlirlite.Void(pool)
has_cptr: int = 0
has_cref: int = 0
has_cvoid: int = 0
first_ty: mlirlite.LLVMType* = None
# Attributes of the segment that produced first_ty (for the has_cptr branch, N12):
@@ -1252,7 +1288,9 @@ def _resolve_vpi_ret_annot_str(pool: memhub.MemBuddy*, ret_annot: str, i32_ty: m
if lvl_cs > cptr_sub_lvl:
cptr_sub_lvl = lvl_cs
cptr_sub_ty = seg_ty_cs
elif string.strcmp(seg_buf, "t.CPtr") == 0 or string.strcmp(seg_buf, "CPtr") == 0: has_cptr = 1
elif string.strcmp(seg_buf, "t.CPtr") == 0 or string.strcmp(seg_buf, "CPtr") == 0: has_cptr = 1
elif string.strcmp(seg_buf, "t.CRef") == 0 or string.strcmp(seg_buf, "CRef") == 0: has_cref = 1
elif string.strcmp(seg_buf, "t.CTempRef") == 0 or string.strcmp(seg_buf, "CTempRef") == 0: has_cref = 1
elif string.strcmp(seg_buf, "void") == 0 or string.strcmp(seg_buf, "CVoid") == 0 or string.strcmp(seg_buf, "void") == 0:
# Bare void is an alias of t.CVoid and must be handled the same, else the
# else branch sets first_td and produces the illegal Ptr(Void) (void* = i8*).
@@ -1274,7 +1312,7 @@ def _resolve_vpi_ret_annot_str(pool: memhub.MemBuddy*, ret_annot: str, i32_ty: m
stdlib.free(seg_buf)
pos += 1 # skip '|'
if has_cptr != 0:
if has_cptr != 0 or has_cref != 0:
if has_cvoid != 0: return i8_ptr_ty
if first_ty is not None:
# The result itself is void (e.g. an opaque typedef resolving to void): CPtr merge
@@ -132,6 +132,8 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str,
if ret_a == 0:
# Container use detection: inject _list/_dict deps when an App file uses list/dict (bare annotation/ctor)
tr._inject_auto_container_visibility(mb, tree)
# assert lowers to testcheck.check(...): inject the testcheck dep when used
tr._inject_auto_assert_import(mb, tree)
# Register the App file in the store (empty incdir) and fill deps; read by
# LookupIncludesDeps(app_sha1) when BFS expands its includes deps
if e_r.Sha1 is not None:
@@ -440,6 +442,8 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str,
# Inject containers on demand (append _list/_dict when includes use list/dict generics);
# inlined to break the _list/_dict cycle
tr_r2._inject_auto_container_visibility(mb, tree_r)
# assert lowers to testcheck.check(...): inject the testcheck dep when used
tr_r2._inject_auto_assert_import(mb, tree_r)
# Fill in-memory deps and write deps.txt (for dep-graph expansion and on-demand Phase B loading)
deps_r2: str = tr_r2._imported_modules