chore(comments): Test 仓注释英文化(R11)

把 81 个 .vp 文件的中文 # 注释与三引号文档串改写为简洁英文,每个连续注释块 <=2 行;运行时中文字符串字面量(testcheck.begin/print 等用户可见消息)保持原样。骨架比对 HEAD 与工作区 112 文件漂移 0,全量 77/77 顺序回归通过。
This commit is contained in:
TermiNexus committed 2026-10-05 22:43:38 +08:00
1 parent aa5a7e7250
commit ee6461be46
81 files changed
+1231 -1925

No files matched your search

+8 -16
View File
@@ -8,7 +8,7 @@ import argparse
import testcheck
# 全局 MBuddy 指针
# Global MBuddy pointer
_mbuddy: memhub.MemBuddy*
@@ -17,7 +17,7 @@ def main() -> int:
global _mbuddy
testcheck.begin("ArgparseTest: 命令行参数解析")
# 初始化内存管理器
# Initialize the memory manager
arena: bytes = stdlib.malloc(16 * 1024 * 1024)
if arena is None:
testcheck.fail("malloc arena failed")
@@ -26,8 +26,8 @@ def main() -> int:
_mbuddy = memhub.MemBuddy(arena, 16 * 1024 * 1024)
argparse._mbuddy = _mbuddy
# 构造模拟 argv: myprog --input test.txt -c 42 --verbose output.dat
argv_buf: bytes = _mbuddy.alloc(8 * 7) # 7 个指针
# Build a synthetic argv: myprog --input test.txt -c 42 --verbose output.dat
argv_buf: bytes = _mbuddy.alloc(8 * 7) # 7 pointers
argv: str* = (str*)(argv_buf)
# argv[0] = "myprog"
@@ -74,9 +74,7 @@ def main() -> int:
argc: INT = 7
# ============================================================
# Test 1: 基本解析 (--input, -c, --verbose, output)
# ============================================================
# Test 1: basic parsing (--input, -c, --verbose, output)
testcheck.section("Test 1: 基本解析")
parser = argparse.ArgumentParser("myprog", "A test program for argparse", pool=_mbuddy)
parser.add_argument("--input", "-i", argparse.STRING, 0, None, True, argparse.STORE, "input file path")
@@ -99,9 +97,7 @@ def main() -> int:
else:
testcheck.fail("parse_args returned NULL")
# ============================================================
# Test 2: --name=value 语法
# ============================================================
# Test 2: --name=value syntax
testcheck.section("Test 2: --name=value 语法")
argv2_buf: bytes = _mbuddy.alloc(8 * 3)
@@ -134,9 +130,7 @@ def main() -> int:
else:
testcheck.fail("parse_args returned NULL")
# ============================================================
# Test 3: -v COUNT 计数动作
# ============================================================
# Test 3: -v COUNT counting action
testcheck.section("Test 3: COUNT 计数动作")
argv3_buf: bytes = _mbuddy.alloc(8 * 4)
@@ -177,9 +171,7 @@ def main() -> int:
else:
testcheck.fail("parse_args returned NULL")
# ============================================================
# Test 4: 关键字参数调用 add_argument
# ============================================================
# Test 4: keyword arguments to add_argument
testcheck.section("Test 4: 关键字参数")
parser3 = argparse.ArgumentParser("myprog", "Keyword arg test", pool=_mbuddy)
+20 -28
View File
@@ -10,16 +10,16 @@ import ast
import w32.win32console
# MBuddy arena 大小:1MB
# MBuddy arena size: 1MB
define ARENA_SIZE = 1048576
# mpool 内存大小:512KB
# mpool memory size: 512KB
define POOL_SIZE = 524288
# dump 缓冲区大小:256KB
# dump buffer size: 256KB
define DUMP_SIZE = 262144
def classify_list(lst: list[ast.AST*]*, depth: int):
"""递归遍历 list[AST | t.CPtr] 容器,逐元素分类(orelse/args/comparators 等)"""
"""Recursively walk a list[AST | t.CPtr] container, classify each element."""
if lst is None:
return
n: sizet = lst.__len__()
@@ -28,13 +28,8 @@ def classify_list(lst: list[ast.AST*]*, depth: int):
def classify_print(node: ast.AST*, depth: int):
"""递归遍历 parse 树,用 isinstance 运行时判定每个节点的类别并打印。
依赖 TPV isinstance 的 vtable 子类集合比较:
- isinstance(node, ast.Stmt) → 语句节点(Assign/If/For/While/...)
- isinstance(node, ast.ExprNode) → 表达式节点(Name/Constant/BinOp/...)
- 两者皆非 → 其他(Module/Expression/...)
验证运行时(非编译期静态)正确区分 Stmt 与 ExprNode。
"""Recursively walk the parse tree and print each node's category at runtime
via TPV isinstance vtable subclass-set comparison (Stmt vs ExprNode vs other).
"""
if node is None:
return
@@ -46,9 +41,8 @@ def classify_print(node: ast.AST*, depth: int):
printf("EXPR %s\n", node.type_name())
else:
printf("OTHER %s\n", node.type_name())
# 按 kind 遍历语句持有的表达式字段(语句 body 块均在 children)。
# 属性访问前先 cast 成具体节点类:node 静态类型是 ast.AST,
# 直接访问 node.value 会在 AST 基类字段表 fast-fail(按需过滤原则)。
# Walk statement expression fields by kind (bodies live in children); cast to
# the concrete class first, since ast.AST base-class field access fast-fails.
k: int = node.kind()
if k == ast.ASTKind.Assign:
asg: ast.Assign* = (ast.Assign*)(node)
@@ -92,7 +86,7 @@ def classify_print(node: ast.AST*, depth: int):
classify_list(call_nd.args, depth + 1)
else:
pass
# children(语句 body 块)
# children (statement bodies)
if node.children is not None:
n: sizet = node.children.__len__()
for i in range(n):
@@ -105,7 +99,7 @@ def main() -> CInt | CExport:
printf("AST Comprehensive Test Start\n")
# 初始化全局 MBuddy 内存分配器
# Initialize the global MBuddy allocator
arena: bytes = stdlib.malloc(ARENA_SIZE)
if arena == None:
printf("FAIL: arena alloc failed\n")
@@ -118,7 +112,7 @@ def main() -> CInt | CExport:
sys._mbuddy = mbuddy_obj
ast._mbuddy = mbuddy_obj
# 为 ast 解析器创建 mpool
# Create an mpool for the ast parser
pool_mem: bytes = stdlib.malloc(POOL_SIZE)
if pool_mem == None:
printf("FAIL: malloc for pool failed\n")
@@ -128,14 +122,14 @@ def main() -> CInt | CExport:
printf("FAIL: memhub.MemPool init failed\n")
return 1
# dump 缓冲区(独立分配)
# dump buffer (separately allocated)
dump_mem: bytes = stdlib.malloc(DUMP_SIZE)
if dump_mem == None:
printf("FAIL: malloc for dump failed\n")
return 1
dump_buf: char* = char(dump_mem, t.CPtr)
# 综合测试源码:覆盖 CPython 主要语法
# Comprehensive test source covering main CPython syntax
src: str = """x = 1
y = 2
z = x + y
@@ -165,7 +159,7 @@ class Point:
printf("Parsing comprehensive source...\n")
# 解析
# Parse
ast._init_tables(pool)
lx_dbg: t.CPtr = ast.new_lexer(pool)
if lx_dbg == None:
@@ -195,19 +189,17 @@ class Point:
printf("ast.dump returned, now printing buffer...\n")
printf("=== AST DUMP ===\n%s\n=== END ===\n", dump_buf)
# ============================================================
# Stmt/Expr 运行时区分测试(isinstance vtable 子类集合比较)
# ============================================================
# ===== Stmt/Expr runtime distinction test (isinstance vtable compare) =====
printf("=== STMT/EXPR RUNTIME DISTINGUISH TEST ===\n")
classify_print(tree, 0)
# 断言 1: Module 既非 Stmt 亦非 ExprNode(顶层容器)
# Assert 1: Module is neither Stmt nor ExprNode (top-level container)
if isinstance(tree, ast.Stmt) != 0 or isinstance(tree, ast.ExprNode) != 0:
printf("FAIL: Module misclassified as Stmt/ExprNode\n")
else:
printf("PASS: Module is neither Stmt nor ExprNode\n")
# 断言 2: 顶层 body 每条语句均为 Stmt
# Assert 2: every top-level body statement is a Stmt
top_ok: int = 1
top_n: sizet = tree.children.__len__()
for i2 in range(top_n):
@@ -218,21 +210,21 @@ class Point:
if top_ok != 0:
printf("PASS: all %lld top-level nodes are Stmt\n", top_n)
# 断言 3: Assign 是 Stmt 且不是 ExprNode
# Assert 3: Assign is Stmt, not ExprNode
first_assign: ast.Assign* = (ast.Assign*)(tree.children.get(0))
if isinstance(first_assign, ast.Stmt) != 0 and isinstance(first_assign, ast.ExprNode) == 0:
printf("PASS: Assign is Stmt, not ExprNode\n")
else:
printf("FAIL: Assign classification wrong\n")
# 断言 4: Assign.value(表达式)是 ExprNode 且不是 Stmt
# Assert 4: Assign.value (an expression) is ExprNode, not Stmt
if isinstance(first_assign.value, ast.ExprNode) != 0 \
and isinstance(first_assign.value, ast.Stmt) == 0:
printf("PASS: Assign.value is ExprNode (%s)\n", first_assign.value.type_name())
else:
printf("FAIL: Assign.value not ExprNode\n")
# 断言 5: 表达式语句 Expr(如 print(x))属于 Stmt(Statement 语义)
# Assert 5: expression statement Expr (e.g. print(x)) is a Stmt
if top_n >= 15:
if_node: ast.If* = (ast.If*)(tree.children.get(14))
if if_node.children is not None and if_node.children.__len__() > 0:
+2 -3
View File
@@ -10,9 +10,8 @@ def main() -> CInt | CExport:
w32.win32console.SetConsoleCP(65001)
w32.win32console.SetConsoleOutputCP(65001)
# memhub 的 [MEMDBG] 悬空/重复 free 检测默认开启(_memdbg_enable=1)。
# BuddyTest 含"故意双重 free,期望静默拒绝且状态不损坏"的负向用例,
# 若保持开启会在第二次 free 处终止进程 → 在此关闭 debug 模式。
# BuddyTest has a negative case that deliberately double-frees. With memhub's
# [MEMDBG] checks on (_memdbg_enable=1) the second free aborts, so disable it.
memhub._memdbg_enable = 0
return mbuddytest.mbuddy_main()
+73 -74
View File
@@ -11,7 +11,7 @@ import w32.win32sync
import w32.win32base
# 线程函数: 在共享 MBuddy 上执行 alloc/free (测试 spinlock 线程安全)
# Thread body: alloc/free on a shared MBuddy to exercise the spinlock
def _thread_alloc_free(param: t.CPtr) -> uint32:
bd: memhub.MemBuddy* = (memhub.MemBuddy*)(param)
i: CInt
@@ -29,7 +29,7 @@ def mbuddy_main() -> CInt:
testcheck.begin("BuddyTest: 伙伴系统内存分配器测试")
# === 基础 alloc/free 测试 ===
# === Basic alloc/free ===
testcheck.section("基础 alloc/free")
arena: bytes = stdlib.malloc(65536)
bd: memhub.MemBuddy | CPtr = memhub.MemBuddy(arena, 65536)
@@ -43,7 +43,7 @@ def mbuddy_main() -> CInt:
testcheck.check(p1 != None and p2 != None and p3 != None,
"3 allocs OK", "alloc FAILED")
# 写入数据验证指针可用
# Write data to verify the returned pointer is usable
p_c: CUInt8T | CPtr = CPtr(p1)
p_c[0] = CUInt8T(0xAB)
p_c[1] = CUInt8T(0xCD)
@@ -57,19 +57,19 @@ def mbuddy_main() -> CInt:
bd.free(p3)
testcheck.ok("3 frees OK")
# 释放后验证合并: free_count 应回到初始分解块数 (10)
# 4096-264 内非 2 的幂: 65536-264=65272 二进制分解为 10 个 2 的幂块
# After free, coalescing must restore the initial 10 free blocks
# (65536 - 264 = 65272 decomposes into 10 power-of-two blocks)
testcheck.check(bd.free_count() == 10,
"coalesce: free_count=10 OK", "coalesce: free_count != 10")
# 合并后应能分配大块
# Coalesced space must allow a large alloc again
big: bytes = bd.alloc(16000)
testcheck.check(big != None, "big alloc OK", "big alloc FAILED")
bd.free(big)
stdlib.free(arena)
# === calloc 测试 (验证清零) ===
# === calloc (verify zeroing) ===
testcheck.section("calloc 清零")
arena2: bytes = stdlib.malloc(4096)
viperlib.snprintf(buf, 256, "arena2 = %p", arena2)
@@ -103,7 +103,7 @@ def mbuddy_main() -> CInt:
stdlib.free(arena2)
# === realloc 扩展测试 ===
# === realloc grow ===
testcheck.section("realloc 扩展")
arena3: bytes = stdlib.malloc(4096)
bd3: memhub.MemBuddy | CPtr = memhub.MemBuddy(arena3, 4096)
@@ -130,7 +130,7 @@ def mbuddy_main() -> CInt:
stdlib.free(arena3)
# === 原地收缩测试 (验证无泄漏) ===
# === in-place shrink (verify no leak) ===
testcheck.section("原地收缩 (realloc shrink)")
arena_shrink: bytes = stdlib.malloc(4096)
bds: memhub.MemBuddy | CPtr = memhub.MemBuddy(arena_shrink, 4096)
@@ -139,15 +139,15 @@ def mbuddy_main() -> CInt:
testcheck.check(sp != None, "alloc 256 OK", "alloc 256 FAILED")
fc_before: CSizeT = bds.free_count()
# realloc 到更小尺寸: 256+8=264 -> order 4 (512); 32+8=40 -> order 1 (64)
# new_order(1) <= old_order(4), 应原地返回同一指针
# Shrink 256 -> 32: order 4 (264) to order 1 (40); since new order <= old,
# realloc must return the same pointer in place
sp2: bytes = bds.realloc(sp, 32)
fc_after: CSizeT = bds.free_count()
testcheck.check(sp2 == sp, "shrink same ptr OK", "shrink ptr changed")
testcheck.check(fc_after == fc_before, "shrink no leak OK", "shrink LEAKED blocks")
# 验证数据仍可读写
# Data must remain readable/writable after shrink
sp_c: CUInt8T | CPtr = CPtr(sp2)
sp_c[0] = CUInt8T(0x42)
testcheck.check(sp_c[0] == CUInt8T(0x42), "shrink data OK", "shrink data FAILED")
@@ -157,32 +157,32 @@ def mbuddy_main() -> CInt:
stdlib.free(arena_shrink)
# === 边界情况测试 ===
# === Edge cases ===
testcheck.section("边界情况")
arena4: bytes = stdlib.malloc(4096)
bd4: memhub.MemBuddy | CPtr = memhub.MemBuddy(arena4, 4096)
# alloc(0) 应返回 None
# alloc(0) must return None
z: bytes = bd4.alloc(0)
testcheck.check(z == None, "alloc(0)=None OK", "alloc(0) should be None")
# free(None) 应安全
# free(None) must be safe
bd4.free(None)
testcheck.ok("free(None) safe")
# realloc(None, size) 等价于 alloc
# realloc(None, size) behaves like alloc
rn: bytes = bd4.realloc(None, 32)
testcheck.check(rn != None, "realloc(None)=alloc OK", "realloc(None) FAILED")
bd4.free(rn)
# realloc(ptr, 0) 等价于 free
# realloc(ptr, 0) behaves like free
rz: bytes = bd4.alloc(32)
rz2: bytes = bd4.realloc(rz, 0)
testcheck.check(rz2 == None, "realloc(ptr,0)=free OK", "realloc(ptr,0) should be None")
stdlib.free(arena4)
# === 非法指针防护测试 ===
# === Illegal pointer defense ===
testcheck.section("非法指针防护")
arena5: bytes = stdlib.malloc(4096)
bd5: memhub.MemBuddy | CPtr = memhub.MemBuddy(arena5, 4096)
@@ -190,7 +190,7 @@ def mbuddy_main() -> CInt:
valid: bytes = bd5.alloc(32)
testcheck.check(valid != None, "alloc for illegal test OK", "alloc FAILED")
# 1. free 随机地址 (地址 1)
# 1. free a random address (address 1)
bd5.free(t.CPtr(uint64(1)))
testcheck.ok("free(addr=1) ignored")
@@ -198,39 +198,39 @@ def mbuddy_main() -> CInt:
bd5.free(None)
testcheck.ok("free(NULL) ignored")
# 3. free 越界指针 (arena 之前)
# 3. free an out-of-range pointer (before arena)
bd5.free(t.CPtr(uint64(arena5)))
testcheck.ok("free(before arena) ignored")
# 4. free 越界指针 (arena 之后)
# 4. free an out-of-range pointer (after arena)
bd5.free(t.CPtr(uint64(arena5) + 99999))
testcheck.ok("free(after arena) ignored")
# 5. free 未对齐指针 (arena + 1, 在 mem 区域内但不对齐)
# 5. free a misaligned pointer (inside mem but not aligned)
bd5.free(t.CPtr(uint64(bd5.base) + 1))
testcheck.ok("free(misaligned) ignored")
# 6. 验证合法 free 仍正常工作 (释放后应能再次分配)
# 6. a valid free must still work (block reusable after)
bd5.free(valid)
retry5: bytes = bd5.alloc(32)
testcheck.check(retry5 != None, "valid free still works OK", "valid free BROKEN")
if retry5 != None:
bd5.free(retry5)
# 7. realloc 非法指针应返回 None
# 7. realloc on an illegal pointer must return None
r_illegal: bytes = bd5.realloc(t.CPtr(1), 64)
testcheck.check(r_illegal == None, "realloc(illegal)=None OK", "realloc(illegal) should be None")
stdlib.free(arena5)
# === OOM 内存耗尽测试 ===
# === OOM exhaustion ===
testcheck.section("OOM 内存耗尽")
arena6: bytes = stdlib.malloc(4096)
bd6: memhub.MemBuddy | CPtr = memhub.MemBuddy(arena6, 4096)
# 持续分配直到失败
# Allocate until failure
alloc_count: CInt = 0
ptrs_arr: bytes = stdlib.malloc(8 * 256) # 存储指针的数组
ptrs_arr: bytes = stdlib.malloc(8 * 256) # Pointer storage array
ptrs: CUInt64T | CPtr = CPtr(ptrs_arr)
while alloc_count < 256:
@@ -244,11 +244,11 @@ def mbuddy_main() -> CInt:
testcheck.info(buf)
testcheck.check(alloc_count > 0, "OOM: got some allocs OK", "OOM: no allocs at all")
# 尝试再分配应失败
# Another alloc must now fail
oom_p: bytes = bd6.alloc(32)
testcheck.check(oom_p == None, "OOM: alloc fails OK", "OOM: alloc should fail")
# 释放一个块后应能再次分配
# After freeing one block, allocation must succeed again
if alloc_count > 0:
first_ptr: bytes = t.CPtr(ptrs[0])
bd6.free(first_ptr)
@@ -257,51 +257,51 @@ def mbuddy_main() -> CInt:
if retry != None:
bd6.free(retry)
# 释放所有块
# Free all blocks
for idx in range(1, alloc_count):
cur_p: bytes = t.CPtr(ptrs[idx])
bd6.free(cur_p)
# 全部释放后应能合并回初始分解块数 (6)
# Full free must coalesce back to the initial 6 blocks
testcheck.check(bd6.free_count() == 6,
"OOM: full coalesce OK", "OOM: free_count != 6 after full free")
stdlib.free(ptrs_arr)
stdlib.free(arena6)
# === 空闲链表状态测试 ===
# === Free-list state ===
testcheck.section("空闲链表状态")
arena7: bytes = stdlib.malloc(4096)
bd7: memhub.MemBuddy | CPtr = memhub.MemBuddy(arena7, 4096)
# 初始: 非 2 的幂 arena (4096-264=3832) 二进制分解为 6 个块
# Initial: non-power-of-two arena (4096 - 264 = 3832) splits into 6 blocks
testcheck.check(bd7.free_count() == 6, "init: 6 free blocks OK", "init: free_count != 6")
# 分配后: 空闲块数应增加 (分裂产生多个小块)
# After alloc: free count grows because a block is split
a1: bytes = bd7.alloc(32)
fc1: CSizeT = bd7.free_count()
viperlib.snprintf(buf, 256, "after alloc(32): free_count=%lu", fc1)
testcheck.info(buf)
testcheck.check(fc1 > 1, "after alloc: split OK", "after alloc: no split")
# 再分配
# Second alloc
a2: bytes = bd7.alloc(32)
fc2: CSizeT = bd7.free_count()
testcheck.check(fc2 >= 1, "after 2nd alloc: free >= 1 OK", "after 2nd alloc: free < 1")
# 释放 a1: 空闲块数应增加
# Free a1: free count must increase
bd7.free(a1)
fc3: CSizeT = bd7.free_count()
testcheck.check(fc3 > fc2, "after free a1: free increased OK", "after free a1: free not increased")
# 释放 a2: 应合并, 空闲块数回到初始 6 块
# Free a2: coalescing must restore the initial 6 blocks
bd7.free(a2)
testcheck.check(bd7.free_count() == 6,
"after free all: coalesced to 6 OK", "after free all: free_count != 6")
stdlib.free(arena7)
# === with 上下文管理器测试 ===
# === with context manager ===
testcheck.section("with 上下文管理器")
arena8: bytes = stdlib.malloc(4096)
with memhub.MemBuddy(arena8, 4096) as wbd:
@@ -309,16 +309,16 @@ def mbuddy_main() -> CInt:
wp2: bytes = wbd.alloc(64)
testcheck.check(wp1 != None and wp2 != None,
"with: allocs OK", "with: allocs FAILED")
# 退出 with 块时 __exit__ 自动 reset
# Leaving the with block triggers __exit__ auto-reset
# 退出后重新进入,验证 reset 生效
# Re-enter after exit to verify the reset took effect
with memhub.MemBuddy(arena8, 4096) as wbd2:
wp3: bytes = wbd2.alloc(1024)
testcheck.check(wp3 != None, "with: reset+realloc OK", "with: reset+realloc FAILED")
stdlib.free(arena8)
# === 双重 free 检测测试 ===
# === Double-free detection ===
testcheck.section("双重 free 检测")
arena_df: bytes = stdlib.malloc(4096)
bd_df: memhub.MemBuddy | CPtr = memhub.MemBuddy(arena_df, 4096)
@@ -326,17 +326,17 @@ def mbuddy_main() -> CInt:
df: bytes = bd_df.alloc(64)
testcheck.check(df != None, "df: alloc OK", "df: alloc FAILED")
# 第一次 free
# First free
bd_df.free(df)
fc_df1: CSizeT = bd_df.free_count()
testcheck.ok("first free OK")
# 第二次 free (双重 free) — 应被静默拒绝
# Second free (double free): must be silently rejected
bd_df.free(df)
fc_df2: CSizeT = bd_df.free_count()
testcheck.check(fc_df2 == fc_df1, "double free rejected OK", "double free CORRUPTED state")
# 验证分配器仍正常工作
# Allocator must still be functional
df2: bytes = bd_df.alloc(64)
testcheck.check(df2 != None, "df: alloc after double-free OK", "df: alloc after double-free FAILED")
if df2 != None:
@@ -344,36 +344,36 @@ def mbuddy_main() -> CInt:
stdlib.free(arena_df)
# === 自检功能测试 ===
# === Self-check ===
testcheck.section("自检功能")
arena_sc: bytes = stdlib.malloc(4096)
bd_sc: memhub.MemBuddy | CPtr = memhub.MemBuddy(arena_sc, 4096)
# 初始状态自检
# Self-check on initial state
testcheck.check(bd_sc.self_check() == 0, "self_check init OK", "self_check init FAILED")
# 分配后自检
# Self-check after alloc
sc_p1: bytes = bd_sc.alloc(32)
sc_p2: bytes = bd_sc.alloc(128)
testcheck.check(bd_sc.self_check() == 0, "self_check after alloc OK", "self_check after alloc FAILED")
# 部分释放后自检
# Self-check after partial free
bd_sc.free(sc_p1)
testcheck.check(bd_sc.self_check() == 0, "self_check after partial free OK", "self_check after partial free FAILED")
# 全部释放后自检 (应合并回单个大块)
# Self-check after full free (should coalesce to one block)
bd_sc.free(sc_p2)
testcheck.check(bd_sc.self_check() == 0, "self_check after full free OK", "self_check after full free FAILED")
# 双重 free 后自检 (验证状态未损坏)
# Self-check after double free (state must be intact)
sc_p3: bytes = bd_sc.alloc(64)
bd_sc.free(sc_p3)
bd_sc.free(sc_p3) # 双重 free,应被拒绝
bd_sc.free(sc_p3) # Double free, must be rejected
testcheck.check(bd_sc.self_check() == 0, "self_check after double-free OK", "self_check after double-free CORRUPTED")
stdlib.free(arena_sc)
# === 并发多线程测试 (spinlock) ===
# === Concurrent threads (spinlock) ===
testcheck.section("并发多线程 (spinlock)")
arena_mt: bytes = stdlib.malloc(65536)
bd_mt: memhub.MemBuddy | CPtr = memhub.MemBuddy(arena_mt, 65536)
@@ -383,19 +383,19 @@ def mbuddy_main() -> CInt:
handles: CUInt64T | CPtr = CPtr(handles_arr)
tid: CUInt32T = 0
# 创建 4 个线程并发 alloc/free
# Spawn 4 threads doing concurrent alloc/free
t_idx: CInt
for t_idx in range(NUM_THREADS):
h: bytes = w32.win32process.CreateThread(None, 0, _thread_alloc_free, t.CPtr(bd_mt), 0, &tid)
handles[t_idx] = CUInt64T(h)
# 等待所有线程完成
# Wait for all threads to finish
for t_idx in range(NUM_THREADS):
h: bytes = t.CPtr(handles[t_idx])
w32.win32sync.WaitForSingleObject(h, w32.win32base.INFINITE)
w32.win32base.CloseHandle(h)
# 验证分配器状态: 自检通过,所有块已合并
# Verify allocator state: self-check passes and all blocks coalesced
testcheck.check(bd_mt.self_check() == 0, "mt: self_check OK", "mt: self_check FAILED")
testcheck.check(bd_mt.free_count() == 10, "mt: free_count=10 OK", "mt: free_count != 10 (leaked)")
@@ -405,18 +405,18 @@ def mbuddy_main() -> CInt:
stdlib.free(handles_arr)
stdlib.free(arena_mt)
# === 极端边界测试 ===
# === Extreme boundaries ===
testcheck.section("极端边界")
# 1. 分配尺寸恰巧是块边界
# 1. Alloc size exactly at a block boundary
arena_ex: bytes = stdlib.malloc(4096)
bd_ex: memhub.MemBuddy | CPtr = memhub.MemBuddy(arena_ex, 4096)
# 24 + 16 = 40 > 32(8 头 + 8 哨兵),需要 order 1 (64 字节)
# 24 + 16 = 40 > 32 (8 header + 8 sentinel), needs order 1 (64 bytes)
exact_fit: bytes = bd_ex.alloc(24)
testcheck.check(exact_fit != None, "exact fit order 0 OK", "exact fit order 0 FAILED")
# 25 + 16 = 41 > 32, 需要 order 1 (64 字节)
# 25 + 16 = 41 > 32, needs order 1 (64 bytes)
over_fit: bytes = bd_ex.alloc(25)
testcheck.check(over_fit != None, "over by 1 byte OK", "over by 1 byte FAILED")
@@ -424,14 +424,13 @@ def mbuddy_main() -> CInt:
bd_ex.free(over_fit)
testcheck.check(bd_ex.free_count() == 6, "boundary: coalesce OK", "boundary: coalesce FAILED")
# 2. 单次分配接近最大块上限(order6=2048,非 2 的幂 arena 的最大分解块)
# 可用数据区 = 2048 - 8(头) - 8(哨兵),alloc(max_usable) 的 needed 恰好
# = 2048,正好填满 order6 最大块
# 2. Alloc near the largest block limit (order6 = 2048): usable = 2048 - 16,
# so alloc(max_usable) exactly fills one order6 block
max_usable: CSizeT = 2048 - 16
viperlib.snprintf(buf, 256, "mem_size=%lu, max_block=2048, max_usable=%lu", bd_ex.mem_size, max_usable)
testcheck.info(buf)
# 恰好用完 order6 块(其余 5 个分解块空闲)
# Exactly consumes the order6 block (5 other blocks stay free)
exact_max: bytes = bd_ex.alloc(max_usable)
testcheck.check(exact_max != None, "exact max alloc OK", "exact max alloc FAILED")
testcheck.check(bd_ex.free_count() == 5, "max alloc: 5 free blocks left OK", "max alloc: free_count != 5")
@@ -439,12 +438,12 @@ def mbuddy_main() -> CInt:
bd_ex.free(exact_max)
testcheck.check(bd_ex.free_count() == 6, "max free: coalesce OK", "max free: coalesce FAILED")
# 再次分配同样大小 — 验证合并后可再次使用
# Alloc the same size again to verify coalesced space is reusable
exact_max2: bytes = bd_ex.alloc(max_usable)
testcheck.check(exact_max2 != None, "exact max re-alloc OK", "exact max re-alloc FAILED")
bd_ex.free(exact_max2)
# 3. 分配超过 arena 上限 — 应失败
# 3. Alloc beyond the arena limit must fail
over_max: bytes = bd_ex.alloc(bd_ex.mem_size)
testcheck.check(over_max == None, "over max: fails OK", "over max: should fail")
@@ -453,7 +452,7 @@ def mbuddy_main() -> CInt:
stdlib.free(arena_ex)
# 4. Arena 太小 (仅够 free_lists 开销, 264 字节)
# 4. Arena too small (only fits the 264-byte free-list overhead)
arena_tiny: bytes = stdlib.malloc(264)
bd_tiny: memhub.MemBuddy | CPtr = memhub.MemBuddy(arena_tiny, 264)
testcheck.check(bd_tiny.stats() == 0, "tiny arena: stats=0 OK", "tiny arena: stats != 0")
@@ -461,12 +460,12 @@ def mbuddy_main() -> CInt:
testcheck.check(tiny_p == None, "tiny arena: alloc fails OK", "tiny arena: should fail")
stdlib.free(arena_tiny)
# 5. Arena 刚好够一个最小块 (264 + 32 = 296)
# 5. Arena fits exactly one minimal block (264 + 32 = 296)
arena_one: bytes = stdlib.malloc(296)
bd_one: memhub.MemBuddy | CPtr = memhub.MemBuddy(arena_one, 296)
testcheck.check(bd_one.stats() == 32, "one block: stats=32 OK", "one block: stats != 32")
# 最小块 32 字节 = 数据 16 + 头 8 + 哨兵 8,alloc(16) 恰好填满
# Minimal block 32 = data 16 + header 8 + sentinel 8; alloc(16) fills it
one_p: bytes = bd_one.alloc(16)
testcheck.check(one_p != None, "one block: alloc OK", "one block: alloc FAILED")
@@ -477,20 +476,20 @@ def mbuddy_main() -> CInt:
testcheck.check(bd_one.free_count() == 1, "one block: free OK", "one block: free FAILED")
stdlib.free(arena_one)
# 6. 2 的幂 arena vs 非 2 的幂 arena
# 6. Power-of-two vs non-power-of-two arena
arena_pow2: bytes = stdlib.malloc(512)
bd_pow2: memhub.MemBuddy | CPtr = memhub.MemBuddy(arena_pow2, 512)
# 512 - 264 = 248, 二进制分解 = 128+64+32 = 224 (尾 24 字节碎片不入池)
# 512 - 264 = 248, decomposes to 128 + 64 + 32 = 224 (24-byte tail dropped)
testcheck.check(bd_pow2.stats() == 224, "pow2 arena: stats=224 OK", "pow2 arena: stats != 224")
stdlib.free(arena_pow2)
arena_non2: bytes = stdlib.malloc(500)
bd_non2: memhub.MemBuddy | CPtr = memhub.MemBuddy(arena_non2, 500)
# 500 - 264 = 236, 二进制分解 = 128+64+32 = 224 (尾 12 字节碎片不入池)
# 500 - 264 = 236, decomposes to 128 + 64 + 32 = 224 (12-byte tail dropped)
testcheck.check(bd_non2.stats() == 224, "non-pow2 arena: stats=224 OK", "non-pow2 arena: stats != 224")
stdlib.free(arena_non2)
# 7. 压力测试: 反复 alloc/free 同一尺寸 1000 次
# 7. Stress: 1000 alloc/free cycles of the same size
arena_stress: bytes = stdlib.malloc(4096)
bd_stress: memhub.MemBuddy | CPtr = memhub.MemBuddy(arena_stress, 4096)
@@ -506,7 +505,7 @@ def mbuddy_main() -> CInt:
testcheck.check(bd_stress.free_count() == 6, "stress: free_count=6 OK", "stress: leaked")
stdlib.free(arena_stress)
# 8. 分配全部最小块然后全部释放
# 8. Allocate all minimal blocks, then free them all
arena_fill: bytes = stdlib.malloc(4096)
bd_fill: memhub.MemBuddy | CPtr = memhub.MemBuddy(arena_fill, 4096)
@@ -527,7 +526,7 @@ def mbuddy_main() -> CInt:
testcheck.check(fill_count > 0, "fill: got blocks OK", "fill: no blocks")
testcheck.check(bd_fill.self_check() == 0, "fill: self_check OK", "fill: self_check FAILED")
# 全部释放
# Free all
fi: CInt
for fi in range(fill_count):
fp2: bytes = t.CPtr(fill_ptrs[fi])
+12 -12
View File
@@ -6,7 +6,7 @@ import testcheck
# ============================================================
# 测试 1:@property getter
# Test 1: @property getter
# ============================================================
class Rect:
width: int
@@ -39,7 +39,7 @@ def test_property_getter():
# ============================================================
# 测试 2:@property.setter
# Test 2: @property.setter
# ============================================================
class Temperature:
_celsius: double
@@ -73,7 +73,7 @@ def test_property_setter():
# ============================================================
# 测试 3:@property.getter(重新定义 getter)
# Test 3: @property.getter redefinition
# ============================================================
class Counter:
_count: int
@@ -102,7 +102,7 @@ def test_property_getter_redef():
# ============================================================
# 测试 4:@property.deleter
# Test 4: @property.deleter
# ============================================================
class Config:
_value: int
@@ -143,7 +143,7 @@ def test_property_deleter():
# ============================================================
# 测试 5:@staticmethod
# Test 5: @staticmethod
# ============================================================
class MathUtils:
@staticmethod
@@ -157,13 +157,13 @@ class MathUtils:
def test_staticmethod():
testcheck.section("@staticmethod")
# 通过类名调用
# call via class name
testcheck.check(MathUtils.add(3, 4) == 7, "MathUtils.add(3,4)==7", "MathUtils.add(3,4) expect 7")
testcheck.check(MathUtils.max_val(5, 10) == 10, "MathUtils.max(5,10)==10", "MathUtils.max(5,10) expect 10")
# ============================================================
# 测试 6:@classmethod
# Test 6: @classmethod
# ============================================================
class Point:
x: double
@@ -190,7 +190,7 @@ class Point:
def test_classmethod():
testcheck.section("@classmethod")
# 通过类名调用
# call via class name
p1: Point = Point.origin()
testcheck.check(p1.x > -0.01 and p1.x < 0.01, "origin.x ~= 0", "origin.x expect ~0")
testcheck.check(p1.y > -0.01 and p1.y < 0.01, "origin.y ~= 0", "origin.y expect ~0")
@@ -203,7 +203,7 @@ def test_classmethod():
# ============================================================
# 测试 7:综合测试 — @property + @staticmethod + @classmethod
# Test 7: combined @property + @staticmethod + @classmethod
# ============================================================
class Circle:
_radius: double
@@ -237,14 +237,14 @@ class Circle:
def test_combined():
testcheck.section("Combined @property + @staticmethod + @classmethod")
# 先测试直接构造
# first test direct construction
cr0: Circle = Circle(1.0)
testcheck.check(cr0.radius > 0.99 and cr0.radius < 1.01, "direct radius ~= 1", "direct radius expect ~1")
testcheck.check(cr0.area > 3.14 and cr0.area < 3.15, "direct area ~= pi", "direct area expect ~pi")
cr0.radius = 2.0
testcheck.check(cr0.radius > 1.99 and cr0.radius < 2.01, "direct radius 2.0", "direct radius expect 2.0")
testcheck.check(cr0.area > 12.56 and cr0.area < 12.58, "direct area ~= 4pi", "direct area expect ~4pi")
# 测试 classmethod
# test classmethod
cr1: Circle = Circle.unit()
testcheck.check(cr1.radius > 0.99 and cr1.radius < 1.01, "unit radius ~= 1", "unit radius expect ~1")
testcheck.check(Circle.is_unit(1.0), "is_unit(1.0)", "is_unit(1.0) should be true")
@@ -252,7 +252,7 @@ def test_combined():
# ============================================================
# 主函数
# main
# ============================================================
def main() -> int | t.CExport:
testcheck.begin("Builtin Decorator Test")
+40 -110
View File
@@ -1,17 +1,13 @@
import t, c
# ============================================================
# PyObject — 所有 Python 对象的基类
# ============================================================
# --- PyObject: base class of all Python objects ---
class PyObject:
ob_refcnt: t.CLong
ob_type: t.CPtr
# ============================================================
# 引用计数
# ============================================================
# --- Reference counting ---
extern def Py_INCREF(op: PyObject*)
extern def Py_DECREF(op: PyObject*)
extern def Py_XINCREF(op: PyObject*)
@@ -19,9 +15,7 @@ extern def Py_XDECREF(op: PyObject*)
extern def Py_DecRef(op: PyObject*)
# ============================================================
# 解释器初始化/终止
# ============================================================
# --- Interpreter init/finalize ---
extern def Py_Initialize()
extern def Py_Finalize()
extern def Py_InitializeEx(initsigs: int)
@@ -29,9 +23,7 @@ extern def Py_FinalizeEx() -> int
extern def Py_IsInitialized() -> int
# ============================================================
# PyConfig
# ============================================================
# --- PyConfig ---
class PySTATUS:
func: const str
err_msg: const str
@@ -107,9 +99,7 @@ extern def Py_DecodeLocale(s: const str) -> str
extern def PyStatus_Exception(status: PySTATUS) -> int
# ============================================================
# 整数操作 (PyLong)
# ============================================================
# --- Integer ops (PyLong) ---
extern def PyLong_FromLong(v: int) -> PyObject*
extern def PyLong_FromUnsignedLong(v: t.CUnsignedLong) -> PyObject*
extern def PyLong_FromLongLong(v: t.CLong) -> PyObject*
@@ -126,17 +116,13 @@ extern def PyLong_AsSsize_t(obj: PyObject*) -> t.CPtrDiffT
extern def PyLong_AsSize_t(obj: PyObject*) -> sizet
# ============================================================
# 浮点数操作 (PyFloat)
# ============================================================
# --- Float ops (PyFloat) ---
extern def PyFloat_FromDouble(v: double) -> PyObject*
extern def PyFloat_AsDouble(obj: PyObject*) -> double
extern def PyFloat_FromString(s: PyObject*) -> PyObject*
# ============================================================
# 字符串操作 (PyUnicode / PyBytes)
# ============================================================
# --- String ops (PyUnicode / PyBytes) ---
extern def PyUnicode_FromString(u: const str) -> PyObject*
extern def PyUnicode_FromStringAndSize(u: const str, size: sizet) -> PyObject*
extern def PyUnicode_FromFormat(fmt: const str) -> PyObject*
@@ -161,9 +147,7 @@ extern def PyBytes_FromObject(o: PyObject*) -> PyObject*
extern def PyBytes_FromFormat(fmt: const str) -> PyObject*
# ============================================================
# 布尔 / None
# ============================================================
# --- Bool / None ---
extern def PyBool_FromLong(v: t.CLong) -> PyObject*
Py_True: PyObject | t.CPtr | t.State
@@ -171,9 +155,7 @@ Py_False: PyObject | t.CPtr | t.State
Py_None: PyObject | t.CPtr | t.State
# ============================================================
# 列表操作 (PyList)
# ============================================================
# --- List ops (PyList) ---
extern def PyList_New(len: sizet) -> PyObject*
extern def PyList_Size(lst: PyObject*) -> sizet
extern def PyList_GetItem(lst: PyObject*, idx: sizet) -> PyObject*
@@ -187,9 +169,7 @@ extern def PyList_Reverse(lst: PyObject*) -> int
extern def PyList_AsTuple(lst: PyObject*) -> PyObject*
# ============================================================
# 元组操作 (PyTuple)
# ============================================================
# --- Tuple ops (PyTuple) ---
extern def PyTuple_New(len: sizet) -> PyObject*
extern def PyTuple_Size(tup: PyObject*) -> sizet
extern def PyTuple_GetItem(tup: PyObject*, idx: sizet) -> PyObject*
@@ -198,9 +178,7 @@ extern def PyTuple_GetSlice(tup: PyObject*, lo: sizet, hi: sizet) -> PyObject*
extern def PyTuple_Pack(n: sizet) -> PyObject*
# ============================================================
# 字典操作 (PyDict)
# ============================================================
# --- Dict ops (PyDict) ---
extern def PyDict_New() -> PyObject*
extern def PyDict_GetItem(d: PyObject*, key: PyObject*) -> PyObject*
extern def PyDict_GetItemString(d: PyObject*, key: const str) -> PyObject*
@@ -220,9 +198,7 @@ extern def PyDict_Merge(d: PyObject*, other: PyObject*, override: int) -> int
extern def PyDict_Update(d: PyObject*, other: PyObject*) -> int
# ============================================================
# 对象通用操作
# ============================================================
# --- Object common ops ---
extern def PyObject_Str(obj: PyObject*) -> PyObject*
extern def PyObject_Repr(obj: PyObject*) -> PyObject*
extern def PyObject_Type(obj: PyObject*) -> PyObject*
@@ -254,9 +230,7 @@ extern def PyObject_GetIter(obj: PyObject*) -> PyObject*
extern def PyIter_Next(obj: PyObject*) -> PyObject*
# ============================================================
# 比较常量
# ============================================================
# --- Comparison constants ---
Py_LT: int | t.State
Py_LE: int | t.State
Py_EQ: int | t.State
@@ -265,9 +239,7 @@ Py_GT: int | t.State
Py_GE: int | t.State
# ============================================================
# 模块操作
# ============================================================
# --- Module ops ---
extern def PyImport_ImportModule(name: const str) -> PyObject*
extern def PyImport_Import(name: PyObject*) -> PyObject*
extern def PyImport_ImportModuleLevelObject(name: PyObject*, globs: PyObject*, locs: PyObject*, fromlist: PyObject*, level: int) -> PyObject*
@@ -277,9 +249,7 @@ extern def PyImport_GetModuleDict() -> PyObject*
extern def PyImport_ImportModuleEx(name: const str, globs: PyObject*, locs: PyObject*, fromlist: PyObject*) -> PyObject*
# ============================================================
# 模块创建
# ============================================================
# --- Module creation ---
class PyMethodDef:
ml_name: const str
ml_meth: t.CPtr
@@ -314,9 +284,7 @@ extern def PyModule_AddIntConstant(mod: PyObject*, name: const str, val: t.CLong
extern def PyModule_AddStringConstant(mod: PyObject*, name: const str, val: const str) -> int
# ============================================================
# GIL 管理
# ============================================================
# --- GIL management ---
extern def PyGILState_Ensure() -> int
extern def PyGILState_Release(state: int): pass
extern def PyEval_SaveThread() -> t.CPtr
@@ -329,9 +297,7 @@ extern def PyEval_ThreadsInitialized() -> int
extern def PyEval_InitThreads(): pass
# ============================================================
# 错误处理
# ============================================================
# --- Error handling ---
extern def PyErr_Occurred() -> PyObject*
extern def PyErr_Clear(): pass
extern def PyErr_Fetch(tp: PyObject**, val: PyObject**, tb: PyObject**): pass
@@ -346,9 +312,7 @@ extern def PyErr_ExceptionMatches(exc: PyObject*) -> int | t.State: pass
extern def PyErr_GivenExceptionMatches(given: PyObject*, exc: PyObject*) -> int | t.State: pass
# ============================================================
# 内置异常类型
# ============================================================
# --- Built-in exception types ---
PyExc_BaseException: PyObject | t.CPtr | t.State
PyExc_Exception: PyObject | t.CPtr | t.State
PyExc_TypeError: PyObject | t.CPtr | t.State
@@ -373,16 +337,12 @@ PyExc_IsADirectoryError: PyObject | t.CPtr | t.State
PyExc_NotADirectoryError: PyObject | t.CPtr | t.State
# ============================================================
# 内置函数
# ============================================================
# --- Built-in functions ---
extern def Py_BuildValue(fmt: const str) -> PyObject*
extern def Py_VaBuildValue(fmt: const str, va: t.CPtr) -> PyObject*
# ============================================================
# 类型检查
# ============================================================
# --- Type checks ---
extern def PyLong_Check(obj: PyObject*) -> int
extern def PyFloat_Check(obj: PyObject*) -> int
extern def PyUnicode_Check(obj: PyObject*) -> int
@@ -394,9 +354,7 @@ extern def PyBool_Check(obj: PyObject*) -> int
extern def PyNone_Check(obj: PyObject*) -> int
# ============================================================
# 内存管理
# ============================================================
# --- Memory management ---
extern def PyMem_Malloc(size: sizet) -> t.CPtr
extern def PyMem_Realloc(ptr: t.CPtr, size: sizet) -> t.CPtr
extern def PyMem_Free(ptr: t.CPtr)
@@ -409,18 +367,14 @@ extern def PyObject_Init(obj: PyObject*, tp: t.CPtr) -> PyObject*
extern def PyObject_InitVar(obj: PyObject*, tp: t.CPtr, size: sizet) -> PyObject*
# ============================================================
# 文件操作
# ============================================================
# --- File ops ---
extern def PyFile_FromString(filename: const str, mode: const str) -> PyObject*
extern def PyFile_AsFile(file: PyObject*) -> t.CPtr
extern def PyFile_WriteObject(obj: PyObject*, file: PyObject*, flags: int) -> int
extern def PyFile_WriteString(s: const str, file: PyObject*) -> int
# ============================================================
# 编译/执行
# ============================================================
# --- Compile/execute ---
extern def Py_CompileString(s: const str, filename: const str, start: int) -> PyObject*
extern def PyEval_EvalCode(code: PyObject*, globs: PyObject*, locs: PyObject*) -> PyObject*
extern def PyEval_EvalCodeEx(code: PyObject*, globs: PyObject*, locs: PyObject*, args: PyObject**, argc: int, kws: PyObject**, kwc: int, defs: PyObject**, defc: int, kwdefs: PyObject*, closure: PyObject*) -> PyObject*: pass
@@ -430,9 +384,7 @@ extern def PyEval_CallFunction(callable: PyObject*, fmt: const str) -> PyObject*
extern def PyEval_CallMethod(obj: PyObject*, method: const str, fmt: const str) -> PyObject*: pass
# ============================================================
# PyRun
# ============================================================
# --- PyRun ---
extern def PyRun_SimpleString(cmd: const str) -> int
extern def PyRun_SimpleFile(fp: t.CPtr, filename: const str) -> int
extern def PyRun_AnyFile(fp: t.CPtr, filename: const str) -> int
@@ -444,9 +396,7 @@ Py_file_input: int | t.State
Py_eval_input: int | t.State
# ============================================================
# Capsule
# ============================================================
# --- Capsule ---
extern def PyCapsule_New(ptr: t.CPtr, name: const str, dtor: t.CPtr) -> PyObject*
extern def PyCapsule_GetPointer(cap: PyObject*, name: const str) -> t.CPtr
extern def PyCapsule_GetName(cap: PyObject*) -> str
@@ -456,9 +406,7 @@ extern def PyCapsule_SetName(cap: PyObject*, name: const str) -> int
extern def PyCapsule_SetDestructor(cap: PyObject*, dtor: t.CPtr) -> int
# ============================================================
# 序列操作
# ============================================================
# --- Sequence ops ---
extern def PySequence_Check(obj: PyObject*) -> int
extern def PySequence_Size(obj: PyObject*) -> sizet
extern def PySequence_Length(obj: PyObject*) -> sizet
@@ -477,9 +425,7 @@ extern def PySequence_List(obj: PyObject*) -> PyObject*
extern def PySequence_Tuple(obj: PyObject*) -> PyObject*
# ============================================================
# 映射操作
# ============================================================
# --- Mapping ops ---
extern def PyMapping_Check(obj: PyObject*) -> int
extern def PyMapping_Size(obj: PyObject*) -> sizet
extern def PyMapping_Length(obj: PyObject*) -> sizet
@@ -492,9 +438,7 @@ extern def PyMapping_Values(obj: PyObject*) -> PyObject*
extern def PyMapping_Items(obj: PyObject*) -> PyObject*
# ============================================================
# 数字操作
# ============================================================
# --- Number ops ---
extern def PyNumber_Add(o1: PyObject*, o2: PyObject*) -> PyObject*
extern def PyNumber_Subtract(o1: PyObject*, o2: PyObject*) -> PyObject*
extern def PyNumber_Multiply(o1: PyObject*, o2: PyObject*) -> PyObject*
@@ -518,17 +462,13 @@ extern def PyNumber_Float(obj: PyObject*) -> PyObject*
extern def PyNumber_Check(obj: PyObject*) -> int
# ============================================================
# 弱引用
# ============================================================
# --- Weak references ---
extern def PyWeakref_NewRef(obj: PyObject*, cb: PyObject*) -> PyObject*
extern def PyWeakref_GetObject(ref: PyObject*) -> PyObject*
extern def PyWeakref_Check(obj: PyObject*) -> int
# ============================================================
# 属性描述符
# ============================================================
# --- Property descriptors ---
class PyGetSetDef:
name: const str
get: t.CPtr
@@ -544,9 +484,7 @@ class PyMemberDef:
doc: const str
# ============================================================
# sys 模块
# ============================================================
# --- sys module ---
extern def PySys_GetObject(name: const str) -> PyObject*
extern def PySys_SetObject(name: const str, val: PyObject*) -> int
extern def PySys_ResetWarnOptions(): pass
@@ -558,17 +496,13 @@ extern def PySys_FormatStdout(fmt: const str): pass
extern def PySys_FormatStderr(fmt: const str): pass
# ============================================================
# 内存视图
# ============================================================
# --- Memory view ---
extern def PyMemoryView_FromObject(obj: PyObject*) -> PyObject*
extern def PyMemoryView_GetContiguous(obj: PyObject*, btype: int, order: char) -> PyObject*
extern def PyMemoryView_Check(obj: PyObject*) -> int
# ============================================================
# set / frozenset
# ============================================================
# --- set / frozenset ---
extern def PySet_New(iterable: PyObject*) -> PyObject*
extern def PySet_Add(s: PyObject*, key: PyObject*) -> int
extern def PySet_Discard(s: PyObject*, key: PyObject*) -> int
@@ -580,9 +514,7 @@ extern def PyFrozenSet_New(iterable: PyObject*) -> PyObject*
extern def PyFrozenSet_Check(obj: PyObject*) -> int
# ============================================================
# slice
# ============================================================
# --- slice ---
extern def PySlice_New(start: PyObject*, stop: PyObject*, step: PyObject*) -> PyObject*
extern def PySlice_GetIndicesEx(sl: PyObject*, length: sizet, start: sizet*, stop: sizet*, step: sizet*, slicelen: sizet*) -> int
extern def PySlice_Unpack(sl: PyObject*, start: t.CPtrDiffT*, stop: t.CPtrDiffT*, step: t.CPtrDiffT*): pass
@@ -590,11 +522,9 @@ extern def PySlice_AdjustIndices(length: sizet, start: t.CPtrDiffT*, stop: t.CPt
extern def PySlice_Check(obj: PyObject*) -> int
# ============================================================
# 类型包装类 — 带运算符重载
# ============================================================
# --- Type wrapper classes: operator overloading ---
# --- PyLongObj: Python 整数包装 ---
# --- PyLongObj: Python integer wrapper ---
class PyLongObj:
ptr: PyObject*
@@ -637,7 +567,7 @@ class PyLongObj:
Py_DecRef(self.ptr)
# --- PyFloatObj: Python 浮点数包装 ---
# --- PyFloatObj: Python float wrapper ---
class PyFloatObj:
ptr: PyObject*
@@ -685,7 +615,7 @@ class PyFloatObj:
Py_DecRef(self.ptr)
# --- PyUnicodeObj: Python 字符串包装 ---
# --- PyUnicodeObj: Python string wrapper ---
class PyUnicodeObj:
ptr: PyObject*
@@ -716,7 +646,7 @@ class PyUnicodeObj:
Py_DecRef(self.ptr)
# --- PyListObj: Python 列表包装 ---
# --- PyListObj: Python list wrapper ---
class PyListObj:
ptr: PyObject*
@@ -745,7 +675,7 @@ class PyListObj:
Py_DecRef(self.ptr)
# --- PyDictObj: Python 字典包装 ---
# --- PyDictObj: Python dict wrapper ---
class PyDictObj:
ptr: PyObject*
+29 -29
View File
@@ -17,35 +17,35 @@ def test_long_operations():
testcheck.section("PyLong operations")
cpython.Py_Initialize()
# 创建整数
# Create int
py_num: cpython.PyObject | CPtr = cpython.PyLong_FromLong(12345)
testcheck.check(py_num != 0, "PyLong_FromLong != NULL", "PyLong_FromLong != NULL")
# 整数转字符串
# Int to string
py_str: cpython.PyObject | CPtr = cpython.PyObject_Str(py_num)
testcheck.check(py_str != 0, "PyObject_Str != NULL", "PyObject_Str != NULL")
# 获取 C 字符串
# Get C string
c_str: char | CPtr = cpython.PyUnicode_AsUTF8(py_str)
testcheck.check(c_str != 0, "PyUnicode_AsUTF8 != NULL", "PyUnicode_AsUTF8 != NULL")
printf(" PyLong_FromLong(12345) -> str = %s\n", c_str)
# 读取回来
# Read back
val: CLong = cpython.PyLong_AsLong(py_num)
testcheck.check(val == 12345, "PyLong_AsLong == 12345", "PyLong_AsLong == 12345")
# 负数
# Negative
py_neg: cpython.PyObject | CPtr = cpython.PyLong_FromLong(-999)
neg_val: CLong = cpython.PyLong_AsLong(py_neg)
testcheck.check(neg_val == -999, "PyLong_FromLong(-999) == -999", "PyLong_FromLong(-999) == -999")
# 浮点数转整数
# Float to int
py_dbl: cpython.PyObject | CPtr = cpython.PyFloat_FromDouble(3.14159)
testcheck.check(py_dbl != 0, "PyFloat_FromDouble != NULL", "PyFloat_FromDouble != NULL")
dbl_val: CDouble = cpython.PyFloat_AsDouble(py_dbl)
testcheck.check(dbl_val > 3.14 and dbl_val < 3.15, "PyFloat_AsDouble ~= 3.14", "PyFloat_AsDouble ~= 3.14")
# 清理
# Cleanup
cpython.Py_DecRef(py_dbl)
cpython.Py_DecRef(py_neg)
cpython.Py_DecRef(py_str)
@@ -58,27 +58,27 @@ def test_string_operations():
testcheck.section("PyUnicode operations")
cpython.Py_Initialize()
# 从 C 字符串创建
# Create from C string
py_s1: cpython.PyObject | CPtr = cpython.PyUnicode_FromString("Hello, Viper!")
testcheck.check(py_s1 != 0, "PyUnicode_FromString != NULL", "PyUnicode_FromString != NULL")
# 获取 UTF8
# Get UTF-8
utf8: char | CPtr = cpython.PyUnicode_AsUTF8(py_s1)
testcheck.check(utf8 != 0, "AsUTF8 != NULL", "AsUTF8 != NULL")
printf(" PyUnicode_FromString -> %s\n", utf8)
# 字符串长度
# String length
length: CLong = cpython.PyUnicode_GetLength(py_s1)
testcheck.check(length == 13, "GetLength == 13", "GetLength == 13")
# 字符串拼接
# String concat
py_s2: cpython.PyObject | CPtr = cpython.PyUnicode_FromString(" World")
py_concat: cpython.PyObject | CPtr = cpython.PyUnicode_Concat(py_s1, py_s2)
concat_utf8: char | CPtr = cpython.PyUnicode_AsUTF8(py_concat)
testcheck.check(py_concat != 0, "Concat != NULL", "Concat != NULL")
printf(" Concat -> %s\n", concat_utf8)
# 清理
# Cleanup
cpython.Py_DecRef(py_concat)
cpython.Py_DecRef(py_s2)
cpython.Py_DecRef(py_s1)
@@ -90,11 +90,11 @@ def test_list_operations():
testcheck.section("PyList operations")
cpython.Py_Initialize()
# 创建列表
# Create list
py_list: cpython.PyObject | CPtr = cpython.PyList_New(0)
testcheck.check(py_list != 0, "PyList_New != NULL", "PyList_New != NULL")
# Append 元素
# Append elements
py_i1: cpython.PyObject | CPtr = cpython.PyLong_FromLong(10)
py_i2: cpython.PyObject | CPtr = cpython.PyLong_FromLong(20)
py_i3: cpython.PyObject | CPtr = cpython.PyLong_FromLong(30)
@@ -102,11 +102,11 @@ def test_list_operations():
cpython.PyList_Append(py_list, py_i2)
cpython.PyList_Append(py_list, py_i3)
# 检查大小
# Check size
list_size: CSizeT = cpython.PyList_Size(py_list)
testcheck.check(list_size == 3, "PyList_Size == 3", "PyList_Size == 3")
# 获取元素
# Get elements
item0: cpython.PyObject | CPtr = cpython.PyList_GetItem(py_list, 0)
val0: CLong = cpython.PyLong_AsLong(item0)
testcheck.check(val0 == 10, "list[0] == 10", "list[0] == 10")
@@ -115,7 +115,7 @@ def test_list_operations():
val2: CLong = cpython.PyLong_AsLong(item2)
testcheck.check(val2 == 30, "list[2] == 30", "list[2] == 30")
# 清理
# Cleanup
cpython.Py_DecRef(py_i3)
cpython.Py_DecRef(py_i2)
cpython.Py_DecRef(py_i1)
@@ -128,11 +128,11 @@ def test_dict_operations():
testcheck.section("PyDict operations")
cpython.Py_Initialize()
# 创建字典
# Create dict
py_dict: cpython.PyObject | CPtr = cpython.PyDict_New()
testcheck.check(py_dict != 0, "PyDict_New != NULL", "PyDict_New != NULL")
# 设置键值对
# Set key/value pairs
py_key1: cpython.PyObject | CPtr = cpython.PyUnicode_FromString("name")
py_val1: cpython.PyObject | CPtr = cpython.PyUnicode_FromString("Viper")
cpython.PyDict_SetItem(py_dict, py_key1, py_val1)
@@ -141,24 +141,24 @@ def test_dict_operations():
py_val2: cpython.PyObject | CPtr = cpython.PyLong_FromLong(1)
cpython.PyDict_SetItem(py_dict, py_key2, py_val2)
# 检查大小
# Check size
dict_size: CSizeT = cpython.PyDict_Size(py_dict)
testcheck.check(dict_size == 2, "PyDict_Size == 2", "PyDict_Size == 2")
# 获取值
# Get value
got_val: cpython.PyObject | CPtr = cpython.PyDict_GetItem(py_dict, py_key1)
testcheck.check(got_val != 0, "GetItem(name) != NULL", "GetItem(name) != NULL")
got_str: char | CPtr = cpython.PyUnicode_AsUTF8(got_val)
testcheck.check(got_str != 0, "name == Viper", "name == Viper")
printf(" dict['name'] = %s\n", got_str)
# 使用 GetItemString
# Use GetItemString
got_ver: cpython.PyObject | CPtr = cpython.PyDict_GetItemString(py_dict, "version")
testcheck.check(got_ver != 0, "GetItemString(version) != NULL", "GetItemString(version) != NULL")
ver_val: CLong = cpython.PyLong_AsLong(got_ver)
testcheck.check(ver_val == 1, "version == 1", "version == 1")
# 清理
# Cleanup
cpython.Py_DecRef(py_val2)
cpython.Py_DecRef(py_key2)
cpython.Py_DecRef(py_val1)
@@ -172,15 +172,15 @@ def test_pyrun_string():
testcheck.section("PyRun_SimpleString")
cpython.Py_Initialize()
# 执行简单 Python 代码
# Run simple Python code
rc: CInt = cpython.PyRun_SimpleString("print('Hello from embedded Python!')")
testcheck.check(rc == 0, "PyRun_SimpleString == 0", "PyRun_SimpleString == 0")
# 执行赋值
# Run assignment
rc2: CInt = cpython.PyRun_SimpleString("x = 6 * 7")
testcheck.check(rc2 == 0, "PyRun_SimpleString(assign) == 0", "PyRun_SimpleString(assign) == 0")
# 读取结果
# Read result
rc3: CInt = cpython.PyRun_SimpleString("print(f'The answer is {x}')")
testcheck.check(rc3 == 0, "PyRun_SimpleString(print) == 0", "PyRun_SimpleString(print) == 0")
@@ -191,12 +191,12 @@ def test_import_module():
testcheck.section("PyImport_ImportModule")
cpython.Py_Initialize()
# 导入 math 模块
# Import math module
math_mod: cpython.PyObject | CPtr = cpython.PyImport_ImportModule("math")
testcheck.check(math_mod != 0, "import math != NULL", "import math != NULL")
if math_mod != 0:
# 获取 math.pi
# Get math.pi
pi_val: cpython.PyObject | CPtr = cpython.PyObject_GetAttrString(math_mod, "pi")
testcheck.check(pi_val != 0, "math.pi != NULL", "math.pi != NULL")
if pi_val != 0:
@@ -205,7 +205,7 @@ def test_import_module():
printf(" math.pi = %f\n", pi_dbl)
cpython.Py_DecRef(pi_val)
# 获取 math.sqrt 函数
# Get math.sqrt function
sqrt_func: cpython.PyObject | CPtr = cpython.PyObject_GetAttrString(math_mod, "sqrt")
testcheck.check(sqrt_func != 0, "math.sqrt != NULL", "math.sqrt != NULL")
if sqrt_func != 0:
+5 -5
View File
@@ -8,23 +8,23 @@ def bump(v: char) -> char:
def main() -> int | t.CExport:
# 1) char 注解:char = t.CChar = i8(标量内置类型,非指针)
# 1) char annotation: char = t.CChar = i8 (scalar builtin, not a pointer)
ch: char = 65
stdio.printf("1 char annot: %d (expect 65)\n", int(ch))
# 2) char() 强转 int→char:300 trunc 到 i8 → 44
# 2) char() cast int to char: 300 truncates to i8, giving 44
big: char = char(300)
stdio.printf("2 char cast trunc: %d (expect 44)\n", int(big))
# 3) 函数返回 char(i8 存储)
# 3) Function returns char (stored as i8)
nx: char = bump(ch)
stdio.printf("3 char return: %d (expect 66)\n", int(nx))
# 4) 单字符字面量 'Z' 赋给 char(90)
# 4) Single-char literal 'Z' assigned to char (90)
lit: char = 'Z'
stdio.printf("4 char literal: %d (expect 90)\n", int(lit))
# 5) char 参与算术(i8 与 int 混合提升)
# 5) char in arithmetic (i8 promoted when mixed with int)
s: int = ch + 1
stdio.printf("5 char arith: %d (expect 66)\n", s)
+5 -10
View File
@@ -3,20 +3,15 @@ import stdio
import testcheck
# ============================================================
# ClosureCallTest - t.CPtr 函数指针调用最小化复现
#
# closure_test.py 中 f: t.CPtr = make_counter() 后调用 f() 报错:
# Undefined function: 'f'
# 根因:f 是 t.CPtr(i8*),line 322 检查 pointee 是 FunctionType 失败
# ============================================================
# ClosureCallTest - minimal repro: call through a t.CPtr function pointer
# f is t.CPtr (i8*); the compiler must treat its pointee as callable.
# nonlocal 关键字测试:嵌套函数修改外层局部变量
# nonlocal test: a nested function mutates an outer local
def make_counter() -> t.CPtr:
count: int = 0
# 内部函数(闭包)捕获 count
# Inner closure captures count
def counter() -> int:
nonlocal count
count = count + 1
@@ -26,7 +21,7 @@ def make_counter() -> t.CPtr:
def test_closure_call():
"""验证 t.CPtr 函数指针调用"""
"""Verify calling a t.CPtr function pointer."""
testcheck.section("Closure call via t.CPtr")
f: t.CPtr = make_counter()
v: int = f()
+10 -10
View File
@@ -3,7 +3,7 @@ import stdio
import testcheck
# ============================================================
# Test 1: global 在嵌套函数中
# Test 1: global in nested function
# ============================================================
g_val: int = 100
@@ -22,7 +22,7 @@ def test_global_in_nested():
testcheck.check(g_val == 150, "global nested (g_val == 150)", "global nested (expect 150)")
# ============================================================
# Test 2: nonlocal 在多层嵌套中
# Test 2: nonlocal across multiple nesting levels
# ============================================================
def test_nonlocal_multi_level():
testcheck.section("Test 2: nonlocal multi-level")
@@ -42,7 +42,7 @@ def test_nonlocal_multi_level():
testcheck.check(x == 1111, "nonlocal multi (x == 1111)", "nonlocal multi (expect 1111)")
# ============================================================
# Test 3: global 和 nonlocal 混合
# Test 3: global and nonlocal mixed
# ============================================================
g_mixed: int = 0
@@ -61,7 +61,7 @@ def test_global_nonlocal_mixed():
testcheck.check(g_mixed == 20 and local_var == 40, "mixed (global==20 local==40)", "mixed (expect global=20 local=40)")
# ============================================================
# Test 4: lambda 捕获多个变量
# Test 4: lambda captures multiple variables
# ============================================================
def test_lambda_multi_capture():
testcheck.section("Test 4: lambda multi-capture")
@@ -72,7 +72,7 @@ def test_lambda_multi_capture():
testcheck.check(r == 30, "lambda multi-capture (a+b == 30)", "lambda multi-capture (expect 30)")
# ============================================================
# Test 5: lambda 带参数 + 捕获
# Test 5: lambda with argument + capture
# ============================================================
def test_lambda_arg_capture():
testcheck.section("Test 5: lambda arg + capture")
@@ -82,7 +82,7 @@ def test_lambda_arg_capture():
testcheck.check(r == 142, "lambda arg+capture (100+42 == 142)", "lambda arg+capture (expect 142)")
# ============================================================
# Test 6: 嵌套函数返回值
# Test 6: nested function return value
# ============================================================
def test_nested_return():
testcheck.section("Test 6: nested function return")
@@ -95,7 +95,7 @@ def test_nested_return():
testcheck.check(r == 10 and x == 10, "nested return (r==10 x==10)", "nested return (expect r=10 x=10)")
# ============================================================
# Test 7: nonlocal 与循环变量
# Test 7: nonlocal with loop variable
# ============================================================
def test_nonlocal_loop():
testcheck.section("Test 7: nonlocal with loop")
@@ -110,7 +110,7 @@ def test_nonlocal_loop():
testcheck.check(total == 20, "nonlocal loop (total == 20)", "nonlocal loop (expect 20)")
# ============================================================
# Test 8: global 数组操作
# Test 8: global array operation
# ============================================================
g_arr: t.CArray[int, 4] = [0]
@@ -125,7 +125,7 @@ def test_global_array():
testcheck.check(total == 100, "global array (total == 100)", "global array (expect 100)")
# ============================================================
# Test 9: 嵌套函数条件调用
# Test 9: nested function conditional call
# ============================================================
def test_nested_conditional():
testcheck.section("Test 9: nested conditional call")
@@ -140,7 +140,7 @@ def test_nested_conditional():
testcheck.check(result == 42, "nested conditional (result == 42)", "nested conditional (expect 42)")
# ============================================================
# Test 10: lambda 链式调用
# Test 10: lambda chained calls
# ============================================================
def test_lambda_chain():
testcheck.section("Test 10: lambda chain")
+12 -12
View File
@@ -3,7 +3,7 @@ import stdio
import testcheck
# ============================================================
# Test 1: nonlocal 在条件分支中修改
# Test 1: nonlocal modified in conditional branches
# ============================================================
def test_nonlocal_conditional():
testcheck.section("Test 1: nonlocal in conditional branches")
@@ -20,7 +20,7 @@ def test_nonlocal_conditional():
testcheck.check(x == 120, "nonlocal conditional (x == 120)", "nonlocal conditional (expect 120)")
# ============================================================
# Test 2: 多个nonlocal变量同时修改
# Test 2: multiple nonlocal variables modified together
# ============================================================
def test_nonlocal_multi_var():
testcheck.section("Test 2: multiple nonlocal variables")
@@ -37,7 +37,7 @@ def test_nonlocal_multi_var():
testcheck.check(a == 2 and b == 3 and c_val == 1, "multi nonlocal (a==2 b==3 c==1)", "multi nonlocal (expect 2 3 1)")
# ============================================================
# Test 3: global 在多个函数中交叉修改
# Test 3: global modified across multiple functions
# ============================================================
g_counter: int = 0
@@ -60,7 +60,7 @@ def test_global_cross_functions():
testcheck.check(g_counter == 13, "global cross (g_counter == 13)", "global cross (expect 13)")
# ============================================================
# Test 4: 嵌套函数修改外层局部变量(引用捕获)
# Test 4: nested function modifies outer local (reference capture)
# ============================================================
def test_nested_ref_capture():
testcheck.section("Test 4: nested function ref capture")
@@ -74,7 +74,7 @@ def test_nested_ref_capture():
testcheck.check(total == 100, "ref capture (total == 100)", "ref capture (expect 100)")
# ============================================================
# Test 5: lambda捕获后修改原变量
# Test 5: modify original variable after lambda capture
# ============================================================
def test_lambda_capture_then_modify():
testcheck.section("Test 5: lambda capture then modify")
@@ -86,7 +86,7 @@ def test_lambda_capture_then_modify():
testcheck.check(r1 == 10 and r2 == 10, "lambda value capture (before==10 after==10)", "lambda value capture (expect 10 10)")
# ============================================================
# Test 6: 嵌套函数中nonlocal与循环结合
# Test 6: nonlocal combined with loop
# ============================================================
def test_nonlocal_loop_accumulate():
testcheck.section("Test 6: nonlocal with loop accumulate")
@@ -102,7 +102,7 @@ def test_nonlocal_loop_accumulate():
testcheck.check(sum_val == 21 and count == 8, "loop accumulate (sum==21 count==8)", "loop accumulate (expect 21 8)")
# ============================================================
# Test 7: 三层嵌套中每层修改不同变量
# Test 7: three-level nesting, each level modifies a different var
# ============================================================
def test_deep_nested_vars():
testcheck.section("Test 7: deep nested different vars")
@@ -125,7 +125,7 @@ def test_deep_nested_vars():
testcheck.check(a == 2 and b == 20 and c_val == 200, "deep nested (a==2 b==20 c==200)", "deep nested (expect 2 20 200)")
# ============================================================
# Test 8: global + nonlocal 在同一嵌套函数中
# Test 8: global and nonlocal in the same nested function
# ============================================================
g_state: int = 0
@@ -144,7 +144,7 @@ def test_global_nonlocal_same_func():
testcheck.check(g_state == 5 and local_state == 10, "global+nonlocal same (g==5 l==10)", "global+nonlocal same (expect 5 10)")
# ============================================================
# Test 9: lambda带默认参数与捕获
# Test 9: lambda with argument and capture
# ============================================================
def test_lambda_default_and_capture():
testcheck.section("Test 9: lambda with arg and capture")
@@ -155,7 +155,7 @@ def test_lambda_default_and_capture():
testcheck.check(r1 == 300 and r2 == 500, "lambda arg+capture (100*3==300 100*5==500)", "lambda arg+capture (expect 300 500)")
# ============================================================
# Test 10: 嵌套函数多次调用累积
# Test 10: nested function accumulates over multiple calls
# ============================================================
def test_nested_accumulate():
testcheck.section("Test 10: nested function accumulate")
@@ -169,7 +169,7 @@ def test_nested_accumulate():
testcheck.check(total == 60, "nested accumulate (total == 60)", "nested accumulate (expect 60)")
# ============================================================
# Test 11: nonlocal在while循环中
# Test 11: nonlocal in while loop
# ============================================================
def test_nonlocal_while():
testcheck.section("Test 11: nonlocal in while loop")
@@ -184,7 +184,7 @@ def test_nonlocal_while():
testcheck.check(result == 15, "nonlocal while (result == 15)", "nonlocal while (expect 15)")
# ============================================================
# Test 12: 嵌套函数修改结构体字段
# Test 12: nested function modifies struct fields
# ============================================================
class Point:
x: int
+32 -74
View File
@@ -2,22 +2,10 @@ import t
from stdio import printf
import testcheck
# ============================================================
# 自定义装饰器处理函数
# 调用约定 (v4):
# i32 decor_name(i8* ctx, i8* func_name, i32 phase,
# i8* args_ptr, i8* ret_ptr, i8* decor_args_ptr)
#
# ctx: 栈帧局部上下文(32字节),每次调用独立,线程/递归安全
# args_ptr: 可读写,装饰器可修改函数入参
# ret_ptr: 后置阶段可读写,装饰器可修改返回值
# 返回值(前置阶段):
# 0 = 跳过原函数调用
# 1 = 正常调用一次
# N = 循环调用 N 次
# ============================================================
# Custom decorator handler calling convention (v4): i32 decor(ctx, func_name, phase, args_ptr, ret_ptr, decor_args_ptr).
# ctx: per-call frame-local context (32 bytes); args_ptr/ret_ptr are read-write; pre-phase returns 0=skip, 1=call once, N=loop N.
# @log 装饰器:打印函数进入/退出,返回 1(正常调用一次)
# @log: print enter/exit, return 1 (call once)
def log(ctx: t.CPtr, func_name: str, phase: int,
args_ptr: t.CPtr,
ret_ptr: t.CPtr,
@@ -29,7 +17,7 @@ def log(ctx: t.CPtr, func_name: str, phase: int,
printf("[LOG] << %s exit\n", func_name)
return 0
# @trace 装饰器:详细追踪
# @trace: verbose tracing
def trace(ctx: t.CPtr, func_name: str, phase: int,
args_ptr: t.CPtr,
ret_ptr: t.CPtr,
@@ -41,10 +29,8 @@ def trace(ctx: t.CPtr, func_name: str, phase: int,
printf("[TRACE] %s returned\n", func_name)
return 0
# @timing 装饰器:使用全局变量记录计时
# 注意:理想情况下应使用 ctx 栈帧局部上下文替代全局变量,
# 但 Viper 当前前端尚不支持 i8* 到 i32* 的指针转型,
# 因此暂时使用全局变量演示计时逻辑
# @timing: measures elapsed time using a global counter.
# A global is used because i8* to i32* pointer casts are not supported yet.
_timing_tmp: int = 0
def timing(ctx: t.CPtr, func_name: str, phase: int,
@@ -61,7 +47,7 @@ def timing(ctx: t.CPtr, func_name: str, phase: int,
printf("[TIMING] %s took %d ms\n", func_name, elapsed)
return 0
# @repeat 装饰器(带参数,流程劫持):循环调用原函数 N 次
# @repeat (with args, flow hijack): call the original function N times
def repeat(ctx: t.CPtr, func_name: str, phase: int,
args_ptr: t.CPtr,
ret_ptr: t.CPtr,
@@ -73,7 +59,7 @@ def repeat(ctx: t.CPtr, func_name: str, phase: int,
printf("[REPEAT] %s all iterations done\n", func_name)
return 0
# @skip 装饰器:跳过原函数调用(流程劫持,返回 0)
# @skip: skip the original call (flow hijack, returns 0)
_skip_count: int = 0
def skip(ctx: t.CPtr, func_name: str, phase: int,
@@ -89,7 +75,7 @@ def skip(ctx: t.CPtr, func_name: str, phase: int,
printf("[SKIP] %s post (ret_ptr=%p)\n", func_name, ret_ptr)
return 0
# @count_calls 装饰器:统计函数被调用次数(递归保护测试用)
# @count_calls: count invocations (used to test recursion guard)
_call_count: int = 0
def count_calls(ctx: t.CPtr, func_name: str, phase: int,
@@ -106,19 +92,14 @@ def count_calls(ctx: t.CPtr, func_name: str, phase: int,
return 0
# ============================================================
# 测试 1:单个装饰器 @log
# ============================================================
# --- Test 1: single @log ---
@log
def add(a: int, b: int) -> int | t.CExport:
return a + b
# ============================================================
# 测试 2:链式装饰器 @log @trace => log(trace(f))
# 执行顺序:log_pre → trace_pre → f → trace_post → log_post
# ============================================================
# --- Test 2: chained @log @trace (log(trace(f))) ---
@log
@trace
@@ -126,45 +107,35 @@ def multiply(a: int, b: int) -> int | t.CExport:
return a * b
# ============================================================
# 测试 3:装饰器修饰 void 返回函数
# ============================================================
# --- Test 3: @log on void function ---
@log
def greet(name: str) -> void | t.CExport:
printf("Hello, %s!\n", name)
# ============================================================
# 测试 4:装饰器修饰无参数函数
# ============================================================
# --- Test 4: @log on no-arg function ---
@log
def get_value() -> int | t.CExport:
return 42
# ============================================================
# 测试 5:@timing 装饰器
# ============================================================
# --- Test 5: @timing ---
@timing
export def compute(x: int) -> int:
return x * x + 1
# ============================================================
# 测试 6:带参数装饰器 @repeat(3) — 流程劫持,循环调用 3 次
# ============================================================
# --- Test 6: @repeat(3) flow hijack ---
@repeat(3)
export def echo(msg: str):
printf(" echo: %s\n", msg)
# ============================================================
# 测试 7:链式 @timing @log
# ============================================================
# --- Test 7: chained @timing @log ---
@timing
@log
@@ -175,9 +146,7 @@ export def power(base: int, exp: int) -> int:
return result
# ============================================================
# 测试 8:@skip 装饰器 — 流程劫持,跳过原函数调用
# ============================================================
# --- Test 8: @skip flow hijack ---
@skip
def dangerous() -> int | t.CExport:
@@ -185,9 +154,7 @@ def dangerous() -> int | t.CExport:
return 999
# ============================================================
# 测试 9:@repeat(3) 修饰有返回值的函数
# ============================================================
# --- Test 9: @repeat(3) with return value ---
@repeat(3)
def accumulate(x: int) -> int | t.CExport:
@@ -195,11 +162,7 @@ def accumulate(x: int) -> int | t.CExport:
return x * 10
# ============================================================
# 测试 10:递归装饰保护 — @count_calls 修饰递归函数
# v4 递归保护:最外层 wrapper 检查全局标志位,
# 递归调用时跳过所有装饰逻辑,仅最外层调用触发装饰器
# ============================================================
# --- Test 10: recursion guard, @count_calls on recursive fn ---
@count_calls
def factorial(n: int) -> int | t.CExport:
@@ -208,10 +171,7 @@ def factorial(n: int) -> int | t.CExport:
return n * factorial(n - 1)
# ============================================================
# 测试 11:@log 修饰递归函数 — 验证递归保护
# 递归保护确保只有最外层调用打印 LOG,内部递归不触发
# ============================================================
# --- Test 11: @log on recursive fib ---
@log
def fib(n: int) -> int | t.CExport:
@@ -220,66 +180,64 @@ def fib(n: int) -> int | t.CExport:
return fib(n - 1) + fib(n - 2)
# ============================================================
# 主函数
# ============================================================
# --- main ---
def main() -> int | t.CExport:
testcheck.begin("Decorator Test v4")
# 测试 1:单个 @log
# Test 1: single @log
testcheck.section("Test 1: single @log")
r1: int = add(3, 4)
printf("add(3,4) = %d\n", r1)
testcheck.check(r1 == 7, "add(3,4) = 7", "add(3,4) expect 7")
# 测试 2:链式 @log @trace
# Test 2: chained @log @trace
testcheck.section("Test 2: chained @log @trace")
r2: int = multiply(5, 6)
printf("multiply(5,6) = %d\n", r2)
testcheck.check(r2 == 30, "multiply(5,6) = 30", "multiply(5,6) expect 30")
# 测试 3:void 返回
# Test 3: void return
testcheck.section("Test 3: @log on void function")
greet("Viper")
testcheck.ok("@log on void function greet")
# 测试 4:无参数
# Test 4: no arguments
testcheck.section("Test 4: @log on no-arg function")
r4: int = get_value()
printf("get_value() = %d\n", r4)
testcheck.check(r4 == 42, "get_value() = 42", "get_value() expect 42")
# 测试 5:@timing
# Test 5: @timing
testcheck.section("Test 5: @timing")
r5: int = compute(7)
printf("compute(7) = %d\n", r5)
testcheck.check(r5 == 50, "compute(7) = 50", "compute(7) expect 50")
# 测试 6:@repeat(3) — 流程劫持,循环 3 次
# Test 6: @repeat(3) flow hijack, loops 3 times
testcheck.section("Test 6: @repeat(3) flow hijack")
echo("hello")
testcheck.ok("@repeat(3) flow hijack echo")
# 测试 7:链式 @timing @log
# Test 7: chained @timing @log
testcheck.section("Test 7: chained @timing @log")
r7: int = power(2, 10)
printf("power(2,10) = %d\n", r7)
testcheck.check(r7 == 1024, "power(2,10) = 1024", "power(2,10) expect 1024")
# 测试 8:@skip — 跳过原函数调用
# Test 8: @skip, skips the original call
testcheck.section("Test 8: @skip flow hijack")
r8: int = dangerous()
printf("dangerous() = %d (should be 0, skipped)\n", r8)
testcheck.check(r8 == 0, "dangerous() skipped = 0", "dangerous() expect 0")
# 测试 9:@repeat(3) 有返回值
# Test 9: @repeat(3) with return value
testcheck.section("Test 9: @repeat(3) with return value")
r9: int = accumulate(5)
printf("accumulate(5) = %d (last iteration result)\n", r9)
testcheck.check(r9 == 50, "accumulate(5) = 50", "accumulate(5) expect 50")
# 测试 10:递归装饰保护 — @count_calls
# Test 10: recursion guard, @count_calls
testcheck.section("Test 10: recursive decoration protection")
global _call_count
_call_count = 0
@@ -288,7 +246,7 @@ def main() -> int | t.CExport:
printf(" decorator call count = %d (should be 1, not 5)\n", _call_count)
testcheck.check(r10 == 120 and _call_count == 1, "factorial(5)=120, calls=1", "factorial(5) expect 120, calls=1")
# 测试 11:@log 递归保护 — fib
# Test 11: @log recursion guard, fib
testcheck.section("Test 11: @log on recursive fib")
r11: int = fib(6)
printf("fib(6) = %d (should be 8)\n", r11)
+9 -9
View File
@@ -5,12 +5,12 @@ import remote
import random
# 同模块:单个尾随默认值
# Same module: single trailing default
def local_one(x: int, cap: sizet = 4096) -> sizet:
return cap
# 同模块:多个尾随默认值
# Same module: multiple trailing defaults
def local_quad(a: int, b: int = 10, c: int = 20, d: int = 30) -> int:
return a + b * 100 + c * 10000 + d * 1000000
@@ -18,26 +18,26 @@ def local_quad(a: int, b: int = 10, c: int = 20, d: int = 30) -> int:
def main() -> int:
testcheck.begin("DefaultArgTest: default / named / out-of-order arguments")
# ① 同模块默认值
# Same-module defaults
testcheck.section("same-module defaults")
r1: sizet = local_one(1)
testcheck.check(r1 == 4096, "local_one(1) cap = 4096", "local_one(1) cap != 4096")
r2: int = local_quad(1)
testcheck.check(r2 == 30201001, "local_quad(1) = 30201001", "local_quad(1) != 30201001")
# ② 跨模块默认值
# Cross-module defaults
testcheck.section("cross-module defaults")
r3: sizet = remote.one(1)
testcheck.check(r3 == 4096, "remote.one(1) cap = 4096", "remote.one(1) cap != 4096")
r4: sizet = remote.write(1, 2, False)
testcheck.check(r4 == 4096, "remote.write(1,2,False) cap = 4096", "remote.write(1,2,False) cap != 4096")
# ③ 显式覆盖默认值
# Explicit override
testcheck.section("explicit override")
r5: sizet = remote.one(1, 8)
testcheck.check(r5 == 8, "remote.one(1,8) cap = 8", "remote.one(1,8) cap != 8")
# ④ 命名 / 乱序传参
# Named / out-of-order arguments
testcheck.section("named / out-of-order arguments")
r6: sizet = remote.one(cap = 8, x = 1)
testcheck.check(r6 == 8, "remote.one(cap = 8, x = 1) = 8", "remote.one(cap = 8, x = 1) != 8")
@@ -48,7 +48,7 @@ def main() -> int:
r9: int = remote.many(z = 3, x = 1, y = 2)
testcheck.check(r9 == 9, "remote.many(z = 3, x = 1, y = 2) = 9", "remote.many(z = 3, x = 1, y = 2) != 9")
# ⑤ 多个尾随默认值只给前几个
# Multiple trailing defaults: pass only the leading ones
testcheck.section("partial trailing defaults")
r10: int = local_quad(1, 2)
testcheck.check(r10 == 30200201, "local_quad(1,2) = 30200201", "local_quad(1,2) != 30200201")
@@ -61,8 +61,8 @@ def main() -> int:
r14: int = remote.quad(1)
testcheck.check(r14 == 30201001, "remote.quad(1) = 30201001", "remote.quad(1) != 30201001")
# ⑥ include 模块(顶层 .vp)默认值:vrandom.randrange(start, stop, step = 1)
# stop-start==1 ⇒ width==1 ⇒ 结果恒为 start;step 未填充时会退化为 0/垃圾
# Include-module (top-level .vp) defaults: vrandom.randrange(start, stop, step = 1)
# stop-start==1 means width==1, so result is always start; unset step degrades to 0/garbage
testcheck.section("include-module defaults")
r15: int = random.randrange(5, 6)
testcheck.check(r15 == 5, "vrandom.randrange(5,6) = 5 (step default)", "vrandom.randrange(5,6) != 5")
+4 -4
View File
@@ -1,21 +1,21 @@
import t
# 跨模块:单个尾随默认值(对照 includes/json/__writer.vp 的 write 形态)
# Cross-module: single trailing default (mirrors write in includes/json/__writer.vp)
def one(x: int, cap: sizet = 4096) -> sizet:
return cap
# 跨模块:4 参、最后一个有默认值(与 json.write(pool, val, pretty, cap=4096) 同形)
# Cross-module: 4 params, last has a default (same shape as json.write(pool, val, pretty, cap=4096))
def write(a: int, b: int, pretty: bool, cap: sizet = 4096) -> sizet:
return cap
# 跨模块:多个尾随默认值
# Cross-module: multiple trailing defaults
def quad(a: int, b: int = 10, c: int = 20, d: int = 30) -> int:
return a + b * 100 + c * 10000 + d * 1000000
# 跨模块:乱序/命名传参(wiki 04-functions.md 的 add 形态)
# Cross-module: named / out-of-order args (add shape in wiki 04-functions.md)
def many(x: int, y: int, z: int = 1) -> int:
return (x + y) * z
+2 -5
View File
@@ -8,11 +8,8 @@ import testcheck
# ============================================================
# DefineTest - CDefine 宏 / c.CIf / platmacro 专项测试
#
# 从 TestProject3/App/definetest.vp 独立提取。
# 验证: CDefine 常量、宏函数、c.CIf/c.CIfdef/c.CIfndef、
# platmacro 平台宏(输出以 print 为准,人工核对)。
# DefineTest: CDefine constants/macros, c.CIf family, platmacro.
# Prints results for manual inspection.
# ============================================================
+13 -14
View File
@@ -15,11 +15,11 @@ def main() -> CInt | CExport:
testcheck.begin("DictTest: 万能 dict (Variant 存储) 测试")
# 分配内存竞技场
# allocate memory arena
arena: bytes = stdlib.malloc(65536)
bd: memhub.MemBuddy* = memhub.MemBuddy(arena, 65536)
# === Test 1: dict set_int / c.Deref 基本操作 ===
# === Test 1: dict set_int / c.Deref basic ops ===
testcheck.section("Test 1: dict set_int / c.Deref 基本操作")
d: dict = dict(bd)
d.set_int("alpha", 10)
@@ -29,9 +29,8 @@ def main() -> CInt | CExport:
stdio.printf("len=%lu\n", n)
testcheck.check(n == 3, "dict len OK (3)", "dict len FAILED")
# dict 的 int 值按 int(i32)写入(见 _dict.vp set_int 的 int_ptr),读回须
# 给出有元素类型的指针:c.Deref 的宽度只认 pointee 类型,i8*(t.CPtr)恒读
# 1 字节,不再按赋值目标注解反推 4 字节。
# dict int values are stored as i32; reading back requires a typed pointer
# because c.Deref uses the pointee width (i8* always reads 1 byte).
p1: t.CPtr = d["alpha"]
stdio.printf("p1=%p\n", p1)
p2: t.CPtr = d["beta"]
@@ -47,7 +46,7 @@ def main() -> CInt | CExport:
testcheck.check(v2 == 20, "dict[beta]==20 OK", "dict[beta] FAILED")
testcheck.check(v3 == 30, "dict[gamma]==30 OK", "dict[gamma] FAILED")
# === Test 2: 更新已有键 ===
# === Test 2: update existing key ===
testcheck.section("Test 2: 更新已有键")
d.set_int("beta", 99)
p2b: t.CPtr = d["beta"]
@@ -74,7 +73,7 @@ def main() -> CInt | CExport:
testcheck.check(has_alpha == 1, "contains alpha OK", "contains alpha FAILED")
testcheck.check(has_missing == 0, "not contains missing OK", "contains missing FAILED")
# === Test 5: 迭代器 ===
# === Test 5: iterator ===
testcheck.section("Test 5: 迭代器 for key in dict")
iter_count: int = 0
for key in d:
@@ -84,7 +83,7 @@ def main() -> CInt | CExport:
iter_count += 1
testcheck.check(iter_count == 3, "dict iter OK (3)", "dict iter FAILED")
# === Test 6: dict set_str 字符串值 ===
# === Test 6: dict set_str string values ===
testcheck.section("Test 6: dict set_str 字符串值")
d2: dict = dict(bd)
d2.set_str("name", "Alice")
@@ -101,12 +100,12 @@ def main() -> CInt | CExport:
city: str = city_p
lang: str = lang_p
stdio.printf("name=%s city=%s lang=%s\n", name, city, lang)
# i8* == 是指针地址比较(C-Like 语义),内容比较需显式 strcmp
# i8* == compares addresses (C-like); content compare needs strcmp
testcheck.check(string.strcmp(name, "Alice") == 0, "dict str name OK", "dict str name FAILED")
testcheck.check(string.strcmp(city, "Beijing") == 0, "dict str city OK", "dict str city FAILED")
testcheck.check(string.strcmp(lang, "TransPyC") == 0, "dict str lang OK", "dict str lang FAILED")
# === Test 7: dict[str] 迭代 ===
# === Test 7: dict[str] iteration ===
testcheck.section("Test 7: dict 迭代 (str values)")
str_iter_count: int = 0
for k in d2:
@@ -116,7 +115,7 @@ def main() -> CInt | CExport:
str_iter_count += 1
testcheck.check(str_iter_count == 3, "dict str iter OK (3)", "dict str iter FAILED")
# === Test 8: 扩容测试 ===
# === Test 8: expansion (>8 elements) ===
testcheck.section("Test 8: 扩容测试 (>8 个元素)")
d3: dict = dict(bd)
for i in range(20):
@@ -127,7 +126,7 @@ def main() -> CInt | CExport:
stdio.printf("d3 len=%lu (after 20 inserts)\n", n3)
testcheck.check(n3 == 20, "dict expand OK (20)", "dict expand FAILED")
# 验证几个值
# verify a few values
k5: str = stdlib.malloc(16)
stdio.sprintf(k5, "key5")
p5: t.CPtr = d3[k5]
@@ -198,7 +197,7 @@ def main() -> CInt | CExport:
testcheck.check(rta == 1, "round-trip a OK", "round-trip a FAILED")
testcheck.check(rtb == 2, "round-trip b OK", "round-trip b FAILED")
# === Test 13: 嵌套 dict ===
# === Test 13: nested dict ===
testcheck.section("Test 13: 嵌套 dict")
outer: dict = dict(bd)
inner: dict = dict(bd)
@@ -215,7 +214,7 @@ def main() -> CInt | CExport:
testcheck.check(sa == 1, "nested sub.a OK", "nested sub.a FAILED")
testcheck.check(sb == 2, "nested sub.b OK", "nested sub.b FAILED")
# === Test 14: get_vtype 类型标签 ===
# === Test 14: get_vtype type tag ===
testcheck.section("Test 14: get_vtype 类型标签")
vt1: int = d.get_vtype("alpha")
vt2: int = d2.get_vtype("name")
+5 -5
View File
@@ -6,18 +6,18 @@ import testcheck
import remote
# 同模块函数(有 docstring)
# Same-module function (has docstring).
def local_func() -> int:
"Local function docstring."
return 0
# 同模块函数(无 docstring)
# Same-module function (no docstring).
def no_doc_func() -> int:
return 0
# 同模块类(有 docstring)
# Same-module class (has docstring).
class LocalClass:
"Local class docstring."
value: int
@@ -28,7 +28,7 @@ class LocalClass:
def _check_doc_adaptive(name: str, doc: str, expected: str):
"""自适应检查 docstring:非空时验证匹配,空时视为优化剥离"""
"""Check docstring: verify when present, treat null as optimized out."""
if doc is None:
testcheck.ok(f"{name}: __doc__ optimized out (null)")
return
@@ -39,7 +39,7 @@ def _check_doc_adaptive(name: str, doc: str, expected: str):
def _check_doc_null(name: str, doc: str):
"""检查 docstring 为 null(无 docstring 的符号)"""
"""Check that a symbol's docstring is null."""
if doc is None:
testcheck.ok(f"{name}: __doc__ is null")
else:
+7 -19
View File
@@ -45,10 +45,8 @@ renum Opt:
None_ = 0
# ============================================================
# Test 5: 前向引用检测 — _class_graph 正确识别父类
# (注:检测已修复,但成员继承仍需父类先处理)
# ============================================================
# Test 5: forward reference detection - _class_graph resolves the base class.
# Member inheritance still requires the base class to be processed first.
class Parent:
a: int
@@ -63,9 +61,7 @@ class Child(Parent):
return self.a + self.b
# ============================================================
# Test 6: 多层继承 A -> B -> C,CVTable 向上传播
# ============================================================
# Test 6: multi-level inheritance A -> B -> C, CVTable propagates upward
class Base:
x: int
@@ -87,24 +83,18 @@ class Leaf(Mid):
return self.z
# ============================================================
# Test 7: 类型别名用于注解
# ============================================================
# Test 7: type alias in annotation
val: myint = 42
# ============================================================
# Test 8: BigEndian 字节序
# ============================================================
# Test 8: BigEndian byte order
class NetHeader:
magic: int | t.BigEndian
length: t.CShort | t.BigEndian
normal: int
# ============================================================
# Test 9: import t as tt; tt.CInt 作为类型注解
# ============================================================
# Test 9: import t as tt; tt.CInt as type annotation
# class TtStruct:
# x: tt.CInt
# y: tt.CFloat
@@ -118,9 +108,7 @@ class TtPoint:
y: int
# ============================================================
# Test 11: import t as tt; @tt.Object 装饰器
# ============================================================
# Test 11: import t as tt; @tt.Object decorator
class TtObject:
val: int
+13 -13
View File
@@ -14,12 +14,12 @@ def main() -> CInt | CExport:
testcheck.begin("== 重载和 is 地址比较测试")
# === Test 1: str == str 值比较 ===
# === Test 1: str == str value compare ===
testcheck.section("Test 1: str == str 值比较")
s1: str = "hello"
s2: str = "hello"
s3: str = "world"
# i8* == 是指针地址比较(C-Like 语义),内容比较需显式 strcmp
# i8* == compares addresses (C-like); use strcmp for content compare
testcheck.check(string.strcmp(s1, s2) == 0, "str == str (same value) OK", "str == str (same value) FAILED")
testcheck.check(string.strcmp(s1, s3) != 0, "str != str (diff value) OK", "str != str (diff value) FAILED")
@@ -28,16 +28,16 @@ def main() -> CInt | CExport:
testcheck.check(string.strcmp(s1, s3) != 0, "str != str (diff) OK", "str != str (diff) FAILED")
testcheck.check(string.strcmp(s1, s2) == 0, "str == str (same) via != OK", "str == str (same) via != FAILED")
# === Test 3: str == 字面量 ===
# === Test 3: str == literal ===
testcheck.section("Test 3: str == literal")
testcheck.check(string.strcmp(s1, "hello") == 0, "str == literal OK", "str == literal FAILED")
testcheck.check(string.strcmp(s1, "world") != 0, "str != literal OK", "str != literal FAILED")
# === Test 4: str is str 地址比较 ===
# === Test 4: str is str address compare ===
testcheck.section("Test 4: str is str address compare")
# s1 和 s2 是不同的字符串变量,地址不同
# s1 and s2 are distinct variables with different addresses
testcheck.check(not (s1 is s2), "str is str (diff addr) OK", "str is str (diff addr) FAILED")
# s1 is s1 应该为 True(同一变量)
# s1 is s1 is True (same variable)
testcheck.check(s1 is s1, "str is self OK", "str is self FAILED")
# === Test 5: int == int ===
@@ -48,32 +48,32 @@ def main() -> CInt | CExport:
testcheck.check(i1 == i2, "int == int (same) OK", "int == int (same) FAILED")
testcheck.check(not (i1 == i3), "int != int (diff) OK", "int != int (diff) FAILED")
# === Test 6: None 比较 ===
# === Test 6: None compare ===
testcheck.section("Test 6: None compare")
null_ptr: str = None
testcheck.check(null_ptr == None, "ptr == None OK", "ptr == None FAILED")
testcheck.check(not (s1 == None), "str != None OK", "str != None FAILED")
# === Test 7: 整型 vs None(整数上的 None 隐式为 0)===
# 语义(TPC / TPV 统一):x is None ≡ x == None ≡ x == 0;x is not None ≡ x != None ≡ x != 0
# === Test 7: int vs None (None on int is implicitly 0) ===
# Unified semantics: x is None, x == None and x == 0 agree (and negations)
testcheck.section("Test 7: int vs None")
nz: int = 7
zr: int = 0
# 非零整数 ⇒ 不等于 None
# nonzero int => not None
testcheck.check(not (nz is None), "int(7) is None -> false OK", "int(7) is None FAILED")
testcheck.check(nz is not None, "int(7) is not None -> true OK", "int(7) is not None FAILED")
testcheck.check(not (nz == None), "int(7) == None -> false OK", "int(7) == None FAILED")
testcheck.check(nz != None, "int(7) != None -> true OK", "int(7) != None FAILED")
# 零值 ⇒ 等价于 None
# zero => equivalent to None
testcheck.check(zr is None, "int(0) is None -> true OK", "int(0) is None FAILED")
testcheck.check(not (zr is not None), "int(0) is not None -> false OK", "int(0) is not None FAILED")
testcheck.check(zr == None, "int(0) == None -> true OK", "int(0) == None FAILED")
testcheck.check(not (zr != None), "int(0) != None -> false OK", "int(0) != None FAILED")
# None 在左侧的镜像方向(TPV 此前该方向分支有误,恒判相等)
# mirrored None-on-left direction
testcheck.check(not (None is nz), "None is int(7) -> false OK", "None is int(7) FAILED")
testcheck.check(None is zr, "None is int(0) -> true OK", "None is int(0) FAILED")
# === Test 8: 其它整型位宽 vs None(i8 / i64,防"从空指针 load"回归)===
# === Test 8: other int widths vs None (i8/i64, guards null-pointer load) ===
testcheck.section("Test 8: char / sizet vs None")
c8: char = 0
c8nz: char = 65
+10 -10
View File
@@ -5,50 +5,50 @@ import testcheck
# ============================================================
# ExpandKeywordsTest - 验证 def 别名关键字 fn/fun/func/function
# 语义与 def 完全相同(定义/调用/嵌套/泛型/空函数体)
# ExpandKeywordsTest - verify def alias keywords fn/fun/func/function;
# identical semantics to def (define/call/nest/generic/empty body).
# ============================================================
# fn: 单参数返回
# fn: single argument, returns value
fn add_one(x: int) -> int:
return x + 1
# fun: 双参数返回
# fun: two arguments, returns value
fun add_two(a: int, b: int) -> int:
return a + b
# func: 浮点参数返回
# func: float arguments
func mul_float(a: double, b: double) -> double:
return a * b
# function: 内部用 def 定义再调用(别名与 def 混用)
# function: defines and calls an inner def (alias mixed with def)
function get_ten() -> int:
def inner() -> int:
return 10
return inner()
# fn 泛型(PEP 695 风格类型参数)
# fn generic (PEP 695 style type parameters)
fn ident[T](x: T) -> T:
return x
# fn 空函数体(pass)
# fn empty body (pass)
fn noop():
pass
# fun 递归
# fun recursion
fun fact(n: int) -> int:
if n <= 1:
return 1
return n * fact(n - 1)
# func 多语句 + 局部变量
# func multiple statements + local variable
func avg3(a: double, b: double, c: double) -> double:
total: double = a + b + c
return total / 3.0
+8 -14
View File
@@ -3,33 +3,27 @@ import stdio
import testcheck
# ============================================================
# Extern2Test - ExternalDecl/StateDecl 重定义错误最小化复现
#
# 在 TransPyV Test 的 deco_test.py 中,这三个声明在生成的 .ll 中
# 被声明两次(line 56-60 和 62-66),导致 llc 报错:
# llc.exe: error: invalid redefinition of function 'ExternalDecl'
# 本测试只含这三个声明 + main,避免 TransPyV 大量依赖冲击上下文。
# ============================================================
# Extern2Test - minimal repro: ExternalDecl/StateDecl redefinition
# Three declarations plus main; each must emit exactly one declare.
# Test 1: t.CExtern | t.CExport - 外部声明函数(pass 体)
# 声明一个外部函数,翻译器应生成 declare 而非 define
# Test 1: t.CExtern | t.CExport - external declaration (pass body)
# Translator must emit declare, not define.
def ExternalDecl(x: int) -> int | t.CExtern | t.CExport: pass
# Test 2: t.State - 状态声明(等价于 CExtern | CExport)
# Test 2: t.State - state declaration (same as CExtern | CExport)
def StateDecl(x: int) -> int | t.State: pass
# Test 3: t.State 返回 void
# Test 3: t.State returning void
def StateVoidDecl() -> t.State: pass
def test_extern_decl():
"""验证三个 extern 声明只生成一次 declare,不重复"""
"""Verify the three extern declarations emit declare only once."""
testcheck.section("Extern/State declarations (no duplicate)")
# 外部声明函数,不调用(应由链接器解析符号)
# External declarations are not called; the linker resolves the symbols.
testcheck.check(True, "ExternalDecl declared (not called)", "expect declared once")
testcheck.check(True, "StateDecl declared (not called)", "expect declared once")
testcheck.check(True, "StateVoidDecl declared (not called)", "expect declared once")
+32 -32
View File
@@ -15,10 +15,10 @@ def main() -> CInt | CExport:
w32.win32console.SetConsoleCP(65001)
w32.win32console.SetConsoleOutputCP(65001)
# FakeDuck 测试: str 类型调用扩展方法 b()
# FakeDuck: str calls extension method b()
a: str = "Hello"
# Type 通用基类测试: str 变量调用 Type 的方法 type_id()
# Type base class: str calls Type.type_id()
tid: CInt = a.type_id()
if tid == 99:
@@ -26,57 +26,57 @@ def main() -> CInt | CExport:
else:
stdio.printf("Type FAIL: a.type_id() = %d\n", tid)
# 直接字段访问测试: 读取 a.__data__ (应等于 a 本身)
# Direct field read: a.__data__ (equals a itself)
data_ptr: str = a.__data__
stdio.printf("a.__data__ = %s\n", data_ptr)
# upper() 测试: 通过 mbuddy 分配内存,返回大写字符串
# upper(): allocates via mbuddy, returns uppercased string
arena: bytes = stdlib.malloc(65536)
bd: memhub.MemBuddy* = memhub.MemBuddy(arena, 65536)
# 直接字段赋值: a.__mbuddy__ = bd (语法糖, 等价于 a.set_mbuddy(bd))
# Direct field write: a.__mbuddy__ = bd (sugar for a.set_mbuddy(bd))
a.__mbuddy__ = bd
upper_str: str = a.upper()
stdio.printf("upper('Hello') = %s\n", upper_str)
# 验证 per-instance 不污染: b 没有设置 __mbuddy__ (初始为 NULL)
# Verify per-instance isolation: b has no __mbuddy__ (NULL)
b: str = "World"
# 直接字段读取: b.__mbuddy__ (应返回 NULL)
# Direct field read: b.__mbuddy__ (returns NULL)
b_buddy: memhub.MemBuddy* = b.__mbuddy__
if int(b_buddy) == 0:
stdio.printf("mbuddy OK: b.__mbuddy__ is NULL (no pollution)\n")
else:
stdio.printf("mbuddy FAIL: b.__mbuddy__ polluted!\n")
# b 也设置 mbuddy 并 upper
# Set mbuddy on b and run upper()
b.__mbuddy__ = bd
upper_b: str = b.upper()
stdio.printf("upper('World') = %s\n", upper_b)
# lower() 测试
# lower()
lower_str: str = a.lower()
stdio.printf("lower('Hello') = %s\n", lower_str)
# capitalize() 测试
# capitalize()
cap_str: str = a.capitalize()
stdio.printf("capitalize('Hello') = %s\n", cap_str)
# swapcase() 测试
# swapcase()
swap_str: str = a.swapcase()
stdio.printf("swapcase('Hello') = %s\n", swap_str)
# casefold() 测试
# casefold()
cf_str: str = a.casefold()
stdio.printf("casefold('Hello') = %s\n", cf_str)
# title() 测试
# title()
t_str: str = "hello world"
t_str.__mbuddy__ = bd
title_result: str = t_str.title()
stdio.printf("title('hello world') = %s\n", title_result)
# 布尔判断函数测试 (不需要 __mbuddy__)
# Predicate methods (no __mbuddy__ needed)
u: str = "HELLO"
lo: str = "hello"
dig: str = "12345"
@@ -101,10 +101,10 @@ def main() -> CInt | CExport:
stdio.printf("istitle('Hello World') = %d\n", title_s.istitle())
stdio.printf("istitle('hello world') = %d\n", t_str.istitle())
# === split() 测试 ===
# --- split() ---
testcheck.begin("FakeDuck split() 测试")
# Test 1: 基本分割
# Test 1: basic split
testcheck.section("Test 1: 基本分割 'a,b,c'")
s1: str = "a,b,c"
s1.__mbuddy__ = bd
@@ -120,7 +120,7 @@ def main() -> CInt | CExport:
testcheck.check(string.strcmp(p1, "b") == 0, "split[1]=='b' OK", "split[1] FAILED")
testcheck.check(string.strcmp(p2, "c") == 0, "split[2]=='c' OK", "split[2] FAILED")
# Test 2: 空字符串分割
# Test 2: no delimiter
testcheck.section("Test 2: 无分隔符 'hello'")
s2: str = "hello"
s2.__mbuddy__ = bd
@@ -131,7 +131,7 @@ def main() -> CInt | CExport:
h0: str = parts2.get(0)
testcheck.check(string.strcmp(h0, "hello") == 0, "no-delim[0]=='hello' OK", "no-delim[0] FAILED")
# Test 3: 连续分隔符
# Test 3: consecutive delimiters
testcheck.section("Test 3: 连续分隔符 'a,,b'")
s3: str = "a,,b"
s3.__mbuddy__ = bd
@@ -147,7 +147,7 @@ def main() -> CInt | CExport:
testcheck.check(string.strcmp(e1, "") == 0, "consec[1]=='' OK", "consec[1] FAILED")
testcheck.check(string.strcmp(e2, "b") == 0, "consec[2]=='b' OK", "consec[2] FAILED")
# Test 4: 空字符串
# Test 4: empty string
testcheck.section("Test 4: 空字符串 ''")
s4: str = ""
s4.__mbuddy__ = bd
@@ -156,7 +156,7 @@ def main() -> CInt | CExport:
stdio.printf("split('', ',') len=%lu\n", n4)
testcheck.check(n4 == 1, "empty len OK (1)", "empty len FAILED expect 1")
# Test 5: 空格分割句子
# Test 5: split on space
testcheck.section("Test 5: 空格分割 'hello world foo'")
s5: str = "hello world foo"
s5.__mbuddy__ = bd
@@ -172,7 +172,7 @@ def main() -> CInt | CExport:
testcheck.check(string.strcmp(w1, "world") == 0, "space[1]=='world' OK", "space[1] FAILED")
testcheck.check(string.strcmp(w2, "foo") == 0, "space[2]=='foo' OK", "space[2] FAILED")
# Test 6: 多字符分隔符 '::'
# Test 6: multi-char delimiter '::'
testcheck.section("Test 6: 多字符分隔符 '::' on 'a::b::c'")
s6: str = "a::b::c"
s6.__mbuddy__ = bd
@@ -188,7 +188,7 @@ def main() -> CInt | CExport:
testcheck.check(string.strcmp(m1, "b") == 0, "multi-colon[1]=='b' OK", "multi-colon[1] FAILED")
testcheck.check(string.strcmp(m2, "c") == 0, "multi-colon[2]=='c' OK", "multi-colon[2] FAILED")
# Test 7: 多字符分隔符 ', ' (逗号+空格)
# Test 7: multi-char delimiter ', '
testcheck.section("Test 7: 多字符分隔符 ', ' on 'hello, world, foo'")
s7: str = "hello, world, foo"
s7.__mbuddy__ = bd
@@ -204,7 +204,7 @@ def main() -> CInt | CExport:
testcheck.check(string.strcmp(cs1, "world") == 0, "comma-space[1]=='world' OK", "comma-space[1] FAILED")
testcheck.check(string.strcmp(cs2, "foo") == 0, "comma-space[2]=='foo' OK", "comma-space[2] FAILED")
# Test 8: 多字符分隔符在首尾
# Test 8: delimiter at edges
testcheck.section("Test 8: 多字符分隔符首尾 '::a::b::'")
s8: str = "::a::b::"
s8.__mbuddy__ = bd
@@ -222,43 +222,43 @@ def main() -> CInt | CExport:
testcheck.check(string.strcmp(ed2, "b") == 0, "edge[2]=='b' OK", "edge[2] FAILED")
testcheck.check(string.strcmp(ed3, "") == 0, "edge[3]=='' OK", "edge[3] FAILED")
# === with 上下文自动注入测试 ===
# --- with-context auto injection ---
testcheck.section("Test 9: with 上下文自动注入 __mbuddy__")
arena2: bytes = stdlib.malloc(65536)
with memhub.MemBuddy(arena2, 65536) as bd2:
# str 变量在 with 上下文内创建,__mbuddy__ 应自动注入(无需手动赋值)
# str created in with-block gets __mbuddy__ injected automatically
w_str: str = "WithTest"
# 验证 __mbuddy__ 已自动注入(非 NULL)
# Verify __mbuddy__ is injected (non-NULL)
w_buddy: memhub.MemBuddy* = w_str.__mbuddy__
testcheck.check(int(w_buddy) != 0, "with inject OK: __mbuddy__ auto-injected", "with inject FAIL: __mbuddy__ is NULL")
# upper() 不需要手动设置 __mbuddy__
# upper() needs no manual __mbuddy__
w_upper: str = w_str.upper()
stdio.printf("with upper('WithTest') = %s\n", w_upper)
testcheck.check(string.strcmp(w_upper, "WITHTEST") == 0, "with upper OK", "with upper FAILED")
# lower() 不需要手动设置 __mbuddy__
# lower() needs no manual __mbuddy__
w_lower: str = w_str.lower()
stdio.printf("with lower('WithTest') = %s\n", w_lower)
testcheck.check(string.strcmp(w_lower, "withtest") == 0, "with lower OK", "with lower FAILED")
# split() 不需要手动设置 __mbuddy__
# split() needs no manual __mbuddy__
w_split_str: str = "x,y,z"
w_parts = w_split_str.split(',')
w_n: sizet = len(w_parts)
stdio.printf("with split('x,y,z') len=%lu\n", w_n)
testcheck.check(w_n == 3, "with split len OK (3)", "with split len FAILED")
# 验证多个 str 变量都获得注入
# Verify multiple str vars all get injection
w_str2: str = "Multiple"
w_buddy2: memhub.MemBuddy* = w_str2.__mbuddy__
testcheck.check(int(w_buddy2) != 0, "with multi inject OK", "with multi inject FAIL")
test_s: str = "www.gvsds.com"
list_s: list[str]* = test_s.split('.')
# 迭代器测试: for idx, i in zip(range(len(list_s)), list_s)
# Iterator test: zip over range and list
iter_count: int = 0
for iter_idx, i in zip(range(len(list_s)), list_s):
stdio.printf("list_s[%d]='%s'\n", iter_idx, i)
@@ -267,7 +267,7 @@ def main() -> CInt | CExport:
#for i in range(3):
# stdio.printf("list_s[%d]='%s'\n", i, list_s[i])
# === zip() 内置测试 ===
# --- zip() builtin ---
testcheck.section("Test 10: zip(list, list) 元组解包")
za: str = "a,b,c"
zb: str = "1,2,3"
+4 -8
View File
@@ -5,9 +5,7 @@ import stdio
import testcheck
# ============================================================
# FormatStringTest - 格式化字符串回归测试
# ============================================================
# FormatStringTest - format string regression test
export def main() -> int:
testcheck.begin("FormatStringTest: Format String Regression")
@@ -31,14 +29,12 @@ export def main() -> int:
print("Dec: ", f"{42:d}")
print("Float: ", f"{3.14159:.2f}")
# f-string 赋值测试(验证不再直接 printf,而是生成字符串)
# f-string assignment: must build a string, not printf directly
s: str = f"Value=0x{ULONGLONG(42)}, Hex=0x{ULONGLONG(0x11):016X}"
print("Assigned: ", s)
# ctraits.isptr 编译时类型判断测试
# &s 取的是局部变量 s(str = i8*)的地址,结果是 i8**(char**);
# 与 INTPTR(= int*,见 includes/stdint.vp)层数与基座都不同,
# 且指针隐式转换已收紧(层数必须相同)⇒ 注解按实际类型写 str*(= i8**)。
# ctraits.isptr compile-time type check.
# &s is i8** (char**); implicit pointer casts require matching depth, so annotate str*.
ptr_var: str* = &s
val_var: int = 42
if c.CIf(ctraits.isptr(ptr_var)):
+2 -3
View File
@@ -4,9 +4,8 @@ import testcheck
from linkedlist import GSListNode
# ============================================================
# G3: 测试 F-bounded polymorphism
# class Node(GSListNode[Node]) — 继承泛型基类,特化自身为类型参数
# 这与 TransPyV 中 class Value(GSListNode[Value]) 是相同的模式
# G3: test F-bounded polymorphism.
# class Node(GSListNode[Node]) inherits a generic base specialized on itself.
# ============================================================
@t.NoVTable
+6 -8
View File
@@ -6,15 +6,13 @@ from g4node import G4Node, new_g4node
# ============================================================
# caller1: 导入 G4Node 并直接访问 Next 字段(不通过访问器)
#
# 模拟 TransPyV/HandlesExprCall.py 的情况:
# 直接访问 n.Next 触发 GEP 指令,若 stub 字段缺失则 GEP 越界
# caller1: import G4Node and access the Next field directly (no accessor).
# Direct n.Next access emits a GEP; a missing stub field makes it out of bounds.
# ============================================================
def caller1_make_chain(pool: memhub.MemBuddy*) -> G4Node*:
"""创建 3 节点链表,直接访问 Next 字段"""
"""Create a 3-node chain, accessing Next directly."""
a: G4Node* = new_g4node(pool)
b: G4Node* = new_g4node(pool)
c: G4Node* = new_g4node(pool)
@@ -23,19 +21,19 @@ def caller1_make_chain(pool: memhub.MemBuddy*) -> G4Node*:
a.IntVal = 100
b.IntVal = 200
c.IntVal = 300
# 直接访问 Next 字段(不通过 g4node_set_next 访问器)
# Access Next directly (bypass g4node_set_next).
a.Next = b
b.Next = c
return a
def caller1_sum_chain(head: G4Node*) -> int:
"""遍历链表求和,直接访问 Next 字段"""
"""Sum the chain by walking Next directly."""
if head is None:
return 0
total: int = head.IntVal
cur: G4Node* = head
# 直接访问 Next 字段(不通过 g4node_get_next 访问器)
# Access Next directly (bypass g4node_get_next).
while cur.Next is not None:
cur = cur.Next
total = total + cur.IntVal
+4 -5
View File
@@ -6,14 +6,13 @@ from g4node import G4Node, new_g4node
# ============================================================
# caller2: 另一个导入 G4Node 的模块
#
# 增加 G4Node 的跨模块引用次数,触发多模块竞争条件
# caller2: a second module importing G4Node.
# Raises cross-module reference count to stress multi-module handling.
# ============================================================
def caller2_reverse_chain(head: G4Node*) -> G4Node*:
"""反转链表,直接访问 Next 字段"""
"""Reverse the chain, accessing Next directly."""
if head is None:
return None
prev: G4Node* = None
@@ -27,7 +26,7 @@ def caller2_reverse_chain(head: G4Node*) -> G4Node*:
def caller2_count_nodes(head: G4Node*) -> int:
"""计算链表节点数"""
"""Count the chain nodes."""
count: int = 0
cur: G4Node* = head
while cur is not None:
+4 -5
View File
@@ -6,14 +6,13 @@ from g4node import G4Node, new_g4node
# ============================================================
# caller3: 第三个导入 G4Node 的模块
#
# 进一步增加跨模块引用,模拟 TransPyV 30+ 模块环境
# caller3: a third module importing G4Node.
# Adds more cross-module references (many-module environment).
# ============================================================
def caller3_find_tail(head: G4Node*) -> G4Node*:
"""找到链表尾部节点,直接访问 Next"""
"""Find the chain tail, accessing Next directly."""
if head is None:
return None
cur: G4Node* = head
@@ -23,7 +22,7 @@ def caller3_find_tail(head: G4Node*) -> G4Node*:
def caller3_append(head: G4Node*, new_node: G4Node*) -> G4Node*:
"""在链表末尾追加节点"""
"""Append a node at the chain tail."""
if head is None:
return new_node
tail: G4Node* = caller3_find_tail(head)
+6 -9
View File
@@ -9,12 +9,9 @@ import caller2
import caller3
# ============================================================
# G4: 验证 includes 中继承 GSListNode[X] 的类是否会出现
# Next 字段缺失或类型降级的问题
#
# G4Node 类在 includes/g4node.py 中(走 Phase1 路径)
# G4Node 有 5 个自有字段 + 1 个继承字段(Next) = 6 字段
# caller1/caller2/caller3 模拟 TransPyV 多模块环境
# G4: verify a class inheriting GSListNode[X] from includes keeps its
# inherited Next field (no missing field / type downgrade).
# caller1/caller2/caller3 reproduce a multi-module environment.
# ============================================================
@@ -84,7 +81,7 @@ def test_g4node_chain():
def test_caller1_direct_access():
"""caller1: 直接访问 Next 字段(不通过访问器)"""
"""caller1: access Next directly (no accessor)."""
testcheck.section("Test 4: caller1 direct Next access")
arena: bytes = stdlib.malloc(8192)
if arena is None:
@@ -101,7 +98,7 @@ def test_caller1_direct_access():
def test_caller2_reverse():
"""caller2: 反转链表直接访问 Next"""
"""caller2: reverse the chain, accessing Next directly."""
testcheck.section("Test 5: caller2 reverse chain")
arena: bytes = stdlib.malloc(8192)
if arena is None:
@@ -121,7 +118,7 @@ def test_caller2_reverse():
def test_caller3_append():
"""caller3: 追加节点直接访问 Next"""
"""caller3: append a node, accessing Next directly."""
testcheck.section("Test 6: caller3 append node")
arena: bytes = stdlib.malloc(8192)
if arena is None:
+8 -16
View File
@@ -3,25 +3,17 @@ from linkedlist import GSListNode
import memhub
# ============================================================
# G4Node: 继承 GSListNode[G4Node] 的测试类
#
# 这个类在 includes 目录中,会走 Phase1 路径
# 模拟 TransPyV 中 Value 类的结构:
# - 继承 GSListNode[G4Node] 获取 Next 字段
# - 5 个自有字段(与 Value 相同数量)
# - @t.NoVTable 装饰器
#
# 继承展平后应有 6 个字段:Next + 5 自有
# 若继承展平失败,只有 5 个字段(缺少 Next)
# G4Node: test class inheriting GSListNode[G4Node] (in includes, so it uses
# the Phase1 path); flattened it must have 6 fields: Next + 5 own fields.
# ============================================================
@t.NoVTable
class G4Node(GSListNode[G4Node]):
Ty: t.CPtr # 模拟 Value.Ty
Name: t.CPtr # 模拟 Value.Name
IsConst: int # 模拟 Value.IsConst
IntVal: int64 # 模拟 Value.IntVal
FloatVal: double # 模拟 Value.FloatVal
Ty: t.CPtr # mirrors Value.Ty
Name: t.CPtr # mirrors Value.Name
IsConst: int # mirrors Value.IsConst
IntVal: int64 # mirrors Value.IntVal
FloatVal: double # mirrors Value.FloatVal
def __init__(self):
self.Ty = None
@@ -32,7 +24,7 @@ class G4Node(GSListNode[G4Node]):
self.Next = None
# 工厂函数(与 __values.py 中的 new_value 类似)
# factory function (similar to new_value in __values.py)
def new_g4node(pool: memhub.MemBuddy*) -> G4Node*:
ptr: G4Node* = pool.alloc(48)
if ptr:
+14 -17
View File
@@ -8,14 +8,12 @@ from linkedlist import GSListNode, GSList
# ============================================================
# G5: 验证 GSList[T] 被降级为 opaque 的问题
#
# 版本 2: 不使用 malloc/MemBuddy,直接用构造函数(像 G3 那样)
# 这样能隔离 GSList opaque 问题
# G5: verify GSList[T] is not degraded to an opaque type; uses direct
# construction (no malloc/MemBuddy) to isolate the issue.
# ============================================================
# G5Node: 继承 GSListNode[G5Node](Phase2 路径,正确特化)
# G5Node: inherits GSListNode[G5Node] (Phase2 path, correct specialization)
@t.NoVTable
class G5Node(GSListNode[G5Node]):
Value: int
@@ -25,9 +23,8 @@ class G5Node(GSListNode[G5Node]):
self.Value = 0
# G5ListWrapper: 包装 GSList[G5Node],测试 GSList 字段访问
# 注意:GSList[G5Node] 走 Phase2 特化路径
# 用 pool 工厂函数分配 GSList,避免栈分配悬垂指针
# G5ListWrapper: wraps GSList[G5Node] (Phase2 specialization path) to test
# field access; a pool factory allocates it, avoiding dangling stack pointers.
define GSLIST_SIZE = 24 # Head(8) + Tail(8) + Count(8)
@t.NoVTable
@@ -44,7 +41,7 @@ class G5ListWrapper:
# ============================================================
# Test 1: G5Node 字段访问(基准测试,应通过)
# Test 1: G5Node field access (baseline, should pass)
# ============================================================
def test_g5node_create():
@@ -71,7 +68,7 @@ def test_g5node_next():
# ============================================================
# Test 3: GSList 字段访问 — 核心测试
# Test 3: GSList field access (core test)
# ============================================================
def test_gslist_create():
@@ -80,7 +77,7 @@ def test_gslist_create():
if lst is None:
testcheck.check(False, "GSList[G5Node]() is None", "FAIL")
return
# 检查初始状态
# check initial state
head: G5Node* = lst.Head
tail: G5Node* = lst.Tail
count: sizet = lst.Count
@@ -106,25 +103,25 @@ def test_gslist_append():
lst.append(b)
lst.append(c)
# 验证 Count
# verify Count
count: sizet = lst.Count
testcheck.check(count == 3, "Count = 3 after 3 appends", "expect 3")
# 验证 Head
# verify Head
head: G5Node* = lst.Head
if head is None:
testcheck.check(False, "Head is None", "FAIL")
return
testcheck.check(head.Value == 1, "Head.Value = 1", "expect 1")
# 验证 Tail
# verify Tail
tail: G5Node* = lst.Tail
if tail is None:
testcheck.check(False, "Tail is None", "FAIL")
return
testcheck.check(tail.Value == 3, "Tail.Value = 3", "expect 3")
# 遍历链表验证顺序
# walk the chain to verify order
sum: int = 0
cur: G5Node* = lst.Head
while cur is not None:
@@ -134,7 +131,7 @@ def test_gslist_append():
# ============================================================
# Test 5: G5ListWrapper.List 字段访问(嵌套 GSList 测试)
# Test 5: G5ListWrapper.List field access (nested GSList, pool alloc)
# ============================================================
def test_wrapper_list_field():
@@ -156,7 +153,7 @@ def test_wrapper_list_field():
n.Value = 999
wrapper.List.append(n)
# 通过 wrapper.List 访问 GSList 字段
# access GSList fields through wrapper.List
head: G5Node* = wrapper.List.Head
if head is None:
testcheck.check(False, "wrapper.List.Head is None", "FAIL")
+23 -54
View File
@@ -4,126 +4,99 @@ from linkedlist import GSListNode, GSList
import memhub
# ============================================================
# G5Node: 继承 GSListNode[G5Node] 的测试节点
#
# 与 __function.py 中的 Line(GSListNode[Line]) 模式相同。
# 这个类在 includes 目录中,走 Phase1 路径。
# Phase1 的 _specialize_member_types 会将 Next 字段类型 T 降级为 i8*
# 而不是 G5Node*(与 TPV 中 Value/Line 类的情况相同)
# ============================================================
# ===== G5Node: test node extending GSListNode[G5Node] =====
# Phase1 _specialize_member_types degrades the Next field type T to i8*, not G5Node*.
@t.NoVTable
class G5Node(GSListNode[G5Node]):
Value: int
# ============================================================
# G5Container: 持有 GSList[G5Node] 字段的容器
#
# 这是 G5 测试的核心:GSList[T] 在 Phase1 中被降级为 opaque,
# 导致 List.Head / List.Tail / List.Count 字段访问无法生成 GEP。
#
# 与 __function.py 中的 Function(GSListNode[Function]):
# Params: GSList[Param] | t.CPtr
# Blocks: GSList[BasicBlock] | t.CPtr
# 模式完全相同。
# ============================================================
# ===== G5Container: container holding a GSList[G5Node] field =====
# In Phase1 GSList[T] is opaque, so List.Head/Tail/Count access emits no GEP.
@t.NoVTable
class G5Container:
List: GSList[G5Node]*
# ============================================================
# 工厂函数(与 __function.py 的 new_line/new_function 模式相同)
# ============================================================
# ===== Factory functions =====
# G5Node 硬编码大小: Next(8) + Value(4) + padding(4) = 16 字节
# G5Node hardcoded size: Next(8) + Value(4) + padding(4) = 16 bytes
define G5NODE_SIZE = 16
def new_g5node(pool: memhub.MemBuddy*) -> G5Node*:
"""从 pool 分配并零初始化一个 G5Node"""
"""Allocate and zero-initialize a G5Node from pool."""
ptr: G5Node* = pool.alloc(G5NODE_SIZE)
if ptr is None: return None
string.memset(ptr, 0, G5NODE_SIZE)
return ptr
# GSList 硬编码大小: Head(8) + Tail(8) + Count(8) = 24 字节
# GSList hardcoded size: Head(8) + Tail(8) + Count(8) = 24 bytes
define G5LIST_SIZE = 24
def new_g5list(pool: memhub.MemBuddy*) -> GSList[G5Node]*:
"""从 pool 分配并零初始化一个 GSList 容器(Head/Tail/Count 全零)"""
"""Allocate and zero-initialize a GSList container from pool."""
gsl: t.CPtr = pool.alloc(G5LIST_SIZE)
if gsl is None: return None
string.memset(gsl, 0, G5LIST_SIZE)
return gsl
# G5Container 硬编码大小: List(8) = 8 字节
# G5Container hardcoded size: List(8) = 8 bytes
define G5CONTAINER_SIZE = 8
def new_g5container(pool: memhub.MemBuddy*) -> G5Container*:
"""从 pool 分配并零初始化一个 G5Container"""
"""Allocate and zero-initialize a G5Container from pool."""
ptr: G5Container* = pool.alloc(G5CONTAINER_SIZE)
if ptr is None: return None
string.memset(ptr, 0, G5CONTAINER_SIZE)
return ptr
# ============================================================
# 字段访问器(供其他模块绕过 stub 类型限制使用)
#
# 跨模块编译时,使用方模块只有 GSList 的 stub 类型(opaque),
# 导致 TransPyC 静默跳过字段访问(不生成 GEP,不报错),
# 字段值永远为 null。
#
# 这些访问器在拥有完整类型定义的本模块内执行,能正确访问
# 所有字段。其他模块通过函数调用获取字段值,绕过 stub 限制。
# ============================================================
# ===== Field accessors (bypass stub-type limits in other modules) =====
# Cross-module GSList is opaque, so field access silently emits no GEP; these run here.
def g5list_get_head(lst: GSList[G5Node]*) -> G5Node*:
"""获取链表头节点"""
"""Get the list head node."""
if lst is None: return None
return lst.Head
def g5list_get_tail(lst: GSList[G5Node]*) -> G5Node*:
"""获取链表尾节点"""
"""Get the list tail node."""
if lst is None: return None
return lst.Tail
def g5list_get_count(lst: GSList[G5Node]*) -> sizet:
"""获取链表节点数"""
"""Get the list node count."""
if lst is None: return 0
return lst.Count
def g5list_set_head(lst: GSList[G5Node]*, node: G5Node*):
"""设置链表头节点"""
"""Set the list head node."""
if lst is None: return
lst.Head = node
def g5list_set_tail(lst: GSList[G5Node]*, node: G5Node*):
"""设置链表尾节点"""
"""Set the list tail node."""
if lst is None: return
lst.Tail = node
def g5list_set_count(lst: GSList[G5Node]*, count: sizet):
"""设置链表节点数"""
"""Set the list node count."""
if lst is None: return
lst.Count = count
def g5list_append(lst: GSList[G5Node]*, node: G5Node*):
"""将 node 追加到链表末尾(O(1))
直接操作 Head/Tail/Count 字段,不依赖 GSList.append 方法
(因为跨模块时方法实现可能缺失)
"""Append node to the list end (O(1)) by directly updating
Head/Tail/Count, since GSList.append may be missing cross-module.
"""
if lst is None or node is None: return
node.Next = None
@@ -135,9 +108,7 @@ def g5list_append(lst: GSList[G5Node]*, node: G5Node*):
lst.Count += 1
# ============================================================
# G5Node 访问器
# ============================================================
# ===== G5Node accessors =====
def g5node_get_value(node: G5Node*) -> int:
if node is None: return 0
@@ -159,9 +130,7 @@ def g5node_set_next(node: G5Node*, next_node: G5Node*):
node.Next = next_node
# ============================================================
# G5Container 访问器
# ============================================================
# ===== G5Container accessors =====
def g5container_get_list(container: G5Container*) -> GSList[G5Node]*:
if container is None: return None
+7 -12
View File
@@ -4,24 +4,19 @@ import testcheck
import atom
# ============================================================
# G6: 验证 atom 模块的内联汇编原子操作
#
# TPV 在编译 atom.py 的 __atomic_test_and_set 时崩溃
# (ACCESS_VIOLATION in ASM args loop ai3=2)
# 此测试用 TPC 编译验证 atom 模块是否正确工作
# ============================================================
# G6: verify the atom module's inline-asm atomic operations.
# Compiled with TPC to validate atom behavior in this area.
def test_atomic_test_and_set():
testcheck.section("Test 1: __atomic_test_and_set")
flag: uint8 = 0
result: bool = atom.__atomic_test_and_set(&flag, atom.ATOMIC_ACQUIRE)
# test_and_set 返回旧值: flag=0 -> 返回 0, flag 变为 1
# test_and_set returns the old value: flag=0 returns 0 and sets flag=1
testcheck.check(result == bool(0), "first set returns old value 0", "expect 0")
testcheck.check(flag == 1, "flag is 1 after set", "expect 1")
# 第二次设置应返回 1(旧值已为 1)
# Second set returns 1 because the old value is now 1.
result2: bool = atom.__atomic_test_and_set(&flag, atom.ATOMIC_ACQUIRE)
testcheck.check(result2 == bool(1), "second set returns old value 1", "expect 1")
@@ -35,7 +30,7 @@ def test_atomic_clear():
def test_atomic_thread_fence():
testcheck.section("Test 3: __atomic_thread_fence")
# 只是验证不崩溃
# Only checks that the call does not crash.
atom.__atomic_thread_fence(atom.ATOMIC_SEQ_CST)
testcheck.ok("mfence executed OK")
@@ -51,12 +46,12 @@ def test_atomic_spinlock():
testcheck.section("Test 5: spinlock pattern (test_and_set + clear)")
lock: uint8 = 0
# 获取锁
# Acquire the lock
while atom.__atomic_test_and_set(&lock, atom.ATOMIC_ACQUIRE) == bool(1):
pass
testcheck.check(lock == 1, "lock acquired", "expect lock=1")
# 释放锁
# Release the lock
atom.__atomic_clear(&lock, atom.ATOMIC_RELEASE)
testcheck.check(lock == 0, "lock released", "expect lock=0")
+6 -13
View File
@@ -5,20 +5,13 @@ import stdlib
import memhub
from conflict_node import Value
# ============================================================
# 关键冲突点:全局变量名 'Value' 与类名 'Value' 相同
#
# LlvmGenerator 预处理扫描会将 'Value' 注册为 IsVariable=True
# 覆盖 SymbolTable 中的类条目。
# 之后 _get_or_create_struct('Value') 发现 IsVariable=True,
# 返回 _TypedPointerType 而非 IdentifiedStructType,
# 导致 _TryLoadStructFromStub 中 set_body 被跳过。
# ============================================================
# G7: global variable 'Value' collides with class 'Value'
# Variable registration overrides the struct symbol, so struct body setup is skipped.
Value: t.CPtr = None
def test_value_struct_fields():
"""验证 Value struct 有 6 个字段(Next + 5 自有)"""
"""Verify the Value struct has 6 fields (Next + 5 own)."""
testcheck.section("Value struct field access (6 fields expected)")
arena: bytes = stdlib.malloc(4096)
if arena is None:
@@ -29,15 +22,15 @@ def test_value_struct_fields():
if node is None:
testcheck.check(False, "alloc Value", "FAIL")
return
# 写入字段 0 (Next, 继承自 GSListNode)
# Field 0: Next (inherited from GSListNode)
node.Next = None
# 写入字段 1-5 (自有字段)
# Fields 1-5: own fields
node.Ty = None
node.Name = None
node.IsConst = 1
node.IntVal = 42
node.FloatVal = 3.14
# 读取验证
# Read back and verify
v: int = node.IntVal
testcheck.check(v == 42, "Value.IntVal = 42", "expect 42")
f: double = node.FloatVal
+2 -11
View File
@@ -1,17 +1,8 @@
import t
from linkedlist import GSListNode
# ============================================================
# 最小化复现:类名 'Value' 与全局变量名冲突
#
# 这个类在 includes 目录中(走 Phase1 路径),生成 stub.ll
# 继承 GSListNode[Value] 获取 Next 字段
# 5 个自有字段 + 1 个继承字段(Next) = 6 字段
#
# 若 _get_or_create_struct('Value') 因 SymbolTable 中
# IsVariable=True 而返回 _TypedPointerType,
# 则 set_body 被跳过,struct 保持不完整 → GEP 越界崩溃
# ============================================================
# Minimal repro: class name 'Value' collides with global variable name.
# GSListNode[Value] supplies Next; if the struct body is skipped, GEP overruns crash.
@t.NoVTable
class Value(GSListNode[Value]):
+7 -7
View File
@@ -7,7 +7,7 @@ import stdlib
import testcheck
# === 函数泛型 ===
# === Generic functions ===
def add[T](a: T, b: T) -> T:
return a + b
@@ -28,7 +28,7 @@ def double_add[T](a: T, b: T) -> T:
return add(a, b) + add(a, b)
# === 结构体泛型 ===
# === Generic structs ===
class A[T]():
a: T
@@ -77,7 +77,7 @@ def main() -> CInt | CExport:
buf: CChar | CPtr = CPtr(stdlib.malloc(256))
# === 基础函数泛型 ===
# === Basic generic functions ===
testcheck.section("基础函数泛型")
print(add(3, 5))
print(add(1.5, 2.5))
@@ -87,7 +87,7 @@ def main() -> CInt | CExport:
print(double_add(5, 7))
testcheck.ok("基础函数泛型测试完成")
# === 基础结构体泛型 ===
# === Basic generic structs ===
testcheck.section("基础结构体泛型")
a = A(100)
print(a.get_a())
@@ -96,7 +96,7 @@ def main() -> CInt | CExport:
print(p1.get_second())
testcheck.ok("基础结构体泛型测试完成")
# === 泛型 + OOP 组合 ===
# === Generic + OOP combined ===
testcheck.section("泛型 + OOP 组合")
calc1 = Calculator(10)
print(calc1.compute(5))
@@ -108,7 +108,7 @@ def main() -> CInt | CExport:
print(c1_gen.get_flag())
testcheck.ok("泛型 + OOP 组合测试完成")
# === snprintf 格式化 ===
# === snprintf formatting ===
testcheck.section("snprintf 格式化")
viperlib.snprintf(buf, 256, "int=%d, float=%.2f", 42, 3.14)
print(buf)
@@ -116,7 +116,7 @@ def main() -> CInt | CExport:
print(buf)
testcheck.ok("snprintf 格式化测试完成")
# === 新语法类型强转 (t1|t2)(x) ===
# === New cast syntax (t1|t2)(x) ===
testcheck.section("新语法类型强转 (t1|t2)(x)")
val_i64: CUInt64T = CUInt64T(42)
val_i32 = (int)(val_i64)
+10 -10
View File
@@ -3,7 +3,7 @@ import stdio
import testcheck
# ============================================================
# Test 1: 泛型函数 - 基本加法
# Test 1: generic function, basic addition
# ============================================================
def add[T](a: T, b: T) -> T:
return a + b
@@ -15,7 +15,7 @@ def test_generic_add():
testcheck.check(r1 == 8 and r2 == 300, "generic add (3+5=8, 100+200=300)", "generic add expect 8 and 300")
# ============================================================
# Test 2: 泛型函数 - 多类型参数
# Test 2: generic function, multiple type parameters
# ============================================================
def combine[T1, T2](a: T1, b: T2) -> T1:
return a + T1(b)
@@ -26,7 +26,7 @@ def test_generic_combine():
testcheck.check(r == 30, "generic combine (10+T1(20)=30)", "generic combine expect 30")
# ============================================================
# Test 3: 泛型函数 - 最大值
# Test 3: generic function, maximum
# ============================================================
def max_val[T](a: T, b: T) -> T:
if a > b:
@@ -40,7 +40,7 @@ def test_generic_max():
testcheck.check(r1 == 20 and r2 == 50, "generic max (max(10,20)=20, max(50,30)=50)", "generic max expect 20 and 50")
# ============================================================
# Test 4: 泛型类 - Box[T]
# Test 4: generic class Box[T]
# ============================================================
class Box[T]():
value: T
@@ -61,7 +61,7 @@ def test_generic_box():
testcheck.check(v == 42, "Box[int] (get=42)", "Box[int] expect 42")
# ============================================================
# Test 5: 泛型类 - Pair[T1, T2]
# Test 5: generic class Pair[T1, T2]
# ============================================================
class Pair[T1, T2]():
first: T1
@@ -81,7 +81,7 @@ def test_generic_pair():
testcheck.check(r == 30, "Pair[int,int] (sum=30)", "Pair[int,int] expect 30")
# ============================================================
# Test 6: list[T, N] 固定数组
# Test 6: list[T, N] fixed array
# ============================================================
def test_fixed_array():
testcheck.section("Test 6: list[T, N] fixed array")
@@ -95,7 +95,7 @@ def test_fixed_array():
testcheck.check(total == 100, "fixed array (total=100)", "fixed array expect 100")
# ============================================================
# Test 7: list[t.CChar, N] 字符数组
# Test 7: list[t.CChar, N] char array
# ============================================================
def test_char_array():
testcheck.section("Test 7: list[t.CChar, N] char array")
@@ -106,7 +106,7 @@ def test_char_array():
testcheck.check(buf[0] == 72 and buf[1] == 105, "char array (H=72 i=105)", "char array expect H=72 i=105")
# ============================================================
# Test 8: 泛型函数多次特化
# Test 8: generic function specialized multiple times
# ============================================================
def identity[T](x: T) -> T:
return x
@@ -118,7 +118,7 @@ def test_generic_identity():
testcheck.check(r1 == 42 and r2 == 0, "identity (42=42, 0=0)", "identity expect 42 and 0")
# ============================================================
# Test 9: 泛型函数嵌套调用
# Test 9: generic function nested call
# ============================================================
def double_val[T](x: T) -> T:
return add(x, x)
@@ -129,7 +129,7 @@ def test_generic_nested():
testcheck.check(r == 42, "generic nested (double(21)=42)", "generic nested expect 42")
# ============================================================
# Test 10: 泛型类方法调用
# Test 10: generic class method call
# ============================================================
class Counter[T]():
count: T
+18 -19
View File
@@ -4,7 +4,7 @@ import c
import testcheck
# ============================================================
# Test 1: 泛型函数 - 不同整数类型特化
# Test 1: generic function with different int type specializations
# ============================================================
def square[T](x: T) -> T:
return x * x
@@ -16,7 +16,7 @@ def test_generic_square_types():
testcheck.check(r1 == 25 and r2 == 100, "square (5^2=25 10^2=100)", "square expect 25 100")
# ============================================================
# Test 2: 泛型函数 - 三参数
# Test 2: generic function with three parameters
# ============================================================
def clamp[T](val: T, lo: T, hi: T) -> T:
if val < lo:
@@ -33,7 +33,7 @@ def test_generic_clamp():
testcheck.check(r1 == 5 and r2 == 0 and r3 == 10, "clamp (5 0 10)", "clamp expect 5 0 10")
# ============================================================
# Test 3: 泛型类 - Stack[T]
# Test 3: generic class Stack[T]
# ============================================================
class Stack[T]():
data: t.CArray[int, 16]
@@ -63,8 +63,8 @@ class Stack[T]():
def test_generic_stack():
testcheck.section("Test 3: generic Stack[T]")
# 显式标注 Stack[int]:T 无法从实参推断(__init__ 无参),且 T 决定
# push/pop 的元素宽度(t.CInt(val) ↔ i32),静默默认 int 已被禁止。
# Annotate Stack[int] explicitly: T is not inferable (no-arg __init__) and
# sets push/pop element width; implicit int default is forbidden.
s = Stack[int]()
s.push(10)
s.push(20)
@@ -75,7 +75,7 @@ def test_generic_stack():
testcheck.check(r1 == 30 and r2 == 20 and r3 == 10, "Stack (pop=30 20 10)", "Stack expect 30 20 10")
# ============================================================
# Test 4: 泛型函数 - swap via pointer
# Test 4: generic swap via pointer
# ============================================================
class IntPair:
a: int
@@ -95,7 +95,7 @@ def test_generic_swap():
testcheck.check(p.a == 200 and p.b == 100, "swap (a=200 b=100)", "swap expect 200 100")
# ============================================================
# Test 5: 泛型类 - Range[T] 迭代器
# Test 5: generic iterable class Range[T]
# ============================================================
class Range[T]():
start: T
@@ -117,12 +117,12 @@ class Range[T]():
def test_generic_range():
testcheck.section("Test 5: generic Range[T]")
r = Range(0, 10, 1) # 0+1+2+...+9=45
r = Range(0, 10, 1) # sum 0..9 = 45
s: int = r.sum_all()
testcheck.check(s == 45, "Range sum (0..9=45)", "Range sum expect 45")
# ============================================================
# Test 6: 泛型函数 - 数组求和(非泛型数组参数)
# Test 6: generic function summing a fixed-size array argument
# ============================================================
def array_sum(arr: t.CArray[int, 8], n: int) -> int:
result: int = 0
@@ -139,7 +139,7 @@ def test_generic_array_sum():
testcheck.check(s == 360, "array sum (360)", "array sum expect 360")
# ============================================================
# Test 7: 泛型函数 - 比较并返回较大值
# Test 7: generic function returning the max of three values
# ============================================================
def max_of_three[T](a: T, b: T, c_val: T) -> T:
m: T = a
@@ -157,7 +157,7 @@ def test_generic_max_three():
testcheck.check(r1 == 3 and r2 == 30 and r3 == 50, "max3 (3 30 50)", "max3 expect 3 30 50")
# ============================================================
# Test 8: 泛型类 - 带方法的容器
# Test 8: generic container class with methods
# ============================================================
class Container[T]():
values: t.CArray[int, 8]
@@ -187,8 +187,8 @@ class Container[T]():
def test_generic_container():
testcheck.section("Test 8: generic Container[T]")
# 显式标注 Container[int]:__init__ 无参 ⇒ T 无从推断;
# 元素由 add(10)/contains(20)/total() 证据确定是 int(t.CArray[t.CInt, 8])。
# Annotate Container[int] explicitly: no-arg __init__ gives no T to infer;
# int is inferred from usage; storage is CArray[int, 8].
c = Container[int]()
c.add(10)
c.add(20)
@@ -199,7 +199,7 @@ def test_generic_container():
testcheck.check(has20 == 1 and has99 == 0 and total == 60, "Container (has20=1 has99=0 total=60)", "Container expect 1 0 60")
# ============================================================
# Test 9: 泛型函数 - 阶乘
# Test 9: generic factorial
# ============================================================
def factorial[T](n: T) -> T:
result: T = T(1)
@@ -216,7 +216,7 @@ def test_generic_factorial():
testcheck.check(r1 == 120 and r2 == 3628800, "factorial (5!=120 10!=3628800)", "factorial expect 120 3628800")
# ============================================================
# Test 10: 泛型类 - 累加器
# Test 10: generic accumulator class
# ============================================================
class Accumulator[T]():
total: T
@@ -240,13 +240,12 @@ def test_generic_accumulator():
testcheck.check(r == 60, "Accumulator (result=60)", "Accumulator expect 60")
# ============================================================
# Test 11: 泛型结构体 sizeof (修复验证)
# 特化后 Stack[int] = { [16 x i32], i32 } = 68 字节
# 验证 obj.__sizeof__() 和类内部 self.__sizeof__() 均返回正确大小
# Test 11: generic struct sizeof; specialized Stack[int] is 68 bytes.
# Checks obj.__sizeof__() and in-class self.__sizeof__().
# ============================================================
def test_generic_sizeof_bug():
testcheck.section("Test 11: generic sizeof (fixed)")
# 同 Test 3:无参构造必须显式标注类型实参;Stack[int] = { [16 x i32], i32 } = 68。
# Same as Test 3: no-arg construction needs an explicit type argument; Stack[int] = 68 bytes.
s = Stack[int]()
s.push(10)
sz: sizet = s.__sizeof__()
+7 -15
View File
@@ -2,10 +2,8 @@ import t
import stdio
import testcheck
# ============================================================
# Test 1: 泛型函数手动传类型参数 - 基本调用
# def xxx[T](x: int) 然后调用 xxx[T](x)
# ============================================================
# Test 1: generic function with explicit type arg - basic call
# def xxx[T](x: int) then call xxx[T](x)
def double[T](x: int) -> int:
return x * 2
@@ -14,9 +12,7 @@ def test_explicit_type_arg():
r: int = double[int](21)
testcheck.check(r == 42, "double[t.CInt](21) = 42", "expect 42")
# ============================================================
# Test 2: 泛型函数手动传类型参数 - 多次调用不同类型
# ============================================================
# Test 2: generic function with explicit type arg - multiple call types
def identity[T](x: int) -> int:
return x
@@ -26,9 +22,7 @@ def test_identity_explicit():
r2: int = identity[int](20)
testcheck.check(r1 == 10 and r2 == 20, "identity[t.CInt](10)=10 (20)=20", "expect 10 20")
# ============================================================
# Test 3: 泛型函数手动传类型参数 - 用 T 作为参数类型
# ============================================================
# Test 3: generic function with explicit type arg - T as parameter type
def add_one[T](x: T) -> T:
return x + T(1)
@@ -37,14 +31,12 @@ def test_add_one_explicit():
r: int = add_one[int](41)
testcheck.check(r == 42, "add_one[t.CInt](41) = 42", "expect 42")
# ============================================================
# Test 4: 泛型函数手动传类型参数 - 混合自动推导和手动传
# ============================================================
# Test 4: generic function with explicit type arg - mixed inference
def test_mixed_inference_explicit():
testcheck.section("Test 4: mixed inference and explicit")
# 自动推导
# Inferred
r1: int = add_one(99)
# 手动传
# Explicit
r2: int = add_one[int](99)
testcheck.check(r1 == 100 and r2 == 100, "add_one(99)=100 add_one[t.CInt](99)=100", "expect 100 100")
+7 -17
View File
@@ -2,9 +2,7 @@ import t
import stdio
import testcheck
# ============================================================
# Test 1: 泛型类手动传类型参数 - Box[t.CInt](v)
# ============================================================
# Test 1: generic class with explicit type arg - Box[t.CInt](v)
class Box[T]():
value: T
@@ -23,9 +21,7 @@ def test_explicit_box():
v: int = b.get()
testcheck.check(v == 42, "Box[t.CInt](42).get() = 42", "expect 42")
# ============================================================
# Test 2: 泛型类手动传类型参数 - Pair[t.CInt, t.CInt]
# ============================================================
# Test 2: generic class with explicit type arg - Pair[t.CInt, t.CInt]
class Pair[T1, T2]():
first: T1
second: T2
@@ -43,9 +39,7 @@ def test_explicit_pair():
r: int = p.sum_as_int()
testcheck.check(r == 30, "Pair[t.CInt,t.CInt](10,20).sum = 30", "expect 30")
# ============================================================
# Test 3: 泛型类手动传 + 自动推导混合
# ============================================================
# Test 3: generic class explicit + inferred mixed
class Wrapper[T]():
data: T
@@ -57,17 +51,15 @@ class Wrapper[T]():
def test_mixed_generic_class():
testcheck.section("Test 3: mixed explicit and inferred")
# 手动传
# Explicit
w1 = Wrapper[int](100)
# 自动推导
# Inferred
w2 = Wrapper(200)
r1: int = w1.get()
r2: int = w2.get()
testcheck.check(r1 == 100 and r2 == 200, "Wrapper[t.CInt](100)=100 Wrapper(200)=200", "expect 100 200")
# ============================================================
# Test 4: 泛型类手动传 - 方法调用
# ============================================================
# Test 4: generic class explicit - method calls
class Counter[T]():
count: T
@@ -89,9 +81,7 @@ def test_explicit_counter():
r: int = c.get_count()
testcheck.check(r == 3, "Counter[t.CInt](0) +3 = 3", "expect 3")
# ============================================================
# Test 5: 泛型类手动传 - set 方法
# ============================================================
# Test 5: generic class explicit - set method
def test_explicit_box_set():
testcheck.section("Test 5: Box[t.CInt] set method")
b = Box[int](10)
+4 -4
View File
@@ -10,7 +10,7 @@ import w32.win32console
# ==============================================
# 工具函数:打印十六进制哈希串
# Helper: print a hash digest as hex.
# ==============================================
def print_hex(buf: uint8*, length: int):
for i in range(length):
@@ -28,7 +28,7 @@ def main() -> int | t.CExport:
testcheck.begin("HashLibTest: 哈希与校验测试")
# ---------- hashlib 摘要测试 ----------
# ---------- hashlib digest tests ----------
testcheck.section("HASHLIB")
plain: str = "hello123"
@@ -67,7 +67,7 @@ def main() -> int | t.CExport:
default_value_test_function(b=2, a=1)
testcheck.ok("default value test completed")
# ---------- base64 编解码测试 ----------
# ---------- base64 encode/decode tests ----------
testcheck.section("BASE64")
b64_out: t.CArray[char, 256]
b64_dec: t.CArray[uint8, 256]
@@ -78,7 +78,7 @@ def main() -> int | t.CExport:
print("Base64 解码:", b64_dec)
testcheck.ok("BASE64 encode/decode completed")
# ---------- binascii 全套测试 ----------
# ---------- binascii tests ----------
testcheck.section("BINASCII")
binascii.init_binascii()
raw: str = "HelloWorld!"
+18 -19
View File
@@ -16,11 +16,11 @@ def main() -> CInt | CExport:
testcheck.begin("HashTableTest: 开放寻址哈希表测试")
# 分配内存竞技场
# Allocate the memory arena
arena: bytes = stdlib.malloc(65536)
bd: memhub.MemBuddy* = memhub.MemBuddy(arena, 65536)
# === Test 1: 基本插入和查找 ===
# === Test 1: basic insert and lookup ===
testcheck.section("Test 1: 基本插入和查找 (set_int)")
ht: hashtable.HashTable = hashtable.HashTable(bd)
ht.set_int("alpha", 10)
@@ -30,9 +30,8 @@ def main() -> CInt | CExport:
stdio.printf("len=%lu\n", n)
testcheck.check(n == 3, "ht len OK (3)", "ht len FAILED")
# 哈希表的 int 值按 int(i32)写入(见 hashtable.vp set_int 的 int_ptr),读回
# 须给出有元素类型的指针:c.Deref 的宽度只认 pointee 类型,i8*(t.CPtr)恒读
# 1 字节,不再按赋值目标注解反推 4 字节。
# set_int stores the value as i32; read it back through a typed pointer, since
# c.Deref width follows the pointee type and i8* (t.CPtr) always reads 1 byte.
p1: t.CPtr = ht["alpha"]
v1: int = *(int*)(p1)
p2: t.CPtr = ht["beta"]
@@ -44,7 +43,7 @@ def main() -> CInt | CExport:
testcheck.check(v2 == 20, "ht[beta]==20 OK", "ht[beta] FAILED")
testcheck.check(v3 == 30, "ht[gamma]==30 OK", "ht[gamma] FAILED")
# === Test 2: 更新已有键 ===
# === Test 2: update existing key ===
testcheck.section("Test 2: 更新已有键")
ht.set_int("beta", 99)
p2b: t.CPtr = ht["beta"]
@@ -70,7 +69,7 @@ def main() -> CInt | CExport:
testcheck.check(has_alpha == 1, "contains alpha OK", "contains alpha FAILED")
testcheck.check(has_missing == 0, "not contains missing OK", "contains missing FAILED")
# === Test 5: 删除 ===
# === Test 5: delete ===
testcheck.section("Test 5: 删除 (del)")
deleted: int = ht.__delitem__("beta")
stdio.printf("del beta=%d\n", deleted)
@@ -79,11 +78,11 @@ def main() -> CInt | CExport:
has_beta: int = "beta" in ht
testcheck.check(has_beta == 0, "beta gone OK", "beta still exists FAILED")
# 删除不存在的 key
# Delete a nonexistent key
del_missing: int = ht.__delitem__("nokey")
testcheck.check(del_missing == 0, "del missing returns 0 OK", "del missing FAILED")
# === Test 6: 删除后重新插入 ===
# === Test 6: re-insert after delete ===
testcheck.section("Test 6: 删除后重新插入")
ht.set_int("beta", 555)
p2c: t.CPtr = ht["beta"]
@@ -92,7 +91,7 @@ def main() -> CInt | CExport:
testcheck.check(v2c == 555, "ht re-insert beta OK", "ht re-insert beta FAILED")
testcheck.check(len(ht) == 3, "ht len 3 after re-insert OK", "ht len after re-insert FAILED")
# === Test 7: 迭代器 ===
# === Test 7: iterator ===
testcheck.section("Test 7: 迭代器 for key in ht")
iter_count: int = 0
for key in ht:
@@ -102,7 +101,7 @@ def main() -> CInt | CExport:
iter_count += 1
testcheck.check(iter_count == 3, "ht iter OK (3)", "ht iter FAILED")
# === Test 8: 字符串值 ===
# === Test 8: string values ===
testcheck.section("Test 8: 字符串值 (set_str)")
ht2: hashtable.HashTable = hashtable.HashTable(bd)
ht2.set_str("name", "Alice")
@@ -119,12 +118,12 @@ def main() -> CInt | CExport:
city: str = city_p
lang: str = lang_p
stdio.printf("name=%s city=%s lang=%s\n", name, city, lang)
# i8* == 是指针地址比较(C-Like 语义),内容比较需显式 strcmp
# i8* == compares pointer addresses (C-like); use strcmp for content
testcheck.check(string.strcmp(name, "Alice") == 0, "ht str name OK", "ht str name FAILED")
testcheck.check(string.strcmp(city, "Beijing") == 0, "ht str city OK", "ht str city FAILED")
testcheck.check(string.strcmp(lang, "TransPyC") == 0, "ht str lang OK", "ht str lang FAILED")
# === Test 9: 扩容测试 ===
# === Test 9: expansion test ===
testcheck.section("Test 9: 扩容测试 (>16 个元素)")
ht3: hashtable.HashTable = hashtable.HashTable(bd)
for i in range(50):
@@ -135,7 +134,7 @@ def main() -> CInt | CExport:
stdio.printf("ht3 len=%lu (after 50 inserts)\n", n3)
testcheck.check(n3 == 50, "ht expand OK (50)", "ht expand FAILED")
# 验证几个值
# Verify some values
k5: str = stdlib.malloc(16)
stdio.sprintf(k5, "key5")
p5: t.CPtr = ht3[k5]
@@ -157,7 +156,7 @@ def main() -> CInt | CExport:
stdio.printf("ht3[key49]=%d\n", v49)
testcheck.check(v49 == 4900, "ht expand key49 OK", "ht expand key49 FAILED")
# === Test 10: 扩容后迭代 ===
# === Test 10: iterate after expansion ===
testcheck.section("Test 10: 扩容后迭代")
iter_count3: int = 0
for k in ht3:
@@ -165,7 +164,7 @@ def main() -> CInt | CExport:
stdio.printf("ht3 iter count=%d\n", iter_count3)
testcheck.check(iter_count3 == 50, "ht expand iter OK (50)", "ht expand iter FAILED")
# === Test 11: 删除后扩容 ===
# === Test 11: operations after batch delete ===
testcheck.section("Test 11: 批量删除后操作")
for j in range(25):
del_buf: str = stdlib.malloc(16)
@@ -175,7 +174,7 @@ def main() -> CInt | CExport:
stdio.printf("ht3 len=%lu (after 25 deletes)\n", n3b)
testcheck.check(n3b == 25, "ht after del OK (25)", "ht after del FAILED")
# 验证剩余的值
# Verify remaining values
k30: str = stdlib.malloc(16)
stdio.sprintf(k30, "key30")
p30: t.CPtr = ht3[k30]
@@ -183,13 +182,13 @@ def main() -> CInt | CExport:
stdio.printf("ht3[key30]=%d\n", v30)
testcheck.check(v30 == 3000, "ht key30 after del OK", "ht key30 after del FAILED")
# 验证已删除的 key 不存在
# Verify the deleted key is gone
k0: str = stdlib.malloc(16)
stdio.sprintf(k0, "key0")
has_k0: int = k0 in ht3
testcheck.check(has_k0 == 0, "ht key0 deleted OK", "ht key0 still exists FAILED")
# === Test 12: 空表操作 ===
# === Test 12: empty table operations ===
testcheck.section("Test 12: 空表操作")
ht4: hashtable.HashTable = hashtable.HashTable(bd)
testcheck.check(len(ht4) == 0, "empty ht len 0 OK", "empty ht len FAILED")
+2 -4
View File
@@ -3,10 +3,8 @@ from t import CInt
# ============================================================
# 跨模块 isinstance 测试库
#
# 供 main.vp import 使用:验证 isinstance 对"定义在其他模块
# 的类"也能正确比较(对象 vtable 指针跨 obj 链接解析)。
# Cross-module isinstance test library: classes defined here are imported by
# main.vp to verify vtable comparison resolves across object files.
# ============================================================
+12 -18
View File
@@ -6,18 +6,12 @@ from t import CInt, CPtr, CExport
# ============================================================
# isinstance 内建函数测试(运行时 vtable 继承链比较)
#
# 场景覆盖:
# 1. CVTable 自身/子类→基类
# 2. 运行时多态(基类指针指向子类对象)
# 3. 元组 (A, B)
# 4. 多继承(AB 同时是 A 和 B 的实例)
# 5. NoVTable 类(编译时静态判断)
# isinstance builtin test: runtime vtable inheritance-chain comparison over
# self/subclass, polymorphism, tuples, multiple inheritance, and NoVTable.
# ============================================================
# ========== CVTable 继承 ==========
# ========== CVTable inheritance ==========
@t.CVTable
class Animal:
@@ -45,7 +39,7 @@ class Cat(Animal):
return "Meow"
# ========== 多继承 ==========
# ========== multiple inheritance ==========
@t.CVTable
class A:
@@ -70,7 +64,7 @@ class AB(A, B):
self.b = b
# ========== NoVTable(编译时判断) ==========
# ========== NoVTable (compile-time) ==========
@t.NoVTable
class Plain:
@@ -80,7 +74,7 @@ class Plain:
def main() -> CInt | CExport:
testcheck.begin("IsinstanceTest: isinstance 内建函数测试")
# --- 1. 自身类型 + 子类→基类 ---
# --- 1. self type and subclass -> base ---
d: Dog | CPtr = Dog("dog")
testcheck.check(isinstance(d, Dog) == 1, "isinstance(d, Dog) 自身 OK",
"isinstance(d, Dog) FAILED")
@@ -89,7 +83,7 @@ def main() -> CInt | CExport:
testcheck.check(isinstance(d, Cat) == 0, "isinstance(d, Cat) 不匹配 OK",
"isinstance(d, Cat) FAILED")
# --- 2. 运行时多态:基类指针指向子类对象 ---
# --- 2. runtime polymorphism: base pointer to subclass object ---
a: Animal | CPtr = (Animal | CPtr)(d)
testcheck.check(isinstance(a, Dog) == 1,
"isinstance(Animal*, Dog 对象) 运行时多态 OK",
@@ -101,13 +95,13 @@ def main() -> CInt | CExport:
"isinstance(Animal*, Cat) 运行时 False OK",
"isinstance(Animal*, Cat) FAILED")
# --- 3. 元组 ---
# --- 3. tuple ---
testcheck.check(isinstance(d, (Cat, Dog)) == 1, "isinstance 元组命中 OK",
"isinstance 元组 FAILED")
testcheck.check(isinstance(d, (Cat, A)) == 0, "isinstance 元组未命中 OK",
"isinstance 元组未命中 FAILED")
# --- 4. 多继承 ---
# --- 4. multiple inheritance ---
ab: AB | CPtr = AB(1, 2)
testcheck.check(isinstance(ab, A) == 1, "isinstance(AB, A) 多继承 OK",
"isinstance(AB, A) FAILED")
@@ -118,14 +112,14 @@ def main() -> CInt | CExport:
testcheck.check(ab.get_a() == 1 and ab.get_b() == 2, "AB 字段/方法正常 OK",
"AB 字段/方法 FAILED")
# --- 5. NoVTable(编译时静态判断) ---
# --- 5. NoVTable (compile-time static) ---
p: Plain | CPtr = Plain()
p.v = 42
testcheck.check(isinstance(p, Plain) == 1, "isinstance NoVTable 编译时 OK",
"isinstance NoVTable FAILED")
testcheck.check(p.v == 42, "NoVTable 字段正常 OK", "NoVTable 字段 FAILED")
# --- 6. 跨模块 isinstance(vtable 跨 obj 链接解析) ---
# --- 6. cross-module isinstance (vtable resolved at link time) ---
cc: geom_lib.Circle | CPtr = geom_lib.Circle(5)
testcheck.check(isinstance(cc, geom_lib.Circle) == 1,
"跨模块 isinstance 自身 OK", "跨模块 isinstance 自身 FAILED")
@@ -144,7 +138,7 @@ def main() -> CInt | CExport:
testcheck.check(shp.area() == 5, "跨模块虚方法分派 OK", "跨模块虚方法分派 FAILED")
testcheck.check(cc.area() == 5, "跨模块 Circle.area OK", "跨模块 Circle.area FAILED")
# --- 7. NoVTable 跨模块静态判断 ---
# --- 7. NoVTable cross-module static ---
ps: geom_lib.PlainShape | CPtr = geom_lib.PlainShape()
testcheck.check(isinstance(ps, geom_lib.PlainShape) == 1,
"跨模块 NoVTable 静态 OK", "跨模块 NoVTable 静态 FAILED")
+3 -3
View File
@@ -26,20 +26,20 @@ def test_for_in_char_ptr():
def test_strcpy_for_in():
testcheck.section("Test 3: strcpy using for-in")
src: char* = "test"
# 手动实现 strcpy 用 for-in
# Implement strcpy by hand with for-in.
import w32.win32memory
buf: char* = w32.win32memory.VirtualAlloc(None, 64, 12288, 4)
if uint64(buf) == 0:
stdio.printf("SKIP: VirtualAlloc returned NULL\n")
return
string.memset(buf, 0, 64)
# 用 for-in 复制
# Copy with for-in.
p: char* = buf
for ch in src:
p[0] = ch
p += 1
p[0] = 0
# i8* == 是指针地址比较(C-Like 语义),字符串内容比较需显式 strcmp
# '==' on pointers compares addresses (C-like); use strcmp for contents.
testcheck.check(string.strcmp(buf, "test") == 0, "strcpy for-in (result=test)", "strcpy for-in (cmp mismatch)")
import w32.win32memory
+35 -51
View File
@@ -7,9 +7,7 @@ import string
import w32.win32memory as win32mem
import testcheck
# ============================================================
# 测试 1:构造 JSON 值(使用 mpool)
# ============================================================
# --- Test 1: construct JSON values (with mpool) ---
def test_construct(pool: memhub.MemPool*):
testcheck.section("Construct JsonValue (with mpool)")
@@ -54,13 +52,11 @@ def test_construct(pool: memhub.MemPool*):
testcheck.check(len(v9) == 0, "object empty len()==0", "object empty len()==0")
# ============================================================
# 测试 2:构造数组和对象(Python风格API)
# ============================================================
# --- Test 2: build arrays and objects (Pythonic API) ---
def test_build_structures(pool: memhub.MemPool*):
testcheck.section("Build Arrays and Objects (Pythonic API)")
# 构建数组 [1, 2, 3]
# Build array [1, 2, 3]
arr: json.JsonValue* = json.array(pool)
json.array_append(pool, arr, json.int_val(pool, 1))
json.array_append(pool, arr, json.int_val(pool, 2))
@@ -70,13 +66,13 @@ def test_build_structures(pool: memhub.MemPool*):
testcheck.check(arr.get_item(1).as_int() == 2, "array get_item(1)==2", "array get_item(1)==2")
testcheck.check(arr.get_item(2).as_int() == 3, "array get_item(2)==3", "array get_item(2)==3")
# 构建对象 {"name": "Viper", "version": 1}
# Build object {"name": "Viper", "version": 1}
obj: json.JsonValue* = json.object(pool)
json.object_set(pool, obj, "name", json.string_val(pool, "Viper"))
json.object_set(pool, obj, "version", json.int_val(pool, 1))
testcheck.check(len(obj) == 2, "object len()==2", "object len()==2")
# Python风格取值:obj["key"]
# Pythonic access: obj["key"]
name_val: json.JsonValue* = obj["name"]
testcheck.check(name_val != None and string.strcmp(name_val.as_string(), "Viper") == 0, "obj['name']==Viper", "obj['name']==Viper")
ver_val: json.JsonValue* = obj["version"]
@@ -85,32 +81,30 @@ def test_build_structures(pool: memhub.MemPool*):
testcheck.check(missing == None, "obj['missing']==None", "obj['missing']==None")
# ============================================================
# 测试 3:JSON 解析
# ============================================================
# --- Test 3: parse JSON ---
def test_parse(pool: memhub.MemPool*):
testcheck.section("Parse JSON")
# 解析整数
# Parse int
v1: json.JsonValue* = json.parse(pool, "42")
testcheck.check(v1.is_int(), "parse int is_int", "parse int is_int")
testcheck.check(v1.as_int() == 42, "parse int == 42", "parse int == 42")
# 解析负数
# Parse negative int
v2: json.JsonValue* = json.parse(pool, "-7")
testcheck.check(v2.as_int() == -7, "parse neg int == -7", "parse neg int == -7")
# 解析浮点数
# Parse float
v3: json.JsonValue* = json.parse(pool, "3.14")
testcheck.check(v3.is_float(), "parse float is_float", "parse float is_float")
testcheck.check(v3.as_float() > 3.13 and v3.as_float() < 3.15, "parse float ~= 3.14", "parse float ~= 3.14")
# 解析字符串
# Parse string
v4: json.JsonValue* = json.parse(pool, '"hello world"')
testcheck.check(v4.is_string(), "parse string is_string", "parse string is_string")
testcheck.check(string.strcmp(v4.as_string(), "hello world") == 0, "parse string == hello world", "parse string == hello world")
# 解析布尔
# Parse bool
v5: json.JsonValue* = json.parse(pool, "true")
testcheck.check(v5.is_bool(), "parse true is_bool", "parse true is_bool")
testcheck.check(v5.as_bool(), "parse true as_bool", "parse true as_bool")
@@ -118,18 +112,18 @@ def test_parse(pool: memhub.MemPool*):
v6: json.JsonValue* = json.parse(pool, "false")
testcheck.check(not v6.as_bool(), "parse false !as_bool", "parse false !as_bool")
# 解析 null
# Parse null
v7: json.JsonValue* = json.parse(pool, "null")
testcheck.check(v7.is_null(), "parse null is_null", "parse null is_null")
# 解析数组
# Parse array
v8: json.JsonValue* = json.parse(pool, "[1, 2, 3]")
testcheck.check(v8.is_array(), "parse array is_array", "parse array is_array")
testcheck.check(len(v8) == 3, "parse array len()==3", "parse array len()==3")
testcheck.check(v8.get_item(0).as_int() == 1, "parse array get_item(0)==1", "parse array get_item(0)==1")
testcheck.check(v8.get_item(2).as_int() == 3, "parse array get_item(2)==3", "parse array get_item(2)==3")
# 解析对象(Python风格取值)
# Parse object (Pythonic access)
v9: json.JsonValue* = json.parse(pool, '{"x": 10, "y": 20}')
testcheck.check(v9.is_object(), "parse object is_object", "parse object is_object")
testcheck.check(len(v9) == 2, "parse object len()==2", "parse object len()==2")
@@ -139,23 +133,21 @@ def test_parse(pool: memhub.MemPool*):
testcheck.check(y_val != None and y_val.as_int() == 20, "parse obj['y']==20", "parse obj['y']==20")
# ============================================================
# 测试 4:JSON 序列化
# ============================================================
# --- Test 4: write JSON ---
def test_write(pool: memhub.MemPool*):
testcheck.section("Write JSON")
# 写整数
# Write int
v1: json.JsonValue* = json.int_val(pool, 42)
s1: char* = json.write(pool, v1, False)
testcheck.check(string.strcmp(s1, "42") == 0, "write int 42", "write int 42")
# 写字符串
# Write string
v2: json.JsonValue* = json.string_val(pool, "hello")
s2: char* = json.write(pool, v2, False)
testcheck.check(string.strcmp(s2, '"hello"') == 0, "write string hello", "write string hello")
# 写布尔
# Write bool
v3: json.JsonValue* = json.bool_val(pool, True)
s3: char* = json.write(pool, v3, False)
testcheck.check(string.strcmp(s3, "true") == 0, "write bool true", "write bool true")
@@ -164,12 +156,12 @@ def test_write(pool: memhub.MemPool*):
s4: char* = json.write(pool, v4, False)
testcheck.check(string.strcmp(s4, "false") == 0, "write bool false", "write bool false")
# 写 null
# Write null
v5: json.JsonValue* = json.null(pool)
s5: char* = json.write(pool, v5, False)
testcheck.check(string.strcmp(s5, "null") == 0, "write null", "write null")
# 写数组
# Write array
arr: json.JsonValue* = json.array(pool)
json.array_append(pool, arr, json.int_val(pool, 1))
json.array_append(pool, arr, json.int_val(pool, 2))
@@ -177,7 +169,7 @@ def test_write(pool: memhub.MemPool*):
s6: char* = json.write(pool, arr, False)
testcheck.check(string.strcmp(s6, "[1,2,3]") == 0, "write array [1,2,3]", "write array [1,2,3]")
# 写对象
# Write object
obj: json.JsonValue* = json.object(pool)
json.object_set(pool, obj, "a", json.int_val(pool, 1))
json.object_set(pool, obj, "b", json.string_val(pool, "x"))
@@ -185,9 +177,7 @@ def test_write(pool: memhub.MemPool*):
testcheck.check(s7 != None, "write object non-null", "write object non-null")
# ============================================================
# 测试 5:解析复杂嵌套 JSON(Python风格API)
# ============================================================
# --- Test 5: parse nested JSON (Pythonic API) ---
def test_nested(pool: memhub.MemPool*):
testcheck.section("Parse Nested JSON (Pythonic API)")
@@ -196,7 +186,7 @@ def test_nested(pool: memhub.MemPool*):
testcheck.check(root.is_object(), "nested is_object", "nested is_object")
testcheck.check(len(root) == 4, "nested len()==4", "nested len()==4")
# Python风格取值:root["name"]
# Pythonic access: root["name"]
name: json.JsonValue* = root["name"]
testcheck.check(name != None and string.strcmp(name.as_string(), "Viper") == 0, "root['name']==Viper", "root['name']==Viper")
@@ -204,14 +194,14 @@ def test_nested(pool: memhub.MemPool*):
ver: json.JsonValue* = root["version"]
testcheck.check(ver != None and ver.as_int() == 1, "root['version']==1", "root['version']==1")
# root["features"] 数组
# root["features"] array
feat: json.JsonValue* = root["features"]
testcheck.check(feat != None and feat.is_array(), "root['features'] is_array", "root['features'] is_array")
testcheck.check(feat != None and len(feat) == 3, "root['features'] len()==3", "root['features'] len()==3")
testcheck.check(feat != None and string.strcmp(feat.get_item(0).as_string(), "fast") == 0, "root['features'][0]==fast", "root['features'][0]==fast")
testcheck.check(feat != None and string.strcmp(feat.get_item(2).as_string(), "portable") == 0, "root['features'][2]==portable", "root['features'][2]==portable")
# root["nested"] 对象
# root["nested"] object
nested: json.JsonValue* = root["nested"]
testcheck.check(nested != None and nested.is_object(), "root['nested'] is_object", "root['nested'] is_object")
nk: json.JsonValue* = nested["key"] if nested != None else None
@@ -220,30 +210,28 @@ def test_nested(pool: memhub.MemPool*):
testcheck.check(nn != None and nn.as_int() == 99, "root['nested']['num']==99", "root['nested']['num']==99")
# ============================================================
# 测试 6:mpool 重置后重新使用
# ============================================================
# --- Test 6: reuse mpool after reset ---
def test_mpool_reuse():
testcheck.section("MPool Reuse")
# 分配内存
# Allocate memory
mem: t.CPtr = win32mem.VirtualAlloc(None, 8192, 0x3000, 0x04)
testcheck.check(mem != None, "VirtualAlloc ok", "VirtualAlloc ok")
pool: memhub.MemPool* = memhub.MemPool(mem, 8192)
# 第一次使用
# First use
v1: json.JsonValue* = json.int_val(pool, 100)
testcheck.check(v1.as_int() == 100, "reuse round1 int==100", "reuse round1 int==100")
# 重置 mpool
# Reset mpool
pool.reset()
# 第二次使用(内存复用)
# Second use (reuses memory)
v2: json.JsonValue* = json.string_val(pool, "reused")
testcheck.check(string.strcmp(v2.as_string(), "reused") == 0, "reuse round2 string==reused", "reuse round2 string==reused")
# 重置后再解析
# Reset then parse again
pool.reset()
v3: json.JsonValue* = json.parse(pool, '{"test": true}')
testcheck.check(v3.is_object(), "reuse round3 parse ok", "reuse round3 parse ok")
@@ -253,13 +241,11 @@ def test_mpool_reuse():
win32mem.VirtualFree(mem, 0, 0x8000)
# ============================================================
# 测试 7:转义字符解析
# ============================================================
# --- Test 7: escape characters ---
def test_escape(pool: memhub.MemPool*):
testcheck.section("Escape Characters")
# 解析含转义字符的字符串
# Parse string with escapes
v1: json.JsonValue* = json.parse(pool, '"hello\\nworld"')
testcheck.check(v1.is_string(), "escape \\n is_string", "escape \\n is_string")
sv1: char* = v1.as_string()
@@ -274,13 +260,11 @@ def test_escape(pool: memhub.MemPool*):
testcheck.check(v3.is_string(), "escape \\\" is_string", "escape \\\" is_string")
# ============================================================
# 主函数
# ============================================================
# --- main ---
def main() -> int | t.CExport:
testcheck.begin("JSON Library Test (Pythonic API)")
# 使用 mpool 的 bump 分配器
# Use mpool bump allocator
mem: t.CPtr = win32mem.VirtualAlloc(None, 65536, 0x3000, 0x04)
pool: memhub.MemPool* = memhub.MemPool(mem, 65536)
+64 -134
View File
@@ -6,16 +6,11 @@ import testcheck
import mlirlite
# 内存大小
# 单端 MLIR 后 mlirlite 渲染单次 PrintModule 需约 1 MiB 缩进缓冲 + 类型/初值
# 草稿,且本测试 27 个用例共享**同一个**池(不像 MLIRLiteTest 每用例切子池)
# ⇒ 512 KB 远不够(池耗尽)。与 MLIRLiteTest 主池同口径放大到 80 MiB。
# Pool size: PrintModule needs ~1 MiB scratch and all 27 cases share one pool, so use 80 MiB.
define POOL_SIZE = 83886080 # 80MB
# ============================================================
# 测试 1: TypePrint 类型打印
# ============================================================
# --- Test 1: TypePrint ---
def test_type_print(pool: memhub.MemBuddy*):
testcheck.section("Test 1: TypePrint")
core: mlirlite.LLVMTypeCore* = mlirlite.LLVMTypeCore(pool)
@@ -29,7 +24,7 @@ def test_type_print(pool: memhub.MemBuddy*):
"Int32 -> i32",
"Int32 fail")
# 不透明指针: Ptr(Int32) -> !llvm.ptr
# opaque pointer: Ptr(Int32) -> !llvm.ptr
ty_ptr: mlirlite.LLVMType* = core.Ptr(ty_i32)
buf[0] = 0
core.PrintType(buf, 64, ty_ptr)
@@ -54,9 +49,7 @@ def test_type_print(pool: memhub.MemBuddy*):
"Int64 fail")
# ============================================================
# 测试 2: ValuePrint 值打印
# ============================================================
# --- Test 2: ValuePrint ---
def test_value_print(pool: memhub.MemBuddy*):
testcheck.section("Test 2: ValuePrint")
core: mlirlite.LLVMTypeCore* = mlirlite.LLVMTypeCore(pool)
@@ -65,7 +58,7 @@ def test_value_print(pool: memhub.MemBuddy*):
ty_i32: mlirlite.LLVMType* = core.Int32()
# 常量 42 -> "42 : i32"(MLIR attribute 文本形态)
# const 42 -> "42 : i32" (MLIR attribute text form)
val42: mlirlite.Value* = mcore.ConstInt32(42)
buf[0] = 0
mcore.PrintValue(buf, 64, val42)
@@ -73,7 +66,7 @@ def test_value_print(pool: memhub.MemBuddy*):
"ConstInt(42) -> '42 : i32'",
"ConstInt fail")
# SSA 值 %0 -> "%0"(MLIR 操作数不带类型)
# SSA value %0 -> "%0" (MLIR operands carry no type)
name_ssa: str = pool.alloc(16)
string.strcpy(name_ssa, "%0")
val_ssa: mlirlite.Value* = mcore.SSAValue(ty_i32, name_ssa)
@@ -84,13 +77,7 @@ def test_value_print(pool: memhub.MemBuddy*):
"SSAValue fail")
# ============================================================
# 测试 3: 构建 add 函数
# llvm.func @add(%a: i32, %b: i32) -> i32 {
# %0 = llvm.add %a, %b : i32
# llvm.return %0 : i32
# }
# ============================================================
# --- Test 3: build add function ---
def test_build_add(pool: memhub.MemBuddy*):
testcheck.section("Test 3: build_add function")
@@ -98,22 +85,22 @@ def test_build_add(pool: memhub.MemBuddy*):
mcore: mlirlite.LLVMModuleCore* = mlirlite.LLVMModuleCore(pool)
ty_i32: mlirlite.LLVMType* = core.Int32()
# 创建模块 + 函数
# create module + function
mod: mlirlite.Module* = mcore.NewModule("test_add")
func: mlirlite.Function* = mcore.CreateFunction(mod, "add", ty_i32)
# 添加参数
# add parameters
mcore.AddParam(func, ty_i32, "%a")
mcore.AddParam(func, ty_i32, "%b")
# 创建 entry 块
# create entry block
entry: mlirlite.BasicBlock* = mcore.CreateBlock(func, "entry")
# 创建 builder
# create builder
builder: mlirlite.IRBuilder* = mcore.NewBuilder(func)
mlirlite.position_at_end(builder, entry)
# 为参数创建 Value 包装
# wrap parameters as Values
v_a: mlirlite.Value* = mcore.SSAValue(ty_i32, "%a")
v_b: mlirlite.Value* = mcore.SSAValue(ty_i32, "%b")
@@ -123,13 +110,13 @@ def test_build_add(pool: memhub.MemBuddy*):
# ret i32 %0
mlirlite.build_ret(builder, v_c)
# 打印函数
# print function
buf: str = pool.alloc(4096)
buf[0] = 0
mcore.PrintFunction(buf, 4096, func)
testcheck.info(buf)
# 验证关键内容
# verify key content
testcheck.check(string.strstr(buf, "llvm.add %a, %b : i32") is not None,
"contains 'llvm.add %a, %b : i32'",
"missing 'llvm.add'")
@@ -141,17 +128,7 @@ def test_build_add(pool: memhub.MemBuddy*):
"missing function definition")
# ============================================================
# 测试 4: 构建 if-then-else 函数(max)
# llvm.func @max(%a: i32, %b: i32) -> i32 {
# %0 = llvm.icmp "sgt" %a, %b : i32
# llvm.cond_br %0, ^then, ^else
# ^then:
# llvm.return %a : i32
# ^else:
# llvm.return %b : i32
# }
# ============================================================
# --- Test 4: build if-then-else (max) ---
def test_build_if_else(pool: memhub.MemBuddy*):
testcheck.section("Test 4: build if-then-else (max)")
@@ -185,13 +162,13 @@ def test_build_if_else(pool: memhub.MemBuddy*):
mlirlite.position_at_end(builder, else_blk)
mlirlite.build_ret(builder, v_b)
# 打印函数
# print function
buf: str = pool.alloc(4096)
buf[0] = 0
mcore.PrintFunction(buf, 4096, func)
testcheck.info(buf)
# 验证关键内容
# verify key content
testcheck.check(string.strstr(buf, "llvm.icmp \"sgt\"") is not None,
"contains 'llvm.icmp \"sgt\"'",
"missing 'llvm.icmp \"sgt\"'")
@@ -206,9 +183,7 @@ def test_build_if_else(pool: memhub.MemBuddy*):
"missing block label '^else:'")
# ============================================================
# 测试 5: 完整模块 ModulePrint
# ============================================================
# --- Test 5: ModulePrint ---
def test_module_print(pool: memhub.MemBuddy*):
testcheck.section("Test 5: ModulePrint")
@@ -217,12 +192,12 @@ def test_module_print(pool: memhub.MemBuddy*):
ty_i32: mlirlite.LLVMType* = core.Int32()
ty_void: mlirlite.LLVMType* = core.Void()
# 创建模块
# create module
mod: mlirlite.Module* = mcore.NewModule("test_module")
mlirlite.module_set_target(mod, "x86_64-pc-windows-gnu")
mlirlite.module_set_datalayout(mod, "e-m:w-p270:32:32")
# 函数 1: add
# function 1: add
func_add: mlirlite.Function* = mcore.CreateFunction(mod, "add", ty_i32)
mcore.AddParam(func_add, ty_i32, "%a")
mcore.AddParam(func_add, ty_i32, "%b")
@@ -234,20 +209,20 @@ def test_module_print(pool: memhub.MemBuddy*):
v_sum: mlirlite.Value* = mlirlite.build_add(builder1, v_a1, v_b1)
mlirlite.build_ret(builder1, v_sum)
# 函数 2: void 函数
# function 2: void function
func_void: mlirlite.Function* = mcore.CreateFunction(mod, "noop", ty_void)
entry2: mlirlite.BasicBlock* = mcore.CreateBlock(func_void, "entry")
builder2: mlirlite.IRBuilder* = mcore.NewBuilder(func_void)
mlirlite.position_at_end(builder2, entry2)
mlirlite.build_ret_void(builder2)
# 打印模块
# print module
buf: str = pool.alloc(8192)
buf[0] = 0
mcore.PrintModule(buf, 8192, mod)
testcheck.info(buf)
# 验证关键内容
# verify key content
testcheck.check(string.strstr(buf, "module {") is not None,
"contains 'module {'",
"missing 'module {'")
@@ -265,9 +240,7 @@ def test_module_print(pool: memhub.MemBuddy*):
"missing 'llvm.return'")
# ============================================================
# 测试 6: 数组类型打印
# ============================================================
# --- Test 6: ArrayType ---
def test_array_type(pool: memhub.MemBuddy*):
testcheck.section("Test 6: ArrayType")
core: mlirlite.LLVMTypeCore* = mlirlite.LLVMTypeCore(pool)
@@ -293,9 +266,7 @@ def test_array_type(pool: memhub.MemBuddy*):
"nested array fail")
# ============================================================
# 测试 7: 结构体类型打印
# ============================================================
# --- Test 7: StructType ---
def test_struct_type(pool: memhub.MemBuddy*):
testcheck.section("Test 7: StructType")
core: mlirlite.LLVMTypeCore* = mlirlite.LLVMTypeCore(pool)
@@ -317,7 +288,7 @@ def test_struct_type(pool: memhub.MemBuddy*):
"struct {i32, i8*} -> !llvm.struct<(i32, !llvm.ptr)>",
"struct fail")
# 空结构体 -> !llvm.struct<()>
# empty struct -> !llvm.struct<()>
ty_empty: mlirlite.LLVMType* = core.Struct(None, 0)
buf[0] = 0
core.PrintType(buf, 128, ty_empty)
@@ -326,9 +297,7 @@ def test_struct_type(pool: memhub.MemBuddy*):
"empty struct fail")
# ============================================================
# 测试 8: 函数类型打印
# ============================================================
# --- Test 8: FuncType ---
def test_func_type(pool: memhub.MemBuddy*):
testcheck.section("Test 8: FuncType")
core: mlirlite.LLVMTypeCore* = mlirlite.LLVMTypeCore(pool)
@@ -350,7 +319,7 @@ def test_func_type(pool: memhub.MemBuddy*):
"func type -> !llvm.func<i32 (i32, !llvm.ptr)>",
"func type fail")
# void () -> !llvm.func<none ()> — 无参数 void 函数类型
# void () -> !llvm.func<none ()>: no-arg void function type
ty_void: mlirlite.LLVMType* = core.Void()
ty_func_void: mlirlite.LLVMType* = core.Func(ty_void, None, 0)
buf[0] = 0
@@ -360,9 +329,7 @@ def test_func_type(pool: memhub.MemBuddy*):
"void func fail")
# ============================================================
# 测试 9: 声明系统(declare vs define)
# ============================================================
# --- Test 9: Declare vs Define ---
def test_declare(pool: memhub.MemBuddy*):
testcheck.section("Test 9: Declare vs Define")
core: mlirlite.LLVMTypeCore* = mlirlite.LLVMTypeCore(pool)
@@ -403,9 +370,7 @@ def test_declare(pool: memhub.MemBuddy*):
"define missing body")
# ============================================================
# 测试 10: 浮点类型与 ConstFloat
# ============================================================
# --- Test 10: Float Types & ConstFloat ---
def test_float_types(pool: memhub.MemBuddy*):
testcheck.section("Test 10: Float Types & ConstFloat")
core: mlirlite.LLVMTypeCore* = mlirlite.LLVMTypeCore(pool)
@@ -444,8 +409,7 @@ def test_float_types(pool: memhub.MemBuddy*):
"FP128 -> f128",
"FP128 fail")
# ConstFloat(3.14) -> "0x40091EB851EB851F : f64"
# (位模式无精度损失;类型注解为 MLIR 形态 f64)
# ConstFloat(3.14) -> "0x40091EB851EB851F : f64" (bit pattern, lossless; MLIR type f64)
val_pi: mlirlite.Value* = mcore.ConstFloat(ty_double, 3.14)
buf[0] = 0
mcore.PrintValue(buf, 128, val_pi)
@@ -457,9 +421,7 @@ def test_float_types(pool: memhub.MemBuddy*):
"ConstFloat missing hex pattern")
# ============================================================
# 测试 11: 浮点二元运算
# ============================================================
# --- Test 11: Float Binary Ops ---
def test_float_binops(pool: memhub.MemBuddy*):
testcheck.section("Test 11: Float Binary Ops")
core: mlirlite.LLVMTypeCore* = mlirlite.LLVMTypeCore(pool)
@@ -492,9 +454,7 @@ def test_float_binops(pool: memhub.MemBuddy*):
"missing 'llvm.return'")
# ============================================================
# 测试 12: 位运算与移位
# ============================================================
# --- Test 12: Bitwise & Shift Ops ---
def test_bitwise_ops(pool: memhub.MemBuddy*):
testcheck.section("Test 12: Bitwise & Shift Ops")
core: mlirlite.LLVMTypeCore* = mlirlite.LLVMTypeCore(pool)
@@ -530,9 +490,7 @@ def test_bitwise_ops(pool: memhub.MemBuddy*):
testcheck.check(string.strstr(buf, "llvm.shl %2, %b : i32") is not None, "has 'llvm.shl %2, %b : i32'", "missing 'llvm.shl'")
# ============================================================
# 测试 13: FCMP 比较
# ============================================================
# --- Test 13: FCMP ---
def test_fcmp(pool: memhub.MemBuddy*):
testcheck.section("Test 13: FCMP")
core: mlirlite.LLVMTypeCore* = mlirlite.LLVMTypeCore(pool)
@@ -563,9 +521,7 @@ def test_fcmp(pool: memhub.MemBuddy*):
"missing 'llvm.fcmp \"oeq\"'")
# ============================================================
# 测试 14: 类型转换 (zext, ptrtoint, inttoptr)
# ============================================================
# --- Test 14: Casts (zext/ptrtoint/inttoptr) ---
def test_casts(pool: memhub.MemBuddy*):
testcheck.section("Test 14: Casts (zext/ptrtoint/inttoptr)")
core: mlirlite.LLVMTypeCore* = mlirlite.LLVMTypeCore(pool)
@@ -603,9 +559,7 @@ def test_casts(pool: memhub.MemBuddy*):
testcheck.check(string.strstr(buf, "llvm.inttoptr %1 : i64 to !llvm.ptr") is not None, "has 'llvm.inttoptr %1 : i64 to !llvm.ptr'", "missing 'llvm.inttoptr'")
# ============================================================
# 测试 15: 浮点转换 (fp2si, si2fp)
# ============================================================
# --- Test 15: FP Conversions (fp2si/si2fp) ---
def test_fp_conversions(pool: memhub.MemBuddy*):
testcheck.section("Test 15: FP Conversions (fp2si/si2fp)")
core: mlirlite.LLVMTypeCore* = mlirlite.LLVMTypeCore(pool)
@@ -638,9 +592,7 @@ def test_fp_conversions(pool: memhub.MemBuddy*):
testcheck.check(string.strstr(buf, "llvm.fptosi %0 : f64 to i32") is not None, "has 'llvm.fptosi %0 : f64 to i32'", "missing 'llvm.fptosi'")
# ============================================================
# 测试 16: Phi 节点
# ============================================================
# --- Test 16: Phi Node ---
def test_phi(pool: memhub.MemBuddy*):
testcheck.section("Test 16: Phi Node")
core: mlirlite.LLVMTypeCore* = mlirlite.LLVMTypeCore(pool)
@@ -682,7 +634,7 @@ def test_phi(pool: memhub.MemBuddy*):
mcore.PrintFunction(buf, 4096, func)
testcheck.info(buf)
# phi 已转为块参数:不再输出 phi 行,改为 ^merge(%…) + llvm.br ^merge(%…)
# phi lowered to block args: no phi line, emits ^merge(%...) + llvm.br ^merge(%...)
testcheck.check(string.strstr(buf, "llvm.br ^merge(%c0 : i32)") is not None, "has 'llvm.br ^merge(%c0 : i32)'", "missing branch block operands")
testcheck.check(string.strstr(buf, "^merge(%0: i32):") is not None, "has '^merge(%0: i32):'", "missing block arguments")
testcheck.check(string.strstr(buf, "^then:") is not None, "has '^then:'", "missing '^then:'")
@@ -690,9 +642,7 @@ def test_phi(pool: memhub.MemBuddy*):
testcheck.check(string.strstr(buf, " = phi ") is None, "phi 行不再输出", "phi line should not be emitted")
# ============================================================
# 测试 17: Switch
# ============================================================
# --- Test 17: Switch ---
def test_switch(pool: memhub.MemBuddy*):
testcheck.section("Test 17: Switch")
core: mlirlite.LLVMTypeCore* = mlirlite.LLVMTypeCore(pool)
@@ -737,9 +687,7 @@ def test_switch(pool: memhub.MemBuddy*):
testcheck.check(string.strstr(buf, "^case0:") is not None, "has '^case0:'", "missing '^case0:'")
# ============================================================
# 测试 18: Select
# ============================================================
# --- Test 18: Select ---
def test_select(pool: memhub.MemBuddy*):
testcheck.section("Test 18: Select")
core: mlirlite.LLVMTypeCore* = mlirlite.LLVMTypeCore(pool)
@@ -768,9 +716,7 @@ def test_select(pool: memhub.MemBuddy*):
testcheck.check(string.strstr(buf, "llvm.select %0, %a, %b : i1, i32") is not None, "has 'llvm.select %0, %a, %b : i1, i32'", "missing 'llvm.select'")
# ============================================================
# 测试 19: 全局变量 (字符串常量 + 整数)
# ============================================================
# --- Test 19: Global Variables ---
def test_globals(pool: memhub.MemBuddy*):
testcheck.section("Test 19: Global Variables")
core: mlirlite.LLVMTypeCore* = mlirlite.LLVMTypeCore(pool)
@@ -781,13 +727,13 @@ def test_globals(pool: memhub.MemBuddy*):
mod: mlirlite.Module* = mcore.NewModule("test_globals")
mlirlite.module_set_target(mod, "x86_64-pc-windows-gnu")
# 字符串常量: @.str = private unnamed_addr constant [6 x i8] c"hello\00"
# string constant: @.str = private unnamed_addr constant [6 x i8] c"hello\00"
mcore.CreateGlobalString(mod, ".str", "hello")
# 整数全局变量: @counter = global i32 0
# integer global: @counter = global i32 0
mcore.CreateGlobalInt(mod, "counter", 32, 0)
# 添加一个简单函数使模块非空
# add a simple function to make the module non-empty
func: mlirlite.Function* = mcore.CreateFunction(mod, "use_global", ty_void)
entry: mlirlite.BasicBlock* = mcore.CreateBlock(func, "entry")
builder: mlirlite.IRBuilder* = mcore.NewBuilder(func)
@@ -809,9 +755,7 @@ def test_globals(pool: memhub.MemBuddy*):
testcheck.check(string.strstr(buf, "llvm.mlir.global @counter") is not None, "has 'llvm.mlir.global @counter'", "missing integer global")
# ============================================================
# 测试 20: 函数与参数属性
# ============================================================
# --- Test 20: Function & Param Attributes ---
def test_attributes(pool: memhub.MemBuddy*):
testcheck.section("Test 20: Function & Param Attributes")
core: mlirlite.LLVMTypeCore* = mlirlite.LLVMTypeCore(pool)
@@ -822,15 +766,15 @@ def test_attributes(pool: memhub.MemBuddy*):
mod: mlirlite.Module* = mcore.NewModule("test_attrs")
func: mlirlite.Function* = mcore.CreateFunction(mod, "attr_test", ty_i32)
# 参数 0: i32 noundef %x
# param 0: i32 noundef %x
p0: mlirlite.Param* = mcore.AddParam(func, ty_i32, "%x")
mcore.ParamSetAttrs(p0, "noundef")
# 参数 1: i8* nocapture %p
# param 1: i8* nocapture %p
p1: mlirlite.Param* = mcore.AddParam(func, ty_i8ptr, "%p")
mcore.ParamSetAttrs(p1, "nocapture")
# 函数属性: nounwind
# function attribute: nounwind
mcore.FunctionSetAttrs(func, "nounwind")
entry: mlirlite.BasicBlock* = mcore.CreateBlock(func, "entry")
@@ -844,8 +788,8 @@ def test_attributes(pool: memhub.MemBuddy*):
mcore.PrintFunction(buf, 4096, func)
testcheck.info(buf)
# MLIR v1: 函数/参数属性(Attrs)记录但不渲染(见 includes/mlirlite/README.md §3.3)。
# 故断言签名本身正确、且属性文本不出现(模型字段仍保留)。
# MLIR v1 records func/param attrs but does not render them (see mlirlite README 3.3),
# so assert the signature is correct and attr text is absent; model fields remain.
testcheck.check(string.strstr(buf, "llvm.func @attr_test(%x: i32, %p: !llvm.ptr) -> i32") is not None,
"has 'llvm.func @attr_test(%x: i32, %p: !llvm.ptr) -> i32'",
"missing attribute-test function signature")
@@ -860,9 +804,7 @@ def test_attributes(pool: memhub.MemBuddy*):
"func attr 'nounwind' should not be rendered")
# ============================================================
# 测试 21: 原子操作 (atomicrmw / cmpxchg)
# ============================================================
# --- Test 21: Atomic Ops ---
def test_atomic(pool: memhub.MemBuddy*):
testcheck.section("Test 21: Atomic Ops")
core: mlirlite.LLVMTypeCore* = mlirlite.LLVMTypeCore(pool)
@@ -893,9 +835,7 @@ def test_atomic(pool: memhub.MemBuddy*):
testcheck.check(string.strstr(buf, "monotonic") is not None, "has 'monotonic'", "missing 'monotonic'")
# ============================================================
# 测试 22: 内联汇编 + unreachable
# ============================================================
# --- Test 22: Inline ASM & Unreachable ---
def test_inline_asm_unreachable(pool: memhub.MemBuddy*):
testcheck.section("Test 22: Inline ASM & Unreachable")
core: mlirlite.LLVMTypeCore* = mlirlite.LLVMTypeCore(pool)
@@ -927,9 +867,7 @@ def test_inline_asm_unreachable(pool: memhub.MemBuddy*):
testcheck.check(string.strstr(buf, "llvm.unreachable") is not None, "has 'llvm.unreachable'", "missing 'llvm.unreachable'")
# ============================================================
# 测试 23: SSA 验证 - 合法函数通过
# ============================================================
# --- Test 23: Verify Valid Function ---
def test_verify_valid(pool: memhub.MemBuddy*):
testcheck.section("Test 23: Verify Valid Function")
core: mlirlite.LLVMTypeCore* = mlirlite.LLVMTypeCore(pool)
@@ -958,9 +896,7 @@ def test_verify_valid(pool: memhub.MemBuddy*):
"wrong error code for valid function")
# ============================================================
# 测试 24: SSA 验证 - 缺少终止指令
# ============================================================
# --- Test 24: Verify Missing Terminator ---
def test_verify_no_terminator(pool: memhub.MemBuddy*):
testcheck.section("Test 24: Verify Missing Terminator")
core: mlirlite.LLVMTypeCore* = mlirlite.LLVMTypeCore(pool)
@@ -974,7 +910,7 @@ def test_verify_no_terminator(pool: memhub.MemBuddy*):
builder: mlirlite.IRBuilder* = mcore.NewBuilder(func)
mlirlite.position_at_end(builder, entry)
v_a: mlirlite.Value* = mcore.SSAValue(ty_i32, "%a")
mlirlite.build_add(builder, v_a, v_a) # 无 ret
mlirlite.build_add(builder, v_a, v_a) # no ret
result: mlirlite.VerifyResult* = mcore.NewVerifyResult(4096)
err_count: int = mcore.VerifyFunction(func, result)
@@ -986,9 +922,7 @@ def test_verify_no_terminator(pool: memhub.MemBuddy*):
"wrong error code for missing terminator")
# ============================================================
# 测试 25: SSA 验证 - 重复定义
# ============================================================
# --- Test 25: Verify Duplicate Definition ---
def test_verify_duplicate_def(pool: memhub.MemBuddy*):
testcheck.section("Test 25: Verify Duplicate Definition")
core: mlirlite.LLVMTypeCore* = mlirlite.LLVMTypeCore(pool)
@@ -1004,7 +938,7 @@ def test_verify_duplicate_def(pool: memhub.MemBuddy*):
v_a: mlirlite.Value* = mcore.SSAValue(ty_i32, "%a")
v_c: mlirlite.Value* = mlirlite.build_add(builder, v_a, v_a)
# 手动追加重复定义行 "%0 = add i32 %a, %a"
# manually append a duplicate definition line "%0 = add i32 %a, %a"
dup_text: str = pool.alloc(64)
string.strcpy(dup_text, "%0 = add i32 %a, %a")
mlirlite.block_append_text(pool, entry, dup_text)
@@ -1021,9 +955,7 @@ def test_verify_duplicate_def(pool: memhub.MemBuddy*):
"wrong error code for duplicate def")
# ============================================================
# 测试 26: SSA 验证 - 未定义引用
# ============================================================
# --- Test 26: Verify Undefined Use ---
def test_verify_undef_use(pool: memhub.MemBuddy*):
testcheck.section("Test 26: Verify Undefined Use")
core: mlirlite.LLVMTypeCore* = mlirlite.LLVMTypeCore(pool)
@@ -1035,12 +967,12 @@ def test_verify_undef_use(pool: memhub.MemBuddy*):
mcore.AddParam(func, ty_i32, "%a")
entry: mlirlite.BasicBlock* = mcore.CreateBlock(func, "entry")
# 手动追加含未定义引用的行 "%0 = add i32 %ghost, %a"
# manually append a line with an undefined reference "%0 = add i32 %ghost, %a"
line1: str = pool.alloc(64)
string.strcpy(line1, "%0 = add i32 %ghost, %a")
mlirlite.block_append_text(pool, entry, line1)
# 手动追加终止指令
# manually append terminator
line2: str = pool.alloc(64)
string.strcpy(line2, "ret i32 %0")
mlirlite.block_append_text(pool, entry, line2)
@@ -1056,9 +988,7 @@ def test_verify_undef_use(pool: memhub.MemBuddy*):
"wrong error code for undefined use")
# ============================================================
# 测试 27: SSA 验证 - 模块级验证(含 phi/分支,验证块标签修复)
# ============================================================
# --- Test 27: Verify Module (phi/labels) ---
def test_verify_module(pool: memhub.MemBuddy*):
testcheck.section("Test 27: Verify Module (phi/labels)")
core: mlirlite.LLVMTypeCore* = mlirlite.LLVMTypeCore(pool)
@@ -1067,7 +997,7 @@ def test_verify_module(pool: memhub.MemBuddy*):
mod: mlirlite.Module* = mcore.NewModule("verify_module")
# 函数 1: 简单 add(合法)
# function 1: simple add (valid)
func1: mlirlite.Function* = mcore.CreateFunction(mod, "add", ty_i32)
mcore.AddParam(func1, ty_i32, "%a")
mcore.AddParam(func1, ty_i32, "%b")
@@ -1079,7 +1009,7 @@ def test_verify_module(pool: memhub.MemBuddy*):
v_c: mlirlite.Value* = mlirlite.build_add(builder1, v_a, v_b)
mlirlite.build_ret(builder1, v_c)
# 函数 2: 含 phi 与分支(合法,验证块标签不被误报为未定义)
# function 2: phi + branches (valid; block labels must not be flagged undefined)
func2: mlirlite.Function* = mcore.CreateFunction(mod, "phi_test", ty_i32)
f2_entry: mlirlite.BasicBlock* = mcore.CreateBlock(func2, "entry")
then_blk: mlirlite.BasicBlock* = mcore.CreateBlock(func2, "then")
@@ -1122,7 +1052,7 @@ def test_verify_module(pool: memhub.MemBuddy*):
def main() -> int:
testcheck.begin("LLvmLiteTest: mlirlite 库(LLVM IR 生成)")
# 初始化 mpool
# init pool
pool_mem: bytes = stdlib.malloc(POOL_SIZE)
if pool_mem is None:
stdio.printf("FAIL: malloc for pool failed\n")
+4 -4
View File
@@ -14,11 +14,11 @@ def main() -> CInt | CExport:
testcheck.begin("ListTest: list[T] 堆容器测试")
# 创建 mbuddy arena
# Create the mbuddy arena.
arena: bytes = stdlib.malloc(65536)
bd: memhub.MemBuddy* = memhub.MemBuddy(arena, 65536)
# === Test 1: 创建和 append ===
# === Test 1: create and append ===
testcheck.section("Test 1: 创建和 append")
nums = list[int](bd)
nums.append(10)
@@ -58,7 +58,7 @@ def main() -> CInt | CExport:
n3: sizet = nums.__len__()
testcheck.check(n3 == 0, "clear OK (0)", "clear FAILED expect 0")
# === Test 6: 容量增长 (append 超过初始容量 8) ===
# === Test 6: capacity growth (append past initial capacity 8) ===
testcheck.section("Test 6: 容量增长")
nums2 = list[int](bd)
i: CInt
@@ -76,7 +76,7 @@ def main() -> CInt | CExport:
break
testcheck.check(ok == 1, "grow data OK", "grow data FAILED")
# === Test 7: 重新 append 后验证 ===
# === Test 7: verify after re-append ===
testcheck.section("Test 7: 重新 append")
nums2.clear()
nums2.append(100)
+8 -10
View File
@@ -361,9 +361,8 @@ def ForWithCaseNoBreakNested(inner_limit: int):
# ============================================================
# match case 内 break = 跳出 match(C switch 语义),**不**跳出外层循环
# 期望 limit=5:i=0 走 _ (+0)、i=1 走 case 1 (+100) 后 break 出 match(循环继续)、
# i=2 走 case 2 (+10)、i=3 (+3)、i=4 (+4) ⇒ 117
# break inside match exits the match (C switch semantics), not the outer loop.
# For limit=5 the expected result is 117.
# ============================================================
def MatchCaseBreakTest(limit: int) -> int:
i: int = 0
@@ -381,8 +380,8 @@ def MatchCaseBreakTest(limit: int) -> int:
# ============================================================
# switch(C switch 语义):默认不穿透;case 体内写 `fallthrough` 才落到下一个 case。
# 期望 value=1 → 1+2+3=6;value=2 → 2+3=5;value=3 → 3;其它 → 77
# switch (C semantics): no fallthrough by default; `fallthrough` continues.
# Expected: value=1 -> 6, value=2 -> 5, value=3 -> 3, else -> 77.
# ============================================================
def SwitchCaseFallthroughTest(value: int) -> int:
result: int = 0
@@ -401,9 +400,8 @@ def SwitchCaseFallthroughTest(value: int) -> int:
# ============================================================
# switch 内 break = 跳出 switch(不跳出外层循环)
# 期望 limit=5:i=0 走 default (+0)、i=1 走 case 1 (+100) 后 break 出 switch、
# i=2 走 case 2 (+10)、i=3 (+3)、i=4 (+4) ⇒ 117
# break inside switch exits the switch, not the outer loop.
# For limit=5 the expected result is 117.
# ============================================================
def SwitchCaseBreakTest(limit: int) -> int:
i: int = 0
@@ -421,8 +419,8 @@ def SwitchCaseBreakTest(limit: int) -> int:
# ============================================================
# switch 多值 case:`case 1 | 2:` 命中同一个臂
# 期望 value=1 → 10;value=2 → 10;value=3 → 30;其它 → 99
# switch multi-value case: `case 1 | 2:` hits the same arm.
# Expected: value=1 -> 10, value=2 -> 10, value=3 -> 30, else -> 99.
# ============================================================
def SwitchMultiValueTest(value: int) -> int:
result: int = 0
+2 -2
View File
@@ -30,7 +30,7 @@ def test_nested_loop():
for j in range(5):
if i < j:
count += 1
# 上三角: 4+3+2+1 = 10
# Upper triangle: 4+3+2+1 = 10.
testcheck.check(count == 10, "nested loop (count=10)", "nested loop (expect 10)")
def test_break():
@@ -50,7 +50,7 @@ def test_continue():
if i % 3 == 0:
continue
sum_val += i
# 跳过 0,3,6,9,12,15,18, 剩余和 = sum(0..19) - sum(0,3,6,9,12,15,18) = 190 - 63 = 127
# Skip multiples of 3: 190 - 63 = 127.
testcheck.check(sum_val == 127, "continue (sum=127)", "continue (expect 127)")
def test_range_step():
+122 -227
View File
@@ -74,9 +74,7 @@ def dump_mlir(pool: memhub.MemBuddy*, name: str, buf: str):
stdio.printf(" [mlir] wrote %s (%d bytes)\n", path, int(string.strlen(buf)))
# ============================================================
# 测试 1: TypePrint 类型打印(MLIR llvm 方言类型)
# ============================================================
# Test 1: TypePrint - MLIR LLVM dialect type printing
def test_type_print(pool: memhub.MemBuddy*):
testcheck.section("Test 1: TypePrint (MLIR types)")
core: mlirlite.LLVMTypeCore* = mlirlite.LLVMTypeCore(pool)
@@ -90,7 +88,7 @@ def test_type_print(pool: memhub.MemBuddy*):
"Int32 -> i32",
"Int32 fail")
# 不透明指针: Ptr(Int32) -> !llvm.ptr
# Opaque pointer: Ptr(Int32) -> !llvm.ptr
ty_ptr: mlirlite.LLVMType* = core.Ptr(ty_i32)
buf[0] = 0
core.PrintType(buf, 256, ty_ptr)
@@ -137,7 +135,7 @@ def test_type_print(pool: memhub.MemBuddy*):
"struct {i32, i8*} -> !llvm.struct<(i32, !llvm.ptr)>",
"struct fail")
# 空结构体 -> !llvm.struct<()>
# Empty struct -> !llvm.struct<()>
ty_empty: mlirlite.LLVMType* = core.Struct(None, 0)
buf[0] = 0
core.PrintType(buf, 256, ty_empty)
@@ -145,7 +143,7 @@ def test_type_print(pool: memhub.MemBuddy*):
"empty struct -> !llvm.struct<()>",
"empty struct fail")
# 函数类型 i32 (i32, i8*) -> !llvm.func<i32 (i32, !llvm.ptr)>
# Function type -> !llvm.func<i32 (i32, !llvm.ptr)>
fn1: mlirlite.ParamNode* = core.NewParamNode(ty_i32)
fn2: mlirlite.ParamNode* = core.NewParamNode(ty_i8ptr)
fhead: mlirlite.ParamNode* = core.ParamListAppend(None, None, fn1)
@@ -154,8 +152,8 @@ def test_type_print(pool: memhub.MemBuddy*):
buf[0] = 0
core.PrintType(buf, 256, ty_func)
dump_mlir(pool, "T01_types.mlir", buf)
# 把实际值写进失败报文:断言失败时 FAIL 行本身就能看到真实形态
# (避免"只看到 fail、看不到实际值"导致来回猜)
# Embed the actual value in the failure message so the FAIL line shows the
# real form directly, avoiding guesswork from a bare "fail"
ft_msg: str = pool.alloc(512)
if ft_msg is not None:
viperlib.snprintf(ft_msg, 512,
@@ -166,9 +164,7 @@ def test_type_print(pool: memhub.MemBuddy*):
ft_msg)
# ============================================================
# 测试 2: ValuePrint 值打印(MLIR,仅供诊断)
# ============================================================
# Test 2: ValuePrint - value printing (diagnostics only)
def test_value_print(pool: memhub.MemBuddy*):
testcheck.section("Test 2: ValuePrint (MLIR)")
core: mlirlite.LLVMTypeCore* = mlirlite.LLVMTypeCore(pool)
@@ -177,7 +173,7 @@ def test_value_print(pool: memhub.MemBuddy*):
ty_i32: mlirlite.LLVMType* = core.Int32()
# 常量 42 -> "42 : i32"
# Constant 42 -> "42 : i32"
val42: mlirlite.Value* = mcore.ConstInt32(42)
buf[0] = 0
mcore.PrintValue(buf, 128, val42)
@@ -185,7 +181,7 @@ def test_value_print(pool: memhub.MemBuddy*):
"ConstInt(42) -> '42 : i32'",
"ConstInt fail")
# SSA 值 -> "%0"(MLIR 操作数不带类型)
# SSA value -> "%0" (MLIR operands carry no type)
val_ssa: mlirlite.Value* = mcore.SSAValue(ty_i32, "%0")
buf[0] = 0
mcore.PrintValue(buf, 128, val_ssa)
@@ -195,13 +191,7 @@ def test_value_print(pool: memhub.MemBuddy*):
"SSAValue fail")
# ============================================================
# 测试 3: 构建 add 函数
# llvm.func @add(%a: i32, %b: i32) -> i32 {
# %0 = llvm.add %a, %b : i32
# llvm.return %0 : i32
# }
# ============================================================
# Test 3: build add function (llvm.func @add + llvm.add + llvm.return)
def test_build_add(pool: memhub.MemBuddy*):
testcheck.section("Test 3: build_add function")
@@ -247,9 +237,7 @@ def test_build_add(pool: memhub.MemBuddy*):
"entry block should not be labelled")
# ============================================================
# 测试 4: if-else(max)
# ============================================================
# Test 4: build if-then-else (max)
def test_build_if_else(pool: memhub.MemBuddy*):
testcheck.section("Test 4: build if-then-else (max)")
@@ -301,9 +289,7 @@ def test_build_if_else(pool: memhub.MemBuddy*):
"missing block label '^else:'")
# ============================================================
# 测试 5: void 函数
# ============================================================
# Test 5: void function
def test_build_void(pool: memhub.MemBuddy*):
testcheck.section("Test 5: void function")
@@ -333,9 +319,7 @@ def test_build_void(pool: memhub.MemBuddy*):
"missing 'llvm.return'")
# ============================================================
# 测试 6: 模块输出(module / declare vs define)
# ============================================================
# Test 6: module printing (module / declare vs define)
def test_module_print(pool: memhub.MemBuddy*):
testcheck.section("Test 6: ModulePrint")
@@ -347,7 +331,7 @@ def test_module_print(pool: memhub.MemBuddy*):
mlirlite.module_set_target(mod, "x86_64-pc-windows-gnu")
mlirlite.module_set_datalayout(mod, "e-m:w-p270:32:32")
# declare: llvm.func @extern_func(%x: i32) -> i32(无体)
# declare: llvm.func @extern_func(%x: i32) -> i32 (no body)
func_decl: mlirlite.Function* = mcore.CreateDeclare(mod, "extern_func", ty_i32)
mcore.AddParam(func_decl, ty_i32, "%x")
@@ -387,9 +371,7 @@ def test_module_print(pool: memhub.MemBuddy*):
"missing define body")
# ============================================================
# 测试 7: 常量物化(操作数 42 -> llvm.mlir.constant)
# ============================================================
# Test 7: constant materialization (operand 42 -> llvm.mlir.constant)
def test_const_materialize(pool: memhub.MemBuddy*):
testcheck.section("Test 7: constant materialization")
@@ -423,7 +405,7 @@ def test_const_materialize(pool: memhub.MemBuddy*):
"add 行引用物化后的 SSA 名 '%c0'",
"add line does not reference materialized constant")
# 同 (类型,文本) 常量只物化一次:add 的两个操作数都是 42
# Same (type, text) constant materializes once: both add operands are 42
func2: mlirlite.Function* = mcore.CreateFunction(mod, "const_twice", ty_i32)
entry2: mlirlite.BasicBlock* = mcore.CreateBlock(func2, "entry")
builder2: mlirlite.IRBuilder* = mcore.NewBuilder(func2)
@@ -439,9 +421,7 @@ def test_const_materialize(pool: memhub.MemBuddy*):
"constant dedup failed")
# ============================================================
# 测试 8: phi -> 块参数
# ============================================================
# Test 8: phi -> block arguments
def test_phi_block_args(pool: memhub.MemBuddy*):
testcheck.section("Test 8: phi -> block arguments")
@@ -497,9 +477,7 @@ def test_phi_block_args(pool: memhub.MemBuddy*):
"phi line should not be emitted")
# ============================================================
# 测试 9: 内存 / 调用 / 转换
# ============================================================
# Test 9: memory / call / cast
def test_mem_call_cast(pool: memhub.MemBuddy*):
testcheck.section("Test 9: memory / call / cast")
@@ -544,9 +522,8 @@ def test_mem_call_cast(pool: memhub.MemBuddy*):
testcheck.info(buf)
dump_mlir(pool, "T09_mem_call_cast.mlir", buf)
# 整模块另存:mlir-opt 要求被调符号在模块作用域内**有声明**;
# 单函数文本不含 declare,会报
# 'llvm.call' op 'callee' does not reference a symbol in the current scope
# Save the whole module: mlir-opt requires callees declared at module scope,
# otherwise single-function text without declare fails symbol resolution
decl: mlirlite.Function* = mcore.CreateDeclare(mod, "callee", ty_i32)
mcore.AddParam(decl, ty_i32, "%x")
mbuf: str = pool.alloc(65536)
@@ -571,9 +548,7 @@ def test_mem_call_cast(pool: memhub.MemBuddy*):
"contains 'llvm.ptrtoint'", "missing 'llvm.ptrtoint'")
# ============================================================
# 测试 10: 全局变量(字符串常量 / 整数 / 整型数组)
# ============================================================
# Test 10: global variables (string constant / int / int array)
def test_globals(pool: memhub.MemBuddy*):
testcheck.section("Test 10: Global Variables")
@@ -591,8 +566,8 @@ def test_globals(pool: memhub.MemBuddy*):
# @counter = global i32 0
mcore.CreateGlobalInt(mod, "counter", 32, 0)
# @arr = [i8 1, i8 2] -> [1 : i8, 2 : i8](元素带类型注解;dense<...> 对
# !llvm.array 非法——dense 只接受 builtin shaped 类型,实测 mlir-opt 22.1.8)
# @arr = [i8 1, i8 2] -> [1 : i8, 2 : i8] (elements carry type annotations);
# dense<...> is illegal for !llvm.array (it only accepts builtin shaped types)
ty_arr2: mlirlite.LLVMType* = core.Array(ty_i8, 2)
gv_arr: mlirlite.GlobalVariable* = mcore.NewGlobal(mod, "arr", ty_arr2)
init_arr: str = pool.alloc(32)
@@ -614,26 +589,24 @@ def test_globals(pool: memhub.MemBuddy*):
testcheck.check(string.strstr(buf, "llvm.mlir.global") is not None,
"contains 'llvm.mlir.global'", "missing 'llvm.mlir.global'")
# 符号名以 '.' 开头必须加引号(MLIR 裸名须字母/下划线开头)
# 实际形态:llvm.mlir.global … constant @".str"("hello\00") : !llvm.array<6 x i8>
# A '.'-prefixed symbol name must be quoted (MLIR bare names start with a letter or _)
# Actual form: llvm.mlir.global ... constant @".str"("hello\00") : !llvm.array<6 x i8>
testcheck.check(string.strstr(buf, "@\".str\"(") is not None,
"字符串全局名引号形态 '@\".str\"('", "missing quoted string global name")
# 字符串属性长度必须等于 i8 数组长度 ⇒ 尾随 NUL 必须保留在属性里
# (剥掉 \00 会被 mlir-opt 拒绝;改为剥类型里的 NUL 则会丢 C 串终止符、破坏 ABI)
# The string attribute length must equal the i8 array length, so the trailing
# NUL must stay: mlir-opt rejects stripping \00, and dropping it breaks the ABI
testcheck.check(string.strstr(buf, "hello\\00") is not None,
"字符串初值保留 NUL 'hello\\00'", "missing string initializer")
testcheck.check(string.strstr(buf, "!llvm.array<6 x i8>") is not None,
"contains '!llvm.array<6 x i8>'", "missing string global type")
testcheck.check(string.strstr(buf, "@counter(0 : i32) : i32") is not None,
"整数全局 '@counter(0 : i32) : i32'", "missing integer global")
# 数组属性:元素带类型注解(dense<...> 对 !llvm.array 非法,只接受 builtin shaped 类型)
# Array attribute: elements carry type annotations (dense<...> invalid for !llvm.array)
testcheck.check(string.strstr(buf, "[1 : i8, 2 : i8]") is not None,
"整型数组初值 '[1 : i8, 2 : i8]'", "missing array initializer")
# ============================================================
# 测试 11: SSA 验证(合法函数 0 错误)
# ============================================================
# Test 11: SSA verification (valid function, 0 errors)
def test_verify_valid(pool: memhub.MemBuddy*):
testcheck.section("Test 11: Verify valid function")
@@ -656,7 +629,7 @@ def test_verify_valid(pool: memhub.MemBuddy*):
result: mlirlite.VerifyResult* = mcore.NewVerifyResult(4096)
err_count: int = mcore.VerifyFunction(func, result)
# 本测试原本没有渲染步骤;为落盘验收补一次 PrintFunction(不涉及断言)
# Render once via PrintFunction for on-disk acceptance (no assertion involved)
buf: str = pool.alloc(4096)
buf[0] = 0
mcore.PrintFunction(buf, 4096, func)
@@ -670,16 +643,8 @@ def test_verify_valid(pool: memhub.MemBuddy*):
"wrong error code for valid function")
# ============================================================
# 测试 12: 结构体/vtable 全局初值 → initializer region
#
# 覆盖: ① vtable 结构体(null + bitcast 符号引用);② 指针数组 + GEP 常量表达式
# (GEP 整体视为 addressof);③ 符号名引号口径(LLVM 口径 @"m0" 剥引号后按 MLIR
# 口径重加:m0 可裸写 → @m0;数字开头的 9m 需引号 → @"9m");④ 根级裸
# null / zeroinitializer(属性形态 `(zeroinitializer)` 被 mlir-opt 拒绝,
# 实测 22.1.8 报 "expected attribute value")→ region + llvm.mlir.zero。
# 断言依赖的形态(含整模块)均已用 mlir-opt 22.1.8 实测通过。
# ============================================================
# Test 12: struct/vtable globals lower to initializer regions
# Covers vtable bitcast refs, GEP addressof, quoted names, bare null/zeroinitializer
def test_struct_global(pool: memhub.MemBuddy*):
testcheck.section("Test 12: struct/vtable global initializer (region)")
@@ -690,8 +655,8 @@ def test_struct_global(pool: memhub.MemBuddy*):
mod: mlirlite.LLVMModule* = mcore.NewModule("test_struct_global")
# ---- ① vtable 结构体 { i8*, i8*, i8* } ----
# Initializer 是 TPV 生成的 LLVM 语法聚合串:null + bitcast 符号引用
# ---- (1) vtable struct { i8*, i8*, i8* } ----
# Initializer is a TPV-generated LLVM syntax aggregate: null + bitcast symbol refs
vt1: mlirlite.ParamNode* = core.NewParamNode(ty_i8ptr)
vt2: mlirlite.ParamNode* = core.NewParamNode(ty_i8ptr)
vt3: mlirlite.ParamNode* = core.NewParamNode(ty_i8ptr)
@@ -705,15 +670,15 @@ def test_struct_global(pool: memhub.MemBuddy*):
string.strcpy(init_vt,
"{ i8* null, i8* bitcast (i8* (i8*)* @\"m0\" to i8*), i8* bitcast (i8* (i8*)* @m1 to i8*) }")
gv_vt.Initializer = init_vt
# IsConstant=1 + linkage 默认 external ⇒ 初值非空时**不输出** external 关键字
# IsConstant=1 with default external linkage: a non-empty initializer omits the keyword
mcore.GlobalSetConstant(gv_vt, 1)
# 声明被引用的方法符号,使模块自洽(mlir-opt 要求 addressof 目标可解析)
# Declare referenced method symbols so the module is self-consistent for mlir-opt
d_m0: mlirlite.Function* = mcore.CreateDeclare(mod, "m0", ty_i8ptr)
mcore.AddParam(d_m0, ty_i8ptr, "%self")
d_m1: mlirlite.Function* = mcore.CreateDeclare(mod, "m1", ty_i8ptr)
mcore.AddParam(d_m1, ty_i8ptr, "%self")
# ---- ③ 引号重加分支: LLVM 裸名 @9m(数字开头)→ MLIR 需 @"9m" ----
# ---- (3) re-quoting branch: LLVM bare name @9m (digit start) -> MLIR @"9m" ----
vq1: mlirlite.ParamNode* = core.NewParamNode(ty_i8ptr)
ty_vtq: mlirlite.LLVMType* = core.Struct(vq1, 1)
gv_vtq: mlirlite.GlobalVariable* = mcore.NewGlobal(mod, "vtq", ty_vtq)
@@ -725,8 +690,8 @@ def test_struct_global(pool: memhub.MemBuddy*):
d_9m: mlirlite.Function* = mcore.CreateDeclare(mod, "9m", ty_i8ptr)
mcore.AddParam(d_9m, ty_i8ptr, "%self")
# ---- ② 指针数组 + GEP 常量表达式 ----
# @s0 = [3 x i8](供 GEP 常量表达式指向)
# ---- (2) pointer array + GEP constant expression ----
# @s0 = [3 x i8], the target of the GEP constant expression
mcore.CreateGlobalString(mod, "s0", "ab")
ty_arr2: mlirlite.LLVMType* = core.Array(ty_i8ptr, 2)
gv_arr: mlirlite.GlobalVariable* = mcore.NewGlobal(mod, "arr", ty_arr2)
@@ -736,26 +701,22 @@ def test_struct_global(pool: memhub.MemBuddy*):
gv_arr.Initializer = init_arr
mcore.GlobalSetLinkage(gv_arr, "internal")
# ---- ②' 根级裸 GEP(TPV `_build_string_ptr_initializer` 的指针全局形态) ----
# 初值无类型前缀,直接是 getelementptr 常量表达式
# ---- (2') root bare GEP (TPV pointer-global form) ----
# Initializer has no type prefix; it is a bare getelementptr constant expression
gv_sp: mlirlite.GlobalVariable* = mcore.NewGlobal(mod, "sp", ty_i8ptr)
init_sp: str = pool.alloc(192)
string.strcpy(init_sp,
"getelementptr inbounds ([3 x i8], [3 x i8]* @s0, i32 0, i32 0)")
gv_sp.Initializer = init_sp
# ---- ④ 根级裸 null / zeroinitializer 全局 ----
# 这两类初值原先走属性路径产出 `(zeroinitializer)`,被 mlir-opt 22.1.8 拒绝
# (实测报 "expected attribute value");现改走 region:
# `@名() : <顶层类型> { <llvm.mlir.zero>; llvm.return }`。
# TPV 侧真实存在这类写法(FuncGenMixin / CallGenVt / TranslatorGenMixin /
# ExprGenConst 均设 Initializer = "null" 或 "zeroinitializer")。
# ---- (4) root bare null / zeroinitializer globals ----
# Lowered to a region with llvm.mlir.zero (mlir-opt rejects the (zeroinitializer) attr form)
gv_pn: mlirlite.GlobalVariable* = mcore.NewGlobal(mod, "pnull", ty_i8ptr)
init_pn: str = pool.alloc(16)
string.strcpy(init_pn, "null")
gv_pn.Initializer = init_pn
# 整型数组 + 裸 zeroinitializer:顶层类型取自 gv.Ty(此处 !llvm.array<2 x i32>)
# Int array + bare zeroinitializer: top-level type comes from gv.Ty (!llvm.array<2 x i32>)
ty_i32: mlirlite.LLVMType* = core.Int32()
ty_arr_i32: mlirlite.LLVMType* = core.Array(ty_i32, 2)
gv_za: mlirlite.GlobalVariable* = mcore.NewGlobal(mod, "zarr", ty_arr_i32)
@@ -769,14 +730,14 @@ def test_struct_global(pool: memhub.MemBuddy*):
testcheck.info(buf)
dump_mlir(pool, "T12_struct_global.mlir", buf)
# ① vtable 型: region 形态 + 顶层聚合类型;元素类型注解来自全局类型树
# (1) vtable: region form + top-level aggregate type; element annotations from type tree
testcheck.check(string.strstr(buf, "@vt() : !llvm.struct<(!llvm.ptr, !llvm.ptr, !llvm.ptr)>") is not None,
"vtable 全局 region 形态 '@vt() : !llvm.struct<(…, …, …)>'",
"missing vtable global region header")
testcheck.check(string.strstr(buf, "llvm.mlir.undef : !llvm.struct<(!llvm.ptr, !llvm.ptr, !llvm.ptr)>") is not None,
"含 'llvm.mlir.undef'(insertvalue 链起点)",
"missing llvm.mlir.undef")
# LLVM 口径 @"m0" 剥引号后按 MLIR 口径裸写 @m0(m0 是合法 MLIR 裸名)
# LLVM @"m0" is unquoted to bare @m0 (a valid MLIR bare name)
testcheck.check(string.strstr(buf, "llvm.mlir.addressof @m0 : !llvm.ptr") is not None,
"bitcast 中的 @\"m0\" → 'llvm.mlir.addressof @m0 : !llvm.ptr'",
"missing addressof for m0")
@@ -795,12 +756,12 @@ def test_struct_global(pool: memhub.MemBuddy*):
testcheck.check(string.strstr(buf, "external") is None,
"external + 有初值 ⇒ 不输出 linkage 关键字",
"unexpected 'external' keyword")
# ③ 数字开头的符号名需引号(_ll_name_needs_quote 判据)
# (3) digit-leading symbol names need quotes (per _ll_name_needs_quote)
testcheck.check(string.strstr(buf, "llvm.mlir.addressof @\"9m\" : !llvm.ptr") is not None,
"数字开头符号名重加引号 'llvm.mlir.addressof @\"9m\" : !llvm.ptr'",
"missing quoted addressof for 9m")
# ② 指针数组 + GEP: GEP 常量表达式 → addressof;数组全局类型 + 下标路径
# (2) pointer array + GEP: GEP constant -> addressof; array global type + index path
testcheck.check(string.strstr(buf, "@arr() : !llvm.array<2 x !llvm.ptr>") is not None,
"数组全局 region 形态 '@arr() : !llvm.array<2 x !llvm.ptr>'",
"missing array global region header")
@@ -814,12 +775,12 @@ def test_struct_global(pool: memhub.MemBuddy*):
"下标 1 形态 '[1] : !llvm.array<2 x !llvm.ptr>'",
"missing index [1] insertvalue")
# ②' 根级裸 GEP(无类型前缀): 顶层叶子 region,无 undef/insertvalue
# (2') root bare GEP: top-level leaf region, no undef/insertvalue
testcheck.check(string.strstr(buf, "@sp() : !llvm.ptr") is not None,
"根级裸 GEP → '@sp() : !llvm.ptr'(顶层叶子 region)",
"missing root bare-GEP global")
# ④ 根级裸 null(指针全局): region 形态,属性括号为空,顶层类型取自 gv.Ty
# (4) root bare null pointer global: region form, empty parens, type from gv.Ty
testcheck.check(string.strstr(buf, "@pnull() : !llvm.ptr") is not None,
"根级裸 null → '@pnull() : !llvm.ptr'(region 形态)",
"missing bare-null pointer global region header")
@@ -830,7 +791,7 @@ def test_struct_global(pool: memhub.MemBuddy*):
"region 内含 'llvm.return'",
"missing llvm.return in region")
# ④' 裸 zeroinitializer(整型数组): region 形态,zero 的类型即顶层类型
# (4') bare zeroinitializer int array: region form, zero type is the top-level type
testcheck.check(string.strstr(buf, "@zarr() : !llvm.array<2 x i32>") is not None,
"裸 zeroinitializer → '@zarr() : !llvm.array<2 x i32>'(region 形态)",
"missing zeroinitializer array global region header")
@@ -838,25 +799,14 @@ def test_struct_global(pool: memhub.MemBuddy*):
"裸 zeroinitializer → 'llvm.mlir.zero : !llvm.array<2 x i32>'",
"missing llvm.mlir.zero for zeroinitializer array global")
# 两类都不得再落到属性形态(mlir-opt 22.1.8 报 "expected attribute value")
# Both must never fall back to the attribute form (mlir-opt rejects it)
testcheck.check(string.strstr(buf, "(zeroinitializer)") is None,
"属性形态 '(zeroinitializer)' 不再出现",
"rejected attribute form '(zeroinitializer)' leaked")
# ============================================================
# 测试 13: alloca 对齐 / switch / inline_asm(v1 三项缺口的补齐)
#
# 三项的 MLIR 形态均由 mlir-opt 22.1.8 实测确定(候选与 exit 码见
# includes/mlirlite/__function.vp 中 _MlirAlloca / _MlirSwitch / _MlirAsm 的注释):
# ① alloca 对齐 → `{alignment = 16 : i64}`
# (`align(16)`、`, align 16`、`{alignment = 16 : i32}` 均实测被拒)
# ② switch → `llvm.switch %v : i32, ^default [0: ^case0, …]`
# (设计规范里的 `llvm.switch %v, ^default […] : i32` 实测被拒:expected ':')
# 目标块带 phi 时追加块实参(与 br/cond_br 同一设施)
# ③ inline_asm → `llvm.inline_asm has_side_effects [asm_dialect = intel] "…", "…" %x : (i32) -> i32`
# (LLVM 的裸 `inteldialect` 与 `"…"(%x)` 词法均实测被拒)
# ============================================================
# Test 13: alloca alignment / switch / inline_asm MLIR forms
# Forms verified against mlir-opt 22.1.8; switch phi targets carry block operands
def test_alloca_align_switch_asm(pool: memhub.MemBuddy*):
testcheck.section("Test 13: alloca align / switch / inline_asm")
@@ -867,7 +817,7 @@ def test_alloca_align_switch_asm(pool: memhub.MemBuddy*):
mod: mlirlite.LLVMModule* = mcore.NewModule("test_align_switch_asm")
# ---- ① alloca 对齐 + ③ inline_asm(builder 形态 + TPV 注入形态)----
# ---- (1) alloca alignment + (3) inline_asm (builder + TPV-injected forms) ----
f1: mlirlite.Function* = mcore.CreateFunction(mod, "align_asm", ty_i32)
mcore.AddParam(f1, ty_i32, "%x")
e1: mlirlite.BasicBlock* = mcore.CreateBlock(f1, "entry")
@@ -877,22 +827,22 @@ def test_alloca_align_switch_asm(pool: memhub.MemBuddy*):
# %0 = alloca i32, align 16
v_slot: mlirlite.Value* = mlirlite.build_alloca_aligned(b1, ty_i32, 16)
# call none asm sideeffect "nop", ""()(无返回值形态)
# call none asm sideeffect "nop", ""() (void form)
mlirlite.build_inline_asm(b1, ty_void, "nop", "", 1)
# %1 = call i32 asm sideeffect "mov $0, $1", "=r,r"()(有返回值形态)
# %1 = call i32 asm sideeffect "mov $0, $1", "=r,r"() (returning form)
v_asm: mlirlite.Value* = mlirlite.build_inline_asm(b1, ty_i32, "mov $0, $1", "=r,r", 1)
v_x: mlirlite.Value* = mcore.SSAValue(ty_i32, "%x")
mlirlite.build_store(b1, v_x, v_slot, 0)
# TPV CallGenCBuiltin 的注入形态(inteldialect + 带类型的输入操作数)
# TPV CallGenCBuiltin injected form (inteldialect + typed input operands)
mlirlite.block_append_text(pool, e1,
"%7 = call i32 asm sideeffect inteldialect \"mov $0, $1\", \"=r,r\"(i32 %x)")
mlirlite.build_ret(b1, v_asm)
# ---- ② switch:3 case + default(不带 phi)----
# ---- (2) switch: 3 cases + default (no phi) ----
f2: mlirlite.Function* = mcore.CreateFunction(mod, "sw", ty_i32)
mcore.AddParam(f2, ty_i32, "%v")
e2: mlirlite.BasicBlock* = mcore.CreateBlock(f2, "entry")
@@ -920,7 +870,7 @@ def test_alloca_align_switch_asm(pool: memhub.MemBuddy*):
mlirlite.position_at_end(b2, dflt)
mlirlite.build_ret(b2, v_v)
# ---- ②' switch:case 与 default 目标块带 phi ⇒ 块实参 ----
# ---- (2') switch: case and default targets carry phi -> block operands ----
f3: mlirlite.Function* = mcore.CreateFunction(mod, "sw_phi", ty_i32)
mcore.AddParam(f3, ty_i32, "%v")
e3: mlirlite.BasicBlock* = mcore.CreateBlock(f3, "entry")
@@ -951,7 +901,7 @@ def test_alloca_align_switch_asm(pool: memhub.MemBuddy*):
testcheck.info(buf)
dump_mlir(pool, "T13_align_switch_asm.mlir", buf)
# ① alloca 对齐:实测形态 `{alignment = 16 : i64}`(LLVM 词法的 `, align 16` 不再出现)
# (1) alloca alignment: form is {alignment = 16 : i64} (LLVM ', align 16' is gone)
testcheck.check(string.strstr(buf, "llvm.alloca %c0 x i32 {alignment = 16 : i64} : (i32) -> !llvm.ptr") is not None,
"alloca 对齐 'llvm.alloca %c0 x i32 {alignment = 16 : i64} : (i32) -> !llvm.ptr'",
"missing alloca alignment attribute")
@@ -959,7 +909,7 @@ def test_alloca_align_switch_asm(pool: memhub.MemBuddy*):
"LLVM 词法 ', align 16' 不再出现(已转写为属性)",
"raw LLVM alloca align leaked")
# ② switch:值类型紧随值(`%v : i32,`)+ 各 case/default 标签
# (2) switch: value type follows the value (%v : i32,) plus case/default labels
testcheck.check(string.strstr(buf, "llvm.switch %v : i32, ^default [0: ^case0, 1: ^case1, 2: ^case2]") is not None,
"switch 实测形态 'llvm.switch %v : i32, ^default [0: ^case0, 1: ^case1, 2: ^case2]'",
"missing llvm.switch")
@@ -970,12 +920,12 @@ def test_alloca_align_switch_asm(pool: memhub.MemBuddy*):
testcheck.check(string.strstr(buf, "^case2") is not None,
"contains '^case2'", "missing '^case2'")
# ②' switch 目标块带 phi ⇒ 块实参(default 与 case 各自携带)
# (2') switch phi targets -> block operands (carried by default and case)
testcheck.check(string.strstr(buf, "llvm.switch %v : i32, ^sdef(%c1 : i32) [0: ^scase(%c0 : i32)]") is not None,
"switch 块实参 'llvm.switch %v : i32, ^sdef(%c1 : i32) [0: ^scase(%c0 : i32)]'",
"missing switch block operands")
# 块参数的具体 SSA 名由 SSA 重编号决定(本用例实际是 %0/%1),
# 故只断言"目标块标签带参数"的形状,不绑定具体编号,避免脆断言。
# Block-argument SSA names depend on renumbering, so assert only the shape
# "target label carries arguments", not specific names, avoiding brittle asserts
testcheck.check(string.strstr(buf, "^scase(%") is not None,
"case 目标块带参数 '^scase(%…: i32):'",
"missing block argument for switch case target")
@@ -983,7 +933,7 @@ def test_alloca_align_switch_asm(pool: memhub.MemBuddy*):
"default 目标块带参数 '^sdef(%…: i32):'",
"missing block argument for switch default target")
# ③ inline_asm:无返回值 / 有返回值 / inteldialect → asm_dialect = intel
# (3) inline_asm: void / returning / inteldialect -> asm_dialect = intel
testcheck.check(string.strstr(buf, "llvm.inline_asm has_side_effects \"nop\", \"\" : () -> ()") is not None,
"无返回值形态 'llvm.inline_asm has_side_effects \"nop\", \"\" : () -> ()'",
"missing void inline_asm")
@@ -1001,20 +951,8 @@ def test_alloca_align_switch_asm(pool: memhub.MemBuddy*):
"raw LLVM inteldialect keyword leaked")
# ============================================================
# 测试 14: 变参函数 / 变参调用 / va_arg / cmpxchg / 全局属性字典(P0 缺口补齐)
#
# 五项 MLIR 形态均由 mlir-opt 22.1.8 实测 exit 0 确立(候选与 exit 码见
# includes/mlirlite/__function.vp 的 _MlirFuncSig / _MlirCall / _MlirVaArg /
# _MlirCmpXchg 与 __module.vp 的 _MlirGlobalLine 注释):
# ① 变参函数声明 → `llvm.func @printf(%p: !llvm.ptr, ...) -> i32`
# ② 变参调用 → `… vararg(!llvm.func<i32 (!llvm.ptr, i32, ...)>) : (!llvm.ptr, i32) -> i32`
# (vararg 内是**被调函数的完整 MLIR 函数类型**,含 `...`)
# ③ va_arg → `%N = "llvm.va_arg"(%ap) : (!llvm.ptr) -> i32`(generic 形态,刻意选择)
# ④ cmpxchg → 单结果 `llvm.cmpxchg` + 两条 `llvm.extractvalue`([0]=旧值、[1]=i1 成功位)
# ⑤ 全局属性字典 → `…("ab\00") {section = "data", alignment = 16 : i64} : !llvm.array<3 x i8>`
# (字典必须在**类型之前**;`unnamed_addr` 是**关键字**,不能进字典)
# ============================================================
# Test 14: vararg function/call, va_arg, cmpxchg, global attribute dict
# Five MLIR forms verified with mlir-opt 22.1.8; the attr dict precedes the type
def test_vararg_vaarg_cmpxchg(pool: memhub.MemBuddy*):
testcheck.section("Test 14: vararg / va_arg / cmpxchg / global attrs")
@@ -1026,7 +964,7 @@ def test_vararg_vaarg_cmpxchg(pool: memhub.MemBuddy*):
mod: mlirlite.LLVMModule* = mcore.NewModule("test_vararg_vaarg_cmpxchg")
# ---- ① 变参函数声明: llvm.func @printf(%p: !llvm.ptr, ...) -> i32 ----
# ---- (1) vararg declaration: llvm.func @printf(%p: !llvm.ptr, ...) -> i32 ----
f_printf: mlirlite.Function* = mcore.CreateDeclare(mod, "printf", ty_i32)
mcore.AddParam(f_printf, ty_i32ptr, "%p")
f_printf.IsVarArg = 1
@@ -1041,7 +979,7 @@ def test_vararg_vaarg_cmpxchg(pool: memhub.MemBuddy*):
v_arg: mlirlite.Value* = mlirlite.build_va_arg(b_va, v_ap, ty_i32)
mlirlite.build_ret(b_va, v_arg)
# ---- ② 变参调用 + ④ cmpxchg(builder 的**单结果**形态)----
# ---- (2) vararg call + (4) cmpxchg (builder single-result form) ----
f_cc: mlirlite.Function* = mcore.CreateFunction(mod, "vcall_cmpx", ty_i32)
mcore.AddParam(f_cc, ty_i32ptr, "%p")
mcore.AddParam(f_cc, ty_i32, "%n")
@@ -1052,30 +990,29 @@ def test_vararg_vaarg_cmpxchg(pool: memhub.MemBuddy*):
v_n: mlirlite.Value* = mcore.SSAValue(ty_i32, "%n")
# %0 = cmpxchg !llvm.ptr %p, i32 %n, i32 %n acq_rel monotonic
# → %0 = llvm.cmpxchg … + 两条 extractvalue;`%0` 绑定到 [0](旧值)
# -> llvm.cmpxchg + two extractvalue; %0 binds to [0] (old value)
v_old: mlirlite.Value* = mlirlite.build_cmpxchg(b_cc, v_p, v_n, v_n,
mlirlite.ATOMIC_ORDER_ACQ_REL,
mlirlite.ATOMIC_ORDER_MONOTONIC)
# %1 = call i32 (i8*, i32, ...) @printf(i8* %p, i32 %n)
# → %1 = llvm.call @printf(%p, %n) vararg(!llvm.func<i32 (!llvm.ptr, i32, ...)>)
# : (!llvm.ptr, i32) -> i32
# -> %1 = llvm.call @printf(%p, %n) vararg(!llvm.func<i32 (!llvm.ptr, i32, ...)>)
mlirlite.value_set_next(v_p, v_n)
v_call: mlirlite.Value* = mlirlite.build_call(b_cc, "printf", v_p, 2, ty_i32, 1)
# ret 用 cmpxchg 结果 ⇒ 断言别名绑定生效(文本里应是 %_0_v = extractvalue[0])
# ret uses the cmpxchg result to assert alias binding (text: %_0_v = extractvalue[0])
mlirlite.build_ret(b_cc, v_old)
# ---- ④' cmpxchg 双结果前缀 `%a, %b = cmpxchg …`(两名字各绑一条 extractvalue)----
# ---- (4') cmpxchg dual-result prefix (both names bind one extractvalue each) ----
f_cc2: mlirlite.Function* = mcore.CreateFunction(mod, "cmpx2", ty_i32)
mcore.AddParam(f_cc2, ty_i32ptr, "%p")
mcore.AddParam(f_cc2, ty_i32, "%n")
e_cc2: mlirlite.BasicBlock* = mcore.CreateBlock(f_cc2, "entry")
mlirlite.block_append_text(pool, e_cc2,
"%a, %b = cmpxchg !llvm.ptr %p, i32 %n, i32 %n acq_rel monotonic")
# %b = 成功位 [1];%a = 旧值 [0]
# %b = success bit [1]; %a = old value [0]
mlirlite.block_append_text(pool, e_cc2, "%r = zext i1 %b to i32")
mlirlite.block_append_text(pool, e_cc2, "ret i32 %a")
# ---- ⑤ 全局属性字典:section/alignment 在**类型之前**;unnamed_addr 作关键字 ----
# ---- (5) global attr dict: section/alignment precede the type; unnamed_addr is a keyword ----
ty_arr3: mlirlite.LLVMType* = core.Array(ty_i8, 3)
init_s: str = pool.alloc(32)
string.strcpy(init_s, "c\"ab\\00\"")
@@ -1099,7 +1036,7 @@ def test_vararg_vaarg_cmpxchg(pool: memhub.MemBuddy*):
testcheck.info(buf)
dump_mlir(pool, "T14_vararg_vaarg_cmpxchg.mlir", buf)
# ① 变参函数声明:参数表尾 `...`
# (1) vararg declaration: parameter list ends with ...
testcheck.check(string.strstr(buf, "llvm.func @printf(%p: !llvm.ptr, ...) -> i32") is not None,
"变参声明 'llvm.func @printf(%p: !llvm.ptr, ...) -> i32'",
"missing vararg function declaration")
@@ -1107,7 +1044,7 @@ def test_vararg_vaarg_cmpxchg(pool: memhub.MemBuddy*):
"参数表尾 '..., ...)' 形态(', ...)')",
"missing vararg ellipsis in declaration")
# ② 变参调用:vararg(完整 MLIR 函数类型)
# (2) vararg call: vararg(full MLIR function type)
testcheck.check(string.strstr(buf, "vararg(!llvm.func<") is not None,
"变参调用 'vararg(!llvm.func<'", "missing vararg(...) attribute")
testcheck.check(string.strstr(buf,
@@ -1115,13 +1052,13 @@ def test_vararg_vaarg_cmpxchg(pool: memhub.MemBuddy*):
"vararg 完整函数类型 'vararg(!llvm.func<i32 (!llvm.ptr, i32, ...)>) : (!llvm.ptr, i32) -> i32'",
"missing vararg function type")
# ③ va_arg:generic 形态(刻意选择,不透明指针下自定义汇编无法表达)
# (3) va_arg: generic form (deliberate; custom asm cannot express opaque pointers)
testcheck.check(string.strstr(buf, "\"llvm.va_arg\"(") is not None,
"va_arg generic 形态 '\"llvm.va_arg\"('", "missing generic llvm.va_arg")
testcheck.check(string.strstr(buf, ") : (!llvm.ptr) -> i32") is not None,
"va_arg 类型串 ') : (!llvm.ptr) -> i32'", "missing va_arg type list")
# ④ cmpxchg:单结果 + 两条 extractvalue([0]=旧值、[1]=i1 成功位)
# (4) cmpxchg: single result + two extractvalue ([0]=old value, [1]=i1 success bit)
testcheck.check(string.strstr(buf, "llvm.cmpxchg") is not None,
"contains 'llvm.cmpxchg'", "missing llvm.cmpxchg")
testcheck.check(string.strstr(buf, "llvm.extractvalue ") is not None,
@@ -1130,9 +1067,8 @@ def test_vararg_vaarg_cmpxchg(pool: memhub.MemBuddy*):
"旧值抽取 '[0] : !llvm.struct<(i32, i1)>'", "missing extractvalue [0]")
testcheck.check(string.strstr(buf, "[1] : !llvm.struct<(i32, i1)>") is not None,
"成功位抽取 '[1] : !llvm.struct<(i32, i1)>'", "missing extractvalue [1]")
# extractvalue 结果名由 struct 结果名**确定性派生**(不再用计数器 ⇒ 两遍必然同名)
# `%0` → `%_0_v`(旧值 [0])/ `%_0_ok`(成功位 [1]);`%a` → `%_a_v`/`%_a_ok`
# (`_` 前缀是必需的:MLIR 裸 SSA 名首字符须为字母或 `_`,`%0_v` 被 mlir-opt 拒绝)
# extractvalue result names derive deterministically from the struct result name
# (%0 -> %_0_v/%_0_ok, %a -> %_a_v/%_a_ok; MLIR requires the _ name prefix)
testcheck.check(string.strstr(buf, "%_0_v = llvm.extractvalue %0[0] : !llvm.struct<(i32, i1)>") is not None,
"旧值定义 '%_0_v = llvm.extractvalue %0[0] …'",
"cmpxchg single result not deterministically named")
@@ -1145,7 +1081,7 @@ def test_vararg_vaarg_cmpxchg(pool: memhub.MemBuddy*):
testcheck.check(string.strstr(buf, "%_a_ok = llvm.extractvalue %a[1] : !llvm.struct<(i32, i1)>") is not None,
"双结果次名定义 '%_a_ok = llvm.extractvalue %a[1] …'",
"cmpxchg double-result ok bit not deterministically named")
# 引用侧:别名把 %0 / %a / %b 改写成上述确定性新名(定义与引用同名 ⇒ 不悬空)
# Reference side: aliases rewrite %0/%a/%b to those names (def and use match)
testcheck.check(string.strstr(buf, "llvm.return %_0_v : i32") is not None,
"单结果引用改写 'llvm.return %_0_v : i32'",
"cmpxchg result not bound to old value")
@@ -1156,7 +1092,7 @@ def test_vararg_vaarg_cmpxchg(pool: memhub.MemBuddy*):
"双结果首名引用改写 'llvm.return %_a_v : i32'",
"cmpxchg first name not bound to old value")
# ⑤ 属性字典在**类型之前**(整串断言);unnamed_addr 作关键字、不进字典
# (5) attr dict precedes the type (whole-string assert); unnamed_addr is not in the dict
testcheck.check(string.strstr(buf,
"(\"ab\\00\") {section = \"data\", alignment = 16 : i64} : !llvm.array<3 x i8>") is not None,
"属性字典在类型之前 '(\"ab\\00\") {section = \"data\", alignment = 16 : i64} : !llvm.array<3 x i8>'",
@@ -1172,23 +1108,8 @@ def test_vararg_vaarg_cmpxchg(pool: memhub.MemBuddy*):
"unnamed_addr leaked into attribute dict")
# ============================================================
# 测试 15: 具名结构体(%"name" = type {…})
#
# TPV 侧对每个类都调 module_add_named_type 登记具名结构体(mlirlite 由此输出
# `%"sha1.Cls" = type {…}` 定义行)。MLIR(llvm 方言) **没有**独立类型定义语法,
# 也**不允许无体前向声明**(实测 mlir-opt 22.1.8:`!llvm.struct<"x">` 报
# "struct without a body only allowed in a recursive struct"),故:
# ① 定义行**整体丢弃**(NamedTypeHead 只作模型保留 + 打印期查表);
# ② 按值使用处内联为 !llvm.struct<"名字", (字段…)>(名字直接作字符串字面量,
# 含数字/`.`/`[`/`]` 均不额外转义);嵌套具名同理递归;
# ③ 指向具名结构体的指针仍是 !llvm.ptr(不透明指针,既有路径不变);
# ④ 中间文本里"只有名字"的形态 `%"name"` 由打印期登记表回查完整定义后展开
# 为 ②(查不到 / 仍是 opaque ⇒ 响亮报错,绝不静默输出空体错误布局)。
# 本用例的期望整模块已用 mlir-opt / mlir-translate 22.1.8 实测 exit 0,
# 降级(--mlir-to-llvmir)可得 MLIR 自动生成的定义行:
# %aa11bb22cc33dd44.Cls = type { i32, ptr }
# ============================================================
# Test 15: named struct types (LLVM %"name" = type) in MLIR
# MLIR has no type defs: drop def lines, inline by value, keep pointers opaque !llvm.ptr
def test_named_struct(pool: memhub.MemBuddy*):
testcheck.section("Test 15: named struct type")
@@ -1198,7 +1119,7 @@ def test_named_struct(pool: memhub.MemBuddy*):
ty_i8: mlirlite.LLVMType* = core.Int8()
ty_i8ptr: mlirlite.LLVMType* = core.Ptr(ty_i8)
# 具名结构体 %"aa11bb22cc33dd44.Cls" = type { i32, i8* }(sha1 风格前缀 + '.')
# Named struct %"aa11bb22cc33dd44.Cls" = type { i32, i8* } (sha1-style prefix with '.')
ns1: mlirlite.ParamNode* = core.NewParamNode(ty_i32)
ns2: mlirlite.ParamNode* = core.NewParamNode(ty_i8ptr)
ns_head: mlirlite.ParamNode* = core.ParamListAppend(None, None, ns1)
@@ -1206,23 +1127,22 @@ def test_named_struct(pool: memhub.MemBuddy*):
ty_named: mlirlite.LLVMType* = core.Struct(ns_head, 2, "aa11bb22cc33dd44.Cls")
ty_named_ptr: mlirlite.LLVMType* = core.Ptr(ty_named)
# packed 具名结构体 %"aa11bb22cc33dd44.Packed" = type <{ i32, i8 }>
# MLIR 侧(实测 mlir-opt / mlir-translate 22.1.8):
# !llvm.struct<"aa11bb22cc33dd44.Packed", packed (i32, i8)> → 降级 type <{ i32, i8 }>
# Packed named struct %"aa11bb22cc33dd44.Packed" = type <{ i32, i8 }>
# MLIR: !llvm.struct<"aa11bb22cc33dd44.Packed", packed (i32, i8)>
pk1: mlirlite.ParamNode* = core.NewParamNode(ty_i32)
pk2: mlirlite.ParamNode* = core.NewParamNode(ty_i8)
pk_head: mlirlite.ParamNode* = core.ParamListAppend(None, None, pk1)
core.ParamListAppend(pk_head, pk1, pk2)
ty_packed: mlirlite.LLVMType* = core.Struct(pk_head, 2, "aa11bb22cc33dd44.Packed")
# ---- 类型文本:按值 = 内联具名形态;指针 = 不透明 !llvm.ptr ----
# ---- type text: by value = inline named form; pointer = opaque !llvm.ptr ----
tbuf: str = pool.alloc(256)
tbuf[0] = 0
core.PrintType(tbuf, 256, ty_named)
testcheck.check(string.strstr(tbuf, "!llvm.struct<\"aa11bb22cc33dd44.Cls\", (i32, !llvm.ptr)>") is not None,
"具名结构体按值形态 '!llvm.struct<\"aa11bb22cc33dd44.Cls\", (i32, !llvm.ptr)>'",
"named struct by-value form missing")
# 名字里的 '.' / 数字开头不需要额外转义或引号(实测 mlir-opt 22.1.8)
# A '.' / digit-leading name needs no extra escaping or quotes (verified)
testcheck.check(string.strstr(tbuf, "<\"aa11bb22cc33dd44.Cls\",") is not None,
"名字直接作字符串字面量(不额外转义)",
"named struct name literal form missing")
@@ -1233,19 +1153,19 @@ def test_named_struct(pool: memhub.MemBuddy*):
"named struct pointer must stay opaque !llvm.ptr")
mod: mlirlite.LLVMModule* = mcore.NewModule("test_named_struct")
# 真实流程:具名结构体经 module_add_named_type 登记(打印期查表用)
# Real flow: register named structs via module_add_named_type for the print-time table
mlirlite.module_add_named_type(mod, pool, ty_named)
# packed 标记唯一设置点(须在 add_named_type 之后设;打印期由登记表携带)
# Only place the packed flag is set (after add_named_type; carried by the table)
mlirlite.module_add_named_type(mod, pool, ty_packed)
mlirlite.module_set_named_type_packed(mod, pool, ty_packed, 1)
# ---- ① 按值全局(类型使用处内联具名体)+ ② 指向它的指针全局 ----
# ---- (1) by-value global (inlines the named body) + (2) pointer global to it ----
gv_v: mlirlite.GlobalVariable* = mcore.NewGlobal(mod, "g_cls", ty_named)
gv_p: mlirlite.GlobalVariable* = mcore.NewGlobal(mod, "g_cls_p", ty_named_ptr)
# ③ packed 按值全局
# (3) packed by-value global
gv_pk: mlirlite.GlobalVariable* = mcore.NewGlobal(mod, "g_packed", ty_packed)
# ---- ① 按值形参 + ② 指针形参 ----
# ---- (1) by-value parameter + (2) pointer parameter ----
fn: mlirlite.Function* = mcore.CreateFunction(mod, "use_named", ty_i32)
mcore.AddParam(fn, ty_named, "%v")
mcore.AddParam(fn, ty_named_ptr, "%p")
@@ -1253,16 +1173,16 @@ def test_named_struct(pool: memhub.MemBuddy*):
b: mlirlite.IRBuilder* = mcore.NewBuilder(fn)
mlirlite.position_at_end(b, entry)
# ---- ④ 中间文本里的"只有名字"形态(手工 / TPV 注入)----
# 打印期由登记表回查完整定义展开;指针形态 %"name"* 仍走 !llvm.ptr
# ---- (4) bare-name form in mid text (hand-written / TPV-injected) ----
# Print time expands it via the table; pointer form %"name"* stays !llvm.ptr
mlirlite.block_append_text(pool, entry, "%0 = alloca %\"aa11bb22cc33dd44.Cls\"")
mlirlite.block_append_text(pool, entry, "%1 = load i32, %\"aa11bb22cc33dd44.Cls\"* %0")
# ⑤ packed 具名结构体的文本形态(同一登记表槽位带 packed 标记)
# (5) packed named struct text form (same table slot carries the packed flag)
mlirlite.block_append_text(pool, entry, "%2 = alloca %\"aa11bb22cc33dd44.Packed\"")
v_1: mlirlite.Value* = mcore.SSAValue(ty_i32, "%1")
mlirlite.build_ret(b, v_1)
# ---- ⑥ 按值 packed 形参:独立声明函数,不改动 use_named 的既有断言 ----
# ---- (6) by-value packed parameter: separate declare, keeping use_named asserts ----
fn_pk: mlirlite.Function* = mcore.CreateDeclare(mod, "use_packed", ty_i32)
mcore.AddParam(fn_pk, ty_packed, "%pk")
@@ -1272,14 +1192,14 @@ def test_named_struct(pool: memhub.MemBuddy*):
testcheck.info(buf)
dump_mlir(pool, "T15_named_struct.mlir", buf)
# ① 按值形参 / 全局:使用处内联具名体
# (1) by-value parameter / global: inline the named body at the use site
testcheck.check(string.strstr(buf, "llvm.func @use_named(%v: !llvm.struct<\"aa11bb22cc33dd44.Cls\", (i32, !llvm.ptr)>, %p: !llvm.ptr) -> i32") is not None,
"按值形参 'llvm.func @use_named(%v: !llvm.struct<\"aa11bb22cc33dd44.Cls\", (i32, !llvm.ptr)>, %p: !llvm.ptr) -> i32'",
"missing inline named struct parameter")
testcheck.check(string.strstr(buf, "@g_cls() : !llvm.struct<\"aa11bb22cc33dd44.Cls\", (i32, !llvm.ptr)>") is not None,
"按值全局 '@g_cls() : !llvm.struct<\"aa11bb22cc33dd44.Cls\", (i32, !llvm.ptr)>'",
"missing inline named struct global")
# ② 指针:仍是不透明 !llvm.ptr
# (2) pointer: remains opaque !llvm.ptr
testcheck.check(string.strstr(buf, "@g_cls_p() : !llvm.ptr") is not None,
"指针全局 '@g_cls_p() : !llvm.ptr'",
"named struct pointer global must be !llvm.ptr")
@@ -1287,7 +1207,7 @@ def test_named_struct(pool: memhub.MemBuddy*):
"不得出现指向具名结构体的指针类型(MLIR 不透明指针)",
"pointer-to-named-struct type leaked")
# ④ 文本形态 %"name" 展开(alloca 元素类型 / load 的指针类型);定义行不输出
# (4) %"name" text expands (alloca element / load pointer type); no def line emitted
testcheck.check(string.strstr(buf, "%0 = llvm.alloca %c0 x !llvm.struct<\"aa11bb22cc33dd44.Cls\", (i32, !llvm.ptr)> : (i32) -> !llvm.ptr") is not None,
"文本 %\"name\" 展开为内联具名体(alloca 元素类型)",
"named struct type text not expanded in alloca")
@@ -1297,12 +1217,12 @@ def test_named_struct(pool: memhub.MemBuddy*):
testcheck.check(string.strstr(buf, "%\"aa11bb22cc33dd44.Cls\"") is None,
"LLVM 口径的 %\"name\" 形态不再出现(已全部转写)",
"raw LLVM named type text leaked")
# ③ 定义行整体丢弃:MLIR 无独立类型定义语法(由 mlir-translate 在使用处自动生成)
# (3) def lines dropped: MLIR has no type-def syntax (mlir-translate emits at use)
testcheck.check(string.strstr(buf, "\"aa11bb22cc33dd44.Cls\" = type") is None,
"模块不输出 '\"name\" = type {…}' 定义行",
"named type definition line should be dropped")
# ⑦ packed 具名结构体:登记表携带 NamedTypeNode.IsPacked,按值形态加 'packed ' 关键字
# (7) packed named struct: the table carries IsPacked and adds the 'packed ' keyword
testcheck.check(string.strstr(buf, "@g_packed() : !llvm.struct<\"aa11bb22cc33dd44.Packed\", packed (i32, i8)>") is not None,
"packed 按值全局 '@g_packed() : !llvm.struct<\"aa11bb22cc33dd44.Packed\", packed (i32, i8)>'",
"missing packed inline named struct global")
@@ -1312,38 +1232,18 @@ def test_named_struct(pool: memhub.MemBuddy*):
testcheck.check(string.strstr(buf, "x !llvm.struct<\"aa11bb22cc33dd44.Packed\", packed (i32, i8)> : (i32) -> !llvm.ptr") is not None,
"文本 %\"name\" 展开为 packed 内联具名体(alloca 元素类型)",
"packed named struct type text not expanded with packed")
# 负向:非 packed 的具名结构体类型串里不得出现 packed
# Negative: a non-packed named struct type string must not contain 'packed'
testcheck.check(string.strstr(buf, "!llvm.struct<\"aa11bb22cc33dd44.Cls\", packed") is None,
"非 packed 具名结构体类型串不含 'packed'",
"packed keyword leaked into non-packed named struct")
# 负向:packed 具名结构体不得漏掉 packed 关键字(按值渲染为无 packed 形态)
# Negative: a packed named struct must not render without the packed keyword
testcheck.check(string.strstr(buf, "!llvm.struct<\"aa11bb22cc33dd44.Packed\", (i32, i8)>") is None,
"packed 具名结构体不得渲染为无 packed 的形态",
"packed named struct rendered without packed keyword")
# ============================================================
# 测试 16: extractvalue(多结果内联汇编的结果抽取)
#
# 依据真实语料(Test/DefaultArgTest/output/*.ll 等 4163 份 TPV 产物):
# %asm_result = call {i32, i32} asm inteldialect "rdrand $1", "=r,=r,~{cc}"()
# %asm_out_0 = extractvalue {i32, i32} %asm_result, 0
# %asm_out_1 = extractvalue {i32, i32} %asm_result, 1
# 即"多结果内联汇编"是 extractvalue 的唯一来源(另有 {i64, i64} /
# {i32, i32, i32, i32} / {i64, i32, i64, i32} 等多字段结构体结果)。
#
# MLIR 形态(mlir-opt / mlir-translate 22.1.8 实测 exit 0):
# ① 多结果内联汇编 = **单结果 + 结构体类型**:
# %0 = llvm.inline_asm has_side_effects "…", "=r,r" : () -> !llvm.struct<(i32, i32)>
# ② extractvalue 的索引列表写在 `[]` 内、逗号分隔(LLVM 词法的 `<聚合>, i0, i1`
# 被拒绝):
# %a = llvm.extractvalue %0[0] : !llvm.struct<(i32, i32)>
# ③ 多级索引合法(`%v[1, 0]` 于嵌套结构体,实测 exit 0)
# 降级(--mlir-to-llvmir)可得:
# %1 = call { i32, i32 } asm sideeffect "…", "=r,r"()
# %2 = extractvalue { i32, i32 } %1, 0
# %3 = extractvalue { i32, i32 } %1, 1
# ============================================================
# Test 16: extractvalue for multi-result inline asm
# MLIR uses a single struct-typed result plus extractvalue with [idx] index lists
def test_extractvalue_multi_asm(pool: memhub.MemBuddy*):
testcheck.section("Test 16: extractvalue (multi-result inline asm)")
@@ -1355,19 +1255,19 @@ def test_extractvalue_multi_asm(pool: memhub.MemBuddy*):
func: mlirlite.Function* = mcore.CreateFunction(mod, "multi_asm", ty_i32)
entry: mlirlite.BasicBlock* = mcore.CreateBlock(func, "entry")
# ① TPV 真实形态:多结果内联汇编 + 两条 extractvalue(单索引)
# (1) TPV real form: multi-result inline asm + two extractvalue (single index)
mlirlite.block_append_text(pool, entry,
"%2 = call {i32, i32} asm sideeffect \"mov $0, $1; mov $1, $1\", \"=r,r\"()")
mlirlite.block_append_text(pool, entry,
"%a = extractvalue {i32, i32} %2, 0")
mlirlite.block_append_text(pool, entry,
"%b = extractvalue {i32, i32} %2, 1")
# ② 多级索引(嵌套结构体结果的 [1, 0],mlir-opt 22.1.8 实测合法)
# (2) multi-level index [1, 0] into a nested struct result (verified legal)
mlirlite.block_append_text(pool, entry,
"%3 = call {i32, {i32, i32}} asm sideeffect \"mov $0, $1\", \"=r,r\"()")
mlirlite.block_append_text(pool, entry,
"%d = extractvalue {i32, {i32, i32}} %3, 1, 0")
# 引用 %a(保证 extractvalue 结果被真实使用)
# Reference %a so the extractvalue result is actually used
mlirlite.block_append_text(pool, entry, "ret i32 %a")
buf: str = pool.alloc(65536)
@@ -1376,14 +1276,14 @@ def test_extractvalue_multi_asm(pool: memhub.MemBuddy*):
testcheck.info(buf)
dump_mlir(pool, "T16_extractvalue.mlir", buf)
# ① 多结果内联汇编 → 单结果结构体类型
# (1) multi-result inline asm -> single struct-typed result
testcheck.check(string.strstr(buf, ": () -> !llvm.struct<(i32, i32)>") is not None,
"多结果内联汇编 '… : () -> !llvm.struct<(i32, i32)>'",
"multi-result inline_asm struct result missing")
testcheck.check(string.strstr(buf, "llvm.inline_asm has_side_effects") is not None,
"contains 'llvm.inline_asm has_side_effects'",
"missing llvm.inline_asm")
# ② extractvalue:索引在 `[]` 内、聚合类型为 MLIR 形态
# (2) extractvalue: index inside [], aggregate type in MLIR form
testcheck.check(string.strstr(buf, "llvm.extractvalue ") is not None,
"contains 'llvm.extractvalue '", "missing llvm.extractvalue")
testcheck.check(string.strstr(buf, "[0] : !llvm.struct<(i32, i32)>") is not None,
@@ -1395,29 +1295,24 @@ def test_extractvalue_multi_asm(pool: memhub.MemBuddy*):
testcheck.check(string.strstr(buf, ": !llvm.struct<(i32, i32)>") is not None,
"聚合类型为 MLIR 结构体 ': !llvm.struct<(i32, i32)>'",
"aggregate type not rendered as MLIR struct")
# ③ 多级索引:`[1, 0]`(MLIR 内逗号分隔,实测合法)
# (3) multi-level index [1, 0] (comma-separated in MLIR, verified legal)
testcheck.check(string.strstr(buf, "[1, 0] : !llvm.struct<(i32, !llvm.struct<(i32, i32)>)>") is not None,
"多级索引 '[1, 0] : !llvm.struct<(i32, !llvm.struct<(i32, i32)>)>'",
"multi-level extractvalue index missing")
# 负向:LLVM 词法的 `<聚合类型> <值>, <索引>` 不再出现(类型文本必须已转写)
# Negative: LLVM <agg type> <value>, <index> must not appear (type text rewritten)
testcheck.check(string.strstr(buf, "{i32, i32} %") is None,
"LLVM 词法聚合类型文本不再出现('{i32, i32} %' 不出现)",
"raw LLVM aggregate type text leaked")
# 引用侧:extractvalue 结果名原样被 return 引用
# Reference side: the extractvalue result name is returned as-is
testcheck.check(string.strstr(buf, "llvm.return %a : i32") is not None,
"extractvalue 结果被引用 'llvm.return %a : i32'",
"extractvalue result not referenced")
def _sub_arena(main_pool: memhub.MemBuddy*) -> rawptr:
"""从主池切一块子池 arena(返回**裸指针**,由调用方在自己帧内构造 MemBuddy)
"""Carve a sub-pool arena from the main pool and return its raw pointer.
为什么只返回裸指针、不返回构造好的 MemBuddy*:Viper 中无 __new__ 的类实例是
值语义,`MemBuddy(...)` 被降级为栈 alloca;"返回指向本帧局部对象"的指针会
悬空(IR 物证:助手函数内 `alloca %MemBuddy` … `ret %MemBuddy*`,随后第一次
alloc 读 max_order 即落到复用的栈垃圾 → memhub 报"字段被写穿")。
arena 分配失败必须在这里 fail-fast,否则 `MemBuddy(None, size)` 会在
`self.free_lists[i] = 0` 处写空指针(现场 0xC0000005 av_addr=0x0)。
MemBuddy is a stack value here, so returning one would dangle; fail fast if alloc fails.
"""
mem: rawptr = main_pool.alloc(SUB_POOL_SIZE)
if mem is None:
@@ -1429,7 +1324,7 @@ def _sub_arena(main_pool: memhub.MemBuddy*) -> rawptr:
def main() -> int:
testcheck.begin("MLIRLiteTest: mlirlite 库(MLIR llvm 方言文本生成)")
# 初始化主池:仅用于给每个测试切子池(测试内分配一律走各自的子池)
# Init main pool: used only to carve a sub-pool per test (allocs use their sub-pool)
pool_mem: bytes = stdlib.malloc(POOL_SIZE)
if pool_mem is None:
stdio.printf("FAIL: malloc for pool failed\n")
@@ -1439,8 +1334,8 @@ def main() -> int:
stdio.printf("FAIL: memhub.MemBuddy init failed\n")
return 1
# 子池必须在 **main 的帧内** 构造:见 _sub_arena 注释(MemBuddy 实例是栈值,
# 其指针不能跨函数返回)。每个测试一块,互不叠加。
# Sub-pools must be built in main's frame (see _sub_arena): MemBuddy is a stack
# value, so its pointer cannot cross functions. One per test, not overlapping.
sub: memhub.MemBuddy* = memhub.MemBuddy(_sub_arena(pool), SUB_POOL_SIZE)
test_type_print(sub)
+6 -6
View File
@@ -6,7 +6,7 @@ import testcheck
import memhub
# 多态测试: 通过 MemManager 基类指针调用, 验证 vtable 分派到正确子类
# Polymorphism test: call through a MemManager base pointer, verify vtable dispatch
def test_polymorphic(mgr: memhub.MemManager*, size: sizet) -> int:
p: t.CPtr = mgr.alloc(size)
if p is None:
@@ -15,12 +15,12 @@ def test_polymorphic(mgr: memhub.MemManager*, size: sizet) -> int:
return 1
# 测试 calloc 多态: calloc 是 MemManager 具体方法, 内部调 self.alloc (虚函数)
# Test calloc polymorphism: calloc is concrete but calls the virtual self.alloc
def test_calloc_polymorphic(mgr: memhub.MemManager*) -> int:
p: t.CPtr = mgr.calloc(4, 8)
if p is None:
return 0
# 验证清零: 读第一个字节应为 0
# Verify zero-fill: the first byte should be 0
first_byte: uint8 = uint8(*uint64(p, t.CPtr))
if first_byte != 0:
return 0
@@ -72,11 +72,11 @@ def main() -> int:
buddy.free(b1)
b3: t.CPtr = buddy.alloc(100)
testcheck.check(b3 is not None, "MemBuddy alloc after free", "FAIL")
# realloc 增长
# Grow via realloc
b4: t.CPtr = buddy.realloc(b2, 400)
testcheck.check(b4 is not None, "MemBuddy realloc 200->400", "FAIL")
# ========== 多态分派 (核心测试) ==========
# ========== Polymorphic dispatch (core test) ==========
testcheck.section("polymorphic dispatch")
r1: int = test_polymorphic(pool, 50)
testcheck.check(r1 == 1, "vtable: MemPool.alloc/free via MemManager", "FAIL")
@@ -85,7 +85,7 @@ def main() -> int:
r3: int = test_polymorphic(buddy, 50)
testcheck.check(r3 == 1, "vtable: MemBuddy.alloc/free via MemManager", "FAIL")
# calloc 多态 (具体方法调虚函数)
# calloc polymorphism (concrete method calls a virtual one)
rc1: int = test_calloc_polymorphic(pool)
testcheck.check(rc1 == 1, "vtable: calloc dispatches MemPool.alloc", "FAIL")
rc2: int = test_calloc_polymorphic(buddy)
+15 -15
View File
@@ -7,7 +7,7 @@ import stdlib
import testcheck
# === 1. 多继承字段合并 ===
# === 1. multiple inheritance field merging ===
class A:
a: CInt
@@ -29,7 +29,7 @@ class B:
return self.b
# 多继承:C(A, B),字段展平 a+b+c,布局 [a, b, c]
# Multiple inheritance C(A, B): fields flatten to layout [a, b, c].
class C(A, B):
c: CInt
@@ -42,7 +42,7 @@ class C(A, B):
return self.c
# === 2. 菱形去重 + 最左优先 ===
# === 2. diamond dedup + leftmost priority ===
class Base:
shared: CInt
@@ -64,14 +64,14 @@ class Right(Base):
return 3
# 菱形:Diamond(Left, Right),Left/Right 共享 Base,
# Base.shared 字段只展平一次,who() 用 Left(先声明优先)
# Diamond(Left, Right) shares Base: Base.shared flattens once,
# and who() resolves to Left (leftmost priority).
class Diamond(Left, Right):
def __init__(self, s: CInt):
self.shared = s
# === 3. 虚方法多继承 vtable ===
# === 3. virtual method multiple-inheritance vtable ===
@t.CVTable
class ShapeM:
@@ -102,7 +102,7 @@ class ColoredCircle(ShapeM, ColorM):
return 3.14159265 * self.r * self.r
# === 4. 运算符重载 + 方法继承链(MRO) ===
# === 4. operator overloading + method inheritance chain (MRO) ===
class Vec2M:
x: CFloat64T
@@ -120,14 +120,14 @@ class Vec2M:
class Vec2Extra:
# 注意:方法体字段访问基于"定义类字段"(TPV 模型),
# 不引用 Vec2M 的 x/y(跨父类字段引用是更深层语义,暂不验证)。
# Field access uses the defining class's fields (TPV model); does not
# reference Vec2M's x/y (cross-parent field access is out of scope here).
def extra_val(self) -> CInt:
return 7
# 多继承:__add__ 继承自 Vec2M(运算符重载 MRO 链),
# extra_val 继承自 Vec2Extra(方法查找 MRO 链)
# Multiple inheritance: __add__ comes from Vec2M (operator-overload MRO),
# extra_val from Vec2Extra (method lookup MRO).
class Vec2Both(Vec2M, Vec2Extra):
def __new__() -> 'Vec2Both' | CPtr:
return stdlib.malloc(16)
@@ -145,7 +145,7 @@ def main() -> CInt | CExport:
buf: CChar | CPtr = CPtr(stdlib.malloc(256))
# === 1. 字段合并 + 属性访问 + 方法调用 ===
# === 1. field merge + attribute access + method calls ===
testcheck.section("多继承字段合并")
obj_c = C(1, 2, 3)
viperlib.snprintf(buf, 256, "C: a=%d b=%d c=%d", obj_c.a, obj_c.b, obj_c.c)
@@ -158,7 +158,7 @@ def main() -> CInt | CExport:
testcheck.check(obj_c.get_c() == 3, "C.get_c 自身 OK", "C.get_c 自身 FAILED")
testcheck.ok("字段合并测试完成")
# === 2. 菱形去重 + 最左优先 ===
# === 2. diamond dedup + leftmost priority ===
testcheck.section("菱形去重 + 最左优先")
dm = Diamond(5)
viperlib.snprintf(buf, 256, "Diamond: shared=%d who=%d base=%d", dm.shared, dm.who(), dm.base_method())
@@ -168,7 +168,7 @@ def main() -> CInt | CExport:
testcheck.check(dm.base_method() == 100, "Base 方法继承 OK", "Base 方法继承 FAILED")
testcheck.ok("菱形去重测试完成")
# === 3. 虚方法多继承 vtable ===
# === 3. virtual method multiple-inheritance vtable ===
testcheck.section("虚方法多继承 vtable")
cc = ColoredCircle(3.0, 7)
area: CFloat64T = cc.area()
@@ -180,7 +180,7 @@ def main() -> CInt | CExport:
testcheck.check(area > 28.0 and area < 28.5, "area 虚方法覆盖 OK", "area 虚方法覆盖 FAILED")
testcheck.ok("虚方法多继承测试完成")
# === 4. 运算符重载 + 方法继承链 ===
# === 4. operator overloading + method inheritance chain ===
testcheck.section("运算符重载 + 方法继承链")
v1 = Vec2Both(3.0, 4.0)
v2 = Vec2Both(1.0, 2.0)
+1 -1
View File
@@ -1,5 +1,5 @@
import t, c
# f8bca62 移动前的旧路径(文件在 lib/Stub/StubMerger/ 下)
# Stale pre-move path; the import is expected to fail.
import lib.Stub.StubMergerStore as StubMergerStore
def main() -> int:
+86 -86
View File
@@ -21,7 +21,7 @@ ARENA_SIZE: CInt = 16777216
def main() -> CInt | CExport:
printf("=== NewAstTest Start ===\n")
# 初始化分配器
# Initialize allocator
arena: bytes = stdlib.malloc(ARENA_SIZE)
if arena is None:
printf("FAIL: arena alloc failed\n")
@@ -34,7 +34,7 @@ def main() -> CInt | CExport:
passed: CInt = 0
failed: CInt = 0
# --- 分配 dump 缓冲区(用于 AST 反向输出测试) ---
# --- Allocate dump buffer for AST round-trip output tests ---
DUMP_BUF_SIZE: sizet = 8192
dump_buf: char | CPtr = stdlib.malloc(DUMP_BUF_SIZE)
if dump_buf is None:
@@ -42,7 +42,7 @@ def main() -> CInt | CExport:
stdlib.free(arena)
return 1
# --- Test 0: Match 语句 ---
# --- Test 0: Match statement ---
match_src: str = """match x:
case 1:
pass
@@ -57,7 +57,7 @@ def main() -> CInt | CExport:
failed += 1
printf("FAIL: parse match with cases failed\n")
# --- Test 1: Name 节点创建 ---
# --- Test 1: Name node creation ---
name_x: Name | CPtr = Name(pool, "x", ASTCtx.Load)
if name_x is None:
printf("FAIL: Name creation\n")
@@ -66,7 +66,7 @@ def main() -> CInt | CExport:
passed += 1
printf("PASS: Name('x'), kind=%d\n", name_x.kind())
# --- Test 2: ConstantInt 节点 ---
# --- Test 2: ConstantInt node ---
int_42: Constant | CPtr = Constant(pool, CONST_INT, 42, 0.0, None, 1, 0)
if int_42 is None:
printf("FAIL: ConstantInt creation\n")
@@ -76,7 +76,7 @@ def main() -> CInt | CExport:
printf("PASS: ConstantInt(42), kind=%d, val=%lld\n",
int_42.kind(), int_42.int_val)
# --- Test 3: ConstantStr 节点 ---
# --- Test 3: ConstantStr node ---
str_hello: Constant | CPtr = Constant(pool, CONST_STR, 0, 0.0, "hello", 2, 0)
if str_hello is None:
printf("FAIL: ConstantStr creation\n")
@@ -85,7 +85,7 @@ def main() -> CInt | CExport:
passed += 1
printf("PASS: ConstantStr('hello'), kind=%d\n", str_hello.kind())
# --- Test 4: ConstantNone 节点 ---
# --- Test 4: ConstantNone node ---
const_none: Constant | CPtr = Constant(pool, CONST_NONE, 0, 0.0, None, 3, 0)
if const_none is None:
printf("FAIL: ConstantNone creation\n")
@@ -94,7 +94,7 @@ def main() -> CInt | CExport:
passed += 1
printf("PASS: ConstantNone, kind=%d\n", const_none.kind())
# --- Test 5: BinOp 节点 (x + 42) ---
# --- Test 5: BinOp node (x + 42) ---
binop: BinOp | CPtr = BinOp(pool, name_x, OpKind.Add, int_42)
if binop is None:
printf("FAIL: BinOp creation\n")
@@ -103,7 +103,7 @@ def main() -> CInt | CExport:
passed += 1
printf("PASS: BinOp(Add), kind=%d\n", binop.kind())
# --- Test 6: UnaryOp 节点 (-x) ---
# --- Test 6: UnaryOp node (-x) ---
unary: UnaryOp | CPtr = UnaryOp(pool, OpKind.USub, name_x)
if unary is None:
printf("FAIL: UnaryOp creation\n")
@@ -112,7 +112,7 @@ def main() -> CInt | CExport:
passed += 1
printf("PASS: UnaryOp(USub), kind=%d\n", unary.kind())
# --- Test 7: list[AST | CPtr] 容器 ---
# --- Test 7: list[AST | CPtr] container ---
body: list[AST | CPtr] | CPtr = list[AST | CPtr](pool, 8)
if body is None:
printf("FAIL: list creation\n")
@@ -128,7 +128,7 @@ def main() -> CInt | CExport:
failed += 1
printf("FAIL: list count=%zu (expected 2)\n", cnt)
# --- Test 8: list get + kind 分派 ---
# --- Test 8: list get + kind dispatch ---
if body is not None:
item0: AST | CPtr = body.get(0)
if item0 is not None:
@@ -143,7 +143,7 @@ def main() -> CInt | CExport:
failed += 1
printf("FAIL: list get(0) returned None\n")
# --- Test 9: Module 节点 (新签名:Module(pool) + append) ---
# --- Test 9: Module node (Module(pool) + append) ---
mod: Module | CPtr = Module(pool)
if mod is None:
printf("FAIL: Module creation\n")
@@ -154,7 +154,7 @@ def main() -> CInt | CExport:
passed += 1
printf("PASS: Module, kind=%d\n", mod.kind())
# --- Test 10: 多态分派 — 通过 AST 基类指针调用 kind() ---
# --- Test 10: polymorphic dispatch via AST base pointer kind() ---
ast_ptr: AST | CPtr = mod
poly_kind: CInt = ast_ptr.kind()
if poly_kind == ASTKind.Module:
@@ -164,7 +164,7 @@ def main() -> CInt | CExport:
failed += 1
printf("FAIL: polymorphic kind()=%d (expected %d)\n", poly_kind, ASTKind.Module)
# --- Test 11: 多态分派 — list 中的节点 ---
# --- Test 11: polymorphic dispatch on list elements ---
if body is not None:
ast_item: AST | CPtr = body.get(1)
if ast_item is not None:
@@ -179,7 +179,7 @@ def main() -> CInt | CExport:
failed += 1
printf("FAIL: list get(1) returned None\n")
# --- Test 12: Return 节点 ---
# --- Test 12: Return node ---
ret: Return | CPtr = Return(pool, binop)
if ret is None:
printf("FAIL: Return creation\n")
@@ -188,7 +188,7 @@ def main() -> CInt | CExport:
passed += 1
printf("PASS: Return, kind=%d\n", ret.kind())
# --- Test 13: Expr 语句节点 ---
# --- Test 13: Expr statement node ---
expr_stmt: Expr | CPtr = Expr(pool, binop)
if expr_stmt is None:
printf("FAIL: Expr creation\n")
@@ -197,7 +197,7 @@ def main() -> CInt | CExport:
passed += 1
printf("PASS: Expr, kind=%d\n", expr_stmt.kind())
# --- Test 14: If 节点 (新签名:If(pool, test, orelse),body=children) ---
# --- Test 14: If node (If(pool, test, orelse), body = children) ---
empty_else: list[AST | CPtr] | CPtr = list[AST | CPtr](pool, 8)
if_stmt: If | CPtr = If(pool, binop, empty_else)
if if_stmt is None:
@@ -209,7 +209,7 @@ def main() -> CInt | CExport:
passed += 1
printf("PASS: If, kind=%d\n", if_stmt.kind())
# --- Test 15: Compare 节点 ---
# --- Test 15: Compare node ---
cmp_ops: list[int] | CPtr = list[int](pool)
cmp_ops.append(OpKind.Lt)
cmp_comparators: list[AST | CPtr] | CPtr = list[AST | CPtr](pool, 8)
@@ -222,7 +222,7 @@ def main() -> CInt | CExport:
passed += 1
printf("PASS: Compare, kind=%d\n", cmp_node.kind())
# --- Test 16: Assign 节点 ---
# --- Test 16: Assign node ---
assign_targets: list[AST | CPtr] | CPtr = list[AST | CPtr](pool, 8)
assign_targets.append(name_x)
assign_node: Assign | CPtr = Assign(pool, assign_targets, int_42)
@@ -233,7 +233,7 @@ def main() -> CInt | CExport:
passed += 1
printf("PASS: Assign, kind=%d\n", assign_node.kind())
# --- Test 17: Call 节点 ---
# --- Test 17: Call node ---
call_args: list[AST | CPtr] | CPtr = list[AST | CPtr](pool, 8)
call_args.append(int_42)
call_kwargs: list[AST | CPtr] | CPtr = list[AST | CPtr](pool, 8)
@@ -245,7 +245,7 @@ def main() -> CInt | CExport:
passed += 1
printf("PASS: Call, kind=%d\n", call_node.kind())
# --- Test 18: 字段访问验证 ---
# --- Test 18: field access check ---
if name_x is not None:
nm: str = name_x.id
if nm is not None:
@@ -259,7 +259,7 @@ def main() -> CInt | CExport:
failed += 1
printf("FAIL: Name.id is None\n")
# --- Test 19: parent 指针验证 (binop 被 append 到 mod) ---
# --- Test 19: parent pointer check (binop appended to mod) ---
if binop is not None and binop.parent is mod:
passed += 1
printf("PASS: BinOp.parent == Module (via append)\n")
@@ -267,7 +267,7 @@ def main() -> CInt | CExport:
failed += 1
printf("FAIL: BinOp.parent != Module\n")
# --- Test 20: Module.children 遍历 ---
# --- Test 20: Module.children traversal ---
if mod is not None and mod.children is not None:
mod_cnt: sizet = mod.children.__len__()
if mod_cnt == 2:
@@ -280,7 +280,7 @@ def main() -> CInt | CExport:
failed += 1
printf("FAIL: Module.children is None\n")
# --- Test 21: Module.children 多态分派 ---
# --- Test 21: Module.children polymorphic dispatch ---
if mod is not None and mod.children is not None:
c0: AST | CPtr = mod.children.get(0)
c1: AST | CPtr = mod.children.get(1)
@@ -300,7 +300,7 @@ def main() -> CInt | CExport:
failed += 1
printf("FAIL: Module.children unavailable\n")
# --- Test 22: If.children 遍历 (ret + expr_stmt) ---
# --- Test 22: If.children traversal (ret + expr_stmt) ---
if if_stmt is not None and if_stmt.children is not None:
if_cnt: sizet = if_stmt.children.__len__()
if if_cnt == 2:
@@ -313,7 +313,7 @@ def main() -> CInt | CExport:
failed += 1
printf("FAIL: If.children is None\n")
# --- Test 23: parent 向上遍历 (if_stmt.children[0].parent == if_stmt) ---
# --- Test 23: parent upward traversal (child.parent == if_stmt) ---
if if_stmt is not None and if_stmt.children is not None:
first_child: AST | CPtr = if_stmt.children.get(0)
if first_child is not None and first_child.parent is if_stmt:
@@ -326,7 +326,7 @@ def main() -> CInt | CExport:
failed += 1
printf("FAIL: If.children unavailable for parent test\n")
# --- Test 24: parse_expression 解析 "x + 42" ---
# --- Test 24: parse_expression on "x + 42" ---
expr_src: str = "x + 42"
expr_tree: AST | CPtr = parse_expression(expr_src, pool)
if expr_tree is not None:
@@ -336,7 +336,7 @@ def main() -> CInt | CExport:
failed += 1
printf("FAIL: parse_expression returned None\n")
# --- Test 25: parse 解析简单模块 "x = 42\n" ---
# --- Test 25: parse simple module "x = 42" ---
mod_src: str = "x = 42\n"
parsed_mod: Module | CPtr = parse(mod_src, pool)
if parsed_mod is not None and parsed_mod.kind() == ASTKind.Module:
@@ -346,7 +346,7 @@ def main() -> CInt | CExport:
failed += 1
printf("FAIL: parse('x = 42') failed\n")
# --- Test 26: parse 模块的 children 验证 ---
# --- Test 26: parsed module children check ---
if parsed_mod is not None and parsed_mod.children is not None:
pmod_cnt: sizet = parsed_mod.children.__len__()
if pmod_cnt == 1:
@@ -359,7 +359,7 @@ def main() -> CInt | CExport:
failed += 1
printf("FAIL: parsed Module.children is None\n")
# --- Test 27: parse 模块子节点类型验证 (Assign) ---
# --- Test 27: parsed module child kind check (Assign) ---
if parsed_mod is not None and parsed_mod.children is not None:
pmod_child: AST | CPtr = parsed_mod.children.get(0)
if pmod_child is not None:
@@ -378,7 +378,7 @@ def main() -> CInt | CExport:
failed += 1
printf("FAIL: parsed Module.children unavailable for kind test\n")
# --- Test 28: parse 多语句模块 ---
# --- Test 28: parse multi-statement module ---
multi_src: str = """a = 1
b = 2
c = a + b
@@ -396,7 +396,7 @@ c = a + b
failed += 1
printf("FAIL: parse multi-stmt failed\n")
# --- Test 29: parse if 语句 ---
# --- Test 29: parse if statement ---
if_src: str = """if x > 0:
y = 1
"""
@@ -414,7 +414,7 @@ c = a + b
failed += 1
printf("FAIL: parse if failed\n")
# --- Test 30: parse for 循环 ---
# --- Test 30: parse for loop ---
for_src: str = """for i in range(10):
pass
"""
@@ -432,7 +432,7 @@ c = a + b
failed += 1
printf("FAIL: parse for failed\n")
# --- Test 31: parse while 循环 ---
# --- Test 31: parse while loop ---
while_src: str = """while x < 100:
x = x + 1
"""
@@ -450,7 +450,7 @@ c = a + b
failed += 1
printf("FAIL: parse while failed\n")
# --- Test 32: parse 函数定义 ---
# --- Test 32: parse function definition ---
def_src: str = """def foo(a, b):
return a + b
"""
@@ -468,7 +468,7 @@ c = a + b
failed += 1
printf("FAIL: parse def failed\n")
# --- Test 33: parse 复杂表达式 (a + b * c - 1) ---
# --- Test 33: parse complex expression (a + b * c - 1) ---
complex_expr_src: str = "a + b * c - 1"
complex_expr: AST | CPtr = parse_expression(complex_expr_src, pool)
if complex_expr is not None:
@@ -483,7 +483,7 @@ c = a + b
failed += 1
printf("FAIL: parse complex expr failed\n")
# --- Test 34: parse 嵌套语句 (for 内 if) ---
# --- Test 34: parse nested statement (if inside for) ---
nested_src: str = """for i in range(10):
if i > 5:
x = 1
@@ -502,7 +502,7 @@ c = a + b
failed += 1
printf("FAIL: parse nested for-if failed\n")
# --- Test 35: parse 混合多语句模块 ---
# --- Test 35: parse mixed multi-statement module ---
mixed_src: str = """x = 1
y = 2
if x < y:
@@ -524,7 +524,7 @@ w = z * 2
failed += 1
printf("FAIL: parse mixed module failed\n")
# --- Test 36: dump 反向 - parse("x = 42") → dump → strstr 验证 ---
# --- Test 36: dump round-trip - parse("x = 42") then strstr check ---
if parsed_mod is not None:
dump(parsed_mod, dump_buf, DUMP_BUF_SIZE)
has_assign: str = string.strstr(dump_buf, "Assign")
@@ -539,7 +539,7 @@ w = z * 2
failed += 1
printf("FAIL: parsed_mod unavailable for dump test\n")
# --- Test 37: dump 反向 - parse_expression("x + 42 * 2") → dump → strstr BinOp ---
# --- Test 37: dump round-trip - complex expr then strstr BinOp ---
if complex_expr is not None:
dump(complex_expr, dump_buf, DUMP_BUF_SIZE)
has_binop: str = string.strstr(dump_buf, "BinOp")
@@ -553,7 +553,7 @@ w = z * 2
failed += 1
printf("FAIL: complex_expr unavailable for dump test\n")
# --- Test 38: dump 反向 - parse if → dump → strstr "If" + "Compare" ---
# --- Test 38: dump round-trip - parse if then strstr If/Compare ---
if if_mod is not None:
dump(if_mod, dump_buf, DUMP_BUF_SIZE)
has_if: str = string.strstr(dump_buf, "If(")
@@ -568,7 +568,7 @@ w = z * 2
failed += 1
printf("FAIL: if_mod unavailable for dump test\n")
# --- Test 39: dump 反向 - parse def → dump → strstr "FunctionDef" ---
# --- Test 39: dump round-trip - parse def then strstr FunctionDef ---
if def_mod is not None:
dump(def_mod, dump_buf, DUMP_BUF_SIZE)
has_fdef: str = string.strstr(dump_buf, "FunctionDef")
@@ -582,11 +582,11 @@ w = z * 2
failed += 1
printf("FAIL: def_mod unavailable for dump test\n")
# --- Test 40: AST 结构化输出 - dump 多语句模块完整输出 ---
# --- Test 40: structured dump of multi-statement module ---
if mixed_mod is not None:
dump(mixed_mod, dump_buf, DUMP_BUF_SIZE)
printf("--- AST dump of mixed module ---\n%s\n--- end dump ---\n", dump_buf)
# 验证包含多种节点
# Check multiple node kinds present
has_m_assign: str = string.strstr(dump_buf, "Assign")
has_m_if: str = string.strstr(dump_buf, "If(")
if has_m_assign is not None and has_m_if is not None:
@@ -599,7 +599,7 @@ w = z * 2
failed += 1
printf("FAIL: mixed_mod unavailable for structured dump\n")
# --- Test 41: AST 结构化输出 - dump for 循环完整输出 ---
# --- Test 41: structured dump of for loop ---
if for_mod is not None:
dump(for_mod, dump_buf, DUMP_BUF_SIZE)
printf("--- AST dump of for loop ---\n%s\n--- end dump ---\n", dump_buf)
@@ -614,7 +614,7 @@ w = z * 2
failed += 1
printf("FAIL: for_mod unavailable for structured dump\n")
# --- Test 42: type_name 多态分派验证 ---
# --- Test 42: type_name polymorphic dispatch check ---
if parsed_mod is not None and parsed_mod.children is not None:
tn_node: AST | CPtr = parsed_mod.children.get(0)
if tn_node is not None:
@@ -632,7 +632,7 @@ w = z * 2
failed += 1
printf("FAIL: parsed_mod unavailable for type_name test\n")
# --- Test 43: parse 类定义 ---
# --- Test 43: parse class definition ---
class_src: str = """class Foo(Base):
x = 1
def bar(self):
@@ -672,7 +672,7 @@ except:
failed += 1
printf("FAIL: parse try/except failed\n")
# --- Test 45: parse import 语句 ---
# --- Test 45: parse import statement ---
import_src: str = """import os
from sys import path
"""
@@ -710,7 +710,7 @@ x += 1
failed += 1
printf("FAIL: parse AugAssign failed\n")
# --- Test 47: parse 条件表达式 (x if y else z) ---
# --- Test 47: parse conditional expression (x if y else z) ---
ifexp_src: str = "x if y else z"
ifexp_tree: AST | CPtr = parse_expression(ifexp_src, pool)
ifexp_expr: Expression | CPtr = (Expression | CPtr)(ifexp_tree)
@@ -726,7 +726,7 @@ x += 1
failed += 1
printf("FAIL: parse IfExp failed\n")
# --- Test 48: parse 嵌套函数定义 ---
# --- Test 48: parse nested function definition ---
nested_def_src: str = """def outer():
x = 1
def inner():
@@ -747,7 +747,7 @@ x += 1
failed += 1
printf("FAIL: parse nested def failed\n")
# --- Test 49: dump 复杂代码 (类 + try + 嵌套函数) ---
# --- Test 49: dump complex code (class + try + nested def) ---
complex_src: str = """class Foo(Base):
x = 1
try:
@@ -774,7 +774,7 @@ def bar():
failed += 1
printf("FAIL: parse complex module failed\n")
# --- Test 50: 复杂 mixed_src - 综合语法实例 ---
# --- Test 50: complex mixed_src - combined syntax sample ---
complex_mixed_src: str = """def gcd(a, b):
while b:
t = b
@@ -819,7 +819,7 @@ else:
failed += 1
printf("FAIL: complex mixed_src parse failed\n")
# --- Test 51: Lambda 表达式 ---
# --- Test 51: Lambda expression ---
lambda_src: str = "f = lambda x: x + 1"
lambda_mod: Module | CPtr = parse(lambda_src, pool)
if lambda_mod is not None:
@@ -887,7 +887,7 @@ else:
failed += 1
printf("FAIL: SetComp parse returned None\n")
# --- Test 55: With 语句 ---
# --- Test 55: With statement ---
with_src: str = """with open('f') as f:
data = f.read()
"""
@@ -907,7 +907,7 @@ else:
failed += 1
printf("FAIL: With parse returned None\n")
# --- Test 56: Raise 语句 ---
# --- Test 56: Raise statement ---
raise_src: str = "raise ValueError('bad')"
raise_mod: Module | CPtr = parse(raise_src, pool)
if raise_mod is not None:
@@ -923,7 +923,7 @@ else:
failed += 1
printf("FAIL: Raise parse returned None\n")
# --- Test 57: Assert 语句 ---
# --- Test 57: Assert statement ---
assert_src: str = "assert x > 0, 'x must be positive'"
assert_mod: Module | CPtr = parse(assert_src, pool)
if assert_mod is not None:
@@ -939,7 +939,7 @@ else:
failed += 1
printf("FAIL: Assert parse returned None\n")
# --- Test 58: Del 语句 ---
# --- Test 58: Del statement ---
del_src: str = "del x"
del_mod: Module | CPtr = parse(del_src, pool)
if del_mod is not None:
@@ -973,7 +973,7 @@ else:
failed += 1
printf("FAIL: Slice parse returned None\n")
# --- Test 60: Tuple 解包 ---
# --- Test 60: Tuple unpacking ---
tuple_src: str = "a, b = 1, 2"
tuple_mod: Module | CPtr = parse(tuple_src, pool)
if tuple_mod is not None:
@@ -989,7 +989,7 @@ else:
failed += 1
printf("FAIL: Tuple parse returned None\n")
# --- Test 61: 默认参数 + 关键字参数签名 ---
# --- Test 61: default args + keyword args signature ---
defdef_src: str = "def f(a, b=10): return a + b"
defdef_mod: Module | CPtr = parse(defdef_src, pool)
if defdef_mod is not None:
@@ -1007,7 +1007,7 @@ else:
failed += 1
printf("FAIL: defdef parse returned None\n")
# --- Test 62: 装饰器 ---
# --- Test 62: decorator ---
deco_src: str = """@my_dec
def f():
pass
@@ -1026,7 +1026,7 @@ def f():
failed += 1
printf("FAIL: Decorator parse returned None\n")
# --- Test 63: 链式赋值 ---
# --- Test 63: chained assignment ---
chain_src: str = "a = b = c = 42"
chain_mod: Module | CPtr = parse(chain_src, pool)
if chain_mod is not None:
@@ -1045,7 +1045,7 @@ def f():
failed += 1
printf("FAIL: Chain parse returned None\n")
# --- Test 64: 位运算 ---
# --- Test 64: bitwise ops ---
bit_src: str = "y = (a | b) & c ^ d << 2"
bit_mod: Module | CPtr = parse(bit_src, pool)
if bit_mod is not None:
@@ -1064,7 +1064,7 @@ def f():
failed += 1
printf("FAIL: Bit ops parse returned None\n")
# --- Test 65: 多继承 + 多装饰器 ---
# --- Test 65: multiple inheritance + decorators ---
multi_src: str = """@dec1
@dec2
class C(Base1, Base2):
@@ -1126,7 +1126,7 @@ class C(Base1, Base2):
failed += 1
printf("FAIL: fstring parse returned None\n")
# --- Test 68: 嵌套函数 + 闭包 ---
# --- Test 68: nested function + closure ---
nested_src: str = """def outer():
x = 10
def inner():
@@ -1149,7 +1149,7 @@ class C(Base1, Base2):
failed += 1
printf("FAIL: nested parse returned None\n")
# --- Test 69: Match 字面量整数模式 ---
# --- Test 69: Match literal int pattern ---
m_lit_src: str = """match x:
case 1:
pass
@@ -1168,7 +1168,7 @@ class C(Base1, Base2):
failed += 1
printf("FAIL: Match literal int parse returned None\n")
# --- Test 70: Match 字面量字符串模式 ---
# --- Test 70: Match literal string pattern ---
m_str_src: str = """match x:
case "hello":
pass
@@ -1187,7 +1187,7 @@ class C(Base1, Base2):
failed += 1
printf("FAIL: Match literal str parse returned None\n")
# --- Test 71: Match 负数字面量模式 ---
# --- Test 71: Match negative literal pattern ---
m_neg_src: str = """match x:
case -1:
pass
@@ -1206,7 +1206,7 @@ class C(Base1, Base2):
failed += 1
printf("FAIL: Match negative literal parse returned None\n")
# --- Test 72: Match None 单例模式 ---
# --- Test 72: Match None singleton pattern ---
m_none_src: str = """match x:
case None:
pass
@@ -1225,7 +1225,7 @@ class C(Base1, Base2):
failed += 1
printf("FAIL: Match None parse returned None\n")
# --- Test 73: Match True 单例模式 ---
# --- Test 73: Match True singleton pattern ---
m_true_src: str = """match x:
case True:
pass
@@ -1244,7 +1244,7 @@ class C(Base1, Base2):
failed += 1
printf("FAIL: Match True parse returned None\n")
# --- Test 74: Match False 单例模式 ---
# --- Test 74: Match False singleton pattern ---
m_false_src: str = """match x:
case False:
pass
@@ -1263,7 +1263,7 @@ class C(Base1, Base2):
failed += 1
printf("FAIL: Match False parse returned None\n")
# --- Test 75: Match 通配符 _ 模式 ---
# --- Test 75: Match wildcard _ pattern ---
m_wild_src: str = """match x:
case _:
pass
@@ -1282,7 +1282,7 @@ class C(Base1, Base2):
failed += 1
printf("FAIL: Match wildcard parse returned None\n")
# --- Test 76: Match 捕获变量模式 ---
# --- Test 76: Match capture variable pattern ---
m_cap_src: str = """match x:
case y:
pass
@@ -1301,7 +1301,7 @@ class C(Base1, Base2):
failed += 1
printf("FAIL: Match capture parse returned None\n")
# --- Test 77: Match 值模式 (dotted name Color.RED) ---
# --- Test 77: Match value pattern (dotted name Color.RED) ---
m_val_src: str = """match x:
case Color.RED:
pass
@@ -1322,7 +1322,7 @@ class C(Base1, Base2):
failed += 1
printf("FAIL: Match value parse returned None\n")
# --- Test 78: Match 序列模式 [1, 2] ---
# --- Test 78: Match sequence pattern [1, 2] ---
m_seq_src: str = """match x:
case [1, 2]:
pass
@@ -1341,7 +1341,7 @@ class C(Base1, Base2):
failed += 1
printf("FAIL: Match sequence parse returned None\n")
# --- Test 79: Match 序列带星号 [a, *rest] ---
# --- Test 79: Match starred sequence [a, *rest] ---
m_star_src: str = """match x:
case [a, *rest]:
pass
@@ -1360,7 +1360,7 @@ class C(Base1, Base2):
failed += 1
printf("FAIL: Match star parse returned None\n")
# --- Test 80: Match 类模式 Point(x, y) ---
# --- Test 80: Match class pattern Point(x, y) ---
m_cls_src: str = """match p:
case Point(x, y):
pass
@@ -1379,7 +1379,7 @@ class C(Base1, Base2):
failed += 1
printf("FAIL: Match class parse returned None\n")
# --- Test 81: Match 类模式带关键字 Point(x=0, y=0) ---
# --- Test 81: Match keyword class pattern Point(x=0, y=0) ---
m_kwcls_src: str = """match p:
case Point(x=0, y=0):
pass
@@ -1398,7 +1398,7 @@ class C(Base1, Base2):
failed += 1
printf("FAIL: Match class kwd parse returned None\n")
# --- Test 82: Match OR 模式 1 | 2 ---
# --- Test 82: Match OR pattern 1 | 2 ---
m_or_src: str = """match x:
case 1 | 2:
pass
@@ -1417,7 +1417,7 @@ class C(Base1, Base2):
failed += 1
printf("FAIL: Match OR parse returned None\n")
# --- Test 83: Match AS 模式 [x] as p ---
# --- Test 83: Match AS pattern [x] as p ---
m_as_src: str = """match x:
case [x] as p:
pass
@@ -1438,7 +1438,7 @@ class C(Base1, Base2):
failed += 1
printf("FAIL: Match AS parse returned None\n")
# --- Test 84: Match guard 模式 case x if x > 0 ---
# --- Test 84: Match guard pattern case x if x > 0 ---
m_guard_src: str = """match x:
case x if x > 0:
pass
@@ -1457,7 +1457,7 @@ class C(Base1, Base2):
failed += 1
printf("FAIL: Match guard parse returned None\n")
# --- Test 85: Match 映射模式 {"k": v} ---
# --- Test 85: Match mapping pattern {"k": v} ---
m_map_src: str = """match x:
case {"k": v}:
pass
@@ -1476,7 +1476,7 @@ class C(Base1, Base2):
failed += 1
printf("FAIL: Match mapping parse returned None\n")
# --- Test 86: Match 映射带 rest {"k": v, **rest} ---
# --- Test 86: Match mapping with rest {"k": v, **rest} ---
m_map2_src: str = """match x:
case {"k": v, **rest}:
pass
@@ -1497,7 +1497,7 @@ class C(Base1, Base2):
failed += 1
printf("FAIL: Match mapping rest parse returned None\n")
# --- Test 87: Match 组合模式 (1 | 2) as p ---
# --- Test 87: Match combined pattern (1 | 2) as p ---
m_combo_src: str = """match x:
case (1 | 2) as p:
pass
@@ -1634,7 +1634,7 @@ class C(Base1, Base2):
failed += 1
printf("FAIL: async with parse returned None\n")
# --- Test 91: Match 复合语句 (多 case + 多类型模式) ---
# --- Test 91: Match compound statement (multi-case, multi-pattern) ---
m_complex_src: str = """match cmd:
case "quit":
pass
@@ -1665,7 +1665,7 @@ class C(Base1, Base2):
failed += 1
printf("FAIL: Match complex parse returned None\n")
# --- Test 92: async def + async for + async with 组合 ---
# --- Test 92: async def + async for + async with combo ---
acombo_src: str = """async def f():
async with ctx:
async for x in y:
@@ -1695,7 +1695,7 @@ class C(Base1, Base2):
failed += 1
printf("FAIL: async combo parse returned None\n")
# --- 结果汇总 ---
# --- Result summary ---
printf("\n=== Results: %d passed, %d failed ===\n", passed, failed)
stdlib.free(dump_buf)
+7 -21
View File
@@ -5,14 +5,8 @@ import testcheck
# ============================================================
# 复现:NoVTable 多继承下跨 Mixin self. 方法调用
#
# 缺陷:BaseB.caller 内 `self.helper()`(helper 定义在兄弟 Mixin BaseA,
# 经 Combined 多继承组合)被 mangle 成 `<sha1>.BaseB.helper`
# (用调用者自身/直接父类做前缀),而定义符号是 `<sha1>.BaseA.helper`
# → ld.lld undefined symbol(TPV 侧 StmtGenMixin.translate_stmt 调
# self.translate_return 同根因,符号成 StmtGenDeclMixin.translate_return)。
# 期望:按实际定义类(BaseA)做前缀,或按最终组合类(Combined)。
# NoVTable multiple inheritance: a sibling-mixin self.helper() call (BaseB
# calling helper defined in BaseA) must resolve the symbol to BaseA/Combined.
# ============================================================
novirtual class BaseA:
a: int
@@ -43,13 +37,8 @@ def test_cross_mixin_call():
# ============================================================
# 扩展 Test 2:多级 Mixin 链(父类继承 + 兄弟)+ 字段写
#
# 覆盖 Handles 去壳核心要求:
# MixinB2 继承 MixinA2(1 级父类);Combined2(MixinB2, MixinC2) 多继承。
# MixinC2.outer2 调兄弟 MixinB2.mid2(this_adjust 到 MixinB2 字段区),
# MixinB2.mid2 调父类 MixinA2.inner2(this_adjust 到 MixinA2 字段区),
# inner2 内写 self.a2(this_adjust 精确到组合类中 a2 字段)。
# Test 2: multilevel mixin chain (parent inheritance + sibling) with field
# writes, exercising this_adjust across sibling and parent field regions.
# ============================================================
novirtual class MixinA2:
a2: int
@@ -83,18 +72,15 @@ def test_multilevel_chain():
c.a2 = 1
c.b2 = 2
c.c2 = 3
# outer2 -> mid2 -> inner2:inner2 写 a2(1->11),mid2=11+2=13,outer2=13+3=16
# outer2 -> mid2 -> inner2: inner2 writes a2 (1->11), mid2=13, outer2=16
testcheck.check(c.outer2() == 16,
"outer2()==16 (C->B->A chain + field write)",
"multilevel chain fail")
# ============================================================
# 扩展 Test 3:第二父类字段区偏移(this_adjust 非 0)+ 指针字段
#
# Combined3(PtrMixin, DataMixin):PtrMixin 第一父类(字段区偏移 0),
# DataMixin 第二父类(字段区偏移 = sizeof(PtrMixin),非 0)。
# DataMixin.get_val 内 self.val 需 this_adjust 到第二父类字段区。
# Test 3: second-parent field offset (nonzero this_adjust) plus a pointer
# field; self.val must adjust into DataMixin's field region.
# ============================================================
novirtual class PtrMixin:
name: char*
+40 -77
View File
@@ -7,19 +7,13 @@ import viperlib
import stdlib
# ============================================================
# 子类继承 linkedlist.LinkedNode:启用链表/树形能力
# 字段展平,无 vtable;OOP 方法通过 _generate_inherited_method_wrappers
# 自动生成子类包装(self bitcast 为父类指针后调用父类方法)。
# 从 LinkedNode* 取回 Node* 需显式向下转型:(Node | t.CPtr)(ptr)
# ============================================================
# Subclass of linkedlist.LinkedNode: flattened fields, no vtable; OOP wrappers are auto-generated.
# Cast LinkedNode* back to Node* explicitly: (Node | t.CPtr)(ptr)
class Node(linkedlist.LinkedNode):
value: int
# ============================================================
# 测试 1:append + child_count
# ============================================================
# --- Test 1: append + child_count ---
def test_append():
testcheck.section("Test 1: append")
root: Node = Node()
@@ -35,7 +29,7 @@ def test_append():
testcheck.check(root.child_count == 3,
"append count=3",
"append count fail")
# 验证顺序(LinkedNode* → Node* 显式向下转型)
# verify order (explicit downcast LinkedNode* -> Node*)
c1: Node* = (Node*)(root.child)
c2: Node* = (Node*)(c1.next)
c3: Node* = (Node*)(c2.next)
@@ -44,9 +38,7 @@ def test_append():
"order fail")
# ============================================================
# 测试 2:双向链表 prev 指针
# ============================================================
# --- Test 2: doubly linked prev ---
def test_prev_link():
testcheck.section("Test 2: prev pointer (doubly linked)")
root: Node = Node()
@@ -56,20 +48,18 @@ def test_prev_link():
b.value = 2
root.append(a)
root.append(b)
# b.prev 应指向 a
# b.prev should point to a
bp: Node* = (Node*)(b.prev)
testcheck.check(bp is not None and bp.value == 1,
"b.prev.value=1",
"prev link fail")
# a.prev 应为 None(第一个子节点)
# a.prev should be None (first child)
testcheck.check(a.prev is None,
"a.prev=None",
"first prev fail")
# ============================================================
# 测试 3:last_child 指针(O(1) 追加验证)
# ============================================================
# --- Test 3: last_child pointer ---
def test_last_child():
testcheck.section("Test 3: last_child pointer")
root: Node = Node()
@@ -89,9 +79,7 @@ def test_last_child():
"last_child fail 2")
# ============================================================
# 测试 4:detach(O(1) 摘除)
# ============================================================
# --- Test 4: detach (O(1) unlink) ---
def test_remove():
testcheck.section("Test 4: detach (O(1) unlink)")
root: Node = Node()
@@ -104,30 +92,28 @@ def test_remove():
root.append(a)
root.append(b)
root.append(c)
# 摘除中间的 b
# detach middle node b
b.detach()
testcheck.check(root.child_count == 2,
"count=2 after detach",
"detach count fail")
# a.next 应直接指向 c
# a.next should point directly to c
an: Node* = (Node*)(a.next)
testcheck.check(an is not None and an.value == 3,
"a.next.value=3",
"detach link fail")
# c.prev 应指向 a
# c.prev should point to a
cp: Node* = (Node*)(c.prev)
testcheck.check(cp is not None and cp.value == 1,
"c.prev.value=1",
"detach prev fail")
# b 的链接应清空
# b links should be cleared
testcheck.check(b.parent is None and b.next is None and b.prev is None,
"b cleared",
"b not cleared")
# ============================================================
# 测试 5:remove_child
# ============================================================
# --- Test 5: remove_child ---
def test_remove_child():
testcheck.section("Test 5: remove_child")
root: Node = Node()
@@ -147,9 +133,7 @@ def test_remove_child():
"remove_child first fail")
# ============================================================
# 测试 6:prepend + insert_before + insert_after
# ============================================================
# --- Test 6: prepend/insert_before/insert_after ---
def test_insert_ops():
testcheck.section("Test 6: prepend/insert_before/insert_after")
root: Node = Node()
@@ -163,9 +147,9 @@ def test_insert_ops():
d.value = 4
root.append(a) # [1]
root.append(c) # [1, 3]
root.insert_before(c, b) # [1, 2, 3] 在 c 前插入 b
root.insert_after(a, d) # [1, 4, 2, 3] 在 a 后插入 d
# 遍历验证顺序
root.insert_before(c, b) # [1, 2, 3] insert b before c
root.insert_after(a, d) # [1, 4, 2, 3] insert d after a
# traverse to verify order
cur: Node* = (Node*)(root.child)
v0: int = cur.value
cur = (Node*)(cur.next)
@@ -182,11 +166,8 @@ def test_insert_ops():
"insert count fail")
# ============================================================
# 测试 7:child_at + count_children
# 注意:Viper 中 Node() 是栈分配,循环内 n 会被复用(同一地址),
# 导致所有子节点指向同一内存。必须用独立变量保证各节点地址不同。
# ============================================================
# --- Test 7: child_at + count_children ---
# Node() is stack-allocated; use distinct variables so each node has a unique address.
def test_index_access():
testcheck.section("Test 7: child_at + count_children")
root: Node = Node()
@@ -229,9 +210,7 @@ def test_index_access():
"count_children fail")
# ============================================================
# 测试 8:has_children + first_sibling/last_sibling
# ============================================================
# --- Test 8: has_children + sibling traverse ---
def test_sibling_traverse():
testcheck.section("Test 8: has_children + sibling traverse")
root: Node = Node()
@@ -250,7 +229,7 @@ def test_sibling_traverse():
testcheck.check(root.has_children() == 1,
"has_children=1",
"has_children fail")
# 从 b 出发找头尾兄弟
# find first/last sibling starting from b
fs: Node* = (Node*)(b.first_sibling())
ls: Node* = (Node*)(b.last_sibling())
testcheck.check(fs is not None and fs.value == 1,
@@ -261,9 +240,7 @@ def test_sibling_traverse():
"last_sibling fail")
# ============================================================
# 测试 9:unlink(断开所有连接)
# ============================================================
# --- Test 9: unlink ---
def test_unlink():
testcheck.section("Test 9: unlink")
root: Node = Node()
@@ -273,7 +250,7 @@ def test_unlink():
b.value = 2
root.append(a)
root.append(b)
# unlink a:从兄弟链摘除 + 断开父子链接
# unlink a: remove from sibling chain and clear parent/child links
a.unlink()
testcheck.check(a.next is None and a.prev is None and a.parent is None,
"a links cleared",
@@ -281,15 +258,13 @@ def test_unlink():
testcheck.check(a.child is None and a.last_child is None and a.child_count == 0,
"a child cleared",
"a child not cleared")
# root 应只剩 b
# root should keep only b
testcheck.check(root.child_count == 1,
"root count=1 after unlink",
"root count fail")
# ============================================================
# 测试 10:SListNode 单向链表(OOP 方法)
# ============================================================
# --- Test 10: SListNode (singly linked, OOP) ---
class SNode(linkedlist.SListNode):
value: int
@@ -302,7 +277,7 @@ def test_slist():
n0.value = 100
n1.value = 200
n2.value = 300
# append (O(n)) — 直接用 n0 作为 head
# append (O(n)); use n0 as head
head: linkedlist.SListNode* = n0
head = head.append(n1)
head = head.append(n2)
@@ -327,7 +302,7 @@ def test_slist():
testcheck.check(a3 is None,
"at(3)=None",
"at 3 fail")
# remove (移除中间节点 n1)
# remove (drop middle node n1)
head = head.remove(n1)
testcheck.check(head.count() == 2,
"after remove count=2",
@@ -335,7 +310,7 @@ def test_slist():
testcheck.check(n1.Next is None,
"n1.Next cleared",
"n1.Next not cleared")
# 移除后 a0.Next 应指向 n2
# after removal a0.Next should point to n2
a0b: SNode* = (SNode*)(a0.Next)
testcheck.check(a0b is not None and a0b.value == 300,
"after remove a0.Next=300",
@@ -352,12 +327,10 @@ def test_slist():
"append count fail")
# ============================================================
# 测试 11:viperlib.sprintf *args 转发
# ============================================================
# --- Test 11: viperlib.sprintf *args forwarding ---
def test_sprintf_vararg():
testcheck.section("Test 11: viperlib.sprintf *args forwarding")
# 测试 %d 单参数
# single %d argument
buf: char* = stdlib.malloc(32)
if buf is None: return
buf[0] = 0
@@ -365,7 +338,7 @@ def test_sprintf_vararg():
testcheck.check(string.strcmp(buf, "key42") == 0,
"sprintf key42",
"sprintf key%d fail")
# 测试无参数
# no argument
buf2: char* = stdlib.malloc(32)
if buf2 is None: return
buf2[0] = 0
@@ -373,7 +346,7 @@ def test_sprintf_vararg():
testcheck.check(string.strcmp(buf2, "hello") == 0,
"sprintf hello",
"sprintf no-arg fail")
# 测试多参数
# multiple arguments
buf3: char* = stdlib.malloc(32)
if buf3 is None: return
buf3[0] = 0
@@ -383,18 +356,8 @@ def test_sprintf_vararg():
"sprintf multi-arg fail")
# ============================================================
# 测试 12:泛型 GSListNode[T] + GSList[T]
#
# 验证 4 个技术点(为 mlirlite 简化铺路):
# 1. 递归泛型 class GNode(GSListNode[GNode]):
# 2. novirtual class + 泛型组合(GNode 无 vptr,字段展平)
# 3. 泛型类作字段类型 lst: GSList[GNode]
# 4. 泛型方法继承 lst.append(n) / lst.count() / lst.at(i)
# (GSList[T] 的方法在特化 GSList[GNode] 后可用)
#
# 注:编译器暂不支持 模块.泛型类[T]() 跨模块构造,故本地定义。
# ============================================================
# --- Test 12: generic GSListNode[T] + GSList[T] ---
# Recursive generic, novirtual flattened fields, generic as field type; local def (no cross-module generic support yet).
novirtual class GSListNode[T]:
Next: T*
@@ -438,10 +401,10 @@ class GNode(GSListNode[GNode]):
def test_generic_slist():
testcheck.section("Test 12: Generic GSListNode[T] + GSList[T]")
# 技术点 3: 泛型类作字段类型 + 构造
# generic class as field type + construction
lst: GSList[GNode]* = GSList[GNode]()
# 技术点 1+2: 递归泛型 + NoVTable 组合(GNode 定义在上方)
# recursive generic + NoVTable combo (GNode defined above)
n0: GNode = GNode()
n1: GNode = GNode()
n2: GNode = GNode()
@@ -449,7 +412,7 @@ def test_generic_slist():
n1.Value = 20
n2.Value = 30
# 技术点 4: 泛型方法继承
# generic method inheritance
lst.append(n0)
lst.append(n1)
lst.append(n2)
@@ -459,7 +422,7 @@ def test_generic_slist():
"GSList.count()=3",
"GSList count fail")
# at (O(n)) — 返回 GNode|CPtr,无需向下转型
# at (O(n)) returns GNode|CPtr, no downcast needed
a0: GNode* = lst.at(0)
a1: GNode* = lst.at(1)
a2: GNode* = lst.at(2)
@@ -477,7 +440,7 @@ def test_generic_slist():
"GSList.at(3)=None",
"GSList at 3 fail")
# Next 字段强类型(a0.Next 直接是 GNode|CPtr,无需转型)
# Next is strongly typed (a0.Next is GNode|CPtr, no cast)
testcheck.check(a0.Next is a1,
"a0.Next is a1 (strong type)",
"a0.Next fail")
+1 -2
View File
@@ -68,8 +68,7 @@ def section_footer():
# ============================================================
# Timer: 单调时钟(GetTickCount64 毫秒 → 秒)
# 原 c.Timer() 无编译器支持(TPC/TPV 均无),改用 Win32 API
# Timer: monotonic clock (GetTickCount64 ms -> s) via Win32 API.
# ============================================================
def timer_sec() -> double:
return double(w32.win32base.GetTickCount64()) / double(1000.0)
+16 -16
View File
@@ -7,7 +7,7 @@ import stdlib
import testcheck
# === OOP 继承 + 虚方法 ===
# === OOP inheritance + virtual methods ===
@t.CVTable
class Shape:
@@ -64,7 +64,7 @@ class Rect(Shape):
return self
# === 运算符重载 + 链式调用(堆分配) ===
# === operator overloading + chained calls (heap allocated) ===
class Vec2:
x: CFloat64T
@@ -133,7 +133,7 @@ class Vec3:
return self.dot(self)
# === 独立类(非继承) ===
# === standalone classes (no inheritance) ===
@t.CVTable
class Dog:
@@ -180,7 +180,7 @@ class Cat:
return 0
# === 嵌套对象组合(堆分配) ===
# === nested object composition (heap allocated) ===
class Transform:
px: CFloat64T
@@ -211,7 +211,7 @@ class Transform:
return Vec3(self.px * self.scale_x, self.py * self.scale_y, self.pz * self.scale_z)
# === 多层继承(子类只重写需要的方法) ===
# === multilevel inheritance (subclasses override only what they need) ===
@t.CVTable
class Vehicle:
@@ -264,7 +264,7 @@ def main() -> CInt | CExport:
buf: CChar | CPtr = CPtr(stdlib.malloc(256))
# === OOP 继承测试 ===
# === OOP inheritance test ===
testcheck.section("OOP 继承测试")
c1 = Circle(0.0, 0.0, 5.0)
viperlib.snprintf(buf, 256, "Circle area=%.2f perim=%.2f", c1.area(), c1.perimeter())
@@ -274,7 +274,7 @@ def main() -> CInt | CExport:
viperlib.snprintf(buf, 256, "Rect area=%.2f perim=%.2f", r1.area(), r1.perimeter())
print(buf)
# 链式调用: scale -> move
# chained calls: scale -> move
c2 = Circle(1.0, 2.0, 3.0)
c2.scale(2.0).move(10.0, 20.0)
viperlib.snprintf(buf, 256, "Circle after scale+move: x=%.1f y=%.1f r=%.1f area=%.2f",
@@ -288,7 +288,7 @@ def main() -> CInt | CExport:
print(buf)
testcheck.ok("OOP 继承测试完成")
# === Vec2 运算符重载 + 链式调用(堆分配) ===
# === Vec2 operator overloading + chained calls (heap) ===
testcheck.section("Vec2 运算符重载 + 链式调用")
v1 = Vec2(3.0, 4.0)
v2 = Vec2(1.0, 2.0)
@@ -312,13 +312,13 @@ def main() -> CInt | CExport:
viperlib.snprintf(buf, 256, "Vec2 dot: %.1f", d)
print(buf)
# 链式运算: (v1 + v2) * 3.0
# chained op: (v1 + v2) * 3.0
v_chain = (v1 + v2) * 3.0
viperlib.snprintf(buf, 256, "Vec2 chain (v1+v2)*3: (%.1f, %.1f)", v_chain.x, v_chain.y)
print(buf)
testcheck.ok("Vec2 运算符重载测试完成")
# === Vec3 运算符重载 + 链式调用(堆分配) ===
# === Vec3 operator overloading + chained calls (heap) ===
testcheck.section("Vec3 运算符重载 + 链式调用")
a1 = Vec3(1.0, 0.0, 0.0)
a2 = Vec3(0.0, 1.0, 0.0)
@@ -330,7 +330,7 @@ def main() -> CInt | CExport:
viperlib.snprintf(buf, 256, "Vec3 dot: %.1f", dot_v)
print(buf)
# 链式: (a + b).dot(c)
# chained: (a + b).dot(c)
a3 = Vec3(1.0, 2.0, 3.0)
a4 = Vec3(4.0, 5.0, 6.0)
a5 = Vec3(7.0, 8.0, 9.0)
@@ -338,18 +338,18 @@ def main() -> CInt | CExport:
viperlib.snprintf(buf, 256, "Vec3 chain dot: %.1f", chain_dot)
print(buf)
# 链式: (a * 2.0 - b).cross(c)
# chained: (a * 2.0 - b).cross(c)
chain_cross = (a3 * 2.0 - a4).cross(a5)
viperlib.snprintf(buf, 256, "Vec3 chain cross: (%.1f, %.1f, %.1f)", chain_cross.x, chain_cross.y, chain_cross.z)
print(buf)
# len_sq 链式
# chained len_sq
lsq = a3.len_sq()
viperlib.snprintf(buf, 256, "Vec3 len_sq: %.1f", lsq)
print(buf)
testcheck.ok("Vec3 运算符重载测试完成")
# === Dog/Cat 虚方法 ===
# === Dog/Cat virtual methods ===
testcheck.section("Dog/Cat 虚方法")
dog = Dog(1, CInt32T(30))
cat = Cat(2, CInt32T(9))
@@ -368,7 +368,7 @@ def main() -> CInt | CExport:
print(buf)
testcheck.ok("Dog/Cat 虚方法测试完成")
# === Transform 嵌套组合(堆分配,链式调用) ===
# === Transform nested composition (heap, chained calls) ===
testcheck.section("Transform 嵌套组合")
tr = Transform(10.0, 20.0, 30.0)
tr.apply_scale(2.0, 3.0, 4.0)
@@ -383,7 +383,7 @@ def main() -> CInt | CExport:
print(buf)
testcheck.ok("Transform 嵌套组合测试完成")
# === 多层继承 ===
# === multilevel inheritance ===
testcheck.section("多层继承")
ec = ElectricCar(CInt32T(120), CInt32T(4), CInt32T(80))
viperlib.snprintf(buf, 256, "ECar speed=%d doors=%d battery=%d", ec.speed, ec.doors, ec.battery)
+36 -44
View File
@@ -6,27 +6,23 @@ import w32.win32console
import w32.win32memory
import testcheck
# ============================================================
# PointerTest - 测试指针操作、global声明、数组退化、指针算术
# ============================================================
# PointerTest: pointer operations, global declarations, array decay, pointer arithmetic
# --- Test 1: global 声明对模块级变量的影响 ---
# --- Test 1: global declaration effects on module-level variables ---
_g_val: int = 0
_g_ptr: uint32* = None
def test_global_write():
"""测试:缺少 global 声明时,赋值是否修改模块级变量"""
"""Write to module-level _g_val through the global declaration."""
global _g_val
_g_val = 42
def test_global_write_no_decl():
"""测试:没有 global 声明时,函数内局部赋值不修改模块级变量
"""Local assignment without global leaves the module-level variable unchanged.
新规则:模块级已有 `_g_val` 时,函数内再写 `_g_val: int = ...`(注解同名)
一律判为"重复声明"并终止编译(TypeError)——**不管**注解类型是否与全局相同。
因此这里改用**不重名**的局部变量验证"函数内局部赋值不影响全局"。
Uses a non-conflicting local name; same-name annotated redeclaration is a compile error.
"""
local_val: int = 99 # 独立局部变量,与全局 _g_val 无关
local_val: int = 99 # standalone local, unrelated to global _g_val
def test_global_ptr():
global _g_ptr
@@ -39,31 +35,27 @@ def test_global_ptr():
p[1] = 0x11223344
def test_global_ptr_no_decl():
"""测试:没有 global 声明时,同名注解声明是编译期错误(此处演示合法写法)
"""Same-name annotated redeclaration of a module variable is a compile error.
新规则:模块级已有 `_g_ptr` 时,函数内写 `_g_ptr: t.CUInt32T* = None`
(无 global)或 `global _g_ptr` 之后仍带类型注解声明,都判为"重复声明"并终止
编译(TypeError)——不管注解类型是否与全局相同。合法写法只有两种:
- 修改全局:`global _g_ptr` + **无注解**赋值(见 test_global_ptr)
- 独立局部:换成不与全局重名的变量名(本函数)
Legal forms: global + unannotated assignment, or a non-conflicting local name.
"""
local_ptr: uint32* = None # 独立局部变量,不触碰全局 _g_ptr
local_ptr: uint32* = None # standalone local, does not touch global _g_ptr
# --- Test 2: 指针算术和数组索引 ---
# --- Test 2: pointer arithmetic and array indexing ---
def test_pointer_arithmetic():
"""测试指针算术:偏移计算是否正确"""
"""Verify pointer arithmetic computes offsets correctly."""
buf: uint32* = w32.win32memory.VirtualAlloc(None, 256, 0x3000, 0x04)
if not buf:
testcheck.fail("pointer arithmetic: VirtualAlloc returned NULL")
return
string.memset(buf, 0, 256)
# 写入值
# Write values
for i in range(8):
buf[i] = uint32(i * 100)
# 读取并验证
# Read back and verify
ok: int = 1
for i in range(8):
v: uint32 = buf[i]
@@ -74,38 +66,38 @@ def test_pointer_arithmetic():
testcheck.check(ok, "pointer arithmetic (buf[i] = i*100)", "pointer arithmetic mismatch")
# --- Test 3: 数组退化为指针 ---
# --- Test 3: array decay to pointer ---
def test_array_decay():
"""测试 list[t.CChar, N] 传递给 t.CConst | str 参数"""
"""Pass list[t.CChar, N] to a t.CConst | str parameter."""
arr: t.CArray[char, 32]
string.memset(&arr, 0, 32)
# 手动写入字符串
# Write string manually
src: str = "Hello"
for i in range(5):
arr[i] = char(ord(src[i]))
arr[5] = 0
# 传递给 print (接受 t.CConst | str)
# Pass to print (accepts t.CConst | str)
stdio.printf("array decay -> %s\n", &arr)
testcheck.ok("array decay (Hello)")
# --- Test 4: 指针类型转换 (CVoid/CPtr) ---
# --- Test 4: pointer type casts (CVoid/CPtr) ---
def test_pointer_cast():
"""测试指针与整数之间的类型转换"""
"""Cast between pointers and integers."""
buf: uint32* = w32.win32memory.VirtualAlloc(None, 256, 0x3000, 0x04)
if not buf:
testcheck.fail("pointer cast: VirtualAlloc returned NULL")
return
string.memset(buf, 0, 256)
# 通过 CVoid 指针写入
# Write through CVoid pointer
raw: t.CPtr = t.CPtr(uint64(buf))
# 将 CVoid 指针转回 CUInt32T 指针
# Cast CVoid pointer back to CUInt32T pointer
p32: uint32* = (uint32*)(raw)
p32[0] = 0xDEADBEEF
# 通过原始指针读取
# Read through raw pointer
if buf[0] == 0xDEADBEEF:
testcheck.ok("pointer cast CVoid -> CUInt32T*")
else:
@@ -113,22 +105,22 @@ def test_pointer_cast():
testcheck.fail("pointer cast failed")
# --- Test 5: 指针偏移计算 (byte offset vs element offset) ---
# --- Test 5: pointer offset (byte offset vs element offset) ---
def test_pointer_offset():
"""测试指针偏移:CUInt8T* + N 应该偏移 N 字节,CUInt32T* + N 应该偏移 N*4 字节"""
"""CUInt8T* + N advances N bytes; CUInt32T* + N advances N*4 bytes."""
buf: uint8* = w32.win32memory.VirtualAlloc(None, 256, 0x3000, 0x04)
if not buf:
testcheck.fail("pointer offset: VirtualAlloc returned NULL")
return
string.memset(buf, 0, 256)
# 写入 4 字节
# Write 4 bytes
buf[0] = 0x41 # 'A'
buf[1] = 0x42 # 'B'
buf[2] = 0x43 # 'C'
buf[3] = 0x44 # 'D'
# 通过 CUInt32T* 读取(应该读到 0x44434241 on little-endian)
# Read via CUInt32T* (0x44434241 on little-endian)
p32: uint32* = (uint32*)(t.CPtr(uint64(buf)))
val: uint32 = p32[0]
@@ -140,14 +132,14 @@ def test_pointer_offset():
testcheck.fail("byte offset vs element offset")
# --- Test 6: 结构体指针访问 ---
# --- Test 6: struct pointer access ---
class TestStruct():
a: int
b: int
c: uint64
def test_struct_pointer():
"""测试结构体指针的成员访问"""
"""Access struct members through a pointer."""
s: TestStruct
s.a = 10
s.b = 20
@@ -158,23 +150,23 @@ def test_struct_pointer():
testcheck.check(p.a == 10 and p.b == 20 and p.c == 0x123456789ABCDEF0, "struct pointer access", "struct pointer access mismatch")
# --- Test 7: memcpy/memset 通过指针 ---
# --- Test 7: memcpy/memset through pointers ---
def test_memcpy_pointers():
"""测试 memcpy 在指针之间的数据复制"""
"""Copy data between pointers with memcpy."""
src_buf: uint32* = w32.win32memory.VirtualAlloc(None, 64, 0x3000, 0x04)
dst_buf: uint32* = w32.win32memory.VirtualAlloc(None, 64, 0x3000, 0x04)
if not src_buf or not dst_buf:
testcheck.fail("memcpy: VirtualAlloc returned NULL")
return
# 初始化 src
# Initialize src
for i in range(8):
src_buf[i] = uint32(i + 1000)
# 复制
# Copy
string.memcpy(t.CPtr(uint64(dst_buf)), t.CPtr(uint64(src_buf)), 32)
# 验证
# Verify
ok: int = 1
for i in range(8):
if dst_buf[i] != uint32(i + 1000):
@@ -183,13 +175,13 @@ def test_memcpy_pointers():
testcheck.check(ok, "memcpy between pointers", "memcpy between pointers failed")
# --- Test 8: 指针作为函数参数 ---
# --- Test 8: pointer as function parameter ---
def fill_array(arr: uint32*, count: int, val: uint32):
for i in range(count):
arr[i] = val
def test_pointer_param():
"""测试指针作为函数参数传递"""
"""Pass a pointer as a function parameter."""
buf: uint32* = w32.win32memory.VirtualAlloc(None, 64, 0x3000, 0x04)
if not buf:
testcheck.fail("pointer param: VirtualAlloc returned NULL")
@@ -225,7 +217,7 @@ def main() -> int | t.CExport:
testcheck.begin("PointerTest: 指针操作基准测试")
# Test 1: global 声明
# Test 1: global declaration
testcheck.section("Test 1: global declaration")
global _g_val
_g_val = 0
+20 -108
View File
@@ -1,109 +1,43 @@
# ============================================================
# main.vp — ProbeGen:代际不稳定性最小探针(勿当普通功能测试改动)
#
# 背景:同一份源码在 TPC→TPV1→TPV2→TPV3 逐代自举出的编译器二进制下
# 产出的 IR 不一致,部分甚至非法。本工程把已定位的 5+1 个"代际
# 不稳定构造"各用一段最小代码覆盖,用两代编译器各编一次,即可在
# 同一份产物里一次性暴露全部差异点,并作为后续修复的回归用例。
#
# 运行(两条命令,各用独立 build_dir,互不覆盖):
# 第 1 代(TPC 产出):
# TransPyV\output\TransPyV.exe --project Test\ProbeGen\project.vpj --clean --run --build-dir Test\ProbeGen\.tpv_build_g1
# 第 2 代(TPV1 产出):
# TransPyV\.tpv_build\output\TransPyV.exe --project Test\ProbeGen\project.vpj --clean --run --build-dir Test\ProbeGen\.tpv_build_g2
# --build-dir 依据:TransPyV\App\main.vp:163 注册该参数,:299-304 在
# resolve_paths 之前覆盖 Config.BuildDir(相对路径基于工程目录解析,
# 注释见 main.vp:300-301);产物 = <build_dir>\temp + <build_dir>\output
# (TransPyV\App\lib\Projectrans\Config.vp:432-443)。
# 注意 TPC 的 Projectrans.py 没有 --build-dir,只有
# --project/--src/--temp/--output(TransPyC\lib\Projectrans\Config.py:139-146);
# 本探针由 Viper 编译器 TransPyV.exe 驱动,故 --build-dir 可用。
#
# 判定:两棵树
# Test\ProbeGen\.tpv_build_g1\temp\<sha1 前 2 位(slice=1)>\<sha1>.{stub,text}.ll
# Test\ProbeGen\.tpv_build_g2\temp\<同上>
# 探针自身模块文件名两侧相同(module_name = 源码 SHA1,与编译器代际无关),
# 可逐 P 点直接 diff;includes 模块若被译为本地产物亦同名可比对。
#
# ⚠ [P6] 在第二代及以后会直接把编译打断(App\lib\core\Gen\AssignGenMixin.vp:2213
# "SyntaxError: subscript ptr is None")。若要单独拿到 P1..P5 的第二代 IR,
# 需临时注释掉 [P6] 段;P6 自身的证据就是那条报错。
# ============================================================
# ProbeGen: minimal probe for cross-generation IR instability. Do not treat as a normal feature test.
# Translate the same source with two compiler generations, then diff the emitted IR per module
# (module file name = source SHA1, so both sides are comparable).
# Gen 1: TransPyV\output\TransPyV.exe --project Test\ProbeGen\project.vpj --clean --run --build-dir Test\ProbeGen\.tpv_build_g1
# Gen 2: TransPyV\.tpv_build\output\TransPyV.exe --project Test\ProbeGen\project.vpj --clean --run --build-dir Test\ProbeGen\.tpv_build_g2
# WARNING [P6] breaks compilation from generation 2 onward; comment out [P6] to get Gen-2 IR for P1..P5.
import t
from stdint import *
import w32.win32console as w32console
# ============================================================
# [P1] 嵌套联合形参
# VOIDPTR 本身是 typedef 联合 t.CPtr(includes/stdint.vp:40),
# 再与 t.CPtr 联合 ⇒ 一侧 i8**、另一侧 i8*。
# 先例(同形):includes/w32/win32sync.vp:65
# extern def InitOnceExecuteOnce(InitOnce: INIT_ONCE | t.CPtr, InitFn: VOIDPTR,
# Parameter: VOIDPTR, Context: VOIDPTR | t.CPtr) -> BOOL
# VOIDPTR 引入方式先例:includes/w32/win32sync.vp:2(from stdint import *)
# extern def 写法先例(语言推荐写法):wiki/08-c-operations.md:238-249
# 只声明不调用:extern 声明未调用不产生链接引用,不影响链接
# 先例:Test/Extern2Test/App/main.vp:18-35(三个仅声明不调用的外部声明)
# ============================================================
# [P1] Nested union parameter: VOIDPTR (typedef of t.CPtr) unioned with t.CPtr gives i8** on one side, i8* on the other.
# Declared but never called, so no link reference is produced.
extern def ProbeNestedUnion(Context: VOIDPTR*) -> BOOL
# ============================================================
# [P2] 结构体按值形参
# 形参是既有 Win32 结构体 COORD(includes/w32/win32console.vp:35-37,X/Y: SHORT),
# 不带 | t.CPtr ⇒ 一侧按值 %COORD、另一侧 %COORD*。
# 先例(同形):includes/w32/win32console.vp:86
# extern def SetConsoleScreenBufferSize(hConsoleOutput: HANDLE, dwSize: COORD) -> BOOL
# 限定名类类型标注先例:TransPyV/App/main.vp:142(argparse.ArgumentParser)
# Test/ArgparseTest/App/main.vp:12(memhub.MemBuddy)
# 模块别名导入先例:TransPyV/App/main.vp:20(import w32.win32console as w32cmd)
# ============================================================
# [P2] Struct by-value parameter: COORD without | t.CPtr gives %COORD on one side, %COORD* on the other.
extern def ProbeCoordByVal(dwSize: w32console.COORD) -> BOOL
# ============================================================
# [P5] 局部 t.CUInt8T = 1 的字面量"蓄池":
# 把局部值写进全局,避免整段被当成死代码/被窥孔吞掉。
# 全局小整型先例:ViperApps/ViperOS/VKernel/Kernel/services/desktop.vp:62
# (_cursor_buttons: uint8 = 0)
# ============================================================
# [P5] Sink for the local uint8 = 1 literal: store it into a global so the code is not dead-code eliminated.
U8Sink: uint8 = 0
# ============================================================
# [P3] CChar → int 提升:参数 t.CChar、返回 int,直接 return
# 一侧应生成 zext i8 %s to i32,另一侧若退化成 ret i8 即丢提升(缺陷)。
# 先例(同形):includes/builtins.vp:12-13
# def ord(s: t.CChar) -> int:
# return s
# ============================================================
# [P3] char -> int promotion: param char, int return. One side must emit zext i8 to i32, not ret i8.
def ProbeOrd(s: char) -> int:
return s
# ============================================================
# [P4] double 比较:参数/返回 double,含 if a < b
# 一侧 fcmp olt double,另一侧若成 icmp slt double(非法)即缺陷。
# 先例(同形):includes/builtins.vp:18-21
# def min(a: double, b: double) -> double:
# if a < b:
# return a
# return b
# ============================================================
# [P4] double comparison: params/return double. One side must emit fcmp olt double, not icmp slt double.
def ProbeMin(a: double, b: double) -> double:
if a < b:
return a
return b
# ============================================================
# [P5] 局部 t.CUInt8T = 1 字面量赋值(字面量定型:一侧 store i8 1, i8*;
# 另一侧 store i32 1, i8*(非法)或 trunc + store)
# 局部声明先例:includes/atom.vp:13(result: t.CUInt8T = 1)
# 局部值落全局(global 声明 + 赋值)先例:
# Test/ArgparseTest/App/main.vp:17(global _mbuddy)→ :26(_mbuddy = ...)
# ============================================================
# [P5] Local uint8 = 1 assignment: literal typing must emit store i8 1, not store i32 1 or trunc+store.
def ProbeU8Literal() -> uint8:
global U8Sink
result: uint8 = 1
@@ -111,22 +45,8 @@ def ProbeU8Literal() -> uint8:
return result
# ============================================================
# [P6] 类字段联合 + 下标写
# 字段为 t.CChar | t.CPtr 联合,必须先判空再按下标写;
# 第二/三代在 App\lib\core\Gen\AssignGenMixin.vp:2213 抛
# "SyntaxError: subscript ptr is None"。
# 先例(同形):includes/viperio.vp:5-20
# class Buf:
# data: t.CChar | t.CPtr
# def clear(self):
# if self.data != None and self.capacity > 0:
# self.data[0] = 0
# 联合类型字段/变量初始化 None 先例:Test/SimdTest/App/main.vp:13
# (arena: t.CUInt8T | t.CPtr = None)
# 无参构造 __init__(self) 先例:TransPyV/App/lib/core/Gen/Translator.vp:75/252-255
# (class Translator: def __init__(self): ...;实例化 TransPyV/App/main.vp:471)
# ============================================================
# [P6] Class field union + subscript write: field is char | t.CPtr, must null-check before indexed write.
# Generations 2+ fail here with "SyntaxError: subscript ptr is None".
class Box:
p: char*
@@ -139,16 +59,8 @@ class Box:
pass
# ============================================================
# 入口:main 保持最小(引用到上面各构造,保证它们真的被翻译;返回 0)
# @t.CExport + main() -> int 先例:ViperApps/ViperTemplateProject/App/main.vp:7-8
# ViperApps/ViperCPW/App/main.vp:181-184
# 字符字面量先例:Test/CharTest/App/main.vp:24(lit: char = 'Z')
# 类实例化先例:Test/StructTest/App/main.vp:21(p: Point = Point())
# double 字面量先例:Test/G7/App/main.vp:39(node.FloatVal = 3.14)
# P1/P2 是 extern 声明,不调用(调用会产生未解析符号,见各自注释);
# 其差异体现在本模块的 declare 上。
# ============================================================
# Entry: keep main minimal, referencing each construct above so it is really translated; return 0.
# P1/P2 are extern declarations and are not called, so their difference shows in this module's declares.
@t.CExport
def main() -> int:
Ch: char = 'A'
+13 -24
View File
@@ -4,15 +4,8 @@ import stdio
import stdlib
# ============================================================
# 指针操作符全形态自检(TPC 侧)
#
# 解析实况(vast_c.c ParseSimpleStmt → ParseExprList + SetStoreContext):
# `*p` 由 ParseFactor 产出 UnaryOp(op=Deref),SetStoreContext **不改 UnaryOp**
# ⇒ `*p = v` 的赋值目标就是 UnaryOp(Deref)(ctx 仍是 Load),与读侧同形。
# 若编译器目标分派没有 UnaryOp 分支,整条语句会被静默丢弃(不落盘、不报错),
# 本程序即用于钉死这一点:每个形态都必须真的写进内存。
# ============================================================
# ===== Pointer operator full-form self-check (TPC side) =====
# `*p = v` targets UnaryOp(Deref); without a dispatch branch it is silently dropped.
def MakePair() -> tuple[int, int]:
return 1, 2
@@ -25,13 +18,13 @@ def main() -> int:
stdio.printf("FAIL: malloc\n")
return 9
# 形态 A:*p = v
# Form A: *p = v
*buf = 7
if buf[0] != 7:
stdio.printf("FAIL A *p = v : buf[0]=%llu(期望 7)\n", buf[0])
fails += 1
# 形态 B:*p = *q
# Form B: *p = *q
q: uint64* = buf + 1
*q = 99
*buf = *q
@@ -39,7 +32,7 @@ def main() -> int:
stdio.printf("FAIL B *p = *q : buf[0]=%llu(期望 99)\n", buf[0])
fails += 1
# 形态 C:&x 取址,*px = v
# Form C: &x address-of, *px = v
x: uint64 = 0
y: uint64 = 5
px: uint64* = &x
@@ -48,25 +41,25 @@ def main() -> int:
stdio.printf("FAIL C *px = v : x=%llu(期望 11)\n", x)
fails += 1
# 形态 D:*&x = *&y
# Form D: *&x = *&y
*&x = *&y
if x != 5:
stdio.printf("FAIL D *&x = *&y : x=%llu(期望 5)\n", x)
fails += 1
# 形态 E(对照):下标写 p[i] = v
# Form E (control): subscript write p[i] = v
buf[0] = 123
if buf[0] != 123:
stdio.printf("FAIL E p[0] = v : buf[0]=%llu(期望 123)\n", buf[0])
fails += 1
# 形态 F:AugAssign 目标 *p += v
# Form F: AugAssign target *p += v
*buf += 5
if buf[0] != 128:
stdio.printf("FAIL F *p += v : buf[0]=%llu(期望 128)\n", buf[0])
fails += 1
# 形态 G1(对照):Tuple 目标 a, b = f()
# Form G1 (control): tuple target a, b = f()
a: int = 0
b: int = 0
a, b = MakePair()
@@ -74,7 +67,7 @@ def main() -> int:
stdio.printf("FAIL G1 a, b = f() : a=%d b=%d(期望 1/2)\n", a, b)
fails += 1
# 形态 G2:List 目标 [c, d] = f()
# Form G2: list target [c, d] = f()
cc: int = 0
dd: int = 0
[cc, dd] = MakePair()
@@ -82,18 +75,14 @@ def main() -> int:
stdio.printf("FAIL G2 [c, d] = f() : c=%d d=%d(期望 1/2)\n", cc, dd)
fails += 1
# 形态 H:值位置的 *p(调用实参 f(*p))——Starred(Load)
# Form H: *p in value position (call arg f(*p)) -- Starred(Load)
got: int = stdio.printf("INFO H f(*p) : %llu(期望 128)\n", *buf)
if got < 0:
stdio.printf("FAIL H f(*p) : printf 返回 %d\n", got)
fails += 1
# 形态 I:memhub 实际用的「两步式读块头」(关键回归点)
# hd1 = *((uint64*)(blk)) —— 直接读
# hd2 = uint64(t.CPtr(*((uint64*)(blk)))) —— 两步式;注意 `*((...))` 位于
# t.CPtr( ) 的**实参位置** ⇒ 解析为 Starred(Load),旧 TPC 在这一形态落到
# 末尾兜底 `return i32 0` ⇒ t.CPtr(0)=NULL ⇒ hd2==0(内存里明明是 0x1234)
# 这正是 OOM 报告里 `hdr=0x9 / hdr2=0x0` 的成因。
# Form I: the two-step block-header read memhub uses (key regression point).
# `*((...))` inside t.CPtr() args parses as Starred(Load); old TPC returned 0.
w: uint64 = 0
pw: uint64* = &w
*pw = 0x1234
+6 -6
View File
@@ -3,26 +3,26 @@ from stdint import *
import stdio
# 模块级全局定长数组(rawarray 复刻 t.CArray)
# Module-level global fixed-size array (rawarray mirrors t.CArray)
g_arr: rawarray[int, 4] = [10, 20, 30, 40]
# struct 内嵌定长数组字段
# Struct with embedded fixed-size array fields
class Ctx:
state: rawarray[uint32, 5]
buf: rawarray[uint8, 64]
def main() -> int | t.CExport:
# 1) 全局数组读取
# 1) Read global array
stdio.printf("1 g_arr[0]=%d g_arr[3]=%d (expect 10 40)\n", g_arr[0], g_arr[3])
# 2) 局部定长数组(写 + 读)
# 2) Local fixed-size array (write + read)
loc: rawarray[uint32, 3] = [0, 0, 0]
loc[1] = 7
stdio.printf("2 loc[1]=%d (expect 7)\n", loc[1])
# 3) struct 内嵌数组字段
# 3) Struct embedded array fields
ctx: Ctx
ctx.state[0] = 100
ctx.state[4] = 400
@@ -30,7 +30,7 @@ def main() -> int | t.CExport:
stdio.printf("3 ctx.state[0]=%d ctx.state[4]=%d ctx.buf[0]=%d (expect 100 400 65)\n",
ctx.state[0], ctx.state[4], int(ctx.buf[0]))
# 4) 参数数组衰减(CArray 形参 → 元素指针)+ sizeof
# 4) Parameter array decay (CArray param to element pointer) + sizeof
total: int = sum_arr(loc, 3)
stdio.printf("4 sum=%d (expect 7)\n", total)
+13 -13
View File
@@ -8,13 +8,13 @@ import string
import testcheck
# 副作用函数:将 buf[0] 置为 1,返回 True
# side-effect helper: set buf[0] = 1 and return True
def bump_true(buf: bytes) -> bool:
buf[0] = 1
return True
# 副作用函数:将 buf[0] 置为 1,返回 False
# side-effect helper: set buf[0] = 1 and return False
def bump_false(buf: bytes) -> bool:
buf[0] = 1
return False
@@ -28,31 +28,31 @@ def main() -> CInt | CExport:
buf: bytes = stdlib.malloc(1)
# === Test 1: False and bump_true() - bump 不应被调用 ===
# === Test 1: False and bump_true() - bump must not be called ===
testcheck.section("Test 1: False and bump_true()")
buf[0] = 0
r1: bool = False and bump_true(buf)
testcheck.check(buf[0] == 0, "and short-circuit OK (bump not called)", "and short-circuit FAILED (bump called)")
# === Test 2: True or bump_true() - bump 不应被调用 ===
# === Test 2: True or bump_true() - bump must not be called ===
testcheck.section("Test 2: True or bump_true()")
buf[0] = 0
r2: bool = True or bump_true(buf)
testcheck.check(buf[0] == 0, "or short-circuit OK (bump not called)", "or short-circuit FAILED (bump called)")
# === Test 3: True and bump_true() - bump 应被调用 ===
# === Test 3: True and bump_true() - bump must be called ===
testcheck.section("Test 3: True and bump_true()")
buf[0] = 0
r3: bool = True and bump_true(buf)
testcheck.check(buf[0] == 1, "and eval OK (bump called)", "and eval FAILED (bump not called)")
# === Test 4: False or bump_true() - bump 应被调用 ===
# === Test 4: False or bump_true() - bump must be called ===
testcheck.section("Test 4: False or bump_true()")
buf[0] = 0
r4: bool = False or bump_true(buf)
testcheck.check(buf[0] == 1, "or eval OK (bump called)", "or eval FAILED (bump not called)")
# === Test 5: if 语句中的短路 ===
# === Test 5: short-circuit in if statement ===
testcheck.section("Test 5: if 语句中的短路")
buf[0] = 0
if False and bump_true(buf):
@@ -66,7 +66,7 @@ def main() -> CInt | CExport:
testcheck.check(False, "should enter if", "if True or else")
testcheck.check(buf[0] == 0, "if or short-circuit OK", "if or short-circuit FAILED")
# === Test 6: 嵌套短路 ===
# === Test 6: nested short-circuit ===
testcheck.section("Test 6: 嵌套短路")
buf[0] = 0
r6: bool = False and (True or bump_true(buf))
@@ -76,7 +76,7 @@ def main() -> CInt | CExport:
r7: bool = True or (False and bump_true(buf))
testcheck.check(buf[0] == 0, "nested or short-circuit OK", "nested or short-circuit FAILED")
# === Test 7: not 与短路 ===
# === Test 7: not with short-circuit ===
testcheck.section("Test 7: not 与短路")
buf[0] = 0
r8: bool = not False and bump_true(buf)
@@ -86,19 +86,19 @@ def main() -> CInt | CExport:
r9: bool = not True or bump_true(buf)
testcheck.check(buf[0] == 1, "not or eval OK (bump called)", "not or eval FAILED (bump not called)")
# === Test 8: and 链中第一个为 False,后续不评估 ===
# === Test 8: and chain, first False stops later evaluation ===
testcheck.section("Test 8: and 链短路")
buf[0] = 0
r10: bool = False and bump_true(buf) and bump_true(buf)
testcheck.check(buf[0] == 0, "and chain short-circuit OK", "and chain short-circuit FAILED")
# === Test 9: or 链中第一个为 True,后续不评估 ===
# === Test 9: or chain, first True stops later evaluation ===
testcheck.section("Test 9: or 链短路")
buf[0] = 0
r11: bool = True or bump_true(buf) or bump_true(buf)
testcheck.check(buf[0] == 0, "or chain short-circuit OK", "or chain short-circuit FAILED")
# === Test 10: and 返回值正确性 ===
# === Test 10: and return value correctness ===
testcheck.section("Test 10: and 返回值正确性")
buf[0] = 0
r12: bool = True and bump_true(buf)
@@ -108,7 +108,7 @@ def main() -> CInt | CExport:
r13: bool = True and bump_false(buf)
testcheck.check(not r13, "and return False OK", "and return False FAILED")
# === Test 11: or 返回值正确性 ===
# === Test 11: or return value correctness ===
testcheck.section("Test 11: or 返回值正确性")
buf[0] = 0
r14: bool = False or bump_true(buf)
+7 -15
View File
@@ -9,19 +9,17 @@ import memhub
import testcheck
# 全局内存池
# Global memory pool
arena: uint8* = None
pool: memhub.MemPool* = None
# 外部函数: clock() 用于性能计时
# External function: clock() for performance timing
def clock() -> t.CLong | t.CExtern: pass
define CLOCK_PER_SEC = 1000
# ============================================================
# 1. AVX2 double4 正确性测试
# ============================================================
# 1. AVX2 double4 correctness tests
def test_avx2_add_sub_mul_div():
testcheck.section("AVX2 add/sub/mul/div 4d")
@@ -220,9 +218,7 @@ def test_avx2_fma():
out.delete()
# ============================================================
# 2. 批量数组运算正确性测试
# ============================================================
# 2. Batch array operation correctness tests
def test_batch_array_ops():
testcheck.section("Batch array operations")
@@ -285,9 +281,7 @@ def test_batch_array_ops():
out1.delete()
# ============================================================
# 3. LLVMIR 精确标量运算测试
# ============================================================
# 3. LLVMIR precise scalar operation tests
def test_llvmir_scalar():
testcheck.section("LLVMIR precise scalar ops")
@@ -357,9 +351,7 @@ def test_llvmir_scalar():
testcheck.check(r == double(1024.0), "pow(2,10)==1024", "pow(2,10)==1024")
# ============================================================
# 4. 性能基准测试: SIMD vs 标量
# ============================================================
# 4. Benchmark: SIMD vs scalar
define N_ELEM = 40000
define N_ITER = 50000
@@ -451,7 +443,7 @@ def benchmark_simd_vs_scalar():
else:
printf(" speedup=N/A\n")
# 验证结果正确性
# Verify result correctness
testcheck.check(out.data[0] > double(0.0), "bench result[0] valid", "bench result[0] valid")
a.delete()
+3 -3
View File
@@ -3,9 +3,9 @@ import ast
# ============================================================
# 回归测试:__slots__ + ast.AST 字段类型
# 验证 TPC 修复:无法识别的类型注解应报错终止,而非 VoidType alloca 崩溃
# 对照:使用 ast.expr(无效)会报错;使用 ast.AST(有效)应编译成功
# Regression test: __slots__ with ast.AST field types.
# An unrecognized type annotation must error out instead of crashing in
# VoidType alloca; ast.expr (invalid) errors, ast.AST (valid) compiles.
# ============================================================
class Result:
__slots__ = ('elem_type_node', 'count_node', 'is_pointer')
+26 -36
View File
@@ -7,16 +7,13 @@ import viperlib
import string
# ============================================================
# SprintfTest - viperlib.snprintf %a/%A 运行时验证
# 预期输出对照 glibc printf("%a", ...) 行为
# ============================================================
# SprintfTest: runtime verification of viperlib.snprintf %a/%A against glibc printf
@t.CExport
def main() -> int:
testcheck.begin("SprintfTest: %a/%A runtime verification")
buf: bytes = stdlib.malloc(256)
# ---------- 默认精度(核心正确性) ----------
# ---------- default precision (core correctness) ----------
testcheck.section("default precision")
v1: double = 1.0
@@ -54,25 +51,25 @@ def main() -> int:
testcheck.info(buf)
testcheck.check(string.strcmp(buf, "-0x1p+0") == 0, "%a -1.0 -> -0x1p+0", "FAIL -1.0")
# ---------- 大写 %A ----------
# ---------- uppercase %A ----------
testcheck.section("uppercase %A")
viperlib.snprintf(buf, 64, "%A", v_pi)
testcheck.info(buf)
testcheck.check(string.strcmp(buf, "0X1.91EB851EB851FP+1") == 0, "%A 3.14 -> 0X1...P+1", "FAIL %A")
# ---------- # flag 强制小数点 ----------
# ---------- # flag forces radix point ----------
testcheck.section("# flag")
viperlib.snprintf(buf, 64, "%#a", v1)
testcheck.info(buf)
testcheck.check(string.strcmp(buf, "0x1.p+0") == 0, "%#a 1.0 -> 0x1.p+0", "FAIL %#a")
# ---------- 显式精度 13(不裁剪) ----------
# ---------- explicit precision 13 (no trimming) ----------
testcheck.section("precision 13")
viperlib.snprintf(buf, 64, "%.13a", v1)
testcheck.info(buf)
testcheck.check(string.strcmp(buf, "0x1.0000000000000p+0") == 0, "%.13a 1.0 -> 0x1.0000000000000p+0", "FAIL %.13a")
# ---------- 宽度/对齐 ----------
# ---------- width/alignment ----------
testcheck.section("width/align")
viperlib.snprintf(buf, 64, "%10a", v1)
testcheck.info(buf)
@@ -91,7 +88,7 @@ def main() -> int:
# ---------- inf / nan ----------
testcheck.section("inf/nan")
# 构造 +inf: bit pattern 0x7FF0000000000000
# Build +inf from bit pattern 0x7FF0000000000000
inf_bits: uint64 = 0x7FF0000000000000
inf_val: double = 0.0
*(&inf_val) = *(&inf_bits)
@@ -99,7 +96,7 @@ def main() -> int:
testcheck.info(buf)
testcheck.check(string.strcmp(buf, "inf") == 0, "%a +inf -> inf", "FAIL +inf")
# 构造 -inf: bit pattern 0xFFF0000000000000
# Build -inf from bit pattern 0xFFF0000000000000
ninf_bits: uint64 = 0xFFF0000000000000
ninf_val: double = 0.0
*(&ninf_val) = *(&ninf_bits)
@@ -107,7 +104,7 @@ def main() -> int:
testcheck.info(buf)
testcheck.check(string.strcmp(buf, "-inf") == 0, "%a -inf -> -inf", "FAIL -inf")
# 构造 nan: bit pattern 0x7FF8000000000000
# Build nan from bit pattern 0x7FF8000000000000
nan_bits: uint64 = 0x7FF8000000000000
nan_val: double = 0.0
*(&nan_val) = *(&nan_bits)
@@ -115,34 +112,31 @@ def main() -> int:
testcheck.info(buf)
testcheck.check(string.strcmp(buf, "nan") == 0, "%a nan -> nan", "FAIL nan")
# 大写 INF/NAN
# Uppercase INF/NAN
viperlib.snprintf(buf, 64, "%A", inf_val)
testcheck.info(buf)
testcheck.check(string.strcmp(buf, "INF") == 0, "%A +inf -> INF", "FAIL INF")
# ============================================================
# viperlib %g/%f/%e 浮点格式化诊断(定位 SimdTest 浮点 CDefine 值错)
# 已知现象: %a 正确, %.17g 输出 3.1397985356295141 (应为 3.1415926535897931)
# 同一 va_list 连续读同一 double, %.17g 错而 %a 对 → 定位是算法还是传参/读取
# ============================================================
# viperlib %g/%f/%e diagnosis: %a is correct but %.17g prints a wrong value.
# Same double read twice from one va_list: %.17g wrong, %a right.
testcheck.section("viperlib %g bug diagnosis")
v_pi17: double = 3.1415926535897931
v_e17: double = 2.7182818284590455
# T1: 同一参数 %.17g vs %a(复现;%a 对则说明值本身正确)
# T1: same arg via %.17g vs %a (repro; %a correct means value is fine)
viperlib.snprintf(buf, 128, "T1 %.17g|%a", v_pi17, v_pi17)
testcheck.info(buf)
# T2: 两个 %.17g 不同值
# T2: two different doubles with %.17g
viperlib.snprintf(buf, 128, "T2 %.17g|%.17g", v_pi17, v_e17)
testcheck.info(buf)
# T3: CRT 对照
# T3: CRT reference
stdio.snprintf(buf, 128, "T3 %.17g|%a", v_pi17, v_pi17)
testcheck.info(buf)
# T4: 不同精度
# T4: different precisions
viperlib.snprintf(buf, 128, "T4 %.17g|%.10g|%.6g|%g", v_pi17, v_pi17, v_pi17, v_pi17)
testcheck.info(buf)
@@ -150,38 +144,34 @@ def main() -> int:
viperlib.snprintf(buf, 128, "T5 %.17f|%.17e", v_pi17, v_pi17)
testcheck.info(buf)
# T6: 简单精确值(1.0/0.5 二进制精确, 若这些也错则算术层坏)
# T6: exact values (1.0/0.5); wrong here means arithmetic layer broken
viperlib.snprintf(buf, 128, "T6 %.17g|%.17g|%.17g", 1.0, 0.5, 123.456)
testcheck.info(buf)
# T7/T8: double 在变参不同位置(va_list 读取位置相关性)
# T7/T8: double at different vararg positions (va_list slot dependence)
viperlib.snprintf(buf, 128, "T7 %d|%.17g|%d", 100, v_pi17, 200)
testcheck.info(buf)
viperlib.snprintf(buf, 128, "T8 %d|%d|%.17g", 100, 200, v_pi17)
testcheck.info(buf)
# T9: 字面量直接传(非常量折叠则看传递路径)
# T9: literals passed directly (checks passing path)
viperlib.snprintf(buf, 128, "T9 %.17g|%a", 3.1415926535897931, 3.1415926535897931)
testcheck.info(buf)
# T10: 顺序反转, %a 在前 %.17g 在后
# T10: reversed order, %a before %.17g
viperlib.snprintf(buf, 128, "T10 %a|%.17g", v_pi17, v_pi17)
testcheck.info(buf)
# ============================================================
# 多整数变参复现(DefineTest test_define_string PAGE= 遗留 bug):
# viperlib.snprintf 3+ 个 int 变参时, 第 2 个 %d 读到垃圾
# (va_arg 游标从寄存器区切到溢出区推进错误, 非本次 CIf 引入)
# 预期: R1-R3 目前 FAIL, 修复后应全部 PASS
# ============================================================
# Multi-int varargs repro: with 3+ int args, viperlib.snprintf reads garbage
# at the 2nd %d (va_arg cursor advances wrong past the register area).
testcheck.section("multi-int varargs repro")
# R1: 3 个常量 int(复现 DefineTest "MAX_SIZE=%d PAGE=%d MASK=0x%x" 模式)
# R1: 3 const ints (reproduces DefineTest MAX_SIZE/PAGE/MASK pattern)
viperlib.snprintf(buf, 128, "R1 %d|%d|%d", 1024, 4096, 255)
testcheck.info(buf)
testcheck.check(string.strcmp(buf, "R1 1024|4096|255") == 0, "R1 3-const-int (1024|4096|255)", "R1 FAIL (第2变参被误读)")
# R2: 3 个运行时变量 int(排除常量折叠差异)
# R2: 3 runtime int vars (rules out constant folding)
ia: int = 1024
ib: int = 4096
ic: int = 255
@@ -189,12 +179,12 @@ def main() -> int:
testcheck.info(buf)
testcheck.check(string.strcmp(buf, "R2 1024|4096|255") == 0, "R2 3-var-int (1024|4096|255)", "R2 FAIL (第2变参被误读)")
# R3: 4 个变参(游标推进进一步暴露)
# R3: 4 varargs (further exposes cursor advance)
viperlib.snprintf(buf, 128, "R3 %d|%d|%d|%d", 1, 2, 3, 4)
testcheck.info(buf)
testcheck.check(string.strcmp(buf, "R3 1|2|3|4") == 0, "R3 4-int (1|2|3|4)", "R3 FAIL (变参游标推进错误)")
# R4: 第 2 个变参为 0(值 0 若被截断读也会暴露)
# R4: 2nd vararg is 0 (exposes truncated reads)
viperlib.snprintf(buf, 128, "R4 %d|%d|%d", 100, 0, 200)
testcheck.info(buf)
testcheck.check(string.strcmp(buf, "R4 100|0|200") == 0, "R4 middle-zero (100|0|200)", "R4 FAIL (第2变参被误读)")
+10 -10
View File
@@ -6,7 +6,7 @@ import testcheck
import inline_test
# ============================================================
# Test 1: 字符串指针迭代 - 逐字符直到\0
# Test 1: string pointer iteration, char by char until NUL
# ============================================================
def test_string_ptr_iter():
testcheck.section("Test 1: string pointer iteration")
@@ -19,7 +19,7 @@ def test_string_ptr_iter():
testcheck.check(count == 5, "ptr iter (count=5)", "ptr iter (count expect 5)")
# ============================================================
# Test 2: 字符串指针求和ASCII值
# Test 2: sum ASCII values via string pointer
# ============================================================
def test_string_ascii_sum():
testcheck.section("Test 2: string ASCII sum")
@@ -33,7 +33,7 @@ def test_string_ascii_sum():
testcheck.check(total == 198, "ASCII sum (total=198)", "ASCII sum (total expect 198)")
# ============================================================
# Test 3: 手动strcpy - 指针复制
# Test 3: manual strcpy via pointers
# ============================================================
def test_manual_strcpy():
testcheck.section("Test 3: manual strcpy via pointers")
@@ -49,7 +49,7 @@ def test_manual_strcpy():
testcheck.check(dst[0] == 84 and dst[1] == 101 and dst[2] == 115 and dst[3] == 116, "manual strcpy (T=84 e=101 s=115 t=116)", "manual strcpy (expect T=84 e=101 s=115 t=116)")
# ============================================================
# Test 4: 指针比较和偏移
# Test 4: pointer comparison and offset
# ============================================================
def test_ptr_offset_compare():
testcheck.section("Test 4: pointer offset and compare")
@@ -65,7 +65,7 @@ def test_ptr_offset_compare():
testcheck.check(total == 100, "ptr offset (total=100)", "ptr offset (total expect 100)")
# ============================================================
# Test 5: 字符串长度手动计算
# Test 5: manual string length
# ============================================================
def test_manual_strlen():
testcheck.section("Test 5: manual strlen")
@@ -78,7 +78,7 @@ def test_manual_strlen():
testcheck.check(length == 12, "manual strlen (len=12)", "manual strlen (len expect 12)")
# ============================================================
# Test 6: 指针反向遍历字符串
# Test 6: reverse string via pointer
# ============================================================
def test_reverse_string_ptr():
testcheck.section("Test 6: reverse string via pointer")
@@ -102,7 +102,7 @@ def test_reverse_string_ptr():
testcheck.check(dst[0] == 100 and dst[1] == 99 and dst[2] == 98 and dst[3] == 97, "reverse string (d=100 c=99 b=98 a=97)", "reverse string (expect d=100 c=99 b=98 a=97)")
# ============================================================
# Test 7: 多级指针 - 指向指针的指针
# Test 7: multi-level pointer (pointer to pointer)
# ============================================================
def test_double_pointer():
testcheck.section("Test 7: double pointer")
@@ -114,7 +114,7 @@ def test_double_pointer():
testcheck.check(val == 42, "double pointer (val=42)", "double pointer (val expect 42)")
# ============================================================
# Test 8: 指针算术 - 数组元素访问
# Test 8: pointer arithmetic, array element access
# ============================================================
def test_ptr_arithmetic():
testcheck.section("Test 8: pointer arithmetic")
@@ -128,7 +128,7 @@ def test_ptr_arithmetic():
testcheck.check(val == 16, "ptr arithmetic (arr[3]=16)", "ptr arithmetic (arr[3] expect 16)")
# ============================================================
# Test 9: 字符串比较 - 逐字符指针
# Test 9: manual string compare via char pointers
# ============================================================
def test_manual_strcmp():
testcheck.section("Test 9: manual strcmp via pointers")
@@ -148,7 +148,7 @@ def test_manual_strcmp():
testcheck.check(equal == 1, "manual strcmp (equal=1)", "manual strcmp (equal expect 1)")
# ============================================================
# Test 10: 结构体指针访问
# Test 10: struct pointer access
# ============================================================
class Vec2:
x: int
+1 -1
View File
@@ -28,7 +28,7 @@ def test_strcat():
stdio.printf("SKIP: VirtualAlloc returned NULL\n")
return
string.memset(buf, 0, 64)
# 手动拼接: 先拷贝 "Hello",再拷贝 " World"
# Manual concat: copy "Hello" then " World".
hello: char* = "Hello"
world: char* = " World"
string.memcpy(buf, hello, 5)
+7 -7
View File
@@ -3,7 +3,7 @@ import stdio
import string
import testcheck
# 定义结构体
# Define structs
class Point():
x: int
y: int
@@ -14,7 +14,7 @@ class Rect():
class Node():
value: int
next: t.CPtr # Node* 类型
next: t.CPtr # Node* type
def test_struct_basic():
testcheck.section("Test 1: struct basic")
@@ -37,12 +37,12 @@ def test_struct_pointer():
p: Point = Point()
p.x = 42
p.y = 84
# 取结构体指针
# Take a struct pointer
pp: Point* = t.CPtr(uint64(p))
# 通过指针修改
# Modify through the pointer
pp.x = 100
pp.y = 200
# 检查原始结构体是否被修改
# Check whether the original struct changed
testcheck.check(p.x == 100 and p.y == 200, "struct pointer (x=100 y=200)", "struct pointer (x y expect 100 200)")
def test_struct_param():
@@ -58,13 +58,13 @@ def point_sum(p: Point) -> int:
def test_struct_array():
testcheck.section("Test 5: struct array")
# 分配结构体数组
# Allocate a struct array
buf: uint8* = w32.win32memory.VirtualAlloc(None, 256, 12288, 4)
if uint64(buf) == 0:
stdio.printf("SKIP: VirtualAlloc returned NULL\n")
return
string.memset(buf, 0, 256)
# 将缓冲区转为 Point 数组
# Reinterpret the buffer as a Point array
pts: Point* = (Point*)(buf)
pts[0].x = 1
pts[0].y = 2
+16 -25
View File
@@ -4,20 +4,11 @@ from t import CPtr, CInt, CExport
import testcheck
# ============================================================
# super() 语义专项测试(由 TransPyV.exe 编译)
#
# 覆盖场景:
# 1. super().__init__(args) — 子类构造调父类构造(字段由父类设置)
# 2. super().method() 静态绑定父类实现(不触发子类 override / 虚分派)
# 3. super() 调未覆盖的父类方法(父类字段区前缀对齐,this 无需调整)
# 4. 三层继承链 super().__init__(Leaf → Mid → Grand 逐层传递,
# 每个中间类的 super() 沿各自 CurClassName 的 MRO 跳自身找父类)
# 5. super().method 沿 MRO 找实际定义类(Mid 未定义 Base → 找到 Grand.Base)
# ============================================================
# ===== super() semantics test =====
# Covers super().__init__ chaining, static method binding, MRO lookup, 3-level chains.
# ========== 单继承:super().__init__ + super().method ==========
# ========== Single inheritance: super().__init__ + super().method ==========
@t.CVTable
class Animal:
@@ -38,21 +29,21 @@ class Dog(Animal):
Breed: CInt
def __init__(self, tag: CInt, breed: CInt):
super().__init__(tag) # 调 Animal.__init__ 设置 Tag
super().__init__(tag) # Call Animal.__init__ to set Tag
self.Breed = breed
def Speak(self) -> CInt:
return 1
def ParentSpeak(self) -> CInt:
return super().Speak() # 静态绑定 Animal.Speak → 0(不走虚分派)
return super().Speak() # Statically bind Animal.Speak -> 0 (no virtual dispatch)
def FullGreet(self) -> CInt:
# super() 调父类 Greet(Dog 未覆盖),再加自身字段
# Call parent Greet (not overridden by Dog), then add own field
return super().Greet() + self.Breed
# ========== 三层继承链:Grand → Mid → Leaf ==========
# ========== Three-level chain: Grand -> Mid -> Leaf ==========
@t.CVTable
class Grand:
@@ -70,7 +61,7 @@ class Mid(Grand):
M: CInt
def __init__(self, v: CInt):
super().__init__(v + 1) # 调 Grand.__init__
super().__init__(v + 1) # Call Grand.__init__
self.M = v
def MidOnly(self) -> CInt:
@@ -80,39 +71,39 @@ class Mid(Grand):
@t.CVTable
class Leaf(Mid):
def __init__(self, v: CInt):
super().__init__(v + 2) # 调 Mid.__init__(Mid 内部再 super 到 Grand)
super().__init__(v + 2) # Call Mid.__init__ (which supers to Grand)
def GetBase(self) -> CInt:
return super().Base() # Mid 未定义 Base → 沿 MRO 找 Grand.Base
return super().Base() # Mid has no Base -> find Grand.Base along MRO
def CallMidOnly(self) -> CInt:
return super().MidOnly() # 调 Mid.MidOnly
return super().MidOnly() # Call Mid.MidOnly
def main() -> CInt | CExport:
testcheck.begin("SuperTest: super() 语义测试")
# --- 1. super().__init__ 设置父类字段 ---
# --- 1. super().__init__ sets parent fields ---
d: Dog | CPtr = Dog(42, 7)
testcheck.check(d.Tag == 42, "super().__init__ 设置父类字段 OK",
"super().__init__ FAILED")
testcheck.check(d.Breed == 7, "子类字段 OK", "子类字段 FAILED")
# --- 2. super().method 静态绑定(不虚分派到子类 override) ---
# --- 2. super().method static binding (no dispatch to child override) ---
testcheck.check(d.ParentSpeak() == 0, "super().Speak() 静态绑定父类 OK",
"super().Speak() FAILED")
testcheck.check(d.Speak() == 1, "子类 Speak() override OK", "Speak() FAILED")
# --- 3. super() 调未覆盖的父类方法(42+1000+7 = 1049) ---
# --- 3. super() calls uncovered parent method (42+1000+7 = 1049) ---
testcheck.check(d.FullGreet() == 1049, "super() 调未覆盖父类方法 OK",
"FullGreet() FAILED")
# --- 4. 三层继承链 super().__init__(Leaf(10) → Mid(12) → Grand(13)) ---
# --- 4. three-level super().__init__ chain (Leaf(10) -> Mid(12) -> Grand(13)) ---
lf: Leaf | CPtr = Leaf(10)
testcheck.check(lf.G == 13, "三层 super().__init__ 链 G OK", "三层 G FAILED")
testcheck.check(lf.M == 12, "中间类 M OK", "中间类 M FAILED")
# --- 5. super().method 沿 MRO 找实际定义类 ---
# --- 5. super().method finds the defining class along MRO ---
testcheck.check(lf.GetBase() == 13, "super().Base() 沿 MRO OK", "GetBase() FAILED")
testcheck.check(lf.CallMidOnly() == 12, "super().MidOnly() OK", "CallMidOnly() FAILED")
+3 -3
View File
@@ -14,7 +14,7 @@ import subprocess
import syslibtest_impl
# MBuddy arena 大小:1MB
# MBuddy arena size: 1 MB.
define ARENA_SIZE = 1048576
@@ -22,11 +22,11 @@ def main() -> CInt | CExport:
w32.win32console.SetConsoleCP(65001)
w32.win32console.SetConsoleOutputCP(65001)
# 初始化全局 MBuddy 内存分配器
# Initialize the global MBuddy allocator.
arena: bytes = stdlib.malloc(ARENA_SIZE)
mbuddy_obj: memhub.MemBuddy* = memhub.MemBuddy(arena, ARENA_SIZE)
# 将 MBuddy 对象赋值给所有需要内存分配的模块
# Assign the MBuddy object to every module that allocates.
sys._mbuddy = mbuddy_obj
os._mbuddy = mbuddy_obj
os._win32._mbuddy = mbuddy_obj
+6 -7
View File
@@ -6,34 +6,33 @@ import os._posix
# =============================================================================
# Workaround: TransPyC 无法正确解析 os.xxx() 包级函数调用
# (os.path.xxx() 子模块调用正常,但 os.xxx() 包级调用解析为本地模块)
# 此文件单独导入 os._win32 / os._posix 子模块,避免污染调用方的 os.rmdir() 等解析。
# Workaround: TransPyC mis-resolves package-level os.xxx() calls as a local
# module. Import os._win32 / os._posix here so caller code stays intact.
# =============================================================================
def os_exists(path: str) -> bool:
"""检查文件/目录是否存在(跨平台)"""
"""Return whether the file/dir exists."""
if platmacro.IS_WINDOWS:
return os._win32.exists(path)
return os._posix.exists(path)
def os_remove(path: str) -> int:
"""删除文件(跨平台)。成功返回 0,失败返回 -1。"""
"""Remove a file. Returns 0 on success, -1 on failure."""
if platmacro.IS_WINDOWS:
return os._win32.remove(path)
return os._posix.remove(path)
def os_isdir(path: str) -> bool:
"""检查路径是否为目录(跨平台)"""
"""Return whether the path is a directory."""
if platmacro.IS_WINDOWS:
return os._win32.isdir(path)
return os._posix.isdir(path)
def os_getsize(path: str) -> int64:
"""返回文件大小(字节,跨平台)。失败返回 -1。"""
"""Return file size in bytes, or -1 on failure."""
if platmacro.IS_WINDOWS:
return os._win32.getsize(path)
return os._posix.getsize(path)
+24 -43
View File
@@ -18,7 +18,7 @@ import w32.win32base
import w32.win32process
# 测试用临时文件/目录名前缀
# Temp file/dir name prefixes used by tests
define TEST_DIR = "__sylibtest_dir__"
define TEST_FILE = "__sylibtest_file.txt"
define TEST_COPY = "__sylibtest_copy.txt"
@@ -26,14 +26,11 @@ define TEST_TREE = "__sylibtest_tree__"
define TEST_MOVE = "__sylibtest_moved.txt"
# =============================================================================
# Workaround: TransPyC 无法正确解析 os.xxx() 包级函数调用
# (os.path.xxx() 子模块调用正常,但 os.xxx() 包级调用解析为本地模块)
# 通过 os_backend 模块(单独导入 os._win32 / os._posix)绕过此问题
# =============================================================================
# ===== Workaround: TransPyC cannot resolve package-level os.xxx() calls =====
# Use os_backend (imports os._win32 / os._posix) to bypass it.
def _cleanup():
"""清理可能残留的测试文件/目录"""
"""Remove leftover test files/dirs."""
if os_backend.os_exists(TEST_DIR):
os.rmdir(TEST_DIR)
if os_backend.os_exists(TEST_FILE):
@@ -51,12 +48,10 @@ def run() -> CInt:
testcheck.begin("SysLibTest: 系统兼容层库测试")
# 清理残留
# Clean leftover
_cleanup()
# =============================================================================
# 全局 MBuddy 初始化验证(在 main 中已初始化)
# =============================================================================
# ===== Global MBuddy init check (initialized in main) =====
testcheck.section("全局 MBuddy 初始化验证")
testcheck.check(os._mbuddy != None, "os._mbuddy initialized OK", "os._mbuddy NOT initialized")
@@ -64,13 +59,11 @@ def run() -> CInt:
testcheck.check(shutil._mbuddy != None, "shutil._mbuddy initialized OK", "shutil._mbuddy NOT initialized")
testcheck.check(subprocess._mbuddy != None, "subprocess._mbuddy initialized OK", "subprocess._mbuddy NOT initialized")
# 所有模块应共享同一个 MBuddy 对象
# All modules must share the same MBuddy object
testcheck.check(os._mbuddy == sys._mbuddy, "os==sys same MBuddy OK", "os!=sys different MBuddy")
testcheck.check(shutil._mbuddy == os._mbuddy, "shutil==os same MBuddy OK", "shutil!=os different MBuddy")
# =============================================================================
# MBuddy alloc/free/calloc/realloc(通过 os._mbuddy 测试)
# =============================================================================
# ===== MBuddy alloc/free/calloc/realloc (via os._mbuddy) =====
testcheck.section("MBuddy alloc/free")
p1: bytes = os._mbuddy.alloc(64)
@@ -87,7 +80,7 @@ def run() -> CInt:
os._mbuddy.free(p2)
testcheck.ok("free OK")
# calloc 清零测试
# calloc zeroing test
testcheck.section("MBuddy calloc/realloc")
cp: bytes = os._mbuddy.calloc(4, 16)
@@ -104,7 +97,7 @@ def run() -> CInt:
else:
testcheck.fail("calloc FAILED")
# realloc 数据保留测试
# realloc data preservation test
rp: bytes = os._mbuddy.alloc(32)
rp_c: CUInt8T | CPtr = CPtr(rp)
for i in range(32):
@@ -122,9 +115,7 @@ def run() -> CInt:
else:
testcheck.fail("realloc FAILED")
# =============================================================================
# os.path 路径操作
# =============================================================================
# ===== os.path path operations =====
testcheck.section("os.path 路径操作")
# sep
@@ -151,9 +142,7 @@ def run() -> CInt:
testcheck.check(os.path.isabs("/usr/local"), "isabs(/usr/local) OK", "isabs FAILED")
testcheck.check(not os.path.isabs("relative/path"), "isabs(relative)=False OK", "isabs(relative) should be False")
# =============================================================================
# os 文件/目录操作
# =============================================================================
# ===== os file/dir operations =====
testcheck.section("os 文件/目录操作")
# getcwd
@@ -181,12 +170,10 @@ def run() -> CInt:
testcheck.check(os_backend.os_exists(TEST_TREE) and not os_backend.os_exists(TEST_DIR), "rename: swapped OK", "rename: swap FAILED")
testcheck.check(os.rmdir(TEST_TREE) == 0, "rmdir renamed OK", "rmdir renamed FAILED")
# =============================================================================
# shutil 高级文件操作
# =============================================================================
# ===== shutil high-level file operations =====
testcheck.section("shutil 高级文件操作")
# 创建测试文件
# Create test file
f: w32.fileio.File | CPtr = w32.fileio.File(TEST_FILE, w32.fileio.MODE.W)
testcheck.check(not f.closed, "create test file OK", "create test file FAILED")
f.write_str("hello shutil")
@@ -197,7 +184,7 @@ def run() -> CInt:
testcheck.check(shutil.copyfile(TEST_FILE, TEST_COPY) == 0, "copyfile OK", "copyfile FAILED")
testcheck.check(os_backend.os_exists(TEST_COPY), "copyfile: dst exists OK", "copyfile: dst not exists")
# 验证拷贝内容一致(检查文件大小)
# Verify copied content matches (compare size)
src_size: int64 = os_backend.os_getsize(TEST_FILE)
dst_size: int64 = os_backend.os_getsize(TEST_COPY)
viperlib.snprintf(buf, 512, "src_size=%lld dst_size=%lld", src_size, dst_size)
@@ -209,12 +196,12 @@ def run() -> CInt:
testcheck.check(os_backend.os_exists(TEST_MOVE), "move: dst exists OK", "move: dst not exists")
os_backend.os_remove(TEST_MOVE)
# rmtree(递归删除目录树)
# rmtree (recursive tree delete)
testcheck.check(os.mkdir(TEST_TREE) == 0, "mkdir tree OK", "mkdir tree FAILED")
# 在树中创建子目录
# Create subdir inside the tree
subdir: str = os.path.join(TEST_TREE, "sub")
testcheck.check(os.mkdir(subdir) == 0, "mkdir subdir OK", "mkdir subdir FAILED")
# 在子目录中创建文件
# Create a file inside the subdir
subfile: str = os.path.join(subdir, "leaf.txt")
sf: w32.fileio.File | CPtr = w32.fileio.File(subfile, w32.fileio.MODE.W)
sf.write_str("leaf")
@@ -225,15 +212,13 @@ def run() -> CInt:
testcheck.check(shutil.rmtree(TEST_TREE) == 0, "rmtree OK", "rmtree FAILED")
testcheck.check(not os_backend.os_exists(TEST_TREE), "rmtree: gone OK", "rmtree: still exists")
# 清理剩余文件
# Clean remaining files
if os_backend.os_exists(TEST_FILE):
os_backend.os_remove(TEST_FILE)
if os_backend.os_exists(TEST_COPY):
os_backend.os_remove(TEST_COPY)
# =============================================================================
# sys 系统信息
# =============================================================================
# ===== sys system info =====
testcheck.section("sys 系统信息")
# platform
@@ -262,12 +247,10 @@ def run() -> CInt:
testcheck.check(argv0 != None, "argv(0) OK", "argv(0) FAILED")
testcheck.info(argv0)
# 越界访问
# Out-of-range access
testcheck.check(sys.argv(9999) == None, "argv(out-of-range)=None OK", "argv(out-of-range) should be None")
# =============================================================================
# subprocess 子进程
# =============================================================================
# ===== subprocess =====
testcheck.section("subprocess 子进程")
# Windows: cmd /c echo hello
@@ -279,7 +262,7 @@ def run() -> CInt:
testcheck.check(result.returncode == 0, "returncode == 0 OK", "returncode != 0")
if result.stdout != None:
testcheck.info(result.stdout)
# 验证输出包含 "hello"
# Verify output contains "hello"
testcheck.check(string.strstr(result.stdout, "hello") != None,
"stdout contains 'hello' OK", "stdout missing 'hello'")
else:
@@ -287,9 +270,7 @@ def run() -> CInt:
else:
testcheck.fail("run returned None")
# =============================================================================
# 清理
# =============================================================================
# ===== Cleanup =====
_cleanup()
stdlib.free(buf)
+30 -44
View File
@@ -1,13 +1,5 @@
# ThreadingTest - vthreading 专项测试
#
# 覆盖范围:
# Thread : start/join/is_alive/get_exit_code/close、线程传参
# Lock : 多线程持锁互斥自增共享计数器
# Event : 线程等待事件被唤醒
# Condition : 生产者/消费者模式
# RWLock : 多读单写(SRWLock)
# local : TLS 线程局部存储 set/get 自校验
# get_current_thread_id / sleep_ms
# ThreadingTest - vthreading coverage
# Thread/Lock/Event/Condition/RWLock/local/id/sleep_ms/args
import t, c
from stdint import *
from w32.win32base import NULL, FALSE, TRUE
@@ -16,16 +8,14 @@ import testcheck
import vthreading
# ============================================================
# 共享状态(模块级全局,跨线程读写)
# ============================================================
_shared_count: int = 0 # Lock 并发测试共享计数器
_evt_done: int = 0 # Event 测试完成标志
_cond_ready: int = 0 # Condition 测试就绪标志
_rw_value: int = 0 # RWLock 测试共享值
_main_tid: uint32 = 0 # 主线程 ID
# ===== Shared state: module globals read/written across threads =====
_shared_count: int = 0 # Lock test shared counter
_evt_done: int = 0 # Event test done flag
_cond_ready: int = 0 # Condition test ready flag
_rw_value: int = 0 # RWLock test shared value
_main_tid: uint32 = 0 # Main thread ID
# 并发规模常量
# Concurrency scale constants
THREAD_NUM: int = 4
LOCK_ITER: int = 1000
RW_ITER: int = 100
@@ -33,17 +23,15 @@ TLS_NUM: int = 4
SYS_ITER: int = 10
# ============================================================
# 线程回调(签名: def worker(arg: t.CPtr) -> t.CPtr)
# ============================================================
# ===== Thread callbacks (signature: def worker(arg: t.CPtr) -> t.CPtr) =====
# Thread 基础: 短暂睡眠后退出,保证 start 后 is_alive 观测窗口
# Thread basic: brief sleep then exit, keeps an is_alive window after start
def _basic_worker(arg: t.CPtr) -> t.CPtr:
vthreading.sleep_ms(100)
return NULL
# 传参: 通过 arg 指针自增 100 次(c.Deref/c.DerefAs 读写)
# Arg passing: increment through arg pointer 100 times (c.Deref/c.DerefAs)
def _increment_worker(arg: t.CPtr) -> t.CPtr:
ip: int* = (int*)(arg)
i: int
@@ -52,7 +40,7 @@ def _increment_worker(arg: t.CPtr) -> t.CPtr:
return NULL
# Lock: 持锁自增全局计数器
# Lock: increment a global counter while holding the lock
def _lock_worker(arg: t.CPtr) -> t.CPtr:
lk: vthreading.Lock* = (vthreading.Lock*)(arg)
global _shared_count
@@ -63,7 +51,7 @@ def _lock_worker(arg: t.CPtr) -> t.CPtr:
return NULL
# Event: 等待事件被唤醒后置位完成标志
# Event: wait to be woken, then set the done flag
def _event_worker(arg: t.CPtr) -> t.CPtr:
ev: vthreading.Event* = (vthreading.Event*)(arg)
global _evt_done
@@ -73,7 +61,7 @@ def _event_worker(arg: t.CPtr) -> t.CPtr:
return NULL
# Condition 消费者: 循环等待 _cond_ready 就绪(限次防挂起)
# Condition consumer: wait for _cond_ready, bounded retries to avoid hanging
def _cond_consumer(arg: t.CPtr) -> t.CPtr:
cond: vthreading.Condition* = (vthreading.Condition*)(arg)
global _cond_ready
@@ -86,7 +74,7 @@ def _cond_consumer(arg: t.CPtr) -> t.CPtr:
return NULL
# Condition 生产者: 延迟后置位 _cond_ready 并 notify
# Condition producer: delay, set _cond_ready, then notify
def _cond_producer(arg: t.CPtr) -> t.CPtr:
cond: vthreading.Condition* = (vthreading.Condition*)(arg)
global _cond_ready
@@ -98,7 +86,7 @@ def _cond_producer(arg: t.CPtr) -> t.CPtr:
return NULL
# RWLock 读者: 持读锁反复读共享值
# RWLock reader: read the shared value repeatedly under the read lock
def _rw_reader(arg: t.CPtr) -> t.CPtr:
rwl: vthreading.RWLock* = (vthreading.RWLock*)(arg)
global _rw_value
@@ -110,7 +98,7 @@ def _rw_reader(arg: t.CPtr) -> t.CPtr:
return NULL
# RWLock 写者: 持写锁自增共享值
# RWLock writer: increment the shared value under the write lock
def _rw_writer(arg: t.CPtr) -> t.CPtr:
rwl: vthreading.RWLock* = (vthreading.RWLock*)(arg)
global _rw_value
@@ -122,7 +110,7 @@ def _rw_writer(arg: t.CPtr) -> t.CPtr:
return NULL
# TLS: 每线程 set/get 自校验(存入自身线程 ID 再读回比对)
# TLS: per-thread set/get self-check (store own thread ID, then read back)
def _tls_worker(arg: t.CPtr) -> t.CPtr:
tls: vthreading.local = vthreading.local()
tls.set(t.CPtr(uint64(vthreading.get_current_thread_id())))
@@ -134,7 +122,7 @@ def _tls_worker(arg: t.CPtr) -> t.CPtr:
return t.CPtr(uint64(ok))
# 线程 ID 隔离: 工作线程 ID 必须与主线程不同
# Thread ID isolation: worker ID must differ from the main thread ID
def _tid_worker(arg: t.CPtr) -> t.CPtr:
global _main_tid
if vthreading.get_current_thread_id() == _main_tid:
@@ -142,7 +130,7 @@ def _tid_worker(arg: t.CPtr) -> t.CPtr:
return t.CPtr(uint64(1))
# stdlib.system 多线程并发: 每线程循环调 C 运行时 system(),统计失败次数
# stdlib.system concurrency: each thread calls C system(), count failures
def _system_worker(arg: t.CPtr) -> t.CPtr:
i: int
fails: int = 0
@@ -153,9 +141,7 @@ def _system_worker(arg: t.CPtr) -> t.CPtr:
return t.CPtr(uint64(fails))
# ============================================================
# main
# ============================================================
# ===== main =====
def main() -> int | t.CExport:
testcheck.begin("ThreadingTest: vthreading 专项测试")
@@ -170,7 +156,7 @@ def main() -> int | t.CExport:
testcheck.check(th1.get_exit_code() == 0, "退出码 == 0", "退出码 != 0")
th1.close()
# ========== Thread: 通过 arg 传参 ==========
# ========== Thread: pass arg ==========
testcheck.section("Thread: arg 传参")
cnt: int = 0
th2: vthreading.Thread = vthreading.Thread(_increment_worker, &cnt)
@@ -179,7 +165,7 @@ def main() -> int | t.CExport:
th2.close()
testcheck.check(cnt == 100, "worker 经 arg 自增 100 次", "cnt != 100")
# ========== Lock: 多线程互斥自增 ==========
# ========== Lock: mutex increment ==========
testcheck.section("Lock: 多线程互斥自增")
lock: vthreading.Lock = vthreading.Lock()
t0: vthreading.Thread = vthreading.Thread(_lock_worker, t.CPtr(lock))
@@ -201,7 +187,7 @@ def main() -> int | t.CExport:
testcheck.check(j0 != 0 and j1 != 0 and j2 != 0 and j3 != 0, "4 线程全部 join 成功", "有线程 join 超时")
testcheck.check(_shared_count == THREAD_NUM * LOCK_ITER, "互斥自增计数正确", "计数丢失")
# ========== Event: 线程等待唤醒 ==========
# ========== Event: thread waits for wakeup ==========
testcheck.section("Event: 线程等待唤醒")
ev: vthreading.Event = vthreading.Event(FALSE, FALSE)
th4: vthreading.Thread = vthreading.Thread(_event_worker, t.CPtr(ev))
@@ -215,7 +201,7 @@ def main() -> int | t.CExport:
ev.close()
testcheck.check(_evt_done == 1, "worker 收到事件并置位", "worker 未收到事件")
# ========== Condition: 生产者/消费者 ==========
# ========== Condition: producer/consumer ==========
testcheck.section("Condition: 生产者/消费者")
cond: vthreading.Condition = vthreading.Condition()
tc: vthreading.Thread = vthreading.Thread(_cond_consumer, t.CPtr(cond))
@@ -229,7 +215,7 @@ def main() -> int | t.CExport:
testcheck.check(_cond_ready == 1, "条件变量值已置位", "条件变量值未置位")
cond.delete()
# ========== RWLock: 多读单写 ==========
# ========== RWLock: multi-reader single-writer ==========
testcheck.section("RWLock: 多读单写")
rwl: vthreading.RWLock = vthreading.RWLock()
r1: vthreading.Thread = vthreading.Thread(_rw_reader, t.CPtr(rwl))
@@ -245,7 +231,7 @@ def main() -> int | t.CExport:
w1.close()
testcheck.check(_rw_value == RW_ITER, "写锁自增计数正确", "写锁计数丢失")
# ========== local: TLS 线程局部存储 ==========
# ========== local: TLS thread-local storage ==========
testcheck.section("local: TLS 线程局部存储")
i_t: int
for i_t in range(TLS_NUM):
@@ -255,7 +241,7 @@ def main() -> int | t.CExport:
testcheck.check(th_t.get_exit_code() == 1, "TLS set/get 自校验通过", "TLS 自校验失败")
th_t.close()
# ========== get_current_thread_id: 线程 ID 隔离 ==========
# ========== get_current_thread_id: thread ID isolation ==========
testcheck.section("get_current_thread_id: 线程 ID 隔离")
global _main_tid
_main_tid = vthreading.get_current_thread_id()
@@ -271,7 +257,7 @@ def main() -> int | t.CExport:
vthreading.sleep_ms(20)
testcheck.ok("sleep_ms(20) 正常返回")
# ========== stdlib.system 多线程并发 ==========
# ========== stdlib.system concurrency ==========
testcheck.section("stdlib.system 多线程并发")
s0: vthreading.Thread = vthreading.Thread(_system_worker, NULL)
s1: vthreading.Thread = vthreading.Thread(_system_worker, NULL)
+34 -38
View File
@@ -6,65 +6,62 @@ import w32.win32console
import w32.win32memory
import testcheck
# ============================================================
# TypeCastTest - 测试类型转换、zext/sext/trunc 行为、
# 有符号/无符号混合运算、CDefine 常量
# ============================================================
# TypeCastTest: type casts, zext/sext/trunc behavior,
# mixed signed/unsigned arithmetic and CDefine constants
# --- Test 1: CUInt8T -> CUInt32T 零扩展 (zext) ---
# --- Test 1: CUInt8T -> CUInt32T zero extension (zext) ---
def test_zext_u8_u32():
v: uint8 = 200 # 0xC8, 如果 sign-extend 会变成 0xFFFFFFC8
v: uint8 = 200 # 0xC8; sign-extension would yield 0xFFFFFFC8
wide: uint32 = uint32(v)
testcheck.check(wide == 200, "zext u8->u32 (200)", "zext u8->u32 (expected 200)")
# --- Test 2: CInt8T -> CInt32T 符号扩展 (sext) ---
# --- Test 2: CInt8T -> CInt32T sign extension (sext) ---
def test_sext_i8_i32():
v: int8 = -50 # 0xCE
wide: int32 = int32(v)
testcheck.check(wide == -50, "sext i8->i32 (-50)", "sext i8->i32 (expected -50)")
# --- Test 3: CUInt32T -> CUInt64T 零扩展 ---
# --- Test 3: CUInt32T -> CUInt64T zero extension ---
def test_zext_u32_u64():
v: uint32 = 0x80000000 # 最高位为1
v: uint32 = 0x80000000 # top bit set
wide: uint64 = uint64(v)
testcheck.check(wide == 0x80000000, "zext u32->u64 (0x80000000)", "zext u32->u64 (expected 0x80000000)")
# --- Test 4: CInt32T -> CInt64T 符号扩展 ---
# --- Test 4: CInt32T -> CInt64T sign extension ---
def test_sext_i32_i64():
v: int32 = -1 # 0xFFFFFFFF
wide: int64 = int64(v)
testcheck.check(wide == -1, "sext i32->i64 (-1)", "sext i32->i64 (expected -1)")
# --- Test 5: CUInt64T -> CUInt32T 截断 (trunc) ---
# --- Test 5: CUInt64T -> CUInt32T truncation (trunc) ---
def test_trunc_u64_u32():
v: uint64 = 0x123456789ABCDEF0
narrow: uint32 = uint32(v)
testcheck.check(narrow == 0x9ABCDEF0, "trunc u64->u32 (0x9ABCDEF0)", "trunc u64->u32 (expected 0x9ABCDEF0)")
# --- Test 6: 有符号/无符号混合运算 ---
# --- Test 6: mixed signed/unsigned arithmetic ---
def test_mixed_signed_unsigned():
a: int = -10
b: uint32 = 20
# C 中有符号/无符号混合运算,有符号会转为无符号
# -10 作为 unsigned 是 0xFFFFFFF6 = 4294967286
# 4294967286 + 20 = 4294967306 (overflow to 10 on u32)
# In C mixed signed/unsigned ops convert the signed value to unsigned.
# -10 as u32 is 0xFFFFFFF6; +20 overflows to 10.
result: uint32 = uint32(a) + b
stdio.printf(" mixed signed+unsigned: %u (C behavior: %u)\n", result, uint32(-10) + 20)
testcheck.ok("mixed signed+unsigned (C behavior)")
# --- Test 7: CDefine 常量在运算中的行为 ---
# --- Test 7: CDefine constants in operations ---
define VAL_32BIT = 0x80000000
define VAL_NEG = -1
define VAL_BIG = 0xFFFFFFFF
def test_cdefine_values():
"""测试 CDefine 常量值是否正确"""
"""Verify CDefine constant values."""
v1: uint32 = uint32(VAL_32BIT)
v2: int = VAL_NEG
v3: uint32 = uint32(VAL_BIG)
@@ -72,20 +69,20 @@ def test_cdefine_values():
testcheck.ok("CDefine constants")
# --- Test 8: 位运算与类型宽度 ---
# --- Test 8: bit operations and type width ---
def test_bitops_width():
"""测试位运算是否保持正确类型宽度"""
# 左移
"""Verify bit operations keep the correct type width."""
# Left shift
v: uint32 = 1
shifted: uint32 = v << 31 # 应该是 0x80000000
shifted: uint32 = v << 31 # should be 0x80000000
testcheck.check(shifted == 0x80000000, "bit shift (1<<31 = 0x80000000)", "bit shift (expected 0x80000000)")
# 右移
back: uint32 = shifted >> 31 # 应该是 1
# Right shift
back: uint32 = shifted >> 31 # should be 1
testcheck.check(back == 1, "bit shift (0x80000000>>31 = 1)", "bit shift (expected 1)")
# --- Test 9: 整数除法与取模 (无符号) ---
# --- Test 9: integer div/mod (unsigned) ---
def test_unsigned_divmod():
a: uint32 = 100
b: uint32 = 7
@@ -94,20 +91,19 @@ def test_unsigned_divmod():
testcheck.check(q == 14 and r == 2, "unsigned div/mod (100//7=14, 100%7=2)", "unsigned div/mod (expected 14,2)")
# --- Test 10: 整数除法与取模 (有符号负数) ---
# --- Test 10: integer div/mod (signed negative) ---
def test_signed_divmod_neg():
a: int = -100
b: int = 7
q: int = a // b
r: int = a % b
# C 语言: -100/7 = -14, -100%7 = -2
# Python: -100//7 = -15, -100%7 = 5
# TransPyC 应该遵循 C 语义
# C: -100/7 = -14, -100%7 = -2; Python: -15 and 5.
# TransPyC follows C semantics.
stdio.printf(" signed div/mod: -100//7=%d, -100%%7=%d (C: -14,-2)\n", q, r)
testcheck.ok("signed div/mod (C semantics)")
# --- Test 11: 比较运算返回值 ---
# --- Test 11: comparison operation results ---
def test_comparison_types():
a: int = 10
b: int = 20
@@ -118,22 +114,22 @@ def test_comparison_types():
testcheck.check(lt == 1 and eq == 1 and gt == 1, "comparison operations", "comparison operations failed")
# --- Test 12: 指针与整数互转 ---
# --- Test 12: pointer/integer casts ---
def test_ptr_int_cast():
buf: uint32* = w32.win32memory.VirtualAlloc(None, 64, 0x3000, 0x04)
if not buf:
testcheck.fail("VirtualAlloc returned NULL")
return
# 指针转整数
# Pointer to integer
addr: uint64 = uint64(buf)
stdio.printf(" ptr->int: addr=0x%lx\n", addr)
# 整数转指针
# Integer to pointer
p2: uint32* = (uint32*)(addr)
p2[0] = 0x12345678
testcheck.check(buf[0] == 0x12345678, "ptr<->int roundtrip", "ptr<->int roundtrip failed")
# --- Test 13: CUInt64T 乘法溢出行为 ---
# --- Test 13: CUInt64T multiplication ---
def test_u64_mul():
a: uint64 = 1000
b: uint64 = 1000
@@ -141,19 +137,19 @@ def test_u64_mul():
testcheck.check(c_val == 1000000, "u64 mul (1000*1000=1000000)", "u64 mul (expected 1000000)")
# --- Test 14: bool 运算 (and/or) ---
# --- Test 14: bool operations (and/or) ---
def test_bool_ops():
a: int = 5
b: int = 0
c_val: int = 3
# Python `and`/`or` 是短路求值
r1: int = a and c_val # 5 and 3 -> 在 C 中应该是 (5 && 3) = 1
r2: int = b or c_val # 0 or 3 -> 在 C 中应该是 (0 || 3) = 1
# Python and/or are short-circuiting
r1: int = a and c_val # 5 and 3 -> (5 && 3) = 1 in C
r2: int = b or c_val # 0 or 3 -> (0 || 3) = 1 in C
stdio.printf(" bool: 5 and 3 = %d, 0 or 3 = %d (expect 1,1 in C)\n", r1, r2)
testcheck.ok("bool ops (C semantics)")
# --- Test 15: 条件表达式 (三元运算符) ---
# --- Test 15: conditional expression (ternary) ---
def test_ternary():
a: int = 10
b: int = 20
+1 -1
View File
@@ -6,7 +6,7 @@ import testcheck
# ============================================================
# VRandomTest - 硬件随机数生成 + 标准分布函数测试
# VRandomTest: hardware RNG and standard distribution functions.
# ============================================================
def main() -> int:
+20 -20
View File
@@ -7,12 +7,12 @@ import viperlib
import w32.win32console
# ============================================================
# VariadicTest - 测试 snprintf/printf variadic 参数传递
# VariadicTest - check snprintf/printf variadic argument passing
# ============================================================
# --- Test 1: %u 格式化小整数 (CUInt8T -> CUnsignedInt) ---
# --- Test 1: %u formats small int (CUInt8T -> CUnsignedInt) ---
def test_snprintf_u8():
"""测试 CUInt8T 值通过 t.CUnsignedInt() 传递给 %u"""
"""Check a CUInt8T value passed to %u via t.CUnsignedInt()."""
testcheck.section("Test 1: %u 格式化小整数 (CUInt8T -> CUnsignedInt)")
hr: uint8 = 14
mn: uint8 = 30
@@ -24,9 +24,9 @@ def test_snprintf_u8():
testcheck.ok("CUInt8T -> %u (expect 14:30:59)")
# --- Test 2: %u 格式化 CUInt16T ---
# --- Test 2: %u formats CUInt16T ---
def test_snprintf_u16():
"""测试 CUInt16T 值通过 t.CUnsignedInt() 传递给 %u"""
"""Check a CUInt16T value passed to %u via t.CUnsignedInt()."""
testcheck.section("Test 2: %u 格式化 CUInt16T")
yr: uint16 = 2026
buf: t.CArray[char, 64]
@@ -36,9 +36,9 @@ def test_snprintf_u16():
testcheck.ok("CUInt16T -> %u (expect 2026)")
# --- Test 3: %lu 格式化 CUInt64T ---
# --- Test 3: %lu formats CUInt64T ---
def test_snprintf_u64():
"""测试 CUInt64T 值传递给 %lu"""
"""Check a CUInt64T value passed to %lu."""
testcheck.section("Test 3: %lu 格式化 CUInt64T")
val: uint64 = 1234567890123
buf: t.CArray[char, 64]
@@ -48,9 +48,9 @@ def test_snprintf_u64():
testcheck.ok("CUInt64T -> %lu (expect 1234567890123)")
# --- Test 4: %d 格式化负数 ---
# --- Test 4: %d formats negative int ---
def test_snprintf_d_neg():
"""测试 %d 格式化负整数"""
"""Check %d formatting of a negative int."""
testcheck.section("Test 4: %d 格式化负数")
val: int = -42
buf: t.CArray[char, 64]
@@ -60,7 +60,7 @@ def test_snprintf_d_neg():
testcheck.ok("CInt -> %d neg (expect -42)")
# --- Test 5: %d 格式化正数 ---
# --- Test 5: %d formats positive int ---
def test_snprintf_d_pos():
testcheck.section("Test 5: %d 格式化正数")
val: int = 42
@@ -71,7 +71,7 @@ def test_snprintf_d_pos():
testcheck.ok("CInt -> %d pos (expect 42)")
# --- Test 6: %x 格式化十六进制 ---
# --- Test 6: %x formats hex ---
def test_snprintf_x():
testcheck.section("Test 6: %x 格式化十六进制")
val: uint32 = 0xDEADBEEF
@@ -82,9 +82,9 @@ def test_snprintf_x():
testcheck.ok("%x hex (expect 0xdeadbeef)")
# --- Test 7: 混合格式化 (模拟 desktop.py 时间格式) ---
# --- Test 7: mixed formatting (desktop.py time format) ---
def test_snprintf_mixed():
"""模拟 desktop.py 的时间格式化"""
"""Mimic desktop.py time formatting."""
testcheck.section("Test 7: 混合格式化 (模拟 desktop.py 时间格式)")
hr: uint8 = 14
mn: uint8 = 5
@@ -101,18 +101,18 @@ def test_snprintf_mixed():
testcheck.ok("time format (expect 2026-06-14 14:05:09)")
# --- Test 8: printf 直接输出 variadic ---
# --- Test 8: printf direct variadic output ---
def test_printf_variadic():
"""测试 printf 直接输出 variadic 参数"""
"""Check printf direct variadic output."""
testcheck.section("Test 8: printf 直接输出 variadic")
stdio.printf("Test8 (printf direct): %u %d %lu 0x%x (expect 100 -50 999999999 0xcafe)\n",
uint(100), -50, uint64(999999999), 0xCAFE)
testcheck.ok("printf direct variadic (expect 100 -50 999999999 0xcafe)")
# --- Test 9: 多个 %lu 连续 ---
# --- Test 9: several consecutive %lu ---
def test_snprintf_multi_lu():
"""测试多个 %lu 连续(模拟 perf 日志格式)"""
"""Check several consecutive %lu (mimics perf log format)."""
testcheck.section("Test 9: 多个 %lu 连续")
v1: uint64 = 16
v2: uint64 = 2
@@ -124,7 +124,7 @@ def test_snprintf_multi_lu():
testcheck.ok("multi %lu (expect wall=16 work=2 render=11)")
# --- Test 10: %u 格式化 0 ---
# --- Test 10: %u formats zero ---
def test_snprintf_zero():
testcheck.section("Test 10: %u 格式化 0")
val: uint32 = 0
@@ -135,7 +135,7 @@ def test_snprintf_zero():
testcheck.ok("%u zero (expect 0)")
# --- Test 11: %u 格式化大值 ---
# --- Test 11: %u formats a large value ---
def test_snprintf_large():
testcheck.section("Test 11: %u 格式化大值")
val: uint32 = 4294967295 # 0xFFFFFFFF
@@ -148,7 +148,7 @@ def test_snprintf_large():
# --- Test 12: CUnsignedInt cast from CUInt8T edge values ---
def test_snprintf_u8_edge():
"""测试 CUInt8T 边界值"""
"""Check CUInt8T edge values."""
testcheck.section("Test 12: CUnsignedInt cast from CUInt8T edge values")
v0: uint8 = 0
v127: uint8 = 127
+7 -7
View File
@@ -7,7 +7,7 @@ import memhub
import requests
# 全局 MBuddy 指针
# Global MBuddy pointer
_mbuddy: memhub.MemBuddy*
@@ -16,7 +16,7 @@ def main() -> int:
global _mbuddy
stdio.printf("WebTest: HTTP client library test\n")
# 初始化内存管理器(16MB arena)
# Initialize the memory manager (16MB arena)
arena: bytes = stdlib.malloc(16 * 1024 * 1024)
if arena is None:
stdio.printf("FATAL: malloc arena failed\n")
@@ -25,11 +25,11 @@ def main() -> int:
_mbuddy = memhub.MemBuddy(arena, 16 * 1024 * 1024)
requests._mbuddy = _mbuddy
# 初始化 Socket 库
# Initialize the socket library
result: INT = socket.SocketInit()
stdio.printf("SocketInit: %d\n", result)
# 测试 Socket OOP API
# Test the Socket OOP API
sock = socket.Socket(socket.AF_INET, socket.SOCK_STREAM)
if sock.fd != socket.INVALID_SOCKET:
stdio.printf("Socket: OK (fd=%d)\n", sock.fd)
@@ -38,7 +38,7 @@ def main() -> int:
else:
stdio.printf("Socket: FAIL\n")
# 测试 DNS 解析 — 通过 Socket.connect 间接测试(内部调用 _MakeAddr)
# Test DNS resolution indirectly via Socket.connect (calls _MakeAddr internally)
stdio.printf("\n--- DNS test ---\n")
dns_sock = socket.Socket(socket.AF_INET, socket.SOCK_STREAM)
if dns_sock.fd != socket.INVALID_SOCKET:
@@ -50,7 +50,7 @@ def main() -> int:
stdio.printf("DNS: cn.bing.com resolved but connect failed (err in _MakeAddr debug above)\n")
dns_sock.close()
# 测试 HTTP GET — 使用 DNS 解析 cn.bing.com(example.com 在部分网络下不可达)
# Test HTTP GET via cn.bing.com (example.com is unreachable on some networks)
stdio.printf("\n--- HTTP GET test (cn.bing.com) ---\n")
resp = requests.get("http://cn.bing.com/")
if resp is not None:
@@ -74,7 +74,7 @@ def main() -> int:
else:
stdio.printf("requests.get: FAIL (network unavailable)\n")
# 清理
# Cleanup
socket.SocketCleanup()
stdio.printf("\nSocketCleanup: OK\n")
stdio.printf("WebTest: ALL PASSED\n")
+8 -22
View File
@@ -20,14 +20,8 @@ def fill_data(data: BYTEPTR, size: sizet, seed: sizet, repeating: int):
def huffman_probe(seed: sizet, size: sizet, repeating: int):
"""对 roundtrip 的同一份数据直接用 zhuff 复算字面量码表并打印分布。
背景:随机数据的 comp 远小于其字面量熵下限(250 字节数据熵下限约 221 字节,
实测 comp=132),说明码表/码长分配异常。本探针打印:
- active:拿到码位(bits>0)的符号数
- no_code:有频率却拿不到码位的符号数(编码期会被 encode_symbol 静默丢弃)
- sum15:Σ hist[b]*2^(15-b),合法完整码表必须恰为 32768(=2^15)
再逐位宽打印码字数直方图。
"""Recompute the literal code table with zhuff for one dataset and print its
distribution (active/no_code/sum15 and code-count histogram per bit width).
"""
data: BYTEPTR = BYTEPTR(stdlib.malloc(size))
fill_data(data, size, seed, repeating)
@@ -67,15 +61,8 @@ def huffman_probe(seed: sizet, size: sizet, repeating: int):
def count_freqs_probe(seed: sizet, size: sizet, repeating: int):
"""调用真实的 zdeflate_count_freqs,与朴素直方图对照。
上面 huffman_probe 证明码表层正确,则 comp 远小于熵下限只能来自
"频率统计与编码遍历不一致":count 阶段漏计某些位置 ⇒ 那些字节值 freq=0 ⇒
码表里 bits=0 ⇒ encode_block_data 仍会写出这些字面量,被 encode_symbol
静默丢弃 ⇒ 码流偏短(dec < size)。本探针打印:
- sum_lit:Σlit_freqs,正常应恰为 size+1(每个字节一次 + EOB)
- active:真实统计下 freq>0 的字面量符号数
- hlit / hdist / Σdist_freqs(>0 说明 count 阶段找到了 LZ77 匹配)
"""Call the real zdeflate_count_freqs and compare it with a naive histogram
(prints sum_lit/active/hlit/hdist; sum_lit should equal size+1).
"""
data: BYTEPTR = BYTEPTR(stdlib.malloc(size))
fill_data(data, size, seed, repeating)
@@ -90,9 +77,8 @@ def count_freqs_probe(seed: sizet, size: sizet, repeating: int):
zdeflate.zdeflate_count_freqs(lit, dist, s, data, size)
s.destroy()
# 元素符号性对拍:UINT8PTR 若被当作**有符号 i8**,则字节 ≥128 读成负数
# (-56 >= 128 恒假),既导致 count 阶段 lit_freqs[负数] 写到数组之前(漏计),
# 也让 encode_symbol(data[pos]) 收到负 symbol 被静默丢弃 ⇒ 码流截断。
# Signedness cross-check: if UINT8PTR were treated as signed i8, bytes >=128
# would read negative, undercounting freqs and dropping symbols -> truncated stream.
up: UINT8PTR = UINT8PTR(data)
ge8_up: int = 0
ge8_bp: int = 0
@@ -165,13 +151,13 @@ def roundtrip(seed: sizet, size: sizet, repeating: int, wbits: int) -> int:
def main() -> int:
testcheck.begin("ZlibDbg: zlib 多 seed/size/wbits 往返")
# 先跑码表探针:定位 comp 远小于熵下限的根因(码表异常 / 还是别处)
# Run the code-table probe first to locate the cause of comp below entropy floor
testcheck.section("字面量码表探针")
huffman_probe(0, 250, 0)
huffman_probe(9, 20000, 0)
huffman_probe(0, 256, 1)
# 真实频率统计 vs 朴素直方图对照
# Real frequency stats vs naive histogram comparison
testcheck.section("频率统计探针 (zdeflate_count_freqs)")
count_freqs_probe(0, 250, 0)
count_freqs_probe(9, 20000, 0)
+1 -1
View File
@@ -12,7 +12,7 @@ def main() -> int:
tpz.main123456()
testcheck.ok("zlib test_pyzlib completed")
# 标准 zlib 库(includes/zlib)
# Standard zlib library (includes/zlib)
testcheck.section("标准 zlib 库 (zlib.pyzlib)")
print(stdzp.runtime_version())
testcheck.ok("zlib runtime version printed")
+7 -10
View File
@@ -176,7 +176,7 @@ def test_compressobj():
printf(" Flush result : %zu bytes -> ", out_length)
print_hex_test(c3, out_length, 16)
if out_length > 0 and c3:
new_all: BYTEPTR = stdlib.realloc(all, total + out_length) # 隐式转换
new_all: BYTEPTR = stdlib.realloc(all, total + out_length) # implicit cast
if new_all:
all = new_all
string.memcpy(all + total, c3, out_length)
@@ -643,7 +643,7 @@ def test_huffman_tree():
printf(" Active codes: %d, max code lengthgth: %d\n", total_codes, max_length_found)
printf(" Code assignments:\n")
names: t.CArray[str, None] = ["A","B","C","D","E","F"] # 一个都æ˜?char* 的数ç»?
names: t.CArray[str, None] = ["A","B","C","D","E","F"] # all char* array
syms: t.CArray[int, None] = ['A','B','C','D','E','F']
for i in range(6):
printf(" '%s' (freq=%3d): code=0x%04X, bits=%d\n",
@@ -761,9 +761,8 @@ def test_huffman_tree():
stdlib.free(w.buf)
# 全量 257 符号往返:ZlibDbg 随机数据的失败只在"多符号码表"场景出现,
# 上面 4 符号抽样覆盖不到——这里把 0..256 全部编码再解码逐一比对,
# 与 ZlibDbg 的失败形态(码表把部分符号编成无码位/错码位)直接对齐。
# Full 257-symbol roundtrip: encode and decode every symbol 0..256.
# The 4-symbol sample above misses failures that only appear with many symbols.
w2 = zdef.zbit_writer(None)
for i in range(257):
of_tree.encode_symbol(i, &w2)
@@ -874,10 +873,8 @@ def main123456() -> int:
printf(" Python zlib - C Implementation Tests\n")
printf("==============================================\n")
# Huffman 树/码表构建前置:此前以 "skip: heap corruption from earlier tests"
# 跳过——排在其它用例之后时,前面用例造成的堆破坏会让本用例崩溃,从而掩盖
# 它自己的结论。前置后可在干净堆上独立复现(ZlibDbg 随机数据 roundtrip 失败
# 已定位到"多符号码表构建"这一层,本用例是当前最小复现入口)。
# Run Huffman tree / code-table construction first, on a clean heap.
# After other tests, earlier heap corruption crashes this case and hides its result.
test_huffman_tree()
test_constants()
test_version()
@@ -895,7 +892,7 @@ def main123456() -> int:
test_gzip_format()
test_raw_deflate()
test_zdict()
# test_huffman_tree() # 已前置到 main123456 开头(理由见该处注释)
# test_huffman_tree() # moved to the start of main123456 (see note there)
test_error_handling()
printf("\n==============================================\n")