把 Test/ 纳入 https://git.gvsds.com/GVSDS/Viper_RegressionTesting 。 1) 新增 .gitignore —— 只保留测试源码,剔除全部构建产物: 目录 **/output*/(output / output_opt / output_orig / output_verify / output_dbg)、 **/temp*/(temp / temp_opt)、**/.tpv_build/ 二进制 *.exe *.obj *.o *.out *.a *.lib *.dll 中间物 *.ll *.vpi *.pyi *.deps.txt *.deps.json *.doc.json *_sha1_map.txt _pyi_cache_v1.pkl _pyi_cache_v1.sig.json _shared_sym.json _phase1_manifest.json 其它 build_all.txt(构建日志)、*.log、__pycache__/、*.bak、IDE 目录 保留 App/*.vp、project.json / project_opt.json / project.vpj、README.md、两个 .py 实测 `git add -A --dry-run`:196 个文件,无任何构建产物混入。 2) TestsOverview.md → README.md(作为仓库首页文档)。 3) SequentialRegressionTest.py:7 处 TestsOverview.md 引用同步改为 README.md (文档串、OVERVIEW 路径、read_test_order 文档与报错文案、argparse description、 启动横幅);同时修正入口路径 PROJECTRANS —— 旧值 <root>/Projectrans.py 已不存在, 改为 <root>/TransPyC/Projectrans.py(与 regression_test.py:45-48 记录一致), 否则本脚本会以 "can't open file" 全量失败。 regression_test.py 无需改动:它按目录扫描 project.json 找项目,不引用该文档。
257 lines
8.8 KiB
Plaintext
257 lines
8.8 KiB
Plaintext
from stdint import *
|
||
import t, c
|
||
from t import CInt, CExport
|
||
from stdio import printf
|
||
import memhub
|
||
import stdlib
|
||
import sys
|
||
import string
|
||
import ast
|
||
import w32.win32console
|
||
|
||
|
||
# MBuddy arena 大小:1MB
|
||
ARENA_SIZE: t.CDefine = 1048576
|
||
# mpool 内存大小:512KB
|
||
POOL_SIZE: t.CDefine = 524288
|
||
# dump 缓冲区大小:256KB
|
||
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)
|
||
|
||
printf("AST Comprehensive Test Start\n")
|
||
|
||
# 初始化全局 MBuddy 内存分配器
|
||
arena: bytes = stdlib.malloc(ARENA_SIZE)
|
||
if arena == None:
|
||
printf("FAIL: arena alloc failed\n")
|
||
return 1
|
||
mbuddy_obj: memhub.MemBuddy | t.CPtr = memhub.MemBuddy(arena, ARENA_SIZE)
|
||
if mbuddy_obj == None:
|
||
printf("FAIL: mbuddy init failed\n")
|
||
return 1
|
||
|
||
sys._mbuddy = mbuddy_obj
|
||
ast._mbuddy = mbuddy_obj
|
||
|
||
# 为 ast 解析器创建 mpool
|
||
pool_mem: bytes = stdlib.malloc(POOL_SIZE)
|
||
if pool_mem == None:
|
||
printf("FAIL: malloc for pool failed\n")
|
||
return 1
|
||
pool: memhub.MemPool | t.CPtr = memhub.MemPool(pool_mem, POOL_SIZE)
|
||
if pool == None:
|
||
printf("FAIL: memhub.MemPool init failed\n")
|
||
return 1
|
||
|
||
# dump 缓冲区(独立分配)
|
||
dump_mem: bytes = stdlib.malloc(DUMP_SIZE)
|
||
if dump_mem == None:
|
||
printf("FAIL: malloc for dump failed\n")
|
||
return 1
|
||
dump_buf: t.CChar | t.CPtr = t.CChar(dump_mem, t.CPtr)
|
||
|
||
# 综合测试源码:覆盖 CPython 主要语法
|
||
src: str = """x = 1
|
||
y = 2
|
||
z = x + y
|
||
a = x - y
|
||
b = x * y
|
||
c = x / y
|
||
d = x == y
|
||
e = x < y
|
||
f = x > y
|
||
g = x and y
|
||
h = x or y
|
||
i = not x
|
||
def foo(a, b):
|
||
return a + b
|
||
result = foo(x, y)
|
||
if x > 0:
|
||
print(x)
|
||
else:
|
||
print(y)
|
||
for i in range(10):
|
||
print(i)
|
||
while x > 0:
|
||
x = x - 1
|
||
class Point:
|
||
pass
|
||
"""
|
||
|
||
printf("Parsing comprehensive source...\n")
|
||
|
||
# 解析
|
||
ast._init_tables(pool)
|
||
lx_dbg: t.CPtr = ast.new_lexer(pool)
|
||
if lx_dbg == None:
|
||
printf("FAIL: new_lexer returned None\n")
|
||
stdlib.free(pool_mem)
|
||
stdlib.free(dump_mem)
|
||
return 1
|
||
ast._lexer_init(lx_dbg, src, pool)
|
||
tokens_dbg: t.CPtr = ast.tokenize(lx_dbg)
|
||
if tokens_dbg == None:
|
||
printf("FAIL: tokenize returned None\n")
|
||
stdlib.free(pool_mem)
|
||
stdlib.free(dump_mem)
|
||
return 1
|
||
tree: ast.AST | t.CPtr = ast.parse_tokens(pool, tokens_dbg)
|
||
if tree == None:
|
||
printf("FAIL: parse returned None\n")
|
||
stdlib.free(pool_mem)
|
||
stdlib.free(dump_mem)
|
||
return 1
|
||
|
||
printf("PASS: parse succeeded\n")
|
||
|
||
# dump AST
|
||
printf("Calling ast.dump...\n")
|
||
ast.dump(tree, dump_buf, DUMP_SIZE)
|
||
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
|