test: AstTest Stmt/Expr 运行时区分测试 + BuddyTest CANARY 断言修正
AstTest main.vp 新增 classify_print/classify_list 递归遍历 parse 树,用 isinstance(vtable 子类集合比较) 区分 STMT/EXPR/OTHER 并附 5 项断言;BuddyTest mbuddytest.vp 按 alloc needed=size+16(8 头+8 哨兵)修正 max_usable 与最小块断言。
This commit is contained in:
1 parent
d687216772
commit
f3b16c397c
2 files changed
+145
-5
No files matched your search
@@ -18,6 +18,93 @@ POOL_SIZE: t.CDefine = 524288
|
||||
DUMP_SIZE: t.CDefine = 262144
|
||||
|
||||
|
||||
def classify_list(lst: list[ast.AST | t.CPtr] | t.CPtr, depth: t.CInt):
|
||||
"""递归遍历 list[AST | t.CPtr] 容器,逐元素分类(orelse/args/comparators 等)"""
|
||||
if lst is None:
|
||||
return
|
||||
n: t.CSizeT = lst.__len__()
|
||||
i: t.CSizeT = 0
|
||||
while i < n:
|
||||
classify_print(lst.get(i), depth + 1)
|
||||
i += 1
|
||||
|
||||
|
||||
def classify_print(node: ast.AST | t.CPtr, depth: t.CInt):
|
||||
"""递归遍历 parse 树,用 isinstance 运行时判定每个节点的类别并打印。
|
||||
|
||||
依赖 TPV isinstance 的 vtable 子类集合比较:
|
||||
- isinstance(node, ast.Stmt) → 语句节点(Assign/If/For/While/...)
|
||||
- isinstance(node, ast.ExprNode) → 表达式节点(Name/Constant/BinOp/...)
|
||||
- 两者皆非 → 其他(Module/Expression/...)
|
||||
验证运行时(非编译期静态)正确区分 Stmt 与 ExprNode。
|
||||
"""
|
||||
if node is None:
|
||||
return
|
||||
sp: t.CInt = 0
|
||||
while sp < depth:
|
||||
printf(" ")
|
||||
sp += 1
|
||||
if isinstance(node, ast.Stmt) != 0:
|
||||
printf("STMT %s\n", node.type_name())
|
||||
elif isinstance(node, ast.ExprNode) != 0:
|
||||
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(按需过滤原则)。
|
||||
k: t.CInt = node.kind()
|
||||
if k == ast.ASTKind.Assign:
|
||||
asg: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(node)
|
||||
classify_print(asg.value, depth + 1)
|
||||
elif k == ast.ASTKind.If:
|
||||
ifn: ast.If | t.CPtr = (ast.If | t.CPtr)(node)
|
||||
classify_print(ifn.test, depth + 1)
|
||||
classify_list(ifn.orelse, depth + 1)
|
||||
elif k == ast.ASTKind.While:
|
||||
whl: ast.While | t.CPtr = (ast.While | t.CPtr)(node)
|
||||
classify_print(whl.test, depth + 1)
|
||||
classify_list(whl.orelse, depth + 1)
|
||||
elif k == ast.ASTKind.For:
|
||||
for_nd: ast.For | t.CPtr = (ast.For | t.CPtr)(node)
|
||||
classify_print(for_nd.iter, depth + 1)
|
||||
classify_print(for_nd.target, depth + 1)
|
||||
classify_list(for_nd.orelse, depth + 1)
|
||||
elif k == ast.ASTKind.Return:
|
||||
ret_nd: ast.Return | t.CPtr = (ast.Return | t.CPtr)(node)
|
||||
classify_print(ret_nd.value, depth + 1)
|
||||
elif k == ast.ASTKind.Expr:
|
||||
expr_nd: ast.Expr | t.CPtr = (ast.Expr | t.CPtr)(node)
|
||||
classify_print(expr_nd.value, depth + 1)
|
||||
elif k == ast.ASTKind.BinOp:
|
||||
bin_nd: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node)
|
||||
classify_print(bin_nd.left, depth + 1)
|
||||
classify_print(bin_nd.right, depth + 1)
|
||||
elif k == ast.ASTKind.UnaryOp:
|
||||
una_nd: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node)
|
||||
classify_print(una_nd.operand, depth + 1)
|
||||
elif k == ast.ASTKind.Compare:
|
||||
cmp_nd: ast.Compare | t.CPtr = (ast.Compare | t.CPtr)(node)
|
||||
classify_print(cmp_nd.left, depth + 1)
|
||||
classify_list(cmp_nd.comparators, depth + 1)
|
||||
elif k == ast.ASTKind.BoolOp:
|
||||
bool_nd: ast.BoolOp | t.CPtr = (ast.BoolOp | t.CPtr)(node)
|
||||
classify_list(bool_nd.values, depth + 1)
|
||||
elif k == ast.ASTKind.Call:
|
||||
call_nd: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node)
|
||||
classify_print(call_nd.func, depth + 1)
|
||||
classify_list(call_nd.args, depth + 1)
|
||||
else:
|
||||
pass
|
||||
# children(语句 body 块)
|
||||
if node.children is not None:
|
||||
n: t.CSizeT = node.children.__len__()
|
||||
i: t.CSizeT = 0
|
||||
while i < n:
|
||||
classify_print(node.children.get(i), depth + 1)
|
||||
i += 1
|
||||
|
||||
|
||||
def main() -> CInt | CExport:
|
||||
w32.win32console.SetConsoleCP(65001)
|
||||
w32.win32console.SetConsoleOutputCP(65001)
|
||||
@@ -118,6 +205,56 @@ class Point:
|
||||
printf("ast.dump returned, now printing buffer...\n")
|
||||
printf("=== AST DUMP ===\n%s\n=== END ===\n", dump_buf)
|
||||
|
||||
# ============================================================
|
||||
# Stmt/Expr 运行时区分测试(isinstance vtable 子类集合比较)
|
||||
# ============================================================
|
||||
printf("=== STMT/EXPR RUNTIME DISTINGUISH TEST ===\n")
|
||||
classify_print(tree, 0)
|
||||
|
||||
# 断言 1: Module 既非 Stmt 亦非 ExprNode(顶层容器)
|
||||
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
|
||||
top_ok: t.CInt = 1
|
||||
top_n: t.CSizeT = tree.children.__len__()
|
||||
i2: t.CSizeT = 0
|
||||
while i2 < top_n:
|
||||
top_node: ast.AST | t.CPtr = tree.children.get(i2)
|
||||
if isinstance(top_node, ast.Stmt) == 0:
|
||||
top_ok = 0
|
||||
printf("FAIL: top-level node not Stmt: %s\n", top_node.type_name())
|
||||
i2 += 1
|
||||
if top_ok != 0:
|
||||
printf("PASS: all %lld top-level nodes are Stmt\n", top_n)
|
||||
|
||||
# 断言 3: Assign 是 Stmt 且不是 ExprNode
|
||||
first_assign: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(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
|
||||
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 语义)
|
||||
if top_n >= 15:
|
||||
if_node: ast.If | t.CPtr = (ast.If | t.CPtr)(tree.children.get(14))
|
||||
if if_node.children is not None and if_node.children.__len__() > 0:
|
||||
expr_stmt: ast.Expr | t.CPtr = (ast.Expr | t.CPtr)(if_node.children.get(0))
|
||||
if isinstance(expr_stmt, ast.Stmt) != 0 and isinstance(expr_stmt, ast.ExprNode) == 0:
|
||||
printf("PASS: Expr(stmt) is Stmt, not ExprNode (%s)\n", expr_stmt.type_name())
|
||||
else:
|
||||
printf("FAIL: Expr(stmt) classification wrong\n")
|
||||
printf("=== END RUNTIME TEST ===\n")
|
||||
|
||||
stdlib.free(pool_mem)
|
||||
stdlib.free(dump_mem)
|
||||
return 0
|
||||
@@ -413,11 +413,11 @@ def mbuddy_main() -> CInt:
|
||||
arena_ex: bytes = stdlib.malloc(4096)
|
||||
bd_ex: memhub.MemBuddy | CPtr = memhub.MemBuddy(arena_ex, 4096)
|
||||
|
||||
# 24 + 8 = 32 = MIN_BLOCK, 恰好填满 order 0 块
|
||||
# 24 + 16 = 40 > 32(8 头 + 8 哨兵),需要 order 1 (64 字节)
|
||||
exact_fit: bytes = bd_ex.alloc(24)
|
||||
testcheck.check(exact_fit != None, "exact fit order 0 OK", "exact fit order 0 FAILED")
|
||||
|
||||
# 25 + 8 = 33 > 32, 需要 order 1 (64 字节)
|
||||
# 25 + 16 = 41 > 32, 需要 order 1 (64 字节)
|
||||
over_fit: bytes = bd_ex.alloc(25)
|
||||
testcheck.check(over_fit != None, "over by 1 byte OK", "over by 1 byte FAILED")
|
||||
|
||||
@@ -426,7 +426,9 @@ def mbuddy_main() -> CInt:
|
||||
testcheck.check(bd_ex.free_count() == 1, "boundary: coalesce OK", "boundary: coalesce FAILED")
|
||||
|
||||
# 2. 单次分配接近 arena 上限
|
||||
max_usable: CSizeT = bd_ex.mem_size - 8
|
||||
# 可用数据区 = mem_size - 8(头) - 8(哨兵),alloc(max_usable) 的 needed
|
||||
# 恰好 = mem_size,正好填满最大块(order 6 = 2048)
|
||||
max_usable: CSizeT = bd_ex.mem_size - 16
|
||||
viperlib.snprintf(buf, 256, "mem_size=%lu, max_usable=%lu", bd_ex.mem_size, max_usable)
|
||||
testcheck.info(buf)
|
||||
|
||||
@@ -465,10 +467,11 @@ def mbuddy_main() -> CInt:
|
||||
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")
|
||||
|
||||
one_p: bytes = bd_one.alloc(24)
|
||||
# 最小块 32 字节 = 数据 16 + 头 8 + 哨兵 8,alloc(16) 恰好填满
|
||||
one_p: bytes = bd_one.alloc(16)
|
||||
testcheck.check(one_p != None, "one block: alloc OK", "one block: alloc FAILED")
|
||||
|
||||
one_p2: bytes = bd_one.alloc(24)
|
||||
one_p2: bytes = bd_one.alloc(16)
|
||||
testcheck.check(one_p2 == None, "one block: OOM OK", "one block: should be OOM")
|
||||
|
||||
bd_one.free(one_p)
|
||||
|
||||
Reference in new issue
Block a user