chore(test): 初始化回归测试仓(新增 .gitignore,TestsOverview.md 改为 README.md)
把 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 找项目,不引用该文档。
This commit is contained in:
commit
3c6fb1d246
196 files changed
+24775
No files matched your search
+54
@@ -0,0 +1,54 @@
|
||||
# ============================================================
|
||||
# Viper 回归测试仓(Test/)
|
||||
# 仅提交测试源码:App/*.vp、project*.json、README.md、两个 .py 脚本
|
||||
# ============================================================
|
||||
|
||||
# Python
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
*.so
|
||||
|
||||
# 构建产物目录
|
||||
# output/ 及其变体(output_opt / output_orig / output_verify / output_dbg)、
|
||||
# temp/ 与 temp_opt/、TransPyV 的 .tpv_build/
|
||||
**/output*/
|
||||
**/temp*/
|
||||
**/.tpv_build/
|
||||
|
||||
# 可执行文件与目标文件
|
||||
*.exe
|
||||
*.obj
|
||||
*.o
|
||||
*.out
|
||||
*.a
|
||||
*.lib
|
||||
*.dll
|
||||
|
||||
# 编译器中间产物(LLVM IR / 存根 / 依赖记录 / 符号表 / 缓存)
|
||||
*.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
|
||||
|
||||
# 备份
|
||||
*.bak
|
||||
|
||||
# IDE
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
.trae/
|
||||
@@ -0,0 +1,204 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import stdio
|
||||
import stdlib
|
||||
import string
|
||||
import memhub
|
||||
import argparse
|
||||
import testcheck
|
||||
|
||||
|
||||
# 全局 MBuddy 指针
|
||||
_mbuddy: memhub.MemBuddy | t.CPtr
|
||||
|
||||
|
||||
@t.CExport
|
||||
def main() -> int:
|
||||
global _mbuddy
|
||||
testcheck.begin("ArgparseTest: 命令行参数解析")
|
||||
|
||||
# 初始化内存管理器
|
||||
arena: bytes = stdlib.malloc(16 * 1024 * 1024)
|
||||
if arena is None:
|
||||
testcheck.fail("malloc arena failed")
|
||||
return 1
|
||||
|
||||
_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 个指针
|
||||
argv: str | t.CPtr = (str | t.CPtr)(argv_buf)
|
||||
|
||||
# argv[0] = "myprog"
|
||||
s0: bytes = _mbuddy.alloc(16)
|
||||
string.strcpy(s0, "myprog")
|
||||
argv0: str | t.CPtr = (str | t.CPtr)(t.CUInt64T(argv))
|
||||
argv0[0] = s0
|
||||
|
||||
# argv[1] = "--input"
|
||||
s1: bytes = _mbuddy.alloc(16)
|
||||
string.strcpy(s1, "--input")
|
||||
argv1: str | t.CPtr = (str | t.CPtr)(t.CUInt64T(argv) + 8)
|
||||
argv1[0] = s1
|
||||
|
||||
# argv[2] = "test.txt"
|
||||
s2: bytes = _mbuddy.alloc(16)
|
||||
string.strcpy(s2, "test.txt")
|
||||
argv2: str | t.CPtr = (str | t.CPtr)(t.CUInt64T(argv) + 16)
|
||||
argv2[0] = s2
|
||||
|
||||
# argv[3] = "-c"
|
||||
s3: bytes = _mbuddy.alloc(8)
|
||||
string.strcpy(s3, "-c")
|
||||
argv3: str | t.CPtr = (str | t.CPtr)(t.CUInt64T(argv) + 24)
|
||||
argv3[0] = s3
|
||||
|
||||
# argv[4] = "42"
|
||||
s4: bytes = _mbuddy.alloc(8)
|
||||
string.strcpy(s4, "42")
|
||||
argv4: str | t.CPtr = (str | t.CPtr)(t.CUInt64T(argv) + 32)
|
||||
argv4[0] = s4
|
||||
|
||||
# argv[5] = "--verbose"
|
||||
s5: bytes = _mbuddy.alloc(16)
|
||||
string.strcpy(s5, "--verbose")
|
||||
argv5: str | t.CPtr = (str | t.CPtr)(t.CUInt64T(argv) + 40)
|
||||
argv5[0] = s5
|
||||
|
||||
# argv[6] = "output.dat"
|
||||
s6: bytes = _mbuddy.alloc(16)
|
||||
string.strcpy(s6, "output.dat")
|
||||
argv6: str | t.CPtr = (str | t.CPtr)(t.CUInt64T(argv) + 48)
|
||||
argv6[0] = s6
|
||||
|
||||
argc: INT = 7
|
||||
|
||||
# ============================================================
|
||||
# Test 1: 基本解析 (--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")
|
||||
parser.add_argument("--count", "-c", argparse.INT, 1, None, False, argparse.STORE, "repeat count")
|
||||
parser.add_argument("--verbose", "-v", argparse.BOOL, 0, None, False, argparse.STORE_TRUE, "enable verbose output")
|
||||
parser.add_argument("output", None, argparse.STRING, 0, None, False, argparse.STORE, "output file path")
|
||||
|
||||
args = parser.parse_args(argc, argv)
|
||||
if args is not None:
|
||||
testcheck.ok("parse_args returned non-NULL")
|
||||
inp: str = args.get_str("input")
|
||||
cnt: INT = args.get_int("count")
|
||||
verb: INT = args.get_bool("verbose")
|
||||
out: str = args.get_str("output")
|
||||
testcheck.check(string.strcmp(inp, "test.txt") == 0, "input = test.txt", "input mismatch")
|
||||
testcheck.check(cnt == 42, "count = 42", "count mismatch")
|
||||
testcheck.check(verb == True, "verbose = True", "verbose mismatch")
|
||||
testcheck.check(string.strcmp(out, "output.dat") == 0, "output = output.dat", "output mismatch")
|
||||
argparse.release(args)
|
||||
else:
|
||||
testcheck.fail("parse_args returned NULL")
|
||||
|
||||
# ============================================================
|
||||
# Test 2: --name=value 语法
|
||||
# ============================================================
|
||||
testcheck.section("Test 2: --name=value 语法")
|
||||
|
||||
argv2_buf: bytes = _mbuddy.alloc(8 * 3)
|
||||
argv2: str | t.CPtr = (str | t.CPtr)(argv2_buf)
|
||||
|
||||
a0: bytes = _mbuddy.alloc(16)
|
||||
string.strcpy(a0, "myprog")
|
||||
a0_ptr: str | t.CPtr = (str | t.CPtr)(t.CUInt64T(argv2))
|
||||
a0_ptr[0] = a0
|
||||
|
||||
a1: bytes = _mbuddy.alloc(32)
|
||||
string.strcpy(a1, "--input=hello.txt")
|
||||
a1_ptr: str | t.CPtr = (str | t.CPtr)(t.CUInt64T(argv2) + 8)
|
||||
a1_ptr[0] = a1
|
||||
|
||||
a2: bytes = _mbuddy.alloc(16)
|
||||
string.strcpy(a2, "output2.dat")
|
||||
a2_ptr: str | t.CPtr = (str | t.CPtr)(t.CUInt64T(argv2) + 16)
|
||||
a2_ptr[0] = a2
|
||||
args2 = parser.parse_args(3, argv2)
|
||||
if args2 is not None:
|
||||
testcheck.ok("parse_args returned non-NULL")
|
||||
inp2: str = args2.get_str("input")
|
||||
cnt2: INT = args2.get_int("count")
|
||||
out2: str = args2.get_str("output")
|
||||
testcheck.check(string.strcmp(inp2, "hello.txt") == 0, "input = hello.txt", "input mismatch")
|
||||
testcheck.check(cnt2 == 1, "count = 1 (default)", "count mismatch")
|
||||
testcheck.check(string.strcmp(out2, "output2.dat") == 0, "output = output2.dat", "output mismatch")
|
||||
argparse.release(args2)
|
||||
else:
|
||||
testcheck.fail("parse_args returned NULL")
|
||||
|
||||
# ============================================================
|
||||
# Test 3: -v COUNT 计数动作
|
||||
# ============================================================
|
||||
testcheck.section("Test 3: COUNT 计数动作")
|
||||
|
||||
argv3_buf: bytes = _mbuddy.alloc(8 * 4)
|
||||
argv3_arr: str | t.CPtr = (str | t.CPtr)(argv3_buf)
|
||||
|
||||
b0: bytes = _mbuddy.alloc(8)
|
||||
string.strcpy(b0, "myprog")
|
||||
b0_ptr: str | t.CPtr = (str | t.CPtr)(t.CUInt64T(argv3_arr))
|
||||
b0_ptr[0] = b0
|
||||
|
||||
b1: bytes = _mbuddy.alloc(8)
|
||||
string.strcpy(b1, "-v")
|
||||
b1_ptr: str | t.CPtr = (str | t.CPtr)(t.CUInt64T(argv3_arr) + 8)
|
||||
b1_ptr[0] = b1
|
||||
|
||||
b2: bytes = _mbuddy.alloc(8)
|
||||
string.strcpy(b2, "-v")
|
||||
b2_ptr: str | t.CPtr = (str | t.CPtr)(t.CUInt64T(argv3_arr) + 16)
|
||||
b2_ptr[0] = b2
|
||||
|
||||
b3: bytes = _mbuddy.alloc(16)
|
||||
string.strcpy(b3, "output3.dat")
|
||||
b3_ptr: str | t.CPtr = (str | t.CPtr)(t.CUInt64T(argv3_arr) + 24)
|
||||
b3_ptr[0] = b3
|
||||
|
||||
parser2 = argparse.ArgumentParser("myprog", "Count test", pool=_mbuddy)
|
||||
parser2.add_argument("--verbose", "-v", argparse.BOOL, 0, None, False, argparse.COUNT, "verbosity level")
|
||||
parser2.add_argument("output", None, argparse.STRING, 0, None, False, argparse.STORE, "output file")
|
||||
|
||||
args3 = parser2.parse_args(4, argv3_arr)
|
||||
if args3 is not None:
|
||||
testcheck.ok("parse_args returned non-NULL")
|
||||
verb3: INT = args3.get_int("verbose")
|
||||
out3: str = args3.get_str("output")
|
||||
testcheck.check(verb3 == 2, "verbose = 2 (counted)", "verbose count mismatch")
|
||||
testcheck.check(string.strcmp(out3, "output3.dat") == 0, "output = output3.dat", "output mismatch")
|
||||
argparse.release(args3)
|
||||
else:
|
||||
testcheck.fail("parse_args returned NULL")
|
||||
|
||||
# ============================================================
|
||||
# Test 4: 关键字参数调用 add_argument
|
||||
# ============================================================
|
||||
testcheck.section("Test 4: 关键字参数")
|
||||
|
||||
parser3 = argparse.ArgumentParser("myprog", "Keyword arg test", pool=_mbuddy)
|
||||
parser3.add_argument("--input", short="-i", arg_type=argparse.STRING, default=0, default_str=None, required=False, action=argparse.STORE, help="input file")
|
||||
parser3.add_argument("--count", short="-c", arg_type=argparse.INT, default=1, required=False, action=argparse.STORE, help="count")
|
||||
parser3.add_argument("--verbose", short="-v", arg_type=argparse.BOOL, default=0, required=False, action=argparse.STORE_TRUE, help="verbose")
|
||||
parser3.add_argument("output", arg_type=argparse.STRING, default=0, required=False, action=argparse.STORE, help="output file")
|
||||
|
||||
args4 = parser3.parse_args(argc, argv)
|
||||
if args4 is not None:
|
||||
testcheck.ok("parse_args returned non-NULL")
|
||||
inp4: str = args4.get_str("input")
|
||||
cnt4: INT = args4.get_int("count")
|
||||
out4: str = args4.get_str("output")
|
||||
testcheck.check(string.strcmp(inp4, "test.txt") == 0, "input = test.txt", "input mismatch")
|
||||
testcheck.check(cnt4 == 42, "count = 42", "count mismatch")
|
||||
testcheck.check(string.strcmp(out4, "output.dat") == 0, "output = output.dat", "output mismatch")
|
||||
argparse.release(args4)
|
||||
else:
|
||||
testcheck.fail("parse_args returned NULL")
|
||||
|
||||
return testcheck.end()
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
|
||||
"name": "ArgparseTest",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": ["-filetype=obj", "-relocation-model=pic"]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": ["-Wl,--allow-multiple-definition", "-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32"],
|
||||
"output": "ArgparseTest.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true,
|
||||
"startup": false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,256 @@
|
||||
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
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
|
||||
"name": "AstTest",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": ["-filetype=obj", "-relocation-model=pic"]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": ["-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32", "-Wl,--allow-multiple-definition"],
|
||||
"output": "AstTest.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
from stdint import *
|
||||
import w32.win32console
|
||||
import t, c
|
||||
from t import CInt, CExport
|
||||
import memhub
|
||||
import mbuddytest
|
||||
|
||||
|
||||
def main() -> CInt | CExport:
|
||||
w32.win32console.SetConsoleCP(65001)
|
||||
w32.win32console.SetConsoleOutputCP(65001)
|
||||
|
||||
# memhub 的 [MEMDBG] 悬空/重复 free 检测默认开启(_memdbg_enable=1)。
|
||||
# BuddyTest 含"故意双重 free,期望静默拒绝且状态不损坏"的负向用例,
|
||||
# 若保持开启会在第二次 free 处终止进程 → 在此关闭 debug 模式。
|
||||
memhub._memdbg_enable = 0
|
||||
|
||||
return mbuddytest.mbuddy_main()
|
||||
@@ -0,0 +1,545 @@
|
||||
import t, c
|
||||
from t import CInt, CPtr, CChar, CUInt8T, CUInt32T, CUInt64T, CSizeT
|
||||
import viperlib
|
||||
import viperio
|
||||
import stdlib
|
||||
import memhub
|
||||
import string
|
||||
import testcheck
|
||||
import w32.win32process
|
||||
import w32.win32sync
|
||||
import w32.win32base
|
||||
|
||||
|
||||
# 线程函数: 在共享 MBuddy 上执行 alloc/free (测试 spinlock 线程安全)
|
||||
def _thread_alloc_free(param: t.CPtr) -> t.CUInt32T:
|
||||
bd: memhub.MemBuddy | t.CPtr = (memhub.MemBuddy | t.CPtr)(param)
|
||||
i: CInt
|
||||
for i in range(100):
|
||||
p: bytes = bd.alloc(32)
|
||||
if p != None:
|
||||
p_c: CUInt8T | CPtr = CPtr(p)
|
||||
p_c[0] = CUInt8T(i & 0xFF)
|
||||
bd.free(p)
|
||||
return 0
|
||||
|
||||
|
||||
def mbuddy_main() -> CInt:
|
||||
buf: bytes = stdlib.malloc(256)
|
||||
|
||||
testcheck.begin("BuddyTest: 伙伴系统内存分配器测试")
|
||||
|
||||
# === 基础 alloc/free 测试 ===
|
||||
testcheck.section("基础 alloc/free")
|
||||
arena: bytes = stdlib.malloc(65536)
|
||||
bd: memhub.MemBuddy | CPtr = memhub.MemBuddy(arena, 65536)
|
||||
|
||||
viperlib.snprintf(buf, 256, "stats=%lu, free_count=%lu", bd.stats(), bd.free_count())
|
||||
testcheck.info(buf)
|
||||
|
||||
p1: bytes = bd.alloc(16)
|
||||
p2: bytes = bd.alloc(64)
|
||||
p3: bytes = bd.alloc(256)
|
||||
testcheck.check(p1 != None and p2 != None and p3 != None,
|
||||
"3 allocs OK", "alloc FAILED")
|
||||
|
||||
# 写入数据验证指针可用
|
||||
p_c: CUInt8T | CPtr = CPtr(p1)
|
||||
p_c[0] = CUInt8T(0xAB)
|
||||
p_c[1] = CUInt8T(0xCD)
|
||||
viperlib.snprintf(buf, 256, "p1[0]=0x%x p1[1]=0x%x", p_c[0], p_c[1])
|
||||
testcheck.info(buf)
|
||||
testcheck.check(p_c[0] == CUInt8T(0xAB) and p_c[1] == CUInt8T(0xCD),
|
||||
"write/read OK", "write/read FAILED")
|
||||
|
||||
bd.free(p1)
|
||||
bd.free(p2)
|
||||
bd.free(p3)
|
||||
testcheck.ok("3 frees OK")
|
||||
|
||||
# 释放后验证合并: free_count 应回到初始分解块数 (10)
|
||||
# 4096-264 内非 2 的幂: 65536-264=65272 二进制分解为 10 个 2 的幂块
|
||||
testcheck.check(bd.free_count() == 10,
|
||||
"coalesce: free_count=10 OK", "coalesce: free_count != 10")
|
||||
|
||||
# 合并后应能分配大块
|
||||
big: bytes = bd.alloc(16000)
|
||||
testcheck.check(big != None, "big alloc OK", "big alloc FAILED")
|
||||
bd.free(big)
|
||||
|
||||
stdlib.free(arena)
|
||||
|
||||
# === calloc 测试 (验证清零) ===
|
||||
testcheck.section("calloc 清零")
|
||||
arena2: bytes = stdlib.malloc(4096)
|
||||
viperlib.snprintf(buf, 256, "arena2 = %p", arena2)
|
||||
testcheck.info(buf)
|
||||
bd2: memhub.MemBuddy | CPtr = memhub.MemBuddy(arena2, 4096)
|
||||
|
||||
dirty: bytes = bd2.alloc(64)
|
||||
viperlib.snprintf(buf, 256, "dirty = %p", dirty)
|
||||
testcheck.info(buf)
|
||||
d_c: CUInt8T | CPtr = CPtr(dirty)
|
||||
i: CInt
|
||||
for i in range(64):
|
||||
d_c[i] = CUInt8T(0xFF)
|
||||
bd2.free(dirty)
|
||||
|
||||
cl: bytes = bd2.calloc(8, 8)
|
||||
viperlib.snprintf(buf, 256, "cl = %p (arena2=%p, dirty was=%p)", cl, arena2, dirty)
|
||||
testcheck.info(buf)
|
||||
if cl != None:
|
||||
cl_c: CUInt8T | CPtr = CPtr(cl)
|
||||
all_zero: CInt = 1
|
||||
j: CInt
|
||||
for j in range(64):
|
||||
if cl_c[j] != 0:
|
||||
all_zero = 0
|
||||
break
|
||||
testcheck.check(all_zero == 1, "calloc zeroed OK", "calloc NOT zeroed")
|
||||
bd2.free(cl)
|
||||
else:
|
||||
testcheck.fail("calloc FAILED")
|
||||
|
||||
stdlib.free(arena2)
|
||||
|
||||
# === realloc 扩展测试 ===
|
||||
testcheck.section("realloc 扩展")
|
||||
arena3: bytes = stdlib.malloc(4096)
|
||||
bd3: memhub.MemBuddy | CPtr = memhub.MemBuddy(arena3, 4096)
|
||||
|
||||
rp: bytes = bd3.alloc(32)
|
||||
rp_c: CUInt8T | CPtr = CPtr(rp)
|
||||
k: CInt
|
||||
for k in range(32):
|
||||
rp_c[k] = CUInt8T(k + 1)
|
||||
|
||||
rp2: bytes = bd3.realloc(rp, 128)
|
||||
if rp2 != None:
|
||||
rp2_c: CUInt8T | CPtr = CPtr(rp2)
|
||||
ok: CInt = 1
|
||||
m: CInt
|
||||
for m in range(32):
|
||||
if rp2_c[m] != CUInt8T(m + 1):
|
||||
ok = 0
|
||||
break
|
||||
testcheck.check(ok == 1, "realloc grow data preserved OK", "realloc grow data LOST")
|
||||
bd3.free(rp2)
|
||||
else:
|
||||
testcheck.fail("realloc grow FAILED")
|
||||
|
||||
stdlib.free(arena3)
|
||||
|
||||
# === 原地收缩测试 (验证无泄漏) ===
|
||||
testcheck.section("原地收缩 (realloc shrink)")
|
||||
arena_shrink: bytes = stdlib.malloc(4096)
|
||||
bds: memhub.MemBuddy | CPtr = memhub.MemBuddy(arena_shrink, 4096)
|
||||
|
||||
sp: bytes = bds.alloc(256)
|
||||
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), 应原地返回同一指针
|
||||
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")
|
||||
|
||||
# 验证数据仍可读写
|
||||
sp_c: CUInt8T | CPtr = CPtr(sp2)
|
||||
sp_c[0] = CUInt8T(0x42)
|
||||
testcheck.check(sp_c[0] == CUInt8T(0x42), "shrink data OK", "shrink data FAILED")
|
||||
|
||||
bds.free(sp2)
|
||||
testcheck.check(bds.free_count() == 6, "shrink+free coalesce OK", "shrink+free coalesce FAILED")
|
||||
|
||||
stdlib.free(arena_shrink)
|
||||
|
||||
# === 边界情况测试 ===
|
||||
testcheck.section("边界情况")
|
||||
arena4: bytes = stdlib.malloc(4096)
|
||||
bd4: memhub.MemBuddy | CPtr = memhub.MemBuddy(arena4, 4096)
|
||||
|
||||
# alloc(0) 应返回 None
|
||||
z: bytes = bd4.alloc(0)
|
||||
testcheck.check(z == None, "alloc(0)=None OK", "alloc(0) should be None")
|
||||
|
||||
# free(None) 应安全
|
||||
bd4.free(None)
|
||||
testcheck.ok("free(None) safe")
|
||||
|
||||
# realloc(None, size) 等价于 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
|
||||
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)
|
||||
|
||||
# === 非法指针防护测试 ===
|
||||
testcheck.section("非法指针防护")
|
||||
arena5: bytes = stdlib.malloc(4096)
|
||||
bd5: memhub.MemBuddy | CPtr = memhub.MemBuddy(arena5, 4096)
|
||||
|
||||
valid: bytes = bd5.alloc(32)
|
||||
testcheck.check(valid != None, "alloc for illegal test OK", "alloc FAILED")
|
||||
|
||||
# 1. free 随机地址 (地址 1)
|
||||
bd5.free(t.CPtr(t.CUInt64T(1)))
|
||||
testcheck.ok("free(addr=1) ignored")
|
||||
|
||||
# 2. free NULL
|
||||
bd5.free(None)
|
||||
testcheck.ok("free(NULL) ignored")
|
||||
|
||||
# 3. free 越界指针 (arena 之前)
|
||||
bd5.free(t.CPtr(t.CUInt64T(arena5)))
|
||||
testcheck.ok("free(before arena) ignored")
|
||||
|
||||
# 4. free 越界指针 (arena 之后)
|
||||
bd5.free(t.CPtr(t.CUInt64T(arena5) + 99999))
|
||||
testcheck.ok("free(after arena) ignored")
|
||||
|
||||
# 5. free 未对齐指针 (arena + 1, 在 mem 区域内但不对齐)
|
||||
bd5.free(t.CPtr(t.CUInt64T(bd5.base) + 1))
|
||||
testcheck.ok("free(misaligned) ignored")
|
||||
|
||||
# 6. 验证合法 free 仍正常工作 (释放后应能再次分配)
|
||||
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
|
||||
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 内存耗尽测试 ===
|
||||
testcheck.section("OOM 内存耗尽")
|
||||
arena6: bytes = stdlib.malloc(4096)
|
||||
bd6: memhub.MemBuddy | CPtr = memhub.MemBuddy(arena6, 4096)
|
||||
|
||||
# 持续分配直到失败
|
||||
alloc_count: CInt = 0
|
||||
ptrs_arr: bytes = stdlib.malloc(8 * 256) # 存储指针的数组
|
||||
ptrs: CUInt64T | CPtr = CPtr(ptrs_arr)
|
||||
|
||||
while alloc_count < 256:
|
||||
p: bytes = bd6.alloc(32)
|
||||
if p == None:
|
||||
break
|
||||
ptrs[alloc_count] = t.CUInt64T(p)
|
||||
alloc_count += 1
|
||||
|
||||
viperlib.snprintf(buf, 256, "allocated %d blocks before OOM", alloc_count)
|
||||
testcheck.info(buf)
|
||||
testcheck.check(alloc_count > 0, "OOM: got some allocs OK", "OOM: no allocs at all")
|
||||
|
||||
# 尝试再分配应失败
|
||||
oom_p: bytes = bd6.alloc(32)
|
||||
testcheck.check(oom_p == None, "OOM: alloc fails OK", "OOM: alloc should fail")
|
||||
|
||||
# 释放一个块后应能再次分配
|
||||
if alloc_count > 0:
|
||||
first_ptr: bytes = t.CPtr(ptrs[0])
|
||||
bd6.free(first_ptr)
|
||||
retry: bytes = bd6.alloc(32)
|
||||
testcheck.check(retry != None, "OOM: free+alloc OK", "OOM: free+alloc FAILED")
|
||||
if retry != None:
|
||||
bd6.free(retry)
|
||||
|
||||
# 释放所有块
|
||||
idx: CInt = 1
|
||||
while idx < alloc_count:
|
||||
cur_p: bytes = t.CPtr(ptrs[idx])
|
||||
bd6.free(cur_p)
|
||||
idx += 1
|
||||
|
||||
# 全部释放后应能合并回初始分解块数 (6)
|
||||
testcheck.check(bd6.free_count() == 6,
|
||||
"OOM: full coalesce OK", "OOM: free_count != 6 after full free")
|
||||
|
||||
stdlib.free(ptrs_arr)
|
||||
stdlib.free(arena6)
|
||||
|
||||
# === 空闲链表状态测试 ===
|
||||
testcheck.section("空闲链表状态")
|
||||
arena7: bytes = stdlib.malloc(4096)
|
||||
bd7: memhub.MemBuddy | CPtr = memhub.MemBuddy(arena7, 4096)
|
||||
|
||||
# 初始: 非 2 的幂 arena (4096-264=3832) 二进制分解为 6 个块
|
||||
testcheck.check(bd7.free_count() == 6, "init: 6 free blocks OK", "init: free_count != 6")
|
||||
|
||||
# 分配后: 空闲块数应增加 (分裂产生多个小块)
|
||||
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")
|
||||
|
||||
# 再分配
|
||||
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: 空闲块数应增加
|
||||
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 块
|
||||
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 上下文管理器测试 ===
|
||||
testcheck.section("with 上下文管理器")
|
||||
arena8: bytes = stdlib.malloc(4096)
|
||||
with memhub.MemBuddy(arena8, 4096) as wbd:
|
||||
wp1: bytes = wbd.alloc(32)
|
||||
wp2: bytes = wbd.alloc(64)
|
||||
testcheck.check(wp1 != None and wp2 != None,
|
||||
"with: allocs OK", "with: allocs FAILED")
|
||||
# 退出 with 块时 __exit__ 自动 reset
|
||||
|
||||
# 退出后重新进入,验证 reset 生效
|
||||
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 检测测试 ===
|
||||
testcheck.section("双重 free 检测")
|
||||
arena_df: bytes = stdlib.malloc(4096)
|
||||
bd_df: memhub.MemBuddy | CPtr = memhub.MemBuddy(arena_df, 4096)
|
||||
|
||||
df: bytes = bd_df.alloc(64)
|
||||
testcheck.check(df != None, "df: alloc OK", "df: alloc FAILED")
|
||||
|
||||
# 第一次 free
|
||||
bd_df.free(df)
|
||||
fc_df1: CSizeT = bd_df.free_count()
|
||||
testcheck.ok("first free OK")
|
||||
|
||||
# 第二次 free (双重 free) — 应被静默拒绝
|
||||
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")
|
||||
|
||||
# 验证分配器仍正常工作
|
||||
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:
|
||||
bd_df.free(df2)
|
||||
|
||||
stdlib.free(arena_df)
|
||||
|
||||
# === 自检功能测试 ===
|
||||
testcheck.section("自检功能")
|
||||
arena_sc: bytes = stdlib.malloc(4096)
|
||||
bd_sc: memhub.MemBuddy | CPtr = memhub.MemBuddy(arena_sc, 4096)
|
||||
|
||||
# 初始状态自检
|
||||
testcheck.check(bd_sc.self_check() == 0, "self_check init OK", "self_check init FAILED")
|
||||
|
||||
# 分配后自检
|
||||
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")
|
||||
|
||||
# 部分释放后自检
|
||||
bd_sc.free(sc_p1)
|
||||
testcheck.check(bd_sc.self_check() == 0, "self_check after partial free OK", "self_check after partial free FAILED")
|
||||
|
||||
# 全部释放后自检 (应合并回单个大块)
|
||||
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 后自检 (验证状态未损坏)
|
||||
sc_p3: bytes = bd_sc.alloc(64)
|
||||
bd_sc.free(sc_p3)
|
||||
bd_sc.free(sc_p3) # 双重 free,应被拒绝
|
||||
testcheck.check(bd_sc.self_check() == 0, "self_check after double-free OK", "self_check after double-free CORRUPTED")
|
||||
|
||||
stdlib.free(arena_sc)
|
||||
|
||||
# === 并发多线程测试 (spinlock) ===
|
||||
testcheck.section("并发多线程 (spinlock)")
|
||||
arena_mt: bytes = stdlib.malloc(65536)
|
||||
bd_mt: memhub.MemBuddy | CPtr = memhub.MemBuddy(arena_mt, 65536)
|
||||
|
||||
NUM_THREADS: CInt = 4
|
||||
handles_arr: bytes = stdlib.malloc(8 * 4)
|
||||
handles: CUInt64T | CPtr = CPtr(handles_arr)
|
||||
tid: CUInt32T = 0
|
||||
|
||||
# 创建 4 个线程并发 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, c.Addr(tid))
|
||||
handles[t_idx] = CUInt64T(h)
|
||||
|
||||
# 等待所有线程完成
|
||||
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)
|
||||
|
||||
# 验证分配器状态: 自检通过,所有块已合并
|
||||
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)")
|
||||
|
||||
viperlib.snprintf(buf, 256, "mt: free_count=%lu", bd_mt.free_count())
|
||||
testcheck.info(buf)
|
||||
|
||||
stdlib.free(handles_arr)
|
||||
stdlib.free(arena_mt)
|
||||
|
||||
# === 极端边界测试 ===
|
||||
testcheck.section("极端边界")
|
||||
|
||||
# 1. 分配尺寸恰巧是块边界
|
||||
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 字节)
|
||||
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 字节)
|
||||
over_fit: bytes = bd_ex.alloc(25)
|
||||
testcheck.check(over_fit != None, "over by 1 byte OK", "over by 1 byte FAILED")
|
||||
|
||||
bd_ex.free(exact_fit)
|
||||
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 最大块
|
||||
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 个分解块空闲)
|
||||
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")
|
||||
|
||||
bd_ex.free(exact_max)
|
||||
testcheck.check(bd_ex.free_count() == 6, "max free: coalesce OK", "max free: coalesce FAILED")
|
||||
|
||||
# 再次分配同样大小 — 验证合并后可再次使用
|
||||
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 上限 — 应失败
|
||||
over_max: bytes = bd_ex.alloc(bd_ex.mem_size)
|
||||
testcheck.check(over_max == None, "over max: fails OK", "over max: should fail")
|
||||
|
||||
over_max2: bytes = bd_ex.alloc(max_usable + 1)
|
||||
testcheck.check(over_max2 == None, "max+1: fails OK", "max+1: should fail")
|
||||
|
||||
stdlib.free(arena_ex)
|
||||
|
||||
# 4. Arena 太小 (仅够 free_lists 开销, 264 字节)
|
||||
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")
|
||||
tiny_p: bytes = bd_tiny.alloc(32)
|
||||
testcheck.check(tiny_p == None, "tiny arena: alloc fails OK", "tiny arena: should fail")
|
||||
stdlib.free(arena_tiny)
|
||||
|
||||
# 5. Arena 刚好够一个最小块 (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) 恰好填满
|
||||
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(16)
|
||||
testcheck.check(one_p2 == None, "one block: OOM OK", "one block: should be OOM")
|
||||
|
||||
bd_one.free(one_p)
|
||||
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
|
||||
arena_pow2: bytes = stdlib.malloc(512)
|
||||
bd_pow2: memhub.MemBuddy | CPtr = memhub.MemBuddy(arena_pow2, 512)
|
||||
# 512 - 264 = 248, 二进制分解 = 128+64+32 = 224 (尾 24 字节碎片不入池)
|
||||
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 字节碎片不入池)
|
||||
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 次
|
||||
arena_stress: bytes = stdlib.malloc(4096)
|
||||
bd_stress: memhub.MemBuddy | CPtr = memhub.MemBuddy(arena_stress, 4096)
|
||||
|
||||
s: CInt
|
||||
for s in range(1000):
|
||||
sp: bytes = bd_stress.alloc(64)
|
||||
if sp != None:
|
||||
sp_c: CUInt8T | CPtr = CPtr(sp)
|
||||
sp_c[0] = CUInt8T(s & 0xFF)
|
||||
bd_stress.free(sp)
|
||||
|
||||
testcheck.check(bd_stress.self_check() == 0, "stress: self_check OK", "stress: self_check FAILED")
|
||||
testcheck.check(bd_stress.free_count() == 6, "stress: free_count=6 OK", "stress: leaked")
|
||||
stdlib.free(arena_stress)
|
||||
|
||||
# 8. 分配全部最小块然后全部释放
|
||||
arena_fill: bytes = stdlib.malloc(4096)
|
||||
bd_fill: memhub.MemBuddy | CPtr = memhub.MemBuddy(arena_fill, 4096)
|
||||
|
||||
fill_count: CInt = 0
|
||||
fill_ptrs_arr: bytes = stdlib.malloc(8 * 256)
|
||||
fill_ptrs: CUInt64T | CPtr = CPtr(fill_ptrs_arr)
|
||||
|
||||
fc: CInt
|
||||
for fc in range(256):
|
||||
fp: bytes = bd_fill.alloc(24)
|
||||
if fp == None:
|
||||
break
|
||||
fill_ptrs[fill_count] = t.CUInt64T(fp)
|
||||
fill_count += 1
|
||||
|
||||
viperlib.snprintf(buf, 256, "fill: %d min blocks allocated", fill_count)
|
||||
testcheck.info(buf)
|
||||
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")
|
||||
|
||||
# 全部释放
|
||||
fi: CInt
|
||||
for fi in range(fill_count):
|
||||
fp2: bytes = t.CPtr(fill_ptrs[fi])
|
||||
bd_fill.free(fp2)
|
||||
|
||||
testcheck.check(bd_fill.free_count() == 6, "fill: all freed OK", "fill: leaked after free all")
|
||||
testcheck.check(bd_fill.self_check() == 0, "fill: self_check after free OK", "fill: self_check FAILED")
|
||||
|
||||
stdlib.free(fill_ptrs_arr)
|
||||
stdlib.free(arena_fill)
|
||||
|
||||
stdlib.free(buf)
|
||||
return testcheck.end()
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
|
||||
"name": "BuddyTest",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": ["-filetype=obj", "-relocation-model=pic"]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": ["-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32", "-Wl,--allow-multiple-definition"],
|
||||
"output": "BuddyTest.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,268 @@
|
||||
import t
|
||||
from stdint import *
|
||||
from stdio import printf
|
||||
from stdlib import malloc
|
||||
import testcheck
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 测试 1:@property getter
|
||||
# ============================================================
|
||||
class Rect:
|
||||
width: t.CInt
|
||||
height: t.CInt
|
||||
|
||||
def __new__(self, w: t.CInt, h: t.CInt) -> 'Rect' | t.CPtr:
|
||||
return t.CPtr(malloc(Rect.__sizeof__()))
|
||||
|
||||
def __init__(self, w: t.CInt, h: t.CInt):
|
||||
self.width = w
|
||||
self.height = h
|
||||
|
||||
@property
|
||||
def area(self) -> t.CInt:
|
||||
return self.width * self.height
|
||||
|
||||
@property
|
||||
def is_square(self) -> bool:
|
||||
return self.width == self.height
|
||||
|
||||
|
||||
def test_property_getter():
|
||||
testcheck.section("@property getter")
|
||||
r1: Rect = Rect(3, 4)
|
||||
testcheck.check(r1.area == 12, "area == 12", "area expect 12")
|
||||
testcheck.check(not r1.is_square, "not square", "should not be square")
|
||||
r2: Rect = Rect(5, 5)
|
||||
testcheck.check(r2.area == 25, "square area == 25", "square area expect 25")
|
||||
testcheck.check(r2.is_square, "is_square", "should be square")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 测试 2:@property.setter
|
||||
# ============================================================
|
||||
class Temperature:
|
||||
_celsius: t.CDouble
|
||||
|
||||
def __new__(self, celsius_val: t.CDouble) -> 'Temperature' | t.CPtr:
|
||||
return t.CPtr(malloc(Temperature.__sizeof__()))
|
||||
|
||||
def __init__(self, celsius_val: t.CDouble):
|
||||
self._celsius = celsius_val
|
||||
|
||||
@property
|
||||
def celsius(self) -> t.CDouble:
|
||||
return self._celsius
|
||||
|
||||
@celsius.setter
|
||||
def celsius(self, val: t.CDouble):
|
||||
self._celsius = val
|
||||
|
||||
@property
|
||||
def fahrenheit(self) -> t.CDouble:
|
||||
return self._celsius * 1.8 + 32.0
|
||||
|
||||
|
||||
def test_property_setter():
|
||||
testcheck.section("@property.setter")
|
||||
tmp1: Temperature = Temperature(0.0)
|
||||
testcheck.check(tmp1.fahrenheit > 31.9 and tmp1.fahrenheit < 32.1, "0C == 32F", "0C expect 32F")
|
||||
tmp1.celsius = 100.0
|
||||
testcheck.check(tmp1.fahrenheit > 211.9 and tmp1.fahrenheit < 212.1, "100C == 212F", "100C expect 212F")
|
||||
testcheck.check(tmp1.celsius > 99.9 and tmp1.celsius < 100.1, "celsius == 100", "celsius expect 100")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 测试 3:@property.getter(重新定义 getter)
|
||||
# ============================================================
|
||||
class Counter:
|
||||
_count: t.CInt
|
||||
|
||||
def __new__(self) -> 'Counter' | t.CPtr:
|
||||
return t.CPtr(malloc(Counter.__sizeof__()))
|
||||
|
||||
def __init__(self):
|
||||
self._count = 0
|
||||
|
||||
@property
|
||||
def value(self) -> t.CInt:
|
||||
return self._count
|
||||
|
||||
@value.setter
|
||||
def value(self, v: t.CInt):
|
||||
self._count = v
|
||||
|
||||
|
||||
def test_property_getter_redef():
|
||||
testcheck.section("@property.getter redef")
|
||||
cnt: Counter = Counter()
|
||||
testcheck.check(cnt.value == 0, "init == 0", "init expect 0")
|
||||
cnt.value = 42
|
||||
testcheck.check(cnt.value == 42, "set == 42", "set expect 42")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 测试 4:@property.deleter
|
||||
# ============================================================
|
||||
class Config:
|
||||
_value: t.CInt
|
||||
_deleted: t.CInt
|
||||
|
||||
def __new__(self, v: t.CInt) -> 'Config' | t.CPtr:
|
||||
return t.CPtr(malloc(Config.__sizeof__()))
|
||||
|
||||
def __init__(self, v: t.CInt):
|
||||
self._value = v
|
||||
self._deleted = 0
|
||||
|
||||
@property
|
||||
def value(self) -> t.CInt:
|
||||
return self._value
|
||||
|
||||
@value.setter
|
||||
def value(self, v: t.CInt):
|
||||
self._value = v
|
||||
|
||||
@value.deleter
|
||||
def value(self):
|
||||
self._value = 0
|
||||
self._deleted = 1
|
||||
|
||||
def is_deleted(self) -> bool:
|
||||
return self._deleted != 0
|
||||
|
||||
|
||||
def test_property_deleter():
|
||||
testcheck.section("@property.deleter")
|
||||
cfg: Config = Config(99)
|
||||
testcheck.check(cfg.value == 99, "init == 99", "init expect 99")
|
||||
testcheck.check(not cfg.is_deleted(), "not deleted", "should not be deleted")
|
||||
del cfg.value
|
||||
testcheck.check(cfg.value == 0, "after del == 0", "after del expect 0")
|
||||
testcheck.check(cfg.is_deleted(), "is_deleted", "should be deleted")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 测试 5:@staticmethod
|
||||
# ============================================================
|
||||
class MathUtils:
|
||||
@staticmethod
|
||||
def add(a: t.CInt, b: t.CInt) -> t.CInt:
|
||||
return a + b
|
||||
|
||||
@staticmethod
|
||||
def max_val(a: t.CInt, b: t.CInt) -> t.CInt:
|
||||
return a if a > b else b
|
||||
|
||||
|
||||
def test_staticmethod():
|
||||
testcheck.section("@staticmethod")
|
||||
# 通过类名调用
|
||||
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
|
||||
# ============================================================
|
||||
class Point:
|
||||
x: t.CDouble
|
||||
y: t.CDouble
|
||||
|
||||
def __new__(self, x: t.CDouble, y: t.CDouble) -> 'Point' | t.CPtr:
|
||||
return t.CPtr(malloc(Point.__sizeof__()))
|
||||
|
||||
def __init__(self, x: t.CDouble, y: t.CDouble):
|
||||
self.x = x
|
||||
self.y = y
|
||||
|
||||
@classmethod
|
||||
def origin(cls: Point) -> Point:
|
||||
return Point(0.0, 0.0)
|
||||
|
||||
@classmethod
|
||||
def from_int(cls: Point, x: t.CInt, y: t.CInt) -> Point:
|
||||
return Point(x * 1.0, y * 1.0)
|
||||
|
||||
def dist_sq(self) -> t.CDouble:
|
||||
return self.x * self.x + self.y * self.y
|
||||
|
||||
|
||||
def test_classmethod():
|
||||
testcheck.section("@classmethod")
|
||||
# 通过类名调用
|
||||
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")
|
||||
testcheck.check(p1.dist_sq() < 0.01, "origin.dist ~= 0", "origin.dist expect ~0")
|
||||
|
||||
p2: Point = Point.from_int(3, 4)
|
||||
testcheck.check(p2.x > 2.99 and p2.x < 3.01, "from_int(3,4).x ~= 3", "from_int(3,4).x expect ~3")
|
||||
testcheck.check(p2.y > 3.99 and p2.y < 4.01, "from_int(3,4).y ~= 4", "from_int(3,4).y expect ~4")
|
||||
testcheck.check(p2.dist_sq() > 24.99 and p2.dist_sq() < 25.01, "dist_sq ~= 25", "dist_sq expect ~25")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 测试 7:综合测试 — @property + @staticmethod + @classmethod
|
||||
# ============================================================
|
||||
class Circle:
|
||||
_radius: t.CDouble
|
||||
|
||||
def __new__(self, r: t.CDouble) -> 'Circle' | t.CPtr:
|
||||
return t.CPtr(malloc(Circle.__sizeof__()))
|
||||
|
||||
def __init__(self, r: t.CDouble):
|
||||
self._radius = r
|
||||
|
||||
@property
|
||||
def radius(self) -> t.CDouble:
|
||||
return self._radius
|
||||
|
||||
@radius.setter
|
||||
def radius(self, val: t.CDouble):
|
||||
self._radius = val
|
||||
|
||||
@property
|
||||
def area(self) -> t.CDouble:
|
||||
return 3.14159265 * self._radius * self._radius
|
||||
|
||||
@staticmethod
|
||||
def is_unit(r: t.CDouble) -> bool:
|
||||
return r > 0.99 and r < 1.01
|
||||
|
||||
@classmethod
|
||||
def unit(cls: Circle) -> Circle:
|
||||
return Circle(1.0)
|
||||
|
||||
|
||||
def test_combined():
|
||||
testcheck.section("Combined @property + @staticmethod + @classmethod")
|
||||
# 先测试直接构造
|
||||
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
|
||||
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")
|
||||
testcheck.check(not Circle.is_unit(2.0), "not is_unit(2.0)", "is_unit(2.0) should be false")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 主函数
|
||||
# ============================================================
|
||||
def main() -> t.CInt | t.CExport:
|
||||
testcheck.begin("Builtin Decorator Test")
|
||||
|
||||
test_property_getter()
|
||||
test_property_setter()
|
||||
test_property_getter_redef()
|
||||
test_property_deleter()
|
||||
test_staticmethod()
|
||||
test_classmethod()
|
||||
test_combined()
|
||||
|
||||
return testcheck.end()
|
||||
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"name": "BuiltinDecoratorTest",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": [
|
||||
"-filetype=obj",
|
||||
"-relocation-model=pic"
|
||||
]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": [
|
||||
"-Wl,--allow-multiple-definition",
|
||||
"-lmsvcrt",
|
||||
"-lucrt",
|
||||
"-lpthread",
|
||||
"-lmingwex",
|
||||
"-lkernel32",
|
||||
"-luser32"
|
||||
],
|
||||
"output": "BuiltinDecoratorTest.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,777 @@
|
||||
import t, c
|
||||
|
||||
|
||||
# ============================================================
|
||||
# PyObject — 所有 Python 对象的基类
|
||||
# ============================================================
|
||||
class PyObject:
|
||||
ob_refcnt: t.CLong
|
||||
ob_type: t.CPtr
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 引用计数
|
||||
# ============================================================
|
||||
extern def Py_INCREF(op: PyObject | t.CPtr)
|
||||
extern def Py_DECREF(op: PyObject | t.CPtr)
|
||||
extern def Py_XINCREF(op: PyObject | t.CPtr)
|
||||
extern def Py_XDECREF(op: PyObject | t.CPtr)
|
||||
extern def Py_DecRef(op: PyObject | t.CPtr)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 解释器初始化/终止
|
||||
# ============================================================
|
||||
extern def Py_Initialize()
|
||||
extern def Py_Finalize()
|
||||
extern def Py_InitializeEx(initsigs: t.CInt)
|
||||
extern def Py_FinalizeEx() -> t.CInt
|
||||
extern def Py_IsInitialized() -> t.CInt
|
||||
|
||||
|
||||
# ============================================================
|
||||
# PyConfig
|
||||
# ============================================================
|
||||
class PySTATUS:
|
||||
func: t.CConst | str
|
||||
err_msg: t.CConst | str
|
||||
exitcode: t.CInt
|
||||
|
||||
class PyPreConfig:
|
||||
_config_version: t.CInt
|
||||
_config_init: t.CInt
|
||||
parse_argv: t.CInt
|
||||
isolated: t.CInt
|
||||
use_environment: t.CInt
|
||||
utf8_mode: t.CInt
|
||||
coerce_c_locale: t.CInt
|
||||
C_locale_warnings: t.CInt
|
||||
allocator: t.CInt
|
||||
dev_mode: t.CInt
|
||||
|
||||
class PyWideStringList:
|
||||
length: t.CSizeT
|
||||
items: t.CPtr
|
||||
|
||||
class PyConfig:
|
||||
_config_version: t.CInt
|
||||
_config_init: t.CInt
|
||||
isolated: t.CInt
|
||||
use_environment: t.CInt
|
||||
dev_mode: t.CInt
|
||||
install_signal_handlers: t.CInt
|
||||
use_hash_seed: t.CInt
|
||||
hash_seed: t.CUnsignedLong
|
||||
faulthandler: t.CInt
|
||||
tracemalloc: t.CInt
|
||||
import_time: t.CInt
|
||||
show_ref_count: t.CInt
|
||||
dump_refs: t.CInt
|
||||
dump_refs_file: t.CConst | str
|
||||
malloc_stats: t.CInt
|
||||
filesystem_errors: t.CInt
|
||||
pycache_prefix: t.CConst | str
|
||||
parse_argv: t.CInt
|
||||
argv: PyWideStringList
|
||||
program_name: t.CConst | str
|
||||
xoptions: PyWideStringList
|
||||
warnoptions: PyWideStringList
|
||||
site_import: t.CInt
|
||||
bytes_warning: t.CInt
|
||||
warn_default_encoding: t.CInt
|
||||
inspect: t.CInt
|
||||
interactive: t.CInt
|
||||
optimization_level: t.CInt
|
||||
parser_debug: t.CInt
|
||||
verbose: t.CInt
|
||||
quiet: t.CInt
|
||||
home: t.CConst | str
|
||||
pythonpath_env: t.CConst | str
|
||||
module_search_paths: PyWideStringList
|
||||
module_search_paths_set: t.CInt
|
||||
executable: t.CConst | str
|
||||
base_executable: t.CConst | str
|
||||
prefix: t.CConst | str
|
||||
base_prefix: t.CConst | str
|
||||
exec_prefix: t.CConst | str
|
||||
base_exec_prefix: t.CConst | str
|
||||
platlibdir: t.CConst | str
|
||||
stdio_filename: t.CConst | str
|
||||
|
||||
extern def PyConfig_InitPythonConfig(config: PyConfig | t.CPtr)
|
||||
extern def PyConfig_InitIsolatedConfig(config: PyConfig | t.CPtr)
|
||||
extern def PyConfig_Clear(config: PyConfig | t.CPtr)
|
||||
extern def PyConfig_Read(config: PyConfig | t.CPtr) -> PySTATUS
|
||||
extern def Py_InitializeFromConfig(config: PyConfig | t.CPtr) -> PySTATUS
|
||||
extern def Py_DecodeLocale(s: t.CConst | str) -> str
|
||||
extern def PyStatus_Exception(status: PySTATUS) -> t.CInt
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 整数操作 (PyLong)
|
||||
# ============================================================
|
||||
extern def PyLong_FromLong(v: t.CInt) -> PyObject | t.CPtr
|
||||
extern def PyLong_FromUnsignedLong(v: t.CUnsignedLong) -> PyObject | t.CPtr
|
||||
extern def PyLong_FromLongLong(v: t.CLong) -> PyObject | t.CPtr
|
||||
extern def PyLong_FromUnsignedLongLong(v: t.CUnsignedLong) -> PyObject | t.CPtr
|
||||
extern def PyLong_FromSsize_t(v: t.CPtrDiffT) -> PyObject | t.CPtr
|
||||
extern def PyLong_FromSize_t(v: t.CSizeT) -> PyObject | t.CPtr
|
||||
extern def PyLong_FromDouble(v: t.CDouble) -> PyObject | t.CPtr
|
||||
extern def PyLong_AsLong(obj: PyObject | t.CPtr) -> t.CInt
|
||||
extern def PyLong_AsUnsignedLong(obj: PyObject | t.CPtr) -> t.CUnsignedLong
|
||||
extern def PyLong_AsLongLong(obj: PyObject | t.CPtr) -> t.CLong
|
||||
extern def PyLong_AsUnsignedLongLong(obj: PyObject | t.CPtr) -> t.CUnsignedLong
|
||||
extern def PyLong_AsDouble(obj: PyObject | t.CPtr) -> t.CDouble
|
||||
extern def PyLong_AsSsize_t(obj: PyObject | t.CPtr) -> t.CPtrDiffT
|
||||
extern def PyLong_AsSize_t(obj: PyObject | t.CPtr) -> t.CSizeT
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 浮点数操作 (PyFloat)
|
||||
# ============================================================
|
||||
extern def PyFloat_FromDouble(v: t.CDouble) -> PyObject | t.CPtr
|
||||
extern def PyFloat_AsDouble(obj: PyObject | t.CPtr) -> t.CDouble
|
||||
extern def PyFloat_FromString(s: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 字符串操作 (PyUnicode / PyBytes)
|
||||
# ============================================================
|
||||
extern def PyUnicode_FromString(u: t.CConst | str) -> PyObject | t.CPtr
|
||||
extern def PyUnicode_FromStringAndSize(u: t.CConst | str, size: t.CSizeT) -> PyObject | t.CPtr
|
||||
extern def PyUnicode_FromFormat(fmt: t.CConst | str) -> PyObject | t.CPtr
|
||||
extern def PyUnicode_AsUTF8(obj: PyObject | t.CPtr) -> str
|
||||
extern def PyUnicode_AsUTF8AndSize(obj: PyObject | t.CPtr, size: t.CPtrDiffT | t.CPtr) -> str
|
||||
extern def PyUnicode_AsWideChar(obj: PyObject | t.CPtr, wbuf: t.CPtr, bufsize: t.CSizeT) -> t.CSizeT
|
||||
extern def PyUnicode_GetLength(obj: PyObject | t.CPtr) -> t.CPtrDiffT
|
||||
extern def PyUnicode_ReadChar(obj: PyObject | t.CPtr, idx: t.CSizeT) -> t.CUInt32T
|
||||
extern def PyUnicode_WriteChar(obj: PyObject | t.CPtr, idx: t.CSizeT, ch: t.CUInt32T) -> t.CInt
|
||||
extern def PyUnicode_Compare(l: PyObject | t.CPtr, r: PyObject | t.CPtr) -> t.CInt
|
||||
extern def PyUnicode_Concat(l: PyObject | t.CPtr, r: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyUnicode_Contains(container: PyObject | t.CPtr, element: PyObject | t.CPtr) -> t.CInt
|
||||
extern def PyUnicode_Format(fmt: PyObject | t.CPtr, args: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyUnicode_InternInPlace(s: PyObject | t.CPtr | t.CPtr): pass
|
||||
extern def PyUnicode_InternFromString(u: t.CConst | str) -> PyObject | t.CPtr
|
||||
|
||||
extern def PyBytes_FromString(v: t.CConst | str) -> PyObject | t.CPtr
|
||||
extern def PyBytes_FromStringAndSize(v: t.CConst | str, size: t.CSizeT) -> PyObject | t.CPtr
|
||||
extern def PyBytes_AsString(obj: PyObject | t.CPtr) -> str
|
||||
extern def PyBytes_Size(obj: PyObject | t.CPtr) -> t.CSizeT
|
||||
extern def PyBytes_FromObject(o: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyBytes_FromFormat(fmt: t.CConst | str) -> PyObject | t.CPtr
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 布尔 / None
|
||||
# ============================================================
|
||||
extern def PyBool_FromLong(v: t.CLong) -> PyObject | t.CPtr
|
||||
|
||||
Py_True: PyObject | t.CPtr | t.State
|
||||
Py_False: PyObject | t.CPtr | t.State
|
||||
Py_None: PyObject | t.CPtr | t.State
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 列表操作 (PyList)
|
||||
# ============================================================
|
||||
extern def PyList_New(len: t.CSizeT) -> PyObject | t.CPtr
|
||||
extern def PyList_Size(lst: PyObject | t.CPtr) -> t.CSizeT
|
||||
extern def PyList_GetItem(lst: PyObject | t.CPtr, idx: t.CSizeT) -> PyObject | t.CPtr
|
||||
extern def PyList_SetItem(lst: PyObject | t.CPtr, idx: t.CSizeT, item: PyObject | t.CPtr) -> t.CInt
|
||||
extern def PyList_Insert(lst: PyObject | t.CPtr, idx: t.CSizeT, item: PyObject | t.CPtr) -> t.CInt
|
||||
extern def PyList_Append(lst: PyObject | t.CPtr, item: PyObject | t.CPtr) -> t.CInt
|
||||
extern def PyList_GetSlice(lst: PyObject | t.CPtr, lo: t.CSizeT, hi: t.CSizeT) -> PyObject | t.CPtr
|
||||
extern def PyList_SetSlice(lst: PyObject | t.CPtr, lo: t.CSizeT, hi: t.CSizeT, items: PyObject | t.CPtr) -> t.CInt
|
||||
extern def PyList_Sort(lst: PyObject | t.CPtr) -> t.CInt
|
||||
extern def PyList_Reverse(lst: PyObject | t.CPtr) -> t.CInt
|
||||
extern def PyList_AsTuple(lst: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 元组操作 (PyTuple)
|
||||
# ============================================================
|
||||
extern def PyTuple_New(len: t.CSizeT) -> PyObject | t.CPtr
|
||||
extern def PyTuple_Size(tup: PyObject | t.CPtr) -> t.CSizeT
|
||||
extern def PyTuple_GetItem(tup: PyObject | t.CPtr, idx: t.CSizeT) -> PyObject | t.CPtr
|
||||
extern def PyTuple_SetItem(tup: PyObject | t.CPtr, idx: t.CSizeT, item: PyObject | t.CPtr) -> t.CInt
|
||||
extern def PyTuple_GetSlice(tup: PyObject | t.CPtr, lo: t.CSizeT, hi: t.CSizeT) -> PyObject | t.CPtr
|
||||
extern def PyTuple_Pack(n: t.CSizeT) -> PyObject | t.CPtr
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 字典操作 (PyDict)
|
||||
# ============================================================
|
||||
extern def PyDict_New() -> PyObject | t.CPtr
|
||||
extern def PyDict_GetItem(d: PyObject | t.CPtr, key: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyDict_GetItemString(d: PyObject | t.CPtr, key: t.CConst | str) -> PyObject | t.CPtr
|
||||
extern def PyDict_SetItem(d: PyObject | t.CPtr, key: PyObject | t.CPtr, val: PyObject | t.CPtr) -> t.CInt
|
||||
extern def PyDict_SetItemString(d: PyObject | t.CPtr, key: t.CConst | str, val: PyObject | t.CPtr) -> t.CInt
|
||||
extern def PyDict_DelItem(d: PyObject | t.CPtr, key: PyObject | t.CPtr) -> t.CInt
|
||||
extern def PyDict_DelItemString(d: PyObject | t.CPtr, key: t.CConst | str) -> t.CInt
|
||||
extern def PyDict_Size(d: PyObject | t.CPtr) -> t.CSizeT
|
||||
extern def PyDict_Keys(d: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyDict_Values(d: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyDict_Items(d: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyDict_Copy(d: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyDict_Clear(d: PyObject | t.CPtr): pass
|
||||
extern def PyDict_Contains(d: PyObject | t.CPtr, key: PyObject | t.CPtr) -> t.CInt
|
||||
extern def PyDict_Next(d: PyObject | t.CPtr, pos: t.CPtrDiffT | t.CPtr, key: PyObject | t.CPtr | t.CPtr, val: PyObject | t.CPtr | t.CPtr) -> t.CInt
|
||||
extern def PyDict_Merge(d: PyObject | t.CPtr, other: PyObject | t.CPtr, override: t.CInt) -> t.CInt
|
||||
extern def PyDict_Update(d: PyObject | t.CPtr, other: PyObject | t.CPtr) -> t.CInt
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 对象通用操作
|
||||
# ============================================================
|
||||
extern def PyObject_Str(obj: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyObject_Repr(obj: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyObject_Type(obj: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyObject_IsInstance(obj: PyObject | t.CPtr, cls: PyObject | t.CPtr) -> t.CInt
|
||||
extern def PyObject_IsSubclass(obj: PyObject | t.CPtr, cls: PyObject | t.CPtr) -> t.CInt
|
||||
extern def PyObject_HasAttr(obj: PyObject | t.CPtr, name: PyObject | t.CPtr) -> t.CInt
|
||||
extern def PyObject_HasAttrString(obj: PyObject | t.CPtr, name: t.CConst | str) -> t.CInt
|
||||
extern def PyObject_GetAttr(obj: PyObject | t.CPtr, name: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyObject_GetAttrString(obj: PyObject | t.CPtr, name: t.CConst | str) -> PyObject | t.CPtr
|
||||
extern def PyObject_SetAttr(obj: PyObject | t.CPtr, name: PyObject | t.CPtr, val: PyObject | t.CPtr) -> t.CInt
|
||||
extern def PyObject_SetAttrString(obj: PyObject | t.CPtr, name: t.CConst | str, val: PyObject | t.CPtr) -> t.CInt
|
||||
extern def PyObject_DelAttr(obj: PyObject | t.CPtr, name: PyObject | t.CPtr) -> t.CInt
|
||||
extern def PyObject_DelAttrString(obj: PyObject | t.CPtr, name: t.CConst | str) -> t.CInt
|
||||
extern def PyObject_Call(callable: PyObject | t.CPtr, args: PyObject | t.CPtr, kwargs: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyObject_CallObject(callable: PyObject | t.CPtr, args: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyObject_CallNoArgs(callable: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyObject_CallOneArg(callable: PyObject | t.CPtr, arg: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyObject_IsTrue(obj: PyObject | t.CPtr) -> t.CInt
|
||||
extern def PyObject_Not(obj: PyObject | t.CPtr) -> t.CInt
|
||||
extern def PyObject_RichCompare(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr, opid: t.CInt) -> PyObject | t.CPtr
|
||||
extern def PyObject_RichCompareBool(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr, opid: t.CInt) -> t.CInt
|
||||
extern def PyObject_Hash(obj: PyObject | t.CPtr) -> t.CLong
|
||||
extern def PyObject_Length(obj: PyObject | t.CPtr) -> t.CSizeT
|
||||
extern def PyObject_GetItem(obj: PyObject | t.CPtr, key: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyObject_SetItem(obj: PyObject | t.CPtr, key: PyObject | t.CPtr, val: PyObject | t.CPtr) -> t.CInt
|
||||
extern def PyObject_DelItem(obj: PyObject | t.CPtr, key: PyObject | t.CPtr) -> t.CInt
|
||||
extern def PyObject_Dir(obj: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyObject_GetIter(obj: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyIter_Next(obj: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 比较常量
|
||||
# ============================================================
|
||||
Py_LT: t.CInt | t.State
|
||||
Py_LE: t.CInt | t.State
|
||||
Py_EQ: t.CInt | t.State
|
||||
Py_NE: t.CInt | t.State
|
||||
Py_GT: t.CInt | t.State
|
||||
Py_GE: t.CInt | t.State
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 模块操作
|
||||
# ============================================================
|
||||
extern def PyImport_ImportModule(name: t.CConst | str) -> PyObject | t.CPtr
|
||||
extern def PyImport_Import(name: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyImport_ImportModuleLevelObject(name: PyObject | t.CPtr, globs: PyObject | t.CPtr, locs: PyObject | t.CPtr, fromlist: PyObject | t.CPtr, level: t.CInt) -> PyObject | t.CPtr
|
||||
extern def PyImport_ReloadModule(mod: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyImport_AddModule(name: t.CConst | str) -> PyObject | t.CPtr
|
||||
extern def PyImport_GetModuleDict() -> PyObject | t.CPtr
|
||||
extern def PyImport_ImportModuleEx(name: t.CConst | str, globs: PyObject | t.CPtr, locs: PyObject | t.CPtr, fromlist: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 模块创建
|
||||
# ============================================================
|
||||
class PyMethodDef:
|
||||
ml_name: t.CConst | str
|
||||
ml_meth: t.CPtr
|
||||
ml_flags: t.CInt
|
||||
ml_doc: t.CConst | str
|
||||
|
||||
class PyModuleDef_Base:
|
||||
ob_base: PyObject
|
||||
m_init: t.CPtr
|
||||
m_index: t.CSizeT
|
||||
m_copy: PyObject | t.CPtr
|
||||
|
||||
class PyModuleDef:
|
||||
m_base: PyModuleDef_Base
|
||||
m_name: t.CConst | str
|
||||
m_doc: t.CConst | str
|
||||
m_size: t.CPtrDiffT
|
||||
m_methods: PyMethodDef | t.CPtr
|
||||
m_slots: t.CPtr
|
||||
m_traverse: t.CPtr
|
||||
m_clear: t.CPtr
|
||||
m_free: t.CPtr
|
||||
|
||||
extern def PyModule_Create(mod: PyModuleDef | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyModule_Create2(mod: PyModuleDef | t.CPtr, ver: t.CInt) -> PyObject | t.CPtr
|
||||
extern def PyModule_GetName(mod: PyObject | t.CPtr) -> str
|
||||
extern def PyModule_GetDict(mod: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyModule_GetFilenameObject(mod: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyModule_AddObject(mod: PyObject | t.CPtr, name: t.CConst | str, val: PyObject | t.CPtr) -> t.CInt
|
||||
extern def PyModule_AddObjectRef(mod: PyObject | t.CPtr, name: t.CConst | str, val: PyObject | t.CPtr) -> t.CInt
|
||||
extern def PyModule_AddIntConstant(mod: PyObject | t.CPtr, name: t.CConst | str, val: t.CLong) -> t.CInt
|
||||
extern def PyModule_AddStringConstant(mod: PyObject | t.CPtr, name: t.CConst | str, val: t.CConst | str) -> t.CInt
|
||||
|
||||
|
||||
# ============================================================
|
||||
# GIL 管理
|
||||
# ============================================================
|
||||
extern def PyGILState_Ensure() -> t.CInt
|
||||
extern def PyGILState_Release(state: t.CInt): pass
|
||||
extern def PyEval_SaveThread() -> t.CPtr
|
||||
extern def PyEval_RestoreThread(tstate: t.CPtr): pass
|
||||
extern def PyEval_AcquireThread(tstate: t.CPtr): pass
|
||||
extern def PyEval_ReleaseThread(tstate: t.CPtr): pass
|
||||
extern def PyEval_AcquireLock(): pass
|
||||
extern def PyEval_ReleaseLock(): pass
|
||||
extern def PyEval_ThreadsInitialized() -> t.CInt
|
||||
extern def PyEval_InitThreads(): pass
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 错误处理
|
||||
# ============================================================
|
||||
extern def PyErr_Occurred() -> PyObject | t.CPtr
|
||||
extern def PyErr_Clear(): pass
|
||||
extern def PyErr_Fetch(tp: PyObject | t.CPtr | t.CPtr, val: PyObject | t.CPtr | t.CPtr, tb: PyObject | t.CPtr | t.CPtr): pass
|
||||
extern def PyErr_Restore(tp: PyObject | t.CPtr, val: PyObject | t.CPtr, tb: PyObject | t.CPtr): pass
|
||||
extern def PyErr_NormalizeException(tp: PyObject | t.CPtr | t.CPtr, val: PyObject | t.CPtr | t.CPtr, tb: PyObject | t.CPtr | t.CPtr): pass
|
||||
extern def PyErr_SetString(tp: PyObject | t.CPtr, msg: t.CConst | str): pass
|
||||
extern def PyErr_SetObject(tp: PyObject | t.CPtr, val: PyObject | t.CPtr): pass
|
||||
extern def PyErr_BadArgument() -> t.CPtr | t.State: pass
|
||||
extern def PyErr_NoMemory() -> t.CPtr | t.State: pass
|
||||
extern def PyErr_Print(): pass
|
||||
extern def PyErr_ExceptionMatches(exc: PyObject | t.CPtr) -> t.CInt | t.State: pass
|
||||
extern def PyErr_GivenExceptionMatches(given: PyObject | t.CPtr, exc: PyObject | t.CPtr) -> t.CInt | t.State: pass
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 内置异常类型
|
||||
# ============================================================
|
||||
PyExc_BaseException: PyObject | t.CPtr | t.State
|
||||
PyExc_Exception: PyObject | t.CPtr | t.State
|
||||
PyExc_TypeError: PyObject | t.CPtr | t.State
|
||||
PyExc_ValueError: PyObject | t.CPtr | t.State
|
||||
PyExc_RuntimeError: PyObject | t.CPtr | t.State
|
||||
PyExc_KeyError: PyObject | t.CPtr | t.State
|
||||
PyExc_IndexError: PyObject | t.CPtr | t.State
|
||||
PyExc_AttributeError: PyObject | t.CPtr | t.State
|
||||
PyExc_ImportError: PyObject | t.CPtr | t.State
|
||||
PyExc_OSError: PyObject | t.CPtr | t.State
|
||||
PyExc_IOError: PyObject | t.CPtr | t.State
|
||||
PyExc_ZeroDivisionError: PyObject | t.CPtr | t.State
|
||||
PyExc_OverflowError: PyObject | t.CPtr | t.State
|
||||
PyExc_MemoryError: PyObject | t.CPtr | t.State
|
||||
PyExc_NameError: PyObject | t.CPtr | t.State
|
||||
PyExc_StopIteration: PyObject | t.CPtr | t.State
|
||||
PyExc_NotImplementedError: PyObject | t.CPtr | t.State
|
||||
PyExc_SyntaxError: PyObject | t.CPtr | t.State
|
||||
PyExc_FileNotFoundError: PyObject | t.CPtr | t.State
|
||||
PyExc_PermissionError: PyObject | t.CPtr | t.State
|
||||
PyExc_IsADirectoryError: PyObject | t.CPtr | t.State
|
||||
PyExc_NotADirectoryError: PyObject | t.CPtr | t.State
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 内置函数
|
||||
# ============================================================
|
||||
extern def Py_BuildValue(fmt: t.CConst | str) -> PyObject | t.CPtr
|
||||
extern def Py_VaBuildValue(fmt: t.CConst | str, va: t.CPtr) -> PyObject | t.CPtr
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 类型检查
|
||||
# ============================================================
|
||||
extern def PyLong_Check(obj: PyObject | t.CPtr) -> t.CInt
|
||||
extern def PyFloat_Check(obj: PyObject | t.CPtr) -> t.CInt
|
||||
extern def PyUnicode_Check(obj: PyObject | t.CPtr) -> t.CInt
|
||||
extern def PyBytes_Check(obj: PyObject | t.CPtr) -> t.CInt
|
||||
extern def PyList_Check(obj: PyObject | t.CPtr) -> t.CInt
|
||||
extern def PyTuple_Check(obj: PyObject | t.CPtr) -> t.CInt
|
||||
extern def PyDict_Check(obj: PyObject | t.CPtr) -> t.CInt
|
||||
extern def PyBool_Check(obj: PyObject | t.CPtr) -> t.CInt
|
||||
extern def PyNone_Check(obj: PyObject | t.CPtr) -> t.CInt
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 内存管理
|
||||
# ============================================================
|
||||
extern def PyMem_Malloc(size: t.CSizeT) -> t.CPtr
|
||||
extern def PyMem_Realloc(ptr: t.CPtr, size: t.CSizeT) -> t.CPtr
|
||||
extern def PyMem_Free(ptr: t.CPtr)
|
||||
extern def PyMem_Calloc(nelem: t.CSizeT, elsize: t.CSizeT) -> t.CPtr
|
||||
extern def PyObject_Malloc(size: t.CSizeT) -> t.CPtr
|
||||
extern def PyObject_Realloc(ptr: t.CPtr, size: t.CSizeT) -> t.CPtr
|
||||
extern def PyObject_Free(ptr: t.CPtr)
|
||||
extern def PyObject_Calloc(nelem: t.CSizeT, elsize: t.CSizeT) -> t.CPtr
|
||||
extern def PyObject_Init(obj: PyObject | t.CPtr, tp: t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyObject_InitVar(obj: PyObject | t.CPtr, tp: t.CPtr, size: t.CSizeT) -> PyObject | t.CPtr
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 文件操作
|
||||
# ============================================================
|
||||
extern def PyFile_FromString(filename: t.CConst | str, mode: t.CConst | str) -> PyObject | t.CPtr
|
||||
extern def PyFile_AsFile(file: PyObject | t.CPtr) -> t.CPtr
|
||||
extern def PyFile_WriteObject(obj: PyObject | t.CPtr, file: PyObject | t.CPtr, flags: t.CInt) -> t.CInt
|
||||
extern def PyFile_WriteString(s: t.CConst | str, file: PyObject | t.CPtr) -> t.CInt
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 编译/执行
|
||||
# ============================================================
|
||||
extern def Py_CompileString(s: t.CConst | str, filename: t.CConst | str, start: t.CInt) -> PyObject | t.CPtr
|
||||
extern def PyEval_EvalCode(code: PyObject | t.CPtr, globs: PyObject | t.CPtr, locs: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyEval_EvalCodeEx(code: PyObject | t.CPtr, globs: PyObject | t.CPtr, locs: PyObject | t.CPtr, args: PyObject | t.CPtr | t.CPtr, argc: t.CInt, kws: PyObject | t.CPtr | t.CPtr, kwc: t.CInt, defs: PyObject | t.CPtr | t.CPtr, defc: t.CInt, kwdefs: PyObject | t.CPtr, closure: PyObject | t.CPtr) -> PyObject | t.CPtr: pass
|
||||
extern def PyEval_EvalFrame(frame: t.CPtr) -> PyObject | t.CPtr: pass
|
||||
extern def PyEval_CallObject(callable: PyObject | t.CPtr, args: PyObject | t.CPtr) -> PyObject | t.CPtr: pass
|
||||
extern def PyEval_CallFunction(callable: PyObject | t.CPtr, fmt: t.CConst | str) -> PyObject | t.CPtr: pass
|
||||
extern def PyEval_CallMethod(obj: PyObject | t.CPtr, method: t.CConst | str, fmt: t.CConst | str) -> PyObject | t.CPtr: pass
|
||||
|
||||
|
||||
# ============================================================
|
||||
# PyRun
|
||||
# ============================================================
|
||||
extern def PyRun_SimpleString(cmd: t.CConst | str) -> t.CInt
|
||||
extern def PyRun_SimpleFile(fp: t.CPtr, filename: t.CConst | str) -> t.CInt
|
||||
extern def PyRun_AnyFile(fp: t.CPtr, filename: t.CConst | str) -> t.CInt
|
||||
extern def PyRun_String(s: t.CConst | str, start: t.CInt, globs: PyObject | t.CPtr, locs: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyRun_File(fp: t.CPtr, filename: t.CConst | str, start: t.CInt, globs: PyObject | t.CPtr, locs: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
|
||||
Py_single_input: t.CInt | t.State
|
||||
Py_file_input: t.CInt | t.State
|
||||
Py_eval_input: t.CInt | t.State
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Capsule
|
||||
# ============================================================
|
||||
extern def PyCapsule_New(ptr: t.CPtr, name: t.CConst | str, dtor: t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyCapsule_GetPointer(cap: PyObject | t.CPtr, name: t.CConst | str) -> t.CPtr
|
||||
extern def PyCapsule_GetName(cap: PyObject | t.CPtr) -> str
|
||||
extern def PyCapsule_IsValid(cap: PyObject | t.CPtr, name: t.CConst | str) -> t.CInt
|
||||
extern def PyCapsule_SetPointer(cap: PyObject | t.CPtr, ptr: t.CPtr) -> t.CInt
|
||||
extern def PyCapsule_SetName(cap: PyObject | t.CPtr, name: t.CConst | str) -> t.CInt
|
||||
extern def PyCapsule_SetDestructor(cap: PyObject | t.CPtr, dtor: t.CPtr) -> t.CInt
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 序列操作
|
||||
# ============================================================
|
||||
extern def PySequence_Check(obj: PyObject | t.CPtr) -> t.CInt
|
||||
extern def PySequence_Size(obj: PyObject | t.CPtr) -> t.CSizeT
|
||||
extern def PySequence_Length(obj: PyObject | t.CPtr) -> t.CSizeT
|
||||
extern def PySequence_Concat(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PySequence_Repeat(obj: PyObject | t.CPtr, count: t.CSizeT) -> PyObject | t.CPtr
|
||||
extern def PySequence_GetItem(obj: PyObject | t.CPtr, idx: t.CSizeT) -> PyObject | t.CPtr
|
||||
extern def PySequence_SetItem(obj: PyObject | t.CPtr, idx: t.CSizeT, val: PyObject | t.CPtr) -> t.CInt
|
||||
extern def PySequence_DelItem(obj: PyObject | t.CPtr, idx: t.CSizeT) -> t.CInt
|
||||
extern def PySequence_GetSlice(obj: PyObject | t.CPtr, start: t.CSizeT, end: t.CSizeT) -> PyObject | t.CPtr
|
||||
extern def PySequence_SetSlice(obj: PyObject | t.CPtr, start: t.CSizeT, end: t.CSizeT, val: PyObject | t.CPtr) -> t.CInt
|
||||
extern def PySequence_DelSlice(obj: PyObject | t.CPtr, start: t.CSizeT, end: t.CSizeT) -> t.CInt
|
||||
extern def PySequence_Contains(obj: PyObject | t.CPtr, val: PyObject | t.CPtr) -> t.CInt
|
||||
extern def PySequence_Index(obj: PyObject | t.CPtr, val: PyObject | t.CPtr) -> t.CSizeT
|
||||
extern def PySequence_Count(obj: PyObject | t.CPtr, val: PyObject | t.CPtr) -> t.CSizeT
|
||||
extern def PySequence_List(obj: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PySequence_Tuple(obj: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 映射操作
|
||||
# ============================================================
|
||||
extern def PyMapping_Check(obj: PyObject | t.CPtr) -> t.CInt
|
||||
extern def PyMapping_Size(obj: PyObject | t.CPtr) -> t.CSizeT
|
||||
extern def PyMapping_Length(obj: PyObject | t.CPtr) -> t.CSizeT
|
||||
extern def PyMapping_HasKey(obj: PyObject | t.CPtr, key: PyObject | t.CPtr) -> t.CInt
|
||||
extern def PyMapping_HasKeyString(obj: PyObject | t.CPtr, key: t.CConst | str) -> t.CInt
|
||||
extern def PyMapping_GetItemString(obj: PyObject | t.CPtr, key: t.CConst | str) -> PyObject | t.CPtr
|
||||
extern def PyMapping_SetItemString(obj: PyObject | t.CPtr, key: t.CConst | str, val: PyObject | t.CPtr) -> t.CInt
|
||||
extern def PyMapping_Keys(obj: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyMapping_Values(obj: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyMapping_Items(obj: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 数字操作
|
||||
# ============================================================
|
||||
extern def PyNumber_Add(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyNumber_Subtract(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyNumber_Multiply(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyNumber_MatrixMultiply(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyNumber_FloorDivide(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyNumber_TrueDivide(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyNumber_Modulo(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyNumber_Power(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr, o3: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyNumber_Negative(obj: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyNumber_Positive(obj: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyNumber_Absolute(obj: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyNumber_Invert(obj: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyNumber_Lshift(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyNumber_Rshift(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyNumber_And(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyNumber_Xor(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyNumber_Or(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyNumber_Index(obj: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyNumber_Long(obj: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyNumber_Float(obj: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyNumber_Check(obj: PyObject | t.CPtr) -> t.CInt
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 弱引用
|
||||
# ============================================================
|
||||
extern def PyWeakref_NewRef(obj: PyObject | t.CPtr, cb: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyWeakref_GetObject(ref: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyWeakref_Check(obj: PyObject | t.CPtr) -> t.CInt
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 属性描述符
|
||||
# ============================================================
|
||||
class PyGetSetDef:
|
||||
name: t.CConst | str
|
||||
get: t.CPtr
|
||||
set: t.CPtr
|
||||
doc: t.CConst | str
|
||||
closure: t.CPtr
|
||||
|
||||
class PyMemberDef:
|
||||
name: t.CConst | str
|
||||
type: t.CInt
|
||||
offset: t.CPtrDiffT
|
||||
flags: t.CInt
|
||||
doc: t.CConst | str
|
||||
|
||||
|
||||
# ============================================================
|
||||
# sys 模块
|
||||
# ============================================================
|
||||
extern def PySys_GetObject(name: t.CConst | str) -> PyObject | t.CPtr
|
||||
extern def PySys_SetObject(name: t.CConst | str, val: PyObject | t.CPtr) -> t.CInt
|
||||
extern def PySys_ResetWarnOptions(): pass
|
||||
extern def PySys_AddWarnOption(s: PyObject | t.CPtr): pass
|
||||
extern def PySYS_AddXOption(s: PyObject | t.CPtr): pass
|
||||
extern def PySys_WriteStdout(fmt: t.CConst | str): pass
|
||||
extern def PySys_WriteStderr(fmt: t.CConst | str): pass
|
||||
extern def PySys_FormatStdout(fmt: t.CConst | str): pass
|
||||
extern def PySys_FormatStderr(fmt: t.CConst | str): pass
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 内存视图
|
||||
# ============================================================
|
||||
extern def PyMemoryView_FromObject(obj: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyMemoryView_GetContiguous(obj: PyObject | t.CPtr, btype: t.CInt, order: t.CChar) -> PyObject | t.CPtr
|
||||
extern def PyMemoryView_Check(obj: PyObject | t.CPtr) -> t.CInt
|
||||
|
||||
|
||||
# ============================================================
|
||||
# set / frozenset
|
||||
# ============================================================
|
||||
extern def PySet_New(iterable: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PySet_Add(s: PyObject | t.CPtr, key: PyObject | t.CPtr) -> t.CInt
|
||||
extern def PySet_Discard(s: PyObject | t.CPtr, key: PyObject | t.CPtr) -> t.CInt
|
||||
extern def PySet_Contains(s: PyObject | t.CPtr, key: PyObject | t.CPtr) -> t.CInt
|
||||
extern def PySet_Size(s: PyObject | t.CPtr) -> t.CSizeT
|
||||
extern def PySet_Clear(s: PyObject | t.CPtr): pass
|
||||
extern def PySet_Check(obj: PyObject | t.CPtr) -> t.CInt
|
||||
extern def PyFrozenSet_New(iterable: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PyFrozenSet_Check(obj: PyObject | t.CPtr) -> t.CInt
|
||||
|
||||
|
||||
# ============================================================
|
||||
# slice
|
||||
# ============================================================
|
||||
extern def PySlice_New(start: PyObject | t.CPtr, stop: PyObject | t.CPtr, step: PyObject | t.CPtr) -> PyObject | t.CPtr
|
||||
extern def PySlice_GetIndicesEx(sl: PyObject | t.CPtr, length: t.CSizeT, start: t.CSizeT | t.CPtr, stop: t.CSizeT | t.CPtr, step: t.CSizeT | t.CPtr, slicelen: t.CSizeT | t.CPtr) -> t.CInt
|
||||
extern def PySlice_Unpack(sl: PyObject | t.CPtr, start: t.CPtrDiffT | t.CPtr, stop: t.CPtrDiffT | t.CPtr, step: t.CPtrDiffT | t.CPtr): pass
|
||||
extern def PySlice_AdjustIndices(length: t.CSizeT, start: t.CPtrDiffT | t.CPtr, stop: t.CPtrDiffT | t.CPtr, step: t.CPtrDiffT) -> t.CSizeT
|
||||
extern def PySlice_Check(obj: PyObject | t.CPtr) -> t.CInt
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 类型包装类 — 带运算符重载
|
||||
# ============================================================
|
||||
|
||||
# --- PyLongObj: Python 整数包装 ---
|
||||
class PyLongObj:
|
||||
ptr: PyObject | t.CPtr
|
||||
|
||||
def __new__(self) -> 'PyLongObj' | t.CPtr:
|
||||
return t.CPtr(malloc(PyLongObj.__sizeof__()))
|
||||
|
||||
@staticmethod
|
||||
def from_long(val: t.CLong) -> 'PyLongObj' | t.CPtr:
|
||||
obj: PyLongObj | t.CPtr = PyLongObj()
|
||||
obj.ptr = PyLong_FromLong(val)
|
||||
return obj
|
||||
|
||||
def __add__(self, other: PyLongObj | t.CPtr) -> 'PyLongObj' | t.CPtr:
|
||||
res: PyLongObj | t.CPtr = PyLongObj()
|
||||
res.ptr = PyNumber_Add(self.ptr, other.ptr)
|
||||
return res
|
||||
|
||||
def __sub__(self, other: PyLongObj | t.CPtr) -> 'PyLongObj' | t.CPtr:
|
||||
res: PyLongObj | t.CPtr = PyLongObj()
|
||||
res.ptr = PyNumber_Subtract(self.ptr, other.ptr)
|
||||
return res
|
||||
|
||||
def __mul__(self, other: PyLongObj | t.CPtr) -> 'PyLongObj' | t.CPtr:
|
||||
res: PyLongObj | t.CPtr = PyLongObj()
|
||||
res.ptr = PyNumber_Multiply(self.ptr, other.ptr)
|
||||
return res
|
||||
|
||||
def __neg__(self) -> 'PyLongObj' | t.CPtr:
|
||||
res: PyLongObj | t.CPtr = PyLongObj()
|
||||
res.ptr = PyNumber_Negative(self.ptr)
|
||||
return res
|
||||
|
||||
def to_long(self) -> t.CLong:
|
||||
return PyLong_AsLong(self.ptr)
|
||||
|
||||
def __str__(self) -> PyObject | t.CPtr:
|
||||
return PyObject_Str(self.ptr)
|
||||
|
||||
def dec_ref(self):
|
||||
Py_DecRef(self.ptr)
|
||||
|
||||
|
||||
# --- PyFloatObj: Python 浮点数包装 ---
|
||||
class PyFloatObj:
|
||||
ptr: PyObject | t.CPtr
|
||||
|
||||
def __new__(self) -> 'PyFloatObj' | t.CPtr:
|
||||
return t.CPtr(malloc(PyFloatObj.__sizeof__()))
|
||||
|
||||
@staticmethod
|
||||
def from_double(val: t.CDouble) -> 'PyFloatObj' | t.CPtr:
|
||||
obj: PyFloatObj | t.CPtr = PyFloatObj()
|
||||
obj.ptr = PyFloat_FromDouble(val)
|
||||
return obj
|
||||
|
||||
def __add__(self, other: PyFloatObj | t.CPtr) -> 'PyFloatObj' | t.CPtr:
|
||||
res: PyFloatObj | t.CPtr = PyFloatObj()
|
||||
res.ptr = PyNumber_Add(self.ptr, other.ptr)
|
||||
return res
|
||||
|
||||
def __sub__(self, other: PyFloatObj | t.CPtr) -> 'PyFloatObj' | t.CPtr:
|
||||
res: PyFloatObj | t.CPtr = PyFloatObj()
|
||||
res.ptr = PyNumber_Subtract(self.ptr, other.ptr)
|
||||
return res
|
||||
|
||||
def __mul__(self, other: PyFloatObj | t.CPtr) -> 'PyFloatObj' | t.CPtr:
|
||||
res: PyFloatObj | t.CPtr = PyFloatObj()
|
||||
res.ptr = PyNumber_Multiply(self.ptr, other.ptr)
|
||||
return res
|
||||
|
||||
def __truediv__(self, other: PyFloatObj | t.CPtr) -> 'PyFloatObj' | t.CPtr:
|
||||
res: PyFloatObj | t.CPtr = PyFloatObj()
|
||||
res.ptr = PyNumber_TrueDivide(self.ptr, other.ptr)
|
||||
return res
|
||||
|
||||
def __neg__(self) -> 'PyFloatObj' | t.CPtr:
|
||||
res: PyFloatObj | t.CPtr = PyFloatObj()
|
||||
res.ptr = PyNumber_Negative(self.ptr)
|
||||
return res
|
||||
|
||||
def to_double(self) -> t.CDouble:
|
||||
return PyFloat_AsDouble(self.ptr)
|
||||
|
||||
def __str__(self) -> PyObject | t.CPtr:
|
||||
return PyObject_Str(self.ptr)
|
||||
|
||||
def dec_ref(self):
|
||||
Py_DecRef(self.ptr)
|
||||
|
||||
|
||||
# --- PyUnicodeObj: Python 字符串包装 ---
|
||||
class PyUnicodeObj:
|
||||
ptr: PyObject | t.CPtr
|
||||
|
||||
def __new__(self) -> 'PyUnicodeObj' | t.CPtr:
|
||||
return t.CPtr(malloc(PyUnicodeObj.__sizeof__()))
|
||||
|
||||
@staticmethod
|
||||
def from_string(s: t.CChar | t.CPtr) -> 'PyUnicodeObj' | t.CPtr:
|
||||
obj: PyUnicodeObj | t.CPtr = PyUnicodeObj()
|
||||
obj.ptr = PyUnicode_FromString(s)
|
||||
return obj
|
||||
|
||||
def __add__(self, other: PyUnicodeObj | t.CPtr) -> 'PyUnicodeObj' | t.CPtr:
|
||||
res: PyUnicodeObj | t.CPtr = PyUnicodeObj()
|
||||
res.ptr = PyUnicode_Concat(self.ptr, other.ptr)
|
||||
return res
|
||||
|
||||
def __len__(self) -> t.CPtrDiffT:
|
||||
return PyUnicode_GetLength(self.ptr)
|
||||
|
||||
def as_utf8(self) -> t.CChar | t.CPtr:
|
||||
return PyUnicode_AsUTF8(self.ptr)
|
||||
|
||||
def __str__(self) -> PyObject | t.CPtr:
|
||||
return self.ptr
|
||||
|
||||
def dec_ref(self):
|
||||
Py_DecRef(self.ptr)
|
||||
|
||||
|
||||
# --- PyListObj: Python 列表包装 ---
|
||||
class PyListObj:
|
||||
ptr: PyObject | t.CPtr
|
||||
|
||||
def __new__(self) -> 'PyListObj' | t.CPtr:
|
||||
return t.CPtr(malloc(PyListObj.__sizeof__()))
|
||||
|
||||
@staticmethod
|
||||
def new() -> 'PyListObj' | t.CPtr:
|
||||
obj: PyListObj | t.CPtr = PyListObj()
|
||||
obj.ptr = PyList_New(0)
|
||||
return obj
|
||||
|
||||
def __getitem__(self, idx: t.CSizeT) -> PyObject | t.CPtr:
|
||||
return PyList_GetItem(self.ptr, idx)
|
||||
|
||||
def __setitem__(self, idx: t.CSizeT, val: PyObject | t.CPtr):
|
||||
PyList_SetItem(self.ptr, idx, val)
|
||||
|
||||
def __len__(self) -> t.CSizeT:
|
||||
return PyList_Size(self.ptr)
|
||||
|
||||
def append(self, item: PyObject | t.CPtr) -> t.CInt:
|
||||
return PyList_Append(self.ptr, item)
|
||||
|
||||
def dec_ref(self):
|
||||
Py_DecRef(self.ptr)
|
||||
|
||||
|
||||
# --- PyDictObj: Python 字典包装 ---
|
||||
class PyDictObj:
|
||||
ptr: PyObject | t.CPtr
|
||||
|
||||
def __new__(self) -> 'PyDictObj' | t.CPtr:
|
||||
return t.CPtr(malloc(PyDictObj.__sizeof__()))
|
||||
|
||||
@staticmethod
|
||||
def new() -> 'PyDictObj' | t.CPtr:
|
||||
obj: PyDictObj | t.CPtr = PyDictObj()
|
||||
obj.ptr = PyDict_New()
|
||||
return obj
|
||||
|
||||
def __getitem__(self, key: PyObject | t.CPtr) -> PyObject | t.CPtr:
|
||||
return PyDict_GetItem(self.ptr, key)
|
||||
|
||||
def __setitem__(self, key: PyObject | t.CPtr, val: PyObject | t.CPtr):
|
||||
PyDict_SetItem(self.ptr, key, val)
|
||||
|
||||
def __len__(self) -> t.CSizeT:
|
||||
return PyDict_Size(self.ptr)
|
||||
|
||||
def get_string(self, key: t.CChar | t.CPtr) -> PyObject | t.CPtr:
|
||||
return PyDict_GetItemString(self.ptr, key)
|
||||
|
||||
def set_string(self, key: t.CChar | t.CPtr, val: PyObject | t.CPtr):
|
||||
PyDict_SetItemString(self.ptr, key, val)
|
||||
|
||||
def dec_ref(self):
|
||||
Py_DecRef(self.ptr)
|
||||
@@ -0,0 +1,359 @@
|
||||
import t, c
|
||||
from t import CInt, CLong, CDouble, CPtr, CSizeT
|
||||
from stdio import printf
|
||||
import cpython
|
||||
import testcheck
|
||||
|
||||
|
||||
def test_init_finalize():
|
||||
testcheck.section("Py_Initialize / Py_Finalize")
|
||||
cpython.Py_Initialize()
|
||||
testcheck.check(cpython.Py_IsInitialized() != 0, "Py_Initialize succeeded", "Py_Initialize succeeded")
|
||||
cpython.Py_Finalize()
|
||||
testcheck.check(cpython.Py_IsInitialized() == 0, "Py_Finalize succeeded", "Py_Finalize succeeded")
|
||||
|
||||
|
||||
def test_long_operations():
|
||||
testcheck.section("PyLong operations")
|
||||
cpython.Py_Initialize()
|
||||
|
||||
# 创建整数
|
||||
py_num: cpython.PyObject | CPtr = cpython.PyLong_FromLong(12345)
|
||||
testcheck.check(py_num != 0, "PyLong_FromLong != NULL", "PyLong_FromLong != NULL")
|
||||
|
||||
# 整数转字符串
|
||||
py_str: cpython.PyObject | CPtr = cpython.PyObject_Str(py_num)
|
||||
testcheck.check(py_str != 0, "PyObject_Str != NULL", "PyObject_Str != NULL")
|
||||
|
||||
# 获取 C 字符串
|
||||
c_str: t.CChar | 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)
|
||||
|
||||
# 读取回来
|
||||
val: CLong = cpython.PyLong_AsLong(py_num)
|
||||
testcheck.check(val == 12345, "PyLong_AsLong == 12345", "PyLong_AsLong == 12345")
|
||||
|
||||
# 负数
|
||||
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")
|
||||
|
||||
# 浮点数转整数
|
||||
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")
|
||||
|
||||
# 清理
|
||||
cpython.Py_DecRef(py_dbl)
|
||||
cpython.Py_DecRef(py_neg)
|
||||
cpython.Py_DecRef(py_str)
|
||||
cpython.Py_DecRef(py_num)
|
||||
|
||||
cpython.Py_Finalize()
|
||||
|
||||
|
||||
def test_string_operations():
|
||||
testcheck.section("PyUnicode operations")
|
||||
cpython.Py_Initialize()
|
||||
|
||||
# 从 C 字符串创建
|
||||
py_s1: cpython.PyObject | CPtr = cpython.PyUnicode_FromString("Hello, Viper!")
|
||||
testcheck.check(py_s1 != 0, "PyUnicode_FromString != NULL", "PyUnicode_FromString != NULL")
|
||||
|
||||
# 获取 UTF8
|
||||
utf8: t.CChar | CPtr = cpython.PyUnicode_AsUTF8(py_s1)
|
||||
testcheck.check(utf8 != 0, "AsUTF8 != NULL", "AsUTF8 != NULL")
|
||||
printf(" PyUnicode_FromString -> %s\n", utf8)
|
||||
|
||||
# 字符串长度
|
||||
length: CLong = cpython.PyUnicode_GetLength(py_s1)
|
||||
testcheck.check(length == 13, "GetLength == 13", "GetLength == 13")
|
||||
|
||||
# 字符串拼接
|
||||
py_s2: cpython.PyObject | CPtr = cpython.PyUnicode_FromString(" World")
|
||||
py_concat: cpython.PyObject | CPtr = cpython.PyUnicode_Concat(py_s1, py_s2)
|
||||
concat_utf8: t.CChar | CPtr = cpython.PyUnicode_AsUTF8(py_concat)
|
||||
testcheck.check(py_concat != 0, "Concat != NULL", "Concat != NULL")
|
||||
printf(" Concat -> %s\n", concat_utf8)
|
||||
|
||||
# 清理
|
||||
cpython.Py_DecRef(py_concat)
|
||||
cpython.Py_DecRef(py_s2)
|
||||
cpython.Py_DecRef(py_s1)
|
||||
|
||||
cpython.Py_Finalize()
|
||||
|
||||
|
||||
def test_list_operations():
|
||||
testcheck.section("PyList operations")
|
||||
cpython.Py_Initialize()
|
||||
|
||||
# 创建列表
|
||||
py_list: cpython.PyObject | CPtr = cpython.PyList_New(0)
|
||||
testcheck.check(py_list != 0, "PyList_New != NULL", "PyList_New != NULL")
|
||||
|
||||
# Append 元素
|
||||
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)
|
||||
cpython.PyList_Append(py_list, py_i1)
|
||||
cpython.PyList_Append(py_list, py_i2)
|
||||
cpython.PyList_Append(py_list, py_i3)
|
||||
|
||||
# 检查大小
|
||||
list_size: CSizeT = cpython.PyList_Size(py_list)
|
||||
testcheck.check(list_size == 3, "PyList_Size == 3", "PyList_Size == 3")
|
||||
|
||||
# 获取元素
|
||||
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")
|
||||
|
||||
item2: cpython.PyObject | CPtr = cpython.PyList_GetItem(py_list, 2)
|
||||
val2: CLong = cpython.PyLong_AsLong(item2)
|
||||
testcheck.check(val2 == 30, "list[2] == 30", "list[2] == 30")
|
||||
|
||||
# 清理
|
||||
cpython.Py_DecRef(py_i3)
|
||||
cpython.Py_DecRef(py_i2)
|
||||
cpython.Py_DecRef(py_i1)
|
||||
cpython.Py_DecRef(py_list)
|
||||
|
||||
cpython.Py_Finalize()
|
||||
|
||||
|
||||
def test_dict_operations():
|
||||
testcheck.section("PyDict operations")
|
||||
cpython.Py_Initialize()
|
||||
|
||||
# 创建字典
|
||||
py_dict: cpython.PyObject | CPtr = cpython.PyDict_New()
|
||||
testcheck.check(py_dict != 0, "PyDict_New != NULL", "PyDict_New != NULL")
|
||||
|
||||
# 设置键值对
|
||||
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)
|
||||
|
||||
py_key2: cpython.PyObject | CPtr = cpython.PyUnicode_FromString("version")
|
||||
py_val2: cpython.PyObject | CPtr = cpython.PyLong_FromLong(1)
|
||||
cpython.PyDict_SetItem(py_dict, py_key2, py_val2)
|
||||
|
||||
# 检查大小
|
||||
dict_size: CSizeT = cpython.PyDict_Size(py_dict)
|
||||
testcheck.check(dict_size == 2, "PyDict_Size == 2", "PyDict_Size == 2")
|
||||
|
||||
# 获取值
|
||||
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: t.CChar | CPtr = cpython.PyUnicode_AsUTF8(got_val)
|
||||
testcheck.check(got_str != 0, "name == Viper", "name == Viper")
|
||||
printf(" dict['name'] = %s\n", got_str)
|
||||
|
||||
# 使用 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")
|
||||
|
||||
# 清理
|
||||
cpython.Py_DecRef(py_val2)
|
||||
cpython.Py_DecRef(py_key2)
|
||||
cpython.Py_DecRef(py_val1)
|
||||
cpython.Py_DecRef(py_key1)
|
||||
cpython.Py_DecRef(py_dict)
|
||||
|
||||
cpython.Py_Finalize()
|
||||
|
||||
|
||||
def test_pyrun_string():
|
||||
testcheck.section("PyRun_SimpleString")
|
||||
cpython.Py_Initialize()
|
||||
|
||||
# 执行简单 Python 代码
|
||||
rc: CInt = cpython.PyRun_SimpleString("print('Hello from embedded Python!')")
|
||||
testcheck.check(rc == 0, "PyRun_SimpleString == 0", "PyRun_SimpleString == 0")
|
||||
|
||||
# 执行赋值
|
||||
rc2: CInt = cpython.PyRun_SimpleString("x = 6 * 7")
|
||||
testcheck.check(rc2 == 0, "PyRun_SimpleString(assign) == 0", "PyRun_SimpleString(assign) == 0")
|
||||
|
||||
# 读取结果
|
||||
rc3: CInt = cpython.PyRun_SimpleString("print(f'The answer is {x}')")
|
||||
testcheck.check(rc3 == 0, "PyRun_SimpleString(print) == 0", "PyRun_SimpleString(print) == 0")
|
||||
|
||||
cpython.Py_Finalize()
|
||||
|
||||
|
||||
def test_import_module():
|
||||
testcheck.section("PyImport_ImportModule")
|
||||
cpython.Py_Initialize()
|
||||
|
||||
# 导入 math 模块
|
||||
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
|
||||
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:
|
||||
pi_dbl: CDouble = cpython.PyFloat_AsDouble(pi_val)
|
||||
testcheck.check(pi_dbl > 3.14 and pi_dbl < 3.15, "math.pi ~= 3.14", "math.pi ~= 3.14")
|
||||
printf(" math.pi = %f\n", pi_dbl)
|
||||
cpython.Py_DecRef(pi_val)
|
||||
|
||||
# 获取 math.sqrt 函数
|
||||
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:
|
||||
cpython.Py_DecRef(sqrt_func)
|
||||
|
||||
cpython.Py_DecRef(math_mod)
|
||||
|
||||
cpython.Py_Finalize()
|
||||
|
||||
|
||||
def test_operator_overload():
|
||||
testcheck.section("Operator Overload (PyLongObj / PyFloatObj / PyUnicodeObj / PyListObj / PyDictObj)")
|
||||
cpython.Py_Initialize()
|
||||
|
||||
# --- PyLongObj: from_long, to_long, +, -, *, - (neg) ---
|
||||
a: cpython.PyLongObj | CPtr = cpython.PyLongObj.from_long(10)
|
||||
b: cpython.PyLongObj | CPtr = cpython.PyLongObj.from_long(3)
|
||||
testcheck.check(a != 0 and b != 0, "PyLongObj.from_long != NULL", "PyLongObj.from_long != NULL")
|
||||
|
||||
add_r: cpython.PyLongObj | CPtr = a + b
|
||||
testcheck.check(add_r.to_long() == 13, "PyLongObj 10 + 3 == 13", "PyLongObj 10 + 3 == 13")
|
||||
|
||||
sub_r: cpython.PyLongObj | CPtr = a - b
|
||||
testcheck.check(sub_r.to_long() == 7, "PyLongObj 10 - 3 == 7", "PyLongObj 10 - 3 == 7")
|
||||
|
||||
mul_r: cpython.PyLongObj | CPtr = a * b
|
||||
testcheck.check(mul_r.to_long() == 30, "PyLongObj 10 * 3 == 30", "PyLongObj 10 * 3 == 30")
|
||||
|
||||
neg_r: cpython.PyLongObj | CPtr = -b
|
||||
testcheck.check(neg_r.to_long() == -3, "PyLongObj -3 == -3", "PyLongObj -3 == -3")
|
||||
|
||||
mul_r.dec_ref()
|
||||
sub_r.dec_ref()
|
||||
add_r.dec_ref()
|
||||
neg_r.dec_ref()
|
||||
b.dec_ref()
|
||||
a.dec_ref()
|
||||
|
||||
# --- PyFloatObj: from_double, to_double, +, -, *, /, - (neg) ---
|
||||
fa: cpython.PyFloatObj | CPtr = cpython.PyFloatObj.from_double(10.0)
|
||||
fb: cpython.PyFloatObj | CPtr = cpython.PyFloatObj.from_double(4.0)
|
||||
testcheck.check(fa != 0 and fb != 0, "PyFloatObj.from_double != NULL", "PyFloatObj.from_double != NULL")
|
||||
|
||||
fadd: cpython.PyFloatObj | CPtr = fa + fb
|
||||
testcheck.check(fadd.to_double() == 14.0, "PyFloatObj 10.0 + 4.0 == 14.0", "PyFloatObj 10.0 + 4.0 == 14.0")
|
||||
|
||||
fsub: cpython.PyFloatObj | CPtr = fa - fb
|
||||
testcheck.check(fsub.to_double() == 6.0, "PyFloatObj 10.0 - 4.0 == 6.0", "PyFloatObj 10.0 - 4.0 == 6.0")
|
||||
|
||||
fmul: cpython.PyFloatObj | CPtr = fa * fb
|
||||
testcheck.check(fmul.to_double() == 40.0, "PyFloatObj 10.0 * 4.0 == 40.0", "PyFloatObj 10.0 * 4.0 == 40.0")
|
||||
|
||||
fdiv: cpython.PyFloatObj | CPtr = fa / fb
|
||||
testcheck.check(fdiv.to_double() == 2.5, "PyFloatObj 10.0 / 4.0 == 2.5", "PyFloatObj 10.0 / 4.0 == 2.5")
|
||||
|
||||
fneg: cpython.PyFloatObj | CPtr = -fb
|
||||
testcheck.check(fneg.to_double() == -4.0, "PyFloatObj -4.0 == -4.0", "PyFloatObj -4.0 == -4.0")
|
||||
|
||||
fadd.dec_ref()
|
||||
fsub.dec_ref()
|
||||
fmul.dec_ref()
|
||||
fdiv.dec_ref()
|
||||
fneg.dec_ref()
|
||||
fb.dec_ref()
|
||||
fa.dec_ref()
|
||||
|
||||
# --- PyUnicodeObj: from_string, as_utf8, len, + (concat) ---
|
||||
sa: cpython.PyUnicodeObj | CPtr = cpython.PyUnicodeObj.from_string("Hello")
|
||||
sb: cpython.PyUnicodeObj | CPtr = cpython.PyUnicodeObj.from_string(" World")
|
||||
testcheck.check(sa != 0 and sb != 0, "PyUnicodeObj.from_string != NULL", "PyUnicodeObj.from_string != NULL")
|
||||
|
||||
sc: cpython.PyUnicodeObj | CPtr = sa + sb
|
||||
sc_utf8: t.CChar | CPtr = sc.as_utf8()
|
||||
testcheck.check(sc_utf8 != 0, "PyUnicodeObj concat != NULL", "PyUnicodeObj concat != NULL")
|
||||
if sc_utf8 != 0:
|
||||
printf(" PyUnicodeObj 'Hello' + ' World' = %s\n", sc_utf8)
|
||||
|
||||
sa_len: t.CPtrDiffT = len(sa)
|
||||
testcheck.check(sa_len == 5, "PyUnicodeObj len('Hello') == 5", "PyUnicodeObj len('Hello') == 5")
|
||||
|
||||
sc.dec_ref()
|
||||
sb.dec_ref()
|
||||
sa.dec_ref()
|
||||
|
||||
# --- PyListObj: new, append, len, [], []= ---
|
||||
lst: cpython.PyListObj | CPtr = cpython.PyListObj.new()
|
||||
testcheck.check(lst != 0, "PyListObj.new != NULL", "PyListObj.new != NULL")
|
||||
if lst != 0:
|
||||
e1: cpython.PyObject | CPtr = cpython.PyLong_FromLong(100)
|
||||
e2: cpython.PyObject | CPtr = cpython.PyLong_FromLong(200)
|
||||
e3: cpython.PyObject | CPtr = cpython.PyLong_FromLong(300)
|
||||
lst.append(e1)
|
||||
lst.append(e2)
|
||||
lst.append(e3)
|
||||
testcheck.check(len(lst) == 3, "PyListObj len == 3", "PyListObj len == 3")
|
||||
|
||||
item0: cpython.PyObject | CPtr = lst[t.CSizeT(0)]
|
||||
testcheck.check(cpython.PyLong_AsLong(item0) == 100, "PyListObj lst[0] == 100", "PyListObj lst[0] == 100")
|
||||
|
||||
# __setitem__
|
||||
e4: cpython.PyObject | CPtr = cpython.PyLong_FromLong(999)
|
||||
lst[t.CSizeT(1)] = e4
|
||||
item1: cpython.PyObject | CPtr = lst[t.CSizeT(1)]
|
||||
testcheck.check(cpython.PyLong_AsLong(item1) == 999, "PyListObj lst[1] = 999", "PyListObj lst[1] = 999")
|
||||
|
||||
cpython.Py_DecRef(e4)
|
||||
cpython.Py_DecRef(e3)
|
||||
cpython.Py_DecRef(e2)
|
||||
cpython.Py_DecRef(e1)
|
||||
lst.dec_ref()
|
||||
|
||||
# --- PyDictObj: new, [], []=, len, set_string, get_string ---
|
||||
dct: cpython.PyDictObj | CPtr = cpython.PyDictObj.new()
|
||||
testcheck.check(dct != 0, "PyDictObj.new != NULL", "PyDictObj.new != NULL")
|
||||
if dct != 0:
|
||||
dk1: cpython.PyObject | CPtr = cpython.PyUnicode_FromString("lang")
|
||||
dv1: cpython.PyObject | CPtr = cpython.PyUnicode_FromString("Viper")
|
||||
dct[dk1] = dv1
|
||||
testcheck.check(len(dct) == 1, "PyDictObj len == 1", "PyDictObj len == 1")
|
||||
|
||||
got_lang: cpython.PyObject | CPtr = dct[dk1]
|
||||
got_str: t.CChar | CPtr = cpython.PyUnicode_AsUTF8(got_lang)
|
||||
testcheck.check(got_str != 0, "PyDictObj dct['lang'] == Viper", "PyDictObj dct['lang'] == Viper")
|
||||
if got_str != 0:
|
||||
printf(" PyDictObj dct['lang'] = %s\n", got_str)
|
||||
|
||||
# get_string / set_string
|
||||
dct.set_string("ver", cpython.PyLong_FromLong(3))
|
||||
got_ver: cpython.PyObject | CPtr = dct.get_string("ver")
|
||||
testcheck.check(got_ver != 0 and cpython.PyLong_AsLong(got_ver) == 3, "PyDictObj get_string('ver') == 3", "PyDictObj get_string('ver') == 3")
|
||||
|
||||
cpython.Py_DecRef(dv1)
|
||||
cpython.Py_DecRef(dk1)
|
||||
dct.dec_ref()
|
||||
|
||||
cpython.Py_Finalize()
|
||||
|
||||
|
||||
def main() -> CInt | t.CExport:
|
||||
testcheck.begin("CPython Integration Test")
|
||||
|
||||
test_init_finalize()
|
||||
test_long_operations()
|
||||
test_string_operations()
|
||||
test_list_operations()
|
||||
test_dict_operations()
|
||||
test_pyrun_string()
|
||||
test_import_module()
|
||||
test_operator_overload()
|
||||
|
||||
return testcheck.end()
|
||||
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
|
||||
"name": "CPythonTest",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": ["-filetype=obj", "-relocation-model=pic"]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": [
|
||||
"-L", "D:\\Python312\\libs",
|
||||
"-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex",
|
||||
"-lkernel32", "-luser32",
|
||||
"-lpython312",
|
||||
"-Wl,--allow-multiple-definition"
|
||||
],
|
||||
"output": "CPythonTest.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import stdio
|
||||
|
||||
|
||||
def bump(v: char) -> char:
|
||||
return char(v + 1)
|
||||
|
||||
|
||||
def main() -> t.CInt | t.CExport:
|
||||
# 1) char 注解:char = t.CChar = i8(标量内置类型,非指针)
|
||||
ch: char = 65
|
||||
stdio.printf("1 char annot: %d (expect 65)\n", int(ch))
|
||||
|
||||
# 2) char() 强转 int→char:300 trunc 到 i8 → 44
|
||||
big: char = char(300)
|
||||
stdio.printf("2 char cast trunc: %d (expect 44)\n", int(big))
|
||||
|
||||
# 3) 函数返回 char(i8 存储)
|
||||
nx: char = bump(ch)
|
||||
stdio.printf("3 char return: %d (expect 66)\n", int(nx))
|
||||
|
||||
# 4) 单字符字面量 'Z' 赋给 char(90)
|
||||
lit: char = 'Z'
|
||||
stdio.printf("4 char literal: %d (expect 90)\n", int(lit))
|
||||
|
||||
# 5) char 参与算术(i8 与 int 混合提升)
|
||||
s: int = ch + 1
|
||||
stdio.printf("5 char arith: %d (expect 66)\n", s)
|
||||
|
||||
return 0
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
|
||||
"name": "CharTest",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": [
|
||||
"-filetype=obj",
|
||||
"-relocation-model=pic"
|
||||
]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": [
|
||||
"-Wl,--allow-multiple-definition",
|
||||
"-lmsvcrt",
|
||||
"-lucrt",
|
||||
"-lpthread",
|
||||
"-lmingwex",
|
||||
"-lkernel32",
|
||||
"-luser32"
|
||||
],
|
||||
"output": "CharTest.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,246 @@
|
||||
import stdio
|
||||
import stdlib
|
||||
import stdint
|
||||
import t, c
|
||||
|
||||
|
||||
class SimpleData():
|
||||
x: t.CInt
|
||||
y: t.CInt
|
||||
|
||||
|
||||
class Point3D():
|
||||
x: t.CFloat
|
||||
y: t.CFloat
|
||||
z: t.CFloat
|
||||
|
||||
|
||||
class Student():
|
||||
name: t.CChar | t.CPtr
|
||||
age: t.CInt
|
||||
score: t.CInt
|
||||
|
||||
def __init__(self, n: t.CChar | t.CPtr, a: t.CInt, s: t.CInt):
|
||||
self.name = n
|
||||
self.age = a
|
||||
self.score = s
|
||||
|
||||
def get_age(self) -> t.CInt:
|
||||
return self.age
|
||||
|
||||
def get_score(self) -> t.CInt:
|
||||
return self.score
|
||||
|
||||
|
||||
class Counter():
|
||||
value: t.CInt
|
||||
|
||||
def __init__(self, initial: t.CInt):
|
||||
self.value = initial
|
||||
|
||||
def increment(self):
|
||||
self.value += 1
|
||||
|
||||
def get_value(self) -> t.CInt:
|
||||
return self.value
|
||||
|
||||
|
||||
class StackObj():
|
||||
data: t.CInt
|
||||
next_ptr: t.CPtr
|
||||
|
||||
|
||||
def TestBasicDataClass():
|
||||
stdio.printf("=== Test Basic Data Class ===\n")
|
||||
p: SimpleData = SimpleData()
|
||||
p.x = 10
|
||||
p.y = 20
|
||||
stdio.printf("SimpleData: x=%d, y=%d\n", p.x, p.y)
|
||||
|
||||
|
||||
def TestPoint3DClass():
|
||||
stdio.printf("=== Test Point3D Class ===\n")
|
||||
pt: Point3D = Point3D()
|
||||
pt.x = 1.5
|
||||
pt.y = 2.5
|
||||
pt.z = 3.5
|
||||
stdio.printf("Point3D: x=%.1f, y=%.1f, z=%.1f\n", pt.x, pt.y, pt.z)
|
||||
|
||||
|
||||
def TestStudentClass():
|
||||
stdio.printf("=== Test Student Class ===\n")
|
||||
s: Student = Student("Alice", 20, 95)
|
||||
stdio.printf("Student: name=%s, age=%d, score=%d\n", s.name, s.age, s.score)
|
||||
stdio.printf(" get_age()=%d, get_score()=%d\n", s.get_age(), s.get_score())
|
||||
|
||||
|
||||
def TestCounterClass():
|
||||
stdio.printf("=== Test Counter Class ===\n")
|
||||
cnt: Counter = Counter(0)
|
||||
stdio.printf("Initial value: %d\n", cnt.get_value())
|
||||
cnt.increment()
|
||||
cnt.increment()
|
||||
cnt.increment()
|
||||
stdio.printf("After 3 increments: %d\n", cnt.get_value())
|
||||
|
||||
|
||||
def TestStackAllocation():
|
||||
stdio.printf("=== Test Stack Allocation ===\n")
|
||||
obj1: SimpleData = SimpleData()
|
||||
obj1.x = 100
|
||||
obj1.y = 200
|
||||
stdio.printf("Stack obj1: x=%d, y=%d\n", obj1.x, obj1.y)
|
||||
|
||||
obj2: Point3D = Point3D()
|
||||
obj2.x = 10.0
|
||||
obj2.y = 20.0
|
||||
obj2.z = 30.0
|
||||
stdio.printf("Stack obj2: x=%.1f, y=%.1f, z=%.1f\n", obj2.x, obj2.y, obj2.z)
|
||||
|
||||
|
||||
def TestHeapAllocation():
|
||||
stdio.printf("=== Test Heap Allocation ===\n")
|
||||
ptr: t.CPtr = stdlib.malloc(1024)
|
||||
if ptr != 0:
|
||||
stdio.printf("Allocated 1024 bytes at %p\n", ptr)
|
||||
stdlib.free(ptr)
|
||||
stdio.printf("Freed memory\n")
|
||||
else:
|
||||
stdio.printf("malloc failed\n")
|
||||
|
||||
|
||||
def TestHeapObjectWithInit():
|
||||
stdio.printf("=== Test Heap Object with Init ===\n")
|
||||
mem_size: t.CSizeT = 256
|
||||
ptr: t.CPtr = stdlib.malloc(mem_size)
|
||||
if ptr != 0:
|
||||
stdio.printf("Allocated %d bytes\n", mem_size)
|
||||
stdlib.free(ptr)
|
||||
else:
|
||||
stdio.printf("malloc failed\n")
|
||||
|
||||
|
||||
def TestMultipleStackObjects():
|
||||
stdio.printf("=== Test Multiple Stack Objects ===\n")
|
||||
objs: SimpleData = SimpleData()
|
||||
objs.x = 1
|
||||
objs.y = 2
|
||||
obj2: Point3D = Point3D()
|
||||
obj2.x = 5.0
|
||||
obj2.y = 10.0
|
||||
obj2.z = 15.0
|
||||
obj3: Counter = Counter(42)
|
||||
stdio.printf("objs: x=%d, y=%d\n", objs.x, objs.y)
|
||||
stdio.printf("obj2: x=%.1f, y=%.1f, z=%.1f\n", obj2.x, obj2.y, obj2.z)
|
||||
stdio.printf("obj3 initial: %d\n", obj3.get_value())
|
||||
obj3.increment()
|
||||
obj3.increment()
|
||||
stdio.printf("obj3 after 2 increments: %d\n", obj3.get_value())
|
||||
|
||||
|
||||
def TestImplicitInitCall():
|
||||
stdio.printf("=== Test Implicit Init Call ===\n")
|
||||
stu1: Student = Student("Bob", 22, 88)
|
||||
stu2: Student = Student("Charlie", 19, 77)
|
||||
stdio.printf("stu1: name=%s, age=%d, score=%d\n", stu1.name, stu1.age, stu1.score)
|
||||
stdio.printf("stu2: name=%s, age=%d, score=%d\n", stu2.name, stu2.age, stu2.score)
|
||||
|
||||
|
||||
def TestClassWithBitFields():
|
||||
stdio.printf("=== Test Class with Bit Fields ===\n")
|
||||
flags: StackObj = StackObj()
|
||||
flags.data = 0
|
||||
flags.next_ptr = 0
|
||||
stdio.printf("StackObj: data=%d, next_ptr=%p\n", flags.data, flags.next_ptr)
|
||||
|
||||
|
||||
def TestIntArray():
|
||||
stdio.printf("=== Test Int Array ===\n")
|
||||
arr: t.CArray[t.CInt, 5] = t.CArray[t.CInt, 5]()
|
||||
i: t.CInt = 0
|
||||
while i < 5:
|
||||
arr[i] = i * 10
|
||||
i += 1
|
||||
i = 0
|
||||
while i < 5:
|
||||
stdio.printf("arr[%d]=%d\n", i, arr[i])
|
||||
i += 1
|
||||
|
||||
|
||||
def TestFloatArray():
|
||||
stdio.printf("=== Test Float Array ===\n")
|
||||
farr: t.CArray[t.CFloat, 4] = t.CArray[t.CFloat, 4]()
|
||||
farr[0] = 1.5
|
||||
farr[1] = 2.5
|
||||
farr[2] = 3.5
|
||||
farr[3] = 4.5
|
||||
i: t.CInt = 0
|
||||
while i < 4:
|
||||
stdio.printf("farr[%d]=%.1f\n", i, farr[i])
|
||||
i += 1
|
||||
|
||||
|
||||
def TestCharArray():
|
||||
stdio.printf("=== Test Char Array (String) ===\n")
|
||||
str_arr: t.CArray[t.CChar, 32] = t.CArray[t.CChar, 32]()
|
||||
str_arr[0] = 'H'
|
||||
str_arr[1] = 'e'
|
||||
str_arr[2] = 'l'
|
||||
str_arr[3] = 'l'
|
||||
str_arr[4] = 'o'
|
||||
str_arr[5] = '\0'
|
||||
stdio.printf("String: %s\n", str_arr)
|
||||
|
||||
|
||||
def TestNestedArray():
|
||||
stdio.printf("=== Test Nested Array (Array of Arrays) ===\n")
|
||||
row0: t.CArray[t.CInt, 3] = t.CArray[t.CInt, 3]()
|
||||
row1: t.CArray[t.CInt, 3] = t.CArray[t.CInt, 3]()
|
||||
row0[0] = 0
|
||||
row0[1] = 1
|
||||
row0[2] = 2
|
||||
row1[0] = 10
|
||||
row1[1] = 11
|
||||
row1[2] = 12
|
||||
i: t.CInt = 0
|
||||
while i < 3:
|
||||
stdio.printf("row0[%d]=%d ", i, row0[i])
|
||||
i += 1
|
||||
stdio.printf("\n")
|
||||
i = 0
|
||||
while i < 3:
|
||||
stdio.printf("row1[%d]=%d ", i, row1[i])
|
||||
i += 1
|
||||
stdio.printf("\n")
|
||||
|
||||
|
||||
def TestArrayWithStruct():
|
||||
stdio.printf("=== Test Array with Struct ===\n")
|
||||
points: t.CArray[SimpleData, 3] = t.CArray[SimpleData, 3]()
|
||||
i: t.CInt = 0
|
||||
while i < 3:
|
||||
points[i].x = i * 10
|
||||
points[i].y = i * 100
|
||||
i += 1
|
||||
i = 0
|
||||
while i < 3:
|
||||
stdio.printf("Point[%d]: x=%d, y=%d\n", i, points[i].x, points[i].y)
|
||||
i += 1
|
||||
|
||||
|
||||
def TestArrayPointer():
|
||||
stdio.printf("=== Test Array Pointer ===\n")
|
||||
data: t.CArray[t.CInt, 8] = t.CArray[t.CInt, 8]()
|
||||
data[0] = 100
|
||||
data[1] = 200
|
||||
data[2] = 300
|
||||
ptr: t.CInt | t.CPtr = data
|
||||
stdio.printf("ptr[0]=%d\n", ptr[0])
|
||||
stdio.printf("ptr[1]=%d\n", ptr[1])
|
||||
stdio.printf("ptr[2]=%d\n", ptr[2])
|
||||
|
||||
|
||||
def TestDynamicString():
|
||||
stdio.printf("=== Test Dynamic String ===\n")
|
||||
name: str = "TransPyC"
|
||||
stdio.printf("Hello %s!\n", name)
|
||||
@@ -0,0 +1,47 @@
|
||||
import t, c
|
||||
import testcheck
|
||||
import class_test
|
||||
|
||||
|
||||
def main() -> t.CInt:
|
||||
testcheck.begin("ClassArrayTest: 类与数组测试")
|
||||
|
||||
testcheck.section("CLASS TESTS")
|
||||
class_test.TestBasicDataClass()
|
||||
testcheck.ok("TestBasicDataClass")
|
||||
class_test.TestPoint3DClass()
|
||||
testcheck.ok("TestPoint3DClass")
|
||||
class_test.TestStudentClass()
|
||||
testcheck.ok("TestStudentClass")
|
||||
class_test.TestCounterClass()
|
||||
testcheck.ok("TestCounterClass")
|
||||
class_test.TestStackAllocation()
|
||||
testcheck.ok("TestStackAllocation")
|
||||
class_test.TestHeapAllocation()
|
||||
testcheck.ok("TestHeapAllocation")
|
||||
class_test.TestHeapObjectWithInit()
|
||||
testcheck.ok("TestHeapObjectWithInit")
|
||||
class_test.TestMultipleStackObjects()
|
||||
testcheck.ok("TestMultipleStackObjects")
|
||||
class_test.TestImplicitInitCall()
|
||||
testcheck.ok("TestImplicitInitCall")
|
||||
class_test.TestClassWithBitFields()
|
||||
testcheck.ok("TestClassWithBitFields")
|
||||
|
||||
testcheck.section("ARRAY TESTS")
|
||||
class_test.TestIntArray()
|
||||
testcheck.ok("TestIntArray")
|
||||
class_test.TestFloatArray()
|
||||
testcheck.ok("TestFloatArray")
|
||||
class_test.TestCharArray()
|
||||
testcheck.ok("TestCharArray")
|
||||
class_test.TestNestedArray()
|
||||
testcheck.ok("TestNestedArray")
|
||||
class_test.TestArrayWithStruct()
|
||||
testcheck.ok("TestArrayWithStruct")
|
||||
class_test.TestArrayPointer()
|
||||
testcheck.ok("TestArrayPointer")
|
||||
class_test.TestDynamicString()
|
||||
testcheck.ok("TestDynamicString")
|
||||
|
||||
return testcheck.end()
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
|
||||
"name": "ClassArrayTest",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": [
|
||||
"-filetype=obj",
|
||||
"-relocation-model=pic"
|
||||
]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": [
|
||||
"-Wl,--allow-multiple-definition",
|
||||
"-lmsvcrt",
|
||||
"-lucrt",
|
||||
"-lpthread",
|
||||
"-lmingwex",
|
||||
"-lkernel32",
|
||||
"-luser32"
|
||||
],
|
||||
"output": "ClassArrayTest.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import t
|
||||
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 失败
|
||||
# ============================================================
|
||||
|
||||
|
||||
# nonlocal 关键字测试:嵌套函数修改外层局部变量
|
||||
def make_counter() -> t.CPtr:
|
||||
count: int = 0
|
||||
|
||||
# 内部函数(闭包)捕获 count
|
||||
def counter() -> int:
|
||||
nonlocal count
|
||||
count = count + 1
|
||||
return count
|
||||
|
||||
return counter
|
||||
|
||||
|
||||
def test_closure_call():
|
||||
"""验证 t.CPtr 函数指针调用"""
|
||||
testcheck.section("Closure call via t.CPtr")
|
||||
f: t.CPtr = make_counter()
|
||||
v: int = f()
|
||||
testcheck.check(v == 1, "f() first call = 1", "expect 1")
|
||||
|
||||
|
||||
def main() -> t.CInt:
|
||||
testcheck.begin("ClosureCallTest: t.CPtr function pointer call")
|
||||
test_closure_call()
|
||||
return testcheck.end()
|
||||
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"name": "ClosureCallTest",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": [
|
||||
"-filetype=obj",
|
||||
"-relocation-model=pic"
|
||||
]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": [
|
||||
"-Wl,--allow-multiple-definition",
|
||||
"-lmsvcrt",
|
||||
"-lucrt",
|
||||
"-lpthread",
|
||||
"-lmingwex",
|
||||
"-lkernel32",
|
||||
"-luser32"
|
||||
],
|
||||
"output": "ClosureCallTest.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
import t
|
||||
import stdio
|
||||
import testcheck
|
||||
|
||||
# ============================================================
|
||||
# Test 1: global 在嵌套函数中
|
||||
# ============================================================
|
||||
g_val: t.CInt = 100
|
||||
|
||||
def outer_modify_global():
|
||||
global g_val
|
||||
def inner_modify():
|
||||
global g_val
|
||||
g_val += 50
|
||||
inner_modify()
|
||||
|
||||
def test_global_in_nested():
|
||||
testcheck.section("Test 1: global in nested function")
|
||||
global g_val
|
||||
g_val = 100
|
||||
outer_modify_global()
|
||||
testcheck.check(g_val == 150, "global nested (g_val == 150)", "global nested (expect 150)")
|
||||
|
||||
# ============================================================
|
||||
# Test 2: nonlocal 在多层嵌套中
|
||||
# ============================================================
|
||||
def test_nonlocal_multi_level():
|
||||
testcheck.section("Test 2: nonlocal multi-level")
|
||||
x: t.CInt = 1
|
||||
def level1():
|
||||
nonlocal x
|
||||
x += 10
|
||||
def level2():
|
||||
nonlocal x
|
||||
x += 100
|
||||
def level3():
|
||||
nonlocal x
|
||||
x += 1000
|
||||
level3()
|
||||
level2()
|
||||
level1()
|
||||
testcheck.check(x == 1111, "nonlocal multi (x == 1111)", "nonlocal multi (expect 1111)")
|
||||
|
||||
# ============================================================
|
||||
# Test 3: global 和 nonlocal 混合
|
||||
# ============================================================
|
||||
g_mixed: t.CInt = 0
|
||||
|
||||
def test_global_nonlocal_mixed():
|
||||
testcheck.section("Test 3: global + nonlocal mixed")
|
||||
global g_mixed
|
||||
g_mixed = 0
|
||||
local_var: t.CInt = 0
|
||||
def modify_both():
|
||||
nonlocal local_var
|
||||
global g_mixed
|
||||
g_mixed += 10
|
||||
local_var += 20
|
||||
modify_both()
|
||||
modify_both()
|
||||
testcheck.check(g_mixed == 20 and local_var == 40, "mixed (global==20 local==40)", "mixed (expect global=20 local=40)")
|
||||
|
||||
# ============================================================
|
||||
# Test 4: lambda 捕获多个变量
|
||||
# ============================================================
|
||||
def test_lambda_multi_capture():
|
||||
testcheck.section("Test 4: lambda multi-capture")
|
||||
a: t.CInt = 10
|
||||
b: t.CInt = 20
|
||||
f = lambda: a + b
|
||||
r: t.CInt = f()
|
||||
testcheck.check(r == 30, "lambda multi-capture (a+b == 30)", "lambda multi-capture (expect 30)")
|
||||
|
||||
# ============================================================
|
||||
# Test 5: lambda 带参数 + 捕获
|
||||
# ============================================================
|
||||
def test_lambda_arg_capture():
|
||||
testcheck.section("Test 5: lambda arg + capture")
|
||||
base: t.CInt = 100
|
||||
add = lambda x: base + x
|
||||
r: t.CInt = add(42)
|
||||
testcheck.check(r == 142, "lambda arg+capture (100+42 == 142)", "lambda arg+capture (expect 142)")
|
||||
|
||||
# ============================================================
|
||||
# Test 6: 嵌套函数返回值
|
||||
# ============================================================
|
||||
def test_nested_return():
|
||||
testcheck.section("Test 6: nested function return")
|
||||
x: t.CInt = 5
|
||||
def double_x() -> t.CInt:
|
||||
nonlocal x
|
||||
x = x * 2
|
||||
return x
|
||||
r: t.CInt = double_x()
|
||||
testcheck.check(r == 10 and x == 10, "nested return (r==10 x==10)", "nested return (expect r=10 x=10)")
|
||||
|
||||
# ============================================================
|
||||
# Test 7: nonlocal 与循环变量
|
||||
# ============================================================
|
||||
def test_nonlocal_loop():
|
||||
testcheck.section("Test 7: nonlocal with loop")
|
||||
total: t.CInt = 0
|
||||
def accumulate(n: t.CInt):
|
||||
nonlocal total
|
||||
for i in range(n):
|
||||
total += i
|
||||
accumulate(5)
|
||||
accumulate(5)
|
||||
# 0+1+2+3+4 = 10, twice = 20
|
||||
testcheck.check(total == 20, "nonlocal loop (total == 20)", "nonlocal loop (expect 20)")
|
||||
|
||||
# ============================================================
|
||||
# Test 8: global 数组操作
|
||||
# ============================================================
|
||||
g_arr: t.CArray[t.CInt, 4] = [0]
|
||||
|
||||
def test_global_array():
|
||||
testcheck.section("Test 8: global array")
|
||||
global g_arr
|
||||
g_arr[0] = 10
|
||||
g_arr[1] = 20
|
||||
g_arr[2] = 30
|
||||
g_arr[3] = 40
|
||||
total: t.CInt = g_arr[0] + g_arr[1] + g_arr[2] + g_arr[3]
|
||||
testcheck.check(total == 100, "global array (total == 100)", "global array (expect 100)")
|
||||
|
||||
# ============================================================
|
||||
# Test 9: 嵌套函数条件调用
|
||||
# ============================================================
|
||||
def test_nested_conditional():
|
||||
testcheck.section("Test 9: nested conditional call")
|
||||
result: t.CInt = 0
|
||||
def set_result(val: t.CInt):
|
||||
nonlocal result
|
||||
result = val
|
||||
if 1:
|
||||
set_result(42)
|
||||
else:
|
||||
set_result(99)
|
||||
testcheck.check(result == 42, "nested conditional (result == 42)", "nested conditional (expect 42)")
|
||||
|
||||
# ============================================================
|
||||
# Test 10: lambda 链式调用
|
||||
# ============================================================
|
||||
def test_lambda_chain():
|
||||
testcheck.section("Test 10: lambda chain")
|
||||
f1 = lambda: 10
|
||||
f2 = lambda: 20
|
||||
r: t.CInt = f1() + f2()
|
||||
testcheck.check(r == 30, "lambda chain (10+20 == 30)", "lambda chain (expect 30)")
|
||||
|
||||
def main() -> t.CInt:
|
||||
testcheck.begin("ClosureAdvancedTest: 高级闭包测试")
|
||||
test_global_in_nested()
|
||||
test_nonlocal_multi_level()
|
||||
test_global_nonlocal_mixed()
|
||||
test_lambda_multi_capture()
|
||||
test_lambda_arg_capture()
|
||||
test_nested_return()
|
||||
test_nonlocal_loop()
|
||||
test_global_array()
|
||||
test_nested_conditional()
|
||||
test_lambda_chain()
|
||||
return testcheck.end()
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
|
||||
"name": "ClosureTest",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": [
|
||||
"-filetype=obj",
|
||||
"-relocation-model=pic"
|
||||
]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": [
|
||||
"-Wl,--allow-multiple-definition",
|
||||
"-lmsvcrt",
|
||||
"-lucrt",
|
||||
"-lpthread",
|
||||
"-lmingwex",
|
||||
"-lkernel32",
|
||||
"-luser32"
|
||||
],
|
||||
"output": "ClosureTest.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
import t
|
||||
import stdio
|
||||
import testcheck
|
||||
|
||||
# ============================================================
|
||||
# Test 1: nonlocal 在条件分支中修改
|
||||
# ============================================================
|
||||
def test_nonlocal_conditional():
|
||||
testcheck.section("Test 1: nonlocal in conditional branches")
|
||||
x: t.CInt = 0
|
||||
def modify(flag: t.CInt):
|
||||
nonlocal x
|
||||
if flag:
|
||||
x += 10
|
||||
else:
|
||||
x += 100
|
||||
modify(1)
|
||||
modify(0)
|
||||
modify(1)
|
||||
testcheck.check(x == 120, "nonlocal conditional (x == 120)", "nonlocal conditional (expect 120)")
|
||||
|
||||
# ============================================================
|
||||
# Test 2: 多个nonlocal变量同时修改
|
||||
# ============================================================
|
||||
def test_nonlocal_multi_var():
|
||||
testcheck.section("Test 2: multiple nonlocal variables")
|
||||
a: t.CInt = 1
|
||||
b: t.CInt = 2
|
||||
c_val: t.CInt = 3
|
||||
def swap_add():
|
||||
nonlocal a, b, c_val
|
||||
tmp: t.CInt = a
|
||||
a = b
|
||||
b = c_val
|
||||
c_val = tmp
|
||||
swap_add()
|
||||
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 在多个函数中交叉修改
|
||||
# ============================================================
|
||||
g_counter: t.CInt = 0
|
||||
|
||||
def inc_global():
|
||||
global g_counter
|
||||
g_counter += 1
|
||||
|
||||
def add_global(n: t.CInt):
|
||||
global g_counter
|
||||
g_counter += n
|
||||
|
||||
def test_global_cross_functions():
|
||||
testcheck.section("Test 3: global cross-function modification")
|
||||
global g_counter
|
||||
g_counter = 0
|
||||
inc_global()
|
||||
inc_global()
|
||||
add_global(10)
|
||||
inc_global()
|
||||
testcheck.check(g_counter == 13, "global cross (g_counter == 13)", "global cross (expect 13)")
|
||||
|
||||
# ============================================================
|
||||
# Test 4: 嵌套函数修改外层局部变量(引用捕获)
|
||||
# ============================================================
|
||||
def test_nested_ref_capture():
|
||||
testcheck.section("Test 4: nested function ref capture")
|
||||
arr: t.CArray[t.CInt, 4] = [0]
|
||||
def fill():
|
||||
nonlocal arr
|
||||
for i in range(4):
|
||||
arr[i] = (i + 1) * 10
|
||||
fill()
|
||||
total: t.CInt = arr[0] + arr[1] + arr[2] + arr[3]
|
||||
testcheck.check(total == 100, "ref capture (total == 100)", "ref capture (expect 100)")
|
||||
|
||||
# ============================================================
|
||||
# Test 5: lambda捕获后修改原变量
|
||||
# ============================================================
|
||||
def test_lambda_capture_then_modify():
|
||||
testcheck.section("Test 5: lambda capture then modify")
|
||||
x: t.CInt = 10
|
||||
f = lambda: x
|
||||
r1: t.CInt = f()
|
||||
x = 20
|
||||
r2: t.CInt = f()
|
||||
testcheck.check(r1 == 10 and r2 == 10, "lambda value capture (before==10 after==10)", "lambda value capture (expect 10 10)")
|
||||
|
||||
# ============================================================
|
||||
# Test 6: 嵌套函数中nonlocal与循环结合
|
||||
# ============================================================
|
||||
def test_nonlocal_loop_accumulate():
|
||||
testcheck.section("Test 6: nonlocal with loop accumulate")
|
||||
sum_val: t.CInt = 0
|
||||
count: t.CInt = 0
|
||||
def add_numbers(n: t.CInt):
|
||||
nonlocal sum_val, count
|
||||
for i in range(1, n + 1):
|
||||
sum_val += i
|
||||
count += 1
|
||||
add_numbers(5) # 1+2+3+4+5=15
|
||||
add_numbers(3) # 1+2+3=6
|
||||
testcheck.check(sum_val == 21 and count == 8, "loop accumulate (sum==21 count==8)", "loop accumulate (expect 21 8)")
|
||||
|
||||
# ============================================================
|
||||
# Test 7: 三层嵌套中每层修改不同变量
|
||||
# ============================================================
|
||||
def test_deep_nested_vars():
|
||||
testcheck.section("Test 7: deep nested different vars")
|
||||
a: t.CInt = 0
|
||||
b: t.CInt = 0
|
||||
c_val: t.CInt = 0
|
||||
def level1():
|
||||
nonlocal a
|
||||
a += 1
|
||||
def level2():
|
||||
nonlocal b
|
||||
b += 10
|
||||
def level3():
|
||||
nonlocal c_val
|
||||
c_val += 100
|
||||
level3()
|
||||
level2()
|
||||
level1()
|
||||
level1()
|
||||
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 在同一嵌套函数中
|
||||
# ============================================================
|
||||
g_state: t.CInt = 0
|
||||
|
||||
def test_global_nonlocal_same_func():
|
||||
testcheck.section("Test 8: global+nonlocal in same nested func")
|
||||
global g_state
|
||||
g_state = 0
|
||||
local_state: t.CInt = 0
|
||||
def worker(n: t.CInt):
|
||||
nonlocal local_state
|
||||
global g_state
|
||||
for i in range(n):
|
||||
g_state += 1
|
||||
local_state += 2
|
||||
worker(5)
|
||||
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带默认参数与捕获
|
||||
# ============================================================
|
||||
def test_lambda_default_and_capture():
|
||||
testcheck.section("Test 9: lambda with arg and capture")
|
||||
base: t.CInt = 100
|
||||
multiply = lambda x: base * x
|
||||
r1: t.CInt = multiply(3)
|
||||
r2: t.CInt = multiply(5)
|
||||
testcheck.check(r1 == 300 and r2 == 500, "lambda arg+capture (100*3==300 100*5==500)", "lambda arg+capture (expect 300 500)")
|
||||
|
||||
# ============================================================
|
||||
# Test 10: 嵌套函数多次调用累积
|
||||
# ============================================================
|
||||
def test_nested_accumulate():
|
||||
testcheck.section("Test 10: nested function accumulate")
|
||||
total: t.CInt = 0
|
||||
def add_val(n: t.CInt):
|
||||
nonlocal total
|
||||
total += n
|
||||
add_val(10)
|
||||
add_val(20)
|
||||
add_val(30)
|
||||
testcheck.check(total == 60, "nested accumulate (total == 60)", "nested accumulate (expect 60)")
|
||||
|
||||
# ============================================================
|
||||
# Test 11: nonlocal在while循环中
|
||||
# ============================================================
|
||||
def test_nonlocal_while():
|
||||
testcheck.section("Test 11: nonlocal in while loop")
|
||||
result: t.CInt = 0
|
||||
def countdown(n: t.CInt):
|
||||
nonlocal result
|
||||
i: t.CInt = n
|
||||
while i > 0:
|
||||
result += i
|
||||
i -= 1
|
||||
countdown(5) # 5+4+3+2+1=15
|
||||
testcheck.check(result == 15, "nonlocal while (result == 15)", "nonlocal while (expect 15)")
|
||||
|
||||
# ============================================================
|
||||
# Test 12: 嵌套函数修改结构体字段
|
||||
# ============================================================
|
||||
class Point:
|
||||
x: t.CInt
|
||||
y: t.CInt
|
||||
|
||||
def test_nested_modify_struct():
|
||||
testcheck.section("Test 12: nested modify struct")
|
||||
p: Point = Point()
|
||||
p.x = 0
|
||||
p.y = 0
|
||||
def translate(dx: t.CInt, dy: t.CInt):
|
||||
nonlocal p
|
||||
p.x += dx
|
||||
p.y += dy
|
||||
translate(10, 20)
|
||||
translate(5, 15)
|
||||
testcheck.check(p.x == 15 and p.y == 35, "nested struct (x==15 y==35)", "nested struct (expect 15 35)")
|
||||
|
||||
def main() -> t.CInt:
|
||||
testcheck.begin("ClosureTest2: Advanced Closure/Lambda/Global/Nonlocal")
|
||||
test_nonlocal_conditional()
|
||||
test_nonlocal_multi_var()
|
||||
test_global_cross_functions()
|
||||
test_nested_ref_capture()
|
||||
test_lambda_capture_then_modify()
|
||||
test_nonlocal_loop_accumulate()
|
||||
test_deep_nested_vars()
|
||||
test_global_nonlocal_same_func()
|
||||
test_lambda_default_and_capture()
|
||||
test_nested_accumulate()
|
||||
test_nonlocal_while()
|
||||
test_nested_modify_struct()
|
||||
return testcheck.end()
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
|
||||
"name": "ClosureTest2",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": [
|
||||
"-filetype=obj",
|
||||
"-relocation-model=pic"
|
||||
]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": [
|
||||
"-Wl,--allow-multiple-definition",
|
||||
"-lmsvcrt",
|
||||
"-lucrt",
|
||||
"-lpthread",
|
||||
"-lmingwex",
|
||||
"-lkernel32",
|
||||
"-luser32"
|
||||
],
|
||||
"output": "ClosureTest2.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import stdio
|
||||
import coro
|
||||
|
||||
|
||||
class MyError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
async def leaf(x: int) -> int:
|
||||
return x + 1
|
||||
|
||||
|
||||
async def boom() -> int:
|
||||
raise MyError("boom msg")
|
||||
return 0
|
||||
|
||||
|
||||
async def task() -> int:
|
||||
fin: int = 0
|
||||
try:
|
||||
fin = 1
|
||||
await boom()
|
||||
finally:
|
||||
fin = fin + 1
|
||||
stdio.printf("finally ran, fin = %d\n", fin)
|
||||
return 99
|
||||
|
||||
|
||||
def main() -> t.CInt:
|
||||
n: t.CInt = 0
|
||||
for i in range(3):
|
||||
tt: coro.Coroutine = c.Addr(task())
|
||||
r: t.CInt = coro.coro_run(tt)
|
||||
e: t.CInt = coro.coro_exception(tt)
|
||||
m: t.CPtr = coro.coro_exception_msg(tt)
|
||||
stdio.printf("[%d] r = %d, exc = %d, msg = %s\n", i, r, e, m)
|
||||
coro.coro_destroy(tt)
|
||||
n = n + 1
|
||||
return 0
|
||||
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
|
||||
"name": "CoroTest",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": [
|
||||
"-filetype=obj"
|
||||
]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": [
|
||||
"-Wl,--allow-multiple-definition",
|
||||
"-lmsvcrt",
|
||||
"-lucrt",
|
||||
"-lpthread",
|
||||
"-lmingwex",
|
||||
"-lkernel32",
|
||||
"-luser32"
|
||||
],
|
||||
"output": "CoroTest.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,299 @@
|
||||
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 次
|
||||
# ============================================================
|
||||
|
||||
# @log 装饰器:打印函数进入/退出,返回 1(正常调用一次)
|
||||
def log(ctx: t.CPtr, func_name: str, phase: t.CInt,
|
||||
args_ptr: t.CPtr,
|
||||
ret_ptr: t.CPtr,
|
||||
decor_args_ptr: t.CPtr) -> t.CInt | t.CExport:
|
||||
if phase == 0:
|
||||
printf("[LOG] >> %s enter\n", func_name)
|
||||
return 1
|
||||
else:
|
||||
printf("[LOG] << %s exit\n", func_name)
|
||||
return 0
|
||||
|
||||
# @trace 装饰器:详细追踪
|
||||
def trace(ctx: t.CPtr, func_name: str, phase: t.CInt,
|
||||
args_ptr: t.CPtr,
|
||||
ret_ptr: t.CPtr,
|
||||
decor_args_ptr: t.CPtr) -> t.CInt | t.CExport:
|
||||
if phase == 0:
|
||||
printf("[TRACE] calling %s...\n", func_name)
|
||||
return 1
|
||||
else:
|
||||
printf("[TRACE] %s returned\n", func_name)
|
||||
return 0
|
||||
|
||||
# @timing 装饰器:使用全局变量记录计时
|
||||
# 注意:理想情况下应使用 ctx 栈帧局部上下文替代全局变量,
|
||||
# 但 Viper 当前前端尚不支持 i8* 到 i32* 的指针转型,
|
||||
# 因此暂时使用全局变量演示计时逻辑
|
||||
_timing_tmp: t.CInt = 0
|
||||
|
||||
def timing(ctx: t.CPtr, func_name: str, phase: t.CInt,
|
||||
args_ptr: t.CPtr,
|
||||
ret_ptr: t.CPtr,
|
||||
decor_args_ptr: t.CPtr) -> t.CInt | t.CExport:
|
||||
global _timing_tmp
|
||||
if phase == 0:
|
||||
_timing_tmp = 100
|
||||
printf("[TIMING] %s start at t=%d\n", func_name, _timing_tmp)
|
||||
return 1
|
||||
else:
|
||||
elapsed: t.CInt = 105 - _timing_tmp
|
||||
printf("[TIMING] %s took %d ms\n", func_name, elapsed)
|
||||
return 0
|
||||
|
||||
# @repeat 装饰器(带参数,流程劫持):循环调用原函数 N 次
|
||||
def repeat(ctx: t.CPtr, func_name: str, phase: t.CInt,
|
||||
args_ptr: t.CPtr,
|
||||
ret_ptr: t.CPtr,
|
||||
decor_args_ptr: t.CPtr) -> t.CInt | t.CExport:
|
||||
if phase == 0:
|
||||
printf("[REPEAT] %s will run 3 times\n", func_name)
|
||||
return 3
|
||||
else:
|
||||
printf("[REPEAT] %s all iterations done\n", func_name)
|
||||
return 0
|
||||
|
||||
# @skip 装饰器:跳过原函数调用(流程劫持,返回 0)
|
||||
_skip_count: t.CInt = 0
|
||||
|
||||
def skip(ctx: t.CPtr, func_name: str, phase: t.CInt,
|
||||
args_ptr: t.CPtr,
|
||||
ret_ptr: t.CPtr,
|
||||
decor_args_ptr: t.CPtr) -> t.CInt | t.CExport:
|
||||
global _skip_count
|
||||
if phase == 0:
|
||||
_skip_count = _skip_count + 1
|
||||
printf("[SKIP] %s skipped! (call #%d)\n", func_name, _skip_count)
|
||||
return 0
|
||||
else:
|
||||
printf("[SKIP] %s post (ret_ptr=%p)\n", func_name, ret_ptr)
|
||||
return 0
|
||||
|
||||
# @count_calls 装饰器:统计函数被调用次数(递归保护测试用)
|
||||
_call_count: t.CInt = 0
|
||||
|
||||
def count_calls(ctx: t.CPtr, func_name: str, phase: t.CInt,
|
||||
args_ptr: t.CPtr,
|
||||
ret_ptr: t.CPtr,
|
||||
decor_args_ptr: t.CPtr) -> t.CInt | t.CExport:
|
||||
global _call_count
|
||||
if phase == 0:
|
||||
_call_count = _call_count + 1
|
||||
printf("[COUNT] %s call #%d\n", func_name, _call_count)
|
||||
return 1
|
||||
else:
|
||||
printf("[COUNT] %s done (total calls: %d)\n", func_name, _call_count)
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 测试 1:单个装饰器 @log
|
||||
# ============================================================
|
||||
|
||||
@log
|
||||
def add(a: t.CInt, b: t.CInt) -> t.CInt | t.CExport:
|
||||
return a + b
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 测试 2:链式装饰器 @log @trace => log(trace(f))
|
||||
# 执行顺序:log_pre → trace_pre → f → trace_post → log_post
|
||||
# ============================================================
|
||||
|
||||
@log
|
||||
@trace
|
||||
def multiply(a: t.CInt, b: t.CInt) -> t.CInt | t.CExport:
|
||||
return a * b
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 测试 3:装饰器修饰 void 返回函数
|
||||
# ============================================================
|
||||
|
||||
@log
|
||||
def greet(name: str) -> t.CVoid | t.CExport:
|
||||
printf("Hello, %s!\n", name)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 测试 4:装饰器修饰无参数函数
|
||||
# ============================================================
|
||||
|
||||
@log
|
||||
def get_value() -> t.CInt | t.CExport:
|
||||
return 42
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 测试 5:@timing 装饰器
|
||||
# ============================================================
|
||||
|
||||
@timing
|
||||
export def compute(x: t.CInt) -> t.CInt:
|
||||
return x * x + 1
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 测试 6:带参数装饰器 @repeat(3) — 流程劫持,循环调用 3 次
|
||||
# ============================================================
|
||||
|
||||
@repeat(3)
|
||||
export def echo(msg: str):
|
||||
printf(" echo: %s\n", msg)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 测试 7:链式 @timing @log
|
||||
# ============================================================
|
||||
|
||||
@timing
|
||||
@log
|
||||
export def power(base: t.CInt, exp: t.CInt) -> t.CInt:
|
||||
result: t.CInt = 1
|
||||
i: t.CInt = 0
|
||||
while i < exp:
|
||||
result = result * base
|
||||
i = i + 1
|
||||
return result
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 测试 8:@skip 装饰器 — 流程劫持,跳过原函数调用
|
||||
# ============================================================
|
||||
|
||||
@skip
|
||||
def dangerous() -> t.CInt | t.CExport:
|
||||
printf("This should NOT be printed!\n")
|
||||
return 999
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 测试 9:@repeat(3) 修饰有返回值的函数
|
||||
# ============================================================
|
||||
|
||||
@repeat(3)
|
||||
def accumulate(x: t.CInt) -> t.CInt | t.CExport:
|
||||
printf(" accumulate(%d)\n", x)
|
||||
return x * 10
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 测试 10:递归装饰保护 — @count_calls 修饰递归函数
|
||||
# v4 递归保护:最外层 wrapper 检查全局标志位,
|
||||
# 递归调用时跳过所有装饰逻辑,仅最外层调用触发装饰器
|
||||
# ============================================================
|
||||
|
||||
@count_calls
|
||||
def factorial(n: t.CInt) -> t.CInt | t.CExport:
|
||||
if n <= 1:
|
||||
return 1
|
||||
return n * factorial(n - 1)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 测试 11:@log 修饰递归函数 — 验证递归保护
|
||||
# 递归保护确保只有最外层调用打印 LOG,内部递归不触发
|
||||
# ============================================================
|
||||
|
||||
@log
|
||||
def fib(n: t.CInt) -> t.CInt | t.CExport:
|
||||
if n <= 1:
|
||||
return n
|
||||
return fib(n - 1) + fib(n - 2)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 主函数
|
||||
# ============================================================
|
||||
|
||||
def main() -> t.CInt | t.CExport:
|
||||
testcheck.begin("Decorator Test v4")
|
||||
|
||||
# 测试 1:单个 @log
|
||||
testcheck.section("Test 1: single @log")
|
||||
r1: t.CInt = 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
|
||||
testcheck.section("Test 2: chained @log @trace")
|
||||
r2: t.CInt = 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 返回
|
||||
testcheck.section("Test 3: @log on void function")
|
||||
greet("Viper")
|
||||
testcheck.ok("@log on void function greet")
|
||||
|
||||
# 测试 4:无参数
|
||||
testcheck.section("Test 4: @log on no-arg function")
|
||||
r4: t.CInt = get_value()
|
||||
printf("get_value() = %d\n", r4)
|
||||
testcheck.check(r4 == 42, "get_value() = 42", "get_value() expect 42")
|
||||
|
||||
# 测试 5:@timing
|
||||
testcheck.section("Test 5: @timing")
|
||||
r5: t.CInt = compute(7)
|
||||
printf("compute(7) = %d\n", r5)
|
||||
testcheck.check(r5 == 50, "compute(7) = 50", "compute(7) expect 50")
|
||||
|
||||
# 测试 6:@repeat(3) — 流程劫持,循环 3 次
|
||||
testcheck.section("Test 6: @repeat(3) flow hijack")
|
||||
echo("hello")
|
||||
testcheck.ok("@repeat(3) flow hijack echo")
|
||||
|
||||
# 测试 7:链式 @timing @log
|
||||
testcheck.section("Test 7: chained @timing @log")
|
||||
r7: t.CInt = 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 — 跳过原函数调用
|
||||
testcheck.section("Test 8: @skip flow hijack")
|
||||
r8: t.CInt = dangerous()
|
||||
printf("dangerous() = %d (should be 0, skipped)\n", r8)
|
||||
testcheck.check(r8 == 0, "dangerous() skipped = 0", "dangerous() expect 0")
|
||||
|
||||
# 测试 9:@repeat(3) 有返回值
|
||||
testcheck.section("Test 9: @repeat(3) with return value")
|
||||
r9: t.CInt = 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
|
||||
testcheck.section("Test 10: recursive decoration protection")
|
||||
global _call_count
|
||||
_call_count = 0
|
||||
r10: t.CInt = factorial(5)
|
||||
printf("factorial(5) = %d (should be 120)\n", r10)
|
||||
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
|
||||
testcheck.section("Test 11: @log on recursive fib")
|
||||
r11: t.CInt = fib(6)
|
||||
printf("fib(6) = %d (should be 8)\n", r11)
|
||||
testcheck.check(r11 == 8, "fib(6) = 8", "fib(6) expect 8")
|
||||
|
||||
return testcheck.end()
|
||||
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"name": "DecoratorTest",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": [
|
||||
"-filetype=obj",
|
||||
"-relocation-model=pic"
|
||||
]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": [
|
||||
"-Wl,--allow-multiple-definition",
|
||||
"-lmsvcrt",
|
||||
"-lucrt",
|
||||
"-lpthread",
|
||||
"-lmingwex",
|
||||
"-lkernel32",
|
||||
"-luser32"
|
||||
],
|
||||
"output": "DecoratorTest.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
import t
|
||||
import stdio
|
||||
import testcheck
|
||||
import remote
|
||||
import vrandom
|
||||
|
||||
|
||||
# 同模块:单个尾随默认值
|
||||
def local_one(x: int, cap: t.CSizeT = 4096) -> t.CSizeT:
|
||||
return cap
|
||||
|
||||
|
||||
# 同模块:多个尾随默认值
|
||||
def local_quad(a: int, b: int = 10, c: int = 20, d: int = 30) -> int:
|
||||
return a + b * 100 + c * 10000 + d * 1000000
|
||||
|
||||
|
||||
def main() -> t.CInt:
|
||||
testcheck.begin("DefaultArgTest: default / named / out-of-order arguments")
|
||||
|
||||
# ① 同模块默认值
|
||||
testcheck.section("same-module defaults")
|
||||
r1: t.CSizeT = 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")
|
||||
|
||||
# ② 跨模块默认值
|
||||
testcheck.section("cross-module defaults")
|
||||
r3: t.CSizeT = remote.one(1)
|
||||
testcheck.check(r3 == 4096, "remote.one(1) cap = 4096", "remote.one(1) cap != 4096")
|
||||
r4: t.CSizeT = remote.write(1, 2, False)
|
||||
testcheck.check(r4 == 4096, "remote.write(1,2,False) cap = 4096", "remote.write(1,2,False) cap != 4096")
|
||||
|
||||
# ③ 显式覆盖默认值
|
||||
testcheck.section("explicit override")
|
||||
r5: t.CSizeT = remote.one(1, 8)
|
||||
testcheck.check(r5 == 8, "remote.one(1,8) cap = 8", "remote.one(1,8) cap != 8")
|
||||
|
||||
# ④ 命名 / 乱序传参
|
||||
testcheck.section("named / out-of-order arguments")
|
||||
r6: t.CSizeT = remote.one(cap = 8, x = 1)
|
||||
testcheck.check(r6 == 8, "remote.one(cap = 8, x = 1) = 8", "remote.one(cap = 8, x = 1) != 8")
|
||||
r7: t.CSizeT = remote.one(x = 1, cap = 8)
|
||||
testcheck.check(r7 == 8, "remote.one(x = 1, cap = 8) = 8", "remote.one(x = 1, cap = 8) != 8")
|
||||
r8: t.CSizeT = remote.one(x = 1)
|
||||
testcheck.check(r8 == 4096, "remote.one(x = 1) cap = 4096", "remote.one(x = 1) cap != 4096")
|
||||
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")
|
||||
|
||||
# ⑤ 多个尾随默认值只给前几个
|
||||
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")
|
||||
r11: int = remote.quad(1, 2)
|
||||
testcheck.check(r11 == 30200201, "remote.quad(1,2) = 30200201", "remote.quad(1,2) != 30200201")
|
||||
r12: int = local_quad(1, 2, 3)
|
||||
testcheck.check(r12 == 30030201, "local_quad(1,2,3) = 30030201", "local_quad(1,2,3) != 30030201")
|
||||
r13: int = remote.quad(1, 2, 3)
|
||||
testcheck.check(r13 == 30030201, "remote.quad(1,2,3) = 30030201", "remote.quad(1,2,3) != 30030201")
|
||||
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/垃圾
|
||||
testcheck.section("include-module defaults")
|
||||
r15: t.CInt = vrandom.randrange(5, 6)
|
||||
testcheck.check(r15 == 5, "vrandom.randrange(5,6) = 5 (step default)", "vrandom.randrange(5,6) != 5")
|
||||
|
||||
return testcheck.end()
|
||||
@@ -0,0 +1,21 @@
|
||||
import t
|
||||
|
||||
|
||||
# 跨模块:单个尾随默认值(对照 includes/json/__writer.vp 的 write 形态)
|
||||
def one(x: int, cap: t.CSizeT = 4096) -> t.CSizeT:
|
||||
return cap
|
||||
|
||||
|
||||
# 跨模块:4 参、最后一个有默认值(与 json.write(pool, val, pretty, cap=4096) 同形)
|
||||
def write(a: int, b: int, pretty: bool, cap: t.CSizeT = 4096) -> t.CSizeT:
|
||||
return cap
|
||||
|
||||
|
||||
# 跨模块:多个尾随默认值
|
||||
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 形态)
|
||||
def many(x: int, y: int, z: int = 1) -> int:
|
||||
return (x + y) * z
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
|
||||
"name": "DefaultArgTest",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": [
|
||||
"-filetype=obj",
|
||||
"-relocation-model=pic"
|
||||
]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": [
|
||||
"-Wl,--allow-multiple-definition",
|
||||
"-lmsvcrt",
|
||||
"-lucrt",
|
||||
"-lpthread",
|
||||
"-lmingwex",
|
||||
"-lkernel32",
|
||||
"-luser32"
|
||||
],
|
||||
"output": "DefaultArgTest.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,421 @@
|
||||
import t, c
|
||||
from t import CInt, CInt32T, CUInt32T, CUInt64T, CFloat64T, CPtr, CChar, CDefine, CUInt16T
|
||||
import viperlib
|
||||
import stdlib
|
||||
import platmacro
|
||||
import w32.win32console
|
||||
import testcheck
|
||||
|
||||
|
||||
# ============================================================
|
||||
# DefineTest - CDefine 宏 / c.CIf / platmacro 专项测试
|
||||
#
|
||||
# 从 TestProject3/App/definetest.vp 独立提取。
|
||||
# 验证: CDefine 常量、宏函数、c.CIf/c.CIfdef/c.CIfndef、
|
||||
# platmacro 平台宏(输出以 print 为准,人工核对)。
|
||||
# ============================================================
|
||||
|
||||
|
||||
MAX_SIZE: t.CDefine = 1024
|
||||
MIN_VAL: t.CDefine = 0
|
||||
MAX_VAL: t.CDefine = 100
|
||||
MASK_BYTE: t.CDefine = 0xFF
|
||||
SHIFT_BITS: t.CDefine = 8
|
||||
PI_INT: t.CDefine = 3
|
||||
ENABLED: t.CDefine = 1
|
||||
DISABLED: t.CDefine = 0
|
||||
PAGE_SIZE: t.CDefine = 4096
|
||||
BUFFER_LEN: t.CDefine = 256
|
||||
|
||||
CODE_SEG: t.CDefine | t.CUInt16T = 0x08
|
||||
DATA_SEG: t.CDefine | t.CUInt16T = 0x10
|
||||
STACK_SEG: t.CDefine | t.CUInt16T = 0x20
|
||||
|
||||
|
||||
def MAKE_FLAG(bit: CInt32T) -> t.CDefine:
|
||||
return 1 << bit
|
||||
|
||||
def CLAMP(x: CInt32T, lo: CInt32T, hi: CInt32T) -> t.CDefine:
|
||||
if x < lo:
|
||||
return lo
|
||||
if x > hi:
|
||||
return hi
|
||||
return x
|
||||
|
||||
def test_basic_define() -> CInt:
|
||||
print(MAX_SIZE)
|
||||
print(MIN_VAL)
|
||||
print(MAX_VAL)
|
||||
print(MASK_BYTE)
|
||||
print(SHIFT_BITS)
|
||||
return 0
|
||||
|
||||
def test_define_arithmetic() -> CInt:
|
||||
a: CInt32T = 10
|
||||
b: CInt32T = a + MAX_SIZE
|
||||
print(b)
|
||||
c_val: CInt32T = (a << SHIFT_BITS) & MASK_BYTE
|
||||
print(c_val)
|
||||
d: CInt32T = MAX_VAL - MIN_VAL
|
||||
print(d)
|
||||
e: CInt32T = PAGE_SIZE / 4
|
||||
print(e)
|
||||
return 0
|
||||
|
||||
def test_define_conditional() -> CInt:
|
||||
mode: CInt32T = ENABLED
|
||||
if mode == ENABLED:
|
||||
print(1)
|
||||
else:
|
||||
print(0)
|
||||
if mode == DISABLED:
|
||||
print(0)
|
||||
else:
|
||||
print(1)
|
||||
val: CInt32T = 50
|
||||
if val > MAX_VAL:
|
||||
print(1)
|
||||
else:
|
||||
print(0)
|
||||
if val < MAX_VAL:
|
||||
print(1)
|
||||
else:
|
||||
print(0)
|
||||
return 0
|
||||
|
||||
def test_define_loop() -> CInt:
|
||||
i: CInt32T = 0
|
||||
while i < MAX_VAL:
|
||||
i = i + 1
|
||||
if i > 10:
|
||||
break
|
||||
print(i)
|
||||
i = 0
|
||||
while i < MAX_SIZE:
|
||||
i = i + PAGE_SIZE
|
||||
if i >= PAGE_SIZE * 4:
|
||||
break
|
||||
print(i)
|
||||
return 0
|
||||
|
||||
def test_typed_define() -> CInt:
|
||||
seg: CUInt16T = CODE_SEG | DATA_SEG | STACK_SEG
|
||||
print(seg)
|
||||
cs: CUInt16T = CODE_SEG
|
||||
print(cs)
|
||||
ds: CUInt16T = DATA_SEG
|
||||
print(ds)
|
||||
return 0
|
||||
|
||||
def test_define_function() -> CInt:
|
||||
flag0 = MAKE_FLAG(0)
|
||||
print(flag0)
|
||||
flag3 = MAKE_FLAG(3)
|
||||
print(flag3)
|
||||
flag7 = MAKE_FLAG(7)
|
||||
print(flag7)
|
||||
return 0
|
||||
|
||||
def test_define_clamp() -> CInt:
|
||||
v1 = CLAMP(50, 0, 100)
|
||||
print(v1)
|
||||
v2 = CLAMP(-10, 0, 100)
|
||||
print(v2)
|
||||
v3 = CLAMP(150, 0, 100)
|
||||
print(v3)
|
||||
return 0
|
||||
|
||||
def test_define_string() -> CInt:
|
||||
buf: CChar | CPtr = CPtr(stdlib.malloc(BUFFER_LEN))
|
||||
viperlib.snprintf(buf, BUFFER_LEN, "MAX_SIZE=%d PAGE=%d MASK=0x%x", MAX_SIZE, PAGE_SIZE, MASK_BYTE)
|
||||
print(buf)
|
||||
stdlib.free(buf)
|
||||
return 0
|
||||
|
||||
def test_define_combined() -> CInt:
|
||||
flags: CUInt32T = MAKE_FLAG(0) | MAKE_FLAG(1) | MAKE_FLAG(2)
|
||||
print(flags)
|
||||
shifted: CUInt32T = MASK_BYTE << SHIFT_BITS
|
||||
print(shifted)
|
||||
total: CUInt32T = PAGE_SIZE + BUFFER_LEN
|
||||
print(total)
|
||||
return 0
|
||||
|
||||
|
||||
def test_cif_basic() -> CInt:
|
||||
if c.CIf(ENABLED):
|
||||
print(1)
|
||||
else:
|
||||
print(0)
|
||||
if c.CIf(DISABLED):
|
||||
print(0)
|
||||
else:
|
||||
print(1)
|
||||
if c.CIf(MAX_SIZE > 512):
|
||||
print(1)
|
||||
else:
|
||||
print(0)
|
||||
if c.CIf(MIN_VAL > 0):
|
||||
print(0)
|
||||
else:
|
||||
print(1)
|
||||
return 0
|
||||
|
||||
def test_cif_elif_else() -> CInt:
|
||||
val: CInt32T = 2
|
||||
if c.CIf(val == 1):
|
||||
print(1)
|
||||
elif c.CIf(val == 2):
|
||||
print(2)
|
||||
elif c.CIf(val == 3):
|
||||
print(3)
|
||||
else:
|
||||
print(0)
|
||||
if c.CIf(val > 10):
|
||||
print(10)
|
||||
elif c.CIf(val > 5):
|
||||
print(5)
|
||||
else:
|
||||
print(val)
|
||||
return 0
|
||||
|
||||
def test_cifdef_cifndef() -> CInt:
|
||||
if c.CIfdef(MAX_SIZE):
|
||||
print(MAX_SIZE)
|
||||
else:
|
||||
print(0)
|
||||
if c.CIfdef(UNDEFINED_MACRO_XYZ):
|
||||
print(0)
|
||||
else:
|
||||
print(1)
|
||||
if c.CIfndef(UNDEFINED_MACRO_XYZ):
|
||||
print(1)
|
||||
else:
|
||||
print(0)
|
||||
if c.CIfndef(MAX_SIZE):
|
||||
print(0)
|
||||
else:
|
||||
print(1)
|
||||
return 0
|
||||
|
||||
def test_cif_platform() -> CInt:
|
||||
if c.CIfdef(_WIN32):
|
||||
print(1)
|
||||
else:
|
||||
print(0)
|
||||
if c.CIfdef(__x86_64__):
|
||||
print(1)
|
||||
else:
|
||||
print(0)
|
||||
if c.CIf(SIZEOF_VOID_P == 8):
|
||||
print(8)
|
||||
elif c.CIf(SIZEOF_VOID_P == 4):
|
||||
print(4)
|
||||
else:
|
||||
print(0)
|
||||
return 0
|
||||
|
||||
def test_cif_nested() -> CInt:
|
||||
if c.CIf(ENABLED):
|
||||
if c.CIf(MAX_SIZE > 512):
|
||||
print(1)
|
||||
else:
|
||||
print(0)
|
||||
if c.CIfdef(PAGE_SIZE):
|
||||
print(PAGE_SIZE)
|
||||
else:
|
||||
print(0)
|
||||
else:
|
||||
print(0)
|
||||
return 0
|
||||
|
||||
def test_cif_expr() -> CInt:
|
||||
if c.CIf(MASK_BYTE & 0x0F):
|
||||
print(1)
|
||||
else:
|
||||
print(0)
|
||||
if c.CIf((MAX_SIZE >> SHIFT_BITS) > 0):
|
||||
print(1)
|
||||
else:
|
||||
print(0)
|
||||
if c.CIf(ENABLED and MAX_SIZE > 0):
|
||||
print(1)
|
||||
else:
|
||||
print(0)
|
||||
if c.CIf(DISABLED or MAX_SIZE > 0):
|
||||
print(1)
|
||||
else:
|
||||
print(0)
|
||||
return 0
|
||||
|
||||
def test_platmacro_platform() -> CInt:
|
||||
if c.CIfdef(platmacro.IS_WINDOWS):
|
||||
print(1)
|
||||
else:
|
||||
print(0)
|
||||
if c.CIf(platmacro.IS_WINDOWS == 1):
|
||||
print(1)
|
||||
else:
|
||||
print(0)
|
||||
if c.CIf(platmacro.IS_LINUX == 0):
|
||||
print(1)
|
||||
else:
|
||||
print(0)
|
||||
if c.CIf(platmacro.IS_X86_64 == 1):
|
||||
print(1)
|
||||
else:
|
||||
print(0)
|
||||
return 0
|
||||
|
||||
def test_platmacro_sizes() -> CInt:
|
||||
print(platmacro.PTR_SIZE)
|
||||
print(platmacro.SIZEOF_INT)
|
||||
print(platmacro.SIZEOF_LONG)
|
||||
print(platmacro.SIZEOF_DOUBLE)
|
||||
print(platmacro.PAGE_SIZE)
|
||||
print(platmacro.CACHE_LINE_SIZE)
|
||||
return 0
|
||||
|
||||
def test_platmacro_endian() -> CInt:
|
||||
if c.CIf(platmacro.IS_LITTLE_ENDIAN == 1):
|
||||
print(1)
|
||||
else:
|
||||
print(0)
|
||||
if c.CIf(platmacro.IS_BIG_ENDIAN == 0):
|
||||
print(1)
|
||||
else:
|
||||
print(0)
|
||||
if c.CIf(platmacro.BYTE_ORDER_LE == 1):
|
||||
print(1)
|
||||
else:
|
||||
print(0)
|
||||
return 0
|
||||
|
||||
def test_platmacro_features() -> CInt:
|
||||
if c.CIf(platmacro.HAS_SSE2 == 1):
|
||||
print(1)
|
||||
else:
|
||||
print(0)
|
||||
if c.CIf(platmacro.HAS_AVX == 1):
|
||||
print(1)
|
||||
else:
|
||||
print(0)
|
||||
if c.CIf(platmacro.HAS_NEON == 0):
|
||||
print(1)
|
||||
else:
|
||||
print(0)
|
||||
return 0
|
||||
|
||||
def test_platmacro_align() -> CInt:
|
||||
print(platmacro.ALIGNOF_INT)
|
||||
print(platmacro.ALIGNOF_PTR)
|
||||
print(platmacro.ALIGNOF_DOUBLE)
|
||||
if c.CIf(platmacro.ALIGNOF_PTR == 8):
|
||||
print(1)
|
||||
else:
|
||||
print(0)
|
||||
return 0
|
||||
|
||||
def test_cifdef_cross_module() -> CInt:
|
||||
if c.CIfdef(platmacro.IS_WINDOWS):
|
||||
if c.CIf(platmacro.PTR_SIZE == 8):
|
||||
print(64)
|
||||
else:
|
||||
print(32)
|
||||
else:
|
||||
print(0)
|
||||
if c.CIfndef(platmacro.IS_ARM64):
|
||||
print(1)
|
||||
else:
|
||||
print(0)
|
||||
if c.CIfdef(platmacro.HAS_AVX2):
|
||||
print(1)
|
||||
else:
|
||||
print(0)
|
||||
return 0
|
||||
|
||||
def test_cifdef_guard() -> CInt:
|
||||
MY_HEADER_GUARD: t.CDefine = 1
|
||||
if c.CIfndef(MY_HEADER_GUARD):
|
||||
print(0)
|
||||
else:
|
||||
print(1)
|
||||
if c.CIfdef(MY_HEADER_GUARD):
|
||||
print(1)
|
||||
else:
|
||||
print(0)
|
||||
return 0
|
||||
|
||||
def test_cifdef_undefined() -> CInt:
|
||||
if c.CIfndef(NONEXISTENT_MACRO_ABC):
|
||||
print(1)
|
||||
else:
|
||||
print(0)
|
||||
if c.CIfndef(THIS_IS_ALSO_NOT_DEFINED):
|
||||
print(1)
|
||||
else:
|
||||
print(0)
|
||||
if c.CIfdef(NONEXISTENT_MACRO_ABC):
|
||||
print(0)
|
||||
else:
|
||||
print(1)
|
||||
return 0
|
||||
|
||||
def test_cifdef_complex() -> CInt:
|
||||
if c.CIfdef(platmacro.IS_WINDOWS) and c.CIf(platmacro.PTR_SIZE == 8):
|
||||
print(1)
|
||||
else:
|
||||
print(0)
|
||||
if c.CIfndef(platmacro.IS_ARM64) and c.CIf(platmacro.IS_X86_64 == 1):
|
||||
print(1)
|
||||
else:
|
||||
print(0)
|
||||
if c.CIfdef(platmacro.HAS_SSE2):
|
||||
if c.CIfdef(platmacro.HAS_AVX):
|
||||
print(2)
|
||||
else:
|
||||
print(1)
|
||||
else:
|
||||
print(0)
|
||||
return 0
|
||||
|
||||
|
||||
def main() -> t.CInt:
|
||||
w32.win32console.SetConsoleCP(65001)
|
||||
w32.win32console.SetConsoleOutputCP(65001)
|
||||
|
||||
testcheck.begin("DefineTest: CDefine 宏与 c.CIf 测试")
|
||||
|
||||
testcheck.section("CDefine 基础")
|
||||
test_basic_define()
|
||||
test_define_arithmetic()
|
||||
test_define_conditional()
|
||||
test_define_loop()
|
||||
test_typed_define()
|
||||
test_define_function()
|
||||
test_define_clamp()
|
||||
test_define_string()
|
||||
test_define_combined()
|
||||
|
||||
testcheck.section("c.CIf")
|
||||
test_cif_basic()
|
||||
test_cif_elif_else()
|
||||
test_cifdef_cifndef()
|
||||
test_cif_platform()
|
||||
test_cif_nested()
|
||||
test_cif_expr()
|
||||
|
||||
testcheck.section("platmacro")
|
||||
test_platmacro_platform()
|
||||
test_platmacro_sizes()
|
||||
test_platmacro_endian()
|
||||
test_platmacro_features()
|
||||
test_platmacro_align()
|
||||
|
||||
testcheck.section("c.CIfdef 综合")
|
||||
test_cifdef_cross_module()
|
||||
test_cifdef_guard()
|
||||
test_cifdef_undefined()
|
||||
test_cifdef_complex()
|
||||
|
||||
return testcheck.end()
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
|
||||
"name": "DefineTest",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": [
|
||||
"-filetype=obj",
|
||||
"-relocation-model=pic"
|
||||
]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": [
|
||||
"-Wl,--allow-multiple-definition",
|
||||
"-lmsvcrt",
|
||||
"-lucrt",
|
||||
"-lpthread",
|
||||
"-lmingwex",
|
||||
"-lkernel32",
|
||||
"-luser32"
|
||||
],
|
||||
"output": "DefineTest.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
from stdint import *
|
||||
import w32.win32console
|
||||
import t, c
|
||||
from t import CInt, CExport
|
||||
import stdio
|
||||
import stdlib
|
||||
import string
|
||||
import memhub
|
||||
import testcheck
|
||||
|
||||
|
||||
def main() -> CInt | CExport:
|
||||
w32.win32console.SetConsoleCP(65001)
|
||||
w32.win32console.SetConsoleOutputCP(65001)
|
||||
|
||||
testcheck.begin("DictTest: 万能 dict (Variant 存储) 测试")
|
||||
|
||||
# 分配内存竞技场
|
||||
arena: bytes = stdlib.malloc(65536)
|
||||
bd: memhub.MemBuddy | t.CPtr = memhub.MemBuddy(arena, 65536)
|
||||
|
||||
# === Test 1: dict set_int / c.Deref 基本操作 ===
|
||||
testcheck.section("Test 1: dict set_int / c.Deref 基本操作")
|
||||
d: dict = dict(bd)
|
||||
d.set_int("alpha", 10)
|
||||
d.set_int("beta", 20)
|
||||
d.set_int("gamma", 30)
|
||||
n: t.CSizeT = len(d)
|
||||
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 字节。
|
||||
p1: t.CPtr = d["alpha"]
|
||||
stdio.printf("p1=%p\n", p1)
|
||||
p2: t.CPtr = d["beta"]
|
||||
stdio.printf("p2=%p\n", p2)
|
||||
p3: t.CPtr = d["gamma"]
|
||||
stdio.printf("p3=%p\n", p3)
|
||||
v1: int = c.Deref((int | t.CPtr)(p1))
|
||||
stdio.printf("v1=%d\n", v1)
|
||||
v2: int = c.Deref((int | t.CPtr)(p2))
|
||||
v3: int = c.Deref((int | t.CPtr)(p3))
|
||||
stdio.printf("alpha=%d beta=%d gamma=%d\n", v1, v2, v3)
|
||||
testcheck.check(v1 == 10, "dict[alpha]==10 OK", "dict[alpha] FAILED")
|
||||
testcheck.check(v2 == 20, "dict[beta]==20 OK", "dict[beta] FAILED")
|
||||
testcheck.check(v3 == 30, "dict[gamma]==30 OK", "dict[gamma] FAILED")
|
||||
|
||||
# === Test 2: 更新已有键 ===
|
||||
testcheck.section("Test 2: 更新已有键")
|
||||
d.set_int("beta", 99)
|
||||
p2b: t.CPtr = d["beta"]
|
||||
v2b: int = c.Deref((int | t.CPtr)(p2b))
|
||||
stdio.printf("beta(updated)=%d\n", v2b)
|
||||
testcheck.check(v2b == 99, "dict update OK", "dict update FAILED")
|
||||
testcheck.check(len(d) == 3, "dict len still 3 OK", "dict len changed FAILED")
|
||||
|
||||
# === Test 3: get with default ===
|
||||
testcheck.section("Test 3: get with default")
|
||||
gv: t.CPtr = d.get("missing", None)
|
||||
testcheck.check(gv == None, "dict get missing OK (None)", "dict get missing FAILED")
|
||||
|
||||
gp: t.CPtr = d.get("alpha", None)
|
||||
ga: int = c.Deref((int | t.CPtr)(gp))
|
||||
stdio.printf("get(alpha)=%d\n", ga)
|
||||
testcheck.check(ga == 10, "dict get existing OK", "dict get existing FAILED")
|
||||
|
||||
# === Test 4: contains ===
|
||||
testcheck.section("Test 4: contains")
|
||||
has_alpha: t.CInt = d.contains("alpha")
|
||||
has_missing: t.CInt = d.contains("missing")
|
||||
stdio.printf("contains(alpha)=%d contains(missing)=%d\n", has_alpha, has_missing)
|
||||
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: 迭代器 ===
|
||||
testcheck.section("Test 5: 迭代器 for key in dict")
|
||||
iter_count: int = 0
|
||||
for key in d:
|
||||
kp: t.CPtr = d[key]
|
||||
val: int = c.Deref((int | t.CPtr)(kp))
|
||||
stdio.printf("dict[%s]=%d\n", key, val)
|
||||
iter_count += 1
|
||||
testcheck.check(iter_count == 3, "dict iter OK (3)", "dict iter FAILED")
|
||||
|
||||
# === Test 6: dict set_str 字符串值 ===
|
||||
testcheck.section("Test 6: dict set_str 字符串值")
|
||||
d2: dict = dict(bd)
|
||||
d2.set_str("name", "Alice")
|
||||
d2.set_str("city", "Beijing")
|
||||
d2.set_str("lang", "TransPyC")
|
||||
n2: t.CSizeT = len(d2)
|
||||
stdio.printf("d2 len=%lu\n", n2)
|
||||
testcheck.check(n2 == 3, "dict set_str len OK (3)", "dict set_str len FAILED")
|
||||
|
||||
name_p: t.CPtr = d2["name"]
|
||||
city_p: t.CPtr = d2["city"]
|
||||
lang_p: t.CPtr = d2["lang"]
|
||||
name: str = name_p
|
||||
city: str = city_p
|
||||
lang: str = lang_p
|
||||
stdio.printf("name=%s city=%s lang=%s\n", name, city, lang)
|
||||
# i8* == 是指针地址比较(C-Like 语义),内容比较需显式 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] 迭代 ===
|
||||
testcheck.section("Test 7: dict 迭代 (str values)")
|
||||
str_iter_count: int = 0
|
||||
for k in d2:
|
||||
svp: t.CPtr = d2[k]
|
||||
sv: str = svp
|
||||
stdio.printf("d2[%s]=%s\n", k, sv)
|
||||
str_iter_count += 1
|
||||
testcheck.check(str_iter_count == 3, "dict str iter OK (3)", "dict str iter FAILED")
|
||||
|
||||
# === Test 8: 扩容测试 ===
|
||||
testcheck.section("Test 8: 扩容测试 (>8 个元素)")
|
||||
d3: dict = dict(bd)
|
||||
i: int = 0
|
||||
while i < 20:
|
||||
key_buf: str = stdlib.malloc(16)
|
||||
stdio.sprintf(key_buf, "key%d", i)
|
||||
d3.set_int(key_buf, i * 100)
|
||||
i += 1
|
||||
n3: t.CSizeT = len(d3)
|
||||
stdio.printf("d3 len=%lu (after 20 inserts)\n", n3)
|
||||
testcheck.check(n3 == 20, "dict expand OK (20)", "dict expand FAILED")
|
||||
|
||||
# 验证几个值
|
||||
k5: str = stdlib.malloc(16)
|
||||
stdio.sprintf(k5, "key5")
|
||||
p5: t.CPtr = d3[k5]
|
||||
v5: int = c.Deref((int | t.CPtr)(p5))
|
||||
stdio.printf("d3[key5]=%d\n", v5)
|
||||
testcheck.check(v5 == 500, "dict expand key5 OK", "dict expand key5 FAILED")
|
||||
|
||||
k15: str = stdlib.malloc(16)
|
||||
stdio.sprintf(k15, "key15")
|
||||
p15: t.CPtr = d3[k15]
|
||||
v15: int = c.Deref((int | t.CPtr)(p15))
|
||||
stdio.printf("d3[key15]=%d\n", v15)
|
||||
testcheck.check(v15 == 1500, "dict expand key15 OK", "dict expand key15 FAILED")
|
||||
|
||||
# === Test 9: JSON dumps ===
|
||||
testcheck.section("Test 9: JSON dumps")
|
||||
pool_mem: bytes = stdlib.malloc(65536)
|
||||
pool: memhub.MemPool = memhub.MemPool(pool_mem, 65536)
|
||||
|
||||
jd: dict = dict(bd)
|
||||
jd.set_int("x", 100)
|
||||
jd.set_int("y", 200)
|
||||
jd.set_int("z", 300)
|
||||
|
||||
json_str: str = jd.dumps(pool)
|
||||
stdio.printf("JSON dumps: %s\n", json_str)
|
||||
testcheck.check(json_str != None, "dumps OK", "dumps FAILED (null)")
|
||||
|
||||
# === Test 10: JSON loads ===
|
||||
testcheck.section("Test 10: JSON loads")
|
||||
jd2: dict = dict(bd)
|
||||
jd2.loads(pool, "{\"x\":1,\"y\":2,\"z\":3}")
|
||||
xp: t.CPtr = jd2["x"]
|
||||
yp: t.CPtr = jd2["y"]
|
||||
zp: t.CPtr = jd2["z"]
|
||||
xv: int = c.Deref((int | t.CPtr)(xp))
|
||||
yv: int = c.Deref((int | t.CPtr)(yp))
|
||||
zv: int = c.Deref((int | t.CPtr)(zp))
|
||||
stdio.printf("loads: x=%d y=%d z=%d\n", xv, yv, zv)
|
||||
testcheck.check(xv == 1, "loads x OK", "loads x FAILED")
|
||||
testcheck.check(yv == 2, "loads y OK", "loads y FAILED")
|
||||
testcheck.check(zv == 3, "loads z OK", "loads z FAILED")
|
||||
|
||||
# === Test 11: JSON dumps (str values) ===
|
||||
testcheck.section("Test 11: JSON dumps (str values)")
|
||||
jd3: dict = dict(bd)
|
||||
jd3.set_str("name", "Alice")
|
||||
jd3.set_str("city", "Beijing")
|
||||
|
||||
json_str2: str = jd3.dumps(pool)
|
||||
stdio.printf("JSON dumps (str): %s\n", json_str2)
|
||||
testcheck.check(json_str2 != None, "dumps str OK", "dumps str FAILED (null)")
|
||||
|
||||
# === Test 12: JSON round-trip ===
|
||||
testcheck.section("Test 12: JSON round-trip")
|
||||
rt: dict = dict(bd)
|
||||
rt.set_int("a", 1)
|
||||
rt.set_int("b", 2)
|
||||
rt_str: str = rt.dumps(pool)
|
||||
stdio.printf("round-trip dump: %s\n", rt_str)
|
||||
rt2: dict = dict(bd)
|
||||
rt2.loads(pool, rt_str)
|
||||
rta_p: t.CPtr = rt2["a"]
|
||||
rtb_p: t.CPtr = rt2["b"]
|
||||
rta: int = c.Deref((int | t.CPtr)(rta_p))
|
||||
rtb: int = c.Deref((int | t.CPtr)(rtb_p))
|
||||
stdio.printf("round-trip: a=%d b=%d\n", rta, rtb)
|
||||
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 ===
|
||||
testcheck.section("Test 13: 嵌套 dict")
|
||||
outer: dict = dict(bd)
|
||||
inner: dict = dict(bd)
|
||||
inner.set_int("a", 1)
|
||||
inner.set_int("b", 2)
|
||||
outer.set_dict("sub", inner)
|
||||
|
||||
sub_p: t.CPtr = outer["sub"]
|
||||
sub: dict = sub_p
|
||||
sa_p: t.CPtr = sub["a"]
|
||||
sb_p: t.CPtr = sub["b"]
|
||||
sa: int = c.Deref((int | t.CPtr)(sa_p))
|
||||
sb: int = c.Deref((int | t.CPtr)(sb_p))
|
||||
stdio.printf("nested: sub.a=%d sub.b=%d\n", sa, sb)
|
||||
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 类型标签 ===
|
||||
testcheck.section("Test 14: get_vtype 类型标签")
|
||||
vt1: t.CInt = d.get_vtype("alpha")
|
||||
vt2: t.CInt = d2.get_vtype("name")
|
||||
vt3: t.CInt = outer.get_vtype("sub")
|
||||
stdio.printf("vtype(alpha)=%d vtype(name)=%d vtype(sub)=%d\n", vt1, vt2, vt3)
|
||||
testcheck.check(vt1 == 1, "vtype int OK", "vtype int FAILED")
|
||||
testcheck.check(vt2 == 4, "vtype str OK", "vtype str FAILED")
|
||||
testcheck.check(vt3 == 5, "vtype dict OK", "vtype dict FAILED")
|
||||
|
||||
stdlib.free(pool_mem)
|
||||
stdlib.free(arena)
|
||||
return testcheck.end()
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
|
||||
"name": "DictTest",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": ["-filetype=obj", "-relocation-model=pic"]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": ["-Wl,--allow-multiple-definition", "-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32"],
|
||||
"output": "DictTest.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
import t
|
||||
import stdio
|
||||
import string
|
||||
import c
|
||||
import testcheck
|
||||
import remote
|
||||
|
||||
|
||||
# 同模块函数(有 docstring)
|
||||
def local_func() -> int:
|
||||
"Local function docstring."
|
||||
return 0
|
||||
|
||||
|
||||
# 同模块函数(无 docstring)
|
||||
def no_doc_func() -> int:
|
||||
return 0
|
||||
|
||||
|
||||
# 同模块类(有 docstring)
|
||||
class LocalClass:
|
||||
"Local class docstring."
|
||||
value: t.CInt
|
||||
|
||||
def local_method(self) -> int:
|
||||
"Local method docstring."
|
||||
return 0
|
||||
|
||||
|
||||
def _check_doc_adaptive(name: str, doc: str, expected: str):
|
||||
"""自适应检查 docstring:非空时验证匹配,空时视为优化剥离"""
|
||||
if doc is None:
|
||||
testcheck.ok(f"{name}: __doc__ optimized out (null)")
|
||||
return
|
||||
if string.strcmp(doc, expected) == 0:
|
||||
testcheck.ok(f"{name}: __doc__ matches")
|
||||
else:
|
||||
testcheck.fail(f"{name}: __doc__ mismatch (got '{doc}', expected '{expected}')")
|
||||
|
||||
|
||||
def _check_doc_null(name: str, doc: str):
|
||||
"""检查 docstring 为 null(无 docstring 的符号)"""
|
||||
if doc is None:
|
||||
testcheck.ok(f"{name}: __doc__ is null")
|
||||
else:
|
||||
testcheck.fail(f"{name}: __doc__ should be null but got '{doc}'")
|
||||
|
||||
|
||||
def test_local_doc():
|
||||
testcheck.section("Local __doc__")
|
||||
_check_doc_adaptive("local_func", local_func.__doc__, "Local function docstring.")
|
||||
_check_doc_adaptive("LocalClass", LocalClass.__doc__, "Local class docstring.")
|
||||
_check_doc_adaptive("LocalClass.local_method", LocalClass.local_method.__doc__, "Local method docstring.")
|
||||
_check_doc_null("no_doc_func", no_doc_func.__doc__)
|
||||
|
||||
|
||||
def test_cross_module_doc():
|
||||
testcheck.section("Cross-module __doc__")
|
||||
_check_doc_adaptive("remote.remote_func", remote.remote_func.__doc__, "Remote function docstring.")
|
||||
_check_doc_adaptive("remote.RemoteClass", remote.RemoteClass.__doc__, "Remote class docstring.")
|
||||
_check_doc_adaptive("remote.RemoteClass.remote_method", remote.RemoteClass.remote_method.__doc__, "Remote method docstring.")
|
||||
_check_doc_null("remote.no_doc_func", remote.no_doc_func.__doc__)
|
||||
|
||||
|
||||
def main() -> t.CInt:
|
||||
testcheck.begin("DocTest: __doc__ magic string test")
|
||||
test_local_doc()
|
||||
test_cross_module_doc()
|
||||
return testcheck.end()
|
||||
@@ -0,0 +1,19 @@
|
||||
import t
|
||||
|
||||
|
||||
def remote_func() -> int:
|
||||
"Remote function docstring."
|
||||
return 0
|
||||
|
||||
|
||||
class RemoteClass:
|
||||
"Remote class docstring."
|
||||
value: t.CInt
|
||||
|
||||
def remote_method(self) -> int:
|
||||
"Remote method docstring."
|
||||
return 0
|
||||
|
||||
|
||||
def no_doc_func() -> int:
|
||||
return 0
|
||||
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
|
||||
"name": "DocTest",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": [
|
||||
"-filetype=obj"
|
||||
]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": [
|
||||
"-Wl,--allow-multiple-definition",
|
||||
"-lmsvcrt",
|
||||
"-lucrt",
|
||||
"-lpthread",
|
||||
"-lmingwex",
|
||||
"-lkernel32",
|
||||
"-luser32"
|
||||
],
|
||||
"output": "DocTest.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 0,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
|
||||
"name": "DocTestOpt",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"temp_dir": "./temp_opt",
|
||||
"output_dir": "./output_opt",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": [
|
||||
"-filetype=obj"
|
||||
]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": [
|
||||
"-Wl,--allow-multiple-definition",
|
||||
"-lmsvcrt",
|
||||
"-lucrt",
|
||||
"-lpthread",
|
||||
"-lmingwex",
|
||||
"-lkernel32",
|
||||
"-luser32"
|
||||
],
|
||||
"output": "DocTestOpt.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,258 @@
|
||||
import t
|
||||
import t as tt
|
||||
import stdio
|
||||
import testcheck
|
||||
|
||||
from t import CEnum as en
|
||||
from t import CUnion as un
|
||||
from t import REnum as ren
|
||||
from t import CStruct as cs
|
||||
from t import CInt as myint
|
||||
from t import CChar, CPtr
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Test 1: from t import CEnum as en; class X(en)
|
||||
# ============================================================
|
||||
enum Color:
|
||||
Red = 0
|
||||
Green = 1
|
||||
Blue = 2
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Test 2: import t as tt; class X(tt.CEnum)
|
||||
# ============================================================
|
||||
enum Status:
|
||||
Ok = 0
|
||||
Error = 1
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Test 3: from t import CUnion as un; class X(un)
|
||||
# ============================================================
|
||||
union Data:
|
||||
i_val: t.CInt
|
||||
f_val: t.CFloat
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Test 4: from t import REnum as ren; class X(ren)
|
||||
# ============================================================
|
||||
renum Opt:
|
||||
class Some:
|
||||
val: myint
|
||||
None_ = 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Test 5: 前向引用检测 — _class_graph 正确识别父类
|
||||
# (注:检测已修复,但成员继承仍需父类先处理)
|
||||
# ============================================================
|
||||
class Parent:
|
||||
a: t.CInt
|
||||
|
||||
def get_a(self) -> t.CInt:
|
||||
return self.a
|
||||
|
||||
|
||||
class Child(Parent):
|
||||
b: t.CInt
|
||||
|
||||
def get_sum(self) -> t.CInt:
|
||||
return self.a + self.b
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Test 6: 多层继承 A -> B -> C,CVTable 向上传播
|
||||
# ============================================================
|
||||
class Base:
|
||||
x: t.CInt
|
||||
|
||||
def base_val(self) -> t.CInt:
|
||||
return self.x
|
||||
|
||||
|
||||
class Mid(Base):
|
||||
y: t.CInt
|
||||
|
||||
def mid_val(self) -> t.CInt:
|
||||
return self.y
|
||||
|
||||
|
||||
class Leaf(Mid):
|
||||
z: t.CInt
|
||||
|
||||
def leaf_val(self) -> t.CInt:
|
||||
return self.z
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Test 7: 类型别名用于注解
|
||||
# ============================================================
|
||||
val: myint = 42
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Test 8: BigEndian 字节序
|
||||
# ============================================================
|
||||
class NetHeader:
|
||||
magic: t.CInt | t.BigEndian
|
||||
length: t.CShort | t.BigEndian
|
||||
normal: t.CInt
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Test 9: import t as tt; tt.CInt 作为类型注解
|
||||
# ============================================================
|
||||
# class TtStruct:
|
||||
# x: tt.CInt
|
||||
# y: tt.CFloat
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Test 10: import t as tt; class X(tt.CStruct)
|
||||
# ============================================================
|
||||
class TtPoint:
|
||||
x: t.CInt
|
||||
y: t.CInt
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Test 11: import t as tt; @tt.Object 装饰器
|
||||
# ============================================================
|
||||
class TtObject:
|
||||
val: t.CInt
|
||||
|
||||
def get_val(self) -> t.CInt:
|
||||
return self.val
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Test 12: from t import CStruct as cs; class X(cs)
|
||||
# ============================================================
|
||||
class CsPoint:
|
||||
x: t.CInt
|
||||
y: t.CInt
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Test 13: import t as tt; class X(tt.CUnion)
|
||||
# ============================================================
|
||||
union TtUnion:
|
||||
a: t.CInt
|
||||
b: t.CFloat
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Test 14: @tt.Object on class without methods (should fail?)
|
||||
# ============================================================
|
||||
class TtEmptyObject:
|
||||
val: t.CInt
|
||||
|
||||
|
||||
def main() -> t.CInt:
|
||||
testcheck.begin("EdgeCaseTest: 类型别名与边界情况测试")
|
||||
|
||||
# Test 1: CEnum alias
|
||||
testcheck.section("Test 1: CEnum alias")
|
||||
c: t.CInt = Color.Green
|
||||
stdio.printf("Test1 CEnum alias: %d\n", c)
|
||||
testcheck.ok("CEnum alias (Color.Green=1)")
|
||||
|
||||
# Test 2: module alias + CEnum
|
||||
testcheck.section("Test 2: module alias + CEnum")
|
||||
s: t.CInt = Status.Error
|
||||
stdio.printf("Test2 t as tt.CEnum: %d\n", s)
|
||||
testcheck.ok("t as tt.CEnum (Status.Error=1)")
|
||||
|
||||
# Test 3: CUnion alias
|
||||
testcheck.section("Test 3: CUnion alias")
|
||||
d: Data = Data()
|
||||
d.i_val = 10
|
||||
d.f_val = 3.14
|
||||
stdio.printf("Test3 CUnion alias: i=%d f=%f\n", d.i_val, d.f_val)
|
||||
testcheck.ok("CUnion alias (i=10 f=3.14)")
|
||||
|
||||
# Test 4: REnum alias
|
||||
testcheck.section("Test 4: REnum alias")
|
||||
o: Opt = Opt.Some(99)
|
||||
match o:
|
||||
case Opt.Some(v):
|
||||
stdio.printf("Test4 REnum alias: val=%d\n", v)
|
||||
case Opt.None_():
|
||||
stdio.printf("Test4 REnum alias: None\n")
|
||||
testcheck.ok("REnum alias (Opt.Some(99))")
|
||||
|
||||
# Test 5: forward reference
|
||||
testcheck.section("Test 5: forward reference")
|
||||
ch: Child = Child()
|
||||
ch.a = 100
|
||||
ch.b = 200
|
||||
stdio.printf("Test5 forward ref: a=%d b=%d sum=%d\n", ch.a, ch.b, ch.get_sum())
|
||||
stdio.printf("Test5 parent method: %d\n", ch.get_a())
|
||||
testcheck.ok("forward ref (a=100 b=200 sum=300)")
|
||||
|
||||
# Test 6: multi-level inheritance
|
||||
testcheck.section("Test 6: multi-level inheritance")
|
||||
lf: Leaf = Leaf()
|
||||
lf.x = 1
|
||||
lf.y = 2
|
||||
lf.z = 3
|
||||
stdio.printf("Test6 multi-inherit: base=%d mid=%d leaf=%d\n",
|
||||
lf.base_val(), lf.mid_val(), lf.leaf_val())
|
||||
testcheck.ok("multi-inherit (base=1 mid=2 leaf=3)")
|
||||
|
||||
# Test 7: type alias in annotation
|
||||
testcheck.section("Test 7: type alias in annotation")
|
||||
stdio.printf("Test7 type alias: val=%d\n", val)
|
||||
testcheck.ok("type alias (val=42)")
|
||||
|
||||
# Test 8: BigEndian
|
||||
testcheck.section("Test 8: BigEndian")
|
||||
nh: NetHeader = NetHeader()
|
||||
nh.magic = 0x12345678
|
||||
nh.length = 256
|
||||
nh.normal = 42
|
||||
stdio.printf("Test8 BigEndian: magic=0x%X length=%d normal=%d\n",
|
||||
nh.magic, nh.length, nh.normal)
|
||||
testcheck.ok("BigEndian (magic=0x12345678 length=256 normal=42)")
|
||||
|
||||
# Test 10: tt.CStruct as base class
|
||||
testcheck.section("Test 10: tt.CStruct as base class")
|
||||
tp: TtPoint = TtPoint()
|
||||
tp.x = 100
|
||||
tp.y = 200
|
||||
stdio.printf("Test10 tt.CStruct: x=%d y=%d\n", tp.x, tp.y)
|
||||
testcheck.ok("tt.CStruct (x=100 y=200)")
|
||||
|
||||
# Test 11: @tt.Object decorator
|
||||
testcheck.section("Test 11: @tt.Object decorator")
|
||||
to: TtObject = TtObject()
|
||||
to.val = 999
|
||||
stdio.printf("Test11 @tt.Object: val=%d\n", to.get_val())
|
||||
testcheck.ok("@tt.Object (val=999)")
|
||||
|
||||
# Test 12: from t import CStruct as cs
|
||||
testcheck.section("Test 12: from t import CStruct as cs")
|
||||
cp: CsPoint = CsPoint()
|
||||
cp.x = 11
|
||||
cp.y = 22
|
||||
stdio.printf("Test12 cs alias: x=%d y=%d\n", cp.x, cp.y)
|
||||
testcheck.ok("cs alias (x=11 y=22)")
|
||||
|
||||
# Test 13: tt.CUnion
|
||||
testcheck.section("Test 13: tt.CUnion")
|
||||
tu: TtUnion = TtUnion()
|
||||
tu.a = 77
|
||||
stdio.printf("Test13 tt.CUnion: a=%d\n", tu.a)
|
||||
testcheck.ok("tt.CUnion (a=77)")
|
||||
|
||||
# Test 14: @tt.Object on empty class
|
||||
testcheck.section("Test 14: @tt.Object on empty class")
|
||||
teo: TtEmptyObject = TtEmptyObject()
|
||||
teo.val = 555
|
||||
stdio.printf("Test14 @tt.Object empty: val=%d\n", teo.val)
|
||||
testcheck.ok("@tt.Object empty (val=555)")
|
||||
|
||||
return testcheck.end()
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
|
||||
"name": "EdgeCaseTest",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": ["-filetype=obj", "-relocation-model=pic"]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": ["-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32", "-Wl,--allow-multiple-definition"],
|
||||
"output": "EdgeCaseTest.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
import t, c
|
||||
from t import CInt, CPtr, CChar, CInt32T, CExport
|
||||
import viperlib
|
||||
import stdlib
|
||||
|
||||
|
||||
class Color(t.CEnum):
|
||||
Red = 0
|
||||
Green = 1
|
||||
Blue = 2
|
||||
|
||||
|
||||
class Option(t.REnum):
|
||||
class Some:
|
||||
value: CInt
|
||||
Empty = 1
|
||||
|
||||
|
||||
class Result(t.REnum):
|
||||
class Ok:
|
||||
value: CInt
|
||||
class Err:
|
||||
msg: t.CChar | CPtr
|
||||
|
||||
|
||||
class GeoShape(t.REnum):
|
||||
class GCircle:
|
||||
radius: CInt
|
||||
class GRect:
|
||||
w: CInt
|
||||
h: CInt
|
||||
class GPoint:
|
||||
x: CInt
|
||||
y: CInt
|
||||
|
||||
|
||||
def enum_main() -> CInt:
|
||||
buf: CChar | CPtr = CPtr(stdlib.malloc(256))
|
||||
|
||||
c1: CInt = Color.Red
|
||||
c2: CInt = Color.Green
|
||||
c3: CInt = Color.Blue
|
||||
viperlib.snprintf(buf, 256, "CEnum: Red=%d Green=%d Blue=%d", c1, c2, c3)
|
||||
print(buf)
|
||||
|
||||
opt: Option = Option.Some(42)
|
||||
match opt:
|
||||
case Option.Some(v):
|
||||
viperlib.snprintf(buf, 256, "Option.Some: value=%d", v)
|
||||
print(buf)
|
||||
case Option.Empty():
|
||||
pass
|
||||
|
||||
res1: Result = Result.Ok(100)
|
||||
match res1:
|
||||
case Result.Ok(v):
|
||||
viperlib.snprintf(buf, 256, "Result.Ok: value=%d", v)
|
||||
print(buf)
|
||||
case Result.Err(e):
|
||||
pass
|
||||
|
||||
res2: Result = Result.Err("not found")
|
||||
match res2:
|
||||
case Result.Ok(v):
|
||||
pass
|
||||
case Result.Err(e):
|
||||
viperlib.snprintf(buf, 256, "Result.Err: msg=%s", e)
|
||||
print(buf)
|
||||
|
||||
s1: GeoShape = GeoShape.GCircle(5)
|
||||
match s1:
|
||||
case GeoShape.GCircle(r):
|
||||
viperlib.snprintf(buf, 256, "GeoShape.GCircle: radius=%d", r)
|
||||
print(buf)
|
||||
case _:
|
||||
pass
|
||||
|
||||
s2: GeoShape = GeoShape.GRect(10, 20)
|
||||
match s2:
|
||||
case GeoShape.GRect(w, h):
|
||||
viperlib.snprintf(buf, 256, "GeoShape.GRect: w=%d h=%d", w, h)
|
||||
print(buf)
|
||||
case _:
|
||||
pass
|
||||
|
||||
s3: GeoShape = GeoShape.GPoint(3, 4)
|
||||
match s3:
|
||||
case GeoShape.GPoint(x, y):
|
||||
viperlib.snprintf(buf, 256, "GeoShape.GPoint: x=%d y=%d", x, y)
|
||||
print(buf)
|
||||
case _:
|
||||
pass
|
||||
|
||||
stdlib.free(buf)
|
||||
return 0
|
||||
@@ -0,0 +1,11 @@
|
||||
import t, c
|
||||
import testcheck
|
||||
import enumtest
|
||||
|
||||
|
||||
def main() -> t.CInt | t.CExport:
|
||||
testcheck.begin("EnumTest: 枚举类型测试")
|
||||
testcheck.section("Enum")
|
||||
enumtest.enum_main()
|
||||
testcheck.ok("Enum 测试完成")
|
||||
return testcheck.end()
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
|
||||
"name": "EnumTest",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": [
|
||||
"-filetype=obj",
|
||||
"-relocation-model=pic"
|
||||
]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": [
|
||||
"-Wl,--allow-multiple-definition",
|
||||
"-lmsvcrt",
|
||||
"-lucrt",
|
||||
"-lpthread",
|
||||
"-lmingwex",
|
||||
"-lkernel32",
|
||||
"-luser32"
|
||||
],
|
||||
"output": "EnumTest.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
from stdint import *
|
||||
import w32.win32console
|
||||
import t, c
|
||||
from t import CInt, CExport
|
||||
import stdio
|
||||
import stdlib
|
||||
import string
|
||||
import testcheck
|
||||
|
||||
|
||||
def main() -> CInt | CExport:
|
||||
w32.win32console.SetConsoleCP(65001)
|
||||
w32.win32console.SetConsoleOutputCP(65001)
|
||||
|
||||
testcheck.begin("== 重载和 is 地址比较测试")
|
||||
|
||||
# === Test 1: str == str 值比较 ===
|
||||
testcheck.section("Test 1: str == str 值比较")
|
||||
s1: str = "hello"
|
||||
s2: str = "hello"
|
||||
s3: str = "world"
|
||||
# i8* == 是指针地址比较(C-Like 语义),内容比较需显式 strcmp
|
||||
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")
|
||||
|
||||
# === Test 2: str != str ===
|
||||
testcheck.section("Test 2: str != str")
|
||||
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 == 字面量 ===
|
||||
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 地址比较 ===
|
||||
testcheck.section("Test 4: str is str address compare")
|
||||
# s1 和 s2 是不同的字符串变量,地址不同
|
||||
testcheck.check(not (s1 is s2), "str is str (diff addr) OK", "str is str (diff addr) FAILED")
|
||||
# s1 is s1 应该为 True(同一变量)
|
||||
testcheck.check(s1 is s1, "str is self OK", "str is self FAILED")
|
||||
|
||||
# === Test 5: int == int ===
|
||||
testcheck.section("Test 5: int == int")
|
||||
i1: int = 42
|
||||
i2: int = 42
|
||||
i3: int = 99
|
||||
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 比较 ===
|
||||
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")
|
||||
|
||||
return testcheck.end()
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
|
||||
"name": "EqTest",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": ["-filetype=obj", "-relocation-model=pic"]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": ["-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32", "-Wl,--allow-multiple-definition"],
|
||||
"output": "EqTest.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
from stdint import *
|
||||
import t, c
|
||||
import stdio
|
||||
import testcheck
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ExpandKeywordsTest - 验证 def 别名关键字 fn/fun/func/function
|
||||
# 语义与 def 完全相同(定义/调用/嵌套/泛型/空函数体)
|
||||
# ============================================================
|
||||
|
||||
# fn: 单参数返回
|
||||
fn add_one(x: t.CInt) -> t.CInt:
|
||||
return x + 1
|
||||
|
||||
|
||||
# fun: 双参数返回
|
||||
fun add_two(a: t.CInt, b: t.CInt) -> t.CInt:
|
||||
return a + b
|
||||
|
||||
|
||||
# func: 浮点参数返回
|
||||
func mul_float(a: t.CDouble, b: t.CDouble) -> t.CDouble:
|
||||
return a * b
|
||||
|
||||
|
||||
# function: 内部用 def 定义再调用(别名与 def 混用)
|
||||
function get_ten() -> t.CInt:
|
||||
def inner() -> t.CInt:
|
||||
return 10
|
||||
return inner()
|
||||
|
||||
|
||||
# fn 泛型(PEP 695 风格类型参数)
|
||||
fn ident[T](x: T) -> T:
|
||||
return x
|
||||
|
||||
|
||||
# fn 空函数体(pass)
|
||||
fn noop():
|
||||
pass
|
||||
|
||||
|
||||
# fun 递归
|
||||
fun fact(n: t.CInt) -> t.CInt:
|
||||
if n <= 1:
|
||||
return 1
|
||||
return n * fact(n - 1)
|
||||
|
||||
|
||||
# func 多语句 + 局部变量
|
||||
func avg3(a: t.CDouble, b: t.CDouble, c: t.CDouble) -> t.CDouble:
|
||||
total: t.CDouble = a + b + c
|
||||
return total / 3.0
|
||||
|
||||
# func12344444 avg3(a: t.CDouble, b: t.CDouble, c: t.CDouble) -> t.CDouble:
|
||||
# total: t.CDouble = a + b + c
|
||||
# return total / 3.0
|
||||
|
||||
|
||||
def main() -> t.CInt:
|
||||
testcheck.begin("ExpandKeywordsTest: fn/fun/func/function")
|
||||
testcheck.section("function def keywords")
|
||||
|
||||
testcheck.check(add_one(41) == 42, "fn add_one(41)==42", "FAIL fn add_one")
|
||||
testcheck.check(add_two(20, 22) == 42, "fun add_two==42", "FAIL fun add_two")
|
||||
testcheck.check(mul_float(2.5, 4.0) == 10.0, "func mul_float==10", "FAIL func mul_float")
|
||||
testcheck.check(get_ten() == 10, "function get_ten==10", "FAIL function get_ten")
|
||||
testcheck.check(ident(7) == 7, "fn ident[T](7)==7", "FAIL fn ident")
|
||||
testcheck.check(fact(5) == 120, "fun fact(5)==120", "FAIL fun fact")
|
||||
testcheck.check(avg3(1.0, 2.0, 3.0) == 2.0, "func avg3==2", "FAIL func avg3")
|
||||
noop()
|
||||
testcheck.check(True, "fn noop() ran", "FAIL fn noop")
|
||||
|
||||
return testcheck.end()
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
|
||||
"name": "ExpandKeywordsTest",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": [
|
||||
"-filetype=obj",
|
||||
"-relocation-model=pic"
|
||||
]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": [
|
||||
"-Wl,--allow-multiple-definition",
|
||||
"-lmsvcrt",
|
||||
"-lucrt",
|
||||
"-lpthread",
|
||||
"-lmingwex",
|
||||
"-lkernel32",
|
||||
"-luser32"
|
||||
],
|
||||
"output": "ExpandKeywordsTest.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import t
|
||||
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 大量依赖冲击上下文。
|
||||
# ============================================================
|
||||
|
||||
|
||||
# Test 1: t.CExtern | t.CExport - 外部声明函数(pass 体)
|
||||
# 声明一个外部函数,翻译器应生成 declare 而非 define
|
||||
def ExternalDecl(x: t.CInt) -> t.CInt | t.CExtern | t.CExport: pass
|
||||
|
||||
|
||||
# Test 2: t.State - 状态声明(等价于 CExtern | CExport)
|
||||
def StateDecl(x: t.CInt) -> t.CInt | t.State: pass
|
||||
|
||||
|
||||
# Test 3: t.State 返回 void
|
||||
def StateVoidDecl() -> t.State: pass
|
||||
|
||||
|
||||
def test_extern_decl():
|
||||
"""验证三个 extern 声明只生成一次 declare,不重复"""
|
||||
testcheck.section("Extern/State declarations (no duplicate)")
|
||||
# 外部声明函数,不调用(应由链接器解析符号)
|
||||
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")
|
||||
|
||||
|
||||
def main() -> t.CInt:
|
||||
testcheck.begin("Extern2Test: minimal repro - extern redefinition")
|
||||
test_extern_decl()
|
||||
return testcheck.end()
|
||||
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"name": "Extern2Test",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": [
|
||||
"-filetype=obj",
|
||||
"-relocation-model=pic"
|
||||
]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": [
|
||||
"-Wl,--allow-multiple-definition",
|
||||
"-lmsvcrt",
|
||||
"-lucrt",
|
||||
"-lpthread",
|
||||
"-lmingwex",
|
||||
"-lkernel32",
|
||||
"-luser32"
|
||||
],
|
||||
"output": "Extern2Test.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,308 @@
|
||||
from stdint import *
|
||||
import w32.win32console
|
||||
import t, c
|
||||
from t import CInt, CExport
|
||||
import _fakeduck
|
||||
import stdio
|
||||
import stdlib
|
||||
import string
|
||||
import memhub
|
||||
import testcheck
|
||||
import _withcontent
|
||||
|
||||
|
||||
def main() -> CInt | CExport:
|
||||
w32.win32console.SetConsoleCP(65001)
|
||||
w32.win32console.SetConsoleOutputCP(65001)
|
||||
|
||||
# FakeDuck 测试: str 类型调用扩展方法 b()
|
||||
a: str = "Hello"
|
||||
|
||||
# Type 通用基类测试: str 变量调用 Type 的方法 type_id()
|
||||
tid: CInt = a.type_id()
|
||||
|
||||
if tid == 99:
|
||||
stdio.printf("Type OK: a.type_id() = %d\n", tid)
|
||||
else:
|
||||
stdio.printf("Type FAIL: a.type_id() = %d\n", tid)
|
||||
|
||||
# 直接字段访问测试: 读取 a.__data__ (应等于 a 本身)
|
||||
data_ptr: str = a.__data__
|
||||
stdio.printf("a.__data__ = %s\n", data_ptr)
|
||||
|
||||
# upper() 测试: 通过 mbuddy 分配内存,返回大写字符串
|
||||
arena: bytes = stdlib.malloc(65536)
|
||||
bd: memhub.MemBuddy | t.CPtr = memhub.MemBuddy(arena, 65536)
|
||||
|
||||
# 直接字段赋值: a.__mbuddy__ = bd (语法糖, 等价于 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)
|
||||
b: str = "World"
|
||||
|
||||
# 直接字段读取: b.__mbuddy__ (应返回 NULL)
|
||||
b_buddy: memhub.MemBuddy | t.CPtr = b.__mbuddy__
|
||||
if t.CInt(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
|
||||
b.__mbuddy__ = bd
|
||||
upper_b: str = b.upper()
|
||||
stdio.printf("upper('World') = %s\n", upper_b)
|
||||
|
||||
# lower() 测试
|
||||
lower_str: str = a.lower()
|
||||
stdio.printf("lower('Hello') = %s\n", lower_str)
|
||||
|
||||
# capitalize() 测试
|
||||
cap_str: str = a.capitalize()
|
||||
stdio.printf("capitalize('Hello') = %s\n", cap_str)
|
||||
|
||||
# swapcase() 测试
|
||||
swap_str: str = a.swapcase()
|
||||
stdio.printf("swapcase('Hello') = %s\n", swap_str)
|
||||
|
||||
# casefold() 测试
|
||||
cf_str: str = a.casefold()
|
||||
stdio.printf("casefold('Hello') = %s\n", cf_str)
|
||||
|
||||
# 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__)
|
||||
u: str = "HELLO"
|
||||
lo: str = "hello"
|
||||
dig: str = "12345"
|
||||
alnum_s: str = "Hello123"
|
||||
space_s: str = " "
|
||||
title_s: str = "Hello World"
|
||||
punct_s: str = "Hello!"
|
||||
|
||||
stdio.printf("isupper('HELLO') = %d\n", u.isupper())
|
||||
stdio.printf("isupper('Hello') = %d\n", a.isupper())
|
||||
stdio.printf("islower('hello') = %d\n", lo.islower())
|
||||
stdio.printf("islower('Hello') = %d\n", a.islower())
|
||||
stdio.printf("isalpha('Hello') = %d\n", a.isalpha())
|
||||
stdio.printf("isalpha('Hello123') = %d\n", alnum_s.isalpha())
|
||||
stdio.printf("isdigit('12345') = %d\n", dig.isdigit())
|
||||
stdio.printf("isdigit('Hello') = %d\n", a.isdigit())
|
||||
stdio.printf("isalnum('Hello123') = %d\n", alnum_s.isalnum())
|
||||
stdio.printf("isalnum('Hello!') = %d\n", punct_s.isalnum())
|
||||
stdio.printf("isspace(' ') = %d\n", space_s.isspace())
|
||||
stdio.printf("isspace('Hello') = %d\n", a.isspace())
|
||||
stdio.printf("isascii('Hello') = %d\n", a.isascii())
|
||||
stdio.printf("istitle('Hello World') = %d\n", title_s.istitle())
|
||||
stdio.printf("istitle('hello world') = %d\n", t_str.istitle())
|
||||
|
||||
# === split() 测试 ===
|
||||
testcheck.begin("FakeDuck split() 测试")
|
||||
|
||||
# Test 1: 基本分割
|
||||
testcheck.section("Test 1: 基本分割 'a,b,c'")
|
||||
s1: str = "a,b,c"
|
||||
s1.__mbuddy__ = bd
|
||||
parts = s1.split(',')
|
||||
n1: t.CSizeT = parts.__len__()
|
||||
stdio.printf("split('a,b,c', ',') len=%lu\n", n1)
|
||||
testcheck.check(n1 == 3, "split len OK (3)", "split len FAILED expect 3")
|
||||
p0: str = parts[0]
|
||||
p1: str = parts[1]
|
||||
p2: str = parts[2]
|
||||
stdio.printf("parts[0]='%s' [1]='%s' [2]='%s'\n", p0, p1, p2)
|
||||
testcheck.check(string.strcmp(p0, "a") == 0, "split[0]=='a' OK", "split[0] FAILED")
|
||||
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: 空字符串分割
|
||||
testcheck.section("Test 2: 无分隔符 'hello'")
|
||||
s2: str = "hello"
|
||||
s2.__mbuddy__ = bd
|
||||
parts2 = s2.split(',')
|
||||
n2: t.CSizeT = parts2.__len__()
|
||||
stdio.printf("split('hello', ',') len=%lu\n", n2)
|
||||
testcheck.check(n2 == 1, "no-delim len OK (1)", "no-delim len FAILED expect 1")
|
||||
h0: str = parts2.get(0)
|
||||
testcheck.check(string.strcmp(h0, "hello") == 0, "no-delim[0]=='hello' OK", "no-delim[0] FAILED")
|
||||
|
||||
# Test 3: 连续分隔符
|
||||
testcheck.section("Test 3: 连续分隔符 'a,,b'")
|
||||
s3: str = "a,,b"
|
||||
s3.__mbuddy__ = bd
|
||||
parts3 = s3.split(',')
|
||||
n3: t.CSizeT = parts3.__len__()
|
||||
stdio.printf("split('a,,b', ',') len=%lu\n", n3)
|
||||
testcheck.check(n3 == 3, "consecutive len OK (3)", "consecutive len FAILED expect 3")
|
||||
e0: str = parts3.get(0)
|
||||
e1: str = parts3.get(1)
|
||||
e2: str = parts3.get(2)
|
||||
stdio.printf("parts[0]='%s' [1]='%s' [2]='%s'\n", e0, e1, e2)
|
||||
testcheck.check(string.strcmp(e0, "a") == 0, "consec[0]=='a' OK", "consec[0] FAILED")
|
||||
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: 空字符串
|
||||
testcheck.section("Test 4: 空字符串 ''")
|
||||
s4: str = ""
|
||||
s4.__mbuddy__ = bd
|
||||
parts4 = s4.split(',')
|
||||
n4: t.CSizeT = parts4.__len__()
|
||||
stdio.printf("split('', ',') len=%lu\n", n4)
|
||||
testcheck.check(n4 == 1, "empty len OK (1)", "empty len FAILED expect 1")
|
||||
|
||||
# Test 5: 空格分割句子
|
||||
testcheck.section("Test 5: 空格分割 'hello world foo'")
|
||||
s5: str = "hello world foo"
|
||||
s5.__mbuddy__ = bd
|
||||
parts5 = s5.split(' ')
|
||||
n5: t.CSizeT = parts5.__len__()
|
||||
stdio.printf("split('hello world foo', ' ') len=%lu\n", n5)
|
||||
testcheck.check(n5 == 3, "space len OK (3)", "space len FAILED expect 3")
|
||||
w0: str = parts5[0]
|
||||
w1: str = parts5[1]
|
||||
w2: str = parts5[2]
|
||||
stdio.printf("words[0]='%s' [1]='%s' [2]='%s'\n", w0, w1, w2)
|
||||
testcheck.check(string.strcmp(w0, "hello") == 0, "space[0]=='hello' OK", "space[0] FAILED")
|
||||
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: 多字符分隔符 '::'
|
||||
testcheck.section("Test 6: 多字符分隔符 '::' on 'a::b::c'")
|
||||
s6: str = "a::b::c"
|
||||
s6.__mbuddy__ = bd
|
||||
parts6 = s6.split("::")
|
||||
n6: t.CSizeT = parts6.__len__()
|
||||
stdio.printf("split('a::b::c', '::') len=%lu\n", n6)
|
||||
testcheck.check(n6 == 3, "multi-colon len OK (3)", "multi-colon len FAILED expect 3")
|
||||
m0: str = parts6[0]
|
||||
m1: str = parts6[1]
|
||||
m2: str = parts6[2]
|
||||
stdio.printf("parts[0]='%s' [1]='%s' [2]='%s'\n", m0, m1, m2)
|
||||
testcheck.check(string.strcmp(m0, "a") == 0, "multi-colon[0]=='a' OK", "multi-colon[0] FAILED")
|
||||
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: 多字符分隔符 ', ' (逗号+空格)
|
||||
testcheck.section("Test 7: 多字符分隔符 ', ' on 'hello, world, foo'")
|
||||
s7: str = "hello, world, foo"
|
||||
s7.__mbuddy__ = bd
|
||||
parts7 = s7.split(", ")
|
||||
n7: t.CSizeT = parts7.__len__()
|
||||
stdio.printf("split('hello, world, foo', ', ') len=%lu\n", n7)
|
||||
testcheck.check(n7 == 3, "comma-space len OK (3)", "comma-space len FAILED expect 3")
|
||||
cs0: str = parts7[0]
|
||||
cs1: str = parts7[1]
|
||||
cs2: str = parts7[2]
|
||||
stdio.printf("parts[0]='%s' [1]='%s' [2]='%s'\n", cs0, cs1, cs2)
|
||||
testcheck.check(string.strcmp(cs0, "hello") == 0, "comma-space[0]=='hello' OK", "comma-space[0] FAILED")
|
||||
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: 多字符分隔符在首尾
|
||||
testcheck.section("Test 8: 多字符分隔符首尾 '::a::b::'")
|
||||
s8: str = "::a::b::"
|
||||
s8.__mbuddy__ = bd
|
||||
parts8 = s8.split("::")
|
||||
n8: t.CSizeT = parts8.__len__()
|
||||
stdio.printf("split('::a::b::', '::') len=%lu\n", n8)
|
||||
testcheck.check(n8 == 4, "edge len OK (4)", "edge len FAILED expect 4")
|
||||
ed0: str = parts8[0]
|
||||
ed1: str = parts8[1]
|
||||
ed2: str = parts8[2]
|
||||
ed3: str = parts8[3]
|
||||
stdio.printf("parts[0]='%s' [1]='%s' [2]='%s' [3]='%s'\n", ed0, ed1, ed2, ed3)
|
||||
testcheck.check(string.strcmp(ed0, "") == 0, "edge[0]=='' OK", "edge[0] FAILED")
|
||||
testcheck.check(string.strcmp(ed1, "a") == 0, "edge[1]=='a' OK", "edge[1] FAILED")
|
||||
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 上下文自动注入测试 ===
|
||||
testcheck.section("Test 9: with 上下文自动注入 __mbuddy__")
|
||||
|
||||
arena2: bytes = stdlib.malloc(65536)
|
||||
with memhub.MemBuddy(arena2, 65536) as bd2:
|
||||
# str 变量在 with 上下文内创建,__mbuddy__ 应自动注入(无需手动赋值)
|
||||
w_str: str = "WithTest"
|
||||
|
||||
# 验证 __mbuddy__ 已自动注入(非 NULL)
|
||||
w_buddy: memhub.MemBuddy | t.CPtr = w_str.__mbuddy__
|
||||
testcheck.check(t.CInt(w_buddy) != 0, "with inject OK: __mbuddy__ auto-injected", "with inject FAIL: __mbuddy__ is NULL")
|
||||
|
||||
# upper() 不需要手动设置 __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__
|
||||
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__
|
||||
w_split_str: str = "x,y,z"
|
||||
w_parts = w_split_str.split(',')
|
||||
w_n: t.CSizeT = 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 变量都获得注入
|
||||
w_str2: str = "Multiple"
|
||||
w_buddy2: memhub.MemBuddy | t.CPtr = w_str2.__mbuddy__
|
||||
testcheck.check(t.CInt(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)
|
||||
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)
|
||||
iter_count += 1
|
||||
testcheck.check(iter_count == 3, "zip(range(len), list) iter OK (3)", "zip(range(len), list) iter FAILED")
|
||||
#for i in range(3):
|
||||
# stdio.printf("list_s[%d]='%s'\n", i, list_s[i])
|
||||
|
||||
# === zip() 内置测试 ===
|
||||
testcheck.section("Test 10: zip(list, list) 元组解包")
|
||||
za: str = "a,b,c"
|
||||
zb: str = "1,2,3"
|
||||
list_a: list[str] = za.split(',')
|
||||
list_b: list[str] = zb.split(',')
|
||||
zip_idx: int = 0
|
||||
for ca, cb in zip(list_a, list_b):
|
||||
stdio.printf("zip[%d]: '%s'='%s'\n", zip_idx, ca, cb)
|
||||
zip_idx += 1
|
||||
testcheck.check(zip_idx == 3, "zip list+list OK (3)", "zip list+list FAILED")
|
||||
|
||||
testcheck.section("Test 11: zip(range, list) 混合迭代")
|
||||
zip_idx2: int = 0
|
||||
for n, s in zip(range(3), list_a):
|
||||
stdio.printf("zip range+list[%d]: %d='%s'\n", zip_idx2, n, s)
|
||||
zip_idx2 += 1
|
||||
testcheck.check(zip_idx2 == 3, "zip range+list OK (3)", "zip range+list FAILED")
|
||||
|
||||
testcheck.section("Test 12: zip(str, str) 字符级并行")
|
||||
sa: str = "abc"
|
||||
sb: str = "123"
|
||||
zip_idx3: int = 0
|
||||
for ch_a, ch_b in zip(sa, sb):
|
||||
stdio.printf("zip str+str[%d]: '%c'%c\n", zip_idx3, ch_a, ch_b)
|
||||
zip_idx3 += 1
|
||||
testcheck.check(zip_idx3 == 3, "zip str+str OK (3)", "zip str+str FAILED")
|
||||
|
||||
stdio.printf("%d\n", " ".isspace())
|
||||
|
||||
stdlib.free(arena2)
|
||||
|
||||
stdlib.free(arena)
|
||||
|
||||
return testcheck.end()
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
|
||||
"name": "FakeDuckTest",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": ["-filetype=obj", "-relocation-model=pic"]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": ["-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32", "-Wl,--allow-multiple-definition"],
|
||||
"static_libs": [
|
||||
"D:/msys64/clang64/lib/clang/22/lib/windows/libclang_rt.asan_dynamic-x86_64.dll.a",
|
||||
"D:/msys64/clang64/lib/clang/22/lib/windows/libclang_rt.asan_dynamic_runtime_thunk-x86_64.a"
|
||||
],
|
||||
"output": "FakeDuckTest.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,395 @@
|
||||
import t, c
|
||||
from t import CInt, CInt32T, CUInt32T, CPtr, CChar, CExport
|
||||
from stdint import *
|
||||
import stdlib
|
||||
import viperlib
|
||||
import w32.win32base
|
||||
import w32.win32file
|
||||
import w32.win32console
|
||||
import w32.fileio
|
||||
from w32.fileio import File, FileW, MODE, FRESULT, SEEK_SET, SEEK_CUR, SEEK_END
|
||||
|
||||
|
||||
BUF_SIZE: t.CDefine = 4096
|
||||
|
||||
|
||||
def fileio_main():
|
||||
buf: bytes = stdlib.malloc(256)
|
||||
write_buf: bytes = stdlib.malloc(BUF_SIZE)
|
||||
read_buf: bytes = stdlib.malloc(BUF_SIZE)
|
||||
bytes_written: ULONG = 0
|
||||
bytes_read: ULONG = 0
|
||||
|
||||
w32.win32console.SetConsoleCP(65001)
|
||||
w32.win32console.SetConsoleOutputCP(65001)
|
||||
|
||||
hFile: w32.win32base.HANDLE = w32.win32file.CreateFileA(
|
||||
"testfile.txt",
|
||||
w32.win32file.GENERIC_WRITE,
|
||||
w32.win32file.FILE_SHARE_READ,
|
||||
None,
|
||||
w32.win32file.CREATE_ALWAYS,
|
||||
w32.win32file.FILE_ATTRIBUTE_NORMAL,
|
||||
None
|
||||
)
|
||||
|
||||
if hFile == w32.win32base.INVALID_HANDLE_VALUE:
|
||||
print("Failed to create file")
|
||||
return
|
||||
|
||||
viperlib.snprintf(write_buf, BUF_SIZE, "Hello from TransPyC Win32 FileIO!\nLine 2: %d + %d = %d\n", 10, 20, 30)
|
||||
write_len: ULONG = 0
|
||||
i: CInt = 0
|
||||
ch: bytes = write_buf
|
||||
while i < BUF_SIZE:
|
||||
if CInt(c.Deref(ch)) == 0:
|
||||
break
|
||||
write_len = write_len + 1
|
||||
i = i + 1
|
||||
ch = ch + 1
|
||||
|
||||
result: BOOL = w32.win32file.WriteFile(hFile, write_buf, write_len, c.Addr(bytes_written), None)
|
||||
if result == 0:
|
||||
print("WriteFile failed")
|
||||
else:
|
||||
viperlib.snprintf(buf, 256, "Written %d bytes to testfile.txt", bytes_written)
|
||||
print(buf)
|
||||
|
||||
w32.win32file.FlushFileBuffers(hFile)
|
||||
w32.win32base.CloseHandle(hFile)
|
||||
|
||||
hFile = w32.win32file.CreateFileA(
|
||||
"testfile.txt",
|
||||
w32.win32file.GENERIC_READ,
|
||||
w32.win32file.FILE_SHARE_READ,
|
||||
None,
|
||||
w32.win32file.OPEN_EXISTING,
|
||||
w32.win32file.FILE_ATTRIBUTE_NORMAL,
|
||||
None
|
||||
)
|
||||
|
||||
if hFile == w32.win32base.INVALID_HANDLE_VALUE:
|
||||
print("Failed to open file for reading")
|
||||
return
|
||||
|
||||
read_len: ULONG = 0
|
||||
result = w32.win32file.ReadFile(hFile, read_buf, BUF_SIZE - 1, c.Addr(read_len), None)
|
||||
if result == 0:
|
||||
print("ReadFile failed")
|
||||
else:
|
||||
viperlib.snprintf(buf, 256, "Read %d bytes from testfile.txt", read_len)
|
||||
print(buf)
|
||||
|
||||
read_ptr: bytes = read_buf
|
||||
read_ptr = read_ptr + read_len
|
||||
c.DerefAs(read_ptr, 0)
|
||||
print("--- File content ---")
|
||||
print(read_buf)
|
||||
print("--- End ---")
|
||||
|
||||
fileSize: ULONG = w32.win32file.GetFileSize(hFile, None)
|
||||
viperlib.snprintf(buf, 256, "File size: %d bytes", fileSize)
|
||||
print(buf)
|
||||
|
||||
w32.win32base.CloseHandle(hFile)
|
||||
|
||||
attrs: ULONG = w32.win32file.GetFileAttributesA("testfile.txt")
|
||||
if attrs == w32.win32base.INVALID_HANDLE_VALUE:
|
||||
print("GetFileAttributes failed")
|
||||
else:
|
||||
viperlib.snprintf(buf, 256, "File attributes: 0x%X", attrs)
|
||||
print(buf)
|
||||
|
||||
w32.win32file.DeleteFileA("testfile.txt")
|
||||
print("File deleted")
|
||||
|
||||
stdlib.free(write_buf)
|
||||
stdlib.free(read_buf)
|
||||
|
||||
print("=== OOP FileIO: with context manager ===")
|
||||
fileio_with_test()
|
||||
|
||||
print("=== OOP FileIO: f handle style ===")
|
||||
fileio_handle_test()
|
||||
|
||||
print("=== OOP FileIO: RP/WP/AP modes ===")
|
||||
fileio_rw_test()
|
||||
|
||||
|
||||
def fileio_with_test():
|
||||
buf: bytes = stdlib.malloc(256)
|
||||
write_buf: bytes = stdlib.malloc(BUF_SIZE)
|
||||
read_buf: bytes = stdlib.malloc(BUF_SIZE)
|
||||
|
||||
with File("oop_with.txt", MODE.W) as f:
|
||||
viperlib.snprintf(write_buf, BUF_SIZE, "with context manager test!\nLine 2: %d\n", 42)
|
||||
n: LONG = f.write_str(write_buf)
|
||||
if n < 0:
|
||||
print("[with] write failed")
|
||||
else:
|
||||
viperlib.snprintf(buf, 256, "[with] wrote %d bytes", n)
|
||||
print(buf)
|
||||
|
||||
with File("oop_with.txt", MODE.R) as f:
|
||||
n = f.read_all(read_buf, BUF_SIZE)
|
||||
if n < 0:
|
||||
print("[with] read failed")
|
||||
else:
|
||||
viperlib.snprintf(buf, 256, "[with] read %d bytes", n)
|
||||
print(buf)
|
||||
print("[with] content:")
|
||||
print(read_buf)
|
||||
|
||||
with File("oop_with.txt", MODE.R) as f:
|
||||
line1_len: LONG = f.readline(buf, 256)
|
||||
viperlib.snprintf(read_buf, BUF_SIZE, "[with] Line1(%d): ", line1_len)
|
||||
print(read_buf)
|
||||
print(buf)
|
||||
line2_len: LONG = f.readline(buf, 256)
|
||||
viperlib.snprintf(read_buf, BUF_SIZE, "[with] Line2(%d): ", line2_len)
|
||||
print(read_buf)
|
||||
print(buf)
|
||||
|
||||
with File("oop_with.txt", MODE.A) as f:
|
||||
f.write_str("Appended line!\n")
|
||||
|
||||
with File("oop_with.txt", MODE.R) as f:
|
||||
n = f.read_all(read_buf, BUF_SIZE)
|
||||
print("[with] after append:")
|
||||
print(read_buf)
|
||||
|
||||
with File("oop_with.txt", MODE.R) as f:
|
||||
sz: LONGLONG = f.size()
|
||||
pos: LONG = f.tell()
|
||||
viperlib.snprintf(buf, 256, "[with] Size=%lld Pos=%d", sz, pos)
|
||||
print(buf)
|
||||
f.seek(5, SEEK_SET)
|
||||
pos = f.tell()
|
||||
viperlib.snprintf(buf, 256, "[with] After seek: Pos=%d", pos)
|
||||
print(buf)
|
||||
|
||||
w32.win32file.DeleteFileA("oop_with.txt")
|
||||
print("[with] test file deleted")
|
||||
|
||||
stdlib.free(buf)
|
||||
stdlib.free(write_buf)
|
||||
stdlib.free(read_buf)
|
||||
|
||||
|
||||
def fileio_handle_test():
|
||||
buf: bytes = stdlib.malloc(256)
|
||||
write_buf: bytes = stdlib.malloc(BUF_SIZE)
|
||||
read_buf: bytes = stdlib.malloc(BUF_SIZE)
|
||||
|
||||
fw: File = File("oop_handle.txt", MODE.W)
|
||||
viperlib.snprintf(write_buf, BUF_SIZE, "f handle style test!\nLine 2: %d\n", 99)
|
||||
n: LONG = fw.write_str(write_buf)
|
||||
viperlib.snprintf(buf, 256, "[handle] wrote %d bytes", n)
|
||||
print(buf)
|
||||
fw.flush()
|
||||
fw.close()
|
||||
|
||||
fr: File = File("oop_handle.txt", MODE.R)
|
||||
n = fr.read_all(read_buf, BUF_SIZE)
|
||||
viperlib.snprintf(buf, 256, "[handle] read %d bytes", n)
|
||||
print(buf)
|
||||
print("[handle] content:")
|
||||
print(read_buf)
|
||||
fr.close()
|
||||
|
||||
fr2: File = File("oop_handle.txt", MODE.R)
|
||||
line1_len: LONG = fr2.readline(buf, 256)
|
||||
viperlib.snprintf(read_buf, BUF_SIZE, "[handle] Line1(%d): ", line1_len)
|
||||
print(read_buf)
|
||||
print(buf)
|
||||
line2_len: LONG = fr2.readline(buf, 256)
|
||||
viperlib.snprintf(read_buf, BUF_SIZE, "[handle] Line2(%d): ", line2_len)
|
||||
print(read_buf)
|
||||
print(buf)
|
||||
fr2.close()
|
||||
|
||||
fa: File = File("oop_handle.txt", MODE.A)
|
||||
fa.write_str("Appended by handle!\n")
|
||||
fa.close()
|
||||
|
||||
fr3: File = File("oop_handle.txt", MODE.R)
|
||||
n = fr3.read_all(read_buf, BUF_SIZE)
|
||||
print("[handle] after append:")
|
||||
print(read_buf)
|
||||
fr3.close()
|
||||
|
||||
fr4: File = File("oop_handle.txt", MODE.R)
|
||||
sz: LONGLONG = fr4.size()
|
||||
pos: LONG = fr4.tell()
|
||||
viperlib.snprintf(buf, 256, "[handle] Size=%lld Pos=%d", sz, pos)
|
||||
print(buf)
|
||||
fr4.seek(5, SEEK_SET)
|
||||
pos = fr4.tell()
|
||||
viperlib.snprintf(buf, 256, "[handle] After seek: Pos=%d", pos)
|
||||
print(buf)
|
||||
fr4.close()
|
||||
|
||||
w32.win32file.DeleteFileA("oop_handle.txt")
|
||||
print("[handle] test file deleted")
|
||||
|
||||
stdlib.free(buf)
|
||||
stdlib.free(write_buf)
|
||||
stdlib.free(read_buf)
|
||||
|
||||
|
||||
def fileio_rw_test():
|
||||
buf: bytes = stdlib.malloc(256)
|
||||
|
||||
fw: File = File("rw_test.txt", MODE.W)
|
||||
fw.write_str("original content\n")
|
||||
fw.close()
|
||||
|
||||
frp: File = File("rw_test.txt", MODE.RP)
|
||||
n: LONG = frp.read_all(buf, 256)
|
||||
viperlib.snprintf(buf, 256, "[rp] read %d bytes", n)
|
||||
print(buf)
|
||||
|
||||
frp.seek(0, SEEK_END)
|
||||
frp.write_str("appended via RP\n")
|
||||
frp.seek(0, SEEK_SET)
|
||||
n = frp.read_all(buf, 256)
|
||||
print("[rp] after RP append:")
|
||||
print(buf)
|
||||
frp.close()
|
||||
|
||||
fwp: File = File("rw_test.txt", MODE.WP)
|
||||
fwp.write_str("truncated + new\n")
|
||||
fwp.seek(0, SEEK_SET)
|
||||
n = fwp.read_all(buf, 256)
|
||||
print("[wp] WP (truncate+read):")
|
||||
print(buf)
|
||||
fwp.close()
|
||||
|
||||
fap: File = File("rw_test.txt", MODE.AP)
|
||||
fap.write_str("a+ appended\n")
|
||||
fap.seek(0, SEEK_SET)
|
||||
n = fap.read_all(buf, 256)
|
||||
print("[ap] AP (append+read):")
|
||||
print(buf)
|
||||
fap.close()
|
||||
|
||||
w32.win32file.DeleteFileA("rw_test.txt")
|
||||
print("[rw] test file deleted")
|
||||
|
||||
print("=== OOP FileIO: wide char (u\"...\") ===")
|
||||
fileio_wide_test()
|
||||
|
||||
stdlib.free(buf)
|
||||
|
||||
|
||||
def fileio_wide_test():
|
||||
buf: bytes = stdlib.malloc(256)
|
||||
|
||||
fw: File = File("wide_test.txt", MODE.W)
|
||||
fw.write_str("wide char test\n")
|
||||
fw.close()
|
||||
|
||||
fw2: FileW = FileW(u"wide_test.txt", MODE.R)
|
||||
n: LONG = fw2.read_all(buf, 256)
|
||||
viperlib.snprintf(buf, 256, "[wide] read %d bytes", n)
|
||||
print(buf)
|
||||
fw2.close()
|
||||
|
||||
w32.win32file.DeleteFileA("wide_test.txt")
|
||||
print("[wide] test file deleted")
|
||||
|
||||
stdlib.free(buf)
|
||||
|
||||
print("=== OOP FileIO: Chinese filename & content (u\"...\" = WCHAR_T) ===")
|
||||
fileio_chinese_test()
|
||||
|
||||
|
||||
def fileio_chinese_test():
|
||||
buf: bytes = stdlib.malloc(512)
|
||||
bytes_written: ULONG = 0
|
||||
|
||||
# === T1: Chinese filename (WCHAR_T) + ANSI content ===
|
||||
print("[chinese] T1: Chinese filename + ANSI content")
|
||||
fw: FileW = FileW(u"中文文件.txt", MODE.W)
|
||||
if fw.closed:
|
||||
print("[chinese] T1: create failed")
|
||||
else:
|
||||
fw.write_str("Hello from Chinese filename!\n")
|
||||
fw.close()
|
||||
|
||||
fr: FileW = FileW(u"中文文件.txt", MODE.R)
|
||||
n: LONG = fr.read_all(buf, 512)
|
||||
viperlib.snprintf(buf, 256, "[chinese] T1: read %d bytes", n)
|
||||
print(buf)
|
||||
print("[chinese] T1 content:")
|
||||
print(buf)
|
||||
fr.close()
|
||||
|
||||
w32.win32file.DeleteFileW(u"中文文件.txt")
|
||||
print("[chinese] T1: deleted")
|
||||
|
||||
# === T2: Chinese filename + Chinese wide content (WCHAR_T) ===
|
||||
print("[chinese] T2: Chinese filename + Chinese wide content")
|
||||
fw2: FileW = FileW(u"中文内容.txt", MODE.W)
|
||||
if fw2.closed:
|
||||
print("[chinese] T2: create failed")
|
||||
else:
|
||||
# u"你好世界\n" = 5 WCHARs = 10 bytes (UTF-16LE)
|
||||
w32.win32file.WriteFile(fw2.handle, u"你好世界\n", 10, c.Addr(bytes_written), None)
|
||||
viperlib.snprintf(buf, 256, "[chinese] T2: wrote %d WCHAR bytes", bytes_written)
|
||||
print(buf)
|
||||
fw2.close()
|
||||
|
||||
fr2: FileW = FileW(u"中文内容.txt", MODE.R)
|
||||
n = fr2.read_all(buf, 512)
|
||||
viperlib.snprintf(buf, 256, "[chinese] T2: read %d bytes (UTF-16LE)", n)
|
||||
print(buf)
|
||||
fr2.close()
|
||||
|
||||
w32.win32file.DeleteFileW(u"中文内容.txt")
|
||||
print("[chinese] T2: deleted")
|
||||
|
||||
# === T3: Chinese filename + mixed ANSI + wide content ===
|
||||
print("[chinese] T3: Chinese filename + mixed content")
|
||||
fw3: FileW = FileW(u"混合测试.txt", MODE.WP)
|
||||
if fw3.closed:
|
||||
print("[chinese] T3: create failed")
|
||||
else:
|
||||
fw3.write_str("ASCII line\n")
|
||||
# u"中文行\n" = 4 WCHARs = 8 bytes (UTF-16LE)
|
||||
w32.win32file.WriteFile(fw3.handle, u"中文行\n", 8, c.Addr(bytes_written), None)
|
||||
fw3.seek(0, SEEK_SET)
|
||||
n: LONG = fw3.read_all(buf, 512)
|
||||
viperlib.snprintf(buf, 256, "[chinese] T3: total %d bytes", n)
|
||||
print(buf)
|
||||
fw3.close()
|
||||
|
||||
w32.win32file.DeleteFileW(u"混合测试.txt")
|
||||
print("[chinese] T3: deleted")
|
||||
|
||||
# === T4: Chinese filename + Chinese content via WriteConsoleW ===
|
||||
print("[chinese] T4: Write wide content and print via WriteConsoleW")
|
||||
fw4: FileW = FileW(u"控制台测试.txt", MODE.W)
|
||||
if fw4.closed:
|
||||
print("[chinese] T4: create failed")
|
||||
else:
|
||||
# u"你好,世界!\n" = 7 WCHARs = 14 bytes (UTF-16LE)
|
||||
w32.win32file.WriteFile(fw4.handle, u"你好,世界!\n", 14, c.Addr(bytes_written), None)
|
||||
viperlib.snprintf(buf, 256, "[chinese] T4: wrote %d WCHAR bytes", bytes_written)
|
||||
print(buf)
|
||||
fw4.close()
|
||||
|
||||
fr4: FileW = FileW(u"控制台测试.txt", MODE.R)
|
||||
n = fr4.read_all(buf, 512)
|
||||
viperlib.snprintf(buf, 256, "[chinese] T4: read %d bytes", n)
|
||||
print(buf)
|
||||
# Print wide content to console using WriteConsoleW
|
||||
chars_written: ULONG = 0
|
||||
hOut: w32.win32base.HANDLE = w32.win32file.GetStdHandle(w32.win32file.STD_OUTPUT_HANDLE)
|
||||
w32.win32console.WriteConsoleW(hOut, u"你好,世界!\n", 7, c.Addr(chars_written), None)
|
||||
fr4.close()
|
||||
|
||||
w32.win32file.DeleteFileW(u"控制台测试.txt")
|
||||
print("[chinese] T4: deleted")
|
||||
|
||||
stdlib.free(buf)
|
||||
@@ -0,0 +1,11 @@
|
||||
import t, c
|
||||
import testcheck
|
||||
import fileiotest
|
||||
|
||||
|
||||
def main() -> t.CInt | t.CExport:
|
||||
testcheck.begin("FileIoTest: Win32 FileIO 测试")
|
||||
testcheck.section("Win32 FileIO")
|
||||
fileiotest.fileio_main()
|
||||
testcheck.ok("Win32 FileIO 测试完成")
|
||||
return testcheck.end()
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
|
||||
"name": "FileIoTest",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": [
|
||||
"-filetype=obj",
|
||||
"-relocation-model=pic"
|
||||
]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": [
|
||||
"-Wl,--allow-multiple-definition",
|
||||
"-lmsvcrt",
|
||||
"-lucrt",
|
||||
"-lpthread",
|
||||
"-lmingwex",
|
||||
"-lkernel32",
|
||||
"-luser32"
|
||||
],
|
||||
"output": "FileIoTest.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
import t
|
||||
import c
|
||||
import stdio
|
||||
import stdlib
|
||||
import string
|
||||
import memhub
|
||||
import testcheck
|
||||
|
||||
|
||||
def test_for_in_range():
|
||||
testcheck.section("Test 1: for i in range(n)")
|
||||
s: t.CInt = 0
|
||||
for i in range(10):
|
||||
s += i
|
||||
testcheck.check(s == 45, "range sum OK (45)", "range sum FAILED expect 45")
|
||||
|
||||
|
||||
def test_for_in_str():
|
||||
testcheck.section("Test 2: for ch in str")
|
||||
cnt: t.CInt = 0
|
||||
for ch in "hello":
|
||||
cnt += 1
|
||||
testcheck.check(cnt == 5, "str iter OK (5)", "str iter FAILED expect 5")
|
||||
|
||||
|
||||
def test_for_in_list():
|
||||
testcheck.section("Test 3: for v in list[str]")
|
||||
arena: bytes = stdlib.malloc(65536)
|
||||
bd: memhub.MemBuddy | t.CPtr = memhub.MemBuddy(arena, 65536)
|
||||
lst: list[str] = list[str](bd)
|
||||
lst.append("x")
|
||||
lst.append("y")
|
||||
lst.append("z")
|
||||
lst.append("w")
|
||||
total: t.CInt = 0
|
||||
for v in lst:
|
||||
total += 1
|
||||
testcheck.check(total == 4, "list iter OK (4)", "list iter FAILED expect 4")
|
||||
stdlib.free(arena)
|
||||
|
||||
|
||||
def test_zip_list_list():
|
||||
testcheck.section("Test 4: zip(list, list)")
|
||||
arena: bytes = stdlib.malloc(65536)
|
||||
bd: memhub.MemBuddy | t.CPtr = memhub.MemBuddy(arena, 65536)
|
||||
la: list[str] = list[str](bd)
|
||||
la.append("a")
|
||||
la.append("b")
|
||||
la.append("c")
|
||||
lb: list[str] = list[str](bd)
|
||||
lb.append("1")
|
||||
lb.append("2")
|
||||
lb.append("3")
|
||||
cnt: t.CInt = 0
|
||||
for ca, cb in zip(la, lb):
|
||||
stdio.printf("zip[%d]: '%s'='%s'\n", cnt, ca, cb)
|
||||
cnt += 1
|
||||
testcheck.check(cnt == 3, "zip list+list OK (3)", "zip list+list FAILED")
|
||||
stdlib.free(arena)
|
||||
|
||||
|
||||
def test_zip_range_list():
|
||||
testcheck.section("Test 5: zip(range, list)")
|
||||
arena: bytes = stdlib.malloc(65536)
|
||||
bd: memhub.MemBuddy | t.CPtr = memhub.MemBuddy(arena, 65536)
|
||||
lst: list[str] = list[str](bd)
|
||||
lst.append("p")
|
||||
lst.append("q")
|
||||
lst.append("r")
|
||||
cnt: t.CInt = 0
|
||||
for n, v in zip(range(3), lst):
|
||||
stdio.printf("zip range+list[%d]: %d='%s'\n", cnt, n, v)
|
||||
cnt += 1
|
||||
testcheck.check(cnt == 3, "zip range+list OK (3)", "zip range+list FAILED")
|
||||
stdlib.free(arena)
|
||||
|
||||
|
||||
def test_zip_str_str():
|
||||
testcheck.section("Test 6: zip(str, str)")
|
||||
sa: str = "abc"
|
||||
sb: str = "123"
|
||||
cnt: t.CInt = 0
|
||||
for ca, cb in zip(sa, sb):
|
||||
stdio.printf("zip str+str[%d]: '%c'%c\n", cnt, ca, cb)
|
||||
cnt += 1
|
||||
testcheck.check(cnt == 3, "zip str+str OK (3)", "zip str+str FAILED")
|
||||
|
||||
|
||||
def test_zip_range_len_list():
|
||||
testcheck.section("Test 7: zip(range(len), list)")
|
||||
arena: bytes = stdlib.malloc(65536)
|
||||
bd: memhub.MemBuddy | t.CPtr = memhub.MemBuddy(arena, 65536)
|
||||
lst: list[str] = list[str](bd)
|
||||
lst.append("www")
|
||||
lst.append("gvsds")
|
||||
lst.append("com")
|
||||
cnt: t.CInt = 0
|
||||
for idx, v in zip(range(len(lst)), lst):
|
||||
stdio.printf("lst[%d]='%s'\n", idx, v)
|
||||
cnt += 1
|
||||
testcheck.check(cnt == 3, "zip(range(len),list) OK (3)", "zip(range(len),list) FAILED")
|
||||
stdlib.free(arena)
|
||||
|
||||
|
||||
def test_enumerate_list():
|
||||
testcheck.section("Test 8: enumerate(list)")
|
||||
arena: bytes = stdlib.malloc(65536)
|
||||
bd: memhub.MemBuddy | t.CPtr = memhub.MemBuddy(arena, 65536)
|
||||
lst: list[str] = list[str](bd)
|
||||
lst.append("alpha")
|
||||
lst.append("beta")
|
||||
lst.append("gamma")
|
||||
cnt: t.CInt = 0
|
||||
last_idx: t.CInt = -1
|
||||
for idx, v in enumerate(lst):
|
||||
stdio.printf("enum[%d]='%s'\n", idx, v)
|
||||
last_idx = idx
|
||||
cnt += 1
|
||||
testcheck.check(cnt == 3, "enumerate list OK (3)", "enumerate list FAILED")
|
||||
testcheck.check(last_idx == 2, "enumerate last_idx OK (2)", "enumerate last_idx FAILED expect 2")
|
||||
stdlib.free(arena)
|
||||
|
||||
|
||||
def test_enumerate_str():
|
||||
testcheck.section("Test 9: enumerate(str)")
|
||||
cnt: t.CInt = 0
|
||||
last_idx: t.CInt = -1
|
||||
for idx, ch in enumerate("ABCD"):
|
||||
stdio.printf("enum str[%d]='%c'\n", idx, ch)
|
||||
last_idx = idx
|
||||
cnt += 1
|
||||
testcheck.check(cnt == 4, "enumerate str OK (4)", "enumerate str FAILED expect 4")
|
||||
testcheck.check(last_idx == 3, "enumerate str last_idx OK (3)", "enumerate str last_idx FAILED expect 3")
|
||||
|
||||
|
||||
def test_enumerate_range():
|
||||
testcheck.section("Test 10: enumerate(range)")
|
||||
cnt: t.CInt = 0
|
||||
last_idx: t.CInt = -1
|
||||
last_val: t.CInt = -1
|
||||
for idx, v in enumerate(range(5)):
|
||||
stdio.printf("enum range[%d]=%d\n", idx, v)
|
||||
last_idx = idx
|
||||
last_val = v
|
||||
cnt += 1
|
||||
testcheck.check(cnt == 5, "enumerate range OK (5)", "enumerate range FAILED expect 5")
|
||||
testcheck.check(last_idx == 4, "enumerate range last_idx OK (4)", "enumerate range last_idx FAILED expect 4")
|
||||
testcheck.check(last_val == 4, "enumerate range last_val OK (4)", "enumerate range last_val FAILED expect 4")
|
||||
|
||||
|
||||
def main() -> t.CInt:
|
||||
testcheck.begin("ForAndLoopTest: 迭代器与循环测试")
|
||||
|
||||
test_for_in_range()
|
||||
test_for_in_str()
|
||||
test_for_in_list()
|
||||
test_zip_list_list()
|
||||
test_zip_range_list()
|
||||
test_zip_str_str()
|
||||
test_zip_range_len_list()
|
||||
test_enumerate_list()
|
||||
test_enumerate_str()
|
||||
test_enumerate_range()
|
||||
|
||||
return testcheck.end()
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
|
||||
"name": "ForAndLoopTest",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": ["-filetype=obj", "-relocation-model=pic"]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": ["-Wl,--allow-multiple-definition", "-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32"],
|
||||
"output": "ForAndLoopTest.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
from stdint import *
|
||||
import t, c
|
||||
import ctraits
|
||||
import stdio
|
||||
import testcheck
|
||||
|
||||
|
||||
# ============================================================
|
||||
# FormatStringTest - 格式化字符串回归测试
|
||||
# ============================================================
|
||||
@t.CExport
|
||||
def main() -> int:
|
||||
testcheck.begin("FormatStringTest: Format String Regression")
|
||||
|
||||
b: str = "hello world"
|
||||
for i in b:
|
||||
stdio.printf("%c\n", i)
|
||||
b += 1
|
||||
print(b-11)
|
||||
|
||||
l: t.CArray[u64] = [0, 43, 2, 3, 4]
|
||||
l[0] = 1000
|
||||
for i in l:
|
||||
stdio.printf("%llu\n", i)
|
||||
|
||||
print("Value: ", f"0x{ULONGLONG(0x11)}")
|
||||
print("ULL Hex: ", f"0x{ULONGLONG(0x11):016X}")
|
||||
print("LL Hex: ", f"{LONGLONG(0x11):016X}")
|
||||
print("ULL Dec: ", f"{ULONGLONG(42):d}")
|
||||
print("LL Dec: ", f"{LONGLONG(42):d}")
|
||||
print("Hex: ", f"{0x11:016X}")
|
||||
print("Dec: ", f"{42:d}")
|
||||
print("Float: ", f"{3.14159:.2f}")
|
||||
|
||||
# f-string 赋值测试(验证不再直接 printf,而是生成字符串)
|
||||
s: str = f"Value=0x{ULONGLONG(42)}, Hex=0x{ULONGLONG(0x11):016X}"
|
||||
print("Assigned: ", s)
|
||||
|
||||
# ctraits.isptr 编译时类型判断测试
|
||||
ptr_var: INTPTR = c.Addr(s)
|
||||
val_var: int = 42
|
||||
if c.CIf(ctraits.isptr(ptr_var)):
|
||||
print("ptr_var is pointer")
|
||||
if c.CIf(not ctraits.isptr(val_var)):
|
||||
print("val_var is not pointer")
|
||||
|
||||
testcheck.section("placeholder")
|
||||
testcheck.ok("testcheck framework ready")
|
||||
testcheck.info("placeholder test")
|
||||
|
||||
return testcheck.end()
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
|
||||
"name": "FormatStringTest",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": ["-filetype=obj", "-relocation-model=pic"]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": ["-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32", "-Wl,--allow-multiple-definition"],
|
||||
"output": "FormatStringTest.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
import t
|
||||
import stdio
|
||||
import testcheck
|
||||
|
||||
# 测试基本函数调用
|
||||
def add(a: t.CInt, b: t.CInt) -> t.CInt:
|
||||
return a + b
|
||||
|
||||
def sub(a: t.CInt, b: t.CInt) -> t.CInt:
|
||||
return a - b
|
||||
|
||||
# 测试多参数
|
||||
def multi_args(a: t.CInt, b: t.CInt, c: t.CInt, d: t.CInt) -> t.CInt:
|
||||
return a + b + c + d
|
||||
|
||||
# 测试递归
|
||||
def factorial(n: t.CInt) -> t.CInt:
|
||||
if n <= 1:
|
||||
return 1
|
||||
return n * factorial(n - 1)
|
||||
|
||||
# 测试尾递归式斐波那契
|
||||
def fib(n: t.CInt) -> t.CInt:
|
||||
if n <= 0:
|
||||
return 0
|
||||
if n == 1:
|
||||
return 1
|
||||
return fib(n - 1) + fib(n - 2)
|
||||
|
||||
# 测试指针参数
|
||||
def add_via_ptr(p: t.CInt | t.CPtr, val: t.CInt):
|
||||
p[0] = p[0] + val
|
||||
|
||||
# 测试 u64 返回值
|
||||
def make_u64() -> t.CUInt64T:
|
||||
return t.CUInt64T(0xDEADBEEF)
|
||||
|
||||
# 测试 bool 返回值
|
||||
def is_even(n: t.CInt) -> t.CBool:
|
||||
return n % 2 == 0
|
||||
|
||||
def test_basic_call():
|
||||
testcheck.section("Test 1: basic function call")
|
||||
r: t.CInt = add(10, 20)
|
||||
testcheck.check(r == 30, "add(10,20)=30", "add(10,20) expect 30")
|
||||
|
||||
def test_multi_args():
|
||||
testcheck.section("Test 2: multi args")
|
||||
r: t.CInt = multi_args(1, 2, 3, 4)
|
||||
testcheck.check(r == 10, "multi_args(1,2,3,4)=10", "multi_args(1,2,3,4) expect 10")
|
||||
|
||||
def test_recursion():
|
||||
testcheck.section("Test 3: recursion (factorial)")
|
||||
r: t.CInt = factorial(10)
|
||||
# 10! = 3628800
|
||||
testcheck.check(r == 3628800, "factorial(10)=3628800", "factorial(10) expect 3628800")
|
||||
|
||||
def test_fibonacci():
|
||||
testcheck.section("Test 4: fibonacci")
|
||||
r: t.CInt = fib(10)
|
||||
# fib(10) = 55
|
||||
testcheck.check(r == 55, "fib(10)=55", "fib(10) expect 55")
|
||||
|
||||
def test_ptr_param():
|
||||
testcheck.section("Test 5: pointer parameter")
|
||||
x: t.CInt = 10
|
||||
# 需要取 x 的地址
|
||||
import w32.win32memory
|
||||
buf: t.CInt | t.CPtr = w32.win32memory.VirtualAlloc(None, 64, 12288, 4)
|
||||
if t.CUInt64T(buf) == 0:
|
||||
testcheck.info("SKIP: VirtualAlloc returned NULL")
|
||||
return
|
||||
buf[0] = 10
|
||||
add_via_ptr(buf, 25)
|
||||
testcheck.check(buf[0] == 35, "ptr param (result=35)", "ptr param expect 35")
|
||||
|
||||
def test_u64_return():
|
||||
testcheck.section("Test 6: u64 return")
|
||||
r: t.CUInt64T = make_u64()
|
||||
testcheck.check(r == t.CUInt64T(0xDEADBEEF), "u64 return (0xdeadbeef)", "u64 return expect 0xdeadbeef")
|
||||
|
||||
def test_bool_return():
|
||||
testcheck.section("Test 7: bool return")
|
||||
r1: t.CBool = is_even(4)
|
||||
r2: t.CBool = is_even(7)
|
||||
testcheck.check(r1 and not r2, "bool return (is_even(4)=1, is_even(7)=0)", "bool return expect is_even(4)=1, is_even(7)=0")
|
||||
|
||||
def test_nested_call():
|
||||
testcheck.section("Test 8: nested function call")
|
||||
r: t.CInt = add(factorial(3), sub(10, 3))
|
||||
# 3! = 6, 10-3 = 7, 6+7 = 13
|
||||
testcheck.check(r == 13, "nested call (add(factorial(3), sub(10,3))=13)", "nested call expect 13")
|
||||
|
||||
import w32.win32memory
|
||||
|
||||
export def main() -> t.CInt:
|
||||
testcheck.begin("FuncTest: 函数调用基准测试")
|
||||
test_basic_call()
|
||||
test_multi_args()
|
||||
test_recursion()
|
||||
test_fibonacci()
|
||||
test_ptr_param()
|
||||
test_u64_return()
|
||||
test_bool_return()
|
||||
test_nested_call()
|
||||
return testcheck.end()
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
|
||||
"name": "FuncTest",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": [
|
||||
"-filetype=obj",
|
||||
"-relocation-model=pic"
|
||||
]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": [
|
||||
"-Wl,--allow-multiple-definition",
|
||||
"-lmsvcrt",
|
||||
"-lucrt",
|
||||
"-lpthread",
|
||||
"-lmingwex",
|
||||
"-lkernel32",
|
||||
"-luser32"
|
||||
],
|
||||
"output": "FuncTest.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import t
|
||||
import stdio
|
||||
import testcheck
|
||||
from linkedlist import GSListNode
|
||||
|
||||
# ============================================================
|
||||
# G3: 测试 F-bounded polymorphism
|
||||
# class Node(GSListNode[Node]) — 继承泛型基类,特化自身为类型参数
|
||||
# 这与 TransPyV 中 class Value(GSListNode[Value]) 是相同的模式
|
||||
# ============================================================
|
||||
|
||||
@t.NoVTable
|
||||
class Node(GSListNode[Node]):
|
||||
value: t.CInt
|
||||
|
||||
def __init__(self):
|
||||
self.value = 0
|
||||
self.Next = None
|
||||
|
||||
|
||||
def test_node_create():
|
||||
testcheck.section("Test 1: Node(GSListNode[Node]) create")
|
||||
n: Node = Node()
|
||||
n.value = 42
|
||||
testcheck.check(n.value == 42, "Node.value = 42", "expect 42")
|
||||
|
||||
|
||||
def test_node_next_field():
|
||||
testcheck.section("Test 2: Next field from GSListNode[Node]")
|
||||
n1: Node = Node()
|
||||
n2: Node = Node()
|
||||
n1.value = 10
|
||||
n2.value = 20
|
||||
n1.Next = n2
|
||||
next_node: Node = n1.Next
|
||||
v: t.CInt = next_node.value
|
||||
testcheck.check(v == 20, "n1.Next.value = 20", "expect 20")
|
||||
|
||||
|
||||
def test_node_chain():
|
||||
testcheck.section("Test 3: Node chain traversal")
|
||||
a: Node = Node()
|
||||
b: Node = Node()
|
||||
c: Node = Node()
|
||||
a.value = 1
|
||||
b.value = 2
|
||||
c.value = 3
|
||||
a.Next = b
|
||||
b.Next = c
|
||||
sum: t.CInt = a.value
|
||||
p: Node = a.Next
|
||||
sum = sum + p.value
|
||||
p = p.Next
|
||||
sum = sum + p.value
|
||||
testcheck.check(sum == 6, "chain sum = 1+2+3 = 6", "expect 6")
|
||||
|
||||
|
||||
def main() -> t.CInt:
|
||||
testcheck.begin("G3: GSListNode inheritance (F-bounded polymorphism)")
|
||||
test_node_create()
|
||||
test_node_next_field()
|
||||
test_node_chain()
|
||||
return testcheck.end()
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
|
||||
"name": "G3",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": [
|
||||
"-filetype=obj",
|
||||
"-relocation-model=pic"
|
||||
]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": [
|
||||
"-Wl,--allow-multiple-definition",
|
||||
"-lmsvcrt",
|
||||
"-lucrt",
|
||||
"-lpthread",
|
||||
"-lmingwex",
|
||||
"-lkernel32",
|
||||
"-luser32"
|
||||
],
|
||||
"output": "G3.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import t
|
||||
import stdio
|
||||
import stdlib
|
||||
import memhub
|
||||
from g4node import G4Node, new_g4node
|
||||
|
||||
|
||||
# ============================================================
|
||||
# caller1: 导入 G4Node 并直接访问 Next 字段(不通过访问器)
|
||||
#
|
||||
# 模拟 TransPyV/HandlesExprCall.py 的情况:
|
||||
# 直接访问 n.Next 触发 GEP 指令,若 stub 字段缺失则 GEP 越界
|
||||
# ============================================================
|
||||
|
||||
|
||||
def caller1_make_chain(pool: memhub.MemBuddy | t.CPtr) -> G4Node | t.CPtr:
|
||||
"""创建 3 节点链表,直接访问 Next 字段"""
|
||||
a: G4Node | t.CPtr = new_g4node(pool)
|
||||
b: G4Node | t.CPtr = new_g4node(pool)
|
||||
c: G4Node | t.CPtr = new_g4node(pool)
|
||||
if a is None or b is None or c is None:
|
||||
return None
|
||||
a.IntVal = 100
|
||||
b.IntVal = 200
|
||||
c.IntVal = 300
|
||||
# 直接访问 Next 字段(不通过 g4node_set_next 访问器)
|
||||
a.Next = b
|
||||
b.Next = c
|
||||
return a
|
||||
|
||||
|
||||
def caller1_sum_chain(head: G4Node | t.CPtr) -> t.CInt:
|
||||
"""遍历链表求和,直接访问 Next 字段"""
|
||||
if head is None:
|
||||
return 0
|
||||
total: t.CInt = head.IntVal
|
||||
cur: G4Node | t.CPtr = head
|
||||
# 直接访问 Next 字段(不通过 g4node_get_next 访问器)
|
||||
while cur.Next is not None:
|
||||
cur = cur.Next
|
||||
total = total + cur.IntVal
|
||||
return total
|
||||
@@ -0,0 +1,36 @@
|
||||
import t
|
||||
import stdio
|
||||
import stdlib
|
||||
import memhub
|
||||
from g4node import G4Node, new_g4node
|
||||
|
||||
|
||||
# ============================================================
|
||||
# caller2: 另一个导入 G4Node 的模块
|
||||
#
|
||||
# 增加 G4Node 的跨模块引用次数,触发多模块竞争条件
|
||||
# ============================================================
|
||||
|
||||
|
||||
def caller2_reverse_chain(head: G4Node | t.CPtr) -> G4Node | t.CPtr:
|
||||
"""反转链表,直接访问 Next 字段"""
|
||||
if head is None:
|
||||
return None
|
||||
prev: G4Node | t.CPtr = None
|
||||
cur: G4Node | t.CPtr = head
|
||||
while cur is not None:
|
||||
nxt: G4Node | t.CPtr = cur.Next
|
||||
cur.Next = prev
|
||||
prev = cur
|
||||
cur = nxt
|
||||
return prev
|
||||
|
||||
|
||||
def caller2_count_nodes(head: G4Node | t.CPtr) -> t.CInt:
|
||||
"""计算链表节点数"""
|
||||
count: t.CInt = 0
|
||||
cur: G4Node | t.CPtr = head
|
||||
while cur is not None:
|
||||
count = count + 1
|
||||
cur = cur.Next
|
||||
return count
|
||||
@@ -0,0 +1,31 @@
|
||||
import t
|
||||
import stdio
|
||||
import stdlib
|
||||
import memhub
|
||||
from g4node import G4Node, new_g4node
|
||||
|
||||
|
||||
# ============================================================
|
||||
# caller3: 第三个导入 G4Node 的模块
|
||||
#
|
||||
# 进一步增加跨模块引用,模拟 TransPyV 30+ 模块环境
|
||||
# ============================================================
|
||||
|
||||
|
||||
def caller3_find_tail(head: G4Node | t.CPtr) -> G4Node | t.CPtr:
|
||||
"""找到链表尾部节点,直接访问 Next"""
|
||||
if head is None:
|
||||
return None
|
||||
cur: G4Node | t.CPtr = head
|
||||
while cur.Next is not None:
|
||||
cur = cur.Next
|
||||
return cur
|
||||
|
||||
|
||||
def caller3_append(head: G4Node | t.CPtr, new_node: G4Node | t.CPtr) -> G4Node | t.CPtr:
|
||||
"""在链表末尾追加节点"""
|
||||
if head is None:
|
||||
return new_node
|
||||
tail: G4Node | t.CPtr = caller3_find_tail(head)
|
||||
tail.Next = new_node
|
||||
return head
|
||||
+154
@@ -0,0 +1,154 @@
|
||||
import t
|
||||
import stdio
|
||||
import testcheck
|
||||
import stdlib
|
||||
from g4node import G4Node, new_g4node, g4node_get_next, g4node_set_next
|
||||
import memhub
|
||||
import caller1
|
||||
import caller2
|
||||
import caller3
|
||||
|
||||
# ============================================================
|
||||
# G4: 验证 includes 中继承 GSListNode[X] 的类是否会出现
|
||||
# Next 字段缺失或类型降级的问题
|
||||
#
|
||||
# G4Node 类在 includes/g4node.py 中(走 Phase1 路径)
|
||||
# G4Node 有 5 个自有字段 + 1 个继承字段(Next) = 6 字段
|
||||
# caller1/caller2/caller3 模拟 TransPyV 多模块环境
|
||||
# ============================================================
|
||||
|
||||
|
||||
def test_g4node_create():
|
||||
testcheck.section("Test 1: G4Node create (from includes)")
|
||||
arena: bytes = stdlib.malloc(4096)
|
||||
if arena is None:
|
||||
testcheck.check(False, "malloc arena", "FAIL")
|
||||
return
|
||||
pool: memhub.MemBuddy | t.CPtr = memhub.MemBuddy(arena, 4096)
|
||||
n: G4Node | t.CPtr = new_g4node(pool)
|
||||
if n is None:
|
||||
testcheck.check(False, "new_g4node", "FAIL")
|
||||
return
|
||||
n.IntVal = 42
|
||||
v: t.CInt = n.IntVal
|
||||
testcheck.check(v == 42, "G4Node.IntVal = 42", "expect 42")
|
||||
|
||||
|
||||
def test_g4node_next_field():
|
||||
testcheck.section("Test 2: Next field from GSListNode[G4Node]")
|
||||
arena: bytes = stdlib.malloc(4096)
|
||||
if arena is None:
|
||||
testcheck.check(False, "malloc arena", "FAIL")
|
||||
return
|
||||
pool: memhub.MemBuddy | t.CPtr = memhub.MemBuddy(arena, 4096)
|
||||
n1: G4Node | t.CPtr = new_g4node(pool)
|
||||
n2: G4Node | t.CPtr = new_g4node(pool)
|
||||
if n1 is None or n2 is None:
|
||||
testcheck.check(False, "new_g4node", "FAIL")
|
||||
return
|
||||
n1.IntVal = 10
|
||||
n2.IntVal = 20
|
||||
g4node_set_next(n1, n2)
|
||||
next_node: G4Node | t.CPtr = g4node_get_next(n1)
|
||||
if next_node is None:
|
||||
testcheck.check(False, "g4node_get_next", "FAIL")
|
||||
return
|
||||
v: t.CInt = next_node.IntVal
|
||||
testcheck.check(v == 20, "n1.Next.IntVal = 20", "expect 20")
|
||||
|
||||
|
||||
def test_g4node_chain():
|
||||
testcheck.section("Test 3: G4Node chain traversal")
|
||||
arena: bytes = stdlib.malloc(4096)
|
||||
if arena is None:
|
||||
testcheck.check(False, "malloc arena", "FAIL")
|
||||
return
|
||||
pool: memhub.MemBuddy | t.CPtr = memhub.MemBuddy(arena, 4096)
|
||||
a: G4Node | t.CPtr = new_g4node(pool)
|
||||
b: G4Node | t.CPtr = new_g4node(pool)
|
||||
c: G4Node | t.CPtr = new_g4node(pool)
|
||||
if a is None or b is None or c is None:
|
||||
testcheck.check(False, "new_g4node", "FAIL")
|
||||
return
|
||||
a.IntVal = 1
|
||||
b.IntVal = 2
|
||||
c.IntVal = 3
|
||||
g4node_set_next(a, b)
|
||||
g4node_set_next(b, c)
|
||||
sum: t.CInt = a.IntVal
|
||||
p: G4Node | t.CPtr = g4node_get_next(a)
|
||||
sum = sum + p.IntVal
|
||||
p = g4node_get_next(p)
|
||||
sum = sum + p.IntVal
|
||||
testcheck.check(sum == 6, "chain sum = 1+2+3 = 6", "expect 6")
|
||||
|
||||
|
||||
def test_caller1_direct_access():
|
||||
"""caller1: 直接访问 Next 字段(不通过访问器)"""
|
||||
testcheck.section("Test 4: caller1 direct Next access")
|
||||
arena: bytes = stdlib.malloc(8192)
|
||||
if arena is None:
|
||||
testcheck.check(False, "malloc arena", "FAIL")
|
||||
return
|
||||
pool: memhub.MemBuddy | t.CPtr = memhub.MemBuddy(arena, 8192)
|
||||
head: G4Node | t.CPtr = caller1.caller1_make_chain(pool)
|
||||
if head is None:
|
||||
testcheck.check(False, "caller1_make_chain", "FAIL")
|
||||
return
|
||||
total: t.CInt = caller1.caller1_sum_chain(head)
|
||||
stdio.printf("caller1 chain total = %d\n", total)
|
||||
testcheck.check(total == 600, "caller1 sum = 100+200+300 = 600", "expect 600")
|
||||
|
||||
|
||||
def test_caller2_reverse():
|
||||
"""caller2: 反转链表直接访问 Next"""
|
||||
testcheck.section("Test 5: caller2 reverse chain")
|
||||
arena: bytes = stdlib.malloc(8192)
|
||||
if arena is None:
|
||||
testcheck.check(False, "malloc arena", "FAIL")
|
||||
return
|
||||
pool: memhub.MemBuddy | t.CPtr = memhub.MemBuddy(arena, 8192)
|
||||
head: G4Node | t.CPtr = caller1.caller1_make_chain(pool)
|
||||
if head is None:
|
||||
testcheck.check(False, "caller1_make_chain", "FAIL")
|
||||
return
|
||||
count_before: t.CInt = caller2.caller2_count_nodes(head)
|
||||
reversed_head: G4Node | t.CPtr = caller2.caller2_reverse_chain(head)
|
||||
count_after: t.CInt = caller2.caller2_count_nodes(reversed_head)
|
||||
stdio.printf("caller2 count before=%d after=%d\n", count_before, count_after)
|
||||
testcheck.check(count_before == 3 and count_after == 3,
|
||||
"caller2 reverse count OK (3,3)", "caller2 count mismatch")
|
||||
|
||||
|
||||
def test_caller3_append():
|
||||
"""caller3: 追加节点直接访问 Next"""
|
||||
testcheck.section("Test 6: caller3 append node")
|
||||
arena: bytes = stdlib.malloc(8192)
|
||||
if arena is None:
|
||||
testcheck.check(False, "malloc arena", "FAIL")
|
||||
return
|
||||
pool: memhub.MemBuddy | t.CPtr = memhub.MemBuddy(arena, 8192)
|
||||
head: G4Node | t.CPtr = caller1.caller1_make_chain(pool)
|
||||
if head is None:
|
||||
testcheck.check(False, "caller1_make_chain", "FAIL")
|
||||
return
|
||||
extra: G4Node | t.CPtr = new_g4node(pool)
|
||||
if extra is None:
|
||||
testcheck.check(False, "new_g4node", "FAIL")
|
||||
return
|
||||
extra.IntVal = 400
|
||||
head = caller3.caller3_append(head, extra)
|
||||
total: t.CInt = caller1.caller1_sum_chain(head)
|
||||
stdio.printf("caller3 after append total = %d\n", total)
|
||||
testcheck.check(total == 1000, "caller3 append sum = 600+400 = 1000", "expect 1000")
|
||||
|
||||
|
||||
def main() -> t.CInt:
|
||||
testcheck.begin("G4: GSListNode inheritance from includes (Phase1 path)")
|
||||
test_g4node_create()
|
||||
test_g4node_next_field()
|
||||
test_g4node_chain()
|
||||
test_caller1_direct_access()
|
||||
test_caller2_reverse()
|
||||
test_caller3_append()
|
||||
return testcheck.end()
|
||||
@@ -0,0 +1,53 @@
|
||||
import t
|
||||
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)
|
||||
# ============================================================
|
||||
|
||||
@t.NoVTable
|
||||
class G4Node(GSListNode[G4Node]):
|
||||
Ty: t.CPtr # 模拟 Value.Ty
|
||||
Name: t.CPtr # 模拟 Value.Name
|
||||
IsConst: t.CInt # 模拟 Value.IsConst
|
||||
IntVal: t.CInt64T # 模拟 Value.IntVal
|
||||
FloatVal: t.CDouble # 模拟 Value.FloatVal
|
||||
|
||||
def __init__(self):
|
||||
self.Ty = None
|
||||
self.Name = None
|
||||
self.IsConst = 0
|
||||
self.IntVal = 0
|
||||
self.FloatVal = 0.0
|
||||
self.Next = None
|
||||
|
||||
|
||||
# 工厂函数(与 __values.py 中的 new_value 类似)
|
||||
def new_g4node(pool: memhub.MemBuddy | t.CPtr) -> G4Node | t.CPtr:
|
||||
ptr: G4Node | t.CPtr = pool.alloc(48)
|
||||
if ptr:
|
||||
ptr.Ty = None
|
||||
ptr.Name = None
|
||||
ptr.IsConst = 0
|
||||
ptr.IntVal = 0
|
||||
ptr.FloatVal = 0.0
|
||||
ptr.Next = None
|
||||
return ptr
|
||||
|
||||
|
||||
def g4node_get_next(node: G4Node | t.CPtr) -> G4Node | t.CPtr:
|
||||
return node.Next
|
||||
|
||||
|
||||
def g4node_set_next(node: G4Node | t.CPtr, next_node: G4Node | t.CPtr):
|
||||
node.Next = next_node
|
||||
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
|
||||
"name": "G4",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": [
|
||||
"-filetype=obj",
|
||||
"-relocation-model=pic"
|
||||
]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": [
|
||||
"-Wl,--allow-multiple-definition",
|
||||
"-lmsvcrt",
|
||||
"-lucrt",
|
||||
"-lpthread",
|
||||
"-lmingwex",
|
||||
"-lkernel32",
|
||||
"-luser32"
|
||||
],
|
||||
"output": "G4.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes",
|
||||
"./includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
+176
@@ -0,0 +1,176 @@
|
||||
import t
|
||||
import stdio
|
||||
import testcheck
|
||||
import stdlib
|
||||
import memhub
|
||||
import string
|
||||
from linkedlist import GSListNode, GSList
|
||||
|
||||
|
||||
# ============================================================
|
||||
# G5: 验证 GSList[T] 被降级为 opaque 的问题
|
||||
#
|
||||
# 版本 2: 不使用 malloc/MemBuddy,直接用构造函数(像 G3 那样)
|
||||
# 这样能隔离 GSList opaque 问题
|
||||
# ============================================================
|
||||
|
||||
|
||||
# G5Node: 继承 GSListNode[G5Node](Phase2 路径,正确特化)
|
||||
@t.NoVTable
|
||||
class G5Node(GSListNode[G5Node]):
|
||||
Value: t.CInt
|
||||
|
||||
def __init__(self):
|
||||
self.Next = None
|
||||
self.Value = 0
|
||||
|
||||
|
||||
# G5ListWrapper: 包装 GSList[G5Node],测试 GSList 字段访问
|
||||
# 注意:GSList[G5Node] 走 Phase2 特化路径
|
||||
# 用 pool 工厂函数分配 GSList,避免栈分配悬垂指针
|
||||
GSLIST_SIZE: t.CDefine = 24 # Head(8) + Tail(8) + Count(8)
|
||||
|
||||
@t.NoVTable
|
||||
class G5ListWrapper:
|
||||
List: GSList[G5Node] | t.CPtr
|
||||
|
||||
def __init__(self, pool: memhub.MemBuddy | t.CPtr):
|
||||
gsl: GSList[G5Node] | t.CPtr = pool.alloc(GSLIST_SIZE)
|
||||
if gsl is None:
|
||||
self.List = None
|
||||
return
|
||||
string.memset(gsl, 0, GSLIST_SIZE)
|
||||
self.List = gsl
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Test 1: G5Node 字段访问(基准测试,应通过)
|
||||
# ============================================================
|
||||
|
||||
def test_g5node_create():
|
||||
testcheck.section("Test 1: G5Node create and field access")
|
||||
n: G5Node = G5Node()
|
||||
n.Value = 42
|
||||
v: t.CInt = n.Value
|
||||
testcheck.check(v == 42, "G5Node.Value = 42", "expect 42")
|
||||
|
||||
|
||||
def test_g5node_next():
|
||||
testcheck.section("Test 2: G5Node.Next field (GSListNode inheritance)")
|
||||
n1: G5Node = G5Node()
|
||||
n2: G5Node = G5Node()
|
||||
n1.Value = 10
|
||||
n2.Value = 20
|
||||
n1.Next = n2
|
||||
next_node: G5Node = n1.Next
|
||||
if next_node is None:
|
||||
testcheck.check(False, "n1.Next is None", "FAIL")
|
||||
return
|
||||
v: t.CInt = next_node.Value
|
||||
testcheck.check(v == 20, "n1.Next.Value = 20", "expect 20")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Test 3: GSList 字段访问 — 核心测试
|
||||
# ============================================================
|
||||
|
||||
def test_gslist_create():
|
||||
testcheck.section("Test 3: GSList[G5Node] create")
|
||||
lst: GSList[G5Node] | t.CPtr = GSList[G5Node]()
|
||||
if lst is None:
|
||||
testcheck.check(False, "GSList[G5Node]() is None", "FAIL")
|
||||
return
|
||||
# 检查初始状态
|
||||
head: G5Node | t.CPtr = lst.Head
|
||||
tail: G5Node | t.CPtr = lst.Tail
|
||||
count: t.CSizeT = lst.Count
|
||||
testcheck.check(head is None, "initial Head is None", "expect None")
|
||||
testcheck.check(tail is None, "initial Tail is None", "expect None")
|
||||
testcheck.check(count == 0, "initial Count = 0", "expect 0")
|
||||
|
||||
|
||||
def test_gslist_append():
|
||||
testcheck.section("Test 4: GSList[G5Node].append 3 nodes")
|
||||
lst: GSList[G5Node] | t.CPtr = GSList[G5Node]()
|
||||
if lst is None:
|
||||
testcheck.check(False, "GSList[G5Node]() is None", "FAIL")
|
||||
return
|
||||
a: G5Node = G5Node()
|
||||
b: G5Node = G5Node()
|
||||
c: G5Node = G5Node()
|
||||
a.Value = 1
|
||||
b.Value = 2
|
||||
c.Value = 3
|
||||
|
||||
lst.append(a)
|
||||
lst.append(b)
|
||||
lst.append(c)
|
||||
|
||||
# 验证 Count
|
||||
count: t.CSizeT = lst.Count
|
||||
testcheck.check(count == 3, "Count = 3 after 3 appends", "expect 3")
|
||||
|
||||
# 验证 Head
|
||||
head: G5Node | t.CPtr = 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
|
||||
tail: G5Node | t.CPtr = lst.Tail
|
||||
if tail is None:
|
||||
testcheck.check(False, "Tail is None", "FAIL")
|
||||
return
|
||||
testcheck.check(tail.Value == 3, "Tail.Value = 3", "expect 3")
|
||||
|
||||
# 遍历链表验证顺序
|
||||
sum: t.CInt = 0
|
||||
cur: G5Node | t.CPtr = lst.Head
|
||||
while cur is not None:
|
||||
sum = sum + cur.Value
|
||||
cur = cur.Next
|
||||
testcheck.check(sum == 6, "chain sum = 1+2+3 = 6", "expect 6")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Test 5: G5ListWrapper.List 字段访问(嵌套 GSList 测试)
|
||||
# ============================================================
|
||||
|
||||
def test_wrapper_list_field():
|
||||
testcheck.section("Test 5: G5ListWrapper.List field (nested GSList, pool alloc)")
|
||||
arena: bytes = stdlib.malloc(4096)
|
||||
if arena is None:
|
||||
testcheck.check(False, "malloc arena", "FAIL")
|
||||
return
|
||||
pool: memhub.MemBuddy | t.CPtr = memhub.MemBuddy(arena, 4096)
|
||||
wrapper: G5ListWrapper = G5ListWrapper(pool)
|
||||
if wrapper is None:
|
||||
testcheck.check(False, "G5ListWrapper(pool) is None", "FAIL")
|
||||
return
|
||||
if wrapper.List is None:
|
||||
testcheck.check(False, "wrapper.List is None", "FAIL")
|
||||
return
|
||||
|
||||
n: G5Node = G5Node()
|
||||
n.Value = 999
|
||||
wrapper.List.append(n)
|
||||
|
||||
# 通过 wrapper.List 访问 GSList 字段
|
||||
head: G5Node | t.CPtr = wrapper.List.Head
|
||||
if head is None:
|
||||
testcheck.check(False, "wrapper.List.Head is None", "FAIL")
|
||||
return
|
||||
count: t.CSizeT = wrapper.List.Count
|
||||
testcheck.check(head.Value == 999, "wrapper.List.Head.Value = 999", "expect 999")
|
||||
testcheck.check(count == 1, "wrapper.List.Count = 1", "expect 1")
|
||||
|
||||
|
||||
def main() -> t.CInt:
|
||||
testcheck.begin("G5: GSList[T] field access (Phase2 path, pool alloc for wrapper)")
|
||||
test_g5node_create()
|
||||
test_g5node_next()
|
||||
test_gslist_create()
|
||||
test_gslist_append()
|
||||
test_wrapper_list_field()
|
||||
return testcheck.end()
|
||||
@@ -0,0 +1,173 @@
|
||||
import t
|
||||
import string
|
||||
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 类的情况相同)
|
||||
# ============================================================
|
||||
|
||||
@t.NoVTable
|
||||
class G5Node(GSListNode[G5Node]):
|
||||
Value: t.CInt
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 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
|
||||
# 模式完全相同。
|
||||
# ============================================================
|
||||
|
||||
@t.NoVTable
|
||||
class G5Container:
|
||||
List: GSList[G5Node] | t.CPtr
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 工厂函数(与 __function.py 的 new_line/new_function 模式相同)
|
||||
# ============================================================
|
||||
|
||||
# G5Node 硬编码大小: Next(8) + Value(4) + padding(4) = 16 字节
|
||||
G5NODE_SIZE: t.CDefine = 16
|
||||
|
||||
def new_g5node(pool: memhub.MemBuddy | t.CPtr) -> G5Node | t.CPtr:
|
||||
"""从 pool 分配并零初始化一个 G5Node"""
|
||||
ptr: G5Node | t.CPtr = 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 字节
|
||||
G5LIST_SIZE: t.CDefine = 24
|
||||
|
||||
def new_g5list(pool: memhub.MemBuddy | t.CPtr) -> GSList | t.CPtr:
|
||||
"""从 pool 分配并零初始化一个 GSList 容器(Head/Tail/Count 全零)"""
|
||||
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_SIZE: t.CDefine = 8
|
||||
|
||||
def new_g5container(pool: memhub.MemBuddy | t.CPtr) -> G5Container | t.CPtr:
|
||||
"""从 pool 分配并零初始化一个 G5Container"""
|
||||
ptr: G5Container | t.CPtr = 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 限制。
|
||||
# ============================================================
|
||||
|
||||
def g5list_get_head(lst: GSList | t.CPtr) -> G5Node | t.CPtr:
|
||||
"""获取链表头节点"""
|
||||
if lst is None: return None
|
||||
return lst.Head
|
||||
|
||||
|
||||
def g5list_get_tail(lst: GSList | t.CPtr) -> G5Node | t.CPtr:
|
||||
"""获取链表尾节点"""
|
||||
if lst is None: return None
|
||||
return lst.Tail
|
||||
|
||||
|
||||
def g5list_get_count(lst: GSList | t.CPtr) -> t.CSizeT:
|
||||
"""获取链表节点数"""
|
||||
if lst is None: return 0
|
||||
return lst.Count
|
||||
|
||||
|
||||
def g5list_set_head(lst: GSList | t.CPtr, node: G5Node | t.CPtr):
|
||||
"""设置链表头节点"""
|
||||
if lst is None: return
|
||||
lst.Head = node
|
||||
|
||||
|
||||
def g5list_set_tail(lst: GSList | t.CPtr, node: G5Node | t.CPtr):
|
||||
"""设置链表尾节点"""
|
||||
if lst is None: return
|
||||
lst.Tail = node
|
||||
|
||||
|
||||
def g5list_set_count(lst: GSList | t.CPtr, count: t.CSizeT):
|
||||
"""设置链表节点数"""
|
||||
if lst is None: return
|
||||
lst.Count = count
|
||||
|
||||
|
||||
def g5list_append(lst: GSList | t.CPtr, node: G5Node | t.CPtr):
|
||||
"""将 node 追加到链表末尾(O(1))
|
||||
|
||||
直接操作 Head/Tail/Count 字段,不依赖 GSList.append 方法
|
||||
(因为跨模块时方法实现可能缺失)
|
||||
"""
|
||||
if lst is None or node is None: return
|
||||
node.Next = None
|
||||
if lst.Head is None:
|
||||
lst.Head = node
|
||||
else:
|
||||
lst.Tail.Next = node
|
||||
lst.Tail = node
|
||||
lst.Count += 1
|
||||
|
||||
|
||||
# ============================================================
|
||||
# G5Node 访问器
|
||||
# ============================================================
|
||||
|
||||
def g5node_get_value(node: G5Node | t.CPtr) -> t.CInt:
|
||||
if node is None: return 0
|
||||
return node.Value
|
||||
|
||||
|
||||
def g5node_set_value(node: G5Node | t.CPtr, value: t.CInt):
|
||||
if node is None: return
|
||||
node.Value = value
|
||||
|
||||
|
||||
def g5node_get_next(node: G5Node | t.CPtr) -> G5Node | t.CPtr:
|
||||
if node is None: return None
|
||||
return node.Next
|
||||
|
||||
|
||||
def g5node_set_next(node: G5Node | t.CPtr, next_node: G5Node | t.CPtr):
|
||||
if node is None: return
|
||||
node.Next = next_node
|
||||
|
||||
|
||||
# ============================================================
|
||||
# G5Container 访问器
|
||||
# ============================================================
|
||||
|
||||
def g5container_get_list(container: G5Container | t.CPtr) -> GSList | t.CPtr:
|
||||
if container is None: return None
|
||||
return container.List
|
||||
|
||||
|
||||
def g5container_set_list(container: G5Container | t.CPtr, lst: GSList | t.CPtr):
|
||||
if container is None: return
|
||||
container.List = lst
|
||||
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
|
||||
"name": "G5",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": [
|
||||
"-filetype=obj",
|
||||
"-relocation-model=pic"
|
||||
]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": [
|
||||
"-Wl,--allow-multiple-definition",
|
||||
"-lmsvcrt",
|
||||
"-lucrt",
|
||||
"-lpthread",
|
||||
"-lmingwex",
|
||||
"-lkernel32",
|
||||
"-luser32"
|
||||
],
|
||||
"output": "G5.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes",
|
||||
"./includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
import t, c
|
||||
import stdio
|
||||
import testcheck
|
||||
import atom
|
||||
|
||||
|
||||
# ============================================================
|
||||
# G6: 验证 atom 模块的内联汇编原子操作
|
||||
#
|
||||
# TPV 在编译 atom.py 的 __atomic_test_and_set 时崩溃
|
||||
# (ACCESS_VIOLATION in ASM args loop ai3=2)
|
||||
# 此测试用 TPC 编译验证 atom 模块是否正确工作
|
||||
# ============================================================
|
||||
|
||||
|
||||
def test_atomic_test_and_set():
|
||||
testcheck.section("Test 1: __atomic_test_and_set")
|
||||
flag: t.CUInt8T = 0
|
||||
result: t.CBool = atom.__atomic_test_and_set(c.Addr(flag), atom.ATOMIC_ACQUIRE)
|
||||
# test_and_set 返回旧值: flag=0 -> 返回 0, flag 变为 1
|
||||
testcheck.check(result == t.CBool(0), "first set returns old value 0", "expect 0")
|
||||
testcheck.check(flag == 1, "flag is 1 after set", "expect 1")
|
||||
|
||||
# 第二次设置应返回 1(旧值已为 1)
|
||||
result2: t.CBool = atom.__atomic_test_and_set(c.Addr(flag), atom.ATOMIC_ACQUIRE)
|
||||
testcheck.check(result2 == t.CBool(1), "second set returns old value 1", "expect 1")
|
||||
|
||||
|
||||
def test_atomic_clear():
|
||||
testcheck.section("Test 2: __atomic_clear")
|
||||
flag: t.CUInt8T = 1
|
||||
atom.__atomic_clear(c.Addr(flag), atom.ATOMIC_RELEASE)
|
||||
testcheck.check(flag == 0, "flag is 0 after clear", "expect 0")
|
||||
|
||||
|
||||
def test_atomic_thread_fence():
|
||||
testcheck.section("Test 3: __atomic_thread_fence")
|
||||
# 只是验证不崩溃
|
||||
atom.__atomic_thread_fence(atom.ATOMIC_SEQ_CST)
|
||||
testcheck.ok("mfence executed OK")
|
||||
|
||||
|
||||
def test_atomic_lock_free():
|
||||
testcheck.section("Test 4: __atomic_is_lock_free")
|
||||
flag: t.CUInt8T = 0
|
||||
result: t.CBool = atom.__atomic_is_lock_free(1, c.Addr(flag))
|
||||
testcheck.check(result == t.CBool(1), "1-byte is lock free", "expect 1")
|
||||
|
||||
|
||||
def test_atomic_spinlock():
|
||||
testcheck.section("Test 5: spinlock pattern (test_and_set + clear)")
|
||||
lock: t.CUInt8T = 0
|
||||
|
||||
# 获取锁
|
||||
while atom.__atomic_test_and_set(c.Addr(lock), atom.ATOMIC_ACQUIRE) == t.CBool(1):
|
||||
pass
|
||||
testcheck.check(lock == 1, "lock acquired", "expect lock=1")
|
||||
|
||||
# 释放锁
|
||||
atom.__atomic_clear(c.Addr(lock), atom.ATOMIC_RELEASE)
|
||||
testcheck.check(lock == 0, "lock released", "expect lock=0")
|
||||
|
||||
|
||||
def main() -> t.CInt:
|
||||
testcheck.begin("G6: atom module (inline asm atomic operations)")
|
||||
test_atomic_test_and_set()
|
||||
test_atomic_clear()
|
||||
test_atomic_thread_fence()
|
||||
test_atomic_lock_free()
|
||||
test_atomic_spinlock()
|
||||
return testcheck.end()
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
|
||||
"name": "G6",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": [
|
||||
"-filetype=obj",
|
||||
"-relocation-model=pic"
|
||||
]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": [
|
||||
"-Wl,--allow-multiple-definition",
|
||||
"-lmsvcrt",
|
||||
"-lucrt",
|
||||
"-lpthread",
|
||||
"-lmingwex",
|
||||
"-lkernel32",
|
||||
"-luser32"
|
||||
],
|
||||
"output": "G6.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import t
|
||||
import stdio
|
||||
import testcheck
|
||||
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 被跳过。
|
||||
# ============================================================
|
||||
Value: t.CPtr = None
|
||||
|
||||
|
||||
def test_value_struct_fields():
|
||||
"""验证 Value struct 有 6 个字段(Next + 5 自有)"""
|
||||
testcheck.section("Value struct field access (6 fields expected)")
|
||||
arena: bytes = stdlib.malloc(4096)
|
||||
if arena is None:
|
||||
testcheck.check(False, "malloc arena", "FAIL")
|
||||
return
|
||||
pool: memhub.MemBuddy | t.CPtr = memhub.MemBuddy(arena, 4096)
|
||||
node: Value | t.CPtr = pool.alloc(48)
|
||||
if node is None:
|
||||
testcheck.check(False, "alloc Value", "FAIL")
|
||||
return
|
||||
# 写入字段 0 (Next, 继承自 GSListNode)
|
||||
node.Next = None
|
||||
# 写入字段 1-5 (自有字段)
|
||||
node.Ty = None
|
||||
node.Name = None
|
||||
node.IsConst = 1
|
||||
node.IntVal = 42
|
||||
node.FloatVal = 3.14
|
||||
# 读取验证
|
||||
v: t.CInt = node.IntVal
|
||||
testcheck.check(v == 42, "Value.IntVal = 42", "expect 42")
|
||||
f: t.CDouble = node.FloatVal
|
||||
testcheck.check(f > 3.0 and f < 4.0, "Value.FloatVal = 3.14", "expect ~3.14")
|
||||
c: t.CInt = node.IsConst
|
||||
testcheck.check(c == 1, "Value.IsConst = 1", "expect 1")
|
||||
|
||||
|
||||
def main() -> t.CInt:
|
||||
testcheck.begin("G7: Minimal repro - class name 'Value' conflicts with variable")
|
||||
test_value_struct_fields()
|
||||
return testcheck.end()
|
||||
@@ -0,0 +1,30 @@
|
||||
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 越界崩溃
|
||||
# ============================================================
|
||||
|
||||
@t.NoVTable
|
||||
class Value(GSListNode[Value]):
|
||||
Ty: t.CPtr
|
||||
Name: t.CPtr
|
||||
IsConst: t.CInt
|
||||
IntVal: t.CInt64T
|
||||
FloatVal: t.CDouble
|
||||
|
||||
def __init__(self):
|
||||
self.Ty = None
|
||||
self.Name = None
|
||||
self.IsConst = 0
|
||||
self.IntVal = 0
|
||||
self.FloatVal = 0.0
|
||||
self.Next = None
|
||||
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
|
||||
"name": "G7",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": [
|
||||
"-filetype=obj",
|
||||
"-relocation-model=pic"
|
||||
]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": [
|
||||
"-Wl,--allow-multiple-definition",
|
||||
"-lmsvcrt",
|
||||
"-lucrt",
|
||||
"-lpthread",
|
||||
"-lmingwex",
|
||||
"-lkernel32",
|
||||
"-luser32"
|
||||
],
|
||||
"output": "G7.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes",
|
||||
"./includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
from stdint import *
|
||||
import w32.win32console
|
||||
import t, c
|
||||
from t import CInt, CPtr, CChar, CInt32T, CUInt64T, CFloat64T, CExport, State
|
||||
import viperlib
|
||||
import stdlib
|
||||
import testcheck
|
||||
|
||||
|
||||
# === 函数泛型 ===
|
||||
|
||||
def add[T](a: T, b: T) -> T:
|
||||
return a + b
|
||||
|
||||
def add_u64[T](a: T, b: T, c: CUInt64T) -> T:
|
||||
return a + b + T(c)
|
||||
|
||||
def fxi[T1, T2](a: T1, b: T2) -> T1:
|
||||
return a + fxi2(a, b, CUInt64T(178900))
|
||||
|
||||
def fxi2[T1, T2, T3](a: T1, b: T2, c: T3) -> T1:
|
||||
return a + T1(b) + T1(c)
|
||||
|
||||
def wrap_add[T](a: T, b: T) -> T:
|
||||
return add(a, b)
|
||||
|
||||
def double_add[T](a: T, b: T) -> T:
|
||||
return add(a, b) + add(a, b)
|
||||
|
||||
|
||||
# === 结构体泛型 ===
|
||||
|
||||
class A[T]():
|
||||
a: T
|
||||
def __init__(self, a: T):
|
||||
self.a = T(a)
|
||||
def get_a(self) -> T:
|
||||
return self.a
|
||||
|
||||
class Pair[T1, T2]():
|
||||
first: T1
|
||||
second: T2
|
||||
def __init__(self, first: T1, second: T2):
|
||||
self.first = T1(first)
|
||||
self.second = T2(second)
|
||||
def get_first(self) -> T1:
|
||||
return self.first
|
||||
def get_second(self) -> T2:
|
||||
return self.second
|
||||
|
||||
class Calculator[T]():
|
||||
val: T
|
||||
def __init__(self, init_val: T):
|
||||
self.val = T(init_val)
|
||||
def compute(self, other: T) -> T:
|
||||
return add(self.val, other)
|
||||
def double_compute(self, other: T) -> T:
|
||||
return double_add(self.val, other)
|
||||
|
||||
class Container[T]():
|
||||
value: T
|
||||
flag: CInt32T
|
||||
def __init__(self, v: T):
|
||||
self.value = T(v)
|
||||
self.flag = CInt32T(1)
|
||||
def get_value(self) -> T:
|
||||
return self.value
|
||||
def get_flag(self) -> CInt32T:
|
||||
return self.flag
|
||||
|
||||
|
||||
def main() -> CInt | CExport:
|
||||
w32.win32console.SetConsoleCP(65001)
|
||||
w32.win32console.SetConsoleOutputCP(65001)
|
||||
|
||||
testcheck.begin("GenericOopTest: 泛型专项测试")
|
||||
|
||||
buf: CChar | CPtr = CPtr(stdlib.malloc(256))
|
||||
|
||||
# === 基础函数泛型 ===
|
||||
testcheck.section("基础函数泛型")
|
||||
print(add(3, 5))
|
||||
print(add(1.5, 2.5))
|
||||
print(add_u64(1, 2, CUInt64T(3000000000000000)))
|
||||
print(fxi(0.2, 6))
|
||||
print(wrap_add(10, 20))
|
||||
print(double_add(5, 7))
|
||||
testcheck.ok("基础函数泛型测试完成")
|
||||
|
||||
# === 基础结构体泛型 ===
|
||||
testcheck.section("基础结构体泛型")
|
||||
a = A(100)
|
||||
print(a.get_a())
|
||||
p1 = Pair(10, 20)
|
||||
print(p1.get_first())
|
||||
print(p1.get_second())
|
||||
testcheck.ok("基础结构体泛型测试完成")
|
||||
|
||||
# === 泛型 + OOP 组合 ===
|
||||
testcheck.section("泛型 + OOP 组合")
|
||||
calc1 = Calculator(10)
|
||||
print(calc1.compute(5))
|
||||
calc2 = Calculator(2)
|
||||
print(calc2.compute(3))
|
||||
|
||||
c1_gen = Container(42)
|
||||
print(c1_gen.get_value())
|
||||
print(c1_gen.get_flag())
|
||||
testcheck.ok("泛型 + OOP 组合测试完成")
|
||||
|
||||
# === snprintf 格式化 ===
|
||||
testcheck.section("snprintf 格式化")
|
||||
viperlib.snprintf(buf, 256, "int=%d, float=%.2f", 42, 3.14)
|
||||
print(buf)
|
||||
viperlib.snprintf(buf, 256, "result=%d", add(100, 200))
|
||||
print(buf)
|
||||
testcheck.ok("snprintf 格式化测试完成")
|
||||
|
||||
# === 新语法类型强转 (t1|t2)(x) ===
|
||||
testcheck.section("新语法类型强转 (t1|t2)(x)")
|
||||
val_i64: CUInt64T = CUInt64T(42)
|
||||
val_i32 = (t.CInt)(val_i64)
|
||||
print(val_i32)
|
||||
|
||||
ptr_raw = stdlib.malloc(8)
|
||||
ptr_typed = (t.CInt | t.CPtr)(ptr_raw)
|
||||
viperlib.snprintf(buf, 256, "cast ptr=%p", ptr_typed)
|
||||
print(buf)
|
||||
|
||||
val_f = (t.CDouble)(42)
|
||||
viperlib.snprintf(buf, 256, "cast float=%.1f", val_f)
|
||||
print(buf)
|
||||
testcheck.ok("新语法类型强转测试完成")
|
||||
|
||||
stdlib.free(buf)
|
||||
return testcheck.end()
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
|
||||
"name": "GenericOopTest",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": [
|
||||
"-filetype=obj",
|
||||
"-relocation-model=pic"
|
||||
]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": [
|
||||
"-Wl,--allow-multiple-definition",
|
||||
"-lmsvcrt",
|
||||
"-lucrt",
|
||||
"-lpthread",
|
||||
"-lmingwex",
|
||||
"-lkernel32",
|
||||
"-luser32"
|
||||
],
|
||||
"output": "GenericOopTest.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
import t
|
||||
import stdio
|
||||
import testcheck
|
||||
|
||||
# ============================================================
|
||||
# Test 1: 泛型函数 - 基本加法
|
||||
# ============================================================
|
||||
def add[T](a: T, b: T) -> T:
|
||||
return a + b
|
||||
|
||||
def test_generic_add():
|
||||
testcheck.section("Test 1: generic add")
|
||||
r1: t.CInt = add(3, 5)
|
||||
r2: t.CInt = add(100, 200)
|
||||
testcheck.check(r1 == 8 and r2 == 300, "generic add (3+5=8, 100+200=300)", "generic add expect 8 and 300")
|
||||
|
||||
# ============================================================
|
||||
# Test 2: 泛型函数 - 多类型参数
|
||||
# ============================================================
|
||||
def combine[T1, T2](a: T1, b: T2) -> T1:
|
||||
return a + T1(b)
|
||||
|
||||
def test_generic_combine():
|
||||
testcheck.section("Test 2: generic combine")
|
||||
r: t.CInt = combine(10, 20)
|
||||
testcheck.check(r == 30, "generic combine (10+T1(20)=30)", "generic combine expect 30")
|
||||
|
||||
# ============================================================
|
||||
# Test 3: 泛型函数 - 最大值
|
||||
# ============================================================
|
||||
def max_val[T](a: T, b: T) -> T:
|
||||
if a > b:
|
||||
return a
|
||||
return b
|
||||
|
||||
def test_generic_max():
|
||||
testcheck.section("Test 3: generic max")
|
||||
r1: t.CInt = max_val(10, 20)
|
||||
r2: t.CInt = max_val(50, 30)
|
||||
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]
|
||||
# ============================================================
|
||||
class Box[T]():
|
||||
value: T
|
||||
|
||||
def __init__(self, v: T):
|
||||
self.value = T(v)
|
||||
|
||||
def get(self) -> T:
|
||||
return self.value
|
||||
|
||||
def set(self, v: T):
|
||||
self.value = T(v)
|
||||
|
||||
def test_generic_box():
|
||||
testcheck.section("Test 4: generic Box[T]")
|
||||
b = Box(42)
|
||||
v: t.CInt = b.get()
|
||||
testcheck.check(v == 42, "Box[int] (get=42)", "Box[int] expect 42")
|
||||
|
||||
# ============================================================
|
||||
# Test 5: 泛型类 - Pair[T1, T2]
|
||||
# ============================================================
|
||||
class Pair[T1, T2]():
|
||||
first: T1
|
||||
second: T2
|
||||
|
||||
def __init__(self, a: T1, b: T2):
|
||||
self.first = T1(a)
|
||||
self.second = T2(b)
|
||||
|
||||
def sum_as_int(self) -> t.CInt:
|
||||
return t.CInt(self.first) + t.CInt(self.second)
|
||||
|
||||
def test_generic_pair():
|
||||
testcheck.section("Test 5: generic Pair[T1,T2]")
|
||||
p = Pair(10, 20)
|
||||
r: t.CInt = p.sum_as_int()
|
||||
testcheck.check(r == 30, "Pair[int,int] (sum=30)", "Pair[int,int] expect 30")
|
||||
|
||||
# ============================================================
|
||||
# Test 6: list[T, N] 固定数组
|
||||
# ============================================================
|
||||
def test_fixed_array():
|
||||
testcheck.section("Test 6: list[T, N] fixed array")
|
||||
arr: t.CArray[t.CInt, 5] = [0]
|
||||
for i in range(5):
|
||||
arr[i] = i * 10
|
||||
total: t.CInt = 0
|
||||
for i in range(5):
|
||||
total += arr[i]
|
||||
# 0+10+20+30+40 = 100
|
||||
testcheck.check(total == 100, "fixed array (total=100)", "fixed array expect 100")
|
||||
|
||||
# ============================================================
|
||||
# Test 7: list[t.CChar, N] 字符数组
|
||||
# ============================================================
|
||||
def test_char_array():
|
||||
testcheck.section("Test 7: list[t.CChar, N] char array")
|
||||
buf: t.CArray[t.CChar, 32] = [0]
|
||||
buf[0] = 72 # H
|
||||
buf[1] = 105 # i
|
||||
buf[2] = 0
|
||||
testcheck.check(buf[0] == 72 and buf[1] == 105, "char array (H=72 i=105)", "char array expect H=72 i=105")
|
||||
|
||||
# ============================================================
|
||||
# Test 8: 泛型函数多次特化
|
||||
# ============================================================
|
||||
def identity[T](x: T) -> T:
|
||||
return x
|
||||
|
||||
def test_generic_identity():
|
||||
testcheck.section("Test 8: generic identity")
|
||||
r1: t.CInt = identity(42)
|
||||
r2: t.CInt = identity(0)
|
||||
testcheck.check(r1 == 42 and r2 == 0, "identity (42=42, 0=0)", "identity expect 42 and 0")
|
||||
|
||||
# ============================================================
|
||||
# Test 9: 泛型函数嵌套调用
|
||||
# ============================================================
|
||||
def double_val[T](x: T) -> T:
|
||||
return add(x, x)
|
||||
|
||||
def test_generic_nested():
|
||||
testcheck.section("Test 9: generic nested call")
|
||||
r: t.CInt = double_val(21)
|
||||
testcheck.check(r == 42, "generic nested (double(21)=42)", "generic nested expect 42")
|
||||
|
||||
# ============================================================
|
||||
# Test 10: 泛型类方法调用
|
||||
# ============================================================
|
||||
class Counter[T]():
|
||||
count: T
|
||||
|
||||
def __init__(self, start: T):
|
||||
self.count = T(start)
|
||||
|
||||
def increment(self):
|
||||
self.count = add(self.count, T(1))
|
||||
|
||||
def get_count(self) -> T:
|
||||
return self.count
|
||||
|
||||
def test_generic_counter():
|
||||
testcheck.section("Test 10: generic Counter[T]")
|
||||
c = Counter(0)
|
||||
c.increment()
|
||||
c.increment()
|
||||
c.increment()
|
||||
r: t.CInt = c.get_count()
|
||||
testcheck.check(r == 3, "Counter[int] (count=3)", "Counter[int] expect 3")
|
||||
|
||||
def main() -> t.CInt:
|
||||
testcheck.begin("GenericTest: 泛型测试")
|
||||
test_generic_add()
|
||||
test_generic_combine()
|
||||
test_generic_max()
|
||||
test_generic_box()
|
||||
test_generic_pair()
|
||||
test_fixed_array()
|
||||
test_char_array()
|
||||
test_generic_identity()
|
||||
test_generic_nested()
|
||||
test_generic_counter()
|
||||
return testcheck.end()
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
|
||||
"name": "GenericTest",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": [
|
||||
"-filetype=obj",
|
||||
"-relocation-model=pic"
|
||||
]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": [
|
||||
"-Wl,--allow-multiple-definition",
|
||||
"-lmsvcrt",
|
||||
"-lucrt",
|
||||
"-lpthread",
|
||||
"-lmingwex",
|
||||
"-lkernel32",
|
||||
"-luser32"
|
||||
],
|
||||
"output": "GenericTest.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,273 @@
|
||||
import t
|
||||
import stdio
|
||||
import c
|
||||
import testcheck
|
||||
|
||||
# ============================================================
|
||||
# Test 1: 泛型函数 - 不同整数类型特化
|
||||
# ============================================================
|
||||
def square[T](x: T) -> T:
|
||||
return x * x
|
||||
|
||||
def test_generic_square_types():
|
||||
testcheck.section("Test 1: generic square with different types")
|
||||
r1: t.CInt = square(5)
|
||||
r2: t.CInt = square(10)
|
||||
testcheck.check(r1 == 25 and r2 == 100, "square (5^2=25 10^2=100)", "square expect 25 100")
|
||||
|
||||
# ============================================================
|
||||
# Test 2: 泛型函数 - 三参数
|
||||
# ============================================================
|
||||
def clamp[T](val: T, lo: T, hi: T) -> T:
|
||||
if val < lo:
|
||||
return lo
|
||||
if val > hi:
|
||||
return hi
|
||||
return val
|
||||
|
||||
def test_generic_clamp():
|
||||
testcheck.section("Test 2: generic clamp")
|
||||
r1: t.CInt = clamp(5, 0, 10)
|
||||
r2: t.CInt = clamp(-3, 0, 10)
|
||||
r3: t.CInt = clamp(15, 0, 10)
|
||||
testcheck.check(r1 == 5 and r2 == 0 and r3 == 10, "clamp (5 0 10)", "clamp expect 5 0 10")
|
||||
|
||||
# ============================================================
|
||||
# Test 3: 泛型类 - Stack[T]
|
||||
# ============================================================
|
||||
class Stack[T]():
|
||||
data: t.CArray[t.CInt, 16]
|
||||
top: t.CInt
|
||||
|
||||
def __init__(self):
|
||||
self.top = 0
|
||||
|
||||
def push(self, val: T):
|
||||
self.data[self.top] = t.CInt(val)
|
||||
self.top += 1
|
||||
|
||||
def pop(self) -> T:
|
||||
self.top -= 1
|
||||
return T(self.data[self.top])
|
||||
|
||||
def is_empty(self) -> t.CInt:
|
||||
if self.top == 0:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def size_of(self) -> t.CSizeT:
|
||||
return self.__sizeof__()
|
||||
|
||||
def type_size(self) -> t.CSizeT:
|
||||
return Stack[T].__sizeof__()
|
||||
|
||||
def test_generic_stack():
|
||||
testcheck.section("Test 3: generic Stack[T]")
|
||||
# 显式标注 Stack[int]:T 无法从实参推断(__init__ 无参),且 T 决定
|
||||
# push/pop 的元素宽度(t.CInt(val) ↔ i32),静默默认 int 已被禁止。
|
||||
s = Stack[int]()
|
||||
s.push(10)
|
||||
s.push(20)
|
||||
s.push(30)
|
||||
r1: t.CInt = s.pop()
|
||||
r2: t.CInt = s.pop()
|
||||
r3: t.CInt = s.pop()
|
||||
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
|
||||
# ============================================================
|
||||
class IntPair:
|
||||
a: t.CInt
|
||||
b: t.CInt
|
||||
|
||||
def generic_swap[T](p: IntPair | t.CPtr):
|
||||
tmp: t.CInt = c.Deref(p).a
|
||||
c.Deref(p).a = c.Deref(p).b
|
||||
c.Deref(p).b = tmp
|
||||
|
||||
def test_generic_swap():
|
||||
testcheck.section("Test 4: generic swap via pointer")
|
||||
p: IntPair = IntPair()
|
||||
p.a = 100
|
||||
p.b = 200
|
||||
generic_swap(c.Addr(p))
|
||||
testcheck.check(p.a == 200 and p.b == 100, "swap (a=200 b=100)", "swap expect 200 100")
|
||||
|
||||
# ============================================================
|
||||
# Test 5: 泛型类 - Range[T] 迭代器
|
||||
# ============================================================
|
||||
class Range[T]():
|
||||
start: T
|
||||
end_val: T
|
||||
step: T
|
||||
|
||||
def __init__(self, s: T, e: T, st: T):
|
||||
self.start = T(s)
|
||||
self.end_val = T(e)
|
||||
self.step = T(st)
|
||||
|
||||
def sum_all(self) -> T:
|
||||
result: T = T(0)
|
||||
i: T = self.start
|
||||
while i < self.end_val:
|
||||
result = result + i
|
||||
i = i + self.step
|
||||
return result
|
||||
|
||||
def test_generic_range():
|
||||
testcheck.section("Test 5: generic Range[T]")
|
||||
r = Range(0, 10, 1) # 0+1+2+...+9=45
|
||||
s: t.CInt = r.sum_all()
|
||||
testcheck.check(s == 45, "Range sum (0..9=45)", "Range sum expect 45")
|
||||
|
||||
# ============================================================
|
||||
# Test 6: 泛型函数 - 数组求和(非泛型数组参数)
|
||||
# ============================================================
|
||||
def array_sum(arr: t.CArray[t.CInt, 8], n: t.CInt) -> t.CInt:
|
||||
result: t.CInt = 0
|
||||
for i in range(n):
|
||||
result += arr[i]
|
||||
return result
|
||||
|
||||
def test_generic_array_sum():
|
||||
testcheck.section("Test 6: array sum")
|
||||
arr: t.CArray[t.CInt, 8] = [0]
|
||||
for i in range(8):
|
||||
arr[i] = (i + 1) * 10
|
||||
s: t.CInt = array_sum(arr, 8)
|
||||
testcheck.check(s == 360, "array sum (360)", "array sum expect 360")
|
||||
|
||||
# ============================================================
|
||||
# Test 7: 泛型函数 - 比较并返回较大值
|
||||
# ============================================================
|
||||
def max_of_three[T](a: T, b: T, c_val: T) -> T:
|
||||
m: T = a
|
||||
if b > m:
|
||||
m = b
|
||||
if c_val > m:
|
||||
m = c_val
|
||||
return m
|
||||
|
||||
def test_generic_max_three():
|
||||
testcheck.section("Test 7: generic max of three")
|
||||
r1: t.CInt = max_of_three(1, 2, 3)
|
||||
r2: t.CInt = max_of_three(10, 30, 20)
|
||||
r3: t.CInt = max_of_three(50, 50, 50)
|
||||
testcheck.check(r1 == 3 and r2 == 30 and r3 == 50, "max3 (3 30 50)", "max3 expect 3 30 50")
|
||||
|
||||
# ============================================================
|
||||
# Test 8: 泛型类 - 带方法的容器
|
||||
# ============================================================
|
||||
class Container[T]():
|
||||
values: t.CArray[t.CInt, 8]
|
||||
size: t.CInt
|
||||
|
||||
def __init__(self):
|
||||
self.size = 0
|
||||
|
||||
def add(self, v: T):
|
||||
self.values[self.size] = t.CInt(v)
|
||||
self.size += 1
|
||||
|
||||
def get(self, idx: t.CInt) -> T:
|
||||
return T(self.values[idx])
|
||||
|
||||
def contains(self, v: T) -> t.CInt:
|
||||
for i in range(self.size):
|
||||
if self.values[i] == t.CInt(v):
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def total(self) -> T:
|
||||
result: T = T(0)
|
||||
for i in range(self.size):
|
||||
result = result + T(self.values[i])
|
||||
return result
|
||||
|
||||
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])。
|
||||
c = Container[int]()
|
||||
c.add(10)
|
||||
c.add(20)
|
||||
c.add(30)
|
||||
has20: t.CInt = c.contains(20)
|
||||
has99: t.CInt = c.contains(99)
|
||||
total: t.CInt = c.total()
|
||||
testcheck.check(has20 == 1 and has99 == 0 and total == 60, "Container (has20=1 has99=0 total=60)", "Container expect 1 0 60")
|
||||
|
||||
# ============================================================
|
||||
# Test 9: 泛型函数 - 阶乘
|
||||
# ============================================================
|
||||
def factorial[T](n: T) -> T:
|
||||
result: T = T(1)
|
||||
i: T = T(2)
|
||||
while i <= n:
|
||||
result = result * i
|
||||
i = i + T(1)
|
||||
return result
|
||||
|
||||
def test_generic_factorial():
|
||||
testcheck.section("Test 9: generic factorial")
|
||||
r1: t.CInt = factorial(5)
|
||||
r2: t.CInt = factorial(10)
|
||||
testcheck.check(r1 == 120 and r2 == 3628800, "factorial (5!=120 10!=3628800)", "factorial expect 120 3628800")
|
||||
|
||||
# ============================================================
|
||||
# Test 10: 泛型类 - 累加器
|
||||
# ============================================================
|
||||
class Accumulator[T]():
|
||||
total: T
|
||||
|
||||
def __init__(self, start: T):
|
||||
self.total = T(start)
|
||||
|
||||
def add_val(self, v: T):
|
||||
self.total = self.total + v
|
||||
|
||||
def get_result(self) -> T:
|
||||
return self.total
|
||||
|
||||
def test_generic_accumulator():
|
||||
testcheck.section("Test 10: generic Accumulator[T]")
|
||||
a = Accumulator(0)
|
||||
a.add_val(10)
|
||||
a.add_val(20)
|
||||
a.add_val(30)
|
||||
r: t.CInt = a.get_result()
|
||||
testcheck.check(r == 60, "Accumulator (result=60)", "Accumulator expect 60")
|
||||
|
||||
# ============================================================
|
||||
# Test 11: 泛型结构体 sizeof (修复验证)
|
||||
# 特化后 Stack[int] = { [16 x i32], i32 } = 68 字节
|
||||
# 验证 obj.__sizeof__() 和类内部 self.__sizeof__() 均返回正确大小
|
||||
# ============================================================
|
||||
def test_generic_sizeof_bug():
|
||||
testcheck.section("Test 11: generic sizeof (fixed)")
|
||||
# 同 Test 3:无参构造必须显式标注类型实参;Stack[int] = { [16 x i32], i32 } = 68。
|
||||
s = Stack[int]()
|
||||
s.push(10)
|
||||
sz: t.CSizeT = s.__sizeof__()
|
||||
inner_sz: t.CSizeT = s.size_of()
|
||||
type_sz: t.CSizeT = s.type_size()
|
||||
stdio.printf("Stack[int] obj.__sizeof__() = %lu, self.__sizeof__() = %lu, Stack[T].__sizeof__() = %lu (expect 68)\n", sz, inner_sz, type_sz)
|
||||
testcheck.check(sz == 68, "obj.__sizeof__() == 68 OK", "obj.__sizeof__() FAILED")
|
||||
testcheck.check(inner_sz == 68, "self.__sizeof__() == 68 OK", "self.__sizeof__() FAILED")
|
||||
testcheck.check(type_sz == 68, "Stack[T].__sizeof__() == 68 OK", "Stack[T].__sizeof__() FAILED")
|
||||
|
||||
def main() -> t.CInt:
|
||||
testcheck.begin("GenericTest2: Advanced Generic Tests")
|
||||
test_generic_square_types()
|
||||
test_generic_clamp()
|
||||
test_generic_stack()
|
||||
test_generic_swap()
|
||||
test_generic_range()
|
||||
test_generic_array_sum()
|
||||
test_generic_max_three()
|
||||
test_generic_container()
|
||||
test_generic_factorial()
|
||||
test_generic_accumulator()
|
||||
test_generic_sizeof_bug()
|
||||
return testcheck.end()
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
|
||||
"name": "GenericTest2",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": [
|
||||
"-filetype=obj",
|
||||
"-relocation-model=pic"
|
||||
]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": [
|
||||
"-Wl,--allow-multiple-definition",
|
||||
"-lmsvcrt",
|
||||
"-lucrt",
|
||||
"-lpthread",
|
||||
"-lmingwex",
|
||||
"-lkernel32",
|
||||
"-luser32"
|
||||
],
|
||||
"output": "GenericTest2.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
import t
|
||||
import stdio
|
||||
import testcheck
|
||||
|
||||
# ============================================================
|
||||
# Test 1: 泛型函数手动传类型参数 - 基本调用
|
||||
# def xxx[T](x: int) 然后调用 xxx[T](x)
|
||||
# ============================================================
|
||||
def double[T](x: int) -> int:
|
||||
return x * 2
|
||||
|
||||
def test_explicit_type_arg():
|
||||
testcheck.section("Test 1: explicit type arg xxx[T](x)")
|
||||
r: t.CInt = double[t.CInt](21)
|
||||
testcheck.check(r == 42, "double[t.CInt](21) = 42", "expect 42")
|
||||
|
||||
# ============================================================
|
||||
# Test 2: 泛型函数手动传类型参数 - 多次调用不同类型
|
||||
# ============================================================
|
||||
def identity[T](x: int) -> int:
|
||||
return x
|
||||
|
||||
def test_identity_explicit():
|
||||
testcheck.section("Test 2: identity[T](x)")
|
||||
r1: t.CInt = identity[t.CInt](10)
|
||||
r2: t.CInt = identity[t.CInt](20)
|
||||
testcheck.check(r1 == 10 and r2 == 20, "identity[t.CInt](10)=10 (20)=20", "expect 10 20")
|
||||
|
||||
# ============================================================
|
||||
# Test 3: 泛型函数手动传类型参数 - 用 T 作为参数类型
|
||||
# ============================================================
|
||||
def add_one[T](x: T) -> T:
|
||||
return x + T(1)
|
||||
|
||||
def test_add_one_explicit():
|
||||
testcheck.section("Test 3: add_one[T](x) with T param")
|
||||
r: t.CInt = add_one[t.CInt](41)
|
||||
testcheck.check(r == 42, "add_one[t.CInt](41) = 42", "expect 42")
|
||||
|
||||
# ============================================================
|
||||
# Test 4: 泛型函数手动传类型参数 - 混合自动推导和手动传
|
||||
# ============================================================
|
||||
def test_mixed_inference_explicit():
|
||||
testcheck.section("Test 4: mixed inference and explicit")
|
||||
# 自动推导
|
||||
r1: t.CInt = add_one(99)
|
||||
# 手动传
|
||||
r2: t.CInt = add_one[t.CInt](99)
|
||||
testcheck.check(r1 == 100 and r2 == 100, "add_one(99)=100 add_one[t.CInt](99)=100", "expect 100 100")
|
||||
|
||||
def main() -> t.CInt:
|
||||
testcheck.begin("GenericTest3: 手动传类型参数 xxx[T](x)")
|
||||
test_explicit_type_arg()
|
||||
test_identity_explicit()
|
||||
test_add_one_explicit()
|
||||
test_mixed_inference_explicit()
|
||||
return testcheck.end()
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
|
||||
"name": "GenericTest3",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": [
|
||||
"-filetype=obj",
|
||||
"-relocation-model=pic"
|
||||
]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": [
|
||||
"-Wl,--allow-multiple-definition",
|
||||
"-lmsvcrt",
|
||||
"-lucrt",
|
||||
"-lpthread",
|
||||
"-lmingwex",
|
||||
"-lkernel32",
|
||||
"-luser32"
|
||||
],
|
||||
"output": "GenericTest3.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
import t
|
||||
import stdio
|
||||
import testcheck
|
||||
|
||||
# ============================================================
|
||||
# Test 1: 泛型类手动传类型参数 - Box[t.CInt](v)
|
||||
# ============================================================
|
||||
class Box[T]():
|
||||
value: T
|
||||
|
||||
def __init__(self, v: T):
|
||||
self.value = T(v)
|
||||
|
||||
def get(self) -> T:
|
||||
return self.value
|
||||
|
||||
def set(self, v: T):
|
||||
self.value = T(v)
|
||||
|
||||
def test_explicit_box():
|
||||
testcheck.section("Test 1: Box[t.CInt](42)")
|
||||
b = Box[t.CInt](42)
|
||||
v: t.CInt = b.get()
|
||||
testcheck.check(v == 42, "Box[t.CInt](42).get() = 42", "expect 42")
|
||||
|
||||
# ============================================================
|
||||
# Test 2: 泛型类手动传类型参数 - Pair[t.CInt, t.CInt]
|
||||
# ============================================================
|
||||
class Pair[T1, T2]():
|
||||
first: T1
|
||||
second: T2
|
||||
|
||||
def __init__(self, a: T1, b: T2):
|
||||
self.first = T1(a)
|
||||
self.second = T2(b)
|
||||
|
||||
def sum_as_int(self) -> t.CInt:
|
||||
return t.CInt(self.first) + t.CInt(self.second)
|
||||
|
||||
def test_explicit_pair():
|
||||
testcheck.section("Test 2: Pair[t.CInt, t.CInt](10, 20)")
|
||||
p = Pair[t.CInt, t.CInt](10, 20)
|
||||
r: t.CInt = p.sum_as_int()
|
||||
testcheck.check(r == 30, "Pair[t.CInt,t.CInt](10,20).sum = 30", "expect 30")
|
||||
|
||||
# ============================================================
|
||||
# Test 3: 泛型类手动传 + 自动推导混合
|
||||
# ============================================================
|
||||
class Wrapper[T]():
|
||||
data: T
|
||||
|
||||
def __init__(self, v: T):
|
||||
self.data = T(v)
|
||||
|
||||
def get(self) -> T:
|
||||
return self.data
|
||||
|
||||
def test_mixed_generic_class():
|
||||
testcheck.section("Test 3: mixed explicit and inferred")
|
||||
# 手动传
|
||||
w1 = Wrapper[t.CInt](100)
|
||||
# 自动推导
|
||||
w2 = Wrapper(200)
|
||||
r1: t.CInt = w1.get()
|
||||
r2: t.CInt = w2.get()
|
||||
testcheck.check(r1 == 100 and r2 == 200, "Wrapper[t.CInt](100)=100 Wrapper(200)=200", "expect 100 200")
|
||||
|
||||
# ============================================================
|
||||
# Test 4: 泛型类手动传 - 方法调用
|
||||
# ============================================================
|
||||
class Counter[T]():
|
||||
count: T
|
||||
|
||||
def __init__(self, start: T):
|
||||
self.count = T(start)
|
||||
|
||||
def increment(self):
|
||||
self.count = self.count + T(1)
|
||||
|
||||
def get_count(self) -> T:
|
||||
return self.count
|
||||
|
||||
def test_explicit_counter():
|
||||
testcheck.section("Test 4: Counter[t.CInt](0) with methods")
|
||||
c = Counter[t.CInt](0)
|
||||
c.increment()
|
||||
c.increment()
|
||||
c.increment()
|
||||
r: t.CInt = c.get_count()
|
||||
testcheck.check(r == 3, "Counter[t.CInt](0) +3 = 3", "expect 3")
|
||||
|
||||
# ============================================================
|
||||
# Test 5: 泛型类手动传 - set 方法
|
||||
# ============================================================
|
||||
def test_explicit_box_set():
|
||||
testcheck.section("Test 5: Box[t.CInt] set method")
|
||||
b = Box[t.CInt](10)
|
||||
b.set(99)
|
||||
v: t.CInt = b.get()
|
||||
testcheck.check(v == 99, "Box[t.CInt].set(99) get = 99", "expect 99")
|
||||
|
||||
def main() -> t.CInt:
|
||||
testcheck.begin("GenericTest4: 泛型结构体手动传类型参数")
|
||||
test_explicit_box()
|
||||
test_explicit_pair()
|
||||
test_mixed_generic_class()
|
||||
test_explicit_counter()
|
||||
test_explicit_box_set()
|
||||
return testcheck.end()
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
|
||||
"name": "GenericTest4",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": [
|
||||
"-filetype=obj",
|
||||
"-relocation-model=pic"
|
||||
]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": [
|
||||
"-Wl,--allow-multiple-definition",
|
||||
"-lmsvcrt",
|
||||
"-lucrt",
|
||||
"-lpthread",
|
||||
"-lmingwex",
|
||||
"-lkernel32",
|
||||
"-luser32"
|
||||
],
|
||||
"output": "GenericTest4.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
import t, c
|
||||
import stdio
|
||||
import stdlib
|
||||
import string
|
||||
import testcheck
|
||||
import hashlib
|
||||
import binascii
|
||||
import base64
|
||||
import w32.win32console
|
||||
|
||||
|
||||
# ==============================================
|
||||
# 工具函数:打印十六进制哈希串
|
||||
# ==============================================
|
||||
def print_hex(buf: t.CUInt8T | t.CPtr, length: t.CInt):
|
||||
for i in range(length):
|
||||
stdio.printf("%02x", buf[i])
|
||||
stdio.printf("\n")
|
||||
|
||||
|
||||
def default_value_test_function(a: t.CInt, b: t.CInt = 1):
|
||||
print(a, b)
|
||||
|
||||
|
||||
def main() -> t.CInt | t.CExport:
|
||||
w32.win32console.SetConsoleCP(65001)
|
||||
w32.win32console.SetConsoleOutputCP(65001)
|
||||
|
||||
testcheck.begin("HashLibTest: 哈希与校验测试")
|
||||
|
||||
# ---------- hashlib 摘要测试 ----------
|
||||
testcheck.section("HASHLIB")
|
||||
plain: str = "hello123"
|
||||
|
||||
md5_buf: t.CArray[t.CUInt8T, hashlib.MD5_DIGEST_LEN]
|
||||
mctx = hashlib.md5()
|
||||
mctx.update(plain)
|
||||
mctx.final(md5_buf)
|
||||
print("MD5: ")
|
||||
print_hex(md5_buf, hashlib.MD5_DIGEST_LEN)
|
||||
testcheck.ok("HASHLIB md5 completed")
|
||||
|
||||
sha1_buf: t.CArray[t.CUInt8T, hashlib.SHA1_DIGEST_LEN]
|
||||
s1ctx = hashlib.sha1()
|
||||
s1ctx.update(plain)
|
||||
s1ctx.final(sha1_buf)
|
||||
print("SHA1: ")
|
||||
print_hex(sha1_buf, hashlib.SHA1_DIGEST_LEN)
|
||||
testcheck.ok("HASHLIB sha1 completed")
|
||||
|
||||
sha256_buf: t.CArray[t.CUInt8T, hashlib.SHA256_DIGEST_LEN]
|
||||
s2ctx = hashlib.sha256()
|
||||
s2ctx.update(plain)
|
||||
s2ctx.final(sha256_buf)
|
||||
print("SHA256: ")
|
||||
print_hex(sha256_buf, hashlib.SHA256_DIGEST_LEN)
|
||||
testcheck.ok("HASHLIB sha256 completed")
|
||||
|
||||
sha512_buf: t.CArray[t.CUInt8T, hashlib.SHA512_DIGEST_LEN]
|
||||
s5ctx = hashlib.sha512()
|
||||
s5ctx.update(plain)
|
||||
s5ctx.final(sha512_buf)
|
||||
print("SHA512: ")
|
||||
print_hex(sha512_buf, hashlib.SHA512_DIGEST_LEN)
|
||||
testcheck.ok("HASHLIB sha512 completed")
|
||||
|
||||
default_value_test_function(b=2, a=1)
|
||||
testcheck.ok("default value test completed")
|
||||
|
||||
# ---------- base64 编解码测试 ----------
|
||||
testcheck.section("BASE64")
|
||||
b64_out: t.CArray[t.CChar, 256]
|
||||
b64_dec: t.CArray[t.CUInt8T, 256]
|
||||
base64.b64encode(plain, b64_out)
|
||||
print("Base64 编码:", b64_out)
|
||||
dlen: t.CSizeT = base64.b64decode(b64_out, b64_dec)
|
||||
b64_dec[dlen] = 0
|
||||
print("Base64 解码:", b64_dec)
|
||||
testcheck.ok("BASE64 encode/decode completed")
|
||||
|
||||
# ---------- binascii 全套测试 ----------
|
||||
testcheck.section("BINASCII")
|
||||
binascii.init_binascii()
|
||||
raw: str = "HelloWorld!"
|
||||
raw_length: t.CInt = 11
|
||||
|
||||
hex_out: str = binascii.b2a_hex(raw, raw_length)
|
||||
if hex_out:
|
||||
stdio.printf("Hex: %s\n", hex_out)
|
||||
stdlib.free(hex_out)
|
||||
testcheck.ok("BINASCII b2a_hex completed")
|
||||
|
||||
crc_val: t.CUnsignedInt = binascii.crc32(raw, raw_length, 0)
|
||||
stdio.printf("CRC32: %u\n", crc_val)
|
||||
testcheck.ok("BINASCII crc32 completed")
|
||||
|
||||
b64_out2: str = binascii.b2a_base64(raw, raw_length)
|
||||
if b64_out2:
|
||||
stdio.printf("Base64: %s\n", b64_out2)
|
||||
stdlib.free(b64_out2)
|
||||
testcheck.ok("BINASCII b2a_base64 completed")
|
||||
|
||||
uu_out: str = binascii.b2a_uu(raw, raw_length)
|
||||
if uu_out:
|
||||
stdio.printf("UU: %s\n", uu_out)
|
||||
stdlib.free(uu_out)
|
||||
testcheck.ok("BINASCII b2a_uu completed")
|
||||
|
||||
hqx_in: t.CArray[t.CChar, 4] = ['A', 'B', 'C', '\0']
|
||||
hqx_crc: t.CUnsignedShort = 0
|
||||
hqx_out: str
|
||||
unhqx: str
|
||||
hqx_out, hqx_crc = binascii.b2a_hqx(hqx_in, 3)
|
||||
unhqx, hqx_crc = binascii.a2b_hqx(hqx_out)
|
||||
stdio.printf("HQX Test: ABC -> %s -> %s (CRC:%u)\n", hqx_out, unhqx, hqx_crc)
|
||||
stdlib.free(hqx_out); stdlib.free(unhqx)
|
||||
testcheck.ok("BINASCII hqx completed")
|
||||
|
||||
adler_val: t.CUnsignedInt = binascii.adler32(raw, raw_length, 1)
|
||||
stdio.printf("Adler32: %u\n", adler_val)
|
||||
testcheck.ok("BINASCII adler32 completed")
|
||||
|
||||
return testcheck.end()
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
|
||||
"name": "HashLibTest",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": [
|
||||
"-filetype=obj",
|
||||
"-relocation-model=pic"
|
||||
]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": [
|
||||
"-Wl,--allow-multiple-definition",
|
||||
"-lmsvcrt",
|
||||
"-lucrt",
|
||||
"-lpthread",
|
||||
"-lmingwex",
|
||||
"-lkernel32",
|
||||
"-luser32"
|
||||
],
|
||||
"output": "HashLibTest.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
from stdint import *
|
||||
import w32.win32console
|
||||
import t, c
|
||||
from t import CInt, CExport
|
||||
import stdio
|
||||
import stdlib
|
||||
import string
|
||||
import memhub
|
||||
import hashtable
|
||||
import testcheck
|
||||
|
||||
|
||||
def main() -> CInt | CExport:
|
||||
w32.win32console.SetConsoleCP(65001)
|
||||
w32.win32console.SetConsoleOutputCP(65001)
|
||||
|
||||
testcheck.begin("HashTableTest: 开放寻址哈希表测试")
|
||||
|
||||
# 分配内存竞技场
|
||||
arena: bytes = stdlib.malloc(65536)
|
||||
bd: memhub.MemBuddy | t.CPtr = memhub.MemBuddy(arena, 65536)
|
||||
|
||||
# === Test 1: 基本插入和查找 ===
|
||||
testcheck.section("Test 1: 基本插入和查找 (set_int)")
|
||||
ht: hashtable.HashTable = hashtable.HashTable(bd)
|
||||
ht.set_int("alpha", 10)
|
||||
ht.set_int("beta", 20)
|
||||
ht.set_int("gamma", 30)
|
||||
n: t.CSizeT = len(ht)
|
||||
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 字节。
|
||||
p1: t.CPtr = ht["alpha"]
|
||||
v1: int = c.Deref((int | t.CPtr)(p1))
|
||||
p2: t.CPtr = ht["beta"]
|
||||
v2: int = c.Deref((int | t.CPtr)(p2))
|
||||
p3: t.CPtr = ht["gamma"]
|
||||
v3: int = c.Deref((int | t.CPtr)(p3))
|
||||
stdio.printf("alpha=%d beta=%d gamma=%d\n", v1, v2, v3)
|
||||
testcheck.check(v1 == 10, "ht[alpha]==10 OK", "ht[alpha] FAILED")
|
||||
testcheck.check(v2 == 20, "ht[beta]==20 OK", "ht[beta] FAILED")
|
||||
testcheck.check(v3 == 30, "ht[gamma]==30 OK", "ht[gamma] FAILED")
|
||||
|
||||
# === Test 2: 更新已有键 ===
|
||||
testcheck.section("Test 2: 更新已有键")
|
||||
ht.set_int("beta", 99)
|
||||
p2b: t.CPtr = ht["beta"]
|
||||
v2b: int = c.Deref((int | t.CPtr)(p2b))
|
||||
stdio.printf("beta(updated)=%d\n", v2b)
|
||||
testcheck.check(v2b == 99, "ht update OK", "ht update FAILED")
|
||||
testcheck.check(len(ht) == 3, "ht len still 3 OK", "ht len changed FAILED")
|
||||
|
||||
# === Test 3: get with default ===
|
||||
testcheck.section("Test 3: get with default")
|
||||
gv: t.CPtr = ht.get("missing", None)
|
||||
testcheck.check(gv == None, "ht get missing OK (None)", "ht get missing FAILED")
|
||||
gp: t.CPtr = ht.get("alpha", None)
|
||||
ga: int = c.Deref((int | t.CPtr)(gp))
|
||||
stdio.printf("get(alpha)=%d\n", ga)
|
||||
testcheck.check(ga == 10, "ht get existing OK", "ht get existing FAILED")
|
||||
|
||||
# === Test 4: contains ===
|
||||
testcheck.section("Test 4: contains (in)")
|
||||
has_alpha: t.CInt = "alpha" in ht
|
||||
has_missing: t.CInt = "missing" in ht
|
||||
stdio.printf("contains(alpha)=%d contains(missing)=%d\n", has_alpha, has_missing)
|
||||
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: 删除 ===
|
||||
testcheck.section("Test 5: 删除 (del)")
|
||||
deleted: t.CInt = ht.__delitem__("beta")
|
||||
stdio.printf("del beta=%d\n", deleted)
|
||||
testcheck.check(deleted == 1, "del beta OK", "del beta FAILED")
|
||||
testcheck.check(len(ht) == 2, "ht len 2 after del OK", "ht len after del FAILED")
|
||||
has_beta: t.CInt = "beta" in ht
|
||||
testcheck.check(has_beta == 0, "beta gone OK", "beta still exists FAILED")
|
||||
|
||||
# 删除不存在的 key
|
||||
del_missing: t.CInt = ht.__delitem__("nokey")
|
||||
testcheck.check(del_missing == 0, "del missing returns 0 OK", "del missing FAILED")
|
||||
|
||||
# === Test 6: 删除后重新插入 ===
|
||||
testcheck.section("Test 6: 删除后重新插入")
|
||||
ht.set_int("beta", 555)
|
||||
p2c: t.CPtr = ht["beta"]
|
||||
v2c: int = c.Deref((int | t.CPtr)(p2c))
|
||||
stdio.printf("beta(re-inserted)=%d\n", v2c)
|
||||
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: 迭代器 ===
|
||||
testcheck.section("Test 7: 迭代器 for key in ht")
|
||||
iter_count: int = 0
|
||||
for key in ht:
|
||||
kp: t.CPtr = ht[key]
|
||||
val: int = c.Deref((int | t.CPtr)(kp))
|
||||
stdio.printf("ht[%s]=%d\n", key, val)
|
||||
iter_count += 1
|
||||
testcheck.check(iter_count == 3, "ht iter OK (3)", "ht iter FAILED")
|
||||
|
||||
# === Test 8: 字符串值 ===
|
||||
testcheck.section("Test 8: 字符串值 (set_str)")
|
||||
ht2: hashtable.HashTable = hashtable.HashTable(bd)
|
||||
ht2.set_str("name", "Alice")
|
||||
ht2.set_str("city", "Beijing")
|
||||
ht2.set_str("lang", "TransPyC")
|
||||
n2: t.CSizeT = len(ht2)
|
||||
stdio.printf("ht2 len=%lu\n", n2)
|
||||
testcheck.check(n2 == 3, "ht set_str len OK (3)", "ht set_str len FAILED")
|
||||
|
||||
name_p: t.CPtr = ht2["name"]
|
||||
city_p: t.CPtr = ht2["city"]
|
||||
lang_p: t.CPtr = ht2["lang"]
|
||||
name: str = name_p
|
||||
city: str = city_p
|
||||
lang: str = lang_p
|
||||
stdio.printf("name=%s city=%s lang=%s\n", name, city, lang)
|
||||
# i8* == 是指针地址比较(C-Like 语义),内容比较需显式 strcmp
|
||||
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: 扩容测试 ===
|
||||
testcheck.section("Test 9: 扩容测试 (>16 个元素)")
|
||||
ht3: hashtable.HashTable = hashtable.HashTable(bd)
|
||||
i: int = 0
|
||||
while i < 50:
|
||||
key_buf: str = stdlib.malloc(16)
|
||||
stdio.sprintf(key_buf, "key%d", i)
|
||||
ht3.set_int(key_buf, i * 100)
|
||||
i += 1
|
||||
n3: t.CSizeT = len(ht3)
|
||||
stdio.printf("ht3 len=%lu (after 50 inserts)\n", n3)
|
||||
testcheck.check(n3 == 50, "ht expand OK (50)", "ht expand FAILED")
|
||||
|
||||
# 验证几个值
|
||||
k5: str = stdlib.malloc(16)
|
||||
stdio.sprintf(k5, "key5")
|
||||
p5: t.CPtr = ht3[k5]
|
||||
v5: int = c.Deref((int | t.CPtr)(p5))
|
||||
stdio.printf("ht3[key5]=%d\n", v5)
|
||||
testcheck.check(v5 == 500, "ht expand key5 OK", "ht expand key5 FAILED")
|
||||
|
||||
k25: str = stdlib.malloc(16)
|
||||
stdio.sprintf(k25, "key25")
|
||||
p25: t.CPtr = ht3[k25]
|
||||
v25: int = c.Deref((int | t.CPtr)(p25))
|
||||
stdio.printf("ht3[key25]=%d\n", v25)
|
||||
testcheck.check(v25 == 2500, "ht expand key25 OK", "ht expand key25 FAILED")
|
||||
|
||||
k49: str = stdlib.malloc(16)
|
||||
stdio.sprintf(k49, "key49")
|
||||
p49: t.CPtr = ht3[k49]
|
||||
v49: int = c.Deref((int | t.CPtr)(p49))
|
||||
stdio.printf("ht3[key49]=%d\n", v49)
|
||||
testcheck.check(v49 == 4900, "ht expand key49 OK", "ht expand key49 FAILED")
|
||||
|
||||
# === Test 10: 扩容后迭代 ===
|
||||
testcheck.section("Test 10: 扩容后迭代")
|
||||
iter_count3: int = 0
|
||||
for k in ht3:
|
||||
iter_count3 += 1
|
||||
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: 删除后扩容 ===
|
||||
testcheck.section("Test 11: 批量删除后操作")
|
||||
j: int = 0
|
||||
while j < 25:
|
||||
del_buf: str = stdlib.malloc(16)
|
||||
stdio.sprintf(del_buf, "key%d", j)
|
||||
del ht3[del_buf]
|
||||
j += 1
|
||||
n3b: t.CSizeT = len(ht3)
|
||||
stdio.printf("ht3 len=%lu (after 25 deletes)\n", n3b)
|
||||
testcheck.check(n3b == 25, "ht after del OK (25)", "ht after del FAILED")
|
||||
|
||||
# 验证剩余的值
|
||||
k30: str = stdlib.malloc(16)
|
||||
stdio.sprintf(k30, "key30")
|
||||
p30: t.CPtr = ht3[k30]
|
||||
v30: int = c.Deref((int | t.CPtr)(p30))
|
||||
stdio.printf("ht3[key30]=%d\n", v30)
|
||||
testcheck.check(v30 == 3000, "ht key30 after del OK", "ht key30 after del FAILED")
|
||||
|
||||
# 验证已删除的 key 不存在
|
||||
k0: str = stdlib.malloc(16)
|
||||
stdio.sprintf(k0, "key0")
|
||||
has_k0: t.CInt = k0 in ht3
|
||||
testcheck.check(has_k0 == 0, "ht key0 deleted OK", "ht key0 still exists FAILED")
|
||||
|
||||
# === Test 12: 空表操作 ===
|
||||
testcheck.section("Test 12: 空表操作")
|
||||
ht4: hashtable.HashTable = hashtable.HashTable(bd)
|
||||
testcheck.check(len(ht4) == 0, "empty ht len 0 OK", "empty ht len FAILED")
|
||||
empty_get: t.CPtr = ht4.get("none", None)
|
||||
testcheck.check(empty_get == None, "empty ht get OK", "empty ht get FAILED")
|
||||
has_none: t.CInt = "none" in ht4
|
||||
testcheck.check(has_none == 0, "empty ht contains OK", "empty ht contains FAILED")
|
||||
empty_iter: int = 0
|
||||
for ek in ht4:
|
||||
empty_iter += 1
|
||||
testcheck.check(empty_iter == 0, "empty ht iter OK (0)", "empty ht iter FAILED")
|
||||
|
||||
stdlib.free(arena)
|
||||
return testcheck.end()
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
|
||||
"name": "HashTableTest",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": ["-filetype=obj", "-relocation-model=pic"]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": ["-Wl,--allow-multiple-definition", "-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32"],
|
||||
"output": "HashTableTest.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import t
|
||||
from t import CInt
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 跨模块 isinstance 测试库
|
||||
#
|
||||
# 供 main.vp import 使用:验证 isinstance 对"定义在其他模块
|
||||
# 的类"也能正确比较(对象 vtable 指针跨 obj 链接解析)。
|
||||
# ============================================================
|
||||
|
||||
|
||||
@t.CVTable
|
||||
class Shape:
|
||||
def area(self) -> CInt:
|
||||
return 0
|
||||
|
||||
|
||||
@t.CVTable
|
||||
class Circle(Shape):
|
||||
r: CInt
|
||||
|
||||
def __init__(self, r: CInt):
|
||||
self.r = r
|
||||
|
||||
def area(self) -> CInt:
|
||||
return self.r
|
||||
|
||||
|
||||
@t.CVTable
|
||||
class Square(Shape):
|
||||
s: CInt
|
||||
|
||||
def __init__(self, s: CInt):
|
||||
self.s = s
|
||||
|
||||
def area(self) -> CInt:
|
||||
return self.s
|
||||
|
||||
|
||||
@t.NoVTable
|
||||
class PlainShape:
|
||||
tag: CInt
|
||||
@@ -0,0 +1,153 @@
|
||||
from stdint import *
|
||||
import t, c
|
||||
import testcheck
|
||||
import geom_lib
|
||||
from t import CInt, CPtr, CExport
|
||||
|
||||
|
||||
# ============================================================
|
||||
# isinstance 内建函数测试(运行时 vtable 继承链比较)
|
||||
#
|
||||
# 场景覆盖:
|
||||
# 1. CVTable 自身/子类→基类
|
||||
# 2. 运行时多态(基类指针指向子类对象)
|
||||
# 3. 元组 (A, B)
|
||||
# 4. 多继承(AB 同时是 A 和 B 的实例)
|
||||
# 5. NoVTable 类(编译时静态判断)
|
||||
# ============================================================
|
||||
|
||||
|
||||
# ========== CVTable 继承 ==========
|
||||
|
||||
@t.CVTable
|
||||
class Animal:
|
||||
Name: str
|
||||
|
||||
def __init__(self, name: str):
|
||||
self.Name = name
|
||||
|
||||
def speak(self) -> str:
|
||||
return "..."
|
||||
|
||||
|
||||
@t.CVTable
|
||||
class Dog(Animal):
|
||||
def __init__(self, name: str):
|
||||
self.Name = name
|
||||
|
||||
def speak(self) -> str:
|
||||
return "Woof"
|
||||
|
||||
|
||||
@t.CVTable
|
||||
class Cat(Animal):
|
||||
def speak(self) -> str:
|
||||
return "Meow"
|
||||
|
||||
|
||||
# ========== 多继承 ==========
|
||||
|
||||
@t.CVTable
|
||||
class A:
|
||||
a: CInt
|
||||
|
||||
def get_a(self) -> CInt:
|
||||
return self.a
|
||||
|
||||
|
||||
@t.CVTable
|
||||
class B:
|
||||
b: CInt
|
||||
|
||||
def get_b(self) -> CInt:
|
||||
return self.b
|
||||
|
||||
|
||||
@t.CVTable
|
||||
class AB(A, B):
|
||||
def __init__(self, a: CInt, b: CInt):
|
||||
self.a = a
|
||||
self.b = b
|
||||
|
||||
|
||||
# ========== NoVTable(编译时判断) ==========
|
||||
|
||||
@t.NoVTable
|
||||
class Plain:
|
||||
v: CInt
|
||||
|
||||
|
||||
def main() -> CInt | CExport:
|
||||
testcheck.begin("IsinstanceTest: isinstance 内建函数测试")
|
||||
|
||||
# --- 1. 自身类型 + 子类→基类 ---
|
||||
d: Dog | CPtr = Dog("dog")
|
||||
testcheck.check(isinstance(d, Dog) == 1, "isinstance(d, Dog) 自身 OK",
|
||||
"isinstance(d, Dog) FAILED")
|
||||
testcheck.check(isinstance(d, Animal) == 1, "isinstance(d, Animal) 子类→基类 OK",
|
||||
"isinstance(d, Animal) FAILED")
|
||||
testcheck.check(isinstance(d, Cat) == 0, "isinstance(d, Cat) 不匹配 OK",
|
||||
"isinstance(d, Cat) FAILED")
|
||||
|
||||
# --- 2. 运行时多态:基类指针指向子类对象 ---
|
||||
a: Animal | CPtr = (Animal | CPtr)(d)
|
||||
testcheck.check(isinstance(a, Dog) == 1,
|
||||
"isinstance(Animal*, Dog 对象) 运行时多态 OK",
|
||||
"isinstance(Animal*, Dog) FAILED")
|
||||
testcheck.check(isinstance(a, Animal) == 1,
|
||||
"isinstance(Animal*, Animal) 基类自身 OK",
|
||||
"isinstance(Animal*, Animal) FAILED")
|
||||
testcheck.check(isinstance(a, Cat) == 0,
|
||||
"isinstance(Animal*, Cat) 运行时 False OK",
|
||||
"isinstance(Animal*, Cat) FAILED")
|
||||
|
||||
# --- 3. 元组 ---
|
||||
testcheck.check(isinstance(d, (Cat, Dog)) == 1, "isinstance 元组命中 OK",
|
||||
"isinstance 元组 FAILED")
|
||||
testcheck.check(isinstance(d, (Cat, A)) == 0, "isinstance 元组未命中 OK",
|
||||
"isinstance 元组未命中 FAILED")
|
||||
|
||||
# --- 4. 多继承 ---
|
||||
ab: AB | CPtr = AB(1, 2)
|
||||
testcheck.check(isinstance(ab, A) == 1, "isinstance(AB, A) 多继承 OK",
|
||||
"isinstance(AB, A) FAILED")
|
||||
testcheck.check(isinstance(ab, B) == 1, "isinstance(AB, B) 多继承 OK",
|
||||
"isinstance(AB, B) FAILED")
|
||||
testcheck.check(isinstance(ab, Animal) == 0, "isinstance(AB, Animal) False OK",
|
||||
"isinstance(AB, Animal) FAILED")
|
||||
testcheck.check(ab.get_a() == 1 and ab.get_b() == 2, "AB 字段/方法正常 OK",
|
||||
"AB 字段/方法 FAILED")
|
||||
|
||||
# --- 5. NoVTable(编译时静态判断) ---
|
||||
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 链接解析) ---
|
||||
cc: geom_lib.Circle | CPtr = geom_lib.Circle(5)
|
||||
testcheck.check(isinstance(cc, geom_lib.Circle) == 1,
|
||||
"跨模块 isinstance 自身 OK", "跨模块 isinstance 自身 FAILED")
|
||||
testcheck.check(isinstance(cc, geom_lib.Shape) == 1,
|
||||
"跨模块 isinstance 子类→基类 OK", "跨模块 isinstance 子类→基类 FAILED")
|
||||
testcheck.check(isinstance(cc, geom_lib.Square) == 0,
|
||||
"跨模块 isinstance 不匹配 OK", "跨模块 isinstance 不匹配 FAILED")
|
||||
sq: geom_lib.Square | CPtr = geom_lib.Square(3)
|
||||
testcheck.check(isinstance(sq, geom_lib.Shape) == 1,
|
||||
"跨模块 Square→Shape OK", "跨模块 Square→Shape FAILED")
|
||||
testcheck.check(isinstance(sq, geom_lib.Circle) == 0,
|
||||
"跨模块 Square vs Circle OK", "跨模块 Square vs Circle FAILED")
|
||||
shp: geom_lib.Shape | CPtr = (geom_lib.Shape | CPtr)(cc)
|
||||
testcheck.check(isinstance(shp, geom_lib.Circle) == 1,
|
||||
"跨模块运行时多态 OK", "跨模块运行时多态 FAILED")
|
||||
testcheck.check(shp.area() == 5, "跨模块虚方法分派 OK", "跨模块虚方法分派 FAILED")
|
||||
testcheck.check(cc.area() == 5, "跨模块 Circle.area OK", "跨模块 Circle.area FAILED")
|
||||
|
||||
# --- 7. NoVTable 跨模块静态判断 ---
|
||||
ps: geom_lib.PlainShape | CPtr = geom_lib.PlainShape()
|
||||
testcheck.check(isinstance(ps, geom_lib.PlainShape) == 1,
|
||||
"跨模块 NoVTable 静态 OK", "跨模块 NoVTable 静态 FAILED")
|
||||
|
||||
testcheck.ok("isinstance 全部测试完成")
|
||||
return testcheck.end()
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
|
||||
"name": "IsinstanceTest",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": [
|
||||
"-filetype=obj",
|
||||
"-relocation-model=pic"
|
||||
]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": [
|
||||
"-Wl,--allow-multiple-definition",
|
||||
"-lmsvcrt",
|
||||
"-lucrt",
|
||||
"-lpthread",
|
||||
"-lmingwex",
|
||||
"-lkernel32",
|
||||
"-luser32"
|
||||
],
|
||||
"output": "IsinstanceTest.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import t
|
||||
import stdio
|
||||
import string
|
||||
import testcheck
|
||||
|
||||
def test_for_in_string():
|
||||
testcheck.section("Test 1: for-in string iteration")
|
||||
s: t.CChar | t.CPtr = "Hello"
|
||||
result: t.CInt = 0
|
||||
for ch in s:
|
||||
result += ch
|
||||
# H=72, e=101, l=108, l=108, o=111 => 500
|
||||
testcheck.check(result == 500, "for-in string (sum=500)", "for-in string (sum expect 500)")
|
||||
|
||||
def test_for_in_char_ptr():
|
||||
testcheck.section("Test 2: for-in char* iteration")
|
||||
s: t.CChar | t.CPtr = "ABC"
|
||||
chars: t.CArray[t.CInt, 4] = [0]
|
||||
idx: t.CInt = 0
|
||||
for ch in s:
|
||||
if idx < 3:
|
||||
chars[idx] = ch
|
||||
idx += 1
|
||||
testcheck.check(chars[0] == 65 and chars[1] == 66 and chars[2] == 67, "for-in char* (A=65 B=66 C=67)", "for-in char* (expect A=65 B=66 C=67)")
|
||||
|
||||
def test_strcpy_for_in():
|
||||
testcheck.section("Test 3: strcpy using for-in")
|
||||
src: t.CChar | t.CPtr = "test"
|
||||
# 手动实现 strcpy 用 for-in
|
||||
import w32.win32memory
|
||||
buf: t.CChar | t.CPtr = w32.win32memory.VirtualAlloc(None, 64, 12288, 4)
|
||||
if t.CUInt64T(buf) == 0:
|
||||
stdio.printf("SKIP: VirtualAlloc returned NULL\n")
|
||||
return
|
||||
string.memset(buf, 0, 64)
|
||||
# 用 for-in 复制
|
||||
p: t.CChar | t.CPtr = buf
|
||||
for ch in src:
|
||||
p[0] = ch
|
||||
p += 1
|
||||
p[0] = 0
|
||||
# i8* == 是指针地址比较(C-Like 语义),字符串内容比较需显式 strcmp
|
||||
testcheck.check(string.strcmp(buf, "test") == 0, "strcpy for-in (result=test)", "strcpy for-in (cmp mismatch)")
|
||||
|
||||
import w32.win32memory
|
||||
|
||||
def main() -> t.CInt:
|
||||
testcheck.begin("IterTest: 指针迭代测试")
|
||||
test_for_in_string()
|
||||
test_for_in_char_ptr()
|
||||
test_strcpy_for_in()
|
||||
return testcheck.end()
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
|
||||
"name": "IterTest",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": [
|
||||
"-filetype=obj",
|
||||
"-relocation-model=pic"
|
||||
]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": [
|
||||
"-Wl,--allow-multiple-definition",
|
||||
"-lmsvcrt",
|
||||
"-lucrt",
|
||||
"-lpthread",
|
||||
"-lmingwex",
|
||||
"-lkernel32",
|
||||
"-luser32"
|
||||
],
|
||||
"output": "IterTest.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,309 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
from stdio import printf
|
||||
import memhub
|
||||
import json
|
||||
import string
|
||||
import w32.win32memory as win32mem
|
||||
import testcheck
|
||||
|
||||
# ============================================================
|
||||
# 测试 1:构造 JSON 值(使用 mpool)
|
||||
# ============================================================
|
||||
def test_construct(pool: memhub.MemPool | t.CPtr):
|
||||
testcheck.section("Construct JsonValue (with mpool)")
|
||||
|
||||
# null
|
||||
v1: json.JsonValue | t.CPtr = json.null(pool)
|
||||
testcheck.check(v1.is_null(), "null is_null", "null is_null")
|
||||
|
||||
# bool
|
||||
v2: json.JsonValue | t.CPtr = json.bool_val(pool, True)
|
||||
testcheck.check(v2.is_bool(), "bool true is_bool", "bool true is_bool")
|
||||
testcheck.check(v2.as_bool(), "bool true as_bool", "bool true as_bool")
|
||||
|
||||
v3: json.JsonValue | t.CPtr = json.bool_val(pool, False)
|
||||
testcheck.check(not v3.as_bool(), "bool false !as_bool", "bool false !as_bool")
|
||||
|
||||
# int
|
||||
v4: json.JsonValue | t.CPtr = json.int_val(pool, 42)
|
||||
testcheck.check(v4.is_int(), "int is_int", "int is_int")
|
||||
testcheck.check(v4.as_int() == 42, "int 42 == 42", "int 42 == 42")
|
||||
|
||||
v5: json.JsonValue | t.CPtr = json.int_val(pool, -100)
|
||||
testcheck.check(v5.as_int() == -100, "int -100 == -100", "int -100 == -100")
|
||||
|
||||
# float
|
||||
v6: json.JsonValue | t.CPtr = json.float_val(pool, 3.14)
|
||||
testcheck.check(v6.is_float(), "float is_float", "float is_float")
|
||||
testcheck.check(v6.as_float() > 3.13 and v6.as_float() < 3.15, "float 3.14 ~= 3.14", "float 3.14 ~= 3.14")
|
||||
|
||||
# string
|
||||
v7: json.JsonValue | t.CPtr = json.string_val(pool, "hello")
|
||||
testcheck.check(v7.is_string(), "string is_string", "string is_string")
|
||||
testcheck.check(string.strcmp(v7.as_string(), "hello") == 0, "string == hello", "string == hello")
|
||||
|
||||
# array
|
||||
v8: json.JsonValue | t.CPtr = json.array(pool)
|
||||
testcheck.check(v8.is_array(), "array is_array", "array is_array")
|
||||
testcheck.check(len(v8) == 0, "array empty len()==0", "array empty len()==0")
|
||||
|
||||
# object
|
||||
v9: json.JsonValue | t.CPtr = json.object(pool)
|
||||
testcheck.check(v9.is_object(), "object is_object", "object is_object")
|
||||
testcheck.check(len(v9) == 0, "object empty len()==0", "object empty len()==0")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 测试 2:构造数组和对象(Python风格API)
|
||||
# ============================================================
|
||||
def test_build_structures(pool: memhub.MemPool | t.CPtr):
|
||||
testcheck.section("Build Arrays and Objects (Pythonic API)")
|
||||
|
||||
# 构建数组 [1, 2, 3]
|
||||
arr: json.JsonValue | t.CPtr = json.array(pool)
|
||||
json.array_append(pool, arr, json.int_val(pool, 1))
|
||||
json.array_append(pool, arr, json.int_val(pool, 2))
|
||||
json.array_append(pool, arr, json.int_val(pool, 3))
|
||||
testcheck.check(len(arr) == 3, "array [1,2,3] len()==3", "array [1,2,3] len()==3")
|
||||
testcheck.check(arr.get_item(0).as_int() == 1, "array get_item(0)==1", "array get_item(0)==1")
|
||||
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}
|
||||
obj: json.JsonValue | t.CPtr = 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"]
|
||||
name_val: json.JsonValue | t.CPtr = 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 | t.CPtr = obj["version"]
|
||||
testcheck.check(ver_val != None and ver_val.as_int() == 1, "obj['version']==1", "obj['version']==1")
|
||||
missing: json.JsonValue | t.CPtr = obj["missing"]
|
||||
testcheck.check(missing == None, "obj['missing']==None", "obj['missing']==None")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 测试 3:JSON 解析
|
||||
# ============================================================
|
||||
def test_parse(pool: memhub.MemPool | t.CPtr):
|
||||
testcheck.section("Parse JSON")
|
||||
|
||||
# 解析整数
|
||||
v1: json.JsonValue | t.CPtr = 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")
|
||||
|
||||
# 解析负数
|
||||
v2: json.JsonValue | t.CPtr = json.parse(pool, "-7")
|
||||
testcheck.check(v2.as_int() == -7, "parse neg int == -7", "parse neg int == -7")
|
||||
|
||||
# 解析浮点数
|
||||
v3: json.JsonValue | t.CPtr = 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")
|
||||
|
||||
# 解析字符串
|
||||
v4: json.JsonValue | t.CPtr = 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")
|
||||
|
||||
# 解析布尔
|
||||
v5: json.JsonValue | t.CPtr = 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")
|
||||
|
||||
v6: json.JsonValue | t.CPtr = json.parse(pool, "false")
|
||||
testcheck.check(not v6.as_bool(), "parse false !as_bool", "parse false !as_bool")
|
||||
|
||||
# 解析 null
|
||||
v7: json.JsonValue | t.CPtr = json.parse(pool, "null")
|
||||
testcheck.check(v7.is_null(), "parse null is_null", "parse null is_null")
|
||||
|
||||
# 解析数组
|
||||
v8: json.JsonValue | t.CPtr = 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风格取值)
|
||||
v9: json.JsonValue | t.CPtr = 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")
|
||||
x_val: json.JsonValue | t.CPtr = v9["x"]
|
||||
testcheck.check(x_val != None and x_val.as_int() == 10, "parse obj['x']==10", "parse obj['x']==10")
|
||||
y_val: json.JsonValue | t.CPtr = v9["y"]
|
||||
testcheck.check(y_val != None and y_val.as_int() == 20, "parse obj['y']==20", "parse obj['y']==20")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 测试 4:JSON 序列化
|
||||
# ============================================================
|
||||
def test_write(pool: memhub.MemPool | t.CPtr):
|
||||
testcheck.section("Write JSON")
|
||||
|
||||
# 写整数
|
||||
v1: json.JsonValue | t.CPtr = json.int_val(pool, 42)
|
||||
s1: t.CChar | t.CPtr = json.write(pool, v1, False)
|
||||
testcheck.check(string.strcmp(s1, "42") == 0, "write int 42", "write int 42")
|
||||
|
||||
# 写字符串
|
||||
v2: json.JsonValue | t.CPtr = json.string_val(pool, "hello")
|
||||
s2: t.CChar | t.CPtr = json.write(pool, v2, False)
|
||||
testcheck.check(string.strcmp(s2, '"hello"') == 0, "write string hello", "write string hello")
|
||||
|
||||
# 写布尔
|
||||
v3: json.JsonValue | t.CPtr = json.bool_val(pool, True)
|
||||
s3: t.CChar | t.CPtr = json.write(pool, v3, False)
|
||||
testcheck.check(string.strcmp(s3, "true") == 0, "write bool true", "write bool true")
|
||||
|
||||
v4: json.JsonValue | t.CPtr = json.bool_val(pool, False)
|
||||
s4: t.CChar | t.CPtr = json.write(pool, v4, False)
|
||||
testcheck.check(string.strcmp(s4, "false") == 0, "write bool false", "write bool false")
|
||||
|
||||
# 写 null
|
||||
v5: json.JsonValue | t.CPtr = json.null(pool)
|
||||
s5: t.CChar | t.CPtr = json.write(pool, v5, False)
|
||||
testcheck.check(string.strcmp(s5, "null") == 0, "write null", "write null")
|
||||
|
||||
# 写数组
|
||||
arr: json.JsonValue | t.CPtr = json.array(pool)
|
||||
json.array_append(pool, arr, json.int_val(pool, 1))
|
||||
json.array_append(pool, arr, json.int_val(pool, 2))
|
||||
json.array_append(pool, arr, json.int_val(pool, 3))
|
||||
s6: t.CChar | t.CPtr = json.write(pool, arr, False)
|
||||
testcheck.check(string.strcmp(s6, "[1,2,3]") == 0, "write array [1,2,3]", "write array [1,2,3]")
|
||||
|
||||
# 写对象
|
||||
obj: json.JsonValue | t.CPtr = 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"))
|
||||
s7: t.CChar | t.CPtr = json.write(pool, obj, False)
|
||||
testcheck.check(s7 != None, "write object non-null", "write object non-null")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 测试 5:解析复杂嵌套 JSON(Python风格API)
|
||||
# ============================================================
|
||||
def test_nested(pool: memhub.MemPool | t.CPtr):
|
||||
testcheck.section("Parse Nested JSON (Pythonic API)")
|
||||
|
||||
src: t.CChar | t.CPtr = '{"name": "Viper", "version": 1, "features": ["fast", "safe", "portable"], "nested": {"key": "value", "num": 99}}'
|
||||
root: json.JsonValue | t.CPtr = json.parse(pool, src)
|
||||
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"]
|
||||
name: json.JsonValue | t.CPtr = root["name"]
|
||||
testcheck.check(name != None and string.strcmp(name.as_string(), "Viper") == 0, "root['name']==Viper", "root['name']==Viper")
|
||||
|
||||
# root["version"]
|
||||
ver: json.JsonValue | t.CPtr = root["version"]
|
||||
testcheck.check(ver != None and ver.as_int() == 1, "root['version']==1", "root['version']==1")
|
||||
|
||||
# root["features"] 数组
|
||||
feat: json.JsonValue | t.CPtr = 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"] 对象
|
||||
nested: json.JsonValue | t.CPtr = root["nested"]
|
||||
testcheck.check(nested != None and nested.is_object(), "root['nested'] is_object", "root['nested'] is_object")
|
||||
nk: json.JsonValue | t.CPtr = nested["key"] if nested != None else None
|
||||
testcheck.check(nk != None and string.strcmp(nk.as_string(), "value") == 0, "root['nested']['key']==value", "root['nested']['key']==value")
|
||||
nn: json.JsonValue | t.CPtr = nested["num"] if nested != None else None
|
||||
testcheck.check(nn != None and nn.as_int() == 99, "root['nested']['num']==99", "root['nested']['num']==99")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 测试 6:mpool 重置后重新使用
|
||||
# ============================================================
|
||||
def test_mpool_reuse():
|
||||
testcheck.section("MPool Reuse")
|
||||
|
||||
# 分配内存
|
||||
mem: t.CPtr = win32mem.VirtualAlloc(None, 8192, 0x3000, 0x04)
|
||||
testcheck.check(mem != None, "VirtualAlloc ok", "VirtualAlloc ok")
|
||||
|
||||
pool: memhub.MemPool | t.CPtr = memhub.MemPool(mem, 8192)
|
||||
|
||||
# 第一次使用
|
||||
v1: json.JsonValue | t.CPtr = json.int_val(pool, 100)
|
||||
testcheck.check(v1.as_int() == 100, "reuse round1 int==100", "reuse round1 int==100")
|
||||
|
||||
# 重置 mpool
|
||||
pool.reset()
|
||||
|
||||
# 第二次使用(内存复用)
|
||||
v2: json.JsonValue | t.CPtr = json.string_val(pool, "reused")
|
||||
testcheck.check(string.strcmp(v2.as_string(), "reused") == 0, "reuse round2 string==reused", "reuse round2 string==reused")
|
||||
|
||||
# 重置后再解析
|
||||
pool.reset()
|
||||
v3: json.JsonValue | t.CPtr = json.parse(pool, '{"test": true}')
|
||||
testcheck.check(v3.is_object(), "reuse round3 parse ok", "reuse round3 parse ok")
|
||||
tv: json.JsonValue | t.CPtr = v3["test"]
|
||||
testcheck.check(tv != None and tv.as_bool(), "reuse round3 obj['test']==true", "reuse round3 obj['test']==true")
|
||||
|
||||
win32mem.VirtualFree(mem, 0, 0x8000)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 测试 7:转义字符解析
|
||||
# ============================================================
|
||||
def test_escape(pool: memhub.MemPool | t.CPtr):
|
||||
testcheck.section("Escape Characters")
|
||||
|
||||
# 解析含转义字符的字符串
|
||||
v1: json.JsonValue | t.CPtr = json.parse(pool, '"hello\\nworld"')
|
||||
testcheck.check(v1.is_string(), "escape \\n is_string", "escape \\n is_string")
|
||||
sv1: t.CChar | t.CPtr = v1.as_string()
|
||||
testcheck.check(sv1 != None and sv1[5] == '\n', "escape \\n contains newline", "escape \\n contains newline")
|
||||
|
||||
v2: json.JsonValue | t.CPtr = json.parse(pool, '"tab\\there"')
|
||||
testcheck.check(v2.is_string(), "escape \\t is_string", "escape \\t is_string")
|
||||
sv2: t.CChar | t.CPtr = v2.as_string()
|
||||
testcheck.check(sv2 != None and sv2[3] == '\t', "escape \\t contains tab", "escape \\t contains tab")
|
||||
|
||||
v3: json.JsonValue | t.CPtr = json.parse(pool, '"quote\\""')
|
||||
testcheck.check(v3.is_string(), "escape \\\" is_string", "escape \\\" is_string")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 主函数
|
||||
# ============================================================
|
||||
def main() -> t.CInt | t.CExport:
|
||||
testcheck.begin("JSON Library Test (Pythonic API)")
|
||||
|
||||
# 使用 mpool 的 bump 分配器
|
||||
mem: t.CPtr = win32mem.VirtualAlloc(None, 65536, 0x3000, 0x04)
|
||||
pool: memhub.MemPool | t.CPtr = memhub.MemPool(mem, 65536)
|
||||
|
||||
test_construct(pool)
|
||||
pool.reset()
|
||||
|
||||
test_build_structures(pool)
|
||||
pool.reset()
|
||||
|
||||
test_parse(pool)
|
||||
pool.reset()
|
||||
|
||||
test_write(pool)
|
||||
pool.reset()
|
||||
|
||||
test_nested(pool)
|
||||
pool.reset()
|
||||
|
||||
test_escape(pool)
|
||||
pool.reset()
|
||||
|
||||
test_mpool_reuse()
|
||||
|
||||
win32mem.VirtualFree(mem, 0, 0x8000)
|
||||
|
||||
return testcheck.end()
|
||||
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"name": "JsonTest",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": [
|
||||
"-filetype=obj",
|
||||
"-relocation-model=pic"
|
||||
]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": [
|
||||
"-Wl,--allow-multiple-definition",
|
||||
"-lmsvcrt",
|
||||
"-lucrt",
|
||||
"-lpthread",
|
||||
"-lmingwex",
|
||||
"-lkernel32",
|
||||
"-luser32"
|
||||
],
|
||||
"output": "JsonTest.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
|
||||
"name": "LLvmLiteTest",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": ["-filetype=obj", "-relocation-model=pic"]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": ["-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32", "-Wl,--allow-multiple-definition"],
|
||||
"output": "LLvmLiteTest.exe",
|
||||
"static_libs": [
|
||||
"D:/msys64/clang64/lib/clang/22/lib/windows/libclang_rt.asan_dynamic-x86_64.dll.a",
|
||||
"D:/msys64/clang64/lib/clang/22/lib/windows/libclang_rt.asan_dynamic_runtime_thunk-x86_64.a"
|
||||
]
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
Loaded 100 of 196 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user