From 3c6fb1d2463a30f322d13a5285b199967ff48131 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Tue, 29 Sep 2026 15:14:59 +0800 Subject: [PATCH] =?UTF-8?q?chore(test):=20=E5=88=9D=E5=A7=8B=E5=8C=96?= =?UTF-8?q?=E5=9B=9E=E5=BD=92=E6=B5=8B=E8=AF=95=E4=BB=93=EF=BC=88=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=20.gitignore=EF=BC=8CTestsOverview.md=20=E6=94=B9?= =?UTF-8?q?=E4=B8=BA=20README.md=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 把 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 —— 旧值 /Projectrans.py 已不存在, 改为 /TransPyC/Projectrans.py(与 regression_test.py:45-48 记录一致), 否则本脚本会以 "can't open file" 全量失败。 regression_test.py 无需改动:它按目录扫描 project.json 找项目,不引用该文档。 --- .gitignore | 54 + ArgparseTest/App/main.vp | 204 ++ ArgparseTest/project.json | 30 + AstTest/App/main.vp | 256 +++ AstTest/project.json | 29 + BuddyTest/App/main.vp | 18 + BuddyTest/App/mbuddytest.vp | 545 ++++++ BuddyTest/project.json | 29 + BuiltinDecoratorTest/App/main.vp | 268 +++ BuiltinDecoratorTest/project.json | 39 + CPythonTest/App/cpython.vp | 777 ++++++++ CPythonTest/App/main.vp | 359 ++++ CPythonTest/project.json | 35 + CharTest/App/main.vp | 31 + CharTest/project.json | 40 + ClassArrayTest/App/class_test.vp | 246 +++ ClassArrayTest/App/main.vp | 47 + ClassArrayTest/project.json | 40 + ClosureCallTest/App/main.vp | 39 + ClosureCallTest/project.json | 39 + ClosureTest/App/main.vp | 164 ++ ClosureTest/project.json | 40 + ClosureTest2/App/main.vp | 220 +++ ClosureTest2/project.json | 40 + CoroTest/App/main.vp | 41 + CoroTest/project.json | 39 + DecoratorTest/App/main.vp | 299 +++ DecoratorTest/project.json | 39 + DefaultArgTest/App/main.vp | 70 + DefaultArgTest/App/remote.vp | 21 + DefaultArgTest/project.json | 40 + DefineTest/App/main.vp | 421 ++++ DefineTest/project.json | 40 + DictTest/App/main.vp | 233 +++ DictTest/project.json | 29 + DocTest/App/main.vp | 69 + DocTest/App/remote.vp | 19 + DocTest/project.json | 39 + DocTest/project_opt.json | 40 + EdgeCaseTest/App/main.vp | 258 +++ EdgeCaseTest/project.json | 29 + EnumTest/App/enumtest.vp | 95 + EnumTest/App/main.vp | 11 + EnumTest/project.json | 40 + EqTest/App/main.vp | 57 + EqTest/project.json | 29 + ExpandKeywordsTest/App/main.vp | 75 + ExpandKeywordsTest/project.json | 40 + Extern2Test/App/main.vp | 41 + Extern2Test/project.json | 39 + FakeDuckTest/App/main.vp | 308 +++ FakeDuckTest/project.json | 33 + FileIoTest/App/fileiotest.vp | 395 ++++ FileIoTest/App/main.vp | 11 + FileIoTest/project.json | 40 + ForAndLoopTest/App/main.vp | 165 ++ ForAndLoopTest/project.json | 29 + FormatStringTest/App/main.vp | 52 + FormatStringTest/project.json | 29 + FuncTest/App/main.vp | 106 + FuncTest/project.json | 40 + G3/App/main.vp | 63 + G3/project.json | 40 + G4/App/caller1.vp | 42 + G4/App/caller2.vp | 36 + G4/App/caller3.vp | 31 + G4/App/main.vp | 154 ++ G4/includes/g4node.vp | 53 + G4/project.json | 41 + G5/App/main.vp | 176 ++ G5/includes/g5container.vp | 173 ++ G5/project.json | 41 + G6/App/main.vp | 71 + G6/project.json | 40 + G7/App/main.vp | 52 + G7/includes/conflict_node.vp | 30 + G7/project.json | 41 + GenericOopTest/App/main.vp | 136 ++ GenericOopTest/project.json | 40 + GenericTest/App/main.vp | 167 ++ GenericTest/project.json | 40 + GenericTest2/App/main.vp | 273 +++ GenericTest2/project.json | 40 + GenericTest3/App/main.vp | 57 + GenericTest3/project.json | 40 + GenericTest4/App/main.vp | 109 ++ GenericTest4/project.json | 40 + HashLibTest/App/main.vp | 123 ++ HashLibTest/project.json | 40 + HashTableTest/App/main.vp | 210 ++ HashTableTest/project.json | 29 + IsinstanceTest/App/geom_lib.vp | 43 + IsinstanceTest/App/main.vp | 153 ++ IsinstanceTest/project.json | 40 + IterTest/App/main.vp | 52 + IterTest/project.json | 40 + JsonTest/App/main.vp | 309 +++ JsonTest/project.json | 39 + LLvmLiteTest/App/main.vp | 1149 +++++++++++ LLvmLiteTest/project.json | 33 + ListTest/App/main.vp | 90 + ListTest/project.json | 29 + LogicFlowTest/App/config.vp | 24 + LogicFlowTest/App/logic_test.vp | 372 ++++ LogicFlowTest/App/main.vp | 106 + LogicFlowTest/project.json | 40 + LoopMathTest/App/config.vp | 24 + LoopMathTest/App/main.vp | 79 + LoopMathTest/App/test.vp | 298 +++ LoopMathTest/project.json | 40 + LoopTest/App/main.vp | 81 + LoopTest/project.json | 40 + MLIRLiteTest/App/main.vp | 1478 ++++++++++++++ MLIRLiteTest/project.json | 29 + MemhubTest/App/main.vp | 97 + MemhubTest/project.json | 29 + MpoolOopTest/App/main.vp | 11 + MpoolOopTest/App/mpooltest.vp | 91 + MpoolOopTest/project.json | 40 + MultiInheritTest/App/main.vp | 199 ++ MultiInheritTest/project.json | 40 + NegativeTest/App/cases/call_float_to_int.vp | 7 + NegativeTest/App/cases/call_too_few.vp | 7 + NegativeTest/App/cases/call_too_many.vp | 7 + NegativeTest/App/cases/call_wrong_type.vp | 7 + .../App/cases/import_missing_module.vp | 5 + NegativeTest/App/cases/import_stale_path.vp | 6 + NegativeTest/App/cases/import_wrong_path.vp | 5 + NegativeTest/App/cases/missing_return.vp | 4 + NegativeTest/App/cases/undefined_func.vp | 4 + NegativeTest/App/main.vp | 7 + NegativeTest/project.json | 37 + NegativeTest/run_negative_tests.py | 71 + NewAstTest/App/main.vp | 1705 +++++++++++++++++ NewAstTest/project.json | 29 + NoVTableCrossMixinTest/App/main.vp | 135 ++ NoVTableCrossMixinTest/project.json | 29 + NoVTableTest/App/main.vp | 506 +++++ NoVTableTest/project.json | 40 + NumpyTest/App/main.vp | 11 + NumpyTest/App/test_numpy.vp | 1096 +++++++++++ NumpyTest/project.json | 40 + OopInheritTest/App/main.vp | 402 ++++ OopInheritTest/project.json | 40 + PointerTest/App/main.vp | 281 +++ PointerTest/project.json | 40 + ProbeGen/App/main.vp | 160 ++ ProbeGen/project.vpj | 40 + PtrOpProbe/App/main.vp | 115 ++ PtrOpProbe/project.json | 29 + README.md | 243 +++ RawArrayTest/App/main.vp | 45 + RawArrayTest/project.json | 40 + SequentialRegressionTest.py | 290 +++ ShortCircuitTest/App/main.vp | 122 ++ ShortCircuitTest/project.json | 29 + SimdTest/App/main.vp | 502 +++++ SimdTest/project.json | 39 + SlotsBugTest/App/main.vp | 19 + SlotsBugTest/project.json | 29 + SprintfTest/App/main.vp | 203 ++ SprintfTest/project.json | 29 + StringIterTest/App/inline_test.vp | 50 + StringIterTest/App/main.vp | 179 ++ StringIterTest/project.json | 40 + StringTest/App/main.vp | 85 + StringTest/project.json | 40 + StructTest/App/main.vp | 85 + StructTest/project.json | 40 + SuperTest/App/main.vp | 120 ++ SuperTest/project.json | 40 + SysLibTest/App/main.vp | 38 + SysLibTest/App/os_backend.vp | 39 + SysLibTest/App/syslibtest_impl.vp | 296 +++ SysLibTest/project.json | 29 + TestFBProject/App/main.vp | 160 ++ TestFBProject/project.json | 36 + ThreadingTest/App/main.vp | 297 +++ ThreadingTest/project.json | 29 + TypeCastTest/App/main.vp | 198 ++ TypeCastTest/project.json | 40 + VRandomTest/App/main.vp | 128 ++ VRandomTest/project.json | 29 + VariadicTest/App/main.vp | 184 ++ VariadicTest/project.json | 40 + VectorGenericTest/App/main.vp | 11 + VectorGenericTest/App/vectortest.vp | 43 + VectorGenericTest/project.json | 40 + WebTest/App/main.vp | 81 + WebTest/project.json | 29 + ZlibDbg/App/main.vp | 74 + ZlibDbg/project.json | 38 + ZlibTest/App/main.vp | 20 + ZlibTest/App/test_pyzlib.vp | 878 +++++++++ ZlibTest/project.json | 43 + regression_test.py | 368 ++++ 196 files changed, 24775 insertions(+) create mode 100644 .gitignore create mode 100644 ArgparseTest/App/main.vp create mode 100644 ArgparseTest/project.json create mode 100644 AstTest/App/main.vp create mode 100644 AstTest/project.json create mode 100644 BuddyTest/App/main.vp create mode 100644 BuddyTest/App/mbuddytest.vp create mode 100644 BuddyTest/project.json create mode 100644 BuiltinDecoratorTest/App/main.vp create mode 100644 BuiltinDecoratorTest/project.json create mode 100644 CPythonTest/App/cpython.vp create mode 100644 CPythonTest/App/main.vp create mode 100644 CPythonTest/project.json create mode 100644 CharTest/App/main.vp create mode 100644 CharTest/project.json create mode 100644 ClassArrayTest/App/class_test.vp create mode 100644 ClassArrayTest/App/main.vp create mode 100644 ClassArrayTest/project.json create mode 100644 ClosureCallTest/App/main.vp create mode 100644 ClosureCallTest/project.json create mode 100644 ClosureTest/App/main.vp create mode 100644 ClosureTest/project.json create mode 100644 ClosureTest2/App/main.vp create mode 100644 ClosureTest2/project.json create mode 100644 CoroTest/App/main.vp create mode 100644 CoroTest/project.json create mode 100644 DecoratorTest/App/main.vp create mode 100644 DecoratorTest/project.json create mode 100644 DefaultArgTest/App/main.vp create mode 100644 DefaultArgTest/App/remote.vp create mode 100644 DefaultArgTest/project.json create mode 100644 DefineTest/App/main.vp create mode 100644 DefineTest/project.json create mode 100644 DictTest/App/main.vp create mode 100644 DictTest/project.json create mode 100644 DocTest/App/main.vp create mode 100644 DocTest/App/remote.vp create mode 100644 DocTest/project.json create mode 100644 DocTest/project_opt.json create mode 100644 EdgeCaseTest/App/main.vp create mode 100644 EdgeCaseTest/project.json create mode 100644 EnumTest/App/enumtest.vp create mode 100644 EnumTest/App/main.vp create mode 100644 EnumTest/project.json create mode 100644 EqTest/App/main.vp create mode 100644 EqTest/project.json create mode 100644 ExpandKeywordsTest/App/main.vp create mode 100644 ExpandKeywordsTest/project.json create mode 100644 Extern2Test/App/main.vp create mode 100644 Extern2Test/project.json create mode 100644 FakeDuckTest/App/main.vp create mode 100644 FakeDuckTest/project.json create mode 100644 FileIoTest/App/fileiotest.vp create mode 100644 FileIoTest/App/main.vp create mode 100644 FileIoTest/project.json create mode 100644 ForAndLoopTest/App/main.vp create mode 100644 ForAndLoopTest/project.json create mode 100644 FormatStringTest/App/main.vp create mode 100644 FormatStringTest/project.json create mode 100644 FuncTest/App/main.vp create mode 100644 FuncTest/project.json create mode 100644 G3/App/main.vp create mode 100644 G3/project.json create mode 100644 G4/App/caller1.vp create mode 100644 G4/App/caller2.vp create mode 100644 G4/App/caller3.vp create mode 100644 G4/App/main.vp create mode 100644 G4/includes/g4node.vp create mode 100644 G4/project.json create mode 100644 G5/App/main.vp create mode 100644 G5/includes/g5container.vp create mode 100644 G5/project.json create mode 100644 G6/App/main.vp create mode 100644 G6/project.json create mode 100644 G7/App/main.vp create mode 100644 G7/includes/conflict_node.vp create mode 100644 G7/project.json create mode 100644 GenericOopTest/App/main.vp create mode 100644 GenericOopTest/project.json create mode 100644 GenericTest/App/main.vp create mode 100644 GenericTest/project.json create mode 100644 GenericTest2/App/main.vp create mode 100644 GenericTest2/project.json create mode 100644 GenericTest3/App/main.vp create mode 100644 GenericTest3/project.json create mode 100644 GenericTest4/App/main.vp create mode 100644 GenericTest4/project.json create mode 100644 HashLibTest/App/main.vp create mode 100644 HashLibTest/project.json create mode 100644 HashTableTest/App/main.vp create mode 100644 HashTableTest/project.json create mode 100644 IsinstanceTest/App/geom_lib.vp create mode 100644 IsinstanceTest/App/main.vp create mode 100644 IsinstanceTest/project.json create mode 100644 IterTest/App/main.vp create mode 100644 IterTest/project.json create mode 100644 JsonTest/App/main.vp create mode 100644 JsonTest/project.json create mode 100644 LLvmLiteTest/App/main.vp create mode 100644 LLvmLiteTest/project.json create mode 100644 ListTest/App/main.vp create mode 100644 ListTest/project.json create mode 100644 LogicFlowTest/App/config.vp create mode 100644 LogicFlowTest/App/logic_test.vp create mode 100644 LogicFlowTest/App/main.vp create mode 100644 LogicFlowTest/project.json create mode 100644 LoopMathTest/App/config.vp create mode 100644 LoopMathTest/App/main.vp create mode 100644 LoopMathTest/App/test.vp create mode 100644 LoopMathTest/project.json create mode 100644 LoopTest/App/main.vp create mode 100644 LoopTest/project.json create mode 100644 MLIRLiteTest/App/main.vp create mode 100644 MLIRLiteTest/project.json create mode 100644 MemhubTest/App/main.vp create mode 100644 MemhubTest/project.json create mode 100644 MpoolOopTest/App/main.vp create mode 100644 MpoolOopTest/App/mpooltest.vp create mode 100644 MpoolOopTest/project.json create mode 100644 MultiInheritTest/App/main.vp create mode 100644 MultiInheritTest/project.json create mode 100644 NegativeTest/App/cases/call_float_to_int.vp create mode 100644 NegativeTest/App/cases/call_too_few.vp create mode 100644 NegativeTest/App/cases/call_too_many.vp create mode 100644 NegativeTest/App/cases/call_wrong_type.vp create mode 100644 NegativeTest/App/cases/import_missing_module.vp create mode 100644 NegativeTest/App/cases/import_stale_path.vp create mode 100644 NegativeTest/App/cases/import_wrong_path.vp create mode 100644 NegativeTest/App/cases/missing_return.vp create mode 100644 NegativeTest/App/cases/undefined_func.vp create mode 100644 NegativeTest/App/main.vp create mode 100644 NegativeTest/project.json create mode 100644 NegativeTest/run_negative_tests.py create mode 100644 NewAstTest/App/main.vp create mode 100644 NewAstTest/project.json create mode 100644 NoVTableCrossMixinTest/App/main.vp create mode 100644 NoVTableCrossMixinTest/project.json create mode 100644 NoVTableTest/App/main.vp create mode 100644 NoVTableTest/project.json create mode 100644 NumpyTest/App/main.vp create mode 100644 NumpyTest/App/test_numpy.vp create mode 100644 NumpyTest/project.json create mode 100644 OopInheritTest/App/main.vp create mode 100644 OopInheritTest/project.json create mode 100644 PointerTest/App/main.vp create mode 100644 PointerTest/project.json create mode 100644 ProbeGen/App/main.vp create mode 100644 ProbeGen/project.vpj create mode 100644 PtrOpProbe/App/main.vp create mode 100644 PtrOpProbe/project.json create mode 100644 README.md create mode 100644 RawArrayTest/App/main.vp create mode 100644 RawArrayTest/project.json create mode 100644 SequentialRegressionTest.py create mode 100644 ShortCircuitTest/App/main.vp create mode 100644 ShortCircuitTest/project.json create mode 100644 SimdTest/App/main.vp create mode 100644 SimdTest/project.json create mode 100644 SlotsBugTest/App/main.vp create mode 100644 SlotsBugTest/project.json create mode 100644 SprintfTest/App/main.vp create mode 100644 SprintfTest/project.json create mode 100644 StringIterTest/App/inline_test.vp create mode 100644 StringIterTest/App/main.vp create mode 100644 StringIterTest/project.json create mode 100644 StringTest/App/main.vp create mode 100644 StringTest/project.json create mode 100644 StructTest/App/main.vp create mode 100644 StructTest/project.json create mode 100644 SuperTest/App/main.vp create mode 100644 SuperTest/project.json create mode 100644 SysLibTest/App/main.vp create mode 100644 SysLibTest/App/os_backend.vp create mode 100644 SysLibTest/App/syslibtest_impl.vp create mode 100644 SysLibTest/project.json create mode 100644 TestFBProject/App/main.vp create mode 100644 TestFBProject/project.json create mode 100644 ThreadingTest/App/main.vp create mode 100644 ThreadingTest/project.json create mode 100644 TypeCastTest/App/main.vp create mode 100644 TypeCastTest/project.json create mode 100644 VRandomTest/App/main.vp create mode 100644 VRandomTest/project.json create mode 100644 VariadicTest/App/main.vp create mode 100644 VariadicTest/project.json create mode 100644 VectorGenericTest/App/main.vp create mode 100644 VectorGenericTest/App/vectortest.vp create mode 100644 VectorGenericTest/project.json create mode 100644 WebTest/App/main.vp create mode 100644 WebTest/project.json create mode 100644 ZlibDbg/App/main.vp create mode 100644 ZlibDbg/project.json create mode 100644 ZlibTest/App/main.vp create mode 100644 ZlibTest/App/test_pyzlib.vp create mode 100644 ZlibTest/project.json create mode 100644 regression_test.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b9ca892 --- /dev/null +++ b/.gitignore @@ -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/ diff --git a/ArgparseTest/App/main.vp b/ArgparseTest/App/main.vp new file mode 100644 index 0000000..c3d17a1 --- /dev/null +++ b/ArgparseTest/App/main.vp @@ -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() \ No newline at end of file diff --git a/ArgparseTest/project.json b/ArgparseTest/project.json new file mode 100644 index 0000000..7c0bf4a --- /dev/null +++ b/ArgparseTest/project.json @@ -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 + } +} diff --git a/AstTest/App/main.vp b/AstTest/App/main.vp new file mode 100644 index 0000000..8fd4d29 --- /dev/null +++ b/AstTest/App/main.vp @@ -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 diff --git a/AstTest/project.json b/AstTest/project.json new file mode 100644 index 0000000..444b993 --- /dev/null +++ b/AstTest/project.json @@ -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 + } +} diff --git a/BuddyTest/App/main.vp b/BuddyTest/App/main.vp new file mode 100644 index 0000000..fd9c7aa --- /dev/null +++ b/BuddyTest/App/main.vp @@ -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() diff --git a/BuddyTest/App/mbuddytest.vp b/BuddyTest/App/mbuddytest.vp new file mode 100644 index 0000000..b27ad5a --- /dev/null +++ b/BuddyTest/App/mbuddytest.vp @@ -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() diff --git a/BuddyTest/project.json b/BuddyTest/project.json new file mode 100644 index 0000000..68ad8f7 --- /dev/null +++ b/BuddyTest/project.json @@ -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 + } +} diff --git a/BuiltinDecoratorTest/App/main.vp b/BuiltinDecoratorTest/App/main.vp new file mode 100644 index 0000000..56566d9 --- /dev/null +++ b/BuiltinDecoratorTest/App/main.vp @@ -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() diff --git a/BuiltinDecoratorTest/project.json b/BuiltinDecoratorTest/project.json new file mode 100644 index 0000000..1d35d42 --- /dev/null +++ b/BuiltinDecoratorTest/project.json @@ -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 + } +} \ No newline at end of file diff --git a/CPythonTest/App/cpython.vp b/CPythonTest/App/cpython.vp new file mode 100644 index 0000000..40e3aae --- /dev/null +++ b/CPythonTest/App/cpython.vp @@ -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) diff --git a/CPythonTest/App/main.vp b/CPythonTest/App/main.vp new file mode 100644 index 0000000..851e520 --- /dev/null +++ b/CPythonTest/App/main.vp @@ -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() diff --git a/CPythonTest/project.json b/CPythonTest/project.json new file mode 100644 index 0000000..f4cac68 --- /dev/null +++ b/CPythonTest/project.json @@ -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 + } +} diff --git a/CharTest/App/main.vp b/CharTest/App/main.vp new file mode 100644 index 0000000..f648772 --- /dev/null +++ b/CharTest/App/main.vp @@ -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 diff --git a/CharTest/project.json b/CharTest/project.json new file mode 100644 index 0000000..eea4548 --- /dev/null +++ b/CharTest/project.json @@ -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 + } +} diff --git a/ClassArrayTest/App/class_test.vp b/ClassArrayTest/App/class_test.vp new file mode 100644 index 0000000..c526cf1 --- /dev/null +++ b/ClassArrayTest/App/class_test.vp @@ -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) \ No newline at end of file diff --git a/ClassArrayTest/App/main.vp b/ClassArrayTest/App/main.vp new file mode 100644 index 0000000..31b6121 --- /dev/null +++ b/ClassArrayTest/App/main.vp @@ -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() diff --git a/ClassArrayTest/project.json b/ClassArrayTest/project.json new file mode 100644 index 0000000..50c9d9b --- /dev/null +++ b/ClassArrayTest/project.json @@ -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 + } +} \ No newline at end of file diff --git a/ClosureCallTest/App/main.vp b/ClosureCallTest/App/main.vp new file mode 100644 index 0000000..67048ec --- /dev/null +++ b/ClosureCallTest/App/main.vp @@ -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() diff --git a/ClosureCallTest/project.json b/ClosureCallTest/project.json new file mode 100644 index 0000000..7f93e8f --- /dev/null +++ b/ClosureCallTest/project.json @@ -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 + } +} \ No newline at end of file diff --git a/ClosureTest/App/main.vp b/ClosureTest/App/main.vp new file mode 100644 index 0000000..89a2fd8 --- /dev/null +++ b/ClosureTest/App/main.vp @@ -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() diff --git a/ClosureTest/project.json b/ClosureTest/project.json new file mode 100644 index 0000000..c26d206 --- /dev/null +++ b/ClosureTest/project.json @@ -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 + } +} \ No newline at end of file diff --git a/ClosureTest2/App/main.vp b/ClosureTest2/App/main.vp new file mode 100644 index 0000000..24e8bfb --- /dev/null +++ b/ClosureTest2/App/main.vp @@ -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() diff --git a/ClosureTest2/project.json b/ClosureTest2/project.json new file mode 100644 index 0000000..451f70c --- /dev/null +++ b/ClosureTest2/project.json @@ -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 + } +} \ No newline at end of file diff --git a/CoroTest/App/main.vp b/CoroTest/App/main.vp new file mode 100644 index 0000000..b22e23d --- /dev/null +++ b/CoroTest/App/main.vp @@ -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 \ No newline at end of file diff --git a/CoroTest/project.json b/CoroTest/project.json new file mode 100644 index 0000000..fbf5c11 --- /dev/null +++ b/CoroTest/project.json @@ -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 + } +} diff --git a/DecoratorTest/App/main.vp b/DecoratorTest/App/main.vp new file mode 100644 index 0000000..976f8ec --- /dev/null +++ b/DecoratorTest/App/main.vp @@ -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() diff --git a/DecoratorTest/project.json b/DecoratorTest/project.json new file mode 100644 index 0000000..6635bc1 --- /dev/null +++ b/DecoratorTest/project.json @@ -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 + } +} \ No newline at end of file diff --git a/DefaultArgTest/App/main.vp b/DefaultArgTest/App/main.vp new file mode 100644 index 0000000..778f2b1 --- /dev/null +++ b/DefaultArgTest/App/main.vp @@ -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() diff --git a/DefaultArgTest/App/remote.vp b/DefaultArgTest/App/remote.vp new file mode 100644 index 0000000..9d49954 --- /dev/null +++ b/DefaultArgTest/App/remote.vp @@ -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 diff --git a/DefaultArgTest/project.json b/DefaultArgTest/project.json new file mode 100644 index 0000000..d74d387 --- /dev/null +++ b/DefaultArgTest/project.json @@ -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 + } +} diff --git a/DefineTest/App/main.vp b/DefineTest/App/main.vp new file mode 100644 index 0000000..0bc7b98 --- /dev/null +++ b/DefineTest/App/main.vp @@ -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() diff --git a/DefineTest/project.json b/DefineTest/project.json new file mode 100644 index 0000000..c538a84 --- /dev/null +++ b/DefineTest/project.json @@ -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 + } +} \ No newline at end of file diff --git a/DictTest/App/main.vp b/DictTest/App/main.vp new file mode 100644 index 0000000..6727da2 --- /dev/null +++ b/DictTest/App/main.vp @@ -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() diff --git a/DictTest/project.json b/DictTest/project.json new file mode 100644 index 0000000..e339dcd --- /dev/null +++ b/DictTest/project.json @@ -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 + } +} diff --git a/DocTest/App/main.vp b/DocTest/App/main.vp new file mode 100644 index 0000000..8e25085 --- /dev/null +++ b/DocTest/App/main.vp @@ -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() diff --git a/DocTest/App/remote.vp b/DocTest/App/remote.vp new file mode 100644 index 0000000..c466307 --- /dev/null +++ b/DocTest/App/remote.vp @@ -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 diff --git a/DocTest/project.json b/DocTest/project.json new file mode 100644 index 0000000..202d53f --- /dev/null +++ b/DocTest/project.json @@ -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 + } +} \ No newline at end of file diff --git a/DocTest/project_opt.json b/DocTest/project_opt.json new file mode 100644 index 0000000..bc0a13a --- /dev/null +++ b/DocTest/project_opt.json @@ -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 + } +} \ No newline at end of file diff --git a/EdgeCaseTest/App/main.vp b/EdgeCaseTest/App/main.vp new file mode 100644 index 0000000..71508a0 --- /dev/null +++ b/EdgeCaseTest/App/main.vp @@ -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() diff --git a/EdgeCaseTest/project.json b/EdgeCaseTest/project.json new file mode 100644 index 0000000..5ab2773 --- /dev/null +++ b/EdgeCaseTest/project.json @@ -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 + } +} diff --git a/EnumTest/App/enumtest.vp b/EnumTest/App/enumtest.vp new file mode 100644 index 0000000..c935a48 --- /dev/null +++ b/EnumTest/App/enumtest.vp @@ -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 diff --git a/EnumTest/App/main.vp b/EnumTest/App/main.vp new file mode 100644 index 0000000..dd8eb58 --- /dev/null +++ b/EnumTest/App/main.vp @@ -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() diff --git a/EnumTest/project.json b/EnumTest/project.json new file mode 100644 index 0000000..9b7f9e3 --- /dev/null +++ b/EnumTest/project.json @@ -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 + } +} \ No newline at end of file diff --git a/EqTest/App/main.vp b/EqTest/App/main.vp new file mode 100644 index 0000000..865cf91 --- /dev/null +++ b/EqTest/App/main.vp @@ -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() diff --git a/EqTest/project.json b/EqTest/project.json new file mode 100644 index 0000000..6ef2d5b --- /dev/null +++ b/EqTest/project.json @@ -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 + } +} diff --git a/ExpandKeywordsTest/App/main.vp b/ExpandKeywordsTest/App/main.vp new file mode 100644 index 0000000..dad7438 --- /dev/null +++ b/ExpandKeywordsTest/App/main.vp @@ -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() diff --git a/ExpandKeywordsTest/project.json b/ExpandKeywordsTest/project.json new file mode 100644 index 0000000..e4174a3 --- /dev/null +++ b/ExpandKeywordsTest/project.json @@ -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 + } +} \ No newline at end of file diff --git a/Extern2Test/App/main.vp b/Extern2Test/App/main.vp new file mode 100644 index 0000000..9758b54 --- /dev/null +++ b/Extern2Test/App/main.vp @@ -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() diff --git a/Extern2Test/project.json b/Extern2Test/project.json new file mode 100644 index 0000000..4f7d62f --- /dev/null +++ b/Extern2Test/project.json @@ -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 + } +} \ No newline at end of file diff --git a/FakeDuckTest/App/main.vp b/FakeDuckTest/App/main.vp new file mode 100644 index 0000000..ead0e0b --- /dev/null +++ b/FakeDuckTest/App/main.vp @@ -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() + + + + diff --git a/FakeDuckTest/project.json b/FakeDuckTest/project.json new file mode 100644 index 0000000..3d7e1f9 --- /dev/null +++ b/FakeDuckTest/project.json @@ -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 + } +} diff --git a/FileIoTest/App/fileiotest.vp b/FileIoTest/App/fileiotest.vp new file mode 100644 index 0000000..98d6e77 --- /dev/null +++ b/FileIoTest/App/fileiotest.vp @@ -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) diff --git a/FileIoTest/App/main.vp b/FileIoTest/App/main.vp new file mode 100644 index 0000000..6394d79 --- /dev/null +++ b/FileIoTest/App/main.vp @@ -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() diff --git a/FileIoTest/project.json b/FileIoTest/project.json new file mode 100644 index 0000000..5ad6b09 --- /dev/null +++ b/FileIoTest/project.json @@ -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 + } +} \ No newline at end of file diff --git a/ForAndLoopTest/App/main.vp b/ForAndLoopTest/App/main.vp new file mode 100644 index 0000000..76d119b --- /dev/null +++ b/ForAndLoopTest/App/main.vp @@ -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() diff --git a/ForAndLoopTest/project.json b/ForAndLoopTest/project.json new file mode 100644 index 0000000..7b56735 --- /dev/null +++ b/ForAndLoopTest/project.json @@ -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 + } +} diff --git a/FormatStringTest/App/main.vp b/FormatStringTest/App/main.vp new file mode 100644 index 0000000..0af881a --- /dev/null +++ b/FormatStringTest/App/main.vp @@ -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() + diff --git a/FormatStringTest/project.json b/FormatStringTest/project.json new file mode 100644 index 0000000..5309e12 --- /dev/null +++ b/FormatStringTest/project.json @@ -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 + } +} diff --git a/FuncTest/App/main.vp b/FuncTest/App/main.vp new file mode 100644 index 0000000..0f788f3 --- /dev/null +++ b/FuncTest/App/main.vp @@ -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() diff --git a/FuncTest/project.json b/FuncTest/project.json new file mode 100644 index 0000000..f51c712 --- /dev/null +++ b/FuncTest/project.json @@ -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 + } +} \ No newline at end of file diff --git a/G3/App/main.vp b/G3/App/main.vp new file mode 100644 index 0000000..95a4558 --- /dev/null +++ b/G3/App/main.vp @@ -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() diff --git a/G3/project.json b/G3/project.json new file mode 100644 index 0000000..da9efc5 --- /dev/null +++ b/G3/project.json @@ -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 + } +} \ No newline at end of file diff --git a/G4/App/caller1.vp b/G4/App/caller1.vp new file mode 100644 index 0000000..ac3b435 --- /dev/null +++ b/G4/App/caller1.vp @@ -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 diff --git a/G4/App/caller2.vp b/G4/App/caller2.vp new file mode 100644 index 0000000..d2f2ccb --- /dev/null +++ b/G4/App/caller2.vp @@ -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 diff --git a/G4/App/caller3.vp b/G4/App/caller3.vp new file mode 100644 index 0000000..771e9f0 --- /dev/null +++ b/G4/App/caller3.vp @@ -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 diff --git a/G4/App/main.vp b/G4/App/main.vp new file mode 100644 index 0000000..696b2e3 --- /dev/null +++ b/G4/App/main.vp @@ -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() diff --git a/G4/includes/g4node.vp b/G4/includes/g4node.vp new file mode 100644 index 0000000..bfd83e1 --- /dev/null +++ b/G4/includes/g4node.vp @@ -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 diff --git a/G4/project.json b/G4/project.json new file mode 100644 index 0000000..709f0a5 --- /dev/null +++ b/G4/project.json @@ -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 + } +} \ No newline at end of file diff --git a/G5/App/main.vp b/G5/App/main.vp new file mode 100644 index 0000000..5e247ad --- /dev/null +++ b/G5/App/main.vp @@ -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() diff --git a/G5/includes/g5container.vp b/G5/includes/g5container.vp new file mode 100644 index 0000000..829a29c --- /dev/null +++ b/G5/includes/g5container.vp @@ -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 diff --git a/G5/project.json b/G5/project.json new file mode 100644 index 0000000..0a71f70 --- /dev/null +++ b/G5/project.json @@ -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 + } +} \ No newline at end of file diff --git a/G6/App/main.vp b/G6/App/main.vp new file mode 100644 index 0000000..e93b5fc --- /dev/null +++ b/G6/App/main.vp @@ -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() diff --git a/G6/project.json b/G6/project.json new file mode 100644 index 0000000..2cc582e --- /dev/null +++ b/G6/project.json @@ -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 + } +} \ No newline at end of file diff --git a/G7/App/main.vp b/G7/App/main.vp new file mode 100644 index 0000000..96ec41d --- /dev/null +++ b/G7/App/main.vp @@ -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() diff --git a/G7/includes/conflict_node.vp b/G7/includes/conflict_node.vp new file mode 100644 index 0000000..3dd6917 --- /dev/null +++ b/G7/includes/conflict_node.vp @@ -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 diff --git a/G7/project.json b/G7/project.json new file mode 100644 index 0000000..a5bad86 --- /dev/null +++ b/G7/project.json @@ -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 + } +} \ No newline at end of file diff --git a/GenericOopTest/App/main.vp b/GenericOopTest/App/main.vp new file mode 100644 index 0000000..307b858 --- /dev/null +++ b/GenericOopTest/App/main.vp @@ -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() diff --git a/GenericOopTest/project.json b/GenericOopTest/project.json new file mode 100644 index 0000000..fdc6384 --- /dev/null +++ b/GenericOopTest/project.json @@ -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 + } +} \ No newline at end of file diff --git a/GenericTest/App/main.vp b/GenericTest/App/main.vp new file mode 100644 index 0000000..0595c27 --- /dev/null +++ b/GenericTest/App/main.vp @@ -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() diff --git a/GenericTest/project.json b/GenericTest/project.json new file mode 100644 index 0000000..847f7e2 --- /dev/null +++ b/GenericTest/project.json @@ -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 + } +} \ No newline at end of file diff --git a/GenericTest2/App/main.vp b/GenericTest2/App/main.vp new file mode 100644 index 0000000..3df610f --- /dev/null +++ b/GenericTest2/App/main.vp @@ -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() diff --git a/GenericTest2/project.json b/GenericTest2/project.json new file mode 100644 index 0000000..8294df9 --- /dev/null +++ b/GenericTest2/project.json @@ -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 + } +} \ No newline at end of file diff --git a/GenericTest3/App/main.vp b/GenericTest3/App/main.vp new file mode 100644 index 0000000..77620af --- /dev/null +++ b/GenericTest3/App/main.vp @@ -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() diff --git a/GenericTest3/project.json b/GenericTest3/project.json new file mode 100644 index 0000000..e006f18 --- /dev/null +++ b/GenericTest3/project.json @@ -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 + } +} \ No newline at end of file diff --git a/GenericTest4/App/main.vp b/GenericTest4/App/main.vp new file mode 100644 index 0000000..e576996 --- /dev/null +++ b/GenericTest4/App/main.vp @@ -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() diff --git a/GenericTest4/project.json b/GenericTest4/project.json new file mode 100644 index 0000000..2761b17 --- /dev/null +++ b/GenericTest4/project.json @@ -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 + } +} \ No newline at end of file diff --git a/HashLibTest/App/main.vp b/HashLibTest/App/main.vp new file mode 100644 index 0000000..ec994d4 --- /dev/null +++ b/HashLibTest/App/main.vp @@ -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() diff --git a/HashLibTest/project.json b/HashLibTest/project.json new file mode 100644 index 0000000..1c818d3 --- /dev/null +++ b/HashLibTest/project.json @@ -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 + } +} \ No newline at end of file diff --git a/HashTableTest/App/main.vp b/HashTableTest/App/main.vp new file mode 100644 index 0000000..4b372d1 --- /dev/null +++ b/HashTableTest/App/main.vp @@ -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() diff --git a/HashTableTest/project.json b/HashTableTest/project.json new file mode 100644 index 0000000..d941747 --- /dev/null +++ b/HashTableTest/project.json @@ -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 + } +} diff --git a/IsinstanceTest/App/geom_lib.vp b/IsinstanceTest/App/geom_lib.vp new file mode 100644 index 0000000..494642a --- /dev/null +++ b/IsinstanceTest/App/geom_lib.vp @@ -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 diff --git a/IsinstanceTest/App/main.vp b/IsinstanceTest/App/main.vp new file mode 100644 index 0000000..32d4358 --- /dev/null +++ b/IsinstanceTest/App/main.vp @@ -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() diff --git a/IsinstanceTest/project.json b/IsinstanceTest/project.json new file mode 100644 index 0000000..1206640 --- /dev/null +++ b/IsinstanceTest/project.json @@ -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 + } +} \ No newline at end of file diff --git a/IterTest/App/main.vp b/IterTest/App/main.vp new file mode 100644 index 0000000..da7c258 --- /dev/null +++ b/IterTest/App/main.vp @@ -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() diff --git a/IterTest/project.json b/IterTest/project.json new file mode 100644 index 0000000..43751cc --- /dev/null +++ b/IterTest/project.json @@ -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 + } +} \ No newline at end of file diff --git a/JsonTest/App/main.vp b/JsonTest/App/main.vp new file mode 100644 index 0000000..f24bd4b --- /dev/null +++ b/JsonTest/App/main.vp @@ -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() diff --git a/JsonTest/project.json b/JsonTest/project.json new file mode 100644 index 0000000..197a85c --- /dev/null +++ b/JsonTest/project.json @@ -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 + } +} \ No newline at end of file diff --git a/LLvmLiteTest/App/main.vp b/LLvmLiteTest/App/main.vp new file mode 100644 index 0000000..ae3d5f0 --- /dev/null +++ b/LLvmLiteTest/App/main.vp @@ -0,0 +1,1149 @@ +import t, c +from stdint import * +import stdio +import string +import stdlib +import memhub +import testcheck +import llvmlite + + +# 内存大小 +POOL_SIZE: t.CDefine = 524288 # 512KB + + +# ============================================================ +# 测试 1: TypePrint 类型打印 +# ============================================================ +def test_type_print(pool: memhub.MemPool | t.CPtr): + testcheck.section("Test 1: TypePrint") + core: llvmlite.LLVMTypeCore | t.CPtr = llvmlite.LLVMTypeCore(pool) + buf: t.CChar | t.CPtr = pool.alloc(64) + + # i32 + ty_i32: llvmlite.LLVMType | t.CPtr = core.Int32() + buf[0] = 0 + core.PrintType(buf, 64, ty_i32) + testcheck.check(string.strcmp(buf, "i32") == 0, + "Int32 -> i32", + "Int32 fail") + + # i32* + ty_ptr: llvmlite.LLVMType | t.CPtr = core.Ptr(ty_i32) + buf[0] = 0 + core.PrintType(buf, 64, ty_ptr) + testcheck.check(string.strcmp(buf, "i32*") == 0, + "Ptr(Int32) -> i32*", + "Ptr fail") + + # void + ty_void: llvmlite.LLVMType | t.CPtr = core.Void() + buf[0] = 0 + core.PrintType(buf, 64, ty_void) + testcheck.check(string.strcmp(buf, "void") == 0, + "Void -> void", + "Void fail") + + # i64 + ty_i64: llvmlite.LLVMType | t.CPtr = core.Int64() + buf[0] = 0 + core.PrintType(buf, 64, ty_i64) + testcheck.check(string.strcmp(buf, "i64") == 0, + "Int64 -> i64", + "Int64 fail") + + +# ============================================================ +# 测试 2: ValuePrint 值打印 +# ============================================================ +def test_value_print(pool: memhub.MemPool | t.CPtr): + testcheck.section("Test 2: ValuePrint") + core: llvmlite.LLVMTypeCore | t.CPtr = llvmlite.LLVMTypeCore(pool) + mcore: llvmlite.LLVMModuleCore | t.CPtr = llvmlite.LLVMModuleCore(pool) + buf: t.CChar | t.CPtr = pool.alloc(64) + + ty_i32: llvmlite.LLVMType | t.CPtr = core.Int32() + + # 常量 42 + val42: llvmlite.Value | t.CPtr = mcore.ConstInt32(42) + buf[0] = 0 + mcore.PrintValue(buf, 64, val42) + testcheck.check(string.strcmp(buf, "i32 42") == 0, + "ConstInt(42) -> i32 42", + "ConstInt fail") + + # SSA 值 %0 + name_ssa: t.CChar | t.CPtr = pool.alloc(16) + string.strcpy(name_ssa, "%0") + val_ssa: llvmlite.Value | t.CPtr = mcore.SSAValue(ty_i32, name_ssa) + buf[0] = 0 + mcore.PrintValue(buf, 64, val_ssa) + testcheck.check(string.strcmp(buf, "i32 %0") == 0, + "SSAValue(%0) -> i32 %0", + "SSAValue fail") + + +# ============================================================ +# 测试 3: 构建 add 函数 +# define i32 @add(i32 %a, i32 %b) { +# entry: +# %0 = add i32 %a, %b +# ret i32 %0 +# } +# ============================================================ +def test_build_add(pool: memhub.MemPool | t.CPtr): + testcheck.section("Test 3: build_add function") + + core: llvmlite.LLVMTypeCore | t.CPtr = llvmlite.LLVMTypeCore(pool) + mcore: llvmlite.LLVMModuleCore | t.CPtr = llvmlite.LLVMModuleCore(pool) + ty_i32: llvmlite.LLVMType | t.CPtr = core.Int32() + + # 创建模块 + 函数 + mod: llvmlite.Module | t.CPtr = mcore.NewModule("test_add") + func: llvmlite.Function | t.CPtr = mcore.CreateFunction(mod, "add", ty_i32) + + # 添加参数 + mcore.AddParam(func, ty_i32, "%a") + mcore.AddParam(func, ty_i32, "%b") + + # 创建 entry 块 + entry: llvmlite.BasicBlock | t.CPtr = mcore.CreateBlock(func, "entry") + + # 创建 builder + builder: llvmlite.IRBuilder | t.CPtr = mcore.NewBuilder(func) + llvmlite.position_at_end(builder, entry) + + # 为参数创建 Value 包装 + v_a: llvmlite.Value | t.CPtr = mcore.SSAValue(ty_i32, "%a") + v_b: llvmlite.Value | t.CPtr = mcore.SSAValue(ty_i32, "%b") + + # %0 = add i32 %a, %b + v_c: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, v_a, v_b) + + # ret i32 %0 + llvmlite.build_ret(builder, v_c) + + # 打印函数 + buf: t.CChar | t.CPtr = pool.alloc(4096) + buf[0] = 0 + mcore.PrintFunction(buf, 4096, func) + testcheck.info(buf) + + # 验证关键内容 + testcheck.check(string.strstr(buf, "add i32") is not None, + "contains 'add i32'", + "missing 'add i32'") + testcheck.check(string.strstr(buf, "ret i32") is not None, + "contains 'ret i32'", + "missing 'ret i32'") + testcheck.check(string.strstr(buf, "define i32 @add") is not None, + "contains 'define i32 @add'", + "missing function definition") + + +# ============================================================ +# 测试 4: 构建 if-then-else 函数(max) +# define i32 @max(i32 %a, i32 %b) { +# entry: +# %0 = icmp sgt i32 %a, %b +# br i1 %0, label %then, label %else +# then: +# ret i32 %a +# else: +# ret i32 %b +# } +# ============================================================ +def test_build_if_else(pool: memhub.MemPool | t.CPtr): + testcheck.section("Test 4: build if-then-else (max)") + + core: llvmlite.LLVMTypeCore | t.CPtr = llvmlite.LLVMTypeCore(pool) + mcore: llvmlite.LLVMModuleCore | t.CPtr = llvmlite.LLVMModuleCore(pool) + ty_i32: llvmlite.LLVMType | t.CPtr = core.Int32() + + mod: llvmlite.Module | t.CPtr = mcore.NewModule("test_max") + func: llvmlite.Function | t.CPtr = mcore.CreateFunction(mod, "max", ty_i32) + mcore.AddParam(func, ty_i32, "%a") + mcore.AddParam(func, ty_i32, "%b") + + entry: llvmlite.BasicBlock | t.CPtr = mcore.CreateBlock(func, "entry") + then_blk: llvmlite.BasicBlock | t.CPtr = mcore.CreateBlock(func, "then") + else_blk: llvmlite.BasicBlock | t.CPtr = mcore.CreateBlock(func, "else") + + builder: llvmlite.IRBuilder | t.CPtr = mcore.NewBuilder(func) + + # entry: %0 = icmp sgt i32 %a, %b; br i1 %0, label %then, label %else + llvmlite.position_at_end(builder, entry) + v_a: llvmlite.Value | t.CPtr = mcore.SSAValue(ty_i32, "%a") + v_b: llvmlite.Value | t.CPtr = mcore.SSAValue(ty_i32, "%b") + v_cond: llvmlite.Value | t.CPtr = llvmlite.build_icmp(builder, llvmlite.ICMP_SGT, v_a, v_b) + llvmlite.build_cond_br(builder, v_cond, then_blk, else_blk) + + # then: ret i32 %a + llvmlite.position_at_end(builder, then_blk) + llvmlite.build_ret(builder, v_a) + + # else: ret i32 %b + llvmlite.position_at_end(builder, else_blk) + llvmlite.build_ret(builder, v_b) + + # 打印函数 + buf: t.CChar | t.CPtr = pool.alloc(4096) + buf[0] = 0 + mcore.PrintFunction(buf, 4096, func) + testcheck.info(buf) + + # 验证关键内容 + testcheck.check(string.strstr(buf, "icmp sgt") is not None, + "contains 'icmp sgt'", + "missing 'icmp sgt'") + testcheck.check(string.strstr(buf, "br i1") is not None, + "contains 'br i1'", + "missing 'br i1'") + testcheck.check(string.strstr(buf, "label %then") is not None, + "contains 'label %then'", + "missing 'label %then'") + testcheck.check(string.strstr(buf, "label %else") is not None, + "contains 'label %else'", + "missing 'label %else'") + + +# ============================================================ +# 测试 5: 完整模块 ModulePrint +# ============================================================ +def test_module_print(pool: memhub.MemPool | t.CPtr): + testcheck.section("Test 5: ModulePrint") + + core: llvmlite.LLVMTypeCore | t.CPtr = llvmlite.LLVMTypeCore(pool) + mcore: llvmlite.LLVMModuleCore | t.CPtr = llvmlite.LLVMModuleCore(pool) + ty_i32: llvmlite.LLVMType | t.CPtr = core.Int32() + ty_void: llvmlite.LLVMType | t.CPtr = core.Void() + + # 创建模块 + mod: llvmlite.Module | t.CPtr = mcore.NewModule("test_module") + llvmlite.module_set_target(mod, "x86_64-pc-windows-gnu") + llvmlite.module_set_datalayout(mod, "e-m:w-p270:32:32") + + # 函数 1: add + func_add: llvmlite.Function | t.CPtr = mcore.CreateFunction(mod, "add", ty_i32) + mcore.AddParam(func_add, ty_i32, "%a") + mcore.AddParam(func_add, ty_i32, "%b") + entry1: llvmlite.BasicBlock | t.CPtr = mcore.CreateBlock(func_add, "entry") + builder1: llvmlite.IRBuilder | t.CPtr = mcore.NewBuilder(func_add) + llvmlite.position_at_end(builder1, entry1) + v_a1: llvmlite.Value | t.CPtr = mcore.SSAValue(ty_i32, "%a") + v_b1: llvmlite.Value | t.CPtr = mcore.SSAValue(ty_i32, "%b") + v_sum: llvmlite.Value | t.CPtr = llvmlite.build_add(builder1, v_a1, v_b1) + llvmlite.build_ret(builder1, v_sum) + + # 函数 2: void 函数 + func_void: llvmlite.Function | t.CPtr = mcore.CreateFunction(mod, "noop", ty_void) + entry2: llvmlite.BasicBlock | t.CPtr = mcore.CreateBlock(func_void, "entry") + builder2: llvmlite.IRBuilder | t.CPtr = mcore.NewBuilder(func_void) + llvmlite.position_at_end(builder2, entry2) + llvmlite.build_ret_void(builder2) + + # 打印模块 + buf: t.CChar | t.CPtr = pool.alloc(8192) + buf[0] = 0 + mcore.PrintModule(buf, 8192, mod) + testcheck.info(buf) + + # 验证关键内容 + testcheck.check(string.strstr(buf, "ModuleID") is not None, + "contains 'ModuleID'", + "missing 'ModuleID'") + testcheck.check(string.strstr(buf, "target triple") is not None, + "contains 'target triple'", + "missing 'target triple'") + testcheck.check(string.strstr(buf, "define i32 @add") is not None, + "contains 'define i32 @add'", + "missing add function") + testcheck.check(string.strstr(buf, "define void @noop") is not None, + "contains 'define void @noop'", + "missing noop function") + testcheck.check(string.strstr(buf, "ret void") is not None, + "contains 'ret void'", + "missing 'ret void'") + + +# ============================================================ +# 测试 6: 数组类型打印 +# ============================================================ +def test_array_type(pool: memhub.MemPool | t.CPtr): + testcheck.section("Test 6: ArrayType") + core: llvmlite.LLVMTypeCore | t.CPtr = llvmlite.LLVMTypeCore(pool) + buf: t.CChar | t.CPtr = pool.alloc(128) + + # [4 x i32] + ty_i32: llvmlite.LLVMType | t.CPtr = core.Int32() + ty_arr: llvmlite.LLVMType | t.CPtr = core.Array(ty_i32, 4) + buf[0] = 0 + core.PrintType(buf, 128, ty_arr) + testcheck.check(string.strcmp(buf, "[4 x i32]") == 0, + "Array(i32,4) -> [4 x i32]", + "Array fail") + + # [2 x [3 x i8]] (嵌套数组) + ty_i8: llvmlite.LLVMType | t.CPtr = core.Int8() + ty_inner: llvmlite.LLVMType | t.CPtr = core.Array(ty_i8, 3) + ty_nested: llvmlite.LLVMType | t.CPtr = core.Array(ty_inner, 2) + buf[0] = 0 + core.PrintType(buf, 128, ty_nested) + testcheck.check(string.strcmp(buf, "[2 x [3 x i8]]") == 0, + "nested array -> [2 x [3 x i8]]", + "nested array fail") + + +# ============================================================ +# 测试 7: 结构体类型打印 +# ============================================================ +def test_struct_type(pool: memhub.MemPool | t.CPtr): + testcheck.section("Test 7: StructType") + core: llvmlite.LLVMTypeCore | t.CPtr = llvmlite.LLVMTypeCore(pool) + buf: t.CChar | t.CPtr = pool.alloc(128) + + ty_i32: llvmlite.LLVMType | t.CPtr = core.Int32() + ty_i8: llvmlite.LLVMType | t.CPtr = core.Int8() + ty_i8ptr: llvmlite.LLVMType | t.CPtr = core.Ptr(ty_i8) + + # {i32, i8*} + n1: llvmlite.ParamNode | t.CPtr = core.NewParamNode(ty_i32) + n2: llvmlite.ParamNode | t.CPtr = core.NewParamNode(ty_i8ptr) + head: llvmlite.ParamNode | t.CPtr = core.ParamListAppend(None, None, n1) + core.ParamListAppend(head, n1, n2) + ty_struct: llvmlite.LLVMType | t.CPtr = core.Struct(head, 2) + buf[0] = 0 + core.PrintType(buf, 128, ty_struct) + testcheck.check(string.strcmp(buf, "{i32, i8*}") == 0, + "struct {i32, i8*}", + "struct fail") + + # 空结构体 {} + ty_empty: llvmlite.LLVMType | t.CPtr = core.Struct(None, 0) + buf[0] = 0 + core.PrintType(buf, 128, ty_empty) + testcheck.check(string.strcmp(buf, "{}") == 0, + "empty struct -> {}", + "empty struct fail") + + +# ============================================================ +# 测试 8: 函数类型打印 +# ============================================================ +def test_func_type(pool: memhub.MemPool | t.CPtr): + testcheck.section("Test 8: FuncType") + core: llvmlite.LLVMTypeCore | t.CPtr = llvmlite.LLVMTypeCore(pool) + buf: t.CChar | t.CPtr = pool.alloc(128) + + ty_i32: llvmlite.LLVMType | t.CPtr = core.Int32() + ty_i8: llvmlite.LLVMType | t.CPtr = core.Int8() + ty_i8ptr: llvmlite.LLVMType | t.CPtr = core.Ptr(ty_i8) + + # i32 (i32, i8*) + n1: llvmlite.ParamNode | t.CPtr = core.NewParamNode(ty_i32) + n2: llvmlite.ParamNode | t.CPtr = core.NewParamNode(ty_i8ptr) + head: llvmlite.ParamNode | t.CPtr = core.ParamListAppend(None, None, n1) + core.ParamListAppend(head, n1, n2) + ty_func: llvmlite.LLVMType | t.CPtr = core.Func(ty_i32, head, 2) + buf[0] = 0 + core.PrintType(buf, 128, ty_func) + testcheck.check(string.strcmp(buf, "i32 (i32, i8*)") == 0, + "func type -> i32 (i32, i8*)", + "func type fail") + + # void () — 无参数函数类型 + ty_void: llvmlite.LLVMType | t.CPtr = core.Void() + ty_func_void: llvmlite.LLVMType | t.CPtr = core.Func(ty_void, None, 0) + buf[0] = 0 + core.PrintType(buf, 128, ty_func_void) + testcheck.check(string.strcmp(buf, "void ()") == 0, + "void func -> void ()", + "void func fail") + + +# ============================================================ +# 测试 9: 声明系统(declare vs define) +# ============================================================ +def test_declare(pool: memhub.MemPool | t.CPtr): + testcheck.section("Test 9: Declare vs Define") + core: llvmlite.LLVMTypeCore | t.CPtr = llvmlite.LLVMTypeCore(pool) + mcore: llvmlite.LLVMModuleCore | t.CPtr = llvmlite.LLVMModuleCore(pool) + ty_i32: llvmlite.LLVMType | t.CPtr = core.Int32() + + mod: llvmlite.Module | t.CPtr = mcore.NewModule("test_declare") + + # declare i32 @extern_func(i32) + func_decl: llvmlite.Function | t.CPtr = mcore.CreateDeclare(mod, "extern_func", ty_i32) + mcore.AddParam(func_decl, ty_i32, "%x") + + # define i32 @defined_func(i32) { entry: ret i32 %x } + func_def: llvmlite.Function | t.CPtr = mcore.CreateFunction(mod, "defined_func", ty_i32) + mcore.AddParam(func_def, ty_i32, "%x") + entry: llvmlite.BasicBlock | t.CPtr = mcore.CreateBlock(func_def, "entry") + builder: llvmlite.IRBuilder | t.CPtr = mcore.NewBuilder(func_def) + llvmlite.position_at_end(builder, entry) + v_x: llvmlite.Value | t.CPtr = mcore.SSAValue(ty_i32, "%x") + llvmlite.build_ret(builder, v_x) + + buf: t.CChar | t.CPtr = pool.alloc(4096) + buf[0] = 0 + mcore.PrintModule(buf, 4096, mod) + testcheck.info(buf) + + testcheck.check(string.strstr(buf, "declare i32 @extern_func") is not None, + "contains 'declare i32 @extern_func'", + "missing declare") + testcheck.check(string.strstr(buf, "define i32 @defined_func") is not None, + "contains 'define i32 @defined_func'", + "missing define") + testcheck.check(string.strstr(buf, "declare i32 @extern_func(i32 %x)") is not None, + "declare has param", + "declare missing param") + testcheck.check(string.strstr(buf, "ret i32 %x") is not None, + "define has body", + "define missing body") + + +# ============================================================ +# 测试 10: 浮点类型与 ConstFloat +# ============================================================ +def test_float_types(pool: memhub.MemPool | t.CPtr): + testcheck.section("Test 10: Float Types & ConstFloat") + core: llvmlite.LLVMTypeCore | t.CPtr = llvmlite.LLVMTypeCore(pool) + mcore: llvmlite.LLVMModuleCore | t.CPtr = llvmlite.LLVMModuleCore(pool) + buf: t.CChar | t.CPtr = pool.alloc(128) + + # half + ty_half: llvmlite.LLVMType | t.CPtr = core.Half() + buf[0] = 0 + core.PrintType(buf, 128, ty_half) + testcheck.check(string.strcmp(buf, "half") == 0, + "Half -> half", + "Half fail") + + # float + ty_float: llvmlite.LLVMType | t.CPtr = core.Float() + buf[0] = 0 + core.PrintType(buf, 128, ty_float) + testcheck.check(string.strcmp(buf, "float") == 0, + "Float -> float", + "Float fail") + + # double + ty_double: llvmlite.LLVMType | t.CPtr = core.Double() + buf[0] = 0 + core.PrintType(buf, 128, ty_double) + testcheck.check(string.strcmp(buf, "double") == 0, + "Double -> double", + "Double fail") + + # fp128 + ty_fp128: llvmlite.LLVMType | t.CPtr = core.FP128() + buf[0] = 0 + core.PrintType(buf, 128, ty_fp128) + testcheck.check(string.strcmp(buf, "fp128") == 0, + "FP128 -> fp128", + "FP128 fail") + + # ConstFloat(3.14) -> "double 0x40091EB851EB851F" + # (LLVM IR 浮点常量规范为十六进制位模式,非科学计数法;位模式无精度损失) + val_pi: llvmlite.Value | t.CPtr = mcore.ConstFloat(ty_double, 3.14) + buf[0] = 0 + mcore.PrintValue(buf, 128, val_pi) + testcheck.check(string.strstr(buf, "double") is not None, + "ConstFloat has 'double'", + "ConstFloat missing type") + testcheck.check(string.strstr(buf, "0x") is not None, + "ConstFloat has hex bit pattern", + "ConstFloat missing hex pattern") + + +# ============================================================ +# 测试 11: 浮点二元运算 +# ============================================================ +def test_float_binops(pool: memhub.MemPool | t.CPtr): + testcheck.section("Test 11: Float Binary Ops") + core: llvmlite.LLVMTypeCore | t.CPtr = llvmlite.LLVMTypeCore(pool) + mcore: llvmlite.LLVMModuleCore | t.CPtr = llvmlite.LLVMModuleCore(pool) + ty_double: llvmlite.LLVMType | t.CPtr = core.Double() + + mod: llvmlite.Module | t.CPtr = mcore.NewModule("test_fadd") + func: llvmlite.Function | t.CPtr = mcore.CreateFunction(mod, "fadd", ty_double) + mcore.AddParam(func, ty_double, "%a") + mcore.AddParam(func, ty_double, "%b") + entry: llvmlite.BasicBlock | t.CPtr = mcore.CreateBlock(func, "entry") + builder: llvmlite.IRBuilder | t.CPtr = mcore.NewBuilder(func) + llvmlite.position_at_end(builder, entry) + + v_a: llvmlite.Value | t.CPtr = mcore.SSAValue(ty_double, "%a") + v_b: llvmlite.Value | t.CPtr = mcore.SSAValue(ty_double, "%b") + v_c: llvmlite.Value | t.CPtr = llvmlite.build_fadd(builder, v_a, v_b) + llvmlite.build_ret(builder, v_c) + + buf: t.CChar | t.CPtr = pool.alloc(4096) + buf[0] = 0 + mcore.PrintFunction(buf, 4096, func) + testcheck.info(buf) + + testcheck.check(string.strstr(buf, "fadd double") is not None, + "contains 'fadd double'", + "missing 'fadd double'") + testcheck.check(string.strstr(buf, "ret double") is not None, + "contains 'ret double'", + "missing 'ret double'") + + +# ============================================================ +# 测试 12: 位运算与移位 +# ============================================================ +def test_bitwise_ops(pool: memhub.MemPool | t.CPtr): + testcheck.section("Test 12: Bitwise & Shift Ops") + core: llvmlite.LLVMTypeCore | t.CPtr = llvmlite.LLVMTypeCore(pool) + mcore: llvmlite.LLVMModuleCore | t.CPtr = llvmlite.LLVMModuleCore(pool) + ty_i32: llvmlite.LLVMType | t.CPtr = core.Int32() + + mod: llvmlite.Module | t.CPtr = mcore.NewModule("test_bitops") + func: llvmlite.Function | t.CPtr = mcore.CreateFunction(mod, "bitops", ty_i32) + mcore.AddParam(func, ty_i32, "%a") + mcore.AddParam(func, ty_i32, "%b") + entry: llvmlite.BasicBlock | t.CPtr = mcore.CreateBlock(func, "entry") + builder: llvmlite.IRBuilder | t.CPtr = mcore.NewBuilder(func) + llvmlite.position_at_end(builder, entry) + + v_a: llvmlite.Value | t.CPtr = mcore.SSAValue(ty_i32, "%a") + v_b: llvmlite.Value | t.CPtr = mcore.SSAValue(ty_i32, "%b") + + # and -> or -> xor -> shl -> ret + v_and: llvmlite.Value | t.CPtr = llvmlite.build_and(builder, v_a, v_b) + v_or: llvmlite.Value | t.CPtr = llvmlite.build_or(builder, v_and, v_b) + v_xor: llvmlite.Value | t.CPtr = llvmlite.build_xor(builder, v_or, v_a) + v_shl: llvmlite.Value | t.CPtr = llvmlite.build_shl(builder, v_xor, v_b) + llvmlite.build_ret(builder, v_shl) + + buf: t.CChar | t.CPtr = pool.alloc(4096) + buf[0] = 0 + mcore.PrintFunction(buf, 4096, func) + testcheck.info(buf) + + testcheck.check(string.strstr(buf, "and i32") is not None, "has 'and i32'", "missing 'and i32'") + testcheck.check(string.strstr(buf, "or i32") is not None, "has 'or i32'", "missing 'or i32'") + testcheck.check(string.strstr(buf, "xor i32") is not None, "has 'xor i32'", "missing 'xor i32'") + testcheck.check(string.strstr(buf, "shl i32") is not None, "has 'shl i32'", "missing 'shl i32'") + + +# ============================================================ +# 测试 13: FCMP 比较 +# ============================================================ +def test_fcmp(pool: memhub.MemPool | t.CPtr): + testcheck.section("Test 13: FCMP") + core: llvmlite.LLVMTypeCore | t.CPtr = llvmlite.LLVMTypeCore(pool) + mcore: llvmlite.LLVMModuleCore | t.CPtr = llvmlite.LLVMModuleCore(pool) + ty_double: llvmlite.LLVMType | t.CPtr = core.Double() + ty_i1: llvmlite.LLVMType | t.CPtr = core.Int1() + + mod: llvmlite.Module | t.CPtr = mcore.NewModule("test_fcmp") + func: llvmlite.Function | t.CPtr = mcore.CreateFunction(mod, "fcmp_test", ty_i1) + mcore.AddParam(func, ty_double, "%a") + mcore.AddParam(func, ty_double, "%b") + entry: llvmlite.BasicBlock | t.CPtr = mcore.CreateBlock(func, "entry") + builder: llvmlite.IRBuilder | t.CPtr = mcore.NewBuilder(func) + llvmlite.position_at_end(builder, entry) + + v_a: llvmlite.Value | t.CPtr = mcore.SSAValue(ty_double, "%a") + v_b: llvmlite.Value | t.CPtr = mcore.SSAValue(ty_double, "%b") + v_cond: llvmlite.Value | t.CPtr = llvmlite.build_fcmp(builder, llvmlite.FCMP_OEQ, v_a, v_b) + llvmlite.build_ret(builder, v_cond) + + buf: t.CChar | t.CPtr = pool.alloc(4096) + buf[0] = 0 + mcore.PrintFunction(buf, 4096, func) + testcheck.info(buf) + + testcheck.check(string.strstr(buf, "fcmp oeq double") is not None, + "contains 'fcmp oeq double'", + "missing 'fcmp oeq double'") + + +# ============================================================ +# 测试 14: 类型转换 (zext, ptrtoint, inttoptr) +# ============================================================ +def test_casts(pool: memhub.MemPool | t.CPtr): + testcheck.section("Test 14: Casts (zext/ptrtoint/inttoptr)") + core: llvmlite.LLVMTypeCore | t.CPtr = llvmlite.LLVMTypeCore(pool) + mcore: llvmlite.LLVMModuleCore | t.CPtr = llvmlite.LLVMModuleCore(pool) + ty_i32: llvmlite.LLVMType | t.CPtr = core.Int32() + ty_i64: llvmlite.LLVMType | t.CPtr = core.Int64() + ty_i8: llvmlite.LLVMType | t.CPtr = core.Int8() + ty_i8ptr: llvmlite.LLVMType | t.CPtr = core.Ptr(ty_i8) + + mod: llvmlite.Module | t.CPtr = mcore.NewModule("test_casts") + func: llvmlite.Function | t.CPtr = mcore.CreateFunction(mod, "cast_test", ty_i64) + mcore.AddParam(func, ty_i32, "%x") + entry: llvmlite.BasicBlock | t.CPtr = mcore.CreateBlock(func, "entry") + builder: llvmlite.IRBuilder | t.CPtr = mcore.NewBuilder(func) + llvmlite.position_at_end(builder, entry) + + v_x: llvmlite.Value | t.CPtr = mcore.SSAValue(ty_i32, "%x") + # zext i32 %x to i64 + v_ext: llvmlite.Value | t.CPtr = llvmlite.build_zext(builder, v_x, ty_i64) + # ptrtoint i8* null to i64 + v_null: llvmlite.Value | t.CPtr = mcore.ConstNull(ty_i8ptr, "null") + v_p2i: llvmlite.Value | t.CPtr = llvmlite.build_ptrtoint(builder, v_null, ty_i64) + # inttoptr i64 %p2i to i8* + v_i2p: llvmlite.Value | t.CPtr = llvmlite.build_inttoptr(builder, v_p2i, ty_i8ptr) + # ret i64 %ext + llvmlite.build_ret(builder, v_ext) + + buf: t.CChar | t.CPtr = pool.alloc(4096) + buf[0] = 0 + mcore.PrintFunction(buf, 4096, func) + testcheck.info(buf) + + testcheck.check(string.strstr(buf, "zext i32") is not None, "has 'zext i32'", "missing 'zext i32'") + testcheck.check(string.strstr(buf, "ptrtoint i8*") is not None, "has 'ptrtoint i8*'", "missing 'ptrtoint i8*'") + testcheck.check(string.strstr(buf, "inttoptr i64") is not None, "has 'inttoptr i64'", "missing 'inttoptr i64'") + + +# ============================================================ +# 测试 15: 浮点转换 (fp2si, si2fp) +# ============================================================ +def test_fp_conversions(pool: memhub.MemPool | t.CPtr): + testcheck.section("Test 15: FP Conversions (fp2si/si2fp)") + core: llvmlite.LLVMTypeCore | t.CPtr = llvmlite.LLVMTypeCore(pool) + mcore: llvmlite.LLVMModuleCore | t.CPtr = llvmlite.LLVMModuleCore(pool) + ty_i32: llvmlite.LLVMType | t.CPtr = core.Int32() + ty_double: llvmlite.LLVMType | t.CPtr = core.Double() + + mod: llvmlite.Module | t.CPtr = mcore.NewModule("test_fpconv") + func: llvmlite.Function | t.CPtr = mcore.CreateFunction(mod, "fpconv", ty_double) + mcore.AddParam(func, ty_i32, "%n") + entry: llvmlite.BasicBlock | t.CPtr = mcore.CreateBlock(func, "entry") + builder: llvmlite.IRBuilder | t.CPtr = mcore.NewBuilder(func) + llvmlite.position_at_end(builder, entry) + + v_n: llvmlite.Value | t.CPtr = mcore.SSAValue(ty_i32, "%n") + # sitofp i32 %n to double + v_d: llvmlite.Value | t.CPtr = llvmlite.build_si2fp(builder, v_n, ty_double) + # fptosi double %d to i32 + v_i: llvmlite.Value | t.CPtr = llvmlite.build_fp2si(builder, v_d, ty_i32) + # sitofp i32 %i to double (return) + v_r: llvmlite.Value | t.CPtr = llvmlite.build_si2fp(builder, v_i, ty_double) + llvmlite.build_ret(builder, v_r) + + buf: t.CChar | t.CPtr = pool.alloc(4096) + buf[0] = 0 + mcore.PrintFunction(buf, 4096, func) + testcheck.info(buf) + + testcheck.check(string.strstr(buf, "sitofp i32") is not None, "has 'sitofp i32'", "missing 'sitofp i32'") + testcheck.check(string.strstr(buf, "fptosi double") is not None, "has 'fptosi double'", "missing 'fptosi double'") + + +# ============================================================ +# 测试 16: Phi 节点 +# ============================================================ +def test_phi(pool: memhub.MemPool | t.CPtr): + testcheck.section("Test 16: Phi Node") + core: llvmlite.LLVMTypeCore | t.CPtr = llvmlite.LLVMTypeCore(pool) + mcore: llvmlite.LLVMModuleCore | t.CPtr = llvmlite.LLVMModuleCore(pool) + ty_i32: llvmlite.LLVMType | t.CPtr = core.Int32() + + mod: llvmlite.Module | t.CPtr = mcore.NewModule("test_phi") + func: llvmlite.Function | t.CPtr = mcore.CreateFunction(mod, "phi_test", ty_i32) + entry: llvmlite.BasicBlock | t.CPtr = mcore.CreateBlock(func, "entry") + then_blk: llvmlite.BasicBlock | t.CPtr = mcore.CreateBlock(func, "then") + else_blk: llvmlite.BasicBlock | t.CPtr = mcore.CreateBlock(func, "else") + merge: llvmlite.BasicBlock | t.CPtr = mcore.CreateBlock(func, "merge") + builder: llvmlite.IRBuilder | t.CPtr = mcore.NewBuilder(func) + + # entry: br label %then + llvmlite.position_at_end(builder, entry) + llvmlite.build_br(builder, then_blk) + + # then: br label %merge + llvmlite.position_at_end(builder, then_blk) + v_1: llvmlite.Value | t.CPtr = mcore.ConstInt32(1) + llvmlite.build_br(builder, merge) + + # else: br label %merge + llvmlite.position_at_end(builder, else_blk) + v_2: llvmlite.Value | t.CPtr = mcore.ConstInt32(2) + llvmlite.build_br(builder, merge) + + # merge: %r = phi i32 [1, %then], [2, %else]; ret i32 %r + llvmlite.position_at_end(builder, merge) + inc1: llvmlite.PhiIncoming | t.CPtr = llvmlite.new_phi_incoming(pool, v_1, then_blk) + inc2: llvmlite.PhiIncoming | t.CPtr = llvmlite.new_phi_incoming(pool, v_2, else_blk) + inc1.Next = inc2 + v_r: llvmlite.Value | t.CPtr = llvmlite.build_phi(builder, ty_i32, inc1, 2) + llvmlite.build_ret(builder, v_r) + + buf: t.CChar | t.CPtr = pool.alloc(4096) + buf[0] = 0 + mcore.PrintFunction(buf, 4096, func) + testcheck.info(buf) + + testcheck.check(string.strstr(buf, "phi i32") is not None, "has 'phi i32'", "missing 'phi i32'") + testcheck.check(string.strstr(buf, "[") is not None, "has '['", "missing '['") + testcheck.check(string.strstr(buf, "%then") is not None, "has '%then'", "missing '%then'") + testcheck.check(string.strstr(buf, "%else") is not None, "has '%else'", "missing '%else'") + + +# ============================================================ +# 测试 17: Switch +# ============================================================ +def test_switch(pool: memhub.MemPool | t.CPtr): + testcheck.section("Test 17: Switch") + core: llvmlite.LLVMTypeCore | t.CPtr = llvmlite.LLVMTypeCore(pool) + mcore: llvmlite.LLVMModuleCore | t.CPtr = llvmlite.LLVMModuleCore(pool) + ty_i32: llvmlite.LLVMType | t.CPtr = core.Int32() + ty_void: llvmlite.LLVMType | t.CPtr = core.Void() + + mod: llvmlite.Module | t.CPtr = mcore.NewModule("test_switch") + func: llvmlite.Function | t.CPtr = mcore.CreateFunction(mod, "switch_test", ty_void) + mcore.AddParam(func, ty_i32, "%x") + entry: llvmlite.BasicBlock | t.CPtr = mcore.CreateBlock(func, "entry") + case0: llvmlite.BasicBlock | t.CPtr = mcore.CreateBlock(func, "case0") + case1: llvmlite.BasicBlock | t.CPtr = mcore.CreateBlock(func, "case1") + default_blk: llvmlite.BasicBlock | t.CPtr = mcore.CreateBlock(func, "default") + builder: llvmlite.IRBuilder | t.CPtr = mcore.NewBuilder(func) + + # entry: switch i32 %x, label %default [i32 0, label %case0; i32 1, label %case1] + llvmlite.position_at_end(builder, entry) + v_x: llvmlite.Value | t.CPtr = mcore.SSAValue(ty_i32, "%x") + v_0: llvmlite.Value | t.CPtr = mcore.ConstInt32(0) + v_1: llvmlite.Value | t.CPtr = mcore.ConstInt32(1) + c0: llvmlite.SwitchCase | t.CPtr = llvmlite.new_switch_case(pool, v_0, case0) + c1: llvmlite.SwitchCase | t.CPtr = llvmlite.new_switch_case(pool, v_1, case1) + c0.Next = c1 + llvmlite.build_switch(builder, v_x, default_blk, c0, 2) + + # case0/case1/default: ret void + llvmlite.position_at_end(builder, case0) + llvmlite.build_ret_void(builder) + llvmlite.position_at_end(builder, case1) + llvmlite.build_ret_void(builder) + llvmlite.position_at_end(builder, default_blk) + llvmlite.build_ret_void(builder) + + buf: t.CChar | t.CPtr = pool.alloc(4096) + buf[0] = 0 + mcore.PrintFunction(buf, 4096, func) + testcheck.info(buf) + + testcheck.check(string.strstr(buf, "switch i32") is not None, "has 'switch i32'", "missing 'switch i32'") + testcheck.check(string.strstr(buf, "label %default") is not None, "has 'label %default'", "missing 'label %default'") + testcheck.check(string.strstr(buf, "label %case0") is not None, "has 'label %case0'", "missing 'label %case0'") + + +# ============================================================ +# 测试 18: Select +# ============================================================ +def test_select(pool: memhub.MemPool | t.CPtr): + testcheck.section("Test 18: Select") + core: llvmlite.LLVMTypeCore | t.CPtr = llvmlite.LLVMTypeCore(pool) + mcore: llvmlite.LLVMModuleCore | t.CPtr = llvmlite.LLVMModuleCore(pool) + ty_i32: llvmlite.LLVMType | t.CPtr = core.Int32() + + mod: llvmlite.Module | t.CPtr = mcore.NewModule("test_select") + func: llvmlite.Function | t.CPtr = mcore.CreateFunction(mod, "sel_test", ty_i32) + mcore.AddParam(func, ty_i32, "%a") + mcore.AddParam(func, ty_i32, "%b") + entry: llvmlite.BasicBlock | t.CPtr = mcore.CreateBlock(func, "entry") + builder: llvmlite.IRBuilder | t.CPtr = mcore.NewBuilder(func) + llvmlite.position_at_end(builder, entry) + + v_a: llvmlite.Value | t.CPtr = mcore.SSAValue(ty_i32, "%a") + v_b: llvmlite.Value | t.CPtr = mcore.SSAValue(ty_i32, "%b") + v_cond: llvmlite.Value | t.CPtr = llvmlite.build_icmp(builder, llvmlite.ICMP_SLT, v_a, v_b) + v_sel: llvmlite.Value | t.CPtr = llvmlite.build_select(builder, v_cond, v_a, v_b) + llvmlite.build_ret(builder, v_sel) + + buf: t.CChar | t.CPtr = pool.alloc(4096) + buf[0] = 0 + mcore.PrintFunction(buf, 4096, func) + testcheck.info(buf) + + testcheck.check(string.strstr(buf, "select i1") is not None, "has 'select i1'", "missing 'select i1'") + + +# ============================================================ +# 测试 19: 全局变量 (字符串常量 + 整数) +# ============================================================ +def test_globals(pool: memhub.MemPool | t.CPtr): + testcheck.section("Test 19: Global Variables") + core: llvmlite.LLVMTypeCore | t.CPtr = llvmlite.LLVMTypeCore(pool) + mcore: llvmlite.LLVMModuleCore | t.CPtr = llvmlite.LLVMModuleCore(pool) + ty_i32: llvmlite.LLVMType | t.CPtr = core.Int32() + ty_void: llvmlite.LLVMType | t.CPtr = core.Void() + + mod: llvmlite.Module | t.CPtr = mcore.NewModule("test_globals") + llvmlite.module_set_target(mod, "x86_64-pc-windows-gnu") + + # 字符串常量: @.str = private unnamed_addr constant [6 x i8] c"hello\00" + mcore.CreateGlobalString(mod, ".str", "hello") + + # 整数全局变量: @counter = global i32 0 + mcore.CreateGlobalInt(mod, "counter", 32, 0) + + # 添加一个简单函数使模块非空 + func: llvmlite.Function | t.CPtr = mcore.CreateFunction(mod, "use_global", ty_void) + entry: llvmlite.BasicBlock | t.CPtr = mcore.CreateBlock(func, "entry") + builder: llvmlite.IRBuilder | t.CPtr = mcore.NewBuilder(func) + llvmlite.position_at_end(builder, entry) + llvmlite.build_ret_void(builder) + + buf: t.CChar | t.CPtr = pool.alloc(8192) + buf[0] = 0 + mcore.PrintModule(buf, 8192, mod) + testcheck.info(buf) + + testcheck.check(string.strstr(buf, "@.str =") is not None, "has '@.str ='", "missing '@.str ='") + testcheck.check(string.strstr(buf, "private unnamed_addr constant") is not None, + "has 'private unnamed_addr constant'", + "missing 'private unnamed_addr constant'") + testcheck.check(string.strstr(buf, "c\"hello") is not None, "has 'c\"hello'", "missing string content") + testcheck.check(string.strstr(buf, "@counter =") is not None, "has '@counter ='", "missing '@counter ='") + testcheck.check(string.strstr(buf, "global i32 0") is not None, "has 'global i32 0'", "missing 'global i32 0'") + + +# ============================================================ +# 测试 20: 函数与参数属性 +# ============================================================ +def test_attributes(pool: memhub.MemPool | t.CPtr): + testcheck.section("Test 20: Function & Param Attributes") + core: llvmlite.LLVMTypeCore | t.CPtr = llvmlite.LLVMTypeCore(pool) + mcore: llvmlite.LLVMModuleCore | t.CPtr = llvmlite.LLVMModuleCore(pool) + ty_i32: llvmlite.LLVMType | t.CPtr = core.Int32() + ty_i8ptr: llvmlite.LLVMType | t.CPtr = core.Ptr(core.Int8()) + + mod: llvmlite.Module | t.CPtr = mcore.NewModule("test_attrs") + func: llvmlite.Function | t.CPtr = mcore.CreateFunction(mod, "attr_test", ty_i32) + + # 参数 0: i32 noundef %x + p0: llvmlite.Param | t.CPtr = mcore.AddParam(func, ty_i32, "%x") + mcore.ParamSetAttrs(p0, "noundef") + + # 参数 1: i8* nocapture %p + p1: llvmlite.Param | t.CPtr = mcore.AddParam(func, ty_i8ptr, "%p") + mcore.ParamSetAttrs(p1, "nocapture") + + # 函数属性: nounwind + mcore.FunctionSetAttrs(func, "nounwind") + + entry: llvmlite.BasicBlock | t.CPtr = mcore.CreateBlock(func, "entry") + builder: llvmlite.IRBuilder | t.CPtr = mcore.NewBuilder(func) + llvmlite.position_at_end(builder, entry) + v_x: llvmlite.Value | t.CPtr = mcore.SSAValue(ty_i32, "%x") + llvmlite.build_ret(builder, v_x) + + buf: t.CChar | t.CPtr = pool.alloc(4096) + buf[0] = 0 + mcore.PrintFunction(buf, 4096, func) + testcheck.info(buf) + + testcheck.check(string.strstr(buf, "noundef i32") is not None, "has 'noundef i32'", "missing 'noundef i32'") + testcheck.check(string.strstr(buf, "nocapture i8*") is not None, "has 'nocapture i8*'", "missing 'nocapture i8*'") + testcheck.check(string.strstr(buf, ") nounwind") is not None, "has ') nounwind'", "missing ') nounwind'") + + +# ============================================================ +# 测试 21: 原子操作 (atomicrmw / cmpxchg) +# ============================================================ +def test_atomic(pool: memhub.MemPool | t.CPtr): + testcheck.section("Test 21: Atomic Ops") + core: llvmlite.LLVMTypeCore | t.CPtr = llvmlite.LLVMTypeCore(pool) + mcore: llvmlite.LLVMModuleCore | t.CPtr = llvmlite.LLVMModuleCore(pool) + ty_i32: llvmlite.LLVMType | t.CPtr = core.Int32() + ty_i32ptr: llvmlite.LLVMType | t.CPtr = core.Ptr(ty_i32) + + mod: llvmlite.Module | t.CPtr = mcore.NewModule("test_atomic") + func: llvmlite.Function | t.CPtr = mcore.CreateFunction(mod, "atomic_test", ty_i32) + mcore.AddParam(func, ty_i32ptr, "%p") + entry: llvmlite.BasicBlock | t.CPtr = mcore.CreateBlock(func, "entry") + builder: llvmlite.IRBuilder | t.CPtr = mcore.NewBuilder(func) + llvmlite.position_at_end(builder, entry) + + v_p: llvmlite.Value | t.CPtr = mcore.SSAValue(ty_i32ptr, "%p") + v_1: llvmlite.Value | t.CPtr = mcore.ConstInt32(1) + # atomicrmw add i32* %p, i32 1 monotonic + v_r: llvmlite.Value | t.CPtr = llvmlite.build_atomicrmw(builder, llvmlite.ATOMIC_ADD, + v_p, v_1, llvmlite.ATOMIC_ORDER_MONOTONIC) + llvmlite.build_ret(builder, v_r) + + buf: t.CChar | t.CPtr = pool.alloc(4096) + buf[0] = 0 + mcore.PrintFunction(buf, 4096, func) + testcheck.info(buf) + + testcheck.check(string.strstr(buf, "atomicrmw add") is not None, "has 'atomicrmw add'", "missing 'atomicrmw add'") + testcheck.check(string.strstr(buf, "monotonic") is not None, "has 'monotonic'", "missing 'monotonic'") + + +# ============================================================ +# 测试 22: 内联汇编 + unreachable +# ============================================================ +def test_inline_asm_unreachable(pool: memhub.MemPool | t.CPtr): + testcheck.section("Test 22: Inline ASM & Unreachable") + core: llvmlite.LLVMTypeCore | t.CPtr = llvmlite.LLVMTypeCore(pool) + mcore: llvmlite.LLVMModuleCore | t.CPtr = llvmlite.LLVMModuleCore(pool) + ty_void: llvmlite.LLVMType | t.CPtr = core.Void() + + mod: llvmlite.Module | t.CPtr = mcore.NewModule("test_asm") + func: llvmlite.Function | t.CPtr = mcore.CreateFunction(mod, "asm_test", ty_void) + entry: llvmlite.BasicBlock | t.CPtr = mcore.CreateBlock(func, "entry") + trap_blk: llvmlite.BasicBlock | t.CPtr = mcore.CreateBlock(func, "trap") + builder: llvmlite.IRBuilder | t.CPtr = mcore.NewBuilder(func) + + # entry: call void asm sideeffect "nop", ""(); br label %trap + llvmlite.position_at_end(builder, entry) + llvmlite.build_inline_asm(builder, ty_void, "nop", "", 1) + llvmlite.build_br(builder, trap_blk) + + # trap: unreachable + llvmlite.position_at_end(builder, trap_blk) + llvmlite.build_unreachable(builder) + + buf: t.CChar | t.CPtr = pool.alloc(4096) + buf[0] = 0 + mcore.PrintFunction(buf, 4096, func) + testcheck.info(buf) + + testcheck.check(string.strstr(buf, "asm sideeffect") is not None, "has 'asm sideeffect'", "missing 'asm sideeffect'") + testcheck.check(string.strstr(buf, "unreachable") is not None, "has 'unreachable'", "missing 'unreachable'") + + +# ============================================================ +# 测试 23: SSA 验证 - 合法函数通过 +# ============================================================ +def test_verify_valid(pool: memhub.MemPool | t.CPtr): + testcheck.section("Test 23: Verify Valid Function") + core: llvmlite.LLVMTypeCore | t.CPtr = llvmlite.LLVMTypeCore(pool) + mcore: llvmlite.LLVMModuleCore | t.CPtr = llvmlite.LLVMModuleCore(pool) + ty_i32: llvmlite.LLVMType | t.CPtr = core.Int32() + + mod: llvmlite.Module | t.CPtr = mcore.NewModule("verify_valid") + func: llvmlite.Function | t.CPtr = mcore.CreateFunction(mod, "add", ty_i32) + mcore.AddParam(func, ty_i32, "%a") + mcore.AddParam(func, ty_i32, "%b") + entry: llvmlite.BasicBlock | t.CPtr = mcore.CreateBlock(func, "entry") + builder: llvmlite.IRBuilder | t.CPtr = mcore.NewBuilder(func) + llvmlite.position_at_end(builder, entry) + v_a: llvmlite.Value | t.CPtr = mcore.SSAValue(ty_i32, "%a") + v_b: llvmlite.Value | t.CPtr = mcore.SSAValue(ty_i32, "%b") + v_c: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, v_a, v_b) + llvmlite.build_ret(builder, v_c) + + result: llvmlite.VerifyResult | t.CPtr = mcore.NewVerifyResult(4096) + err_count: t.CInt = mcore.VerifyFunction(func, result) + testcheck.check(err_count == 0, + "valid add function: 0 errors", + "valid function should pass verification") + testcheck.check(result.ErrorCode == llvmlite.VERIFY_OK, + "error code = VERIFY_OK", + "wrong error code for valid function") + + +# ============================================================ +# 测试 24: SSA 验证 - 缺少终止指令 +# ============================================================ +def test_verify_no_terminator(pool: memhub.MemPool | t.CPtr): + testcheck.section("Test 24: Verify Missing Terminator") + core: llvmlite.LLVMTypeCore | t.CPtr = llvmlite.LLVMTypeCore(pool) + mcore: llvmlite.LLVMModuleCore | t.CPtr = llvmlite.LLVMModuleCore(pool) + ty_i32: llvmlite.LLVMType | t.CPtr = core.Int32() + + mod: llvmlite.Module | t.CPtr = mcore.NewModule("verify_noterm") + func: llvmlite.Function | t.CPtr = mcore.CreateFunction(mod, "noterm", ty_i32) + mcore.AddParam(func, ty_i32, "%a") + entry: llvmlite.BasicBlock | t.CPtr = mcore.CreateBlock(func, "entry") + builder: llvmlite.IRBuilder | t.CPtr = mcore.NewBuilder(func) + llvmlite.position_at_end(builder, entry) + v_a: llvmlite.Value | t.CPtr = mcore.SSAValue(ty_i32, "%a") + llvmlite.build_add(builder, v_a, v_a) # 无 ret + + result: llvmlite.VerifyResult | t.CPtr = mcore.NewVerifyResult(4096) + err_count: t.CInt = mcore.VerifyFunction(func, result) + testcheck.check(err_count > 0, + "missing terminator detected", + "should detect missing terminator") + testcheck.check(result.ErrorCode == llvmlite.VERIFY_ERR_NO_TERMINATOR, + "error code = NO_TERMINATOR", + "wrong error code for missing terminator") + + +# ============================================================ +# 测试 25: SSA 验证 - 重复定义 +# ============================================================ +def test_verify_duplicate_def(pool: memhub.MemPool | t.CPtr): + testcheck.section("Test 25: Verify Duplicate Definition") + core: llvmlite.LLVMTypeCore | t.CPtr = llvmlite.LLVMTypeCore(pool) + mcore: llvmlite.LLVMModuleCore | t.CPtr = llvmlite.LLVMModuleCore(pool) + ty_i32: llvmlite.LLVMType | t.CPtr = core.Int32() + + mod: llvmlite.Module | t.CPtr = mcore.NewModule("verify_dup") + func: llvmlite.Function | t.CPtr = mcore.CreateFunction(mod, "dup_test", ty_i32) + mcore.AddParam(func, ty_i32, "%a") + entry: llvmlite.BasicBlock | t.CPtr = mcore.CreateBlock(func, "entry") + builder: llvmlite.IRBuilder | t.CPtr = mcore.NewBuilder(func) + llvmlite.position_at_end(builder, entry) + v_a: llvmlite.Value | t.CPtr = mcore.SSAValue(ty_i32, "%a") + v_c: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, v_a, v_a) + + # 手动追加重复定义行 "%0 = add i32 %a, %a" + dup_text: t.CChar | t.CPtr = pool.alloc(64) + string.strcpy(dup_text, "%0 = add i32 %a, %a") + llvmlite.block_append_text(pool, entry, dup_text) + + llvmlite.build_ret(builder, v_c) + + result: llvmlite.VerifyResult | t.CPtr = mcore.NewVerifyResult(4096) + err_count: t.CInt = mcore.VerifyFunction(func, result) + testcheck.check(err_count > 0, + "duplicate definition detected", + "should detect duplicate definition") + testcheck.check(result.ErrorCode == llvmlite.VERIFY_ERR_DUPLICATE_DEF, + "error code = DUPLICATE_DEF", + "wrong error code for duplicate def") + + +# ============================================================ +# 测试 26: SSA 验证 - 未定义引用 +# ============================================================ +def test_verify_undef_use(pool: memhub.MemPool | t.CPtr): + testcheck.section("Test 26: Verify Undefined Use") + core: llvmlite.LLVMTypeCore | t.CPtr = llvmlite.LLVMTypeCore(pool) + mcore: llvmlite.LLVMModuleCore | t.CPtr = llvmlite.LLVMModuleCore(pool) + ty_i32: llvmlite.LLVMType | t.CPtr = core.Int32() + + mod: llvmlite.Module | t.CPtr = mcore.NewModule("verify_undef") + func: llvmlite.Function | t.CPtr = mcore.CreateFunction(mod, "undef_test", ty_i32) + mcore.AddParam(func, ty_i32, "%a") + entry: llvmlite.BasicBlock | t.CPtr = mcore.CreateBlock(func, "entry") + + # 手动追加含未定义引用的行 "%0 = add i32 %ghost, %a" + line1: t.CChar | t.CPtr = pool.alloc(64) + string.strcpy(line1, "%0 = add i32 %ghost, %a") + llvmlite.block_append_text(pool, entry, line1) + + # 手动追加终止指令 + line2: t.CChar | t.CPtr = pool.alloc(64) + string.strcpy(line2, "ret i32 %0") + llvmlite.block_append_text(pool, entry, line2) + entry.IsTerminated = 1 + + result: llvmlite.VerifyResult | t.CPtr = mcore.NewVerifyResult(4096) + err_count: t.CInt = mcore.VerifyFunction(func, result) + testcheck.check(err_count > 0, + "undefined use detected", + "should detect undefined use") + testcheck.check(result.ErrorCode == llvmlite.VERIFY_ERR_UNDEFINED_USE, + "error code = UNDEFINED_USE", + "wrong error code for undefined use") + + +# ============================================================ +# 测试 27: SSA 验证 - 模块级验证(含 phi/分支,验证块标签修复) +# ============================================================ +def test_verify_module(pool: memhub.MemPool | t.CPtr): + testcheck.section("Test 27: Verify Module (phi/labels)") + core: llvmlite.LLVMTypeCore | t.CPtr = llvmlite.LLVMTypeCore(pool) + mcore: llvmlite.LLVMModuleCore | t.CPtr = llvmlite.LLVMModuleCore(pool) + ty_i32: llvmlite.LLVMType | t.CPtr = core.Int32() + + mod: llvmlite.Module | t.CPtr = mcore.NewModule("verify_module") + + # 函数 1: 简单 add(合法) + func1: llvmlite.Function | t.CPtr = mcore.CreateFunction(mod, "add", ty_i32) + mcore.AddParam(func1, ty_i32, "%a") + mcore.AddParam(func1, ty_i32, "%b") + entry1: llvmlite.BasicBlock | t.CPtr = mcore.CreateBlock(func1, "entry") + builder1: llvmlite.IRBuilder | t.CPtr = mcore.NewBuilder(func1) + llvmlite.position_at_end(builder1, entry1) + v_a: llvmlite.Value | t.CPtr = mcore.SSAValue(ty_i32, "%a") + v_b: llvmlite.Value | t.CPtr = mcore.SSAValue(ty_i32, "%b") + v_c: llvmlite.Value | t.CPtr = llvmlite.build_add(builder1, v_a, v_b) + llvmlite.build_ret(builder1, v_c) + + # 函数 2: 含 phi 与分支(合法,验证块标签不被误报为未定义) + func2: llvmlite.Function | t.CPtr = mcore.CreateFunction(mod, "phi_test", ty_i32) + f2_entry: llvmlite.BasicBlock | t.CPtr = mcore.CreateBlock(func2, "entry") + then_blk: llvmlite.BasicBlock | t.CPtr = mcore.CreateBlock(func2, "then") + else_blk: llvmlite.BasicBlock | t.CPtr = mcore.CreateBlock(func2, "else") + merge: llvmlite.BasicBlock | t.CPtr = mcore.CreateBlock(func2, "merge") + builder2: llvmlite.IRBuilder | t.CPtr = mcore.NewBuilder(func2) + + # entry: br label %then + llvmlite.position_at_end(builder2, f2_entry) + llvmlite.build_br(builder2, then_blk) + + # then: br label %merge + llvmlite.position_at_end(builder2, then_blk) + v_1: llvmlite.Value | t.CPtr = mcore.ConstInt32(1) + llvmlite.build_br(builder2, merge) + + # else: br label %merge + llvmlite.position_at_end(builder2, else_blk) + v_2: llvmlite.Value | t.CPtr = mcore.ConstInt32(2) + llvmlite.build_br(builder2, merge) + + # merge: %r = phi i32 [1, %then], [2, %else]; ret i32 %r + llvmlite.position_at_end(builder2, merge) + inc1: llvmlite.PhiIncoming | t.CPtr = llvmlite.new_phi_incoming(pool, v_1, then_blk) + inc2: llvmlite.PhiIncoming | t.CPtr = llvmlite.new_phi_incoming(pool, v_2, else_blk) + inc1.Next = inc2 + v_r: llvmlite.Value | t.CPtr = llvmlite.build_phi(builder2, ty_i32, inc1, 2) + llvmlite.build_ret(builder2, v_r) + + result: llvmlite.VerifyResult | t.CPtr = mcore.NewVerifyResult(4096) + err_count: t.CInt = mcore.VerifyModule(mod, result) + testcheck.check(err_count == 0, + "module with phi/branches: 0 errors", + "valid module with phi should pass verification") + testcheck.check(result.ErrorCode == llvmlite.VERIFY_OK, + "error code = VERIFY_OK", + "wrong error code for valid module") + + +def main() -> int: + testcheck.begin("LLvmLiteTest: llvmlite 库(LLVM IR 生成)") + + # 初始化 mpool + pool_mem: bytes = stdlib.malloc(POOL_SIZE) + if pool_mem is None: + stdio.printf("FAIL: malloc for pool failed\n") + return 1 + pool: memhub.MemPool | t.CPtr = memhub.MemPool(pool_mem, POOL_SIZE) + if pool is None: + stdio.printf("FAIL: memhub.MemPool init failed\n") + return 1 + + test_type_print(pool) + test_value_print(pool) + test_build_add(pool) + test_build_if_else(pool) + test_module_print(pool) + test_array_type(pool) + test_struct_type(pool) + test_func_type(pool) + test_declare(pool) + test_float_types(pool) + test_float_binops(pool) + test_bitwise_ops(pool) + test_fcmp(pool) + test_casts(pool) + test_fp_conversions(pool) + test_phi(pool) + test_switch(pool) + test_select(pool) + test_globals(pool) + test_attributes(pool) + test_atomic(pool) + test_inline_asm_unreachable(pool) + test_verify_valid(pool) + test_verify_no_terminator(pool) + test_verify_duplicate_def(pool) + test_verify_undef_use(pool) + test_verify_module(pool) + + return testcheck.end() diff --git a/LLvmLiteTest/project.json b/LLvmLiteTest/project.json new file mode 100644 index 0000000..6dc5fbb --- /dev/null +++ b/LLvmLiteTest/project.json @@ -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 + } +} diff --git a/ListTest/App/main.vp b/ListTest/App/main.vp new file mode 100644 index 0000000..86baf2f --- /dev/null +++ b/ListTest/App/main.vp @@ -0,0 +1,90 @@ +from stdint import * +import w32.win32console +import t, c +from t import CInt, CExport +import stdlib +import stdio +import memhub +import testcheck + + +def main() -> CInt | CExport: + w32.win32console.SetConsoleCP(65001) + w32.win32console.SetConsoleOutputCP(65001) + + testcheck.begin("ListTest: list[T] 堆容器测试") + + # 创建 mbuddy arena + arena: bytes = stdlib.malloc(65536) + bd: memhub.MemBuddy | t.CPtr = memhub.MemBuddy(arena, 65536) + + # === Test 1: 创建和 append === + testcheck.section("Test 1: 创建和 append") + nums = list[int](bd) + nums.append(10) + nums.append(20) + nums.append(30) + v0: CInt = nums.get(0) + v1: CInt = nums.get(1) + v2: CInt = nums.get(2) + stdio.printf("v0=%d v1=%d v2=%d\n", v0, v1, v2) + testcheck.check(v0 == 10 and v1 == 20 and v2 == 30, + "append+get OK (10,20,30)", "append+get FAILED") + + # === Test 2: __len__ === + testcheck.section("Test 2: __len__") + n: t.CSizeT = nums.__len__() + stdio.printf("len=%lu\n", n) + testcheck.check(n == 3, "__len__ OK (3)", "__len__ FAILED expect 3") + + # === Test 3: set === + testcheck.section("Test 3: set") + nums.set(1, 99) + v1b: CInt = nums.get(1) + stdio.printf("after set(1,99): v1=%d\n", v1b) + testcheck.check(v1b == 99, "set OK (idx1=99)", "set FAILED") + + # === Test 4: pop === + testcheck.section("Test 4: pop") + popped: CInt = nums.pop() + stdio.printf("popped=%d\n", popped) + testcheck.check(popped == 30, "pop OK (30)", "pop FAILED expect 30") + n2: t.CSizeT = nums.__len__() + testcheck.check(n2 == 2, "pop len OK (2)", "pop len FAILED expect 2") + + # === Test 5: clear === + testcheck.section("Test 5: clear") + nums.clear() + n3: t.CSizeT = nums.__len__() + testcheck.check(n3 == 0, "clear OK (0)", "clear FAILED expect 0") + + # === Test 6: 容量增长 (append 超过初始容量 8) === + testcheck.section("Test 6: 容量增长") + nums2 = list[int](bd) + i: CInt + for i in range(20): + nums2.append(i * 5) + n4: t.CSizeT = nums2.__len__() + stdio.printf("after 20 appends: len=%lu\n", n4) + testcheck.check(n4 == 20, "grow len OK (20)", "grow len FAILED") + ok: CInt = 1 + for i in range(20): + v: CInt = nums2.get(i) + if v != i * 5: + stdio.printf("MISMATCH at %d: got %d expect %d\n", i, v, i * 5) + ok = 0 + break + testcheck.check(ok == 1, "grow data OK", "grow data FAILED") + + # === Test 7: 重新 append 后验证 === + testcheck.section("Test 7: 重新 append") + nums2.clear() + nums2.append(100) + nums2.append(200) + va: CInt = nums2.get(0) + vb: CInt = nums2.get(1) + stdio.printf("re-append: va=%d vb=%d\n", va, vb) + testcheck.check(va == 100 and vb == 200, "re-append OK", "re-append FAILED") + + stdlib.free(arena) + return testcheck.end() diff --git a/ListTest/project.json b/ListTest/project.json new file mode 100644 index 0000000..984f96d --- /dev/null +++ b/ListTest/project.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "ListTest", + "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": "ListTest.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 + } +} diff --git a/LogicFlowTest/App/config.vp b/LogicFlowTest/App/config.vp new file mode 100644 index 0000000..1b4e36f --- /dev/null +++ b/LogicFlowTest/App/config.vp @@ -0,0 +1,24 @@ +import t, c + + +POSMAX: t.CDefine = 100 +MAX_RETRY: t.CDefine = 5 +BUFFER_SIZE: t.CDefine = 256 +PI: t.CDefine = 3.14159 +EULER: t.CDefine = 2.71828 +TRUE: t.CDefine = 1 +FALSE: t.CDefine = 0 +NULL: t.CDefine = 0 + + +MATH_OFFSET: t.CDefine = 10 +MATH_SCALE: t.CDefine = 2 +THRESHOLD: t.CDefine = 50 +LOOP_LIMIT: t.CDefine = 20 +SHIFT_AMOUNT: t.CDefine = 2 +MASK_VALUE: t.CDefine = 0xFF +BIT_RANGE: t.CDefine = 4 +EXPONENT_BASE: t.CDefine = 3 +MODULO_DIVISOR: t.CDefine = 7 +SCALE_SHIFT: t.CDefine = 4 +HALF_SCALE: t.CDefine = 0.5 \ No newline at end of file diff --git a/LogicFlowTest/App/logic_test.vp b/LogicFlowTest/App/logic_test.vp new file mode 100644 index 0000000..4d5c266 --- /dev/null +++ b/LogicFlowTest/App/logic_test.vp @@ -0,0 +1,372 @@ +import config +import t, c + + +def ForRangeBasicTest(stop: t.CInt): + i: t.CInt = 0 + for i in range(stop): + print("For range: ", i) + print("Done") + + +def ForRangeWithStartStop(start: t.CInt, stop: t.CInt, step: t.CInt): + i: t.CInt = 0 + for i in range(start, stop, step): + print("Range: ", i) + print("Done") + + +def NestedForRangeTest(rows: t.CInt, cols: t.CInt): + r: t.CInt = 0 + c_val: t.CInt = 0 + for r in range(rows): + for c_val in range(cols): + print("Cell: ", r, c_val) + print("Grid done") + + +def ForWithIfBreakTest(data_size: t.CInt): + i: t.CInt = 0 + found: t.CInt = 0 + for i in range(data_size): + if i == 5: + print("Found at: ", i) + found = 1 + break + print("Checking: ", i) + if found == 0: + print("Not found") + + +def ForWithIfContinueTest(n: t.CInt): + i: t.CInt = 0 + count: t.CInt = 0 + for i in range(n): + if i % 2 == 0: + continue + print("Odd: ", i) + count += 1 + print("Total odd: ", count) + + +def ForWithElifBranchTest(value: t.CInt): + i: t.CInt = 0 + result: t.CInt = 0 + for i in range(value): + if i < 3: + result += 1 + elif i < 6: + result += 2 + elif i < 9: + result += 3 + else: + result += 4 + print("Elif branch result: ", result) + + +def WhileWithIfElifElseTest(iterations: t.CInt): + counter: t.CInt = 0 + while counter < iterations: + if counter < 2: + print("Phase 1: ", counter) + elif counter < 4: + print("Phase 2: ", counter) + elif counter < 6: + print("Phase 3: ", counter) + else: + print("Phase 4: ", counter) + counter += 1 + print("While done") + + +def WhileWithNestedIfTest(limit: t.CInt): + outer: t.CInt = 0 + while outer < limit: + inner: t.CInt = 0 + while inner < limit: + if inner == 2 and outer == 1: + print("Target: ", outer, inner) + inner += 1 + continue + if inner > 3: + break + print("Inner: ", inner) + inner += 1 + outer += 1 + + +def WhileWithMatchCaseTest(value: t.CInt): + result: t.CInt = 0 + match value: + case 1: + result = 100 + print("Case 1") + case 2: + result = 200 + print("Case 2") + case 3: + result = 300 + print("Case 3") + case _: + result = 999 + print("Default case") + print("Match result: ", result) + + +def WhileWithMatchCaseNoBreakTest(value: t.CInt): + result: t.CInt = 0 + match value: + case 1: + result = 10 + print("Case 1: ", result) + case 2: + result = 20 + print("Case 2: ", result) + result += 5 + case 3: + result = 30 + print("Case 3: ", result) + case _: + result = 0 + print("No break match result: ", result) + + +def ComplexForWhileMatchTest(outer_limit: t.CInt, inner_limit: t.CInt): + i: t.CInt = 0 + j: t.CInt = 0 + result: t.CInt = 0 + for i in range(outer_limit): + j = 0 + while j < inner_limit: + match (i, j): + case (0, 0): + result += 1 + case (1, 1): + result += 10 + case (2, _): + result += 100 + case (_, 0): + result += 1000 + case _: + result += 10000 + j += 1 + print("Complex match result: ", result) + + +def ForWithCaseAndNoBreakTest(n: t.CInt): + i: t.CInt = 0 + result: t.CInt = 0 + for i in range(n): + match i: + case 0: + result += 1 + case 1: + result += 2 + case 2: + result += 3 + result += 10 + case _: + result += i + c.NoBreak + print("NoBreak result: ", result) + + +def WhileWithBreakConditionTest(limit: t.CInt): + i: t.CInt = 0 + early_exit: t.CInt = 0 + while i < limit: + if i == 3: + early_exit = 1 + break + if i == 2: + i += 1 + continue + print("While i: ", i) + i += 1 + + +def NestedWhileWithMultipleBreakPoints(depth: t.CInt, width: t.CInt): + d: t.CInt = 0 + w: t.CInt = 0 + count: t.CInt = 0 + while d < depth: + w = 0 + while w < width: + if w == 2: + break + if d == 1 and w == 1: + c.Break + count += 1 + w += 1 + d += 1 + print("Nested break count: ", count) + + +def ForWithMatchCaseInLoopTest(iterations: t.CInt): + i: t.CInt = 0 + sum_even: t.CInt = 0 + sum_odd: t.CInt = 0 + for i in range(iterations): + match i % 3: + case 0: + sum_even += i + case 1: + sum_odd += i + case 2: + sum_even += i * 2 + case _: + pass + print("Sum even: ", sum_even) + print("Sum odd: ", sum_odd) + + +def ComplexLogicWithElifChains(a: t.CInt, b: t.CInt, c_val: t.CInt): + i: t.CInt = 0 + result: t.CInt = 0 + while i < 10: + if i < a: + if i < b: + result += 1 + elif i < c_val: + result += 2 + else: + result += 3 + elif i < b: + if i < c_val: + result += 4 + else: + result += 5 + elif i < c_val: + result += 6 + else: + result += 7 + i += 1 + print("Complex elif chain result: ", result) + + +def ForRangeWithStepAndCondition(n: t.CInt, step: t.CInt): + i: t.CInt = 0 + count: t.CInt = 0 + for i in range(0, n, step): + if i % 2 == 0: + print("Even step: ", i) + count += 1 + else: + if i > 5: + print("Large odd: ", i) + else: + print("Small odd: ", i) + print("Total steps: ", count) + + +def MatchCaseWithGuardConditions(value: t.CInt): + result: t.CInt = 0 + match value: + case 1 if config.TRUE == 1: + result = 100 + case 2 if config.FALSE == 0: + result = 200 + case 3: + result = 300 + case _: + result = 0 + print("Guard match result: ", result) + + +def WhileWithMultipleMatchCases(iterations: t.CInt): + i: t.CInt = 0 + state: t.CInt = 0 + while i < iterations: + match state: + case 0: + if i > 3: + state = 1 + case 1: + if i > 6: + state = 2 + case 2: + if i > 9: + state = 0 + print("State at i=", i, ": ", state) + i += 1 + + +def ForWhileMixWithBreakAndContinue(n: t.CInt): + i: t.CInt = 0 + j: t.CInt = 0 + count: t.CInt = 0 + for i in range(n): + j = 0 + while j < n: + if j == 2: + j += 1 + continue + if i == 3 and j == 3: + break + count += 1 + j += 1 + print("Mix break continue count: ", count) + + +def ComplexCaseMatchingWithRanges(start: t.CInt, end: t.CInt): + i: t.CInt = 0 + bucket0: t.CInt = 0 + bucket1: t.CInt = 0 + bucket2: t.CInt = 0 + bucket3: t.CInt = 0 + for i in range(start, end): + match i: + case _ if i < 10: + bucket0 += 1 + case _ if i < 20: + bucket1 += 1 + case _ if i < 30: + bucket2 += 1 + case _: + bucket3 += 1 + print("Bucket0 (<10): ", bucket0) + print("Bucket1 (10-19): ", bucket1) + print("Bucket2 (20-29): ", bucket2) + print("Bucket3 (>=30): ", bucket3) + + +def WhileWithElifInElifChain(limit: t.CInt): + i: t.CInt = 0 + result: t.CInt = 0 + while i < limit: + if i < 2: + if i == 0: + result = 1 + else: + result = 2 + elif i < 4: + if i == 2: + result = 3 + else: + result = 4 + elif i < 6: + if i == 4: + result = 5 + else: + result = 6 + else: + result = 7 + print("Chain result[", i, "]: ", result) + i += 1 + + +def ForWithCaseNoBreakNested(inner_limit: t.CInt): + i: t.CInt = 0 + j: t.CInt = 0 + result: t.CInt = 0 + for i in range(3): + for j in range(inner_limit): + match j: + case 0: + result += 1 + case 1: + result += 2 + case _: + result += 3 + c.NoBreak + print("Nested NoBreak result: ", result) \ No newline at end of file diff --git a/LogicFlowTest/App/main.vp b/LogicFlowTest/App/main.vp new file mode 100644 index 0000000..78154c4 --- /dev/null +++ b/LogicFlowTest/App/main.vp @@ -0,0 +1,106 @@ +import t, c +import config +import logic_test +import testcheck + + +def main() -> t.CInt: + testcheck.begin("LogicFlowTest: For/While/Match/控制流测试") + + testcheck.section("For Range Basic Test (stop=5)") + logic_test.ForRangeBasicTest(5) + testcheck.ok("For Range Basic Test (5)") + + testcheck.section("For Range With Start Stop Step (start=1, stop=10, step=2)") + logic_test.ForRangeWithStartStop(1, 10, 2) + testcheck.ok("For Range With Start Stop (1, 10, 2)") + + testcheck.section("Nested For Range Test (rows=2, cols=3)") + logic_test.NestedForRangeTest(2, 3) + testcheck.ok("Nested For Range Test (2, 3)") + + testcheck.section("For With If Break Test (size=8)") + logic_test.ForWithIfBreakTest(8) + testcheck.ok("For With If Break Test (8)") + + testcheck.section("For With If Continue Test (n=10)") + logic_test.ForWithIfContinueTest(10) + testcheck.ok("For With If Continue Test (10)") + + testcheck.section("For With Elif Branch Test (value=10)") + logic_test.ForWithElifBranchTest(10) + testcheck.ok("For With Elif Branch Test (10)") + + testcheck.section("While With If Elif Else Test (iterations=7)") + logic_test.WhileWithIfElifElseTest(7) + testcheck.ok("While With If Elif Else Test (7)") + + testcheck.section("While With Nested If Test (limit=4)") + logic_test.WhileWithNestedIfTest(4) + testcheck.ok("While With Nested If Test (4)") + + testcheck.section("While With Match Case Test (value=2)") + logic_test.WhileWithMatchCaseTest(2) + testcheck.ok("While With Match Case Test (2)") + + testcheck.section("While With Match Case Test (value=99)") + logic_test.WhileWithMatchCaseTest(99) + testcheck.ok("While With Match Case Test (99)") + + testcheck.section("While With Match Case NoBreak Test (value=3)") + logic_test.WhileWithMatchCaseNoBreakTest(3) + testcheck.ok("While With Match Case NoBreak Test (3)") + + testcheck.section("Complex For While Match Test (outer=3, inner=3)") + logic_test.ComplexForWhileMatchTest(3, 3) + testcheck.ok("Complex For While Match Test (3, 3)") + + testcheck.section("For With Case And NoBreak Test (n=5)") + logic_test.ForWithCaseAndNoBreakTest(5) + testcheck.ok("For With Case And NoBreak Test (5)") + + testcheck.section("While With Break Condition Test (limit=6)") + logic_test.WhileWithBreakConditionTest(6) + testcheck.ok("While With Break Condition Test (6)") + + testcheck.section("Nested While With Multiple BreakPoints (depth=3, width=4)") + logic_test.NestedWhileWithMultipleBreakPoints(3, 4) + testcheck.ok("Nested While With Multiple BreakPoints (3, 4)") + + testcheck.section("For With Match Case In Loop Test (iterations=9)") + logic_test.ForWithMatchCaseInLoopTest(9) + testcheck.ok("For With Match Case In Loop Test (9)") + + testcheck.section("Complex Logic With Elif Chains (a=3, b=5, c=7)") + logic_test.ComplexLogicWithElifChains(3, 5, 7) + testcheck.ok("Complex Logic With Elif Chains (3, 5, 7)") + + testcheck.section("For Range With Step And Condition (n=12, step=2)") + logic_test.ForRangeWithStepAndCondition(12, 2) + testcheck.ok("For Range With Step And Condition (12, 2)") + + testcheck.section("Match Case With Guard Conditions (value=1)") + logic_test.MatchCaseWithGuardConditions(1) + testcheck.ok("Match Case With Guard Conditions (1)") + + testcheck.section("While With Multiple Match Cases (iterations=12)") + logic_test.WhileWithMultipleMatchCases(12) + testcheck.ok("While With Multiple Match Cases (12)") + + testcheck.section("For While Mix With Break And Continue (n=5)") + logic_test.ForWhileMixWithBreakAndContinue(5) + testcheck.ok("For While Mix With Break And Continue (5)") + + testcheck.section("Complex Case Matching With Ranges (start=0, end=35)") + logic_test.ComplexCaseMatchingWithRanges(0, 35) + testcheck.ok("Complex Case Matching With Ranges (0, 35)") + + testcheck.section("While With Elif In Elif Chain (limit=7)") + logic_test.WhileWithElifInElifChain(7) + testcheck.ok("While With Elif In Elif Chain (7)") + + testcheck.section("For With Case NoBreak Nested (inner_limit=4)") + logic_test.ForWithCaseNoBreakNested(4) + testcheck.ok("For With Case NoBreak Nested (4)") + + return testcheck.end() diff --git a/LogicFlowTest/project.json b/LogicFlowTest/project.json new file mode 100644 index 0000000..60a87ba --- /dev/null +++ b/LogicFlowTest/project.json @@ -0,0 +1,40 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "LogicFlowTest", + "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": "LogicFlowTest.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 + } +} \ No newline at end of file diff --git a/LoopMathTest/App/config.vp b/LoopMathTest/App/config.vp new file mode 100644 index 0000000..1b4e36f --- /dev/null +++ b/LoopMathTest/App/config.vp @@ -0,0 +1,24 @@ +import t, c + + +POSMAX: t.CDefine = 100 +MAX_RETRY: t.CDefine = 5 +BUFFER_SIZE: t.CDefine = 256 +PI: t.CDefine = 3.14159 +EULER: t.CDefine = 2.71828 +TRUE: t.CDefine = 1 +FALSE: t.CDefine = 0 +NULL: t.CDefine = 0 + + +MATH_OFFSET: t.CDefine = 10 +MATH_SCALE: t.CDefine = 2 +THRESHOLD: t.CDefine = 50 +LOOP_LIMIT: t.CDefine = 20 +SHIFT_AMOUNT: t.CDefine = 2 +MASK_VALUE: t.CDefine = 0xFF +BIT_RANGE: t.CDefine = 4 +EXPONENT_BASE: t.CDefine = 3 +MODULO_DIVISOR: t.CDefine = 7 +SCALE_SHIFT: t.CDefine = 4 +HALF_SCALE: t.CDefine = 0.5 \ No newline at end of file diff --git a/LoopMathTest/App/main.vp b/LoopMathTest/App/main.vp new file mode 100644 index 0000000..40c70ef --- /dev/null +++ b/LoopMathTest/App/main.vp @@ -0,0 +1,79 @@ +import stdio +import t, c +import config +import test +import testcheck + + +def main() -> t.CInt: + testcheck.begin("LoopMathTest: While/数学/跨模块宏测试") + + testcheck.section("Cross-module macros") + stdio.printf(" POSMAX: %d\n", config.POSMAX) + stdio.printf(" MATH_SCALE: %d\n", config.MATH_SCALE) + stdio.printf(" THRESHOLD: %d\n", config.THRESHOLD) + stdio.printf(" SHIFT_AMOUNT: %d\n", config.SHIFT_AMOUNT) + stdio.printf(" MASK_VALUE: 0x%x\n", config.MASK_VALUE) + testcheck.ok("config macros accessible") + + testcheck.section("While Loop Test") + test.AboutSizeTWhileTest(10) + testcheck.ok("While Loop Test (10)") + + testcheck.section("Math Basic Test (20, 6)") + test.MathBasicTest(20, 6) + testcheck.ok("Math Basic Test (20, 6)") + + testcheck.section("Math Advanced Test (value=15)") + test.MathAdvancedTest(15) + testcheck.ok("Math Advanced Test (value=15)") + + testcheck.section("While with Elif-Else Test (-2 to 12)") + test.WhileWithElifElseTest(-2, 12) + testcheck.ok("While with Elif-Else Test (-2 to 12)") + + testcheck.section("Nested While with Macros Test") + test.NestedWhileWithMacrosTest(3, 4) + testcheck.ok("Nested While with Macros Test (3, 4)") + + testcheck.section("Complex Condition Test (1, 2, 3)") + test.ComplexConditionTest(1, 2, 3) + testcheck.ok("Complex Condition Test (1, 2, 3)") + + testcheck.section("Retry Loop Test (8)") + test.RetryLoopTest(8) + testcheck.ok("Retry Loop Test (8)") + + testcheck.section("Bitwise Operations Test (0b1101101)") + test.BitwiseOperationsTest(109) + testcheck.ok("Bitwise Operations Test (109)") + + testcheck.section("Compound Assignment Math Test (15, 4)") + test.CompoundAssignmentMathTest(15, 4) + testcheck.ok("Compound Assignment Math Test (15, 4)") + + testcheck.section("Power and Modulo Test (2, 8)") + test.PowerAndModuloTest(2, 8) + testcheck.ok("Power and Modulo Test (2, 8)") + + testcheck.section("Mixed Arithmetic Test (5, 3, 4)") + test.MixedArithmeticTest(5, 3, 4) + testcheck.ok("Mixed Arithmetic Test (5, 3, 4)") + + testcheck.section("Math with While Loop Test (start=1, count=5)") + test.MathWithWhileLoopTest(1, 5) + testcheck.ok("Math with While Loop Test (1, 5)") + + testcheck.section("Complex Nested Math Test (7, 3)") + test.ComplexNestedMathTest(7, 3) + testcheck.ok("Complex Nested Math Test (7, 3)") + + testcheck.section("Conditional Math Chain Test (value=10)") + test.ConditionalMathChainTest(10) + testcheck.ok("Conditional Math Chain Test (value=10)") + + testcheck.section("Bit Manipulation Math Test (0xABCD)") + test.BitManipulationMathTest(0xABCD) + testcheck.ok("Bit Manipulation Math Test (0xABCD)") + + return testcheck.end() diff --git a/LoopMathTest/App/test.vp b/LoopMathTest/App/test.vp new file mode 100644 index 0000000..24a08a8 --- /dev/null +++ b/LoopMathTest/App/test.vp @@ -0,0 +1,298 @@ +import config +import t, c + + +def AboutSizeTWhileTest(length: t.CSizeT): + pos: t.CSizeT = 0 + while pos < length: + print("Pos: ", pos) + if pos > config.POSMAX: break + pos += 1 + while pos < length: + if pos > config.POSMAX: + print("Pos: ", pos) + pos += 1 + else: + print("Pos: ", pos) + pos += 1 + if pos > config.POSMAX: break + else: + pos += 1 + print("Pos: ", pos) + while pos < length: + print("Pos: ", pos) + pos += 1 + + +def MathBasicTest(x: t.CInt, y: t.CInt) -> t.CInt: + result: t.CInt = 0 + result = x + y + print("Add: ", result) + result = x - y + print("Sub: ", result) + result = x * y + print("Mul: ", result) + if y != 0: + result = x / y + print("Div: ", result) + result = x % y if y != 0 else 0 + print("Mod: ", result) + return result + + +def MathAdvancedTest(value: t.CInt) -> t.CInt: + counter: t.CInt = 0 + scaled: t.CInt = 0 + offset: t.CInt = 0 + scaled = value * config.MATH_SCALE + print("Scaled: ", scaled) + offset = scaled + config.MATH_OFFSET + print("Offset: ", offset) + threshold: t.CInt = config.THRESHOLD + if offset > threshold: + print("Above threshold") + counter = 1 + elif offset == threshold: + print("At threshold") + counter = 0 + else: + print("Below threshold") + counter = -1 + return counter + + +def WhileWithElifElseTest(start: t.CInt, end: t.CInt): + idx: t.CInt = start + while idx < end: + if idx < 0: + print("Negative: ", idx) + elif idx == 0: + print("Zero: ", idx) + elif idx > 0 and idx < 5: + print("Small positive: ", idx) + elif idx >= 5 and idx < 10: + print("Medium positive: ", idx) + else: + print("Large: ", idx) + idx += 1 + + +def NestedWhileWithMacrosTest(outer_limit: t.CInt, inner_limit: t.CInt): + outer: t.CInt = 0 + inner: t.CInt = 0 + total_ops: t.CInt = 0 + while outer < outer_limit: + inner = 0 + while inner < inner_limit: + if inner == config.TRUE: + print("Inner loop break condition at: ", inner) + total_ops += 1 + inner += 1 + outer += 1 + print("Total operations: ", total_ops) + + +def ComplexConditionTest(a: t.CInt, b: t.CInt, c_val: t.CInt): + x: t.CInt = a + y: t.CInt = b + z: t.CInt = c_val + while x < config.LOOP_LIMIT: + if x > 0 and y > 0 and z > 0: + print("All positive: ", x, y, z) + elif x <= 0 and y <= 0 and z <= 0: + print("All non-positive: ", x, y, z) + else: + if x > 0: + print("X positive") + elif y > 0: + print("Y positive") + else: + print("Z positive") + x += 1 + y += 1 + z += 1 + + +def RetryLoopTest(retry_count: t.CInt) -> t.CInt: + attempt: t.CInt = 0 + success: t.CInt = 0 + while attempt < retry_count: + if attempt < config.MAX_RETRY: + print("Attempt: ", attempt, " less than max") + success = attempt * 2 + elif attempt == config.MAX_RETRY: + print("At max retry") + success = -1 + else: + print("Beyond max retry") + success = -2 + attempt += 1 + return success + + +def BitwiseOperationsTest(value: t.CInt) -> t.CInt: + shifted: t.CInt = 0 + masked: t.CInt = 0 + xored: t.CInt = 0 + anded: t.CInt = 0 + ored: t.CInt = 0 + shifted = value << config.SHIFT_AMOUNT + print("Left shift: ", shifted) + shifted = value >> config.SHIFT_AMOUNT + print("Right shift: ", shifted) + masked = value & config.MASK_VALUE + print("Bitwise AND mask: ", masked) + xored = value ^ config.MASK_VALUE + print("Bitwise XOR: ", xored) + anded = value & (config.MASK_VALUE >> config.SHIFT_AMOUNT) + print("Bitwise AND shifted mask: ", anded) + ored = value | config.SHIFT_AMOUNT + print("Bitwise OR shift: ", ored) + return masked + + +def CompoundAssignmentMathTest(a: t.CInt, b: t.CInt) -> t.CInt: + x: t.CInt = a + y: t.CInt = b + result: t.CInt = 0 + x += y + print("x += y: ", x) + x -= y + print("x -= y: ", x) + x *= y + print("x *= y: ", x) + x = a + y = b + if b != 0: + x /= b + print("x /= y: ", x) + x = a + if b != 0: + x %= b + print("x %%= y: ", x) + x = a + x <<= config.SHIFT_AMOUNT + print("x <<= shift: ", x) + x >>= config.SHIFT_AMOUNT + print("x >>= shift: ", x) + x &= config.MASK_VALUE + print("x &= mask: ", x) + x |= config.SHIFT_AMOUNT + print("x |= shift: ", x) + result = (a + b) * config.MATH_SCALE - config.MATH_OFFSET + print("Compound: (a+b)*scale-offset: ", result) + result = (a * b) + (config.MATH_OFFSET / 2) + print("Compound: a*b+offset/2: ", result) + return result + + +def PowerAndModuloTest(base: t.CInt, exponent: t.CInt) -> t.CInt: + result: t.CInt = 1 + temp: t.CInt = 0 + i: t.CInt = 0 + while i < exponent: + result *= base + i += 1 + print("Power: ", result) + temp = result % config.MODULO_DIVISOR + print("Power mod: ", temp) + temp = (base * config.EXPONENT_BASE) % config.MODULO_DIVISOR + print("base*exp %% divisor: ", temp) + temp = ((base + config.MATH_OFFSET) * config.MATH_SCALE) % config.MODULO_DIVISOR + print("(base+offset)*scale %% divisor: ", temp) + return result + + +def MixedArithmeticTest(x: t.CInt, y: t.CInt, z: t.CInt) -> t.CInt: + result: t.CInt = 0 + result = (x + y) * z + print("(x+y)*z: ", result) + result = x + (y * z) + print("x+(y*z): ", result) + result = ((x + y) * config.MATH_SCALE) - config.MATH_OFFSET + print("((x+y)*scale)-offset: ", result) + result = (x * config.MATH_SCALE) + (y * config.MATH_SCALE) + print("x*scale + y*scale: ", result) + result = ((x % config.MODULO_DIVISOR) + (y % config.MODULO_DIVISOR)) * config.MATH_SCALE + print("(x%%mod + y%%mod)*scale: ", result) + temp: t.CInt = 0 + temp = x | y & z + print("x | y & z: ", temp) + temp = (x | y) & z + print("(x | y) & z: ", temp) + temp = x ^ y ^ z + print("x ^ y ^ z: ", temp) + return result + + +def MathWithWhileLoopTest(start: t.CInt, count: t.CInt) -> t.CInt: + idx: t.CInt = 0 + accumulator: t.CInt = 0 + multiplier: t.CInt = config.MATH_SCALE + while idx < count: + temp: t.CInt = (start + idx) * multiplier + temp = temp + config.MATH_OFFSET + if temp > config.THRESHOLD: + temp = config.THRESHOLD + accumulator += temp + multiplier += 1 + idx += 1 + print("Accumulator: ", accumulator) + return accumulator + + +def ComplexNestedMathTest(a: t.CInt, b: t.CInt) -> t.CInt: + layer1: t.CInt = 0 + layer2: t.CInt = 0 + layer3: t.CInt = 0 + i: t.CInt = 0 + layer1 = (a + b) * config.MATH_SCALE + print("Layer1: ", layer1) + while i < config.BIT_RANGE: + layer2 += layer1 >> 1 + i += 1 + print("Layer2: ", layer2) + layer3 = layer1 + layer2 - config.MATH_OFFSET + print("Layer3: ", layer3) + layer3 = layer3 * config.MATH_SCALE / 2 if config.MATH_SCALE != 0 else layer3 + print("Layer3 scaled: ", layer3) + return layer3 + + +def ConditionalMathChainTest(value: t.CInt) -> t.CInt: + result: t.CInt = 0 + step: t.CInt = 0 + while step < config.LOOP_LIMIT: + if step < 5: + result += step * config.MATH_SCALE + print("step<5: ", result) + elif step < 10: + result -= step - config.MATH_OFFSET + print("step<10: ", result) + elif step < 15: + result += (step * config.MATH_OFFSET) / config.MATH_SCALE + print("step<15: ", result) + else: + result = result * config.EXPONENT_BASE % config.MODULO_DIVISOR + print("step>=15: ", result) + step += 1 + return result + + +def BitManipulationMathTest(value: t.CInt) -> t.CInt: + original: t.CInt = value + nibble: t.CInt = 0 + result: t.CInt = 0 + result = (value << config.SHIFT_AMOUNT) | (value >> (8 - config.SHIFT_AMOUNT)) + print("Rotate left: ", result) + result = (value >> config.SHIFT_AMOUNT) | (value << (8 - config.SHIFT_AMOUNT)) + print("Rotate right: ", result) + nibble = value & 0xF + print("Lower nibble: ", nibble) + nibble = (value >> config.BIT_RANGE) & 0xF + print("Upper nibble: ", nibble) + result = ((value & config.MASK_VALUE) + config.MATH_OFFSET) * config.MATH_SCALE + print("Masked and scaled: ", result) + result = ((original << config.SHIFT_AMOUNT) ^ original) & config.MASK_VALUE + print("XOR shifted: ", result) + return result \ No newline at end of file diff --git a/LoopMathTest/project.json b/LoopMathTest/project.json new file mode 100644 index 0000000..9b1a44d --- /dev/null +++ b/LoopMathTest/project.json @@ -0,0 +1,40 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "LoopMathTest", + "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": "LoopMathTest.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 + } +} \ No newline at end of file diff --git a/LoopTest/App/main.vp b/LoopTest/App/main.vp new file mode 100644 index 0000000..e47117e --- /dev/null +++ b/LoopTest/App/main.vp @@ -0,0 +1,81 @@ +import t +import stdio +import testcheck + +def test_for_loop(): + testcheck.section("Test 1: for loop") + sum_val: t.CInt = 0 + for i in range(10): + sum_val += i + # 0+1+2+...+9 = 45 + testcheck.check(sum_val == 45, "for loop sum (0..9 = 45)", "for loop sum (expect 45)") + +def test_while_loop(): + testcheck.section("Test 2: while loop") + n: t.CInt = 100 + count: t.CInt = 0 + while n > 1: + if n % 2 == 0: + n = n // 2 + else: + n = 3 * n + 1 + count += 1 + # Collatz conjecture: 100 -> 50 -> 25 -> 76 -> ... -> 1, takes 25 steps + testcheck.ok("while loop Collatz(100) steps=25") + +def test_nested_loop(): + testcheck.section("Test 3: nested loop") + count: t.CInt = 0 + for i in range(5): + for j in range(5): + if i < j: + count += 1 + # 上三角: 4+3+2+1 = 10 + testcheck.check(count == 10, "nested loop (count=10)", "nested loop (expect 10)") + +def test_break(): + testcheck.section("Test 4: break") + found: t.CInt = -1 + for i in range(100): + if i * i > 50: + found = i + break + # 7*7=49<=50, 8*8=64>50 + testcheck.check(found == 8, "break (found=8)", "break (expect 8)") + +def test_continue(): + testcheck.section("Test 5: continue") + sum_val: t.CInt = 0 + for i in range(20): + if i % 3 == 0: + continue + sum_val += i + # 跳过 0,3,6,9,12,15,18, 剩余和 = sum(0..19) - sum(0,3,6,9,12,15,18) = 190 - 63 = 127 + testcheck.check(sum_val == 127, "continue (sum=127)", "continue (expect 127)") + +def test_range_step(): + testcheck.section("Test 6: range with step") + sum_val: t.CInt = 0 + for i in range(0, 20, 3): + sum_val += i + # 0+3+6+9+12+15+18 = 63 + testcheck.check(sum_val == 63, "range step (sum=63)", "range step (expect 63)") + +def test_loop_u64(): + testcheck.section("Test 7: loop with u64 counter") + total: t.CUInt64T = 0 + for i in range(100): + total += t.CUInt64T(i) + # 0+1+2+...+99 = 4950 + testcheck.check(total == 4950, "u64 loop (total=4950)", "u64 loop (expect 4950)") + +def main() -> t.CInt: + testcheck.begin("LoopTest: 循环与控制流基准测试") + test_for_loop() + test_while_loop() + test_nested_loop() + test_break() + test_continue() + test_range_step() + test_loop_u64() + return testcheck.end() diff --git a/LoopTest/project.json b/LoopTest/project.json new file mode 100644 index 0000000..ac809b0 --- /dev/null +++ b/LoopTest/project.json @@ -0,0 +1,40 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "LoopTest", + "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": "LoopTest.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 + } +} \ No newline at end of file diff --git a/MLIRLiteTest/App/main.vp b/MLIRLiteTest/App/main.vp new file mode 100644 index 0000000..862abac --- /dev/null +++ b/MLIRLiteTest/App/main.vp @@ -0,0 +1,1478 @@ +import t, c +from stdint import * +import stdio +import string +import stdlib +import w32.fileio as fileio +import memhub +import testcheck +import viperlib +import mlirlite + + +# 内存大小(MLIR 渲染期会为每个函数分配 scratch/常量表,故给足 4MB) +POOL_SIZE: t.CDefine = 4194304 + + +# 把 buf 中的 MLIR 文本落盘到 Test/MLIRLiteTest/output/,供 +# mlir-opt / mlir-translate 离线验收(测试 exe 的 cwd 是仓库根,故用相对路径)。 +# 目录必须已存在:fileio.File(MODE.W) 在目录缺失时静默失败(f.closed 保持 +# True,StubMergerCollect.vp 有同类注释记录),故此处对 f.closed 显式告警, +# 不静默吞掉失败。 +# path 缓冲取自 pool.alloc:MemPool 是无释放的 bump 分配器(memhub.vp 里 +# free 为空操作),缓冲随整个 pool 生命周期统一回收,故此处不调用 free。 +# dump 序号:name 传 None 时用于自动命名(auto_NN.mlir),便于在各测试点无参调用。 +_DUMP_SEQ: int = 0 + + +def _dump_is_module(text: str) -> int: + """判断落盘文本是否为 MLIR **模块单元**(跳过空白与 // 注释行后以 module 开头) + + 非模块文本有三类,都不该进 mlir-opt 校验集: + 1) 类型文本(如 `!llvm.func<…>`):类型不是顶层 op,实测报 + "type names with a '.' are reserved for dialect-defined names"; + 2) 值文本(如 `%0`):实测报 "expected '=' after SSA name"; + 3) 裸函数(无 module 包裹):父级不是 SymbolTable,父级内外的符号引用 + (如 llvm.call 的 callee)无法解析。 + 这类统一落 .txt,使 output/*.mlir 成为纯净的 mlir-opt 校验集。 + """ + if text is None: + return 0 + p: str = text + while p[0] != '\0': + ch: char = p[0] + if ch == ' ' or ch == '\t' or ch == '\n' or ch == '\r': + p = p + 1 + continue + if ch == '/' and p[1] == '/': + while p[0] != '\0' and p[0] != '\n': + p = p + 1 + continue + break + if p[0] == '\0': + return 0 + if string.strncmp(p, "module", 6) == 0: + return 1 + return 0 + + +def dump_mlir(pool: memhub.MemPool | t.CPtr, name: str, buf: str): + """把 buf 中的 MLIR 文本落盘到 Test/MLIRLiteTest/output/ + + name 为 None 时按调用顺序自动命名 auto_NN.mlir。 + **非模块文本自动改落 .txt**(见 _dump_is_module 的说明),避免把 + "类型文本/值文本/裸函数"混进 mlir-opt 校验集造成假失败。 + 目录必须已存在:fileio.File(MODE.W) 在目录缺失时静默失败(f.closed 保持 + True,StubMergerCollect.vp 有同类注释记录),故此处对 f.closed 显式告警, + 不静默吞掉失败。 + path/hdr 缓冲取自 pool.alloc:MemPool 是无释放的 bump 分配器(memhub.vp 里 + free 为空操作),缓冲随整个 pool 生命周期统一回收,故此处不调用 free。 + """ + global _DUMP_SEQ + _DUMP_SEQ += 1 + path: t.CChar | t.CPtr = pool.alloc(256) + if path is None: + stdio.printf("[mlir] WARN: alloc path failed\n") + return + if name is None: + viperlib.snprintf(path, 256, "Test/MLIRLiteTest/output/auto_%02d.mlir", _DUMP_SEQ) + else: + viperlib.snprintf(path, 256, "Test/MLIRLiteTest/output/%s", name) + # 非模块文本改落 .txt:类型/值文本不是顶层 op,裸函数父级非 SymbolTable, + # 三者都会被 mlir-opt 拒绝;改扩展名后 output/*.mlir 即为纯净校验集。 + if _dump_is_module(buf) == 0: + cut: sizet = string.strlen(path) + d2: sizet = cut + while d2 > 0: + d2 -= 1 + if path[d2] == '.': + path[d2] = '\0' + break + ext_txt: t.CChar | t.CPtr = pool.alloc(8) + if ext_txt is not None: + string.strcpy(ext_txt, ".txt") + tmp_path: t.CChar | t.CPtr = pool.alloc(256) + if tmp_path is not None: + # 经临时缓冲再拷回:避免 snprintf 目标与源同缓冲 + viperlib.snprintf(tmp_path, 256, "%s%s", path, ext_txt) + string.strcpy(path, tmp_path) + f: rawptr[fileio.File] = fileio.File(path, fileio.MODE.W) + if f.closed: + stdio.printf("[mlir] WARN: open failed: %s\n", path) + return + # 首行写注释标明来源(MLIR 支持 // 注释),便于与测试用例对应 + hdr: t.CChar | t.CPtr = pool.alloc(128) + if hdr is not None: + viperlib.snprintf(hdr, 128, "// dumped by MLIRLiteTest #%d\n", _DUMP_SEQ) + f.write(hdr, string.strlen(hdr)) + f.write(buf, string.strlen(buf)) + f.close() + stdio.printf(" [mlir] wrote %s (%d bytes)\n", path, int(string.strlen(buf))) + + +# ============================================================ +# 测试 1: TypePrint 类型打印(MLIR llvm 方言类型) +# ============================================================ +def test_type_print(pool: memhub.MemPool | t.CPtr): + testcheck.section("Test 1: TypePrint (MLIR types)") + core: mlirlite.LLVMTypeCore | t.CPtr = mlirlite.LLVMTypeCore(pool) + buf: t.CChar | t.CPtr = pool.alloc(256) + + # i32 + ty_i32: mlirlite.LLVMType | t.CPtr = core.Int32() + buf[0] = 0 + core.PrintType(buf, 256, ty_i32) + testcheck.check(string.strcmp(buf, "i32") == 0, + "Int32 -> i32", + "Int32 fail") + + # 不透明指针: Ptr(Int32) -> !llvm.ptr + ty_ptr: mlirlite.LLVMType | t.CPtr = core.Ptr(ty_i32) + buf[0] = 0 + core.PrintType(buf, 256, ty_ptr) + testcheck.check(string.strcmp(buf, "!llvm.ptr") == 0, + "Ptr(Int32) -> !llvm.ptr", + "Ptr fail") + + # Void -> none + ty_void: mlirlite.LLVMType | t.CPtr = core.Void() + buf[0] = 0 + core.PrintType(buf, 256, ty_void) + testcheck.check(string.strcmp(buf, "none") == 0, + "Void -> none", + "Void fail") + + # [4 x i32] -> !llvm.array<4 x i32> + ty_arr: mlirlite.LLVMType | t.CPtr = core.Array(ty_i32, 4) + buf[0] = 0 + core.PrintType(buf, 256, ty_arr) + testcheck.check(string.strcmp(buf, "!llvm.array<4 x i32>") == 0, + "Array(i32,4) -> !llvm.array<4 x i32>", + "Array fail") + + # [2 x [3 x i8]] -> !llvm.array<2 x !llvm.array<3 x i8>> + ty_i8: mlirlite.LLVMType | t.CPtr = core.Int8() + ty_inner: mlirlite.LLVMType | t.CPtr = core.Array(ty_i8, 3) + ty_nested: mlirlite.LLVMType | t.CPtr = core.Array(ty_inner, 2) + buf[0] = 0 + core.PrintType(buf, 256, ty_nested) + testcheck.check(string.strcmp(buf, "!llvm.array<2 x !llvm.array<3 x i8>>") == 0, + "nested array -> !llvm.array<2 x !llvm.array<3 x i8>>", + "nested array fail") + + # {i32, i8*} -> !llvm.struct<(i32, !llvm.ptr)> + ty_i8ptr: mlirlite.LLVMType | t.CPtr = core.Ptr(ty_i8) + n1: mlirlite.ParamNode | t.CPtr = core.NewParamNode(ty_i32) + n2: mlirlite.ParamNode | t.CPtr = core.NewParamNode(ty_i8ptr) + head: mlirlite.ParamNode | t.CPtr = core.ParamListAppend(None, None, n1) + core.ParamListAppend(head, n1, n2) + ty_struct: mlirlite.LLVMType | t.CPtr = core.Struct(head, 2) + buf[0] = 0 + core.PrintType(buf, 256, ty_struct) + testcheck.check(string.strcmp(buf, "!llvm.struct<(i32, !llvm.ptr)>") == 0, + "struct {i32, i8*} -> !llvm.struct<(i32, !llvm.ptr)>", + "struct fail") + + # 空结构体 -> !llvm.struct<()> + ty_empty: mlirlite.LLVMType | t.CPtr = core.Struct(None, 0) + buf[0] = 0 + core.PrintType(buf, 256, ty_empty) + testcheck.check(string.strcmp(buf, "!llvm.struct<()>") == 0, + "empty struct -> !llvm.struct<()>", + "empty struct fail") + + # 函数类型 i32 (i32, i8*) -> !llvm.func + fn1: mlirlite.ParamNode | t.CPtr = core.NewParamNode(ty_i32) + fn2: mlirlite.ParamNode | t.CPtr = core.NewParamNode(ty_i8ptr) + fhead: mlirlite.ParamNode | t.CPtr = core.ParamListAppend(None, None, fn1) + core.ParamListAppend(fhead, fn1, fn2) + ty_func: mlirlite.LLVMType | t.CPtr = core.Func(ty_i32, fhead, 2) + buf[0] = 0 + core.PrintType(buf, 256, ty_func) + dump_mlir(pool, "T01_types.mlir", buf) + # 把实际值写进失败报文:断言失败时 FAIL 行本身就能看到真实形态 + # (避免"只看到 fail、看不到实际值"导致来回猜) + ft_msg: t.CChar | t.CPtr = pool.alloc(512) + if ft_msg is not None: + viperlib.snprintf(ft_msg, 512, + "func type fail: actual='%s' expected='!llvm.func'", + buf) + testcheck.check(string.strcmp(buf, "!llvm.func") == 0, + "func type -> !llvm.func", + ft_msg) + + +# ============================================================ +# 测试 2: ValuePrint 值打印(MLIR,仅供诊断) +# ============================================================ +def test_value_print(pool: memhub.MemPool | t.CPtr): + testcheck.section("Test 2: ValuePrint (MLIR)") + core: mlirlite.LLVMTypeCore | t.CPtr = mlirlite.LLVMTypeCore(pool) + mcore: mlirlite.LLVMModuleCore | t.CPtr = mlirlite.LLVMModuleCore(pool) + buf: t.CChar | t.CPtr = pool.alloc(128) + + ty_i32: mlirlite.LLVMType | t.CPtr = core.Int32() + + # 常量 42 -> "42 : i32" + val42: mlirlite.Value | t.CPtr = mcore.ConstInt32(42) + buf[0] = 0 + mcore.PrintValue(buf, 128, val42) + testcheck.check(string.strcmp(buf, "42 : i32") == 0, + "ConstInt(42) -> '42 : i32'", + "ConstInt fail") + + # SSA 值 -> "%0"(MLIR 操作数不带类型) + val_ssa: mlirlite.Value | t.CPtr = mcore.SSAValue(ty_i32, "%0") + buf[0] = 0 + mcore.PrintValue(buf, 128, val_ssa) + dump_mlir(pool, "T02_value.mlir", buf) + testcheck.check(string.strcmp(buf, "%0") == 0, + "SSAValue(%0) -> '%0'", + "SSAValue fail") + + +# ============================================================ +# 测试 3: 构建 add 函数 +# llvm.func @add(%a: i32, %b: i32) -> i32 { +# %0 = llvm.add %a, %b : i32 +# llvm.return %0 : i32 +# } +# ============================================================ +def test_build_add(pool: memhub.MemPool | t.CPtr): + testcheck.section("Test 3: build_add function") + + core: mlirlite.LLVMTypeCore | t.CPtr = mlirlite.LLVMTypeCore(pool) + mcore: mlirlite.LLVMModuleCore | t.CPtr = mlirlite.LLVMModuleCore(pool) + ty_i32: mlirlite.LLVMType | t.CPtr = core.Int32() + + mod: mlirlite.LLVMModule | t.CPtr = mcore.NewModule("test_add") + func: mlirlite.Function | t.CPtr = mcore.CreateFunction(mod, "add", ty_i32) + + mcore.AddParam(func, ty_i32, "%a") + mcore.AddParam(func, ty_i32, "%b") + + entry: mlirlite.BasicBlock | t.CPtr = mcore.CreateBlock(func, "entry") + + builder: mlirlite.IRBuilder | t.CPtr = mcore.NewBuilder(func) + mlirlite.position_at_end(builder, entry) + + v_a: mlirlite.Value | t.CPtr = mcore.SSAValue(ty_i32, "%a") + v_b: mlirlite.Value | t.CPtr = mcore.SSAValue(ty_i32, "%b") + + v_c: mlirlite.Value | t.CPtr = mlirlite.build_add(builder, v_a, v_b) + mlirlite.build_ret(builder, v_c) + + buf: t.CChar | t.CPtr = pool.alloc(4096) + buf[0] = 0 + mcore.PrintFunction(buf, 4096, func) + dump_mlir(pool, None, buf) + testcheck.info(buf) + dump_mlir(pool, "T03_add.mlir", buf) + + testcheck.check(string.strstr(buf, "llvm.func @add(%a: i32, %b: i32) -> i32") is not None, + "contains 'llvm.func @add(%a: i32, %b: i32) -> i32'", + "missing MLIR function signature") + testcheck.check(string.strstr(buf, "llvm.add %a, %b : i32") is not None, + "contains 'llvm.add %a, %b : i32'", + "missing 'llvm.add'") + testcheck.check(string.strstr(buf, "llvm.return") is not None, + "contains 'llvm.return'", + "missing 'llvm.return'") + testcheck.check(string.strstr(buf, "entry:") is None, + "entry 块不带标签", + "entry block should not be labelled") + + +# ============================================================ +# 测试 4: if-else(max) +# ============================================================ +def test_build_if_else(pool: memhub.MemPool | t.CPtr): + testcheck.section("Test 4: build if-then-else (max)") + + core: mlirlite.LLVMTypeCore | t.CPtr = mlirlite.LLVMTypeCore(pool) + mcore: mlirlite.LLVMModuleCore | t.CPtr = mlirlite.LLVMModuleCore(pool) + ty_i32: mlirlite.LLVMType | t.CPtr = core.Int32() + + mod: mlirlite.LLVMModule | t.CPtr = mcore.NewModule("test_max") + func: mlirlite.Function | t.CPtr = mcore.CreateFunction(mod, "max", ty_i32) + mcore.AddParam(func, ty_i32, "%a") + mcore.AddParam(func, ty_i32, "%b") + + entry: mlirlite.BasicBlock | t.CPtr = mcore.CreateBlock(func, "entry") + then_blk: mlirlite.BasicBlock | t.CPtr = mcore.CreateBlock(func, "then") + else_blk: mlirlite.BasicBlock | t.CPtr = mcore.CreateBlock(func, "else") + + builder: mlirlite.IRBuilder | t.CPtr = mcore.NewBuilder(func) + + mlirlite.position_at_end(builder, entry) + v_a: mlirlite.Value | t.CPtr = mcore.SSAValue(ty_i32, "%a") + v_b: mlirlite.Value | t.CPtr = mcore.SSAValue(ty_i32, "%b") + v_cond: mlirlite.Value | t.CPtr = mlirlite.build_icmp(builder, mlirlite.ICMP_SGT, v_a, v_b) + mlirlite.build_cond_br(builder, v_cond, then_blk, else_blk) + + mlirlite.position_at_end(builder, then_blk) + mlirlite.build_ret(builder, v_a) + + mlirlite.position_at_end(builder, else_blk) + mlirlite.build_ret(builder, v_b) + + buf: t.CChar | t.CPtr = pool.alloc(4096) + buf[0] = 0 + mcore.PrintFunction(buf, 4096, func) + dump_mlir(pool, None, buf) + testcheck.info(buf) + dump_mlir(pool, "T04_ifelse.mlir", buf) + + testcheck.check(string.strstr(buf, "llvm.icmp \"sgt\"") is not None, + "contains 'llvm.icmp \"sgt\"'", + "missing 'llvm.icmp \"sgt\"'") + testcheck.check(string.strstr(buf, "llvm.cond_br") is not None, + "contains 'llvm.cond_br'", + "missing 'llvm.cond_br'") + testcheck.check(string.strstr(buf, "^then:") is not None, + "contains '^then:'", + "missing block label '^then:'") + testcheck.check(string.strstr(buf, "^else:") is not None, + "contains '^else:'", + "missing block label '^else:'") + + +# ============================================================ +# 测试 5: void 函数 +# ============================================================ +def test_build_void(pool: memhub.MemPool | t.CPtr): + testcheck.section("Test 5: void function") + + core: mlirlite.LLVMTypeCore | t.CPtr = mlirlite.LLVMTypeCore(pool) + mcore: mlirlite.LLVMModuleCore | t.CPtr = mlirlite.LLVMModuleCore(pool) + ty_void: mlirlite.LLVMType | t.CPtr = core.Void() + + mod: mlirlite.LLVMModule | t.CPtr = mcore.NewModule("test_void") + func: mlirlite.Function | t.CPtr = mcore.CreateFunction(mod, "noop", ty_void) + entry: mlirlite.BasicBlock | t.CPtr = mcore.CreateBlock(func, "entry") + builder: mlirlite.IRBuilder | t.CPtr = mcore.NewBuilder(func) + mlirlite.position_at_end(builder, entry) + mlirlite.build_ret_void(builder) + + buf: t.CChar | t.CPtr = pool.alloc(4096) + buf[0] = 0 + mcore.PrintFunction(buf, 4096, func) + dump_mlir(pool, None, buf) + testcheck.info(buf) + dump_mlir(pool, "T05_void.mlir", buf) + + testcheck.check(string.strstr(buf, "llvm.func @noop() {") is not None, + "contains 'llvm.func @noop() {'(void 返回省略 -> ty)", + "missing void function signature") + testcheck.check(string.strstr(buf, "llvm.return") is not None, + "contains 'llvm.return'", + "missing 'llvm.return'") + + +# ============================================================ +# 测试 6: 模块输出(module / declare vs define) +# ============================================================ +def test_module_print(pool: memhub.MemPool | t.CPtr): + testcheck.section("Test 6: ModulePrint") + + core: mlirlite.LLVMTypeCore | t.CPtr = mlirlite.LLVMTypeCore(pool) + mcore: mlirlite.LLVMModuleCore | t.CPtr = mlirlite.LLVMModuleCore(pool) + ty_i32: mlirlite.LLVMType | t.CPtr = core.Int32() + + mod: mlirlite.LLVMModule | t.CPtr = mcore.NewModule("test_module") + mlirlite.module_set_target(mod, "x86_64-pc-windows-gnu") + mlirlite.module_set_datalayout(mod, "e-m:w-p270:32:32") + + # declare: llvm.func @extern_func(%x: i32) -> i32(无体) + func_decl: mlirlite.Function | t.CPtr = mcore.CreateDeclare(mod, "extern_func", ty_i32) + mcore.AddParam(func_decl, ty_i32, "%x") + + # define: llvm.func @add(%a: i32, %b: i32) -> i32 { … } + func_add: mlirlite.Function | t.CPtr = mcore.CreateFunction(mod, "add", ty_i32) + mcore.AddParam(func_add, ty_i32, "%a") + mcore.AddParam(func_add, ty_i32, "%b") + entry1: mlirlite.BasicBlock | t.CPtr = mcore.CreateBlock(func_add, "entry") + builder1: mlirlite.IRBuilder | t.CPtr = mcore.NewBuilder(func_add) + mlirlite.position_at_end(builder1, entry1) + v_a1: mlirlite.Value | t.CPtr = mcore.SSAValue(ty_i32, "%a") + v_b1: mlirlite.Value | t.CPtr = mcore.SSAValue(ty_i32, "%b") + v_sum: mlirlite.Value | t.CPtr = mlirlite.build_add(builder1, v_a1, v_b1) + mlirlite.build_ret(builder1, v_sum) + + buf: t.CChar | t.CPtr = pool.alloc(65536) + buf[0] = 0 + mcore.PrintModule(buf, 65536, mod) + dump_mlir(pool, None, buf) + testcheck.info(buf) + dump_mlir(pool, "T06_module.mlir", buf) + + testcheck.check(string.strstr(buf, "module {") is not None, + "contains 'module {'", + "missing 'module {'") + testcheck.check(string.strstr(buf, "llvm.func @add") is not None, + "contains 'llvm.func @add'", + "missing add function") + testcheck.check(string.strstr(buf, "llvm.func @extern_func(%x: i32) -> i32") is not None, + "declare 形态 'llvm.func @extern_func(%x: i32) -> i32'", + "missing declare") + testcheck.check(string.strstr(buf, "llvm.func @extern_func(%x: i32) -> i32 {") is None, + "declare 无函数体(不出现 '{')", + "declare should not have a body") + testcheck.check(string.strstr(buf, "llvm.func @add(%a: i32, %b: i32) -> i32 {") is not None, + "define 形态带函数体", + "missing define body") + + +# ============================================================ +# 测试 7: 常量物化(操作数 42 -> llvm.mlir.constant) +# ============================================================ +def test_const_materialize(pool: memhub.MemPool | t.CPtr): + testcheck.section("Test 7: constant materialization") + + core: mlirlite.LLVMTypeCore | t.CPtr = mlirlite.LLVMTypeCore(pool) + mcore: mlirlite.LLVMModuleCore | t.CPtr = mlirlite.LLVMModuleCore(pool) + ty_i32: mlirlite.LLVMType | t.CPtr = core.Int32() + + mod: mlirlite.LLVMModule | t.CPtr = mcore.NewModule("test_const") + func: mlirlite.Function | t.CPtr = mcore.CreateFunction(mod, "const_test", ty_i32) + mcore.AddParam(func, ty_i32, "%a") + entry: mlirlite.BasicBlock | t.CPtr = mcore.CreateBlock(func, "entry") + builder: mlirlite.IRBuilder | t.CPtr = mcore.NewBuilder(func) + mlirlite.position_at_end(builder, entry) + + v_a: mlirlite.Value | t.CPtr = mcore.SSAValue(ty_i32, "%a") + v_42: mlirlite.Value | t.CPtr = mcore.ConstInt32(42) + v_sum: mlirlite.Value | t.CPtr = mlirlite.build_add(builder, v_a, v_42) + mlirlite.build_ret(builder, v_sum) + + buf: t.CChar | t.CPtr = pool.alloc(4096) + buf[0] = 0 + mcore.PrintFunction(buf, 4096, func) + dump_mlir(pool, None, buf) + testcheck.info(buf) + dump_mlir(pool, "T07_consts.mlir", buf) + + testcheck.check(string.strstr(buf, "llvm.mlir.constant(42 : i32) : i32") is not None, + "contains 'llvm.mlir.constant(42 : i32) : i32'", + "constant not materialized") + testcheck.check(string.strstr(buf, "llvm.add %a, %c0 : i32") is not None, + "add 行引用物化后的 SSA 名 '%c0'", + "add line does not reference materialized constant") + + # 同 (类型,文本) 常量只物化一次:add 的两个操作数都是 42 + func2: mlirlite.Function | t.CPtr = mcore.CreateFunction(mod, "const_twice", ty_i32) + entry2: mlirlite.BasicBlock | t.CPtr = mcore.CreateBlock(func2, "entry") + builder2: mlirlite.IRBuilder | t.CPtr = mcore.NewBuilder(func2) + mlirlite.position_at_end(builder2, entry2) + v_42b: mlirlite.Value | t.CPtr = mcore.ConstInt32(42) + v_42c: mlirlite.Value | t.CPtr = mcore.ConstInt32(42) + v_sum2: mlirlite.Value | t.CPtr = mlirlite.build_add(builder2, v_42b, v_42c) + mlirlite.build_ret(builder2, v_sum2) + buf[0] = 0 + mcore.PrintFunction(buf, 4096, func2) + testcheck.check(string.strstr(buf, "llvm.add %c0, %c0 : i32") is not None, + "相同 (类型,文本) 常量只物化一次(llvm.add %c0, %c0)", + "constant dedup failed") + + +# ============================================================ +# 测试 8: phi -> 块参数 +# ============================================================ +def test_phi_block_args(pool: memhub.MemPool | t.CPtr): + testcheck.section("Test 8: phi -> block arguments") + + core: mlirlite.LLVMTypeCore | t.CPtr = mlirlite.LLVMTypeCore(pool) + mcore: mlirlite.LLVMModuleCore | t.CPtr = mlirlite.LLVMModuleCore(pool) + ty_i32: mlirlite.LLVMType | t.CPtr = core.Int32() + + mod: mlirlite.LLVMModule | t.CPtr = mcore.NewModule("test_merge") + func: mlirlite.Function | t.CPtr = mcore.CreateFunction(mod, "merge_test", ty_i32) + entry: mlirlite.BasicBlock | t.CPtr = mcore.CreateBlock(func, "entry") + then_blk: mlirlite.BasicBlock | t.CPtr = mcore.CreateBlock(func, "then") + else_blk: mlirlite.BasicBlock | t.CPtr = mcore.CreateBlock(func, "else") + merge: mlirlite.BasicBlock | t.CPtr = mcore.CreateBlock(func, "merge") + builder: mlirlite.IRBuilder | t.CPtr = mcore.NewBuilder(func) + + # entry: br label %then + mlirlite.position_at_end(builder, entry) + mlirlite.build_br(builder, then_blk) + + # then: br label %merge + mlirlite.position_at_end(builder, then_blk) + v_1: mlirlite.Value | t.CPtr = mcore.ConstInt32(1) + mlirlite.build_br(builder, merge) + + # else: br label %merge + mlirlite.position_at_end(builder, else_blk) + v_2: mlirlite.Value | t.CPtr = mcore.ConstInt32(2) + mlirlite.build_br(builder, merge) + + # merge: %r = phi i32 [1, %then], [2, %else]; ret i32 %r + mlirlite.position_at_end(builder, merge) + inc1: mlirlite.PhiIncoming | t.CPtr = mlirlite.new_phi_incoming(pool, v_1, then_blk) + inc2: mlirlite.PhiIncoming | t.CPtr = mlirlite.new_phi_incoming(pool, v_2, else_blk) + inc1.Next = inc2 + v_r: mlirlite.Value | t.CPtr = mlirlite.build_phi(builder, ty_i32, inc1, 2) + mlirlite.build_ret(builder, v_r) + + buf: t.CChar | t.CPtr = pool.alloc(4096) + buf[0] = 0 + mcore.PrintFunction(buf, 4096, func) + dump_mlir(pool, None, buf) + testcheck.info(buf) + dump_mlir(pool, "T08_phi.mlir", buf) + + testcheck.check(string.strstr(buf, "^merge(%") is not None, + "块参数形态 '^merge(%'", + "missing block arguments") + testcheck.check(string.strstr(buf, "llvm.br ^merge(%") is not None, + "跳转实参形态 'llvm.br ^merge(%'", + "missing branch block operands") + testcheck.check(string.strstr(buf, " = phi ") is None, + "phi 行不再输出", + "phi line should not be emitted") + + +# ============================================================ +# 测试 9: 内存 / 调用 / 转换 +# ============================================================ +def test_mem_call_cast(pool: memhub.MemPool | t.CPtr): + testcheck.section("Test 9: memory / call / cast") + + core: mlirlite.LLVMTypeCore | t.CPtr = mlirlite.LLVMTypeCore(pool) + mcore: mlirlite.LLVMModuleCore | t.CPtr = mlirlite.LLVMModuleCore(pool) + ty_i32: mlirlite.LLVMType | t.CPtr = core.Int32() + ty_i64: mlirlite.LLVMType | t.CPtr = core.Int64() + ty_i8: mlirlite.LLVMType | t.CPtr = core.Int8() + ty_i8ptr: mlirlite.LLVMType | t.CPtr = core.Ptr(ty_i8) + + mod: mlirlite.LLVMModule | t.CPtr = mcore.NewModule("test_mem") + func: mlirlite.Function | t.CPtr = mcore.CreateFunction(mod, "mem_test", ty_i32) + mcore.AddParam(func, ty_i8ptr, "%s") + mcore.AddParam(func, ty_i32, "%n") + entry: mlirlite.BasicBlock | t.CPtr = mcore.CreateBlock(func, "entry") + builder: mlirlite.IRBuilder | t.CPtr = mcore.NewBuilder(func) + mlirlite.position_at_end(builder, entry) + + v_s: mlirlite.Value | t.CPtr = mcore.SSAValue(ty_i8ptr, "%s") + v_n: mlirlite.Value | t.CPtr = mcore.SSAValue(ty_i32, "%n") + + # %0 = alloca i32 ; store i32 %n, !llvm.ptr %0 ; %1 = load i32, !llvm.ptr %0 + v_slot: mlirlite.Value | t.CPtr = mlirlite.build_alloca(builder, ty_i32) + mlirlite.build_store(builder, v_n, v_slot, 0) + v_loaded: mlirlite.Value | t.CPtr = mlirlite.build_load(builder, ty_i32, v_slot, 0) + + # %2 = getelementptr i8, !llvm.ptr %s, i32 %1 + v_gep: mlirlite.Value | t.CPtr = mlirlite.build_gep(builder, ty_i8, v_s, v_loaded) + + # %3 = zext i32 %1 to i64 ; %4 = ptrtoint !llvm.ptr %s to i64 + v_zext: mlirlite.Value | t.CPtr = mlirlite.build_zext(builder, v_loaded, ty_i64) + v_p2i: mlirlite.Value | t.CPtr = mlirlite.build_ptrtoint(builder, v_s, ty_i64) + + # %5 = call i32 @callee(i32 %1) + v_call: mlirlite.Value | t.CPtr = mlirlite.build_call(builder, "callee", v_loaded, 1, ty_i32, 0) + mlirlite.build_ret(builder, v_call) + + buf: t.CChar | t.CPtr = pool.alloc(4096) + buf[0] = 0 + mcore.PrintFunction(buf, 4096, func) + dump_mlir(pool, None, buf) + testcheck.info(buf) + dump_mlir(pool, "T09_mem_call_cast.mlir", buf) + + # 整模块另存:mlir-opt 要求被调符号在模块作用域内**有声明**; + # 单函数文本不含 declare,会报 + # 'llvm.call' op 'callee' does not reference a symbol in the current scope + decl: mlirlite.Function | t.CPtr = mcore.CreateDeclare(mod, "callee", ty_i32) + mcore.AddParam(decl, ty_i32, "%x") + mbuf: t.CChar | t.CPtr = pool.alloc(65536) + if mbuf is not None: + mbuf[0] = 0 + mcore.PrintModule(mbuf, 65536, mod) + dump_mlir(pool, "T09_mem_module.mlir", mbuf) + + testcheck.check(string.strstr(buf, "llvm.alloca") is not None, + "contains 'llvm.alloca'", "missing 'llvm.alloca'") + testcheck.check(string.strstr(buf, "llvm.store %n, %") is not None, + "contains 'llvm.store'", "missing 'llvm.store'") + testcheck.check(string.strstr(buf, "llvm.load %") is not None, + "contains 'llvm.load'", "missing 'llvm.load'") + testcheck.check(string.strstr(buf, "llvm.getelementptr") is not None, + "contains 'llvm.getelementptr'", "missing 'llvm.getelementptr'") + testcheck.check(string.strstr(buf, "llvm.call @callee(") is not None, + "contains 'llvm.call @callee('", "missing 'llvm.call'") + testcheck.check(string.strstr(buf, "llvm.zext") is not None, + "contains 'llvm.zext'", "missing 'llvm.zext'") + testcheck.check(string.strstr(buf, "llvm.ptrtoint") is not None, + "contains 'llvm.ptrtoint'", "missing 'llvm.ptrtoint'") + + +# ============================================================ +# 测试 10: 全局变量(字符串常量 / 整数 / 整型数组) +# ============================================================ +def test_globals(pool: memhub.MemPool | t.CPtr): + testcheck.section("Test 10: Global Variables") + + core: mlirlite.LLVMTypeCore | t.CPtr = mlirlite.LLVMTypeCore(pool) + mcore: mlirlite.LLVMModuleCore | t.CPtr = mlirlite.LLVMModuleCore(pool) + ty_void: mlirlite.LLVMType | t.CPtr = core.Void() + ty_i8: mlirlite.LLVMType | t.CPtr = core.Int8() + + mod: mlirlite.LLVMModule | t.CPtr = mcore.NewModule("test_globals") + mlirlite.module_set_target(mod, "x86_64-pc-windows-gnu") + + # @.str = private unnamed_addr constant [6 x i8] c"hello\00" + mcore.CreateGlobalString(mod, ".str", "hello") + + # @counter = global i32 0 + mcore.CreateGlobalInt(mod, "counter", 32, 0) + + # @arr = [i8 1, i8 2] -> [1 : i8, 2 : i8](元素带类型注解;dense<...> 对 + # !llvm.array 非法——dense 只接受 builtin shaped 类型,实测 mlir-opt 22.1.8) + ty_arr2: mlirlite.LLVMType | t.CPtr = core.Array(ty_i8, 2) + gv_arr: mlirlite.GlobalVariable | t.CPtr = mcore.NewGlobal(mod, "arr", ty_arr2) + init_arr: t.CChar | t.CPtr = pool.alloc(32) + string.strcpy(init_arr, "[i8 1, i8 2]") + gv_arr.Initializer = init_arr + + func: mlirlite.Function | t.CPtr = mcore.CreateFunction(mod, "use_global", ty_void) + entry: mlirlite.BasicBlock | t.CPtr = mcore.CreateBlock(func, "entry") + builder: mlirlite.IRBuilder | t.CPtr = mcore.NewBuilder(func) + mlirlite.position_at_end(builder, entry) + mlirlite.build_ret_void(builder) + + buf: t.CChar | t.CPtr = pool.alloc(65536) + buf[0] = 0 + mcore.PrintModule(buf, 65536, mod) + dump_mlir(pool, None, buf) + testcheck.info(buf) + dump_mlir(pool, "T10_globals.mlir", buf) + + testcheck.check(string.strstr(buf, "llvm.mlir.global") is not None, + "contains 'llvm.mlir.global'", "missing 'llvm.mlir.global'") + # 符号名以 '.' 开头必须加引号(MLIR 裸名须字母/下划线开头) + # 实际形态:llvm.mlir.global … constant @".str"("hello\00") : !llvm.array<6 x i8> + testcheck.check(string.strstr(buf, "@\".str\"(") is not None, + "字符串全局名引号形态 '@\".str\"('", "missing quoted string global name") + # 字符串属性长度必须等于 i8 数组长度 ⇒ 尾随 NUL 必须保留在属性里 + # (剥掉 \00 会被 mlir-opt 拒绝;改为剥类型里的 NUL 则会丢 C 串终止符、破坏 ABI) + testcheck.check(string.strstr(buf, "hello\\00") is not None, + "字符串初值保留 NUL 'hello\\00'", "missing string initializer") + testcheck.check(string.strstr(buf, "!llvm.array<6 x i8>") is not None, + "contains '!llvm.array<6 x i8>'", "missing string global type") + testcheck.check(string.strstr(buf, "@counter(0 : i32) : i32") is not None, + "整数全局 '@counter(0 : i32) : i32'", "missing integer global") + # 数组属性:元素带类型注解(dense<...> 对 !llvm.array 非法,只接受 builtin shaped 类型) + testcheck.check(string.strstr(buf, "[1 : i8, 2 : i8]") is not None, + "整型数组初值 '[1 : i8, 2 : i8]'", "missing array initializer") + + +# ============================================================ +# 测试 11: SSA 验证(合法函数 0 错误) +# ============================================================ +def test_verify_valid(pool: memhub.MemPool | t.CPtr): + testcheck.section("Test 11: Verify valid function") + + core: mlirlite.LLVMTypeCore | t.CPtr = mlirlite.LLVMTypeCore(pool) + mcore: mlirlite.LLVMModuleCore | t.CPtr = mlirlite.LLVMModuleCore(pool) + ty_i32: mlirlite.LLVMType | t.CPtr = core.Int32() + + mod: mlirlite.LLVMModule | t.CPtr = mcore.NewModule("verify_valid") + func: mlirlite.Function | t.CPtr = mcore.CreateFunction(mod, "add", ty_i32) + mcore.AddParam(func, ty_i32, "%a") + mcore.AddParam(func, ty_i32, "%b") + entry: mlirlite.BasicBlock | t.CPtr = mcore.CreateBlock(func, "entry") + builder: mlirlite.IRBuilder | t.CPtr = mcore.NewBuilder(func) + mlirlite.position_at_end(builder, entry) + v_a: mlirlite.Value | t.CPtr = mcore.SSAValue(ty_i32, "%a") + v_b: mlirlite.Value | t.CPtr = mcore.SSAValue(ty_i32, "%b") + v_c: mlirlite.Value | t.CPtr = mlirlite.build_add(builder, v_a, v_b) + mlirlite.build_ret(builder, v_c) + + result: mlirlite.VerifyResult | t.CPtr = mcore.NewVerifyResult(4096) + err_count: t.CInt = mcore.VerifyFunction(func, result) + + # 本测试原本没有渲染步骤;为落盘验收补一次 PrintFunction(不涉及断言) + buf: t.CChar | t.CPtr = pool.alloc(4096) + buf[0] = 0 + mcore.PrintFunction(buf, 4096, func) + dump_mlir(pool, "T11_verify.mlir", buf) + + testcheck.check(err_count == 0, + "valid add function: 0 errors", + "valid function should pass verification") + testcheck.check(result.ErrorCode == mlirlite.VERIFY_OK, + "error code = VERIFY_OK", + "wrong error code for valid function") + + +# ============================================================ +# 测试 12: 结构体/vtable 全局初值 → initializer region +# +# 覆盖: ① vtable 结构体(null + bitcast 符号引用);② 指针数组 + GEP 常量表达式 +# (GEP 整体视为 addressof);③ 符号名引号口径(LLVM 口径 @"m0" 剥引号后按 MLIR +# 口径重加:m0 可裸写 → @m0;数字开头的 9m 需引号 → @"9m");④ 根级裸 +# null / zeroinitializer(属性形态 `(zeroinitializer)` 被 mlir-opt 拒绝, +# 实测 22.1.8 报 "expected attribute value")→ region + llvm.mlir.zero。 +# 断言依赖的形态(含整模块)均已用 mlir-opt 22.1.8 实测通过。 +# ============================================================ +def test_struct_global(pool: memhub.MemPool | t.CPtr): + testcheck.section("Test 12: struct/vtable global initializer (region)") + + core: mlirlite.LLVMTypeCore | t.CPtr = mlirlite.LLVMTypeCore(pool) + mcore: mlirlite.LLVMModuleCore | t.CPtr = mlirlite.LLVMModuleCore(pool) + ty_i8: mlirlite.LLVMType | t.CPtr = core.Int8() + ty_i8ptr: mlirlite.LLVMType | t.CPtr = core.Ptr(ty_i8) + + mod: mlirlite.LLVMModule | t.CPtr = mcore.NewModule("test_struct_global") + + # ---- ① vtable 结构体 { i8*, i8*, i8* } ---- + # Initializer 是 TPV 生成的 LLVM 语法聚合串:null + bitcast 符号引用 + vt1: mlirlite.ParamNode | t.CPtr = core.NewParamNode(ty_i8ptr) + vt2: mlirlite.ParamNode | t.CPtr = core.NewParamNode(ty_i8ptr) + vt3: mlirlite.ParamNode | t.CPtr = core.NewParamNode(ty_i8ptr) + vt_head: mlirlite.ParamNode | t.CPtr = core.ParamListAppend(None, None, vt1) + core.ParamListAppend(vt_head, vt1, vt2) + core.ParamListAppend(vt_head, vt2, vt3) + ty_vt: mlirlite.LLVMType | t.CPtr = core.Struct(vt_head, 3) + + gv_vt: mlirlite.GlobalVariable | t.CPtr = mcore.NewGlobal(mod, "vt", ty_vt) + init_vt: t.CChar | t.CPtr = pool.alloc(256) + string.strcpy(init_vt, + "{ i8* null, i8* bitcast (i8* (i8*)* @\"m0\" to i8*), i8* bitcast (i8* (i8*)* @m1 to i8*) }") + gv_vt.Initializer = init_vt + # IsConstant=1 + linkage 默认 external ⇒ 初值非空时**不输出** external 关键字 + mcore.GlobalSetConstant(gv_vt, 1) + # 声明被引用的方法符号,使模块自洽(mlir-opt 要求 addressof 目标可解析) + d_m0: mlirlite.Function | t.CPtr = mcore.CreateDeclare(mod, "m0", ty_i8ptr) + mcore.AddParam(d_m0, ty_i8ptr, "%self") + d_m1: mlirlite.Function | t.CPtr = mcore.CreateDeclare(mod, "m1", ty_i8ptr) + mcore.AddParam(d_m1, ty_i8ptr, "%self") + + # ---- ③ 引号重加分支: LLVM 裸名 @9m(数字开头)→ MLIR 需 @"9m" ---- + vq1: mlirlite.ParamNode | t.CPtr = core.NewParamNode(ty_i8ptr) + ty_vtq: mlirlite.LLVMType | t.CPtr = core.Struct(vq1, 1) + gv_vtq: mlirlite.GlobalVariable | t.CPtr = mcore.NewGlobal(mod, "vtq", ty_vtq) + init_vtq: t.CChar | t.CPtr = pool.alloc(128) + string.strcpy(init_vtq, "{ i8* bitcast (i8* (i8*)* @9m to i8*) }") + gv_vtq.Initializer = init_vtq + mcore.GlobalSetConstant(gv_vtq, 1) + mcore.GlobalSetLinkage(gv_vtq, "internal") + d_9m: mlirlite.Function | t.CPtr = mcore.CreateDeclare(mod, "9m", ty_i8ptr) + mcore.AddParam(d_9m, ty_i8ptr, "%self") + + # ---- ② 指针数组 + GEP 常量表达式 ---- + # @s0 = [3 x i8](供 GEP 常量表达式指向) + mcore.CreateGlobalString(mod, "s0", "ab") + ty_arr2: mlirlite.LLVMType | t.CPtr = core.Array(ty_i8ptr, 2) + gv_arr: mlirlite.GlobalVariable | t.CPtr = mcore.NewGlobal(mod, "arr", ty_arr2) + init_arr: t.CChar | t.CPtr = pool.alloc(256) + string.strcpy(init_arr, + "[i8* getelementptr inbounds ([3 x i8], [3 x i8]* @s0, i32 0, i32 0), i8* null]") + gv_arr.Initializer = init_arr + mcore.GlobalSetLinkage(gv_arr, "internal") + + # ---- ②' 根级裸 GEP(TPV `_build_string_ptr_initializer` 的指针全局形态) ---- + # 初值无类型前缀,直接是 getelementptr 常量表达式 + gv_sp: mlirlite.GlobalVariable | t.CPtr = mcore.NewGlobal(mod, "sp", ty_i8ptr) + init_sp: t.CChar | t.CPtr = pool.alloc(192) + string.strcpy(init_sp, + "getelementptr inbounds ([3 x i8], [3 x i8]* @s0, i32 0, i32 0)") + gv_sp.Initializer = init_sp + + # ---- ④ 根级裸 null / zeroinitializer 全局 ---- + # 这两类初值原先走属性路径产出 `(zeroinitializer)`,被 mlir-opt 22.1.8 拒绝 + # (实测报 "expected attribute value");现改走 region: + # `@名() : <顶层类型> { ; llvm.return }`。 + # TPV 侧真实存在这类写法(FuncGenMixin / CallGenVt / TranslatorGenMixin / + # ExprGenConst 均设 Initializer = "null" 或 "zeroinitializer")。 + gv_pn: mlirlite.GlobalVariable | t.CPtr = mcore.NewGlobal(mod, "pnull", ty_i8ptr) + init_pn: t.CChar | t.CPtr = pool.alloc(16) + string.strcpy(init_pn, "null") + gv_pn.Initializer = init_pn + + # 整型数组 + 裸 zeroinitializer:顶层类型取自 gv.Ty(此处 !llvm.array<2 x i32>) + ty_i32: mlirlite.LLVMType | t.CPtr = core.Int32() + ty_arr_i32: mlirlite.LLVMType | t.CPtr = core.Array(ty_i32, 2) + gv_za: mlirlite.GlobalVariable | t.CPtr = mcore.NewGlobal(mod, "zarr", ty_arr_i32) + init_za: t.CChar | t.CPtr = pool.alloc(24) + string.strcpy(init_za, "zeroinitializer") + gv_za.Initializer = init_za + + buf: t.CChar | t.CPtr = pool.alloc(65536) + buf[0] = 0 + mcore.PrintModule(buf, 65536, mod) + testcheck.info(buf) + dump_mlir(pool, "T12_struct_global.mlir", buf) + + # ① vtable 型: region 形态 + 顶层聚合类型;元素类型注解来自全局类型树 + testcheck.check(string.strstr(buf, "@vt() : !llvm.struct<(!llvm.ptr, !llvm.ptr, !llvm.ptr)>") is not None, + "vtable 全局 region 形态 '@vt() : !llvm.struct<(…, …, …)>'", + "missing vtable global region header") + testcheck.check(string.strstr(buf, "llvm.mlir.undef : !llvm.struct<(!llvm.ptr, !llvm.ptr, !llvm.ptr)>") is not None, + "含 'llvm.mlir.undef'(insertvalue 链起点)", + "missing llvm.mlir.undef") + # LLVM 口径 @"m0" 剥引号后按 MLIR 口径裸写 @m0(m0 是合法 MLIR 裸名) + testcheck.check(string.strstr(buf, "llvm.mlir.addressof @m0 : !llvm.ptr") is not None, + "bitcast 中的 @\"m0\" → 'llvm.mlir.addressof @m0 : !llvm.ptr'", + "missing addressof for m0") + testcheck.check(string.strstr(buf, "llvm.mlir.addressof @m1 : !llvm.ptr") is not None, + "bitcast 中的 @m1 → 'llvm.mlir.addressof @m1 : !llvm.ptr'", + "missing addressof for m1") + testcheck.check(string.strstr(buf, "i8* null") is None, + "LLVM 语法初值串不再出现(i8* null 已转 llvm.mlir.zero)", + "raw LLVM initializer text leaked") + testcheck.check(string.strstr(buf, "llvm.insertvalue") is not None, + "含 'llvm.insertvalue'", + "missing llvm.insertvalue") + testcheck.check(string.strstr(buf, "llvm.return") is not None, + "含 'llvm.return'", + "missing llvm.return") + testcheck.check(string.strstr(buf, "external") is None, + "external + 有初值 ⇒ 不输出 linkage 关键字", + "unexpected 'external' keyword") + # ③ 数字开头的符号名需引号(_ll_name_needs_quote 判据) + testcheck.check(string.strstr(buf, "llvm.mlir.addressof @\"9m\" : !llvm.ptr") is not None, + "数字开头符号名重加引号 'llvm.mlir.addressof @\"9m\" : !llvm.ptr'", + "missing quoted addressof for 9m") + + # ② 指针数组 + GEP: GEP 常量表达式 → addressof;数组全局类型 + 下标路径 + testcheck.check(string.strstr(buf, "@arr() : !llvm.array<2 x !llvm.ptr>") is not None, + "数组全局 region 形态 '@arr() : !llvm.array<2 x !llvm.ptr>'", + "missing array global region header") + testcheck.check(string.strstr(buf, "llvm.mlir.addressof @s0 : !llvm.ptr") is not None, + "GEP 常量表达式 → 'llvm.mlir.addressof @s0 : !llvm.ptr'", + "missing addressof for s0") + testcheck.check(string.strstr(buf, "%undef[0] : !llvm.array<2 x !llvm.ptr>") is not None, + "下标 0 形态 '%undef[0] : !llvm.array<2 x !llvm.ptr>'", + "missing index [0] insertvalue") + testcheck.check(string.strstr(buf, "[1] : !llvm.array<2 x !llvm.ptr>") is not None, + "下标 1 形态 '[1] : !llvm.array<2 x !llvm.ptr>'", + "missing index [1] insertvalue") + + # ②' 根级裸 GEP(无类型前缀): 顶层叶子 region,无 undef/insertvalue + testcheck.check(string.strstr(buf, "@sp() : !llvm.ptr") is not None, + "根级裸 GEP → '@sp() : !llvm.ptr'(顶层叶子 region)", + "missing root bare-GEP global") + + # ④ 根级裸 null(指针全局): region 形态,属性括号为空,顶层类型取自 gv.Ty + testcheck.check(string.strstr(buf, "@pnull() : !llvm.ptr") is not None, + "根级裸 null → '@pnull() : !llvm.ptr'(region 形态)", + "missing bare-null pointer global region header") + testcheck.check(string.strstr(buf, "llvm.mlir.zero : !llvm.ptr") is not None, + "根级裸 null → 'llvm.mlir.zero : !llvm.ptr'", + "missing llvm.mlir.zero for bare-null global") + testcheck.check(string.strstr(buf, "llvm.return") is not None, + "region 内含 'llvm.return'", + "missing llvm.return in region") + + # ④' 裸 zeroinitializer(整型数组): region 形态,zero 的类型即顶层类型 + testcheck.check(string.strstr(buf, "@zarr() : !llvm.array<2 x i32>") is not None, + "裸 zeroinitializer → '@zarr() : !llvm.array<2 x i32>'(region 形态)", + "missing zeroinitializer array global region header") + testcheck.check(string.strstr(buf, "llvm.mlir.zero : !llvm.array<2 x i32>") is not None, + "裸 zeroinitializer → 'llvm.mlir.zero : !llvm.array<2 x i32>'", + "missing llvm.mlir.zero for zeroinitializer array global") + + # 两类都不得再落到属性形态(mlir-opt 22.1.8 报 "expected attribute value") + testcheck.check(string.strstr(buf, "(zeroinitializer)") is None, + "属性形态 '(zeroinitializer)' 不再出现", + "rejected attribute form '(zeroinitializer)' leaked") + + +# ============================================================ +# 测试 13: alloca 对齐 / switch / inline_asm(v1 三项缺口的补齐) +# +# 三项的 MLIR 形态均由 mlir-opt 22.1.8 实测确定(候选与 exit 码见 +# includes/mlirlite/__function.vp 中 _MlirAlloca / _MlirSwitch / _MlirAsm 的注释): +# ① alloca 对齐 → `{alignment = 16 : i64}` +# (`align(16)`、`, align 16`、`{alignment = 16 : i32}` 均实测被拒) +# ② switch → `llvm.switch %v : i32, ^default [0: ^case0, …]` +# (设计规范里的 `llvm.switch %v, ^default […] : i32` 实测被拒:expected ':') +# 目标块带 phi 时追加块实参(与 br/cond_br 同一设施) +# ③ inline_asm → `llvm.inline_asm has_side_effects [asm_dialect = intel] "…", "…" %x : (i32) -> i32` +# (LLVM 的裸 `inteldialect` 与 `"…"(%x)` 词法均实测被拒) +# ============================================================ +def test_alloca_align_switch_asm(pool: memhub.MemPool | t.CPtr): + testcheck.section("Test 13: alloca align / switch / inline_asm") + + core: mlirlite.LLVMTypeCore | t.CPtr = mlirlite.LLVMTypeCore(pool) + mcore: mlirlite.LLVMModuleCore | t.CPtr = mlirlite.LLVMModuleCore(pool) + ty_i32: mlirlite.LLVMType | t.CPtr = core.Int32() + ty_void: mlirlite.LLVMType | t.CPtr = core.Void() + + mod: mlirlite.LLVMModule | t.CPtr = mcore.NewModule("test_align_switch_asm") + + # ---- ① alloca 对齐 + ③ inline_asm(builder 形态 + TPV 注入形态)---- + f1: mlirlite.Function | t.CPtr = mcore.CreateFunction(mod, "align_asm", ty_i32) + mcore.AddParam(f1, ty_i32, "%x") + e1: mlirlite.BasicBlock | t.CPtr = mcore.CreateBlock(f1, "entry") + b1: mlirlite.IRBuilder | t.CPtr = mcore.NewBuilder(f1) + mlirlite.position_at_end(b1, e1) + + # %0 = alloca i32, align 16 + v_slot: mlirlite.Value | t.CPtr = mlirlite.build_alloca_aligned(b1, ty_i32, 16) + + # call none asm sideeffect "nop", ""()(无返回值形态) + mlirlite.build_inline_asm(b1, ty_void, "nop", "", 1) + + # %1 = call i32 asm sideeffect "mov $0, $1", "=r,r"()(有返回值形态) + v_asm: mlirlite.Value | t.CPtr = mlirlite.build_inline_asm(b1, ty_i32, "mov $0, $1", "=r,r", 1) + + v_x: mlirlite.Value | t.CPtr = mcore.SSAValue(ty_i32, "%x") + mlirlite.build_store(b1, v_x, v_slot, 0) + + # TPV CallGenCBuiltin 的注入形态(inteldialect + 带类型的输入操作数) + mlirlite.block_append_text(pool, e1, + "%7 = call i32 asm sideeffect inteldialect \"mov $0, $1\", \"=r,r\"(i32 %x)") + + mlirlite.build_ret(b1, v_asm) + + # ---- ② switch:3 case + default(不带 phi)---- + f2: mlirlite.Function | t.CPtr = mcore.CreateFunction(mod, "sw", ty_i32) + mcore.AddParam(f2, ty_i32, "%v") + e2: mlirlite.BasicBlock | t.CPtr = mcore.CreateBlock(f2, "entry") + c0: mlirlite.BasicBlock | t.CPtr = mcore.CreateBlock(f2, "case0") + c1: mlirlite.BasicBlock | t.CPtr = mcore.CreateBlock(f2, "case1") + c2: mlirlite.BasicBlock | t.CPtr = mcore.CreateBlock(f2, "case2") + dflt: mlirlite.BasicBlock | t.CPtr = mcore.CreateBlock(f2, "default") + b2: mlirlite.IRBuilder | t.CPtr = mcore.NewBuilder(f2) + + mlirlite.position_at_end(b2, e2) + v_v: mlirlite.Value | t.CPtr = mcore.SSAValue(ty_i32, "%v") + sc0: mlirlite.SwitchCase | t.CPtr = mlirlite.new_switch_case(pool, mcore.ConstInt32(0), c0) + sc1: mlirlite.SwitchCase | t.CPtr = mlirlite.new_switch_case(pool, mcore.ConstInt32(1), c1) + sc2: mlirlite.SwitchCase | t.CPtr = mlirlite.new_switch_case(pool, mcore.ConstInt32(2), c2) + sc0.Next = sc1 + sc1.Next = sc2 + mlirlite.build_switch(b2, v_v, dflt, sc0, 3) + + mlirlite.position_at_end(b2, c0) + mlirlite.build_ret(b2, v_v) + mlirlite.position_at_end(b2, c1) + mlirlite.build_ret(b2, v_v) + mlirlite.position_at_end(b2, c2) + mlirlite.build_ret(b2, v_v) + mlirlite.position_at_end(b2, dflt) + mlirlite.build_ret(b2, v_v) + + # ---- ②' switch:case 与 default 目标块带 phi ⇒ 块实参 ---- + f3: mlirlite.Function | t.CPtr = mcore.CreateFunction(mod, "sw_phi", ty_i32) + mcore.AddParam(f3, ty_i32, "%v") + e3: mlirlite.BasicBlock | t.CPtr = mcore.CreateBlock(f3, "entry") + sk: mlirlite.BasicBlock | t.CPtr = mcore.CreateBlock(f3, "scase") + sd: mlirlite.BasicBlock | t.CPtr = mcore.CreateBlock(f3, "sdef") + b3: mlirlite.IRBuilder | t.CPtr = mcore.NewBuilder(f3) + + mlirlite.position_at_end(b3, e3) + v_v3: mlirlite.Value | t.CPtr = mcore.SSAValue(ty_i32, "%v") + skc: mlirlite.SwitchCase | t.CPtr = mlirlite.new_switch_case(pool, mcore.ConstInt32(0), sk) + mlirlite.build_switch(b3, v_v3, sd, skc, 1) + + # scase: %p0 = phi i32 [1, %entry]; ret i32 %p0 + mlirlite.position_at_end(b3, sk) + in1: mlirlite.PhiIncoming | t.CPtr = mlirlite.new_phi_incoming(pool, mcore.ConstInt32(1), e3) + v_p0: mlirlite.Value | t.CPtr = mlirlite.build_phi(b3, ty_i32, in1, 1) + mlirlite.build_ret(b3, v_p0) + + # sdef: %p1 = phi i32 [2, %entry]; ret i32 %p1 + mlirlite.position_at_end(b3, sd) + in2: mlirlite.PhiIncoming | t.CPtr = mlirlite.new_phi_incoming(pool, mcore.ConstInt32(2), e3) + v_p1: mlirlite.Value | t.CPtr = mlirlite.build_phi(b3, ty_i32, in2, 1) + mlirlite.build_ret(b3, v_p1) + + buf: t.CChar | t.CPtr = pool.alloc(65536) + buf[0] = 0 + mcore.PrintModule(buf, 65536, mod) + testcheck.info(buf) + dump_mlir(pool, "T13_align_switch_asm.mlir", buf) + + # ① alloca 对齐:实测形态 `{alignment = 16 : i64}`(LLVM 词法的 `, align 16` 不再出现) + testcheck.check(string.strstr(buf, "llvm.alloca %c0 x i32 {alignment = 16 : i64} : (i32) -> !llvm.ptr") is not None, + "alloca 对齐 'llvm.alloca %c0 x i32 {alignment = 16 : i64} : (i32) -> !llvm.ptr'", + "missing alloca alignment attribute") + testcheck.check(string.strstr(buf, ", align 16") is None, + "LLVM 词法 ', align 16' 不再出现(已转写为属性)", + "raw LLVM alloca align leaked") + + # ② switch:值类型紧随值(`%v : i32,`)+ 各 case/default 标签 + testcheck.check(string.strstr(buf, "llvm.switch %v : i32, ^default [0: ^case0, 1: ^case1, 2: ^case2]") is not None, + "switch 实测形态 'llvm.switch %v : i32, ^default [0: ^case0, 1: ^case1, 2: ^case2]'", + "missing llvm.switch") + testcheck.check(string.strstr(buf, "^case0") is not None, + "contains '^case0'", "missing '^case0'") + testcheck.check(string.strstr(buf, "^case1") is not None, + "contains '^case1'", "missing '^case1'") + testcheck.check(string.strstr(buf, "^case2") is not None, + "contains '^case2'", "missing '^case2'") + + # ②' switch 目标块带 phi ⇒ 块实参(default 与 case 各自携带) + testcheck.check(string.strstr(buf, "llvm.switch %v : i32, ^sdef(%c1 : i32) [0: ^scase(%c0 : i32)]") is not None, + "switch 块实参 'llvm.switch %v : i32, ^sdef(%c1 : i32) [0: ^scase(%c0 : i32)]'", + "missing switch block operands") + # 块参数的具体 SSA 名由 SSA 重编号决定(本用例实际是 %0/%1), + # 故只断言"目标块标签带参数"的形状,不绑定具体编号,避免脆断言。 + testcheck.check(string.strstr(buf, "^scase(%") is not None, + "case 目标块带参数 '^scase(%…: i32):'", + "missing block argument for switch case target") + testcheck.check(string.strstr(buf, "^sdef(%") is not None, + "default 目标块带参数 '^sdef(%…: i32):'", + "missing block argument for switch default target") + + # ③ inline_asm:无返回值 / 有返回值 / inteldialect → asm_dialect = intel + testcheck.check(string.strstr(buf, "llvm.inline_asm has_side_effects \"nop\", \"\" : () -> ()") is not None, + "无返回值形态 'llvm.inline_asm has_side_effects \"nop\", \"\" : () -> ()'", + "missing void inline_asm") + testcheck.check(string.strstr(buf, "llvm.inline_asm has_side_effects \"mov $0, $1\", \"=r,r\" : () -> i32") is not None, + "有返回值形态 '… \"=r,r\" : () -> i32'", + "missing returning inline_asm") + testcheck.check(string.strstr(buf, "asm_dialect = intel") is not None, + "LLVM 的 inteldialect → 'asm_dialect = intel'", + "missing asm_dialect for inteldialect") + testcheck.check(string.strstr(buf, "asm_dialect = intel \"mov $0, $1\", \"=r,r\" %x : (i32) -> i32") is not None, + "注入形态操作数不带括号 'asm_dialect = intel \"…\", \"…\" %x : (i32) -> i32'", + "missing operand form of inline_asm") + testcheck.check(string.strstr(buf, "inteldialect") is None, + "LLVM 词法关键字 'inteldialect' 不再出现", + "raw LLVM inteldialect keyword leaked") + + +# ============================================================ +# 测试 14: 变参函数 / 变参调用 / va_arg / cmpxchg / 全局属性字典(P0 缺口补齐) +# +# 五项 MLIR 形态均由 mlir-opt 22.1.8 实测 exit 0 确立(候选与 exit 码见 +# includes/mlirlite/__function.vp 的 _MlirFuncSig / _MlirCall / _MlirVaArg / +# _MlirCmpXchg 与 __module.vp 的 _MlirGlobalLine 注释): +# ① 变参函数声明 → `llvm.func @printf(%p: !llvm.ptr, ...) -> i32` +# ② 变参调用 → `… vararg(!llvm.func) : (!llvm.ptr, i32) -> i32` +# (vararg 内是**被调函数的完整 MLIR 函数类型**,含 `...`) +# ③ va_arg → `%N = "llvm.va_arg"(%ap) : (!llvm.ptr) -> i32`(generic 形态,刻意选择) +# ④ cmpxchg → 单结果 `llvm.cmpxchg` + 两条 `llvm.extractvalue`([0]=旧值、[1]=i1 成功位) +# ⑤ 全局属性字典 → `…("ab\00") {section = "data", alignment = 16 : i64} : !llvm.array<3 x i8>` +# (字典必须在**类型之前**;`unnamed_addr` 是**关键字**,不能进字典) +# ============================================================ +def test_vararg_vaarg_cmpxchg(pool: memhub.MemPool | t.CPtr): + testcheck.section("Test 14: vararg / va_arg / cmpxchg / global attrs") + + core: mlirlite.LLVMTypeCore | t.CPtr = mlirlite.LLVMTypeCore(pool) + mcore: mlirlite.LLVMModuleCore | t.CPtr = mlirlite.LLVMModuleCore(pool) + ty_i32: mlirlite.LLVMType | t.CPtr = core.Int32() + ty_i8: mlirlite.LLVMType | t.CPtr = core.Int8() + ty_i32ptr: mlirlite.LLVMType | t.CPtr = core.Ptr(ty_i32) + + mod: mlirlite.LLVMModule | t.CPtr = mcore.NewModule("test_vararg_vaarg_cmpxchg") + + # ---- ① 变参函数声明: llvm.func @printf(%p: !llvm.ptr, ...) -> i32 ---- + f_printf: mlirlite.Function | t.CPtr = mcore.CreateDeclare(mod, "printf", ty_i32) + mcore.AddParam(f_printf, ty_i32ptr, "%p") + f_printf.IsVarArg = 1 + + # ---- ③ va_arg: %0 = "llvm.va_arg"(%ap) : (!llvm.ptr) -> i32 ---- + f_va: mlirlite.Function | t.CPtr = mcore.CreateFunction(mod, "va_reader", ty_i32) + mcore.AddParam(f_va, ty_i32ptr, "%ap") + e_va: mlirlite.BasicBlock | t.CPtr = mcore.CreateBlock(f_va, "entry") + b_va: mlirlite.IRBuilder | t.CPtr = mcore.NewBuilder(f_va) + mlirlite.position_at_end(b_va, e_va) + v_ap: mlirlite.Value | t.CPtr = mcore.SSAValue(ty_i32ptr, "%ap") + v_arg: mlirlite.Value | t.CPtr = mlirlite.build_va_arg(b_va, v_ap, ty_i32) + mlirlite.build_ret(b_va, v_arg) + + # ---- ② 变参调用 + ④ cmpxchg(builder 的**单结果**形态)---- + f_cc: mlirlite.Function | t.CPtr = mcore.CreateFunction(mod, "vcall_cmpx", ty_i32) + mcore.AddParam(f_cc, ty_i32ptr, "%p") + mcore.AddParam(f_cc, ty_i32, "%n") + e_cc: mlirlite.BasicBlock | t.CPtr = mcore.CreateBlock(f_cc, "entry") + b_cc: mlirlite.IRBuilder | t.CPtr = mcore.NewBuilder(f_cc) + mlirlite.position_at_end(b_cc, e_cc) + v_p: mlirlite.Value | t.CPtr = mcore.SSAValue(ty_i32ptr, "%p") + v_n: mlirlite.Value | t.CPtr = mcore.SSAValue(ty_i32, "%n") + + # %0 = cmpxchg !llvm.ptr %p, i32 %n, i32 %n acq_rel monotonic + # → %0 = llvm.cmpxchg … + 两条 extractvalue;`%0` 绑定到 [0](旧值) + v_old: mlirlite.Value | t.CPtr = mlirlite.build_cmpxchg(b_cc, v_p, v_n, v_n, + mlirlite.ATOMIC_ORDER_ACQ_REL, + mlirlite.ATOMIC_ORDER_MONOTONIC) + # %1 = call i32 (i8*, i32, ...) @printf(i8* %p, i32 %n) + # → %1 = llvm.call @printf(%p, %n) vararg(!llvm.func) + # : (!llvm.ptr, i32) -> i32 + mlirlite.value_set_next(v_p, v_n) + v_call: mlirlite.Value | t.CPtr = mlirlite.build_call(b_cc, "printf", v_p, 2, ty_i32, 1) + # ret 用 cmpxchg 结果 ⇒ 断言别名绑定生效(文本里应是 %_0_v = extractvalue[0]) + mlirlite.build_ret(b_cc, v_old) + + # ---- ④' cmpxchg 双结果前缀 `%a, %b = cmpxchg …`(两名字各绑一条 extractvalue)---- + f_cc2: mlirlite.Function | t.CPtr = mcore.CreateFunction(mod, "cmpx2", ty_i32) + mcore.AddParam(f_cc2, ty_i32ptr, "%p") + mcore.AddParam(f_cc2, ty_i32, "%n") + e_cc2: mlirlite.BasicBlock | t.CPtr = mcore.CreateBlock(f_cc2, "entry") + mlirlite.block_append_text(pool, e_cc2, + "%a, %b = cmpxchg !llvm.ptr %p, i32 %n, i32 %n acq_rel monotonic") + # %b = 成功位 [1];%a = 旧值 [0] + mlirlite.block_append_text(pool, e_cc2, "%r = zext i1 %b to i32") + mlirlite.block_append_text(pool, e_cc2, "ret i32 %a") + + # ---- ⑤ 全局属性字典:section/alignment 在**类型之前**;unnamed_addr 作关键字 ---- + ty_arr3: mlirlite.LLVMType | t.CPtr = core.Array(ty_i8, 3) + init_s: t.CChar | t.CPtr = pool.alloc(32) + string.strcpy(init_s, "c\"ab\\00\"") + + gv_s: mlirlite.GlobalVariable | t.CPtr = mcore.NewGlobal(mod, "s", ty_arr3) + gv_s.Initializer = init_s + mlirlite.global_set_linkage(gv_s, "internal") + mlirlite.global_set_constant(gv_s, 1) + mlirlite.global_set_section(gv_s, "data") + gv_s.Align = 16 + + gv_t: mlirlite.GlobalVariable | t.CPtr = mcore.NewGlobal(mod, "t", ty_arr3) + gv_t.Initializer = init_s + mlirlite.global_set_linkage(gv_t, "internal") + mlirlite.global_set_constant(gv_t, 1) + mlirlite.global_set_unnamed_addr(gv_t, 1) + + buf: t.CChar | t.CPtr = pool.alloc(65536) + buf[0] = 0 + mcore.PrintModule(buf, 65536, mod) + testcheck.info(buf) + dump_mlir(pool, "T14_vararg_vaarg_cmpxchg.mlir", buf) + + # ① 变参函数声明:参数表尾 `...` + testcheck.check(string.strstr(buf, "llvm.func @printf(%p: !llvm.ptr, ...) -> i32") is not None, + "变参声明 'llvm.func @printf(%p: !llvm.ptr, ...) -> i32'", + "missing vararg function declaration") + testcheck.check(string.strstr(buf, ", ...) -> i32") is not None, + "参数表尾 '..., ...)' 形态(', ...)')", + "missing vararg ellipsis in declaration") + + # ② 变参调用:vararg(完整 MLIR 函数类型) + testcheck.check(string.strstr(buf, "vararg(!llvm.func<") is not None, + "变参调用 'vararg(!llvm.func<'", "missing vararg(...) attribute") + testcheck.check(string.strstr(buf, + "vararg(!llvm.func) : (!llvm.ptr, i32) -> i32") is not None, + "vararg 完整函数类型 'vararg(!llvm.func) : (!llvm.ptr, i32) -> i32'", + "missing vararg function type") + + # ③ va_arg:generic 形态(刻意选择,不透明指针下自定义汇编无法表达) + testcheck.check(string.strstr(buf, "\"llvm.va_arg\"(") is not None, + "va_arg generic 形态 '\"llvm.va_arg\"('", "missing generic llvm.va_arg") + testcheck.check(string.strstr(buf, ") : (!llvm.ptr) -> i32") is not None, + "va_arg 类型串 ') : (!llvm.ptr) -> i32'", "missing va_arg type list") + + # ④ cmpxchg:单结果 + 两条 extractvalue([0]=旧值、[1]=i1 成功位) + testcheck.check(string.strstr(buf, "llvm.cmpxchg") is not None, + "contains 'llvm.cmpxchg'", "missing llvm.cmpxchg") + testcheck.check(string.strstr(buf, "llvm.extractvalue ") is not None, + "contains 'llvm.extractvalue '", "missing llvm.extractvalue") + testcheck.check(string.strstr(buf, "[0] : !llvm.struct<(i32, i1)>") is not None, + "旧值抽取 '[0] : !llvm.struct<(i32, i1)>'", "missing extractvalue [0]") + testcheck.check(string.strstr(buf, "[1] : !llvm.struct<(i32, i1)>") is not None, + "成功位抽取 '[1] : !llvm.struct<(i32, i1)>'", "missing extractvalue [1]") + # extractvalue 结果名由 struct 结果名**确定性派生**(不再用计数器 ⇒ 两遍必然同名) + # `%0` → `%_0_v`(旧值 [0])/ `%_0_ok`(成功位 [1]);`%a` → `%_a_v`/`%_a_ok` + # (`_` 前缀是必需的:MLIR 裸 SSA 名首字符须为字母或 `_`,`%0_v` 被 mlir-opt 拒绝) + testcheck.check(string.strstr(buf, "%_0_v = llvm.extractvalue %0[0] : !llvm.struct<(i32, i1)>") is not None, + "旧值定义 '%_0_v = llvm.extractvalue %0[0] …'", + "cmpxchg single result not deterministically named") + testcheck.check(string.strstr(buf, "%_0_ok = llvm.extractvalue %0[1] : !llvm.struct<(i32, i1)>") is not None, + "成功位定义 '%_0_ok = llvm.extractvalue %0[1] …'", + "cmpxchg ok bit not deterministically named") + testcheck.check(string.strstr(buf, "%_a_v = llvm.extractvalue %a[0] : !llvm.struct<(i32, i1)>") is not None, + "双结果首名定义 '%_a_v = llvm.extractvalue %a[0] …'", + "cmpxchg double-result old value not deterministically named") + testcheck.check(string.strstr(buf, "%_a_ok = llvm.extractvalue %a[1] : !llvm.struct<(i32, i1)>") is not None, + "双结果次名定义 '%_a_ok = llvm.extractvalue %a[1] …'", + "cmpxchg double-result ok bit not deterministically named") + # 引用侧:别名把 %0 / %a / %b 改写成上述确定性新名(定义与引用同名 ⇒ 不悬空) + testcheck.check(string.strstr(buf, "llvm.return %_0_v : i32") is not None, + "单结果引用改写 'llvm.return %_0_v : i32'", + "cmpxchg result not bound to old value") + testcheck.check(string.strstr(buf, "llvm.zext %_a_ok : i1 to i32") is not None, + "双结果次名引用改写 'llvm.zext %_a_ok : i1 to i32'", + "cmpxchg second name not bound to success bit") + testcheck.check(string.strstr(buf, "llvm.return %_a_v : i32") is not None, + "双结果首名引用改写 'llvm.return %_a_v : i32'", + "cmpxchg first name not bound to old value") + + # ⑤ 属性字典在**类型之前**(整串断言);unnamed_addr 作关键字、不进字典 + testcheck.check(string.strstr(buf, + "(\"ab\\00\") {section = \"data\", alignment = 16 : i64} : !llvm.array<3 x i8>") is not None, + "属性字典在类型之前 '(\"ab\\00\") {section = \"data\", alignment = 16 : i64} : !llvm.array<3 x i8>'", + "global attribute dict not before type") + testcheck.check(string.strstr(buf, "!llvm.array<3 x i8> {section") is None, + "字典不在类型之后('!llvm.array<3 x i8> {section' 不出现)", + "global attribute dict leaked after type") + testcheck.check(string.strstr(buf, "unnamed_addr constant @t(") is not None, + "unnamed_addr 作关键字 'unnamed_addr constant @t('", + "missing unnamed_addr keyword") + testcheck.check(string.strstr(buf, "{unnamed_addr") is None, + "unnamed_addr 不进属性字典('{unnamed_addr' 不出现)", + "unnamed_addr leaked into attribute dict") + + +# ============================================================ +# 测试 15: 具名结构体(%"name" = type {…}) +# +# TPV 侧对每个类都调 module_add_named_type 登记具名结构体(llvmlite 由此输出 +# `%"sha1.Cls" = type {…}` 定义行)。MLIR(llvm 方言) **没有**独立类型定义语法, +# 也**不允许无体前向声明**(实测 mlir-opt 22.1.8:`!llvm.struct<"x">` 报 +# "struct without a body only allowed in a recursive struct"),故: +# ① 定义行**整体丢弃**(NamedTypeHead 只作模型保留 + 打印期查表); +# ② 按值使用处内联为 !llvm.struct<"名字", (字段…)>(名字直接作字符串字面量, +# 含数字/`.`/`[`/`]` 均不额外转义);嵌套具名同理递归; +# ③ 指向具名结构体的指针仍是 !llvm.ptr(不透明指针,既有路径不变); +# ④ 中间文本里"只有名字"的形态 `%"name"` 由打印期登记表回查完整定义后展开 +# 为 ②(查不到 / 仍是 opaque ⇒ 响亮报错,绝不静默输出空体错误布局)。 +# 本用例的期望整模块已用 mlir-opt / mlir-translate 22.1.8 实测 exit 0, +# 降级(--mlir-to-llvmir)可得 MLIR 自动生成的定义行: +# %aa11bb22cc33dd44.Cls = type { i32, ptr } +# ============================================================ +def test_named_struct(pool: memhub.MemPool | t.CPtr): + testcheck.section("Test 15: named struct type") + + core: mlirlite.LLVMTypeCore | t.CPtr = mlirlite.LLVMTypeCore(pool) + mcore: mlirlite.LLVMModuleCore | t.CPtr = mlirlite.LLVMModuleCore(pool) + ty_i32: mlirlite.LLVMType | t.CPtr = core.Int32() + ty_i8: mlirlite.LLVMType | t.CPtr = core.Int8() + ty_i8ptr: mlirlite.LLVMType | t.CPtr = core.Ptr(ty_i8) + + # 具名结构体 %"aa11bb22cc33dd44.Cls" = type { i32, i8* }(sha1 风格前缀 + '.') + ns1: mlirlite.ParamNode | t.CPtr = core.NewParamNode(ty_i32) + ns2: mlirlite.ParamNode | t.CPtr = core.NewParamNode(ty_i8ptr) + ns_head: mlirlite.ParamNode | t.CPtr = core.ParamListAppend(None, None, ns1) + core.ParamListAppend(ns_head, ns1, ns2) + ty_named: mlirlite.LLVMType | t.CPtr = core.Struct(ns_head, 2, "aa11bb22cc33dd44.Cls") + ty_named_ptr: mlirlite.LLVMType | t.CPtr = core.Ptr(ty_named) + + # packed 具名结构体 %"aa11bb22cc33dd44.Packed" = type <{ i32, i8 }> + # MLIR 侧(实测 mlir-opt / mlir-translate 22.1.8): + # !llvm.struct<"aa11bb22cc33dd44.Packed", packed (i32, i8)> → 降级 type <{ i32, i8 }> + pk1: mlirlite.ParamNode | t.CPtr = core.NewParamNode(ty_i32) + pk2: mlirlite.ParamNode | t.CPtr = core.NewParamNode(ty_i8) + pk_head: mlirlite.ParamNode | t.CPtr = core.ParamListAppend(None, None, pk1) + core.ParamListAppend(pk_head, pk1, pk2) + ty_packed: mlirlite.LLVMType | t.CPtr = core.Struct(pk_head, 2, "aa11bb22cc33dd44.Packed") + + # ---- 类型文本:按值 = 内联具名形态;指针 = 不透明 !llvm.ptr ---- + tbuf: t.CChar | t.CPtr = pool.alloc(256) + tbuf[0] = 0 + core.PrintType(tbuf, 256, ty_named) + testcheck.check(string.strstr(tbuf, "!llvm.struct<\"aa11bb22cc33dd44.Cls\", (i32, !llvm.ptr)>") is not None, + "具名结构体按值形态 '!llvm.struct<\"aa11bb22cc33dd44.Cls\", (i32, !llvm.ptr)>'", + "named struct by-value form missing") + # 名字里的 '.' / 数字开头不需要额外转义或引号(实测 mlir-opt 22.1.8) + testcheck.check(string.strstr(tbuf, "<\"aa11bb22cc33dd44.Cls\",") is not None, + "名字直接作字符串字面量(不额外转义)", + "named struct name literal form missing") + tbuf[0] = 0 + core.PrintType(tbuf, 256, ty_named_ptr) + testcheck.check(string.strcmp(tbuf, "!llvm.ptr") == 0, + "Ptr(具名结构体) -> '!llvm.ptr'(不透明指针,不回退为指针类型)", + "named struct pointer must stay opaque !llvm.ptr") + + mod: mlirlite.LLVMModule | t.CPtr = mcore.NewModule("test_named_struct") + # 真实流程:具名结构体经 module_add_named_type 登记(打印期查表用) + mlirlite.module_add_named_type(mod, pool, ty_named) + # packed 标记唯一设置点(须在 add_named_type 之后设;打印期由登记表携带) + mlirlite.module_add_named_type(mod, pool, ty_packed) + mlirlite.module_set_named_type_packed(mod, pool, ty_packed, 1) + + # ---- ① 按值全局(类型使用处内联具名体)+ ② 指向它的指针全局 ---- + gv_v: mlirlite.GlobalVariable | t.CPtr = mcore.NewGlobal(mod, "g_cls", ty_named) + gv_p: mlirlite.GlobalVariable | t.CPtr = mcore.NewGlobal(mod, "g_cls_p", ty_named_ptr) + # ③ packed 按值全局 + gv_pk: mlirlite.GlobalVariable | t.CPtr = mcore.NewGlobal(mod, "g_packed", ty_packed) + + # ---- ① 按值形参 + ② 指针形参 ---- + fn: mlirlite.Function | t.CPtr = mcore.CreateFunction(mod, "use_named", ty_i32) + mcore.AddParam(fn, ty_named, "%v") + mcore.AddParam(fn, ty_named_ptr, "%p") + entry: mlirlite.BasicBlock | t.CPtr = mcore.CreateBlock(fn, "entry") + b: mlirlite.IRBuilder | t.CPtr = mcore.NewBuilder(fn) + mlirlite.position_at_end(b, entry) + + # ---- ④ 中间文本里的"只有名字"形态(手工 / TPV 注入)---- + # 打印期由登记表回查完整定义展开;指针形态 %"name"* 仍走 !llvm.ptr + mlirlite.block_append_text(pool, entry, "%0 = alloca %\"aa11bb22cc33dd44.Cls\"") + mlirlite.block_append_text(pool, entry, "%1 = load i32, %\"aa11bb22cc33dd44.Cls\"* %0") + # ⑤ packed 具名结构体的文本形态(同一登记表槽位带 packed 标记) + mlirlite.block_append_text(pool, entry, "%2 = alloca %\"aa11bb22cc33dd44.Packed\"") + v_1: mlirlite.Value | t.CPtr = mcore.SSAValue(ty_i32, "%1") + mlirlite.build_ret(b, v_1) + + # ---- ⑥ 按值 packed 形参:独立声明函数,不改动 use_named 的既有断言 ---- + fn_pk: mlirlite.Function | t.CPtr = mcore.CreateDeclare(mod, "use_packed", ty_i32) + mcore.AddParam(fn_pk, ty_packed, "%pk") + + buf: t.CChar | t.CPtr = pool.alloc(65536) + buf[0] = 0 + mcore.PrintModule(buf, 65536, mod) + testcheck.info(buf) + dump_mlir(pool, "T15_named_struct.mlir", buf) + + # ① 按值形参 / 全局:使用处内联具名体 + testcheck.check(string.strstr(buf, "llvm.func @use_named(%v: !llvm.struct<\"aa11bb22cc33dd44.Cls\", (i32, !llvm.ptr)>, %p: !llvm.ptr) -> i32") is not None, + "按值形参 'llvm.func @use_named(%v: !llvm.struct<\"aa11bb22cc33dd44.Cls\", (i32, !llvm.ptr)>, %p: !llvm.ptr) -> i32'", + "missing inline named struct parameter") + testcheck.check(string.strstr(buf, "@g_cls() : !llvm.struct<\"aa11bb22cc33dd44.Cls\", (i32, !llvm.ptr)>") is not None, + "按值全局 '@g_cls() : !llvm.struct<\"aa11bb22cc33dd44.Cls\", (i32, !llvm.ptr)>'", + "missing inline named struct global") + # ② 指针:仍是不透明 !llvm.ptr + testcheck.check(string.strstr(buf, "@g_cls_p() : !llvm.ptr") is not None, + "指针全局 '@g_cls_p() : !llvm.ptr'", + "named struct pointer global must be !llvm.ptr") + testcheck.check(string.strstr(buf, "!llvm.struct<\"aa11bb22cc33dd44.Cls\", (i32, !llvm.ptr)>*") is None, + "不得出现指向具名结构体的指针类型(MLIR 不透明指针)", + "pointer-to-named-struct type leaked") + + # ④ 文本形态 %"name" 展开(alloca 元素类型 / load 的指针类型);定义行不输出 + testcheck.check(string.strstr(buf, "%0 = llvm.alloca %c0 x !llvm.struct<\"aa11bb22cc33dd44.Cls\", (i32, !llvm.ptr)> : (i32) -> !llvm.ptr") is not None, + "文本 %\"name\" 展开为内联具名体(alloca 元素类型)", + "named struct type text not expanded in alloca") + testcheck.check(string.strstr(buf, "%1 = llvm.load %0 : !llvm.ptr -> i32") is not None, + "文本 %\"name\"* 仍为不透明指针('%1 = llvm.load %0 : !llvm.ptr -> i32')", + "named struct pointer text not collapsed to !llvm.ptr") + testcheck.check(string.strstr(buf, "%\"aa11bb22cc33dd44.Cls\"") is None, + "LLVM 口径的 %\"name\" 形态不再出现(已全部转写)", + "raw LLVM named type text leaked") + # ③ 定义行整体丢弃:MLIR 无独立类型定义语法(由 mlir-translate 在使用处自动生成) + testcheck.check(string.strstr(buf, "\"aa11bb22cc33dd44.Cls\" = type") is None, + "模块不输出 '\"name\" = type {…}' 定义行", + "named type definition line should be dropped") + + # ⑦ packed 具名结构体:登记表携带 NamedTypeNode.IsPacked,按值形态加 'packed ' 关键字 + testcheck.check(string.strstr(buf, "@g_packed() : !llvm.struct<\"aa11bb22cc33dd44.Packed\", packed (i32, i8)>") is not None, + "packed 按值全局 '@g_packed() : !llvm.struct<\"aa11bb22cc33dd44.Packed\", packed (i32, i8)>'", + "missing packed inline named struct global") + testcheck.check(string.strstr(buf, "llvm.func @use_packed(%pk: !llvm.struct<\"aa11bb22cc33dd44.Packed\", packed (i32, i8)>) -> i32") is not None, + "packed 按值形参 'llvm.func @use_packed(%pk: !llvm.struct<\"aa11bb22cc33dd44.Packed\", packed (i32, i8)>) -> i32'", + "missing packed inline named struct parameter") + testcheck.check(string.strstr(buf, "x !llvm.struct<\"aa11bb22cc33dd44.Packed\", packed (i32, i8)> : (i32) -> !llvm.ptr") is not None, + "文本 %\"name\" 展开为 packed 内联具名体(alloca 元素类型)", + "packed named struct type text not expanded with packed") + # 负向:非 packed 的具名结构体类型串里不得出现 packed + testcheck.check(string.strstr(buf, "!llvm.struct<\"aa11bb22cc33dd44.Cls\", packed") is None, + "非 packed 具名结构体类型串不含 'packed'", + "packed keyword leaked into non-packed named struct") + # 负向:packed 具名结构体不得漏掉 packed 关键字(按值渲染为无 packed 形态) + testcheck.check(string.strstr(buf, "!llvm.struct<\"aa11bb22cc33dd44.Packed\", (i32, i8)>") is None, + "packed 具名结构体不得渲染为无 packed 的形态", + "packed named struct rendered without packed keyword") + + +# ============================================================ +# 测试 16: extractvalue(多结果内联汇编的结果抽取) +# +# 依据真实语料(Test/DefaultArgTest/output/*.ll 等 4163 份 TPV 产物): +# %asm_result = call {i32, i32} asm inteldialect "rdrand $1", "=r,=r,~{cc}"() +# %asm_out_0 = extractvalue {i32, i32} %asm_result, 0 +# %asm_out_1 = extractvalue {i32, i32} %asm_result, 1 +# 即"多结果内联汇编"是 extractvalue 的唯一来源(另有 {i64, i64} / +# {i32, i32, i32, i32} / {i64, i32, i64, i32} 等多字段结构体结果)。 +# +# MLIR 形态(mlir-opt / mlir-translate 22.1.8 实测 exit 0): +# ① 多结果内联汇编 = **单结果 + 结构体类型**: +# %0 = llvm.inline_asm has_side_effects "…", "=r,r" : () -> !llvm.struct<(i32, i32)> +# ② extractvalue 的索引列表写在 `[]` 内、逗号分隔(LLVM 词法的 `<聚合>, i0, i1` +# 被拒绝): +# %a = llvm.extractvalue %0[0] : !llvm.struct<(i32, i32)> +# ③ 多级索引合法(`%v[1, 0]` 于嵌套结构体,实测 exit 0) +# 降级(--mlir-to-llvmir)可得: +# %1 = call { i32, i32 } asm sideeffect "…", "=r,r"() +# %2 = extractvalue { i32, i32 } %1, 0 +# %3 = extractvalue { i32, i32 } %1, 1 +# ============================================================ +def test_extractvalue_multi_asm(pool: memhub.MemPool | t.CPtr): + testcheck.section("Test 16: extractvalue (multi-result inline asm)") + + core: mlirlite.LLVMTypeCore | t.CPtr = mlirlite.LLVMTypeCore(pool) + mcore: mlirlite.LLVMModuleCore | t.CPtr = mlirlite.LLVMModuleCore(pool) + ty_i32: mlirlite.LLVMType | t.CPtr = core.Int32() + + mod: mlirlite.LLVMModule | t.CPtr = mcore.NewModule("test_extractvalue_multi_asm") + func: mlirlite.Function | t.CPtr = mcore.CreateFunction(mod, "multi_asm", ty_i32) + entry: mlirlite.BasicBlock | t.CPtr = mcore.CreateBlock(func, "entry") + + # ① TPV 真实形态:多结果内联汇编 + 两条 extractvalue(单索引) + mlirlite.block_append_text(pool, entry, + "%2 = call {i32, i32} asm sideeffect \"mov $0, $1; mov $1, $1\", \"=r,r\"()") + mlirlite.block_append_text(pool, entry, + "%a = extractvalue {i32, i32} %2, 0") + mlirlite.block_append_text(pool, entry, + "%b = extractvalue {i32, i32} %2, 1") + # ② 多级索引(嵌套结构体结果的 [1, 0],mlir-opt 22.1.8 实测合法) + mlirlite.block_append_text(pool, entry, + "%3 = call {i32, {i32, i32}} asm sideeffect \"mov $0, $1\", \"=r,r\"()") + mlirlite.block_append_text(pool, entry, + "%d = extractvalue {i32, {i32, i32}} %3, 1, 0") + # 引用 %a(保证 extractvalue 结果被真实使用) + mlirlite.block_append_text(pool, entry, "ret i32 %a") + + buf: t.CChar | t.CPtr = pool.alloc(65536) + buf[0] = 0 + mcore.PrintModule(buf, 65536, mod) + testcheck.info(buf) + dump_mlir(pool, "T16_extractvalue.mlir", buf) + + # ① 多结果内联汇编 → 单结果结构体类型 + testcheck.check(string.strstr(buf, ": () -> !llvm.struct<(i32, i32)>") is not None, + "多结果内联汇编 '… : () -> !llvm.struct<(i32, i32)>'", + "multi-result inline_asm struct result missing") + testcheck.check(string.strstr(buf, "llvm.inline_asm has_side_effects") is not None, + "contains 'llvm.inline_asm has_side_effects'", + "missing llvm.inline_asm") + # ② extractvalue:索引在 `[]` 内、聚合类型为 MLIR 形态 + testcheck.check(string.strstr(buf, "llvm.extractvalue ") is not None, + "contains 'llvm.extractvalue '", "missing llvm.extractvalue") + testcheck.check(string.strstr(buf, "[0] : !llvm.struct<(i32, i32)>") is not None, + "字段 0 抽取 '[0] : !llvm.struct<(i32, i32)>'", + "missing extractvalue [0]") + testcheck.check(string.strstr(buf, "[1] : !llvm.struct<(i32, i32)>") is not None, + "字段 1 抽取 '[1] : !llvm.struct<(i32, i32)>'", + "missing extractvalue [1]") + testcheck.check(string.strstr(buf, ": !llvm.struct<(i32, i32)>") is not None, + "聚合类型为 MLIR 结构体 ': !llvm.struct<(i32, i32)>'", + "aggregate type not rendered as MLIR struct") + # ③ 多级索引:`[1, 0]`(MLIR 内逗号分隔,实测合法) + testcheck.check(string.strstr(buf, "[1, 0] : !llvm.struct<(i32, !llvm.struct<(i32, i32)>)>") is not None, + "多级索引 '[1, 0] : !llvm.struct<(i32, !llvm.struct<(i32, i32)>)>'", + "multi-level extractvalue index missing") + # 负向:LLVM 词法的 `<聚合类型> <值>, <索引>` 不再出现(类型文本必须已转写) + testcheck.check(string.strstr(buf, "{i32, i32} %") is None, + "LLVM 词法聚合类型文本不再出现('{i32, i32} %' 不出现)", + "raw LLVM aggregate type text leaked") + # 引用侧:extractvalue 结果名原样被 return 引用 + testcheck.check(string.strstr(buf, "llvm.return %a : i32") is not None, + "extractvalue 结果被引用 'llvm.return %a : i32'", + "extractvalue result not referenced") + + +def main() -> int: + testcheck.begin("MLIRLiteTest: mlirlite 库(MLIR llvm 方言文本生成)") + + # 初始化 mpool + pool_mem: bytes = stdlib.malloc(POOL_SIZE) + if pool_mem is None: + stdio.printf("FAIL: malloc for pool failed\n") + return 1 + pool: memhub.MemPool | t.CPtr = memhub.MemPool(pool_mem, POOL_SIZE) + if pool is None: + stdio.printf("FAIL: memhub.MemPool init failed\n") + return 1 + + test_type_print(pool) + test_value_print(pool) + test_build_add(pool) + test_build_if_else(pool) + test_build_void(pool) + test_module_print(pool) + test_const_materialize(pool) + test_phi_block_args(pool) + test_mem_call_cast(pool) + test_globals(pool) + test_verify_valid(pool) + test_struct_global(pool) + test_alloca_align_switch_asm(pool) + test_vararg_vaarg_cmpxchg(pool) + test_named_struct(pool) + test_extractvalue_multi_asm(pool) + + return testcheck.end() diff --git a/MLIRLiteTest/project.json b/MLIRLiteTest/project.json new file mode 100644 index 0000000..b738460 --- /dev/null +++ b/MLIRLiteTest/project.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "MLIRLiteTest", + "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": "MLIRLiteTest.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 + } +} diff --git a/MemhubTest/App/main.vp b/MemhubTest/App/main.vp new file mode 100644 index 0000000..8ea0fe9 --- /dev/null +++ b/MemhubTest/App/main.vp @@ -0,0 +1,97 @@ +from stdint import * +import t, c +import stdio +import stdlib +import testcheck +import memhub + + +# 多态测试: 通过 MemManager 基类指针调用, 验证 vtable 分派到正确子类 +def test_polymorphic(mgr: memhub.MemManager | t.CPtr, size: t.CSizeT) -> t.CInt: + p: t.CPtr = mgr.alloc(size) + if p is None: + return 0 + mgr.free(p) + return 1 + + +# 测试 calloc 多态: calloc 是 MemManager 具体方法, 内部调 self.alloc (虚函数) +def test_calloc_polymorphic(mgr: memhub.MemManager | t.CPtr) -> t.CInt: + p: t.CPtr = mgr.calloc(4, 8) + if p is None: + return 0 + # 验证清零: 读第一个字节应为 0 + first_byte: t.CUInt8T = t.CUInt8T(c.Deref(t.CUInt64T(p, t.CPtr))) + if first_byte != 0: + return 0 + return 1 + + +@t.CExport +def main() -> int: + testcheck.begin("MemhubTest: polymorphic memory manager") + + arena1: bytes = stdlib.malloc(65536) + arena2: bytes = stdlib.malloc(65536) + arena3: bytes = stdlib.malloc(65536) + + # ========== MemPool (bump) ========== + testcheck.section("MemPool (bump)") + pool: memhub.MemPool = memhub.MemPool(arena1, 65536) + p1: t.CPtr = pool.alloc(100) + testcheck.check(p1 is not None, "MemPool alloc 100", "FAIL") + p2: t.CPtr = pool.alloc(200) + testcheck.check(p2 is not None, "MemPool alloc 200", "FAIL") + testcheck.check(t.CUInt64T(p1) != t.CUInt64T(p2), "MemPool different ptrs", "FAIL") + pool.reset() + p3: t.CPtr = pool.alloc(100) + testcheck.check(p3 is not None, "MemPool alloc after reset", "FAIL") + testcheck.check(t.CUInt64T(p3) == t.CUInt64T(p1), "MemPool reset reuses addr", "FAIL") + + # ========== MemSlab (fixed block) ========== + testcheck.section("MemSlab (fixed block)") + slab: memhub.MemSlab = memhub.MemSlab(arena2, 65536, 64) + s1: t.CPtr = slab.alloc(32) + testcheck.check(s1 is not None, "MemSlab alloc 32", "FAIL") + s2: t.CPtr = slab.alloc(64) + testcheck.check(s2 is not None, "MemSlab alloc 64", "FAIL") + s3: t.CPtr = slab.alloc(128) + testcheck.check(s3 is None, "MemSlab alloc > block_size fails", "FAIL") + slab.free(s1) + s4: t.CPtr = slab.alloc(32) + testcheck.check(s4 is not None, "MemSlab alloc after free", "FAIL") + testcheck.check(t.CUInt64T(s4) == t.CUInt64T(s1), "MemSlab free reuse addr", "FAIL") + + # ========== MemBuddy (buddy system) ========== + testcheck.section("MemBuddy (buddy system)") + buddy: memhub.MemBuddy = memhub.MemBuddy(arena3, 65536) + b1: t.CPtr = buddy.alloc(100) + testcheck.check(b1 is not None, "MemBuddy alloc 100", "FAIL") + b2: t.CPtr = buddy.alloc(200) + testcheck.check(b2 is not None, "MemBuddy alloc 200", "FAIL") + buddy.free(b1) + b3: t.CPtr = buddy.alloc(100) + testcheck.check(b3 is not None, "MemBuddy alloc after free", "FAIL") + # realloc 增长 + b4: t.CPtr = buddy.realloc(b2, 400) + testcheck.check(b4 is not None, "MemBuddy realloc 200->400", "FAIL") + + # ========== 多态分派 (核心测试) ========== + testcheck.section("polymorphic dispatch") + r1: t.CInt = test_polymorphic(pool, 50) + testcheck.check(r1 == 1, "vtable: MemPool.alloc/free via MemManager", "FAIL") + r2: t.CInt = test_polymorphic(slab, 32) + testcheck.check(r2 == 1, "vtable: MemSlab.alloc/free via MemManager", "FAIL") + r3: t.CInt = test_polymorphic(buddy, 50) + testcheck.check(r3 == 1, "vtable: MemBuddy.alloc/free via MemManager", "FAIL") + + # calloc 多态 (具体方法调虚函数) + rc1: t.CInt = test_calloc_polymorphic(pool) + testcheck.check(rc1 == 1, "vtable: calloc dispatches MemPool.alloc", "FAIL") + rc2: t.CInt = test_calloc_polymorphic(buddy) + testcheck.check(rc2 == 1, "vtable: calloc dispatches MemBuddy.alloc", "FAIL") + + stdlib.free(arena1) + stdlib.free(arena2) + stdlib.free(arena3) + return 0 diff --git a/MemhubTest/project.json b/MemhubTest/project.json new file mode 100644 index 0000000..b3357a2 --- /dev/null +++ b/MemhubTest/project.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "MemhubTest", + "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": "MemhubTest.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 + } +} diff --git a/MpoolOopTest/App/main.vp b/MpoolOopTest/App/main.vp new file mode 100644 index 0000000..4d9dbd7 --- /dev/null +++ b/MpoolOopTest/App/main.vp @@ -0,0 +1,11 @@ +import t, c +import testcheck +import mpooltest + + +def main() -> t.CInt | t.CExport: + testcheck.begin("MpoolOopTest: MemPool OOP 测试") + testcheck.section("MPool OOP") + mpooltest.mpool_main() + testcheck.ok("MPool OOP 测试完成") + return testcheck.end() diff --git a/MpoolOopTest/App/mpooltest.vp b/MpoolOopTest/App/mpooltest.vp new file mode 100644 index 0000000..90012b8 --- /dev/null +++ b/MpoolOopTest/App/mpooltest.vp @@ -0,0 +1,91 @@ +import t, c +from t import CInt, CPtr, CChar +import viperlib +import viperio +import stdlib +import memhub + + +def mpool_main() -> CInt: + buf: bytes = stdlib.malloc(256) + + arena: bytes = stdlib.malloc(4096) + with memhub.MemPool(arena, 4096) as pool: + p1: bytes = pool.alloc(32) + p2: bytes = pool.alloc(64) + p3: bytes = pool.alloc(128) + if p1 != None and p2 != None and p3 != None: + viperlib.snprintf(buf, 256, "MPool bump: 3 allocs OK") + print(buf) + else: + viperlib.snprintf(buf, 256, "MPool bump: alloc FAILED") + print(buf) + + pool.reset() + p4: bytes = pool.alloc(256) + if p4 != None: + viperlib.snprintf(buf, 256, "MPool bump: reset+alloc OK") + print(buf) + else: + viperlib.snprintf(buf, 256, "MPool bump: reset+alloc FAILED") + print(buf) + + stdlib.free(arena) + + arena2: bytes = stdlib.malloc(4096) + with memhub.MemSlab(arena2, 4096, 64) as spool: + b1: bytes = spool.alloc(64) + b2: bytes = spool.alloc(64) + b3: bytes = spool.alloc(64) + if b1 != None and b2 != None and b3 != None: + viperlib.snprintf(buf, 256, "MPool slab: 3 allocs OK") + print(buf) + else: + viperlib.snprintf(buf, 256, "MPool slab: alloc FAILED") + print(buf) + + spool.free(b2) + b4: bytes = spool.alloc(64) + if b4 != None: + viperlib.snprintf(buf, 256, "MPool slab: free+realloc OK") + print(buf) + else: + viperlib.snprintf(buf, 256, "MPool slab: free+realloc FAILED") + print(buf) + + stdlib.free(arena2) + + arena3: bytes = stdlib.malloc(4096) + hpool: memhub.MemPool | CPtr = memhub.MemPool(arena3, 4096) + h1: bytes = hpool.alloc(32) + h2: bytes = hpool.alloc(64) + if h1 != None and h2 != None: + viperlib.snprintf(buf, 256, "MPool manual: 2 allocs OK") + print(buf) + else: + viperlib.snprintf(buf, 256, "MPool manual: alloc FAILED") + print(buf) + hpool.reset() + h3: bytes = hpool.alloc(128) + if h3 != None: + viperlib.snprintf(buf, 256, "MPool manual: reset+alloc OK") + print(buf) + else: + viperlib.snprintf(buf, 256, "MPool manual: reset+alloc FAILED") + print(buf) + + stdlib.free(arena3) + + arena4: bytes = stdlib.malloc(4096) + with memhub.MemPool(arena4, 4096) as bpool: + wb: viperio.Buf | CPtr = bpool.alloc_buf(128) + if wb.data != None: + viperlib.snprintf(wb.cstr(), 128, "MPool alloc_buf: hello from Buf!") + print(wb.cstr()) + else: + viperlib.snprintf(buf, 256, "MPool alloc_buf: FAILED") + print(buf) + + stdlib.free(arena4) + stdlib.free(buf) + return 0 diff --git a/MpoolOopTest/project.json b/MpoolOopTest/project.json new file mode 100644 index 0000000..4004fe8 --- /dev/null +++ b/MpoolOopTest/project.json @@ -0,0 +1,40 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "MpoolOopTest", + "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": "MpoolOopTest.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 + } +} \ No newline at end of file diff --git a/MultiInheritTest/App/main.vp b/MultiInheritTest/App/main.vp new file mode 100644 index 0000000..88f1897 --- /dev/null +++ b/MultiInheritTest/App/main.vp @@ -0,0 +1,199 @@ +from stdint import * +import w32.win32console +import t, c +from t import CInt, CPtr, CChar, CInt32T, CFloat64T, CExport, State +import viperlib +import stdlib +import testcheck + + +# === 1. 多继承字段合并 === + +class A: + a: CInt + + def __init__(self, a: CInt): + self.a = a + + def get_a(self) -> CInt: + return self.a + + +class B: + b: CInt + + def __init__(self, b: CInt): + self.b = b + + def get_b(self) -> CInt: + return self.b + + +# 多继承:C(A, B),字段展平 a+b+c,布局 [a, b, c] +class C(A, B): + c: CInt + + def __init__(self, a: CInt, b: CInt, cc: CInt): + self.a = a + self.b = b + self.c = cc + + def get_c(self) -> CInt: + return self.c + + +# === 2. 菱形去重 + 最左优先 === + +class Base: + shared: CInt + + def who(self) -> CInt: + return 1 + + def base_method(self) -> CInt: + return 100 + + +class Left(Base): + def who(self) -> CInt: + return 2 + + +class Right(Base): + def who(self) -> CInt: + return 3 + + +# 菱形:Diamond(Left, Right),Left/Right 共享 Base, +# Base.shared 字段只展平一次,who() 用 Left(先声明优先) +class Diamond(Left, Right): + def __init__(self, s: CInt): + self.shared = s + + +# === 3. 虚方法多继承 vtable === + +@t.CVTable +class ShapeM: + def area(self) -> CFloat64T: + return 0.0 + + +@t.CVTable +class ColorM: + color: CInt + + def __init__(self, color: CInt): + self.color = color + + def color_code(self) -> CInt: + return self.color + + +@t.CVTable +class ColoredCircle(ShapeM, ColorM): + r: CFloat64T + + def __init__(self, r: CFloat64T, color: CInt): + self.color = color + self.r = r + + def area(self) -> CFloat64T: + return 3.14159265 * self.r * self.r + + +# === 4. 运算符重载 + 方法继承链(MRO) === + +class Vec2M: + x: CFloat64T + y: CFloat64T + + def __new__() -> 'Vec2M' | CPtr: + return stdlib.malloc(16) + + def __init__(self, x: CFloat64T, y: CFloat64T): + self.x = x + self.y = y + + def __add__(self, b: 'Vec2M' | CPtr) -> 'Vec2M' | CPtr: + return Vec2M(self.x + b.x, self.y + b.y) + + +class Vec2Extra: + # 注意:方法体字段访问基于"定义类字段"(TPV 模型), + # 不引用 Vec2M 的 x/y(跨父类字段引用是更深层语义,暂不验证)。 + def extra_val(self) -> CInt: + return 7 + + +# 多继承:__add__ 继承自 Vec2M(运算符重载 MRO 链), +# extra_val 继承自 Vec2Extra(方法查找 MRO 链) +class Vec2Both(Vec2M, Vec2Extra): + def __new__() -> 'Vec2Both' | CPtr: + return stdlib.malloc(16) + + def __init__(self, x: CFloat64T, y: CFloat64T): + self.x = x + self.y = y + + +def main() -> CInt | CExport: + w32.win32console.SetConsoleCP(65001) + w32.win32console.SetConsoleOutputCP(65001) + + testcheck.begin("MultiInheritTest: 多继承专项测试") + + buf: CChar | CPtr = CPtr(stdlib.malloc(256)) + + # === 1. 字段合并 + 属性访问 + 方法调用 === + testcheck.section("多继承字段合并") + obj_c = C(1, 2, 3) + viperlib.snprintf(buf, 256, "C: a=%d b=%d c=%d", obj_c.a, obj_c.b, obj_c.c) + print(buf) + testcheck.check(obj_c.a == 1, "C.a 合并 OK", "C.a 合并 FAILED") + testcheck.check(obj_c.b == 2, "C.b 合并 OK", "C.b 合并 FAILED") + testcheck.check(obj_c.c == 3, "C.c 自身 OK", "C.c 自身 FAILED") + testcheck.check(obj_c.get_a() == 1, "C.get_a 继承 OK", "C.get_a 继承 FAILED") + testcheck.check(obj_c.get_b() == 2, "C.get_b 继承 OK", "C.get_b 继承 FAILED") + testcheck.check(obj_c.get_c() == 3, "C.get_c 自身 OK", "C.get_c 自身 FAILED") + testcheck.ok("字段合并测试完成") + + # === 2. 菱形去重 + 最左优先 === + testcheck.section("菱形去重 + 最左优先") + dm = Diamond(5) + viperlib.snprintf(buf, 256, "Diamond: shared=%d who=%d base=%d", dm.shared, dm.who(), dm.base_method()) + print(buf) + testcheck.check(dm.shared == 5, "Diamond.shared 菱形去重 OK", "Diamond.shared 菱形去重 FAILED") + testcheck.check(dm.who() == 2, "who() 最左优先(Left) OK", "who() 最左优先 FAILED") + testcheck.check(dm.base_method() == 100, "Base 方法继承 OK", "Base 方法继承 FAILED") + testcheck.ok("菱形去重测试完成") + + # === 3. 虚方法多继承 vtable === + testcheck.section("虚方法多继承 vtable") + cc = ColoredCircle(3.0, 7) + area: CFloat64T = cc.area() + viperlib.snprintf(buf, 256, "ColoredCircle: r=%.1f color=%d area=%.2f code=%d", + cc.r, cc.color, area, cc.color_code()) + print(buf) + testcheck.check(cc.color == 7, "ColorM.color 字段 OK", "ColorM.color 字段 FAILED") + testcheck.check(cc.color_code() == 7, "color_code 虚方法分派 OK", "color_code 虚方法分派 FAILED") + testcheck.check(area > 28.0 and area < 28.5, "area 虚方法覆盖 OK", "area 虚方法覆盖 FAILED") + testcheck.ok("虚方法多继承测试完成") + + # === 4. 运算符重载 + 方法继承链 === + testcheck.section("运算符重载 + 方法继承链") + v1 = Vec2Both(3.0, 4.0) + v2 = Vec2Both(1.0, 2.0) + v3 = v1 + v2 + viperlib.snprintf(buf, 256, "Vec2Both add: (%.1f, %.1f)", v3.x, v3.y) + print(buf) + testcheck.check(v3.x == 4.0, "Vec2Both __add__ 继承 OK", "Vec2Both __add__ 继承 FAILED") + testcheck.check(v3.y == 6.0, "Vec2Both __add__ y OK", "Vec2Both __add__ y FAILED") + lsq: CInt = v1.extra_val() + viperlib.snprintf(buf, 256, "Vec2Both extra_val: %d", lsq) + print(buf) + testcheck.check(lsq == 7, "extra_val 继承(Vec2Extra) OK", "extra_val 继承(Vec2Extra) FAILED") + testcheck.ok("运算符重载继承链测试完成") + + stdlib.free(buf) + return testcheck.end() diff --git a/MultiInheritTest/project.json b/MultiInheritTest/project.json new file mode 100644 index 0000000..169d3d3 --- /dev/null +++ b/MultiInheritTest/project.json @@ -0,0 +1,40 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "MultiInheritTest", + "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": "MultiInheritTest.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 + } +} \ No newline at end of file diff --git a/NegativeTest/App/cases/call_float_to_int.vp b/NegativeTest/App/cases/call_float_to_int.vp new file mode 100644 index 0000000..05f6650 --- /dev/null +++ b/NegativeTest/App/cases/call_float_to_int.vp @@ -0,0 +1,7 @@ +import t, c + +def g(x: int) -> int: + return x + +def main() -> int: + return g(1.5) diff --git a/NegativeTest/App/cases/call_too_few.vp b/NegativeTest/App/cases/call_too_few.vp new file mode 100644 index 0000000..dd0e72b --- /dev/null +++ b/NegativeTest/App/cases/call_too_few.vp @@ -0,0 +1,7 @@ +import t, c + +def f(a: int, b: int) -> int: + return a + b + +def main() -> int: + return f(1) diff --git a/NegativeTest/App/cases/call_too_many.vp b/NegativeTest/App/cases/call_too_many.vp new file mode 100644 index 0000000..16436ca --- /dev/null +++ b/NegativeTest/App/cases/call_too_many.vp @@ -0,0 +1,7 @@ +import t, c + +def f(a: int, b: int) -> int: + return a + b + +def main() -> int: + return f(1, 2, 3) diff --git a/NegativeTest/App/cases/call_wrong_type.vp b/NegativeTest/App/cases/call_wrong_type.vp new file mode 100644 index 0000000..7ab4c1c --- /dev/null +++ b/NegativeTest/App/cases/call_wrong_type.vp @@ -0,0 +1,7 @@ +import t, c + +def f(a: int, b: int) -> int: + return a + b + +def main() -> int: + return f("x", 2) diff --git a/NegativeTest/App/cases/import_missing_module.vp b/NegativeTest/App/cases/import_missing_module.vp new file mode 100644 index 0000000..52828ca --- /dev/null +++ b/NegativeTest/App/cases/import_missing_module.vp @@ -0,0 +1,5 @@ +import t, c +import lib.core.Handles.HandlesStruct as HandlesStruct + +def main() -> int: + return 0 diff --git a/NegativeTest/App/cases/import_stale_path.vp b/NegativeTest/App/cases/import_stale_path.vp new file mode 100644 index 0000000..5715cd7 --- /dev/null +++ b/NegativeTest/App/cases/import_stale_path.vp @@ -0,0 +1,6 @@ +import t, c +# f8bca62 移动前的旧路径(文件在 lib/Stub/StubMerger/ 下) +import lib.Stub.StubMergerStore as StubMergerStore + +def main() -> int: + return 0 diff --git a/NegativeTest/App/cases/import_wrong_path.vp b/NegativeTest/App/cases/import_wrong_path.vp new file mode 100644 index 0000000..0c53a7a --- /dev/null +++ b/NegativeTest/App/cases/import_wrong_path.vp @@ -0,0 +1,5 @@ +import t, c +import lib.NopeModule as NopeModule + +def main() -> int: + return 0 diff --git a/NegativeTest/App/cases/missing_return.vp b/NegativeTest/App/cases/missing_return.vp new file mode 100644 index 0000000..becd10d --- /dev/null +++ b/NegativeTest/App/cases/missing_return.vp @@ -0,0 +1,4 @@ +import t, c + +def h(x: int) -> int: + x = x + 1 diff --git a/NegativeTest/App/cases/undefined_func.vp b/NegativeTest/App/cases/undefined_func.vp new file mode 100644 index 0000000..e9e5c33 --- /dev/null +++ b/NegativeTest/App/cases/undefined_func.vp @@ -0,0 +1,4 @@ +import t, c + +def main() -> int: + return foo(1) diff --git a/NegativeTest/App/main.vp b/NegativeTest/App/main.vp new file mode 100644 index 0000000..e4e5d4a --- /dev/null +++ b/NegativeTest/App/main.vp @@ -0,0 +1,7 @@ +import t, c +from stdint import * +import stdio + +def main() -> int: + stdio.printf("NegativeTest baseline OK\n") + return 0 diff --git a/NegativeTest/project.json b/NegativeTest/project.json new file mode 100644 index 0000000..2394ae0 --- /dev/null +++ b/NegativeTest/project.json @@ -0,0 +1,37 @@ +{ + "name": "NegativeTest", + "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": "NegativeTest.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, + "target": "llvm", + "strict_mode": true + } +} \ No newline at end of file diff --git a/NegativeTest/run_negative_tests.py b/NegativeTest/run_negative_tests.py new file mode 100644 index 0000000..e013663 --- /dev/null +++ b/NegativeTest/run_negative_tests.py @@ -0,0 +1,71 @@ +# NegativeTest 反向测试运行器:对每个错误用例执行 TPC 单文件编译, +# 断言"编译失败且输出诊断信息"。编译成功 = 编译器漏检(FAIL)。 +import os +import subprocess +import sys + +ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +CASES_DIR = os.path.join(ROOT, 'Test', 'NegativeTest', 'App', 'cases') +OUT_DIR = os.path.join(ROOT, 'Test', 'NegativeTest', '.out') +os.makedirs(OUT_DIR, exist_ok=True) + +# 用例 -> 期望错误关键字(用于确认报错方向正确) +EXPECT = { + 'import_wrong_path.vp': ['NopeModule', '模块', 'import'], + 'import_stale_path.vp': ['StubMergerStore', '模块', 'import'], + 'import_missing_module.vp': ['HandlesStruct', '模块', 'import'], + 'call_too_few.vp': ['参数', '少', '2', 'f'], + 'call_too_many.vp': ['参数', '多', '3', 'f'], + 'call_wrong_type.vp': ['类型', 'int', 'f'], + 'call_float_to_int.vp': ['类型', 'int', 'g'], + 'undefined_func.vp': ['foo', '未定义', 'NameError'], + 'missing_return.vp': ['返回', 'return', '末尾'], +} + + +def main() -> int: + cases = sorted(f for f in os.listdir(CASES_DIR) if f.endswith('.vp')) + passed, failed, skipped = [], [], [] + for case in cases: + src = os.path.join(CASES_DIR, case) + out_ll = os.path.join(OUT_DIR, case[:-3] + '.ll') + try: + r = subprocess.run( + [sys.executable, 'TransPyC.py', '-f', src, '-o', out_ll], + capture_output=True, text=True, cwd=ROOT, timeout=120, + ) + except subprocess.TimeoutExpired: + failed.append((case, 'TIMEOUT', '')) + continue + err_text = (r.stderr or '') + (r.stdout or '') + if r.returncode == 0: + failed.append((case, 'COMPILED_OK(漏检)', err_text.strip()[-500:])) + continue + # 编译失败:检查是否报了我们预期的错误方向 + lower = err_text.lower() + keywords = EXPECT.get(case, []) + hit = [k for k in keywords if k.lower() in lower] + if hit: + passed.append((case, 'PASS', hit, err_text.strip()[-300:])) + else: + skipped.append((case, 'ERR_BUT_UNEXPECTED', err_text.strip()[-300:])) + + print('\n==== NegativeTest 结果 ====') + print(f'PASS(预期失败且方向正确): {len(passed)}') + for c, tag, hit, tail in passed: + print(f' [PASS] {c} 命中关键字 {hit}') + print(f'FAIL(编译器漏检): {len(failed)}') + for c, tag, tail in failed: + print(f' [FAIL] {c} {tag}') + if tail: + print(f' {tail}') + print(f'SKIP(报错但非预期方向): {len(skipped)}') + for c, tag, tail in skipped: + print(f' [SKIP] {c}') + if tail: + print(f' {tail}') + return 1 if failed else 0 + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/NewAstTest/App/main.vp b/NewAstTest/App/main.vp new file mode 100644 index 0000000..9699dbc --- /dev/null +++ b/NewAstTest/App/main.vp @@ -0,0 +1,1705 @@ +import t, c +from t import CInt, CExport, CPtr +from stdio import printf +import memhub +import stdlib +import string +from ast import ( + AST, ASTKind, Module, FunctionDef, Assign, If, For, While, With, + Return, Expr, Name, Constant, BinOp, UnaryOp, Call, Compare, + Import, ImportFrom, Expression, + CONST_INT, CONST_STR, CONST_BOOL, CONST_NONE, + OpKind, ASTCtx, + FLAG_IS_ASYNC, + parse, parse_expression, dump, +) + + +ARENA_SIZE: CInt = 16777216 + + +def main() -> CInt | CExport: + printf("=== NewAstTest Start ===\n") + + # 初始化分配器 + arena: bytes = stdlib.malloc(ARENA_SIZE) + if arena is None: + printf("FAIL: arena alloc failed\n") + return 1 + pool: memhub.MemBuddy | CPtr = memhub.MemBuddy(arena, ARENA_SIZE) + if pool is None: + printf("FAIL: pool init failed\n") + return 1 + + passed: CInt = 0 + failed: CInt = 0 + + # --- 分配 dump 缓冲区(用于 AST 反向输出测试) --- + DUMP_BUF_SIZE: t.CSizeT = 8192 + dump_buf: t.CChar | CPtr = stdlib.malloc(DUMP_BUF_SIZE) + if dump_buf is None: + printf("FAIL: dump_buf alloc failed\n") + stdlib.free(arena) + return 1 + + # --- Test 0: Match 语句 --- + match_src: str = """match x: + case 1: + pass + case _: + pass +""" + match_mod: Module | CPtr = parse(match_src, pool) + if match_mod is not None and match_mod.kind() == ASTKind.Module: + passed += 1 + printf("PASS: parse('match x: case 1: ... case _: ...') -> Module\n") + else: + failed += 1 + printf("FAIL: parse match with cases failed\n") + + # --- Test 1: Name 节点创建 --- + name_x: Name | CPtr = Name(pool, "x", ASTCtx.Load) + if name_x is None: + printf("FAIL: Name creation\n") + failed += 1 + else: + passed += 1 + printf("PASS: Name('x'), kind=%d\n", name_x.kind()) + + # --- Test 2: ConstantInt 节点 --- + int_42: Constant | CPtr = Constant(pool, CONST_INT, 42, 0.0, None, 1, 0) + if int_42 is None: + printf("FAIL: ConstantInt creation\n") + failed += 1 + else: + passed += 1 + printf("PASS: ConstantInt(42), kind=%d, val=%lld\n", + int_42.kind(), int_42.int_val) + + # --- Test 3: ConstantStr 节点 --- + str_hello: Constant | CPtr = Constant(pool, CONST_STR, 0, 0.0, "hello", 2, 0) + if str_hello is None: + printf("FAIL: ConstantStr creation\n") + failed += 1 + else: + passed += 1 + printf("PASS: ConstantStr('hello'), kind=%d\n", str_hello.kind()) + + # --- Test 4: ConstantNone 节点 --- + const_none: Constant | CPtr = Constant(pool, CONST_NONE, 0, 0.0, None, 3, 0) + if const_none is None: + printf("FAIL: ConstantNone creation\n") + failed += 1 + else: + passed += 1 + printf("PASS: ConstantNone, kind=%d\n", const_none.kind()) + + # --- Test 5: BinOp 节点 (x + 42) --- + binop: BinOp | CPtr = BinOp(pool, name_x, OpKind.Add, int_42) + if binop is None: + printf("FAIL: BinOp creation\n") + failed += 1 + else: + passed += 1 + printf("PASS: BinOp(Add), kind=%d\n", binop.kind()) + + # --- Test 6: UnaryOp 节点 (-x) --- + unary: UnaryOp | CPtr = UnaryOp(pool, OpKind.USub, name_x) + if unary is None: + printf("FAIL: UnaryOp creation\n") + failed += 1 + else: + passed += 1 + printf("PASS: UnaryOp(USub), kind=%d\n", unary.kind()) + + # --- Test 7: list[AST | CPtr] 容器 --- + body: list[AST | CPtr] | CPtr = list[AST | CPtr](pool, 8) + if body is None: + printf("FAIL: list creation\n") + failed += 1 + else: + body.append(binop) + body.append(unary) + cnt: t.CSizeT = body.__len__() + if cnt == 2: + passed += 1 + printf("PASS: list append x2, count=%zu\n", cnt) + else: + failed += 1 + printf("FAIL: list count=%zu (expected 2)\n", cnt) + + # --- Test 8: list get + kind 分派 --- + if body is not None: + item0: AST | CPtr = body.get(0) + if item0 is not None: + k: CInt = item0.kind() + if k == ASTKind.BinOp: + passed += 1 + printf("PASS: list get(0).kind()=%d (BinOp)\n", k) + else: + failed += 1 + printf("FAIL: list get(0).kind()=%d (expected %d)\n", k, ASTKind.BinOp) + else: + failed += 1 + printf("FAIL: list get(0) returned None\n") + + # --- Test 9: Module 节点 (新签名:Module(pool) + append) --- + mod: Module | CPtr = Module(pool) + if mod is None: + printf("FAIL: Module creation\n") + failed += 1 + else: + mod.append(binop) + mod.append(unary) + passed += 1 + printf("PASS: Module, kind=%d\n", mod.kind()) + + # --- Test 10: 多态分派 — 通过 AST 基类指针调用 kind() --- + ast_ptr: AST | CPtr = mod + poly_kind: CInt = ast_ptr.kind() + if poly_kind == ASTKind.Module: + passed += 1 + printf("PASS: polymorphic kind()=%d (Module via AST ptr)\n", poly_kind) + else: + failed += 1 + printf("FAIL: polymorphic kind()=%d (expected %d)\n", poly_kind, ASTKind.Module) + + # --- Test 11: 多态分派 — list 中的节点 --- + if body is not None: + ast_item: AST | CPtr = body.get(1) + if ast_item is not None: + pk2: CInt = ast_item.kind() + if pk2 == ASTKind.UnaryOp: + passed += 1 + printf("PASS: polymorphic kind()=%d (UnaryOp via AST ptr)\n", pk2) + else: + failed += 1 + printf("FAIL: polymorphic kind()=%d (expected %d)\n", pk2, ASTKind.UnaryOp) + else: + failed += 1 + printf("FAIL: list get(1) returned None\n") + + # --- Test 12: Return 节点 --- + ret: Return | CPtr = Return(pool, binop) + if ret is None: + printf("FAIL: Return creation\n") + failed += 1 + else: + passed += 1 + printf("PASS: Return, kind=%d\n", ret.kind()) + + # --- Test 13: Expr 语句节点 --- + expr_stmt: Expr | CPtr = Expr(pool, binop) + if expr_stmt is None: + printf("FAIL: Expr creation\n") + failed += 1 + else: + passed += 1 + printf("PASS: Expr, kind=%d\n", expr_stmt.kind()) + + # --- Test 14: If 节点 (新签名:If(pool, test, orelse),body=children) --- + empty_else: list[AST | CPtr] | CPtr = list[AST | CPtr](pool, 8) + if_stmt: If | CPtr = If(pool, binop, empty_else) + if if_stmt is None: + printf("FAIL: If creation\n") + failed += 1 + else: + if_stmt.append(ret) + if_stmt.append(expr_stmt) + passed += 1 + printf("PASS: If, kind=%d\n", if_stmt.kind()) + + # --- Test 15: Compare 节点 --- + cmp_ops: list[t.CInt] | CPtr = list[t.CInt](pool) + cmp_ops.append(OpKind.Lt) + cmp_comparators: list[AST | CPtr] | CPtr = list[AST | CPtr](pool, 8) + cmp_comparators.append(int_42) + cmp_node: Compare | CPtr = Compare(pool, name_x, cmp_ops, cmp_comparators) + if cmp_node is None: + printf("FAIL: Compare creation\n") + failed += 1 + else: + passed += 1 + printf("PASS: Compare, kind=%d\n", cmp_node.kind()) + + # --- Test 16: Assign 节点 --- + assign_targets: list[AST | CPtr] | CPtr = list[AST | CPtr](pool, 8) + assign_targets.append(name_x) + assign_node: Assign | CPtr = Assign(pool, assign_targets, int_42) + if assign_node is None: + printf("FAIL: Assign creation\n") + failed += 1 + else: + passed += 1 + printf("PASS: Assign, kind=%d\n", assign_node.kind()) + + # --- Test 17: Call 节点 --- + call_args: list[AST | CPtr] | CPtr = list[AST | CPtr](pool, 8) + call_args.append(int_42) + call_kwargs: list[AST | CPtr] | CPtr = list[AST | CPtr](pool, 8) + call_node: Call | CPtr = Call(pool, name_x, call_args, call_kwargs) + if call_node is None: + printf("FAIL: Call creation\n") + failed += 1 + else: + passed += 1 + printf("PASS: Call, kind=%d\n", call_node.kind()) + + # --- Test 18: 字段访问验证 --- + if name_x is not None: + nm: str = name_x.id + if nm is not None: + if string.strcmp(nm, "x") == 0: + passed += 1 + printf("PASS: Name.id == 'x'\n") + else: + failed += 1 + printf("FAIL: Name.id != 'x'\n") + else: + failed += 1 + printf("FAIL: Name.id is None\n") + + # --- Test 19: parent 指针验证 (binop 被 append 到 mod) --- + if binop is not None and binop.parent is mod: + passed += 1 + printf("PASS: BinOp.parent == Module (via append)\n") + else: + failed += 1 + printf("FAIL: BinOp.parent != Module\n") + + # --- Test 20: Module.children 遍历 --- + if mod is not None and mod.children is not None: + mod_cnt: t.CSizeT = mod.children.__len__() + if mod_cnt == 2: + passed += 1 + printf("PASS: Module.children count=%zu (expected 2)\n", mod_cnt) + else: + failed += 1 + printf("FAIL: Module.children count=%zu (expected 2)\n", mod_cnt) + else: + failed += 1 + printf("FAIL: Module.children is None\n") + + # --- Test 21: Module.children 多态分派 --- + if mod is not None and mod.children is not None: + c0: AST | CPtr = mod.children.get(0) + c1: AST | CPtr = mod.children.get(1) + if c0 is not None and c1 is not None: + k0: CInt = c0.kind() + k1: CInt = c1.kind() + if k0 == ASTKind.BinOp and k1 == ASTKind.UnaryOp: + passed += 1 + printf("PASS: Module.children[0]=BinOp, [1]=UnaryOp\n") + else: + failed += 1 + printf("FAIL: Module.children kinds=%d,%d\n", k0, k1) + else: + failed += 1 + printf("FAIL: Module.children get returned None\n") + else: + failed += 1 + printf("FAIL: Module.children unavailable\n") + + # --- Test 22: If.children 遍历 (ret + expr_stmt) --- + if if_stmt is not None and if_stmt.children is not None: + if_cnt: t.CSizeT = if_stmt.children.__len__() + if if_cnt == 2: + passed += 1 + printf("PASS: If.children count=%zu (expected 2)\n", if_cnt) + else: + failed += 1 + printf("FAIL: If.children count=%zu (expected 2)\n", if_cnt) + else: + failed += 1 + printf("FAIL: If.children is None\n") + + # --- Test 23: parent 向上遍历 (if_stmt.children[0].parent == if_stmt) --- + if if_stmt is not None and if_stmt.children is not None: + first_child: AST | CPtr = if_stmt.children.get(0) + if first_child is not None and first_child.parent is if_stmt: + passed += 1 + printf("PASS: If.children[0].parent == If\n") + else: + failed += 1 + printf("FAIL: If.children[0].parent != If\n") + else: + failed += 1 + printf("FAIL: If.children unavailable for parent test\n") + + # --- Test 24: parse_expression 解析 "x + 42" --- + expr_src: str = "x + 42" + expr_tree: AST | CPtr = parse_expression(expr_src, pool) + if expr_tree is not None: + passed += 1 + printf("PASS: parse_expression('x + 42') -> kind=%d\n", expr_tree.kind()) + else: + failed += 1 + printf("FAIL: parse_expression returned None\n") + + # --- Test 25: parse 解析简单模块 "x = 42\n" --- + mod_src: str = "x = 42\n" + parsed_mod: Module | CPtr = parse(mod_src, pool) + if parsed_mod is not None and parsed_mod.kind() == ASTKind.Module: + passed += 1 + printf("PASS: parse('x = 42') -> Module, kind=%d\n", parsed_mod.kind()) + else: + failed += 1 + printf("FAIL: parse('x = 42') failed\n") + + # --- Test 26: parse 模块的 children 验证 --- + if parsed_mod is not None and parsed_mod.children is not None: + pmod_cnt: t.CSizeT = parsed_mod.children.__len__() + if pmod_cnt == 1: + passed += 1 + printf("PASS: parsed Module.children count=%zu (expected 1)\n", pmod_cnt) + else: + failed += 1 + printf("FAIL: parsed Module.children count=%zu (expected 1)\n", pmod_cnt) + else: + failed += 1 + printf("FAIL: parsed Module.children is None\n") + + # --- Test 27: parse 模块子节点类型验证 (Assign) --- + if parsed_mod is not None and parsed_mod.children is not None: + pmod_child: AST | CPtr = parsed_mod.children.get(0) + if pmod_child is not None: + pmod_k: CInt = pmod_child.kind() + if pmod_k == ASTKind.Assign: + passed += 1 + printf("PASS: parsed Module.children[0].kind()=%d (Assign)\n", pmod_k) + else: + failed += 1 + printf("FAIL: parsed Module.children[0].kind()=%d (expected %d)\n", + pmod_k, ASTKind.Assign) + else: + failed += 1 + printf("FAIL: parsed Module.children.get(0) returned None\n") + else: + failed += 1 + printf("FAIL: parsed Module.children unavailable for kind test\n") + + # --- Test 28: parse 多语句模块 --- + multi_src: str = """a = 1 +b = 2 +c = a + b +""" + multi_mod: Module | CPtr = parse(multi_src, pool) + if multi_mod is not None and multi_mod.children is not None: + multi_cnt: t.CSizeT = multi_mod.children.__len__() + if multi_cnt == 3: + passed += 1 + printf("PASS: parse multi-stmt, children=%zu (expected 3)\n", multi_cnt) + else: + failed += 1 + printf("FAIL: parse multi-stmt, children=%zu (expected 3)\n", multi_cnt) + else: + failed += 1 + printf("FAIL: parse multi-stmt failed\n") + + # --- Test 29: parse if 语句 --- + if_src: str = """if x > 0: + y = 1 +""" + if_mod: Module | CPtr = parse(if_src, pool) + if if_mod is not None and if_mod.children is not None: + if_cnt2: t.CSizeT = if_mod.children.__len__() + if_k: CInt = if_mod.children.get(0).kind() + if if_cnt2 == 1 and if_k == ASTKind.If: + passed += 1 + printf("PASS: parse if, children=%zu kind=%d (If)\n", if_cnt2, if_k) + else: + failed += 1 + printf("FAIL: parse if, children=%zu kind=%d\n", if_cnt2, if_k) + else: + failed += 1 + printf("FAIL: parse if failed\n") + + # --- Test 30: parse for 循环 --- + for_src: str = """for i in range(10): + pass +""" + for_mod: Module | CPtr = parse(for_src, pool) + if for_mod is not None and for_mod.children is not None: + for_cnt: t.CSizeT = for_mod.children.__len__() + for_k: CInt = for_mod.children.get(0).kind() + if for_cnt == 1 and for_k == ASTKind.For: + passed += 1 + printf("PASS: parse for, children=%zu kind=%d (For)\n", for_cnt, for_k) + else: + failed += 1 + printf("FAIL: parse for, children=%zu kind=%d\n", for_cnt, for_k) + else: + failed += 1 + printf("FAIL: parse for failed\n") + + # --- Test 31: parse while 循环 --- + while_src: str = """while x < 100: + x = x + 1 +""" + while_mod: Module | CPtr = parse(while_src, pool) + if while_mod is not None and while_mod.children is not None: + while_cnt: t.CSizeT = while_mod.children.__len__() + while_k: CInt = while_mod.children.get(0).kind() + if while_cnt == 1 and while_k == ASTKind.While: + passed += 1 + printf("PASS: parse while, children=%zu kind=%d (While)\n", while_cnt, while_k) + else: + failed += 1 + printf("FAIL: parse while, children=%zu kind=%d\n", while_cnt, while_k) + else: + failed += 1 + printf("FAIL: parse while failed\n") + + # --- Test 32: parse 函数定义 --- + def_src: str = """def foo(a, b): + return a + b +""" + def_mod: Module | CPtr = parse(def_src, pool) + if def_mod is not None and def_mod.children is not None: + def_cnt: t.CSizeT = def_mod.children.__len__() + def_k: CInt = def_mod.children.get(0).kind() + if def_cnt == 1 and def_k == ASTKind.FunctionDef: + passed += 1 + printf("PASS: parse def, children=%zu kind=%d (FunctionDef)\n", def_cnt, def_k) + else: + failed += 1 + printf("FAIL: parse def, children=%zu kind=%d\n", def_cnt, def_k) + else: + failed += 1 + printf("FAIL: parse def failed\n") + + # --- Test 33: parse 复杂表达式 (a + b * c - 1) --- + complex_expr_src: str = "a + b * c - 1" + complex_expr: AST | CPtr = parse_expression(complex_expr_src, pool) + if complex_expr is not None: + ce_k: CInt = complex_expr.kind() + if ce_k == ASTKind.Expression: + passed += 1 + printf("PASS: parse complex expr, kind=%d (Expression)\n", ce_k) + else: + failed += 1 + printf("FAIL: parse complex expr, kind=%d\n", ce_k) + else: + failed += 1 + printf("FAIL: parse complex expr failed\n") + + # --- Test 34: parse 嵌套语句 (for 内 if) --- + nested_src: str = """for i in range(10): + if i > 5: + x = 1 +""" + nested_mod: Module | CPtr = parse(nested_src, pool) + if nested_mod is not None and nested_mod.children is not None: + nested_cnt: t.CSizeT = nested_mod.children.__len__() + nested_k: CInt = nested_mod.children.get(0).kind() + if nested_cnt == 1 and nested_k == ASTKind.For: + passed += 1 + printf("PASS: parse nested for-if, children=%zu kind=%d (For)\n", nested_cnt, nested_k) + else: + failed += 1 + printf("FAIL: parse nested for-if, children=%zu kind=%d\n", nested_cnt, nested_k) + else: + failed += 1 + printf("FAIL: parse nested for-if failed\n") + + # --- Test 35: parse 混合多语句模块 --- + mixed_src: str = """x = 1 +y = 2 +if x < y: + z = x + y +else: + z = 0 +w = z * 2 +""" + mixed_mod: Module | CPtr = parse(mixed_src, pool) + if mixed_mod is not None and mixed_mod.children is not None: + mixed_cnt: t.CSizeT = mixed_mod.children.__len__() + if mixed_cnt == 4: + passed += 1 + printf("PASS: parse mixed module, children=%zu (expected 4)\n", mixed_cnt) + else: + failed += 1 + printf("FAIL: parse mixed module, children=%zu (expected 4)\n", mixed_cnt) + else: + failed += 1 + printf("FAIL: parse mixed module failed\n") + + # --- Test 36: dump 反向 - parse("x = 42") → dump → strstr 验证 --- + if parsed_mod is not None: + dump(parsed_mod, dump_buf, DUMP_BUF_SIZE) + has_assign: str = string.strstr(dump_buf, "Assign") + has_42: str = string.strstr(dump_buf, "42") + if has_assign is not None and has_42 is not None: + passed += 1 + printf("PASS: dump parse('x = 42') contains 'Assign' and '42'\n") + else: + failed += 1 + printf("FAIL: dump parse('x = 42') missing tokens\n") + else: + failed += 1 + printf("FAIL: parsed_mod unavailable for dump test\n") + + # --- Test 37: dump 反向 - parse_expression("x + 42 * 2") → dump → strstr BinOp --- + if complex_expr is not None: + dump(complex_expr, dump_buf, DUMP_BUF_SIZE) + has_binop: str = string.strstr(dump_buf, "BinOp") + if has_binop is not None: + passed += 1 + printf("PASS: dump complex expr contains 'BinOp'\n") + else: + failed += 1 + printf("FAIL: dump complex expr missing 'BinOp'\n") + else: + failed += 1 + printf("FAIL: complex_expr unavailable for dump test\n") + + # --- Test 38: dump 反向 - parse if → dump → strstr "If" + "Compare" --- + if if_mod is not None: + dump(if_mod, dump_buf, DUMP_BUF_SIZE) + has_if: str = string.strstr(dump_buf, "If(") + has_cmp: str = string.strstr(dump_buf, "Compare") + if has_if is not None and has_cmp is not None: + passed += 1 + printf("PASS: dump parse if contains 'If(' and 'Compare'\n") + else: + failed += 1 + printf("FAIL: dump parse if missing tokens\n") + else: + failed += 1 + printf("FAIL: if_mod unavailable for dump test\n") + + # --- Test 39: dump 反向 - parse def → dump → strstr "FunctionDef" --- + if def_mod is not None: + dump(def_mod, dump_buf, DUMP_BUF_SIZE) + has_fdef: str = string.strstr(dump_buf, "FunctionDef") + if has_fdef is not None: + passed += 1 + printf("PASS: dump parse def contains 'FunctionDef'\n") + else: + failed += 1 + printf("FAIL: dump parse def missing 'FunctionDef'\n") + else: + failed += 1 + printf("FAIL: def_mod unavailable for dump test\n") + + # --- Test 40: AST 结构化输出 - dump 多语句模块完整输出 --- + if mixed_mod is not None: + dump(mixed_mod, dump_buf, DUMP_BUF_SIZE) + printf("--- AST dump of mixed module ---\n%s\n--- end dump ---\n", dump_buf) + # 验证包含多种节点 + has_m_assign: str = string.strstr(dump_buf, "Assign") + has_m_if: str = string.strstr(dump_buf, "If(") + if has_m_assign is not None and has_m_if is not None: + passed += 1 + printf("PASS: structured dump of mixed module contains Assign + If\n") + else: + failed += 1 + printf("FAIL: structured dump of mixed module missing nodes\n") + else: + failed += 1 + printf("FAIL: mixed_mod unavailable for structured dump\n") + + # --- Test 41: AST 结构化输出 - dump for 循环完整输出 --- + if for_mod is not None: + dump(for_mod, dump_buf, DUMP_BUF_SIZE) + printf("--- AST dump of for loop ---\n%s\n--- end dump ---\n", dump_buf) + has_for: str = string.strstr(dump_buf, "For(") + if has_for is not None: + passed += 1 + printf("PASS: structured dump of for loop contains 'For('\n") + else: + failed += 1 + printf("FAIL: structured dump of for loop missing 'For('\n") + else: + failed += 1 + printf("FAIL: for_mod unavailable for structured dump\n") + + # --- Test 42: type_name 多态分派验证 --- + if parsed_mod is not None and parsed_mod.children is not None: + tn_node: AST | CPtr = parsed_mod.children.get(0) + if tn_node is not None: + tn: str = tn_node.type_name() + if tn is not None and string.strcmp(tn, "Assign") == 0: + passed += 1 + printf("PASS: type_name() = 'Assign' (polymorphic)\n") + else: + failed += 1 + printf("FAIL: type_name() != 'Assign'\n") + else: + failed += 1 + printf("FAIL: type_name test node None\n") + else: + failed += 1 + printf("FAIL: parsed_mod unavailable for type_name test\n") + + # --- Test 43: parse 类定义 --- + class_src: str = """class Foo(Base): + x = 1 + def bar(self): + return self.x +""" + class_mod: Module | CPtr = parse(class_src, pool) + if class_mod is not None and class_mod.children is not None: + class_cnt: t.CSizeT = class_mod.children.__len__() + class_k: CInt = class_mod.children.get(0).kind() + if class_cnt == 1 and class_k == ASTKind.ClassDef: + passed += 1 + printf("PASS: parse class, children=%zu kind=%d (ClassDef)\n", class_cnt, class_k) + else: + failed += 1 + printf("FAIL: parse class, children=%zu kind=%d\n", class_cnt, class_k) + else: + failed += 1 + printf("FAIL: parse class failed\n") + + # --- Test 44: parse try/except --- + try_src: str = """try: + x = 1 +except: + x = 0 +""" + try_mod: Module | CPtr = parse(try_src, pool) + if try_mod is not None and try_mod.children is not None: + try_cnt: t.CSizeT = try_mod.children.__len__() + try_k: CInt = try_mod.children.get(0).kind() + if try_cnt == 1 and try_k == ASTKind.Try: + passed += 1 + printf("PASS: parse try/except, children=%zu kind=%d (Try)\n", try_cnt, try_k) + else: + failed += 1 + printf("FAIL: parse try/except, children=%zu kind=%d\n", try_cnt, try_k) + else: + failed += 1 + printf("FAIL: parse try/except failed\n") + + # --- Test 45: parse import 语句 --- + import_src: str = """import os +from sys import path +""" + import_mod: Module | CPtr = parse(import_src, pool) + if import_mod is not None and import_mod.children is not None: + import_cnt: t.CSizeT = import_mod.children.__len__() + k0: CInt = import_mod.children.get(0).kind() + k1: CInt = import_mod.children.get(1).kind() + if import_cnt == 2 and k0 == ASTKind.Import and k1 == ASTKind.ImportFrom: + passed += 1 + printf("PASS: parse import, children=%zu k0=%d(Import) k1=%d(ImportFrom)\n", + import_cnt, k0, k1) + else: + failed += 1 + printf("FAIL: parse import, children=%zu k0=%d k1=%d\n", import_cnt, k0, k1) + else: + failed += 1 + printf("FAIL: parse import failed\n") + + # --- Test 46: parse AugAssign (x += 1) --- + aug_src: str = """x = 0 +x += 1 +""" + aug_mod: Module | CPtr = parse(aug_src, pool) + if aug_mod is not None and aug_mod.children is not None: + aug_cnt: t.CSizeT = aug_mod.children.__len__() + aug_k: CInt = aug_mod.children.get(1).kind() + if aug_cnt == 2 and aug_k == ASTKind.AugAssign: + passed += 1 + printf("PASS: parse AugAssign, children=%zu kind=%d (AugAssign)\n", aug_cnt, aug_k) + else: + failed += 1 + printf("FAIL: parse AugAssign, children=%zu kind=%d\n", aug_cnt, aug_k) + else: + failed += 1 + printf("FAIL: parse AugAssign failed\n") + + # --- Test 47: parse 条件表达式 (x if y else z) --- + ifexp_src: str = "x if y else z" + ifexp_tree: AST | CPtr = parse_expression(ifexp_src, pool) + ifexp_expr: Expression | CPtr = (Expression | CPtr)(ifexp_tree) + if ifexp_expr is not None and ifexp_expr.body is not None: + ie_k: CInt = ifexp_expr.body.kind() + if ie_k == ASTKind.IfExp: + passed += 1 + printf("PASS: parse IfExp, kind=%d (IfExp)\n", ie_k) + else: + failed += 1 + printf("FAIL: parse IfExp, kind=%d\n", ie_k) + else: + failed += 1 + printf("FAIL: parse IfExp failed\n") + + # --- Test 48: parse 嵌套函数定义 --- + nested_def_src: str = """def outer(): + x = 1 + def inner(): + return x + return inner() +""" + nested_def_mod: Module | CPtr = parse(nested_def_src, pool) + if nested_def_mod is not None and nested_def_mod.children is not None: + nd_cnt: t.CSizeT = nested_def_mod.children.__len__() + nd_k: CInt = nested_def_mod.children.get(0).kind() + if nd_cnt == 1 and nd_k == ASTKind.FunctionDef: + passed += 1 + printf("PASS: parse nested def, children=%zu kind=%d (FunctionDef)\n", nd_cnt, nd_k) + else: + failed += 1 + printf("FAIL: parse nested def, children=%zu kind=%d\n", nd_cnt, nd_k) + else: + failed += 1 + printf("FAIL: parse nested def failed\n") + + # --- Test 49: dump 复杂代码 (类 + try + 嵌套函数) --- + complex_src: str = """class Foo(Base): + x = 1 +try: + y = Foo() +except: + y = None +def bar(): + return y +""" + complex_mod: Module | CPtr = parse(complex_src, pool) + if complex_mod is not None: + dump(complex_mod, dump_buf, DUMP_BUF_SIZE) + printf("--- AST dump of complex module ---\n%s\n--- end dump ---\n", dump_buf) + has_cls: str = string.strstr(dump_buf, "ClassDef") + has_try: str = string.strstr(dump_buf, "Try") + has_fdef2: str = string.strstr(dump_buf, "FunctionDef") + if has_cls is not None and has_try is not None and has_fdef2 is not None: + passed += 1 + printf("PASS: dump complex module contains ClassDef + Try + FunctionDef\n") + else: + failed += 1 + printf("FAIL: dump complex module missing nodes\n") + else: + failed += 1 + printf("FAIL: parse complex module failed\n") + + # --- Test 50: 复杂 mixed_src - 综合语法实例 --- + complex_mixed_src: str = """def gcd(a, b): + while b: + t = b + b = a % b + a = t + return a +x = gcd(48, 36) +if x > 1 and x < 100: + y = x * 2 + 1 +elif x == 1: + y = 1 +else: + y = 0 +""" + cmix_mod: Module | CPtr = parse(complex_mixed_src, pool) + if cmix_mod is not None and cmix_mod.children is not None: + cmix_cnt: t.CSizeT = cmix_mod.children.__len__() + dump(cmix_mod, dump_buf, DUMP_BUF_SIZE) + printf("--- AST dump of complex mixed ---\n%s\n--- end dump ---\n", dump_buf) + cm_def: str = string.strstr(dump_buf, "FunctionDef") + cm_while: str = string.strstr(dump_buf, "While(") + cm_call: str = string.strstr(dump_buf, "Call(") + cm_bool: str = string.strstr(dump_buf, "BoolOp(") + cm_cmp: str = string.strstr(dump_buf, "Compare(") + cm_ret: str = string.strstr(dump_buf, "Return(") + ok: t.CInt = 0 + if cmix_cnt == 3: + if cm_def is not None and cm_while is not None: + if cm_call is not None and cm_bool is not None: + if cm_cmp is not None and cm_ret is not None: + ok = 1 + if ok == 1: + passed += 1 + printf("PASS: complex mixed_src, children=%zu contains Def+While+Call+BoolOp+Compare+Return\n", cmix_cnt) + else: + failed += 1 + printf("FAIL: complex mixed_src, children=%zu def=%d while=%d call=%d bool=%d cmp=%d ret=%d\n", + cmix_cnt, cm_def is not None, cm_while is not None, + cm_call is not None, cm_bool is not None, cm_cmp is not None, + cm_ret is not None) + else: + failed += 1 + printf("FAIL: complex mixed_src parse failed\n") + + # --- Test 51: Lambda 表达式 --- + lambda_src: str = "f = lambda x: x + 1" + lambda_mod: Module | CPtr = parse(lambda_src, pool) + if lambda_mod is not None: + dump(lambda_mod, dump_buf, DUMP_BUF_SIZE) + has_lambda: str = string.strstr(dump_buf, "Lambda(") + has_arg: str = string.strstr(dump_buf, "Arg(arg='x'") + if has_lambda is not None and has_arg is not None: + passed += 1 + printf("PASS: Lambda with arg parsed\n") + else: + failed += 1 + printf("FAIL: Lambda parse, lambda=%d arg=%d\n", + has_lambda is not None, has_arg is not None) + else: + failed += 1 + printf("FAIL: Lambda parse returned None\n") + + # --- Test 52: List comprehension --- + listcomp_src: str = "squares = [x*x for x in range(10)]" + lc_mod: Module | CPtr = parse(listcomp_src, pool) + if lc_mod is not None: + dump(lc_mod, dump_buf, DUMP_BUF_SIZE) + has_lc: str = string.strstr(dump_buf, "ListComp(") + has_comp: str = string.strstr(dump_buf, "Comprehension(") + if has_lc is not None and has_comp is not None: + passed += 1 + printf("PASS: ListComp with Comprehension parsed\n") + else: + failed += 1 + printf("FAIL: ListComp parse, lc=%d comp=%d\n", + has_lc is not None, has_comp is not None) + else: + failed += 1 + printf("FAIL: ListComp parse returned None\n") + + # --- Test 53: Dict comprehension --- + dictcomp_src: str = "d = {k: v for k, v in items}" + dc_mod: Module | CPtr = parse(dictcomp_src, pool) + if dc_mod is not None: + dump(dc_mod, dump_buf, DUMP_BUF_SIZE) + has_dc: str = string.strstr(dump_buf, "DictComp(") + if has_dc is not None: + passed += 1 + printf("PASS: DictComp parsed\n") + else: + failed += 1 + printf("FAIL: DictComp parse, dc=%d\n", has_dc is not None) + else: + failed += 1 + printf("FAIL: DictComp parse returned None\n") + + # --- Test 54: Set comprehension --- + setcomp_src: str = "s = {x for x in items}" + sc_mod: Module | CPtr = parse(setcomp_src, pool) + if sc_mod is not None: + dump(sc_mod, dump_buf, DUMP_BUF_SIZE) + has_sc: str = string.strstr(dump_buf, "SetComp(") + if has_sc is not None: + passed += 1 + printf("PASS: SetComp parsed\n") + else: + failed += 1 + printf("FAIL: SetComp parse, sc=%d\n", has_sc is not None) + else: + failed += 1 + printf("FAIL: SetComp parse returned None\n") + + # --- Test 55: With 语句 --- + with_src: str = """with open('f') as f: + data = f.read() +""" + with_mod: Module | CPtr = parse(with_src, pool) + if with_mod is not None and with_mod.children is not None: + dump(with_mod, dump_buf, DUMP_BUF_SIZE) + has_with: str = string.strstr(dump_buf, "With(") + has_witem: str = string.strstr(dump_buf, "WithItem(") + if has_with is not None and has_witem is not None: + passed += 1 + printf("PASS: With + WithItem parsed\n") + else: + failed += 1 + printf("FAIL: With parse, with=%d witem=%d\n", + has_with is not None, has_witem is not None) + else: + failed += 1 + printf("FAIL: With parse returned None\n") + + # --- Test 56: Raise 语句 --- + raise_src: str = "raise ValueError('bad')" + raise_mod: Module | CPtr = parse(raise_src, pool) + if raise_mod is not None: + dump(raise_mod, dump_buf, DUMP_BUF_SIZE) + has_raise: str = string.strstr(dump_buf, "Raise(") + if has_raise is not None: + passed += 1 + printf("PASS: Raise parsed\n") + else: + failed += 1 + printf("FAIL: Raise parse, raise=%d\n", has_raise is not None) + else: + failed += 1 + printf("FAIL: Raise parse returned None\n") + + # --- Test 57: Assert 语句 --- + assert_src: str = "assert x > 0, 'x must be positive'" + assert_mod: Module | CPtr = parse(assert_src, pool) + if assert_mod is not None: + dump(assert_mod, dump_buf, DUMP_BUF_SIZE) + has_assert: str = string.strstr(dump_buf, "Assert(") + if has_assert is not None: + passed += 1 + printf("PASS: Assert parsed\n") + else: + failed += 1 + printf("FAIL: Assert parse, assert=%d\n", has_assert is not None) + else: + failed += 1 + printf("FAIL: Assert parse returned None\n") + + # --- Test 58: Del 语句 --- + del_src: str = "del x" + del_mod: Module | CPtr = parse(del_src, pool) + if del_mod is not None: + dump(del_mod, dump_buf, DUMP_BUF_SIZE) + has_del: str = string.strstr(dump_buf, "Delete(") + if has_del is not None: + passed += 1 + printf("PASS: Delete parsed\n") + else: + failed += 1 + printf("FAIL: Delete parse, del=%d\n", has_del is not None) + else: + failed += 1 + printf("FAIL: Delete parse returned None\n") + + # --- Test 59: Subscript + Slice --- + slice_src: str = "y = a[1:3]" + slice_mod: Module | CPtr = parse(slice_src, pool) + if slice_mod is not None: + dump(slice_mod, dump_buf, DUMP_BUF_SIZE) + has_sub: str = string.strstr(dump_buf, "Subscript(") + has_slice: str = string.strstr(dump_buf, "Slice(") + if has_sub is not None and has_slice is not None: + passed += 1 + printf("PASS: Subscript + Slice parsed\n") + else: + failed += 1 + printf("FAIL: Slice parse, sub=%d slice=%d\n", + has_sub is not None, has_slice is not None) + else: + failed += 1 + printf("FAIL: Slice parse returned None\n") + + # --- Test 60: Tuple 解包 --- + tuple_src: str = "a, b = 1, 2" + tuple_mod: Module | CPtr = parse(tuple_src, pool) + if tuple_mod is not None: + dump(tuple_mod, dump_buf, DUMP_BUF_SIZE) + has_tuple: str = string.strstr(dump_buf, "Tuple(") + if has_tuple is not None: + passed += 1 + printf("PASS: Tuple unpacking parsed\n") + else: + failed += 1 + printf("FAIL: Tuple parse, tuple=%d\n", has_tuple is not None) + else: + failed += 1 + printf("FAIL: Tuple parse returned None\n") + + # --- Test 61: 默认参数 + 关键字参数签名 --- + defdef_src: str = "def f(a, b=10): return a + b" + defdef_mod: Module | CPtr = parse(defdef_src, pool) + if defdef_mod is not None: + dump(defdef_mod, dump_buf, DUMP_BUF_SIZE) + has_fdef: str = string.strstr(dump_buf, "FunctionDef(name='f'") + has_def: str = string.strstr(dump_buf, "Constant(value=10)") + if has_fdef is not None and has_def is not None: + passed += 1 + printf("PASS: FunctionDef with default arg parsed\n") + else: + failed += 1 + printf("FAIL: defdef parse, fdef=%d def=%d\n", + has_fdef is not None, has_def is not None) + else: + failed += 1 + printf("FAIL: defdef parse returned None\n") + + # --- Test 62: 装饰器 --- + deco_src: str = """@my_dec +def f(): + pass +""" + deco_mod: Module | CPtr = parse(deco_src, pool) + if deco_mod is not None: + dump(deco_mod, dump_buf, DUMP_BUF_SIZE) + has_dec: str = string.strstr(dump_buf, "decorator_list=[Name(id='my_dec'") + if has_dec is not None: + passed += 1 + printf("PASS: Decorator parsed\n") + else: + failed += 1 + printf("FAIL: Decorator parse, dec=%d\n", has_dec is not None) + else: + failed += 1 + printf("FAIL: Decorator parse returned None\n") + + # --- Test 63: 链式赋值 --- + chain_src: str = "a = b = c = 42" + chain_mod: Module | CPtr = parse(chain_src, pool) + if chain_mod is not None: + dump(chain_mod, dump_buf, DUMP_BUF_SIZE) + has_chain: str = string.strstr(dump_buf, "Assign(targets=[Name(id='a'") + has_b: str = string.strstr(dump_buf, "Name(id='b'") + has_c: str = string.strstr(dump_buf, "Name(id='c'") + if has_chain is not None and has_b is not None and has_c is not None: + passed += 1 + printf("PASS: Chain assignment a=b=c=42 parsed\n") + else: + failed += 1 + printf("FAIL: Chain, a=%d b=%d c=%d\n", + has_chain is not None, has_b is not None, has_c is not None) + else: + failed += 1 + printf("FAIL: Chain parse returned None\n") + + # --- Test 64: 位运算 --- + bit_src: str = "y = (a | b) & c ^ d << 2" + bit_mod: Module | CPtr = parse(bit_src, pool) + if bit_mod is not None: + dump(bit_mod, dump_buf, DUMP_BUF_SIZE) + has_bor: str = string.strstr(dump_buf, "op=BitOr") + has_band: str = string.strstr(dump_buf, "op=BitAnd") + has_bxor: str = string.strstr(dump_buf, "op=BitXor") + if has_bor is not None and has_band is not None and has_bxor is not None: + passed += 1 + printf("PASS: Bit ops (| & ^) parsed\n") + else: + failed += 1 + printf("FAIL: Bit ops, bor=%d band=%d bxor=%d\n", + has_bor is not None, has_band is not None, has_bxor is not None) + else: + failed += 1 + printf("FAIL: Bit ops parse returned None\n") + + # --- Test 65: 多继承 + 多装饰器 --- + multi_src: str = """@dec1 +@dec2 +class C(Base1, Base2): + pass +""" + multi_mod: Module | CPtr = parse(multi_src, pool) + if multi_mod is not None: + dump(multi_mod, dump_buf, DUMP_BUF_SIZE) + m_dec1: str = string.strstr(dump_buf, "Name(id='dec1'") + m_dec2: str = string.strstr(dump_buf, "Name(id='dec2'") + m_b1: str = string.strstr(dump_buf, "Name(id='Base1'") + m_b2: str = string.strstr(dump_buf, "Name(id='Base2'") + if m_dec1 is not None and m_dec2 is not None and m_b1 is not None and m_b2 is not None: + passed += 1 + printf("PASS: Multi-decorator + multi-inheritance parsed\n") + else: + failed += 1 + printf("FAIL: multi, dec1=%d dec2=%d b1=%d b2=%d\n", + m_dec1 is not None, m_dec2 is not None, + m_b1 is not None, m_b2 is not None) + else: + failed += 1 + printf("FAIL: multi parse returned None\n") + + # --- Test 66: Global / Nonlocal --- + glob_src: str = """def f(): + global x + x = 1 +""" + glob_mod: Module | CPtr = parse(glob_src, pool) + if glob_mod is not None: + dump(glob_mod, dump_buf, DUMP_BUF_SIZE) + has_glob: str = string.strstr(dump_buf, "Global(") + if has_glob is not None: + passed += 1 + printf("PASS: Global statement parsed\n") + else: + failed += 1 + printf("FAIL: Global parse, glob=%d\n", has_glob is not None) + else: + failed += 1 + printf("FAIL: Global parse returned None\n") + + # --- Test 67: f-string (FormattedValue) --- + fstr_src: str = "s = f'value={x}'" + fstr_mod: Module | CPtr = parse(fstr_src, pool) + if fstr_mod is not None: + dump(fstr_mod, dump_buf, DUMP_BUF_SIZE) + has_fv: str = string.strstr(dump_buf, "FormattedValue(") + has_js: str = string.strstr(dump_buf, "JoinedStr(") + if has_fv is not None and has_js is not None: + passed += 1 + printf("PASS: f-string with FormattedValue + JoinedStr parsed\n") + else: + failed += 1 + printf("FAIL: fstring, fv=%d js=%d\n", + has_fv is not None, has_js is not None) + else: + failed += 1 + printf("FAIL: fstring parse returned None\n") + + # --- Test 68: 嵌套函数 + 闭包 --- + nested_src: str = """def outer(): + x = 10 + def inner(): + return x + 1 + return inner() +""" + nested_mod: Module | CPtr = parse(nested_src, pool) + if nested_mod is not None and nested_mod.children is not None: + dump(nested_mod, dump_buf, DUMP_BUF_SIZE) + n_outer: str = string.strstr(dump_buf, "FunctionDef(name='outer'") + n_inner: str = string.strstr(dump_buf, "FunctionDef(name='inner'") + if n_outer is not None and n_inner is not None: + passed += 1 + printf("PASS: Nested function definitions parsed\n") + else: + failed += 1 + printf("FAIL: nested, outer=%d inner=%d\n", + n_outer is not None, n_inner is not None) + else: + failed += 1 + printf("FAIL: nested parse returned None\n") + + # --- Test 69: Match 字面量整数模式 --- + m_lit_src: str = """match x: + case 1: + pass +""" + m_lit_mod: Module | CPtr = parse(m_lit_src, pool) + if m_lit_mod is not None: + dump(m_lit_mod, dump_buf, DUMP_BUF_SIZE) + has_mv: str = string.strstr(dump_buf, "MatchValue(") + if has_mv is not None: + passed += 1 + printf("PASS: Match literal int -> MatchValue\n") + else: + failed += 1 + printf("FAIL: Match literal int, mv=%d\n", has_mv is not None) + else: + failed += 1 + printf("FAIL: Match literal int parse returned None\n") + + # --- Test 70: Match 字面量字符串模式 --- + m_str_src: str = """match x: + case "hello": + pass +""" + m_str_mod: Module | CPtr = parse(m_str_src, pool) + if m_str_mod is not None: + dump(m_str_mod, dump_buf, DUMP_BUF_SIZE) + has_mv2: str = string.strstr(dump_buf, "MatchValue(") + if has_mv2 is not None: + passed += 1 + printf("PASS: Match literal str -> MatchValue\n") + else: + failed += 1 + printf("FAIL: Match literal str\n") + else: + failed += 1 + printf("FAIL: Match literal str parse returned None\n") + + # --- Test 71: Match 负数字面量模式 --- + m_neg_src: str = """match x: + case -1: + pass +""" + m_neg_mod: Module | CPtr = parse(m_neg_src, pool) + if m_neg_mod is not None: + dump(m_neg_mod, dump_buf, DUMP_BUF_SIZE) + has_mv3: str = string.strstr(dump_buf, "MatchValue(") + if has_mv3 is not None: + passed += 1 + printf("PASS: Match negative literal -> MatchValue\n") + else: + failed += 1 + printf("FAIL: Match negative literal\n") + else: + failed += 1 + printf("FAIL: Match negative literal parse returned None\n") + + # --- Test 72: Match None 单例模式 --- + m_none_src: str = """match x: + case None: + pass +""" + m_none_mod: Module | CPtr = parse(m_none_src, pool) + if m_none_mod is not None: + dump(m_none_mod, dump_buf, DUMP_BUF_SIZE) + has_ms: str = string.strstr(dump_buf, "MatchSingleton(") + if has_ms is not None: + passed += 1 + printf("PASS: Match None -> MatchSingleton\n") + else: + failed += 1 + printf("FAIL: Match None, ms=%d\n", has_ms is not None) + else: + failed += 1 + printf("FAIL: Match None parse returned None\n") + + # --- Test 73: Match True 单例模式 --- + m_true_src: str = """match x: + case True: + pass +""" + m_true_mod: Module | CPtr = parse(m_true_src, pool) + if m_true_mod is not None: + dump(m_true_mod, dump_buf, DUMP_BUF_SIZE) + has_ms2: str = string.strstr(dump_buf, "MatchSingleton(") + if has_ms2 is not None: + passed += 1 + printf("PASS: Match True -> MatchSingleton\n") + else: + failed += 1 + printf("FAIL: Match True\n") + else: + failed += 1 + printf("FAIL: Match True parse returned None\n") + + # --- Test 74: Match False 单例模式 --- + m_false_src: str = """match x: + case False: + pass +""" + m_false_mod: Module | CPtr = parse(m_false_src, pool) + if m_false_mod is not None: + dump(m_false_mod, dump_buf, DUMP_BUF_SIZE) + has_ms3: str = string.strstr(dump_buf, "MatchSingleton(") + if has_ms3 is not None: + passed += 1 + printf("PASS: Match False -> MatchSingleton\n") + else: + failed += 1 + printf("FAIL: Match False\n") + else: + failed += 1 + printf("FAIL: Match False parse returned None\n") + + # --- Test 75: Match 通配符 _ 模式 --- + m_wild_src: str = """match x: + case _: + pass +""" + m_wild_mod: Module | CPtr = parse(m_wild_src, pool) + if m_wild_mod is not None: + dump(m_wild_mod, dump_buf, DUMP_BUF_SIZE) + has_ma: str = string.strstr(dump_buf, "MatchAs(") + if has_ma is not None: + passed += 1 + printf("PASS: Match wildcard _ -> MatchAs\n") + else: + failed += 1 + printf("FAIL: Match wildcard, ma=%d\n", has_ma is not None) + else: + failed += 1 + printf("FAIL: Match wildcard parse returned None\n") + + # --- Test 76: Match 捕获变量模式 --- + m_cap_src: str = """match x: + case y: + pass +""" + m_cap_mod: Module | CPtr = parse(m_cap_src, pool) + if m_cap_mod is not None: + dump(m_cap_mod, dump_buf, DUMP_BUF_SIZE) + has_ma2: str = string.strstr(dump_buf, "name='y'") + if has_ma2 is not None: + passed += 1 + printf("PASS: Match capture y -> MatchAs(name='y')\n") + else: + failed += 1 + printf("FAIL: Match capture, ma=%d\n", has_ma2 is not None) + else: + failed += 1 + printf("FAIL: Match capture parse returned None\n") + + # --- Test 77: Match 值模式 (dotted name Color.RED) --- + m_val_src: str = """match x: + case Color.RED: + pass +""" + m_val_mod: Module | CPtr = parse(m_val_src, pool) + if m_val_mod is not None: + dump(m_val_mod, dump_buf, DUMP_BUF_SIZE) + has_mv4: str = string.strstr(dump_buf, "MatchValue(") + has_attr: str = string.strstr(dump_buf, "Attribute(") + if has_mv4 is not None and has_attr is not None: + passed += 1 + printf("PASS: Match Color.RED -> MatchValue + Attribute\n") + else: + failed += 1 + printf("FAIL: Match value, mv=%d attr=%d\n", + has_mv4 is not None, has_attr is not None) + else: + failed += 1 + printf("FAIL: Match value parse returned None\n") + + # --- Test 78: Match 序列模式 [1, 2] --- + m_seq_src: str = """match x: + case [1, 2]: + pass +""" + m_seq_mod: Module | CPtr = parse(m_seq_src, pool) + if m_seq_mod is not None: + dump(m_seq_mod, dump_buf, DUMP_BUF_SIZE) + has_msq: str = string.strstr(dump_buf, "MatchSequence(") + if has_msq is not None: + passed += 1 + printf("PASS: Match [1, 2] -> MatchSequence\n") + else: + failed += 1 + printf("FAIL: Match sequence, msq=%d\n", has_msq is not None) + else: + failed += 1 + printf("FAIL: Match sequence parse returned None\n") + + # --- Test 79: Match 序列带星号 [a, *rest] --- + m_star_src: str = """match x: + case [a, *rest]: + pass +""" + m_star_mod: Module | CPtr = parse(m_star_src, pool) + if m_star_mod is not None: + dump(m_star_mod, dump_buf, DUMP_BUF_SIZE) + has_mstar: str = string.strstr(dump_buf, "MatchStar(name='rest')") + if has_mstar is not None: + passed += 1 + printf("PASS: Match [a, *rest] -> MatchStar\n") + else: + failed += 1 + printf("FAIL: Match star, mstar=%d\n", has_mstar is not None) + else: + failed += 1 + printf("FAIL: Match star parse returned None\n") + + # --- Test 80: Match 类模式 Point(x, y) --- + m_cls_src: str = """match p: + case Point(x, y): + pass +""" + m_cls_mod: Module | CPtr = parse(m_cls_src, pool) + if m_cls_mod is not None: + dump(m_cls_mod, dump_buf, DUMP_BUF_SIZE) + has_mc: str = string.strstr(dump_buf, "MatchClass(") + if has_mc is not None: + passed += 1 + printf("PASS: Match Point(x, y) -> MatchClass\n") + else: + failed += 1 + printf("FAIL: Match class, mc=%d\n", has_mc is not None) + else: + failed += 1 + printf("FAIL: Match class parse returned None\n") + + # --- Test 81: Match 类模式带关键字 Point(x=0, y=0) --- + m_kwcls_src: str = """match p: + case Point(x=0, y=0): + pass +""" + m_kwcls_mod: Module | CPtr = parse(m_kwcls_src, pool) + if m_kwcls_mod is not None: + dump(m_kwcls_mod, dump_buf, DUMP_BUF_SIZE) + has_mc2: str = string.strstr(dump_buf, "MatchClass(") + if has_mc2 is not None: + passed += 1 + printf("PASS: Match Point(x=0, y=0) -> MatchClass with kwd\n") + else: + failed += 1 + printf("FAIL: Match class kwd, mc=%d\n", has_mc2 is not None) + else: + failed += 1 + printf("FAIL: Match class kwd parse returned None\n") + + # --- Test 82: Match OR 模式 1 | 2 --- + m_or_src: str = """match x: + case 1 | 2: + pass +""" + m_or_mod: Module | CPtr = parse(m_or_src, pool) + if m_or_mod is not None: + dump(m_or_mod, dump_buf, DUMP_BUF_SIZE) + has_mo: str = string.strstr(dump_buf, "MatchOr(") + if has_mo is not None: + passed += 1 + printf("PASS: Match 1 | 2 -> MatchOr\n") + else: + failed += 1 + printf("FAIL: Match OR, mo=%d\n", has_mo is not None) + else: + failed += 1 + printf("FAIL: Match OR parse returned None\n") + + # --- Test 83: Match AS 模式 [x] as p --- + m_as_src: str = """match x: + case [x] as p: + pass +""" + m_as_mod: Module | CPtr = parse(m_as_src, pool) + if m_as_mod is not None: + dump(m_as_mod, dump_buf, DUMP_BUF_SIZE) + has_mas: str = string.strstr(dump_buf, "MatchAs(pattern=") + has_msq2: str = string.strstr(dump_buf, "MatchSequence(") + if has_mas is not None and has_msq2 is not None: + passed += 1 + printf("PASS: Match [x] as p -> MatchAs(MatchSequence)\n") + else: + failed += 1 + printf("FAIL: Match AS, mas=%d msq=%d\n", + has_mas is not None, has_msq2 is not None) + else: + failed += 1 + printf("FAIL: Match AS parse returned None\n") + + # --- Test 84: Match guard 模式 case x if x > 0 --- + m_guard_src: str = """match x: + case x if x > 0: + pass +""" + m_guard_mod: Module | CPtr = parse(m_guard_src, pool) + if m_guard_mod is not None: + dump(m_guard_mod, dump_buf, DUMP_BUF_SIZE) + has_guard: str = string.strstr(dump_buf, "guard=Compare(") + if has_guard is not None: + passed += 1 + printf("PASS: Match x if x > 0 -> guard=Compare\n") + else: + failed += 1 + printf("FAIL: Match guard, guard=%d\n", has_guard is not None) + else: + failed += 1 + printf("FAIL: Match guard parse returned None\n") + + # --- Test 85: Match 映射模式 {"k": v} --- + m_map_src: str = """match x: + case {"k": v}: + pass +""" + m_map_mod: Module | CPtr = parse(m_map_src, pool) + if m_map_mod is not None: + dump(m_map_mod, dump_buf, DUMP_BUF_SIZE) + has_mm: str = string.strstr(dump_buf, "MatchMapping(") + if has_mm is not None: + passed += 1 + printf("PASS: Match {'k': v} -> MatchMapping\n") + else: + failed += 1 + printf("FAIL: Match mapping, mm=%d\n", has_mm is not None) + else: + failed += 1 + printf("FAIL: Match mapping parse returned None\n") + + # --- Test 86: Match 映射带 rest {"k": v, **rest} --- + m_map2_src: str = """match x: + case {"k": v, **rest}: + pass +""" + m_map2_mod: Module | CPtr = parse(m_map2_src, pool) + if m_map2_mod is not None: + dump(m_map2_mod, dump_buf, DUMP_BUF_SIZE) + has_mm2: str = string.strstr(dump_buf, "MatchMapping(") + has_rest: str = string.strstr(dump_buf, "rest='rest'") + if has_mm2 is not None and has_rest is not None: + passed += 1 + printf("PASS: Match {'k': v, **rest} -> MatchMapping with rest\n") + else: + failed += 1 + printf("FAIL: Match mapping rest, mm=%d rest=%d\n", + has_mm2 is not None, has_rest is not None) + else: + failed += 1 + printf("FAIL: Match mapping rest parse returned None\n") + + # --- Test 87: Match 组合模式 (1 | 2) as p --- + m_combo_src: str = """match x: + case (1 | 2) as p: + pass +""" + m_combo_mod: Module | CPtr = parse(m_combo_src, pool) + if m_combo_mod is not None: + dump(m_combo_mod, dump_buf, DUMP_BUF_SIZE) + has_combo_or: str = string.strstr(dump_buf, "MatchOr(") + has_combo_as: str = string.strstr(dump_buf, "MatchAs(") + if has_combo_or is not None and has_combo_as is not None: + passed += 1 + printf("PASS: Match (1|2) as p -> MatchAs(MatchOr)\n") + else: + failed += 1 + printf("FAIL: Match combo, or=%d as=%d\n", + has_combo_or is not None, has_combo_as is not None) + else: + failed += 1 + printf("FAIL: Match combo parse returned None\n") + + # --- Test 88: async def --- + adef_src: str = """async def f(): + pass +""" + adef_mod: Module | CPtr = parse(adef_src, pool) + if adef_mod is not None and adef_mod.children is not None: + adef_cnt: t.CSizeT = adef_mod.children.__len__() + if adef_cnt == 1: + adef_child: AST | CPtr = adef_mod.children.get(0) + if adef_child is not None and adef_child.kind() == ASTKind.FunctionDef: + adef_fd: FunctionDef | CPtr = (FunctionDef | CPtr)(adef_child) + if (adef_fd.flags & FLAG_IS_ASYNC) != 0: + passed += 1 + printf("PASS: async def f() -> FunctionDef with FLAG_IS_ASYNC\n") + else: + failed += 1 + printf("FAIL: async def flags=%d (no FLAG_IS_ASYNC)\n", adef_fd.flags) + else: + failed += 1 + printf("FAIL: async def child kind=%d\n", + adef_child.kind() if adef_child is not None else -1) + else: + failed += 1 + printf("FAIL: async def children=%zu (expected 1)\n", adef_cnt) + else: + failed += 1 + printf("FAIL: async def parse returned None\n") + + # --- Test 89: async for (inside async def) --- + afor_src: str = """async def f(): + async for x in y: + pass +""" + afor_mod: Module | CPtr = parse(afor_src, pool) + if afor_mod is not None and afor_mod.children is not None: + afor_cnt: t.CSizeT = afor_mod.children.__len__() + if afor_cnt == 1: + afor_child: AST | CPtr = afor_mod.children.get(0) + if afor_child is not None and afor_child.kind() == ASTKind.FunctionDef: + afor_fd2: FunctionDef | CPtr = (FunctionDef | CPtr)(afor_child) + if (afor_fd2.flags & FLAG_IS_ASYNC) != 0: + if afor_fd2.children is not None: + afor_inner: AST | CPtr = afor_fd2.children.get(0) + if afor_inner is not None and afor_inner.kind() == ASTKind.For: + afor_for: For | CPtr = (For | CPtr)(afor_inner) + if (afor_for.flags & FLAG_IS_ASYNC) != 0: + passed += 1 + printf("PASS: async for -> For with FLAG_IS_ASYNC\n") + else: + failed += 1 + printf("FAIL: async for flags=%d\n", afor_for.flags) + else: + failed += 1 + printf("FAIL: async for inner kind=%d\n", + afor_inner.kind() if afor_inner is not None else -1) + else: + failed += 1 + printf("FAIL: async for no children\n") + else: + failed += 1 + printf("FAIL: async for outer def flags=%d\n", afor_fd2.flags) + else: + failed += 1 + printf("FAIL: async for outer kind=%d\n", + afor_child.kind() if afor_child is not None else -1) + else: + failed += 1 + printf("FAIL: async for children=%zu\n", afor_cnt) + else: + failed += 1 + printf("FAIL: async for parse returned None\n") + + # --- Test 90: async with (inside async def) --- + awith_src: str = """async def f(): + async with ctx: + pass +""" + awith_mod: Module | CPtr = parse(awith_src, pool) + if awith_mod is not None and awith_mod.children is not None: + awith_cnt: t.CSizeT = awith_mod.children.__len__() + if awith_cnt == 1: + awith_child: AST | CPtr = awith_mod.children.get(0) + if awith_child is not None and awith_child.kind() == ASTKind.FunctionDef: + awith_fd: FunctionDef | CPtr = (FunctionDef | CPtr)(awith_child) + if (awith_fd.flags & FLAG_IS_ASYNC) != 0: + if awith_fd.children is not None: + awith_inner: AST | CPtr = awith_fd.children.get(0) + if awith_inner is not None and awith_inner.kind() == ASTKind.With: + awith_w: With | CPtr = (With | CPtr)(awith_inner) + if (awith_w.flags & FLAG_IS_ASYNC) != 0: + passed += 1 + printf("PASS: async with -> With with FLAG_IS_ASYNC\n") + else: + failed += 1 + printf("FAIL: async with flags=%d\n", awith_w.flags) + else: + failed += 1 + printf("FAIL: async with inner kind=%d\n", + awith_inner.kind() if awith_inner is not None else -1) + else: + failed += 1 + printf("FAIL: async with no children\n") + else: + failed += 1 + printf("FAIL: async with outer def flags=%d\n", awith_fd.flags) + else: + failed += 1 + printf("FAIL: async with outer kind=%d\n", + awith_child.kind() if awith_child is not None else -1) + else: + failed += 1 + printf("FAIL: async with children=%zu\n", awith_cnt) + else: + failed += 1 + printf("FAIL: async with parse returned None\n") + + # --- Test 91: Match 复合语句 (多 case + 多类型模式) --- + m_complex_src: str = """match cmd: + case "quit": + pass + case ["go", dir]: + pass + case Point(x=0, y=0): + pass + case _: + pass +""" + m_complex_mod: Module | CPtr = parse(m_complex_src, pool) + if m_complex_mod is not None: + dump(m_complex_mod, dump_buf, DUMP_BUF_SIZE) + has_c_mv: str = string.strstr(dump_buf, "MatchValue(") + has_c_msq: str = string.strstr(dump_buf, "MatchSequence(") + has_c_mc: str = string.strstr(dump_buf, "MatchClass(") + has_c_ma: str = string.strstr(dump_buf, "MatchAs(") + if has_c_mv is not None and has_c_msq is not None and \ + has_c_mc is not None and has_c_ma is not None: + passed += 1 + printf("PASS: Match complex (4 cases) -> all pattern types\n") + else: + failed += 1 + printf("FAIL: Match complex, mv=%d msq=%d mc=%d ma=%d\n", + has_c_mv is not None, has_c_msq is not None, + has_c_mc is not None, has_c_ma is not None) + else: + failed += 1 + printf("FAIL: Match complex parse returned None\n") + + # --- Test 92: async def + async for + async with 组合 --- + acombo_src: str = """async def f(): + async with ctx: + async for x in y: + pass +""" + acombo_mod: Module | CPtr = parse(acombo_src, pool) + if acombo_mod is not None and acombo_mod.children is not None: + acombo_cnt: t.CSizeT = acombo_mod.children.__len__() + if acombo_cnt == 1: + acombo_child: AST | CPtr = acombo_mod.children.get(0) + if acombo_child is not None and acombo_child.kind() == ASTKind.FunctionDef: + acombo_fd2: FunctionDef | CPtr = (FunctionDef | CPtr)(acombo_child) + if (acombo_fd2.flags & FLAG_IS_ASYNC) != 0: + passed += 1 + printf("PASS: async def + async with + async for combo\n") + else: + failed += 1 + printf("FAIL: async combo flags=%d\n", acombo_fd2.flags) + else: + failed += 1 + printf("FAIL: async combo kind=%d\n", + acombo_child.kind() if acombo_child is not None else -1) + else: + failed += 1 + printf("FAIL: async combo children=%zu\n", acombo_cnt) + else: + failed += 1 + printf("FAIL: async combo parse returned None\n") + + # --- 结果汇总 --- + printf("\n=== Results: %d passed, %d failed ===\n", passed, failed) + + stdlib.free(dump_buf) + stdlib.free(arena) + if failed > 0: + return 1 + return 0 diff --git a/NewAstTest/project.json b/NewAstTest/project.json new file mode 100644 index 0000000..683d709 --- /dev/null +++ b/NewAstTest/project.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "NewAstTest", + "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": "NewAstTest.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 + } +} diff --git a/NoVTableCrossMixinTest/App/main.vp b/NoVTableCrossMixinTest/App/main.vp new file mode 100644 index 0000000..33729f5 --- /dev/null +++ b/NoVTableCrossMixinTest/App/main.vp @@ -0,0 +1,135 @@ +import t +import stdio +import string +import testcheck + + +# ============================================================ +# 复现:NoVTable 多继承下跨 Mixin self. 方法调用 +# +# 缺陷:BaseB.caller 内 `self.helper()`(helper 定义在兄弟 Mixin BaseA, +# 经 Combined 多继承组合)被 mangle 成 `.BaseB.helper` +# (用调用者自身/直接父类做前缀),而定义符号是 `.BaseA.helper` +# → ld.lld undefined symbol(TPV 侧 StmtGenMixin.translate_stmt 调 +# self.translate_return 同根因,符号成 StmtGenDeclMixin.translate_return)。 +# 期望:按实际定义类(BaseA)做前缀,或按最终组合类(Combined)。 +# ============================================================ +novirtual class BaseA: + a: t.CInt + + def helper(self) -> int: + return self.a + + +novirtual class BaseB: + b: t.CInt + + def caller(self) -> int: + return self.helper() + + +novirtual class Combined(BaseA, BaseB): + pass + + +def test_cross_mixin_call(): + testcheck.section("Test 1: cross-mixin self. call") + c: Combined = Combined() + c.a = 42 + c.b = 7 + testcheck.check(c.caller() == 42, + "caller()==42 (BaseB->BaseA)", + "cross-mixin call fail") + + +# ============================================================ +# 扩展 Test 2:多级 Mixin 链(父类继承 + 兄弟)+ 字段写 +# +# 覆盖 Handles 去壳核心要求: +# MixinB2 继承 MixinA2(1 级父类);Combined2(MixinB2, MixinC2) 多继承。 +# MixinC2.outer2 调兄弟 MixinB2.mid2(this_adjust 到 MixinB2 字段区), +# MixinB2.mid2 调父类 MixinA2.inner2(this_adjust 到 MixinA2 字段区), +# inner2 内写 self.a2(this_adjust 精确到组合类中 a2 字段)。 +# ============================================================ +novirtual class MixinA2: + a2: t.CInt + + def inner2(self) -> int: + self.a2 = self.a2 + 10 + return self.a2 + + +novirtual class MixinB2(MixinA2): + b2: t.CInt + + def mid2(self) -> int: + return self.inner2() + self.b2 + + +novirtual class MixinC2: + c2: t.CInt + + def outer2(self) -> int: + return self.mid2() + self.c2 + + +novirtual class Combined2(MixinB2, MixinC2): + pass + + +def test_multilevel_chain(): + testcheck.section("Test 2: multilevel mixin chain + field write") + c: Combined2 = Combined2() + c.a2 = 1 + c.b2 = 2 + c.c2 = 3 + # outer2 -> mid2 -> inner2:inner2 写 a2(1->11),mid2=11+2=13,outer2=13+3=16 + testcheck.check(c.outer2() == 16, + "outer2()==16 (C->B->A chain + field write)", + "multilevel chain fail") + + +# ============================================================ +# 扩展 Test 3:第二父类字段区偏移(this_adjust 非 0)+ 指针字段 +# +# Combined3(PtrMixin, DataMixin):PtrMixin 第一父类(字段区偏移 0), +# DataMixin 第二父类(字段区偏移 = sizeof(PtrMixin),非 0)。 +# DataMixin.get_val 内 self.val 需 this_adjust 到第二父类字段区。 +# ============================================================ +novirtual class PtrMixin: + name: t.CChar | t.CPtr + + def get_name(self) -> t.CChar | t.CPtr: + return self.name + + +novirtual class DataMixin: + val: t.CInt + + def get_val(self) -> int: + return self.val + + +novirtual class Combined3(PtrMixin, DataMixin): + pass + + +def test_second_parent_offset(): + testcheck.section("Test 3: second-parent field offset (this_adjust != 0)") + c: Combined3 = Combined3() + c.name = "hello" + c.val = 99 + testcheck.check(string.strcmp(c.get_name(), "hello") == 0, + "get_name()==hello (first parent)", + "first parent fail") + testcheck.check(c.get_val() == 99, + "get_val()==99 (second parent field offset)", + "second parent this_adjust fail") + + +def main() -> t.CInt: + testcheck.begin("NoVTableCrossMixinTest") + test_cross_mixin_call() + test_multilevel_chain() + test_second_parent_offset() + return testcheck.end() diff --git a/NoVTableCrossMixinTest/project.json b/NoVTableCrossMixinTest/project.json new file mode 100644 index 0000000..073341c --- /dev/null +++ b/NoVTableCrossMixinTest/project.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "NoVTableCrossMixinTest", + "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": "NoVTableCrossMixinTest.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 + } +} diff --git a/NoVTableTest/App/main.vp b/NoVTableTest/App/main.vp new file mode 100644 index 0000000..03e1a5d --- /dev/null +++ b/NoVTableTest/App/main.vp @@ -0,0 +1,506 @@ +import t +import stdio +import string +import testcheck +import linkedlist +import viperlib +import stdlib + + +# ============================================================ +# 子类继承 linkedlist.LinkedNode:启用链表/树形能力 +# 字段展平,无 vtable;OOP 方法通过 _generate_inherited_method_wrappers +# 自动生成子类包装(self bitcast 为父类指针后调用父类方法)。 +# 从 LinkedNode* 取回 Node* 需显式向下转型:(Node | t.CPtr)(ptr) +# ============================================================ +class Node(linkedlist.LinkedNode): + value: t.CInt + + +# ============================================================ +# 测试 1:append + child_count +# ============================================================ +def test_append(): + testcheck.section("Test 1: append") + root: Node = Node() + a: Node = Node() + b: Node = Node() + c: Node = Node() + a.value = 10 + b.value = 20 + c.value = 30 + root.append(a) + root.append(b) + root.append(c) + testcheck.check(root.child_count == 3, + "append count=3", + "append count fail") + # 验证顺序(LinkedNode* → Node* 显式向下转型) + c1: Node | t.CPtr = (Node | t.CPtr)(root.child) + c2: Node | t.CPtr = (Node | t.CPtr)(c1.next) + c3: Node | t.CPtr = (Node | t.CPtr)(c2.next) + testcheck.check(c1.value == 10 and c2.value == 20 and c3.value == 30, + "order 10,20,30", + "order fail") + + +# ============================================================ +# 测试 2:双向链表 prev 指针 +# ============================================================ +def test_prev_link(): + testcheck.section("Test 2: prev pointer (doubly linked)") + root: Node = Node() + a: Node = Node() + b: Node = Node() + a.value = 1 + b.value = 2 + root.append(a) + root.append(b) + # b.prev 应指向 a + bp: Node | t.CPtr = (Node | t.CPtr)(b.prev) + testcheck.check(bp is not None and bp.value == 1, + "b.prev.value=1", + "prev link fail") + # a.prev 应为 None(第一个子节点) + testcheck.check(a.prev is None, + "a.prev=None", + "first prev fail") + + +# ============================================================ +# 测试 3:last_child 指针(O(1) 追加验证) +# ============================================================ +def test_last_child(): + testcheck.section("Test 3: last_child pointer") + root: Node = Node() + a: Node = Node() + b: Node = Node() + a.value = 100 + b.value = 200 + root.append(a) + lc: Node | t.CPtr = (Node | t.CPtr)(root.last_child) + testcheck.check(lc is not None and lc.value == 100, + "last_child=100 after 1 append", + "last_child fail 1") + root.append(b) + lc = (Node | t.CPtr)(root.last_child) + testcheck.check(lc is not None and lc.value == 200, + "last_child=200 after 2 append", + "last_child fail 2") + + +# ============================================================ +# 测试 4:detach(O(1) 摘除) +# ============================================================ +def test_remove(): + testcheck.section("Test 4: detach (O(1) unlink)") + root: Node = Node() + a: Node = Node() + b: Node = Node() + c: Node = Node() + a.value = 1 + b.value = 2 + c.value = 3 + root.append(a) + root.append(b) + root.append(c) + # 摘除中间的 b + b.detach() + testcheck.check(root.child_count == 2, + "count=2 after detach", + "detach count fail") + # a.next 应直接指向 c + an: Node | t.CPtr = (Node | t.CPtr)(a.next) + testcheck.check(an is not None and an.value == 3, + "a.next.value=3", + "detach link fail") + # c.prev 应指向 a + cp: Node | t.CPtr = (Node | t.CPtr)(c.prev) + testcheck.check(cp is not None and cp.value == 1, + "c.prev.value=1", + "detach prev fail") + # b 的链接应清空 + testcheck.check(b.parent is None and b.next is None and b.prev is None, + "b cleared", + "b not cleared") + + +# ============================================================ +# 测试 5:remove_child +# ============================================================ +def test_remove_child(): + testcheck.section("Test 5: remove_child") + root: Node = Node() + a: Node = Node() + b: Node = Node() + a.value = 10 + b.value = 20 + root.append(a) + root.append(b) + root.remove_child(a) + testcheck.check(root.child_count == 1, + "count=1 after remove_child", + "remove_child count fail") + fc: Node | t.CPtr = (Node | t.CPtr)(root.child) + testcheck.check(fc is not None and fc.value == 20, + "first child=20", + "remove_child first fail") + + +# ============================================================ +# 测试 6:prepend + insert_before + insert_after +# ============================================================ +def test_insert_ops(): + testcheck.section("Test 6: prepend/insert_before/insert_after") + root: Node = Node() + a: Node = Node() + b: Node = Node() + c: Node = Node() + d: Node = Node() + a.value = 1 + b.value = 2 + c.value = 3 + d.value = 4 + root.append(a) # [1] + root.append(c) # [1, 3] + root.insert_before(c, b) # [1, 2, 3] 在 c 前插入 b + root.insert_after(a, d) # [1, 4, 2, 3] 在 a 后插入 d + # 遍历验证顺序 + cur: Node | t.CPtr = (Node | t.CPtr)(root.child) + v0: t.CInt = cur.value + cur = (Node | t.CPtr)(cur.next) + v1: t.CInt = cur.value + cur = (Node | t.CPtr)(cur.next) + v2: t.CInt = cur.value + cur = (Node | t.CPtr)(cur.next) + v3: t.CInt = cur.value + testcheck.check(v0 == 1 and v1 == 4 and v2 == 2 and v3 == 3, + "order 1,4,2,3", + "insert order fail") + testcheck.check(root.child_count == 4, + "count=4", + "insert count fail") + + +# ============================================================ +# 测试 7:child_at + count_children +# 注意:Viper 中 Node() 是栈分配,循环内 n 会被复用(同一地址), +# 导致所有子节点指向同一内存。必须用独立变量保证各节点地址不同。 +# ============================================================ +def test_index_access(): + testcheck.section("Test 7: child_at + count_children") + root: Node = Node() + n0: Node = Node() + n1: Node = Node() + n2: Node = Node() + n3: Node = Node() + n4: Node = Node() + n0.value = 0 + n1.value = 10 + n2.value = 20 + n3.value = 30 + n4.value = 40 + root.append(n0) + root.append(n1) + root.append(n2) + root.append(n3) + root.append(n4) + # child_at + r0: Node | t.CPtr = (Node | t.CPtr)(root.child_at(0)) + r2: Node | t.CPtr = (Node | t.CPtr)(root.child_at(2)) + r4: Node | t.CPtr = (Node | t.CPtr)(root.child_at(4)) + r5: Node | t.CPtr = (Node | t.CPtr)(root.child_at(5)) + testcheck.check(r0 is not None and r0.value == 0, + "child_at(0)=0", + "child_at 0 fail") + testcheck.check(r2 is not None and r2.value == 20, + "child_at(2)=20", + "child_at 2 fail") + testcheck.check(r4 is not None and r4.value == 40, + "child_at(4)=40", + "child_at 4 fail") + testcheck.check(r5 is None, + "child_at(5)=None", + "child_at 5 fail") + # count_children + cc: t.CSizeT = root.count_children() + testcheck.check(cc == 5, + "count_children=5", + "count_children fail") + + +# ============================================================ +# 测试 8:has_children + first_sibling/last_sibling +# ============================================================ +def test_sibling_traverse(): + testcheck.section("Test 8: has_children + sibling traverse") + root: Node = Node() + testcheck.check(root.has_children() == 0, + "empty has_children=0", + "has_children empty fail") + a: Node = Node() + b: Node = Node() + c: Node = Node() + a.value = 1 + b.value = 2 + c.value = 3 + root.append(a) + root.append(b) + root.append(c) + testcheck.check(root.has_children() == 1, + "has_children=1", + "has_children fail") + # 从 b 出发找头尾兄弟 + fs: Node | t.CPtr = (Node | t.CPtr)(b.first_sibling()) + ls: Node | t.CPtr = (Node | t.CPtr)(b.last_sibling()) + testcheck.check(fs is not None and fs.value == 1, + "first_sibling=1", + "first_sibling fail") + testcheck.check(ls is not None and ls.value == 3, + "last_sibling=3", + "last_sibling fail") + + +# ============================================================ +# 测试 9:unlink(断开所有连接) +# ============================================================ +def test_unlink(): + testcheck.section("Test 9: unlink") + root: Node = Node() + a: Node = Node() + b: Node = Node() + a.value = 1 + b.value = 2 + root.append(a) + root.append(b) + # unlink a:从兄弟链摘除 + 断开父子链接 + a.unlink() + testcheck.check(a.next is None and a.prev is None and a.parent is None, + "a links cleared", + "a links not cleared") + testcheck.check(a.child is None and a.last_child is None and a.child_count == 0, + "a child cleared", + "a child not cleared") + # root 应只剩 b + testcheck.check(root.child_count == 1, + "root count=1 after unlink", + "root count fail") + + +# ============================================================ +# 测试 10:SListNode 单向链表(OOP 方法) +# ============================================================ +class SNode(linkedlist.SListNode): + value: t.CInt + + +def test_slist(): + testcheck.section("Test 10: SListNode (singly linked, OOP)") + n0: SNode = SNode() + n1: SNode = SNode() + n2: SNode = SNode() + n0.value = 100 + n1.value = 200 + n2.value = 300 + # append (O(n)) — 直接用 n0 作为 head + head: linkedlist.SListNode | t.CPtr = n0 + head = head.append(n1) + head = head.append(n2) + # count + testcheck.check(head.count() == 3, + "count=3", + "count fail") + # at + a0: SNode | t.CPtr = (SNode | t.CPtr)(head.at(0)) + a1: SNode | t.CPtr = (SNode | t.CPtr)(head.at(1)) + a2: SNode | t.CPtr = (SNode | t.CPtr)(head.at(2)) + a3: SNode | t.CPtr = (SNode | t.CPtr)(head.at(3)) + testcheck.check(a0 is not None and a0.value == 100, + "at(0)=100", + "at 0 fail") + testcheck.check(a1 is not None and a1.value == 200, + "at(1)=200", + "at 1 fail") + testcheck.check(a2 is not None and a2.value == 300, + "at(2)=300", + "at 2 fail") + testcheck.check(a3 is None, + "at(3)=None", + "at 3 fail") + # remove (移除中间节点 n1) + head = head.remove(n1) + testcheck.check(head.count() == 2, + "after remove count=2", + "remove count fail") + testcheck.check(n1.Next is None, + "n1.Next cleared", + "n1.Next not cleared") + # 移除后 a0.Next 应指向 n2 + a0b: SNode | t.CPtr = (SNode | t.CPtr)(a0.Next) + testcheck.check(a0b is not None and a0b.value == 300, + "after remove a0.Next=300", + "a0.Next fail") + # append_after (O(1)) + n3: SNode = SNode() + n3.value = 400 + tail: linkedlist.SListNode | t.CPtr = n2.append_after(n3) + testcheck.check(tail is n3, + "append_after returns n3", + "append_after fail") + testcheck.check(head.count() == 3, + "after append count=3", + "append count fail") + + +# ============================================================ +# 测试 11:viperlib.sprintf *args 转发 +# ============================================================ +def test_sprintf_vararg(): + testcheck.section("Test 11: viperlib.sprintf *args forwarding") + # 测试 %d 单参数 + buf: t.CChar | t.CPtr = stdlib.malloc(32) + if buf is None: return + buf[0] = 0 + viperlib.sprintf(buf, "key%d", 42) + testcheck.check(string.strcmp(buf, "key42") == 0, + "sprintf key42", + "sprintf key%d fail") + # 测试无参数 + buf2: t.CChar | t.CPtr = stdlib.malloc(32) + if buf2 is None: return + buf2[0] = 0 + viperlib.sprintf(buf2, "hello") + testcheck.check(string.strcmp(buf2, "hello") == 0, + "sprintf hello", + "sprintf no-arg fail") + # 测试多参数 + buf3: t.CChar | t.CPtr = stdlib.malloc(32) + if buf3 is None: return + buf3[0] = 0 + viperlib.sprintf(buf3, "%d+%d=%d", 1, 2, 3) + testcheck.check(string.strcmp(buf3, "1+2=3") == 0, + "sprintf 1+2=3", + "sprintf multi-arg fail") + + +# ============================================================ +# 测试 12:泛型 GSListNode[T] + GSList[T] +# +# 验证 4 个技术点(为 llvmlite 简化铺路): +# 1. 递归泛型 class GNode(GSListNode[GNode]): +# 2. novirtual class + 泛型组合(GNode 无 vptr,字段展平) +# 3. 泛型类作字段类型 lst: GSList[GNode] +# 4. 泛型方法继承 lst.append(n) / lst.count() / lst.at(i) +# (GSList[T] 的方法在特化 GSList[GNode] 后可用) +# +# 注:编译器暂不支持 模块.泛型类[T]() 跨模块构造,故本地定义。 +# ============================================================ +novirtual class GSListNode[T]: + Next: T | t.CPtr + +novirtual class GSList[T]: + Head: T | t.CPtr + Tail: T | t.CPtr + Count: t.CSizeT + + def __init__(self): + self.Head = None + self.Tail = None + self.Count = 0 + + def append(self, node: T): + if node is None: return + node.Next = None + if self.Head is None: + self.Head = node + else: + self.Tail.Next = node + self.Tail = node + self.Count += 1 + + def count(self) -> t.CSizeT: + return self.Count + + def at(self, index: t.CSizeT) -> T | t.CPtr: + if self.Head is None: return None + cur: T | t.CPtr = self.Head + i: t.CSizeT = 0 + while cur is not None: + if i == index: return cur + i += 1 + cur = cur.Next + return None + + +class GNode(GSListNode[GNode]): + Value: t.CInt + + +def test_generic_slist(): + testcheck.section("Test 12: Generic GSListNode[T] + GSList[T]") + # 技术点 3: 泛型类作字段类型 + 构造 + lst: GSList[GNode] | t.CPtr = GSList[GNode]() + + # 技术点 1+2: 递归泛型 + NoVTable 组合(GNode 定义在上方) + n0: GNode = GNode() + n1: GNode = GNode() + n2: GNode = GNode() + n0.Value = 10 + n1.Value = 20 + n2.Value = 30 + + # 技术点 4: 泛型方法继承 + lst.append(n0) + lst.append(n1) + lst.append(n2) + + # count (O(1)) + testcheck.check(lst.count() == 3, + "GSList.count()=3", + "GSList count fail") + + # at (O(n)) — 返回 GNode|CPtr,无需向下转型 + a0: GNode | t.CPtr = lst.at(0) + a1: GNode | t.CPtr = lst.at(1) + a2: GNode | t.CPtr = lst.at(2) + a3: GNode | t.CPtr = lst.at(3) + testcheck.check(a0 is not None and a0.Value == 10, + "GSList.at(0)=10", + "GSList at 0 fail") + testcheck.check(a1 is not None and a1.Value == 20, + "GSList.at(1)=20", + "GSList at 1 fail") + testcheck.check(a2 is not None and a2.Value == 30, + "GSList.at(2)=30", + "GSList at 2 fail") + testcheck.check(a3 is None, + "GSList.at(3)=None", + "GSList at 3 fail") + + # Next 字段强类型(a0.Next 直接是 GNode|CPtr,无需转型) + testcheck.check(a0.Next is a1, + "a0.Next is a1 (strong type)", + "a0.Next fail") + testcheck.check(a1.Next is a2, + "a1.Next is a2 (strong type)", + "a1.Next fail") + testcheck.check(a2.Next is None, + "a2.Next is None", + "a2.Next fail") + + +def main() -> t.CInt: + testcheck.begin("NoVTableTest: linkedlist 库(@t.NoVTable OOP 方法 + 字段展平继承)") + test_append() + test_prev_link() + test_last_child() + test_remove() + test_remove_child() + test_insert_ops() + test_index_access() + test_sibling_traverse() + test_unlink() + test_slist() + test_sprintf_vararg() + test_generic_slist() + return testcheck.end() diff --git a/NoVTableTest/project.json b/NoVTableTest/project.json new file mode 100644 index 0000000..331b723 --- /dev/null +++ b/NoVTableTest/project.json @@ -0,0 +1,40 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "NoVTableTest", + "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": "NoVTableTest.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 + } +} \ No newline at end of file diff --git a/NumpyTest/App/main.vp b/NumpyTest/App/main.vp new file mode 100644 index 0000000..8db7688 --- /dev/null +++ b/NumpyTest/App/main.vp @@ -0,0 +1,11 @@ +import t, c +import testcheck +import test_numpy + + +def main() -> t.CInt | t.CExport: + testcheck.begin("NumpyTest: numpy 正确性测试") + testcheck.section("numpy Correctness Tests") + test_numpy.test_numpy_correct() + testcheck.ok("numpy 正确性测试完成") + return testcheck.end() diff --git a/NumpyTest/App/test_numpy.vp b/NumpyTest/App/test_numpy.vp new file mode 100644 index 0000000..79cc7e4 --- /dev/null +++ b/NumpyTest/App/test_numpy.vp @@ -0,0 +1,1096 @@ +from stdint import * +import numpy +from stdio import printf +from stdlib import calloc, free +import string +import math +import memhub +import w32.win32base +import t, c + +# ============================================================ +# Constants +# ============================================================ +EPS: t.CDouble = t.CDouble(1e-9) +EPS_LOOSE: t.CDouble = t.CDouble(1e-5) +SIMD_BLOCK: t.CSizeT = 4 + +# ============================================================ +# Global state +# ============================================================ +arena: t.CUInt8T | t.CPtr = None +pool: memhub.MemPool | t.CPtr = None + +test_passed: t.CInt = 0 +test_failed: t.CInt = 0 + +# ============================================================ +# Global check function +# ============================================================ +def check(name: str, condition: t.CInt, detail: str): + global test_passed, test_failed + if condition: + test_passed += 1 + printf(" [PASS] %s\n", name) + else: + test_failed += 1 + printf(" [FAIL] %s -- %s\n", name, detail if detail else "") + + +# ============================================================ +# Approximate comparison (top-level, uses vipermath.fabs) +# ============================================================ +def approx_eq(a: t.CDouble, b: t.CDouble) -> t.CInt: + d: t.CDouble = a - b + if d < t.CDouble(0.0): + d = t.CDouble(0.0) - d + if d < EPS: + return 1 + return 0 + +def approx_loose(a: t.CDouble, b: t.CDouble) -> t.CInt: + d: t.CDouble = a - b + if d < t.CDouble(0.0): + d = t.CDouble(0.0) - d + if d < EPS_LOOSE: + return 1 + return 0 + + +# ============================================================ +# Section headers +# ============================================================ +def section_header(title: str): + printf("\n+-- %s --+\n", title) + +def section_footer(): + printf("+--------------------------------------------+\n") + + +# ============================================================ +# Timer: 单调时钟(GetTickCount64 毫秒 → 秒) +# 原 c.Timer() 无编译器支持(TPC/TPV 均无),改用 Win32 API +# ============================================================ +def timer_sec() -> t.CDouble: + return t.CDouble(w32.win32base.GetTickCount64()) / t.CDouble(1000.0) + + +# ============================================================ +# Utility: quick array creation +# ============================================================ +def vec4(p: memhub.MemPool | t.CPtr, v0: t.CDouble, v1: t.CDouble, v2: t.CDouble, v3: t.CDouble) -> numpy.ndarray[t.CDouble] | t.CPtr: + a: numpy.ndarray[t.CDouble] | t.CPtr = numpy.zeros(p, 4) + a.data[0] = v0; a.data[1] = v1; a.data[2] = v2; a.data[3] = v3 + return a + +def vec3(p: memhub.MemPool | t.CPtr, v0: t.CDouble, v1: t.CDouble, v2: t.CDouble) -> numpy.ndarray[t.CDouble] | t.CPtr: + a: numpy.ndarray[t.CDouble] | t.CPtr = numpy.zeros(p, 3) + a.data[0] = v0; a.data[1] = v1; a.data[2] = v2 + return a + +def vec2(p: memhub.MemPool | t.CPtr, v0: t.CDouble, v1: t.CDouble) -> numpy.ndarray[t.CDouble] | t.CPtr: + a: numpy.ndarray[t.CDouble] | t.CPtr = numpy.zeros(p, 2) + a.data[0] = v0; a.data[1] = v1 + return a + + +# ============================================================ +# 1. Array creation +# ============================================================ +def test_zeros_ones(): + section_header("zeros / ones / full") + + a: numpy.ndarray[t.CDouble] | t.CPtr = numpy.zeros(pool, 5) + check("zeros not None", a != None, "zeros returned None") + check("zeros size == 5", a.size == 5, "size mismatch") + check("zeros [0]==0", a.data[0] == t.CDouble(0.0), "not zero") + check("zeros [4]==0", a.data[4] == t.CDouble(0.0), "not zero") + + b: numpy.ndarray[t.CDouble] | t.CPtr = numpy.ones(pool, 4) + check("ones not None", b != None, "ones returned None") + check("ones [0]==1", b.data[0] == t.CDouble(1.0), "not one") + check("ones [3]==1", b.data[3] == t.CDouble(1.0), "not one") + + c: numpy.ndarray[t.CDouble] | t.CPtr = numpy.full(pool, 3, t.CDouble(7.5)) + check("full not None", c != None, "full returned None") + check("full value", c.data[0] == t.CDouble(7.5), "value mismatch") + + a.delete() + b.delete() + c.delete() + section_footer() + + +def test_arange_linspace(): + section_header("arange / linspace") + + a: numpy.ndarray[t.CDouble] | t.CPtr = numpy.arange(pool, t.CDouble(0.0), t.CDouble(5.0), t.CDouble(1.0)) + check("arange not None", a != None, "arange returned None") + check("arange size == 5", a.size == 5, "size mismatch") + check("arange [0]==0", approx_eq(a.data[0], t.CDouble(0.0)), "mismatch") + check("arange [4]==4", approx_eq(a.data[4], t.CDouble(4.0)), "mismatch") + + b: numpy.ndarray[t.CDouble] | t.CPtr = numpy.linspace(pool, t.CDouble(0.0), t.CDouble(1.0), 5) + check("linspace not None", b != None, "linspace returned None") + check("linspace size == 5", b.size == 5, "size mismatch") + check("linspace [0]==0", approx_eq(b.data[0], t.CDouble(0.0)), "mismatch") + check("linspace [4]==1", approx_eq(b.data[4], t.CDouble(1.0)), "mismatch") + + a.delete() + b.delete() + section_footer() + + +def test_eye_diag(): + section_header("eye / diag") + + e: numpy.ndarray[t.CDouble] | t.CPtr = numpy.eye(pool, 3) + check("eye not None", e != None, "eye returned None") + check("eye ndim == 2", e.ndim == 2, "ndim mismatch") + check("eye [0,0]==1", e.at2d(0, 0) == t.CDouble(1.0), "mismatch") + check("eye [0,1]==0", e.at2d(0, 1) == t.CDouble(0.0), "mismatch") + check("eye [1,1]==1", e.at2d(1, 1) == t.CDouble(1.0), "mismatch") + + vals: numpy.ndarray[t.CDouble] | t.CPtr = vec3(pool, t.CDouble(1.0), t.CDouble(2.0), t.CDouble(3.0)) + d: numpy.ndarray[t.CDouble] | t.CPtr = numpy.diag(pool, vals) + check("diag not None", d != None, "diag returned None") + check("diag [0,0]==1", d.at2d(0, 0) == t.CDouble(1.0), "mismatch") + check("diag [1,1]==2", d.at2d(1, 1) == t.CDouble(2.0), "mismatch") + check("diag [2,2]==3", d.at2d(2, 2) == t.CDouble(3.0), "mismatch") + + e.delete() + vals.delete() + d.delete() + section_footer() + + +# ============================================================ +# 2. Methods +# ============================================================ +def test_sum_mean_min_max(): + section_header("sum / mean / min / max / argmax / argmin") + + a: numpy.ndarray[t.CDouble] | t.CPtr = numpy.arange(pool, t.CDouble(1.0), t.CDouble(6.0), t.CDouble(1.0)) + check("sum == 15", approx_eq(a.sum(), t.CDouble(15.0)), "mismatch") + check("mean == 3", approx_eq(a.mean(), t.CDouble(3.0)), "mismatch") + check("min == 1", approx_eq(a.min(), t.CDouble(1.0)), "mismatch") + check("max == 5", approx_eq(a.max(), t.CDouble(5.0)), "mismatch") + check("argmax == 4", a.argmax() == 4, "mismatch") + check("argmin == 0", a.argmin() == 0, "mismatch") + + a.delete() + section_footer() + + +def test_fill_copy(): + section_header("fill / copy") + + a: numpy.ndarray[t.CDouble] | t.CPtr = numpy.zeros(pool, 3) + a.fill(t.CDouble(9.0)) + check("fill [0]==9", a.data[0] == t.CDouble(9.0), "mismatch") + check("fill [2]==9", a.data[2] == t.CDouble(9.0), "mismatch") + + b: numpy.ndarray[t.CDouble] | t.CPtr = a.copy() + check("copy not None", b != None, "copy returned None") + check("copy [0]==9", b.data[0] == t.CDouble(9.0), "mismatch") + + b.data[0] = t.CDouble(0.0) + check("copy is independent", a.data[0] == t.CDouble(9.0), "copy not independent") + + a.delete() + b.delete() + section_footer() + + +# ============================================================ +# 3. Operator overloading +# ============================================================ +def test_add_sub_mul_div(): + section_header("__add__ / __sub__ / __mul__ / __truediv__") + + a: numpy.ndarray[t.CDouble] | t.CPtr = vec3(pool, t.CDouble(1.0), t.CDouble(2.0), t.CDouble(3.0)) + b: numpy.ndarray[t.CDouble] | t.CPtr = vec3(pool, t.CDouble(4.0), t.CDouble(5.0), t.CDouble(6.0)) + + c_add: numpy.ndarray[t.CDouble] | t.CPtr = a + b + check("a+b not None", c_add != None, "add returned None") + check("a+b [0]==5", c_add.data[0] == t.CDouble(5.0), "mismatch") + check("a+b [2]==9", c_add.data[2] == t.CDouble(9.0), "mismatch") + + c_sub: numpy.ndarray[t.CDouble] | t.CPtr = a - b + check("a-b [0]==-3", c_sub.data[0] == t.CDouble(-3.0), "mismatch") + + c_mul: numpy.ndarray[t.CDouble] | t.CPtr = a * b + check("a*b [1]==10", c_mul.data[1] == t.CDouble(10.0), "mismatch") + + c_div: numpy.ndarray[t.CDouble] | t.CPtr = b / a + check("b/a [0]==4", c_div.data[0] == t.CDouble(4.0), "mismatch") + check("b/a [2]==2", c_div.data[2] == t.CDouble(2.0), "mismatch") + + a.delete() + b.delete() + c_add.delete() + c_sub.delete() + c_mul.delete() + c_div.delete() + section_footer() + + +def test_neg(): + section_header("__neg__") + + a: numpy.ndarray[t.CDouble] | t.CPtr = vec3(pool, t.CDouble(1.0), t.CDouble(-2.0), t.CDouble(3.0)) + neg_a: numpy.ndarray[t.CDouble] | t.CPtr = -a + check("neg not None", neg_a != None, "neg returned None") + check("neg [0]==-1", neg_a.data[0] == t.CDouble(-1.0), "mismatch") + check("neg [1]==2", neg_a.data[1] == t.CDouble(2.0), "mismatch") + + a.delete() + neg_a.delete() + section_footer() + + +def test_len(): + section_header("__len__") + + a: numpy.ndarray[t.CDouble] | t.CPtr = numpy.zeros(pool, 10) + check("len == 10", len(a) == 10, "mismatch") + + a.delete() + section_footer() + + +# ============================================================ +# 4. Scalar operations +# ============================================================ +def test_scalar_ops(): + section_header("add_scalar / mul_scalar / sub_scalar / div_scalar") + + a: numpy.ndarray[t.CDouble] | t.CPtr = numpy.ones(pool, 3) + + r1: numpy.ndarray[t.CDouble] | t.CPtr = numpy.add_scalar(a, t.CDouble(2.0)) + check("add_scalar [0]==3", r1.data[0] == t.CDouble(3.0), "mismatch") + + r2: numpy.ndarray[t.CDouble] | t.CPtr = numpy.mul_scalar(a, t.CDouble(5.0)) + check("mul_scalar [0]==5", r2.data[0] == t.CDouble(5.0), "mismatch") + + r3: numpy.ndarray[t.CDouble] | t.CPtr = numpy.sub_scalar(a, t.CDouble(0.5)) + check("sub_scalar [0]==0.5", r3.data[0] == t.CDouble(0.5), "mismatch") + + r4: numpy.ndarray[t.CDouble] | t.CPtr = numpy.div_scalar(a, t.CDouble(2.0)) + check("div_scalar [0]==0.5", r4.data[0] == t.CDouble(0.5), "mismatch") + + a.delete() + r1.delete() + r2.delete() + r3.delete() + r4.delete() + section_footer() + + +# ============================================================ +# 5. Math functions +# ============================================================ +def test_math_funcs(): + section_header("np_abs / np_sqrt / np_pow") + + a: numpy.ndarray[t.CDouble] | t.CPtr = vec3(pool, t.CDouble(1.0), t.CDouble(4.0), t.CDouble(9.0)) + + r_sqrt: numpy.ndarray[t.CDouble] | t.CPtr = numpy.np_sqrt(a) + check("sqrt [0]==1", approx_eq(r_sqrt.data[0], t.CDouble(1.0)), "mismatch") + check("sqrt [1]==2", approx_eq(r_sqrt.data[1], t.CDouble(2.0)), "mismatch") + check("sqrt [2]==3", approx_eq(r_sqrt.data[2], t.CDouble(3.0)), "mismatch") + + b: numpy.ndarray[t.CDouble] | t.CPtr = vec3(pool, t.CDouble(-1.0), t.CDouble(-4.0), t.CDouble(9.0)) + r_abs: numpy.ndarray[t.CDouble] | t.CPtr = numpy.np_abs(b) + check("abs [0]==1", approx_eq(r_abs.data[0], t.CDouble(1.0)), "mismatch") + check("abs [1]==4", approx_eq(r_abs.data[1], t.CDouble(4.0)), "mismatch") + + c: numpy.ndarray[t.CDouble] | t.CPtr = vec3(pool, t.CDouble(1.0), t.CDouble(2.0), t.CDouble(3.0)) + r_pow: numpy.ndarray[t.CDouble] | t.CPtr = numpy.np_pow(c, t.CDouble(2.0)) + check("pow [0]==1", approx_eq(r_pow.data[0], t.CDouble(1.0)), "mismatch") + check("pow [1]==4", approx_eq(r_pow.data[1], t.CDouble(4.0)), "mismatch") + check("pow [2]==9", approx_eq(r_pow.data[2], t.CDouble(9.0)), "mismatch") + + a.delete() + b.delete() + c.delete() + r_sqrt.delete() + r_abs.delete() + r_pow.delete() + section_footer() + + +# ============================================================ +# 6. Matrix operations +# ============================================================ +def test_matmul(): + section_header("matmul") + + # [1,2;3,4] x [5,6;7,8] = [19,22;43,50] + a: numpy.ndarray[t.CDouble] | t.CPtr = numpy.empty2d(pool, 2, 2) + a.set2d(0, 0, t.CDouble(1.0)); a.set2d(0, 1, t.CDouble(2.0)) + a.set2d(1, 0, t.CDouble(3.0)); a.set2d(1, 1, t.CDouble(4.0)) + + b: numpy.ndarray[t.CDouble] | t.CPtr = numpy.empty2d(pool, 2, 2) + b.set2d(0, 0, t.CDouble(5.0)); b.set2d(0, 1, t.CDouble(6.0)) + b.set2d(1, 0, t.CDouble(7.0)); b.set2d(1, 1, t.CDouble(8.0)) + + c: numpy.ndarray[t.CDouble] | t.CPtr = numpy.matmul(a, b) + check("matmul not None", c != None, "matmul returned None") + check("matmul [0,0]==19", c.at2d(0, 0) == t.CDouble(19.0), "mismatch") + check("matmul [0,1]==22", c.at2d(0, 1) == t.CDouble(22.0), "mismatch") + check("matmul [1,0]==43", c.at2d(1, 0) == t.CDouble(43.0), "mismatch") + check("matmul [1,1]==50", c.at2d(1, 1) == t.CDouble(50.0), "mismatch") + + a.delete() + b.delete() + c.delete() + section_footer() + + +def test_dot(): + section_header("dot / dot_product") + + a: numpy.ndarray[t.CDouble] | t.CPtr = vec3(pool, t.CDouble(1.0), t.CDouble(2.0), t.CDouble(3.0)) + b: numpy.ndarray[t.CDouble] | t.CPtr = vec3(pool, t.CDouble(4.0), t.CDouble(5.0), t.CDouble(6.0)) + + d: t.CDouble = a.dot(b) + check("dot == 32", approx_eq(d, t.CDouble(32.0)), "mismatch") + + d2: t.CDouble = numpy.dot_product(a, b) + check("dot_product == 32", approx_eq(d2, t.CDouble(32.0)), "mismatch") + + a.delete() + b.delete() + section_footer() + + +def test_transpose(): + section_header("T (transpose)") + + a: numpy.ndarray[t.CDouble] | t.CPtr = numpy.empty2d(pool, 2, 3) + a.set2d(0, 0, t.CDouble(1.0)); a.set2d(0, 1, t.CDouble(2.0)); a.set2d(0, 2, t.CDouble(3.0)) + a.set2d(1, 0, t.CDouble(4.0)); a.set2d(1, 1, t.CDouble(5.0)); a.set2d(1, 2, t.CDouble(6.0)) + + at: numpy.ndarray[t.CDouble] | t.CPtr = a.T() + check("T not None", at != None, "T returned None") + check("T shape[0]==3", at.shape[0] == 3, "shape mismatch") + check("T shape[1]==2", at.shape[1] == 2, "shape mismatch") + check("T [0,0]==1", at.at2d(0, 0) == t.CDouble(1.0), "mismatch") + check("T [0,1]==4", at.at2d(0, 1) == t.CDouble(4.0), "mismatch") + check("T [1,0]==2", at.at2d(1, 0) == t.CDouble(2.0), "mismatch") + + a.delete() + at.delete() + section_footer() + + +# ============================================================ +# 7. Utility +# ============================================================ +def test_var_std_norm(): + section_header("var / std / norm") + + # [2,4,4,4,5,5,7,9] mean=5, var=4, std=2 + a: numpy.ndarray[t.CDouble] | t.CPtr = numpy.zeros(pool, 8) + a.data[0] = t.CDouble(2.0); a.data[1] = t.CDouble(4.0) + a.data[2] = t.CDouble(4.0); a.data[3] = t.CDouble(4.0) + a.data[4] = t.CDouble(5.0); a.data[5] = t.CDouble(5.0) + a.data[6] = t.CDouble(7.0); a.data[7] = t.CDouble(9.0) + + v: t.CDouble = numpy.var(a) + printf(" var = %.6f (expect 4.0)\n", v) + check("var ~= 4", approx_eq(v, t.CDouble(4.0)), "mismatch") + + s: t.CDouble = numpy.std(a) + printf(" std = %.6f (expect 2.0)\n", s) + check("std ~= 2", approx_eq(s, t.CDouble(2.0)), "mismatch") + + b: numpy.ndarray[t.CDouble] | t.CPtr = vec2(pool, t.CDouble(3.0), t.CDouble(4.0)) + n: t.CDouble = numpy.norm(b) + printf(" norm = %.6f (expect 5.0)\n", n) + check("norm ~= 5", approx_eq(n, t.CDouble(5.0)), "mismatch") + + a.delete() + b.delete() + section_footer() + + +def test_clip_concatenate(): + section_header("clip / concatenate") + + a: numpy.ndarray[t.CDouble] | t.CPtr = vec3(pool, t.CDouble(1.0), t.CDouble(5.0), t.CDouble(10.0)) + r: numpy.ndarray[t.CDouble] | t.CPtr = numpy.clip(a, t.CDouble(2.0), t.CDouble(8.0)) + check("clip [0]==2", r.data[0] == t.CDouble(2.0), "mismatch") + check("clip [1]==5", r.data[1] == t.CDouble(5.0), "mismatch") + check("clip [2]==8", r.data[2] == t.CDouble(8.0), "mismatch") + + b: numpy.ndarray[t.CDouble] | t.CPtr = vec2(pool, t.CDouble(1.0), t.CDouble(2.0)) + c: numpy.ndarray[t.CDouble] | t.CPtr = vec2(pool, t.CDouble(3.0), t.CDouble(4.0)) + cat: numpy.ndarray[t.CDouble] | t.CPtr = numpy.concatenate(b, c) + check("concatenate not None", cat != None, "concatenate returned None") + check("concatenate size == 4", cat.size == 4, "size mismatch") + check("concatenate [0]==1", cat.data[0] == t.CDouble(1.0), "mismatch") + check("concatenate [3]==4", cat.data[3] == t.CDouble(4.0), "mismatch") + + a.delete() + r.delete() + b.delete() + c.delete() + cat.delete() + section_footer() + + +def test_sort_reverse(): + section_header("sort_arr / reverse") + + a: numpy.ndarray[t.CDouble] | t.CPtr = vec3(pool, t.CDouble(3.0), t.CDouble(1.0), t.CDouble(2.0)) + s: numpy.ndarray[t.CDouble] | t.CPtr = numpy.sort_arr(a) + check("sort not None", s != None, "sort returned None") + check("sort [0]==1", s.data[0] == t.CDouble(1.0), "mismatch") + check("sort [1]==2", s.data[1] == t.CDouble(2.0), "mismatch") + check("sort [2]==3", s.data[2] == t.CDouble(3.0), "mismatch") + + r: numpy.ndarray[t.CDouble] | t.CPtr = numpy.reverse(a) + check("reverse not None", r != None, "reverse returned None") + check("reverse [0]==2", r.data[0] == t.CDouble(2.0), "mismatch") + check("reverse [1]==1", r.data[1] == t.CDouble(1.0), "mismatch") + check("reverse [2]==3", r.data[2] == t.CDouble(3.0), "mismatch") + + a.delete() + s.delete() + r.delete() + section_footer() + + +def test_print_arr(): + section_header("print_arr") + + a: numpy.ndarray[t.CDouble] | t.CPtr = vec3(pool, t.CDouble(1.0), t.CDouble(2.0), t.CDouble(3.0)) + printf(" 1D array: ") + a.print_arr() + + b: numpy.ndarray[t.CDouble] | t.CPtr = numpy.eye(pool, 3) + printf(" 2D eye(3):\n") + b.print_arr() + + a.delete() + b.delete() + section_footer() + + +# ============================================================ +# 8. Additional operator overloading +# ============================================================ +def test_floordiv_mod(): + section_header("__floordiv__ / __mod__") + + a: numpy.ndarray[t.CDouble] | t.CPtr = vec3(pool, t.CDouble(7.0), t.CDouble(10.0), t.CDouble(15.0)) + b: numpy.ndarray[t.CDouble] | t.CPtr = vec3(pool, t.CDouble(2.0), t.CDouble(3.0), t.CDouble(4.0)) + + c_fd: numpy.ndarray[t.CDouble] | t.CPtr = a // b + check("7//2==3", c_fd.data[0] == t.CDouble(3.0), "mismatch") + check("10//3==3", c_fd.data[1] == t.CDouble(3.0), "mismatch") + check("15//4==3", c_fd.data[2] == t.CDouble(3.0), "mismatch") + + c_mod: numpy.ndarray[t.CDouble] | t.CPtr = a % b + check("7%%2==1", c_mod.data[0] == t.CDouble(1.0), "mismatch") + check("10%%3==1", c_mod.data[1] == t.CDouble(1.0), "mismatch") + check("15%%4==3", c_mod.data[2] == t.CDouble(3.0), "mismatch") + + a.delete() + b.delete() + c_fd.delete() + c_mod.delete() + section_footer() + + +# ============================================================ +# 9. Additional math functions +# ============================================================ +def test_additional_math(): + section_header("np_log10 / np_log2 / np_floor / np_ceil / np_round / np_sign") + + a: numpy.ndarray[t.CDouble] | t.CPtr = vec3(pool, t.CDouble(10.0), t.CDouble(100.0), t.CDouble(1000.0)) + r_log10: numpy.ndarray[t.CDouble] | t.CPtr = numpy.np_log10(a) + check("log10(10)~=1", approx_loose(r_log10.data[0], t.CDouble(1.0)), "mismatch") + check("log10(100)~=2", approx_loose(r_log10.data[1], t.CDouble(2.0)), "mismatch") + + b: numpy.ndarray[t.CDouble] | t.CPtr = vec3(pool, t.CDouble(2.0), t.CDouble(4.0), t.CDouble(8.0)) + r_log2: numpy.ndarray[t.CDouble] | t.CPtr = numpy.np_log2(b) + check("log2(2)~=1", approx_loose(r_log2.data[0], t.CDouble(1.0)), "mismatch") + check("log2(4)~=2", approx_loose(r_log2.data[1], t.CDouble(2.0)), "mismatch") + + c: numpy.ndarray[t.CDouble] | t.CPtr = vec3(pool, t.CDouble(1.5), t.CDouble(2.7), t.CDouble(-1.3)) + r_floor: numpy.ndarray[t.CDouble] | t.CPtr = numpy.np_floor(c) + check("floor(1.5)==1", r_floor.data[0] == t.CDouble(1.0), "mismatch") + check("floor(2.7)==2", r_floor.data[1] == t.CDouble(2.0), "mismatch") + check("floor(-1.3)==-2", r_floor.data[2] == t.CDouble(-2.0), "mismatch") + + r_ceil: numpy.ndarray[t.CDouble] | t.CPtr = numpy.np_ceil(c) + check("ceil(1.5)==2", r_ceil.data[0] == t.CDouble(2.0), "mismatch") + check("ceil(2.7)==3", r_ceil.data[1] == t.CDouble(3.0), "mismatch") + check("ceil(-1.3)==-1", r_ceil.data[2] == t.CDouble(-1.0), "mismatch") + + d: numpy.ndarray[t.CDouble] | t.CPtr = vec3(pool, t.CDouble(1.4), t.CDouble(2.5), t.CDouble(3.6)) + r_round: numpy.ndarray[t.CDouble] | t.CPtr = numpy.np_round(d) + check("round(1.4)==1", r_round.data[0] == t.CDouble(1.0), "mismatch") + check("round(3.6)==4", r_round.data[2] == t.CDouble(4.0), "mismatch") + + e: numpy.ndarray[t.CDouble] | t.CPtr = numpy.zeros(pool, 4) + e.data[0] = t.CDouble(-3.0); e.data[1] = t.CDouble(0.0); e.data[2] = t.CDouble(5.0); e.data[3] = t.CDouble(-0.1) + r_sign: numpy.ndarray[t.CDouble] | t.CPtr = numpy.np_sign(e) + check("sign(-3)==-1", r_sign.data[0] == t.CDouble(-1.0), "mismatch") + check("sign(0)==0", r_sign.data[1] == t.CDouble(0.0), "mismatch") + check("sign(5)==1", r_sign.data[2] == t.CDouble(1.0), "mismatch") + + a.delete() + b.delete() + c.delete() + d.delete() + e.delete() + r_log10.delete() + r_log2.delete() + r_floor.delete() + r_ceil.delete() + r_round.delete() + r_sign.delete() + section_footer() + + +def test_trig_hyperbolic(): + section_header("np_tanh / np_sinh / np_cosh / np_arcsin / np_arccos / np_arctan") + + a: numpy.ndarray[t.CDouble] | t.CPtr = vec3(pool, t.CDouble(0.0), t.CDouble(1.0), t.CDouble(-1.0)) + + r_tanh: numpy.ndarray[t.CDouble] | t.CPtr = numpy.np_tanh(a) + check("tanh(0)~=0", approx_loose(r_tanh.data[0], t.CDouble(0.0)), "mismatch") + + r_sinh: numpy.ndarray[t.CDouble] | t.CPtr = numpy.np_sinh(a) + check("sinh(0)~=0", approx_loose(r_sinh.data[0], t.CDouble(0.0)), "mismatch") + + r_cosh: numpy.ndarray[t.CDouble] | t.CPtr = numpy.np_cosh(a) + check("cosh(0)~=1", approx_loose(r_cosh.data[0], t.CDouble(1.0)), "mismatch") + + b: numpy.ndarray[t.CDouble] | t.CPtr = vec2(pool, t.CDouble(0.0), t.CDouble(0.5)) + r_asin: numpy.ndarray[t.CDouble] | t.CPtr = numpy.np_arcsin(b) + check("arcsin(0)~=0", approx_loose(r_asin.data[0], t.CDouble(0.0)), "mismatch") + + r_acos: numpy.ndarray[t.CDouble] | t.CPtr = numpy.np_arccos(b) + check("arccos(0)~=pi/2", approx_loose(r_acos.data[0], t.CDouble(1.5707963)), "mismatch") + + r_atan: numpy.ndarray[t.CDouble] | t.CPtr = numpy.np_arctan(b) + check("arctan(0)~=0", approx_loose(r_atan.data[0], t.CDouble(0.0)), "mismatch") + + a.delete() + b.delete() + r_tanh.delete() + r_sinh.delete() + r_cosh.delete() + r_asin.delete() + r_acos.delete() + r_atan.delete() + section_footer() + + +def test_degrees_radians(): + section_header("np_degrees / np_radians") + + a: numpy.ndarray[t.CDouble] | t.CPtr = vec2(pool, t.CDouble(0.0), t.CDouble(1.5707963267948966)) + + r_deg: numpy.ndarray[t.CDouble] | t.CPtr = numpy.np_degrees(a) + check("deg(0)~=0", approx_loose(r_deg.data[0], t.CDouble(0.0)), "mismatch") + check("deg(pi/2)~=90", approx_loose(r_deg.data[1], t.CDouble(90.0)), "mismatch") + + b: numpy.ndarray[t.CDouble] | t.CPtr = vec2(pool, t.CDouble(0.0), t.CDouble(90.0)) + r_rad: numpy.ndarray[t.CDouble] | t.CPtr = numpy.np_radians(b) + check("rad(0)~=0", approx_loose(r_rad.data[0], t.CDouble(0.0)), "mismatch") + check("rad(90)~=pi/2", approx_loose(r_rad.data[1], t.CDouble(1.5707963)), "mismatch") + + a.delete() + b.delete() + r_deg.delete() + r_rad.delete() + section_footer() + + +# ============================================================ +# 10. Additional array operations +# ============================================================ +def test_cumsum_diff(): + section_header("cumsum / diff") + + a: numpy.ndarray[t.CDouble] | t.CPtr = numpy.zeros(pool, 4) + a.data[0] = t.CDouble(1.0); a.data[1] = t.CDouble(2.0); a.data[2] = t.CDouble(3.0); a.data[3] = t.CDouble(4.0) + + r_cs: numpy.ndarray[t.CDouble] | t.CPtr = numpy.cumsum(a) + check("cumsum not None", r_cs != None, "cumsum returned None") + check("cumsum[0]==1", r_cs.data[0] == t.CDouble(1.0), "mismatch") + check("cumsum[1]==3", r_cs.data[1] == t.CDouble(3.0), "mismatch") + check("cumsum[2]==6", r_cs.data[2] == t.CDouble(6.0), "mismatch") + check("cumsum[3]==10", r_cs.data[3] == t.CDouble(10.0), "mismatch") + + r_diff: numpy.ndarray[t.CDouble] | t.CPtr = numpy.diff(a) + check("diff not None", r_diff != None, "diff returned None") + check("diff size==3", r_diff.size == 3, "size mismatch") + check("diff[0]==1", r_diff.data[0] == t.CDouble(1.0), "mismatch") + check("diff[2]==1", r_diff.data[2] == t.CDouble(1.0), "mismatch") + + a.delete() + r_cs.delete() + r_diff.delete() + section_footer() + + +def test_max_min_where(): + section_header("np_maximum / np_minimum / np_where") + + a: numpy.ndarray[t.CDouble] | t.CPtr = vec3(pool, t.CDouble(1.0), t.CDouble(5.0), t.CDouble(3.0)) + b: numpy.ndarray[t.CDouble] | t.CPtr = vec3(pool, t.CDouble(4.0), t.CDouble(2.0), t.CDouble(6.0)) + + r_max: numpy.ndarray[t.CDouble] | t.CPtr = numpy.np_maximum(a, b) + check("maximum[0]==4", r_max.data[0] == t.CDouble(4.0), "mismatch") + check("maximum[1]==5", r_max.data[1] == t.CDouble(5.0), "mismatch") + check("maximum[2]==6", r_max.data[2] == t.CDouble(6.0), "mismatch") + + r_min: numpy.ndarray[t.CDouble] | t.CPtr = numpy.np_minimum(a, b) + check("minimum[0]==1", r_min.data[0] == t.CDouble(1.0), "mismatch") + check("minimum[1]==2", r_min.data[1] == t.CDouble(2.0), "mismatch") + check("minimum[2]==3", r_min.data[2] == t.CDouble(3.0), "mismatch") + + # where: cond > 0 ? a : b + cond: numpy.ndarray[t.CDouble] | t.CPtr = vec3(pool, t.CDouble(0.0), t.CDouble(1.0), t.CDouble(0.0)) + r_where: numpy.ndarray[t.CDouble] | t.CPtr = numpy.np_where(cond, a, b) + check("where[0]==4", r_where.data[0] == t.CDouble(4.0), "mismatch") + check("where[1]==5", r_where.data[1] == t.CDouble(5.0), "mismatch") + check("where[2]==6", r_where.data[2] == t.CDouble(6.0), "mismatch") + + a.delete() + b.delete() + cond.delete() + r_max.delete() + r_min.delete() + r_where.delete() + section_footer() + + +def test_flatten_trace(): + section_header("flatten / trace") + + a: numpy.ndarray[t.CDouble] | t.CPtr = numpy.empty2d(pool, 2, 3) + a.set2d(0, 0, t.CDouble(1.0)); a.set2d(0, 1, t.CDouble(2.0)); a.set2d(0, 2, t.CDouble(3.0)) + a.set2d(1, 0, t.CDouble(4.0)); a.set2d(1, 1, t.CDouble(5.0)); a.set2d(1, 2, t.CDouble(6.0)) + + r_flat: numpy.ndarray[t.CDouble] | t.CPtr = numpy.flatten(a) + check("flatten not None", r_flat != None, "flatten returned None") + check("flatten ndim==1", r_flat.ndim == 1, "ndim mismatch") + check("flatten size==6", r_flat.size == 6, "size mismatch") + check("flatten[0]==1", r_flat.data[0] == t.CDouble(1.0), "mismatch") + + # trace of [[1,2],[3,4]] = 1+4 = 5 + b: numpy.ndarray[t.CDouble] | t.CPtr = numpy.empty2d(pool, 2, 2) + b.set2d(0, 0, t.CDouble(1.0)); b.set2d(0, 1, t.CDouble(2.0)) + b.set2d(1, 0, t.CDouble(3.0)); b.set2d(1, 1, t.CDouble(4.0)) + tr: t.CDouble = numpy.trace(b) + check("trace == 5", tr == t.CDouble(5.0), "mismatch") + + a.delete() + r_flat.delete() + b.delete() + section_footer() + + +def test_outer(): + section_header("outer") + + a: numpy.ndarray[t.CDouble] | t.CPtr = vec2(pool, t.CDouble(1.0), t.CDouble(2.0)) + b: numpy.ndarray[t.CDouble] | t.CPtr = vec3(pool, t.CDouble(3.0), t.CDouble(4.0), t.CDouble(5.0)) + + r: numpy.ndarray[t.CDouble] | t.CPtr = numpy.outer(a, b) + check("outer not None", r != None, "outer returned None") + check("outer ndim==2", r.ndim == 2, "ndim mismatch") + check("outer[0,0]==3", r.at2d(0, 0) == t.CDouble(3.0), "mismatch") + check("outer[0,1]==4", r.at2d(0, 1) == t.CDouble(4.0), "mismatch") + check("outer[1,0]==6", r.at2d(1, 0) == t.CDouble(6.0), "mismatch") + check("outer[1,2]==10", r.at2d(1, 2) == t.CDouble(10.0), "mismatch") + + a.delete() + b.delete() + r.delete() + section_footer() + + +# ============================================================ +# 11. Boolean / comparison +# ============================================================ +def test_bool_comparison(): + section_header("np_all / np_any / np_count_nonzero / np_equal / np_less / np_greater") + + a: numpy.ndarray[t.CDouble] | t.CPtr = numpy.zeros(pool, 4) + a.data[0] = t.CDouble(1.0); a.data[1] = t.CDouble(0.0); a.data[2] = t.CDouble(3.0); a.data[3] = t.CDouble(0.0) + check("count_nonzero==2", numpy.np_count_nonzero(a) == 2, "mismatch") + check("any==1", numpy.np_any(a) == 1, "mismatch") + + b: numpy.ndarray[t.CDouble] | t.CPtr = vec3(pool, t.CDouble(1.0), t.CDouble(2.0), t.CDouble(3.0)) + check("all(1,2,3)==1", numpy.np_all(b) == 1, "mismatch") + + c: numpy.ndarray[t.CDouble] | t.CPtr = numpy.zeros(pool, 3) + check("all(0,0,0)==0", numpy.np_all(c) == 0, "mismatch") + check("any(0,0,0)==0", numpy.np_any(c) == 0, "mismatch") + + d: numpy.ndarray[t.CDouble] | t.CPtr = vec3(pool, t.CDouble(1.0), t.CDouble(2.0), t.CDouble(3.0)) + e: numpy.ndarray[t.CDouble] | t.CPtr = vec3(pool, t.CDouble(1.0), t.CDouble(0.0), t.CDouble(4.0)) + + r_eq: numpy.ndarray[t.CDouble] | t.CPtr = numpy.np_equal(d, e) + check("equal[0]==1", r_eq.data[0] == t.CDouble(1.0), "mismatch") + check("equal[1]==0", r_eq.data[1] == t.CDouble(0.0), "mismatch") + + r_lt: numpy.ndarray[t.CDouble] | t.CPtr = numpy.np_less(d, e) + check("less[2]==1", r_lt.data[2] == t.CDouble(1.0), "mismatch") + check("less[0]==0", r_lt.data[0] == t.CDouble(0.0), "mismatch") + + r_gt: numpy.ndarray[t.CDouble] | t.CPtr = numpy.np_greater(d, e) + check("greater[1]==1", r_gt.data[1] == t.CDouble(1.0), "mismatch") + + a.delete() + b.delete() + c.delete() + d.delete() + e.delete() + r_eq.delete() + r_lt.delete() + r_gt.delete() + section_footer() + + +# ============================================================ +# 12. Linear algebra +# ============================================================ +def test_linalg(): + section_header("det2x2 / inv2x2 / cross3 / prod / median / percentile") + + # det2x2: [[1,2],[3,4]] -> 1*4-2*3 = -2 + a: numpy.ndarray[t.CDouble] | t.CPtr = numpy.empty2d(pool, 2, 2) + a.set2d(0, 0, t.CDouble(1.0)); a.set2d(0, 1, t.CDouble(2.0)) + a.set2d(1, 0, t.CDouble(3.0)); a.set2d(1, 1, t.CDouble(4.0)) + d: t.CDouble = numpy.det2x2(a) + check("det2x2==-2", d == t.CDouble(-2.0), "mismatch") + + # inv2x2 of [[1,2],[3,4]] + inv: numpy.ndarray[t.CDouble] | t.CPtr = numpy.inv2x2(a) + check("inv2x2 not None", inv != None, "inv2x2 returned None") + check("inv[0,0]==-2", approx_eq(inv.at2d(0, 0), t.CDouble(-2.0)), "mismatch") + check("inv[0,1]==1", approx_eq(inv.at2d(0, 1), t.CDouble(1.0)), "mismatch") + + # cross3: [1,0,0] x [0,1,0] = [0,0,1] + x: numpy.ndarray[t.CDouble] | t.CPtr = vec3(pool, t.CDouble(1.0), t.CDouble(0.0), t.CDouble(0.0)) + y: numpy.ndarray[t.CDouble] | t.CPtr = vec3(pool, t.CDouble(0.0), t.CDouble(1.0), t.CDouble(0.0)) + cr: numpy.ndarray[t.CDouble] | t.CPtr = numpy.cross3(x, y) + check("cross not None", cr != None, "cross returned None") + check("cross[2]==1", cr.data[2] == t.CDouble(1.0), "mismatch") + + # prod + p: numpy.ndarray[t.CDouble] | t.CPtr = numpy.zeros(pool, 4) + p.data[0] = t.CDouble(1.0); p.data[1] = t.CDouble(2.0); p.data[2] = t.CDouble(3.0); p.data[3] = t.CDouble(4.0) + check("prod==24", numpy.prod(p) == t.CDouble(24.0), "mismatch") + + # median + m: numpy.ndarray[t.CDouble] | t.CPtr = numpy.zeros(pool, 5) + m.data[0] = t.CDouble(3.0); m.data[1] = t.CDouble(1.0); m.data[2] = t.CDouble(2.0) + m.data[3] = t.CDouble(5.0); m.data[4] = t.CDouble(4.0) + check("median==3", numpy.median(m) == t.CDouble(3.0), "mismatch") + + # percentile + check("p50==3", approx_eq(numpy.percentile(m, t.CDouble(50.0)), t.CDouble(3.0)), "mismatch") + + a.delete() + inv.delete() + x.delete() + y.delete() + cr.delete() + p.delete() + m.delete() + section_footer() + + +# ============================================================ +# 13. Additional creation / constants +# ============================================================ +def test_additional_creation(): + section_header("full2d / zeros_like / ones_like / arange1 / constants") + + f: numpy.ndarray[t.CDouble] | t.CPtr = numpy.full2d(pool, 2, 3, t.CDouble(7.0)) + check("full2d not None", f != None, "full2d returned None") + check("full2d ndim==2", f.ndim == 2, "ndim mismatch") + check("full2d[0,0]==7", f.at2d(0, 0) == t.CDouble(7.0), "mismatch") + check("full2d[1,2]==7", f.at2d(1, 2) == t.CDouble(7.0), "mismatch") + + a: numpy.ndarray[t.CDouble] | t.CPtr = vec3(pool, t.CDouble(1.0), t.CDouble(2.0), t.CDouble(3.0)) + zl: numpy.ndarray[t.CDouble] | t.CPtr = numpy.zeros_like(a) + check("zeros_like not None", zl != None, "returned None") + check("zeros_like size==3", zl.size == 3, "size mismatch") + check("zeros_like[0]==0", zl.data[0] == t.CDouble(0.0), "mismatch") + + ol: numpy.ndarray[t.CDouble] | t.CPtr = numpy.ones_like(a) + check("ones_like not None", ol != None, "returned None") + check("ones_like[0]==1", ol.data[0] == t.CDouble(1.0), "mismatch") + + ar: numpy.ndarray[t.CDouble] | t.CPtr = numpy.arange1(pool, t.CDouble(4.0)) + check("arange1 not None", ar != None, "returned None") + check("arange1 size==4", ar.size == 4, "size mismatch") + check("arange1[0]==0", ar.data[0] == t.CDouble(0.0), "mismatch") + check("arange1[3]==3", ar.data[3] == t.CDouble(3.0), "mismatch") + + # Constants + check("pi ~= 3.14", approx_loose(numpy.pi, t.CDouble(3.14159265)), "mismatch") + check("e ~= 2.71", approx_loose(numpy.e, t.CDouble(2.71828182)), "mismatch") + + f.delete() + a.delete() + zl.delete() + ol.delete() + ar.delete() + section_footer() + + +# ============================================================ +# 14. Interpolation +# ============================================================ +def test_interp(): + section_header("np_interp") + + xp: numpy.ndarray[t.CDouble] | t.CPtr = vec3(pool, t.CDouble(0.0), t.CDouble(1.0), t.CDouble(2.0)) + fp: numpy.ndarray[t.CDouble] | t.CPtr = vec3(pool, t.CDouble(0.0), t.CDouble(10.0), t.CDouble(20.0)) + + v: t.CDouble = numpy.np_interp(t.CDouble(0.5), xp, fp) + check("interp(0.5)==5", approx_eq(v, t.CDouble(5.0)), "mismatch") + + v2: t.CDouble = numpy.np_interp(t.CDouble(1.5), xp, fp) + check("interp(1.5)==15", approx_eq(v2, t.CDouble(15.0)), "mismatch") + + v3: t.CDouble = numpy.np_interp(t.CDouble(-1.0), xp, fp) + check("interp(-1)==0", approx_eq(v3, t.CDouble(0.0)), "mismatch") + + v4: t.CDouble = numpy.np_interp(t.CDouble(3.0), xp, fp) + check("interp(3)==20", approx_eq(v4, t.CDouble(20.0)), "mismatch") + + xp.delete() + fp.delete() + section_footer() + + +# ============================================================ +# 15. Edge / boundary / exception tests +# ============================================================ +def test_numpy_edge(): + section_header("edge: size=0 / size=1 / non-SIMD-block / negative / div-zero") + + # size=0: pool.alloc(0) returns None, so zeros(0) returns None (expected) + a0: numpy.ndarray[t.CDouble] | t.CPtr = numpy.zeros(pool, 0) + check("zeros(0) returns None", a0 == None, "expected None for size=0") + + # size=1 + a1: numpy.ndarray[t.CDouble] | t.CPtr = numpy.zeros(pool, 1) + check("zeros(1) not None", a1 != None, "returned None") + check("zeros(1) size==1", a1.size == 1, "size mismatch") + check("zeros(1) [0]==0", a1.data[0] == t.CDouble(0.0), "mismatch") + a1.delete() + + # non-SIMD-block sizes (1,2,3,5,6,7) + a5: numpy.ndarray[t.CDouble] | t.CPtr = numpy.arange(pool, t.CDouble(0.0), t.CDouble(5.0), t.CDouble(1.0)) + check("arange(5) size==5", a5.size == 5, "size mismatch") + check("arange(5) sum==10", approx_eq(a5.sum(), t.CDouble(10.0)), "mismatch") + a5.delete() + + a6: numpy.ndarray[t.CDouble] | t.CPtr = numpy.arange(pool, t.CDouble(0.0), t.CDouble(6.0), t.CDouble(1.0)) + check("arange(6) sum==15", approx_eq(a6.sum(), t.CDouble(15.0)), "mismatch") + a6.delete() + + a7: numpy.ndarray[t.CDouble] | t.CPtr = numpy.arange(pool, t.CDouble(0.0), t.CDouble(7.0), t.CDouble(1.0)) + check("arange(7) sum==21", approx_eq(a7.sum(), t.CDouble(21.0)), "mismatch") + a7.delete() + + # negative values in sqrt + neg_arr: numpy.ndarray[t.CDouble] | t.CPtr = vec3(pool, t.CDouble(-1.0), t.CDouble(0.0), t.CDouble(4.0)) + r_sqrt_neg: numpy.ndarray[t.CDouble] | t.CPtr = numpy.np_sqrt(neg_arr) + check("sqrt(neg) not None", r_sqrt_neg != None, "returned None") + # sqrt(4)=2, sqrt(0)=0; sqrt(-1) is NaN (implementation-defined) + check("sqrt(4)==2", approx_eq(r_sqrt_neg.data[2], t.CDouble(2.0)), "mismatch") + neg_arr.delete() + r_sqrt_neg.delete() + + # div-by-zero: b/a where a has zeros + za: numpy.ndarray[t.CDouble] | t.CPtr = vec3(pool, t.CDouble(0.0), t.CDouble(2.0), t.CDouble(0.0)) + zb: numpy.ndarray[t.CDouble] | t.CPtr = vec3(pool, t.CDouble(6.0), t.CDouble(4.0), t.CDouble(8.0)) + r_divz: numpy.ndarray[t.CDouble] | t.CPtr = za / zb + check("0/6==0", r_divz.data[0] == t.CDouble(0.0), "mismatch") + check("2/4==0.5", r_divz.data[1] == t.CDouble(0.5), "mismatch") + za.delete() + zb.delete() + r_divz.delete() + + # large array (non-aligned, non-SIMD-block) + big: numpy.ndarray[t.CDouble] | t.CPtr = numpy.zeros(pool, 1000) + check("zeros(1000) not None", big != None, "returned None") + check("zeros(1000) size==1000", big.size == 1000, "size mismatch") + big.delete() + + section_footer() + + +# ============================================================ +# 16. Performance benchmark +# ============================================================ +def bench_numpy_perf(): + section_header("Benchmark: numpy ops") + + N: t.CSizeT = 10000 + ITERS: t.CInt = 5 + + a: numpy.ndarray[t.CDouble] | t.CPtr = numpy.zeros(pool, N) + b: numpy.ndarray[t.CDouble] | t.CPtr = numpy.zeros(pool, N) + i: t.CSizeT = 0 + while i < N: + a.data[i] = t.CDouble(1.0) + b.data[i] = t.CDouble(2.0) + i += 1 + + # add benchmark + t0: t.CDouble = timer_sec() + j: t.CInt = 0 + while j < ITERS: + r: numpy.ndarray[t.CDouble] | t.CPtr = a + b + r.delete() + j += 1 + t1: t.CDouble = timer_sec() + printf(" ADD: %.1f ms\n", (t1 - t0) * t.CDouble(1000.0)) + + # mul benchmark + t0 = timer_sec() + j = 0 + while j < ITERS: + r2: numpy.ndarray[t.CDouble] | t.CPtr = a * b + r2.delete() + j += 1 + t1 = timer_sec() + printf(" MUL: %.1f ms\n", (t1 - t0) * t.CDouble(1000.0)) + + # sqrt benchmark + t0 = timer_sec() + j = 0 + while j < ITERS: + r3: numpy.ndarray[t.CDouble] | t.CPtr = numpy.np_sqrt(a) + r3.delete() + j += 1 + t1 = timer_sec() + printf(" SQRT: %.1f ms\n", (t1 - t0) * t.CDouble(1000.0)) + + a.delete() + b.delete() + section_footer() + + +# ============================================================ +# Entry points +# ============================================================ +def test_numpy_correct() -> t.CInt: + global arena, pool, test_passed, test_failed + + arena = calloc(2 * 1024 * 1024, 1) + pool = memhub.MemPool(arena, 2 * 1024 * 1024) + + test_passed = 0 + test_failed = 0 + + printf("==============================================\n") + printf(" numpy Correctness Tests\n") + printf("==============================================\n") + + test_zeros_ones() + test_arange_linspace() + test_eye_diag() + test_sum_mean_min_max() + test_fill_copy() + test_add_sub_mul_div() + test_neg() + test_len() + test_scalar_ops() + test_math_funcs() + test_matmul() + test_dot() + test_transpose() + test_var_std_norm() + test_clip_concatenate() + test_sort_reverse() + test_print_arr() + test_floordiv_mod() + test_additional_math() + test_trig_hyperbolic() + test_degrees_radians() + test_cumsum_diff() + test_max_min_where() + test_flatten_trace() + test_outer() + test_bool_comparison() + test_linalg() + test_additional_creation() + test_interp() + + printf("\n==============================================\n") + printf(" Correctness: %d passed, %d failed\n", test_passed, test_failed) + printf("==============================================\n") + + return test_failed + + +def test_numpy_edge_main() -> t.CInt: + global arena, pool, test_passed, test_failed + + arena = calloc(2 * 1024 * 1024, 1) + pool = memhub.MemPool(arena, 2 * 1024 * 1024) + + test_passed = 0 + test_failed = 0 + + printf("==============================================\n") + printf(" numpy Edge / Boundary Tests\n") + printf("==============================================\n") + + test_numpy_edge() + + printf("\n==============================================\n") + printf(" Edge: %d passed, %d failed\n", test_passed, test_failed) + printf("==============================================\n") + + return test_failed + + +def bench_numpy_main() -> t.CInt: + global arena, pool + + arena = calloc(8 * 1024 * 1024, 1) + pool = memhub.MemPool(arena, 8 * 1024 * 1024) + + printf("==============================================\n") + printf(" numpy Performance Benchmark\n") + printf("==============================================\n") + + bench_numpy_perf() + + printf("==============================================\n") + return 0 + + +# Backward-compatible entry +def test_numpy_main() -> t.CInt: + global arena, pool + + arena = calloc(2 * 1024 * 1024, 1) + pool = memhub.MemPool(arena, 2 * 1024 * 1024) + + failed: t.CInt = test_numpy_correct() + if failed == 0: + failed = test_numpy_edge_main() + if failed == 0: + bench_numpy_main() + return failed diff --git a/NumpyTest/project.json b/NumpyTest/project.json new file mode 100644 index 0000000..68baaae --- /dev/null +++ b/NumpyTest/project.json @@ -0,0 +1,40 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "NumpyTest", + "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": "NumpyTest.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 + } +} \ No newline at end of file diff --git a/OopInheritTest/App/main.vp b/OopInheritTest/App/main.vp new file mode 100644 index 0000000..d7d0d0d --- /dev/null +++ b/OopInheritTest/App/main.vp @@ -0,0 +1,402 @@ +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 + + +# === OOP 继承 + 虚方法 === + +@t.CVTable +class Shape: + x: CFloat64T + y: CFloat64T + + def __init__(self, x: CFloat64T, y: CFloat64T): + self.x = x + self.y = y + def area(self) -> CFloat64T: + return 0.0 + def perimeter(self) -> CFloat64T: + return 0.0 + def describe(self) -> CFloat64T: + return self.area() + self.perimeter() + +@t.CVTable +class Circle(Shape): + r: CFloat64T + + def __init__(self, x: CFloat64T, y: CFloat64T, r: CFloat64T): + self.x = x + self.y = y + self.r = r + def area(self) -> CFloat64T: + return 3.14159265 * self.r * self.r + def perimeter(self) -> CFloat64T: + return 2.0 * 3.14159265 * self.r + def scale(self, factor: CFloat64T) -> 'Circle' | CPtr: + self.r = self.r * factor + return self + def move(self, dx: CFloat64T, dy: CFloat64T) -> 'Circle' | CPtr: + self.x = self.x + dx + self.y = self.y + dy + return self + +@t.CVTable +class Rect(Shape): + w: CFloat64T + h: CFloat64T + + def __init__(self, x: CFloat64T, y: CFloat64T, w: CFloat64T, h: CFloat64T): + self.x = x + self.y = y + self.w = w + self.h = h + def area(self) -> CFloat64T: + return self.w * self.h + def perimeter(self) -> CFloat64T: + return 2.0 * (self.w + self.h) + def scale(self, factor: CFloat64T) -> 'Rect' | CPtr: + self.w = self.w * factor + self.h = self.h * factor + return self + + +# === 运算符重载 + 链式调用(堆分配) === + +class Vec2: + x: CFloat64T + y: CFloat64T + + def __new__() -> 'Vec2' | CPtr: + return stdlib.malloc(16) + + def __init__(self, x: CFloat64T, y: CFloat64T): + self.x = x + self.y = y + + def __add__(self, b: 'Vec2' | CPtr) -> 'Vec2' | CPtr: + return Vec2(self.x + b.x, self.y + b.y) + + def __sub__(self, b: 'Vec2' | CPtr) -> 'Vec2' | CPtr: + return Vec2(self.x - b.x, self.y - b.y) + + def __mul__(self, s: CFloat64T) -> 'Vec2' | CPtr: + return Vec2(self.x * s, self.y * s) + + def __neg__(self) -> 'Vec2' | CPtr: + return Vec2(-self.x, -self.y) + + def dot(self, b: 'Vec2' | CPtr) -> CFloat64T: + return self.x * b.x + self.y * b.y + + def len_sq(self) -> CFloat64T: + return self.x * self.x + self.y * self.y + + +class Vec3: + x: CFloat64T + y: CFloat64T + z: CFloat64T + + def __new__() -> 'Vec3' | CPtr: + return stdlib.malloc(24) + + def __init__(self, x: CFloat64T, y: CFloat64T, z: CFloat64T): + self.x = x + self.y = y + self.z = z + + def __add__(self, b: 'Vec3' | CPtr) -> 'Vec3' | CPtr: + return Vec3(self.x + b.x, self.y + b.y, self.z + b.z) + + def __sub__(self, b: 'Vec3' | CPtr) -> 'Vec3' | CPtr: + return Vec3(self.x - b.x, self.y - b.y, self.z - b.z) + + def __mul__(self, s: CFloat64T) -> 'Vec3' | CPtr: + return Vec3(self.x * s, self.y * s, self.z * s) + + def __neg__(self) -> 'Vec3' | CPtr: + return Vec3(-self.x, -self.y, -self.z) + + def dot(self, b: 'Vec3' | CPtr) -> CFloat64T: + return self.x * b.x + self.y * b.y + self.z * b.z + + def cross(self, b: 'Vec3' | CPtr) -> 'Vec3' | CPtr: + return Vec3(self.y * b.z - self.z * b.y, + self.z * b.x - self.x * b.z, + self.x * b.y - self.y * b.x) + + def len_sq(self) -> CFloat64T: + return self.dot(self) + + +# === 独立类(非继承) === + +@t.CVTable +class Dog: + name_val: CInt + health: CInt32T + bark_power: CInt32T + + def __init__(self, name_val: CInt, bark_power: CInt32T): + self.name_val = name_val + self.health = CInt32T(100) + self.bark_power = bark_power + def speak(self) -> CInt: + return 1 + def bite(self) -> CInt32T: + return self.bark_power + def take_damage(self, dmg: CInt32T) -> 'Dog' | CPtr: + self.health = self.health - dmg + return self + def is_alive(self) -> CInt: + if self.health > 0: + return 1 + return 0 + +@t.CVTable +class Cat: + name_val: CInt + health: CInt32T + lives: CInt32T + + def __init__(self, name_val: CInt, lives: CInt32T): + self.name_val = name_val + self.health = CInt32T(80) + self.lives = lives + def speak(self) -> CInt: + return 2 + def scratch(self) -> CInt32T: + return CInt32T(15) + def take_damage(self, dmg: CInt32T) -> 'Cat' | CPtr: + self.health = self.health - dmg + return self + def is_alive(self) -> CInt: + if self.health > 0: + return 1 + return 0 + + +# === 嵌套对象组合(堆分配) === + +class Transform: + px: CFloat64T + py: CFloat64T + pz: CFloat64T + scale_x: CFloat64T + scale_y: CFloat64T + scale_z: CFloat64T + + def __new__() -> 'Transform' | CPtr: + return stdlib.malloc(48) + + def __init__(self, px: CFloat64T, py: CFloat64T, pz: CFloat64T): + self.px = px + self.py = py + self.pz = pz + self.scale_x = 1.0 + self.scale_y = 1.0 + self.scale_z = 1.0 + + def apply_scale(self, sx: CFloat64T, sy: CFloat64T, sz: CFloat64T) -> 'Transform' | CPtr: + self.scale_x = self.scale_x * sx + self.scale_y = self.scale_y * sy + self.scale_z = self.scale_z * sz + return self + + def world_position(self) -> 'Vec3' | CPtr: + return Vec3(self.px * self.scale_x, self.py * self.scale_y, self.pz * self.scale_z) + + +# === 多层继承(子类只重写需要的方法) === + +@t.CVTable +class Vehicle: + speed: CInt32T + fuel: CInt32T + + def __init__(self, speed: CInt32T): + self.speed = speed + self.fuel = CInt32T(100) + def move(self) -> CInt: + self.fuel = self.fuel - CInt32T(10) + return self.speed + def is_running(self) -> CInt: + if self.fuel > 0: + return 1 + return 0 + +@t.CVTable +class Car(Vehicle): + doors: CInt32T + + def __init__(self, speed: CInt32T, doors: CInt32T): + self.speed = speed + self.fuel = CInt32T(100) + self.doors = doors + def honk(self) -> CInt: + return 1 + +@t.CVTable +class ElectricCar(Car): + battery: CInt32T + + def __init__(self, speed: CInt32T, doors: CInt32T, battery: CInt32T): + self.speed = speed + self.fuel = CInt32T(100) + self.doors = doors + self.battery = battery + def charge(self): + self.battery = self.battery + CInt32T(20) + def move(self) -> CInt: + self.battery = self.battery - CInt32T(5) + return self.speed + + +def main() -> CInt | CExport: + w32.win32console.SetConsoleCP(65001) + w32.win32console.SetConsoleOutputCP(65001) + + testcheck.begin("OopInheritTest: OOP 继承与多态专项测试") + + buf: CChar | CPtr = CPtr(stdlib.malloc(256)) + + # === OOP 继承测试 === + testcheck.section("OOP 继承测试") + c1 = Circle(0.0, 0.0, 5.0) + viperlib.snprintf(buf, 256, "Circle area=%.2f perim=%.2f", c1.area(), c1.perimeter()) + print(buf) + + r1 = Rect(0.0, 0.0, 4.0, 3.0) + viperlib.snprintf(buf, 256, "Rect area=%.2f perim=%.2f", r1.area(), r1.perimeter()) + print(buf) + + # 链式调用: scale -> move + c2 = Circle(1.0, 2.0, 3.0) + c2.scale(2.0).move(10.0, 20.0) + viperlib.snprintf(buf, 256, "Circle after scale+move: x=%.1f y=%.1f r=%.1f area=%.2f", + c2.x, c2.y, c2.r, c2.area()) + print(buf) + + r2 = Rect(0.0, 0.0, 10.0, 5.0) + r2.scale(2.0).scale(0.5) + viperlib.snprintf(buf, 256, "Rect after double scale: w=%.1f h=%.1f area=%.2f", + r2.w, r2.h, r2.area()) + print(buf) + testcheck.ok("OOP 继承测试完成") + + # === Vec2 运算符重载 + 链式调用(堆分配) === + testcheck.section("Vec2 运算符重载 + 链式调用") + v1 = Vec2(3.0, 4.0) + v2 = Vec2(1.0, 2.0) + v3 = v1 + v2 + viperlib.snprintf(buf, 256, "Vec2 add: (%.1f, %.1f)", v3.x, v3.y) + print(buf) + + v4 = v1 - v2 + viperlib.snprintf(buf, 256, "Vec2 sub: (%.1f, %.1f)", v4.x, v4.y) + print(buf) + + v5 = v1 * 2.0 + viperlib.snprintf(buf, 256, "Vec2 mul: (%.1f, %.1f)", v5.x, v5.y) + print(buf) + + v6 = -v1 + viperlib.snprintf(buf, 256, "Vec2 neg: (%.1f, %.1f)", v6.x, v6.y) + print(buf) + + d = v1.dot(v2) + viperlib.snprintf(buf, 256, "Vec2 dot: %.1f", d) + print(buf) + + # 链式运算: (v1 + v2) * 3.0 + v_chain = (v1 + v2) * 3.0 + viperlib.snprintf(buf, 256, "Vec2 chain (v1+v2)*3: (%.1f, %.1f)", v_chain.x, v_chain.y) + print(buf) + testcheck.ok("Vec2 运算符重载测试完成") + + # === Vec3 运算符重载 + 链式调用(堆分配) === + testcheck.section("Vec3 运算符重载 + 链式调用") + a1 = Vec3(1.0, 0.0, 0.0) + a2 = Vec3(0.0, 1.0, 0.0) + cross_v = a1.cross(a2) + viperlib.snprintf(buf, 256, "Vec3 cross: (%.1f, %.1f, %.1f)", cross_v.x, cross_v.y, cross_v.z) + print(buf) + + dot_v = a1.dot(a2) + viperlib.snprintf(buf, 256, "Vec3 dot: %.1f", dot_v) + print(buf) + + # 链式: (a + b).dot(c) + a3 = Vec3(1.0, 2.0, 3.0) + a4 = Vec3(4.0, 5.0, 6.0) + a5 = Vec3(7.0, 8.0, 9.0) + chain_dot = (a3 + a4).dot(a5) + viperlib.snprintf(buf, 256, "Vec3 chain dot: %.1f", chain_dot) + print(buf) + + # 链式: (a * 2.0 - b).cross(c) + chain_cross = (a3 * 2.0 - a4).cross(a5) + viperlib.snprintf(buf, 256, "Vec3 chain cross: (%.1f, %.1f, %.1f)", chain_cross.x, chain_cross.y, chain_cross.z) + print(buf) + + # len_sq 链式 + lsq = a3.len_sq() + viperlib.snprintf(buf, 256, "Vec3 len_sq: %.1f", lsq) + print(buf) + testcheck.ok("Vec3 运算符重载测试完成") + + # === Dog/Cat 虚方法 === + testcheck.section("Dog/Cat 虚方法") + dog = Dog(1, CInt32T(30)) + cat = Cat(2, CInt32T(9)) + + viperlib.snprintf(buf, 256, "Dog speak=%d bite=%d alive=%d", dog.speak(), dog.bite(), dog.is_alive()) + print(buf) + viperlib.snprintf(buf, 256, "Cat speak=%d scratch=%d alive=%d", cat.speak(), cat.scratch(), cat.is_alive()) + print(buf) + + dog.take_damage(CInt32T(40)).take_damage(CInt32T(30)) + viperlib.snprintf(buf, 256, "Dog after 70dmg: health=%d alive=%d", dog.health, dog.is_alive()) + print(buf) + + cat.take_damage(CInt32T(50)) + viperlib.snprintf(buf, 256, "Cat after 50dmg: health=%d alive=%d", cat.health, cat.is_alive()) + print(buf) + testcheck.ok("Dog/Cat 虚方法测试完成") + + # === Transform 嵌套组合(堆分配,链式调用) === + testcheck.section("Transform 嵌套组合") + tr = Transform(10.0, 20.0, 30.0) + tr.apply_scale(2.0, 3.0, 4.0) + pos = tr.world_position() + viperlib.snprintf(buf, 256, "Transform pos: (%.1f, %.1f, %.1f)", pos.x, pos.y, pos.z) + print(buf) + + tr2 = Transform(5.0, 10.0, 15.0) + tr2.apply_scale(2.0, 2.0, 2.0) + pos2 = tr2.world_position() + viperlib.snprintf(buf, 256, "Transform2 pos: (%.1f, %.1f, %.1f)", pos2.x, pos2.y, pos2.z) + print(buf) + testcheck.ok("Transform 嵌套组合测试完成") + + # === 多层继承 === + testcheck.section("多层继承") + ec = ElectricCar(CInt32T(120), CInt32T(4), CInt32T(80)) + viperlib.snprintf(buf, 256, "ECar speed=%d doors=%d battery=%d", ec.speed, ec.doors, ec.battery) + print(buf) + ec.charge() + viperlib.snprintf(buf, 256, "ECar after charge: battery=%d", ec.battery) + print(buf) + spd = ec.move() + viperlib.snprintf(buf, 256, "ECar move: speed=%d battery=%d", spd, ec.battery) + print(buf) + viperlib.snprintf(buf, 256, "ECar honk=%d running=%d", ec.honk(), ec.is_running()) + print(buf) + testcheck.ok("多层继承测试完成") + + stdlib.free(buf) + return testcheck.end() diff --git a/OopInheritTest/project.json b/OopInheritTest/project.json new file mode 100644 index 0000000..c62a67b --- /dev/null +++ b/OopInheritTest/project.json @@ -0,0 +1,40 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "OopInheritTest", + "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": "OopInheritTest.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 + } +} \ No newline at end of file diff --git a/PointerTest/App/main.vp b/PointerTest/App/main.vp new file mode 100644 index 0000000..a2e46e1 --- /dev/null +++ b/PointerTest/App/main.vp @@ -0,0 +1,281 @@ +from stdint import * +import t, c +import stdio +import string +import w32.win32console +import w32.win32memory +import testcheck + +# ============================================================ +# PointerTest - 测试指针操作、global声明、数组退化、指针算术 +# ============================================================ + +# --- Test 1: global 声明对模块级变量的影响 --- +_g_val: t.CInt = 0 +_g_ptr: t.CUInt32T | t.CPtr = None + +def test_global_write(): + """测试:缺少 global 声明时,赋值是否修改模块级变量""" + global _g_val + _g_val = 42 + +def test_global_write_no_decl(): + """测试:没有 global 声明时,函数内局部赋值不修改模块级变量 + + 新规则:模块级已有 `_g_val` 时,函数内再写 `_g_val: int = ...`(注解同名) + 一律判为"重复声明"并终止编译(TypeError)——**不管**注解类型是否与全局相同。 + 因此这里改用**不重名**的局部变量验证"函数内局部赋值不影响全局"。 + """ + local_val: int = 99 # 独立局部变量,与全局 _g_val 无关 + +def test_global_ptr(): + global _g_ptr + buf: t.CUInt32T | t.CPtr = w32.win32memory.VirtualAlloc(None, 256, 0x3000, 0x04) + if buf: + string.memset(buf, 0, 256) + _g_ptr = buf + p: t.CUInt32T | t.CPtr = _g_ptr + p[0] = 0xAABBCCDD + p[1] = 0x11223344 + +def test_global_ptr_no_decl(): + """测试:没有 global 声明时,同名注解声明是编译期错误(此处演示合法写法) + + 新规则:模块级已有 `_g_ptr` 时,函数内写 `_g_ptr: t.CUInt32T | t.CPtr = None` + (无 global)或 `global _g_ptr` 之后仍带类型注解声明,都判为"重复声明"并终止 + 编译(TypeError)——不管注解类型是否与全局相同。合法写法只有两种: + - 修改全局:`global _g_ptr` + **无注解**赋值(见 test_global_ptr) + - 独立局部:换成不与全局重名的变量名(本函数) + """ + local_ptr: t.CUInt32T | t.CPtr = None # 独立局部变量,不触碰全局 _g_ptr + + +# --- Test 2: 指针算术和数组索引 --- +def test_pointer_arithmetic(): + """测试指针算术:偏移计算是否正确""" + buf: t.CUInt32T | t.CPtr = w32.win32memory.VirtualAlloc(None, 256, 0x3000, 0x04) + if not buf: + testcheck.fail("pointer arithmetic: VirtualAlloc returned NULL") + return + string.memset(buf, 0, 256) + + # 写入值 + for i in range(8): + buf[i] = t.CUInt32T(i * 100) + + # 读取并验证 + ok: t.CInt = 1 + for i in range(8): + v: t.CUInt32T = buf[i] + expected: t.CUInt32T = t.CUInt32T(i * 100) + if v != expected: + stdio.printf("buf[%d] = 0x%x, expected 0x%x\n", i, v, expected) + ok = 0 + testcheck.check(ok, "pointer arithmetic (buf[i] = i*100)", "pointer arithmetic mismatch") + + +# --- Test 3: 数组退化为指针 --- +def test_array_decay(): + """测试 list[t.CChar, N] 传递给 t.CConst | str 参数""" + arr: t.CArray[t.CChar, 32] + string.memset(c.Addr(arr), 0, 32) + # 手动写入字符串 + src: str = "Hello" + for i in range(5): + arr[i] = t.CChar(ord(src[i])) + arr[5] = 0 + + # 传递给 print (接受 t.CConst | str) + stdio.printf("array decay -> %s\n", c.Addr(arr)) + testcheck.ok("array decay (Hello)") + + +# --- Test 4: 指针类型转换 (CVoid/CPtr) --- +def test_pointer_cast(): + """测试指针与整数之间的类型转换""" + buf: t.CUInt32T | t.CPtr = w32.win32memory.VirtualAlloc(None, 256, 0x3000, 0x04) + if not buf: + testcheck.fail("pointer cast: VirtualAlloc returned NULL") + return + string.memset(buf, 0, 256) + + # 通过 CVoid 指针写入 + raw: t.CPtr = t.CPtr(t.CUInt64T(buf)) + # 将 CVoid 指针转回 CUInt32T 指针 + p32: t.CUInt32T | t.CPtr = (t.CUInt32T | t.CPtr)(raw) + p32[0] = 0xDEADBEEF + + # 通过原始指针读取 + if buf[0] == 0xDEADBEEF: + testcheck.ok("pointer cast CVoid -> CUInt32T*") + else: + stdio.printf("got 0x%x\n", buf[0]) + testcheck.fail("pointer cast failed") + + +# --- Test 5: 指针偏移计算 (byte offset vs element offset) --- +def test_pointer_offset(): + """测试指针偏移:CUInt8T* + N 应该偏移 N 字节,CUInt32T* + N 应该偏移 N*4 字节""" + buf: t.CUInt8T | t.CPtr = w32.win32memory.VirtualAlloc(None, 256, 0x3000, 0x04) + if not buf: + testcheck.fail("pointer offset: VirtualAlloc returned NULL") + return + string.memset(buf, 0, 256) + + # 写入 4 字节 + buf[0] = 0x41 # 'A' + buf[1] = 0x42 # 'B' + buf[2] = 0x43 # 'C' + buf[3] = 0x44 # 'D' + + # 通过 CUInt32T* 读取(应该读到 0x44434241 on little-endian) + p32: t.CUInt32T | t.CPtr = (t.CUInt32T | t.CPtr)(t.CPtr(t.CUInt64T(buf))) + val: t.CUInt32T = p32[0] + + # little-endian: 0x44434241 + if val == 0x44434241: + testcheck.ok("byte offset vs element offset (0x44434241)") + else: + stdio.printf("expected 0x44434241, got 0x%x\n", val) + testcheck.fail("byte offset vs element offset") + + +# --- Test 6: 结构体指针访问 --- +class TestStruct(): + a: t.CInt + b: t.CInt + c: t.CUInt64T + +def test_struct_pointer(): + """测试结构体指针的成员访问""" + s: TestStruct + s.a = 10 + s.b = 20 + s.c = 0x123456789ABCDEF0 + + p: TestStruct | t.CPtr = c.Addr(s) + stdio.printf("struct pointer access (a=%d b=%d c=0x%llx)\n", p.a, p.b, p.c) + testcheck.check(p.a == 10 and p.b == 20 and p.c == 0x123456789ABCDEF0, "struct pointer access", "struct pointer access mismatch") + + +# --- Test 7: memcpy/memset 通过指针 --- +def test_memcpy_pointers(): + """测试 memcpy 在指针之间的数据复制""" + src_buf: t.CUInt32T | t.CPtr = w32.win32memory.VirtualAlloc(None, 64, 0x3000, 0x04) + dst_buf: t.CUInt32T | t.CPtr = w32.win32memory.VirtualAlloc(None, 64, 0x3000, 0x04) + if not src_buf or not dst_buf: + testcheck.fail("memcpy: VirtualAlloc returned NULL") + return + + # 初始化 src + for i in range(8): + src_buf[i] = t.CUInt32T(i + 1000) + + # 复制 + string.memcpy(t.CPtr(t.CUInt64T(dst_buf)), t.CPtr(t.CUInt64T(src_buf)), 32) + + # 验证 + ok: t.CInt = 1 + for i in range(8): + if dst_buf[i] != t.CUInt32T(i + 1000): + stdio.printf("dst[%d] = %u, expected %u\n", i, dst_buf[i], i + 1000) + ok = 0 + testcheck.check(ok, "memcpy between pointers", "memcpy between pointers failed") + + +# --- Test 8: 指针作为函数参数 --- +def fill_array(arr: t.CUInt32T | t.CPtr, count: t.CInt, val: t.CUInt32T): + for i in range(count): + arr[i] = val + +def test_pointer_param(): + """测试指针作为函数参数传递""" + buf: t.CUInt32T | t.CPtr = w32.win32memory.VirtualAlloc(None, 64, 0x3000, 0x04) + if not buf: + testcheck.fail("pointer param: VirtualAlloc returned NULL") + return + + fill_array(buf, 8, 0xCAFEBABE) + + ok: t.CInt = 1 + for i in range(8): + if buf[i] != 0xCAFEBABE: + ok = 0 + testcheck.check(ok, "pointer as function parameter", "pointer as function parameter failed") + + +def main() -> t.CInt | t.CExport: + w32.win32console.SetConsoleCP(65001) + w32.win32console.SetConsoleOutputCP(65001) + + print("你好") + l: t.CArray[t.CChar, 2] = 0 + for i in "hello": + l[0] = i + print(l) + + #u: t.CArray[t.CUInt64T | t.BigEndian, 2] = [0x4141414141414141, 0x0000000000000000] + #for i in c.Addr(u): + # # l[0] = i + # stdio.printf("0x%llx\n", i) + + k: t.CArray[t.CChar, 12] = ['1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C'] + for i in k: + stdio.printf("%c\n", i) + + testcheck.begin("PointerTest: 指针操作基准测试") + + # Test 1: global 声明 + testcheck.section("Test 1: global declaration") + global _g_val + _g_val = 0 + test_global_write() + stdio.printf("After test_global_write(): _g_val = %d (expect 42)\n", _g_val) + test_global_write_no_decl() + stdio.printf("After test_global_write_no_decl(): _g_val = %d (expect 42, not 99)\n", _g_val) + testcheck.check(_g_val == 42, "global declaration (_g_val = 42)", "global declaration failed") + + # Test 1b: global pointer + testcheck.section("Test 1b: global pointer") + test_global_ptr() + if _g_ptr: + p: t.CUInt32T | t.CPtr = _g_ptr + stdio.printf("_g_ptr[0] = 0x%x (expect 0xAABBCCDD)\n", p[0]) + stdio.printf("_g_ptr[1] = 0x%x (expect 0x11223344)\n", p[1]) + testcheck.check(p[0] == 0xAABBCCDD and p[1] == 0x11223344, "global pointer values", "global pointer mismatch") + test_global_ptr_no_decl() + stdio.printf("After test_global_ptr_no_decl(): _g_ptr = %p (expect 非 NULL:局部遮蔽未改全局)\n", t.CPtr(t.CUInt64T(_g_ptr))) + if _g_ptr: + testcheck.ok("global ptr no decl (global untouched by local shadow)") + else: + testcheck.fail("global ptr no decl: 无 global 声明的局部遮蔽不应修改全局 _g_ptr") + + # Test 2: pointer arithmetic + testcheck.section("Test 2: pointer arithmetic") + test_pointer_arithmetic() + + # Test 3: array decay + testcheck.section("Test 3: array decay") + test_array_decay() + + # Test 4: pointer cast + testcheck.section("Test 4: pointer cast") + test_pointer_cast() + + # Test 5: pointer offset + testcheck.section("Test 5: pointer offset (byte vs element)") + test_pointer_offset() + + # Test 6: struct pointer + testcheck.section("Test 6: struct pointer access") + test_struct_pointer() + + # Test 7: memcpy pointers + testcheck.section("Test 7: memcpy between pointers") + test_memcpy_pointers() + + # Test 8: pointer as param + testcheck.section("Test 8: pointer as function parameter") + test_pointer_param() + + return testcheck.end() diff --git a/PointerTest/project.json b/PointerTest/project.json new file mode 100644 index 0000000..755d4e5 --- /dev/null +++ b/PointerTest/project.json @@ -0,0 +1,40 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "PointerTest", + "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": "PointerTest.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 + } +} \ No newline at end of file diff --git a/ProbeGen/App/main.vp b/ProbeGen/App/main.vp new file mode 100644 index 0000000..7921eb0 --- /dev/null +++ b/ProbeGen/App/main.vp @@ -0,0 +1,160 @@ +# ============================================================ +# main.vp — ProbeGen:代际不稳定性最小探针(勿当普通功能测试改动) +# +# 背景:同一份源码在 TPC→TPV1→TPV2→TPV3 逐代自举出的编译器二进制下 +# 产出的 IR 不一致,部分甚至非法。本工程把已定位的 5+1 个"代际 +# 不稳定构造"各用一段最小代码覆盖,用两代编译器各编一次,即可在 +# 同一份产物里一次性暴露全部差异点,并作为后续修复的回归用例。 +# +# 运行(两条命令,各用独立 build_dir,互不覆盖): +# 第 1 代(TPC 产出): +# TransPyV\output\TransPyV.exe --project Test\ProbeGen\project.vpj --clean --run --build-dir Test\ProbeGen\.tpv_build_g1 +# 第 2 代(TPV1 产出): +# TransPyV\.tpv_build\output\TransPyV.exe --project Test\ProbeGen\project.vpj --clean --run --build-dir Test\ProbeGen\.tpv_build_g2 +# --build-dir 依据:TransPyV\App\main.vp:163 注册该参数,:299-304 在 +# resolve_paths 之前覆盖 Config.BuildDir(相对路径基于工程目录解析, +# 注释见 main.vp:300-301);产物 = \temp + \output +# (TransPyV\App\lib\Projectrans\Config.vp:432-443)。 +# 注意 TPC 的 Projectrans.py 没有 --build-dir,只有 +# --project/--src/--temp/--output(TransPyC\lib\Projectrans\Config.py:139-146); +# 本探针由 Viper 编译器 TransPyV.exe 驱动,故 --build-dir 可用。 +# +# 判定:两棵树 +# Test\ProbeGen\.tpv_build_g1\temp\\.{stub,text}.ll +# Test\ProbeGen\.tpv_build_g2\temp\<同上> +# 探针自身模块文件名两侧相同(module_name = 源码 SHA1,与编译器代际无关), +# 可逐 P 点直接 diff;includes 模块若被译为本地产物亦同名可比对。 +# +# ⚠ [P6] 在第二代及以后会直接把编译打断(App\lib\core\Gen\AssignGenMixin.vp:2213 +# "SyntaxError: subscript ptr is None")。若要单独拿到 P1..P5 的第二代 IR, +# 需临时注释掉 [P6] 段;P6 自身的证据就是那条报错。 +# ============================================================ +import t +from stdint import * +import w32.win32console as w32console + + +# ============================================================ +# [P1] 嵌套联合形参 +# VOIDPTR 本身是 typedef 联合 t.CPtr(includes/stdint.vp:40), +# 再与 t.CPtr 联合 ⇒ 一侧 i8**、另一侧 i8*。 +# 先例(同形):includes/w32/win32sync.vp:65 +# extern def InitOnceExecuteOnce(InitOnce: INIT_ONCE | t.CPtr, InitFn: VOIDPTR, +# Parameter: VOIDPTR, Context: VOIDPTR | t.CPtr) -> BOOL +# VOIDPTR 引入方式先例:includes/w32/win32sync.vp:2(from stdint import *) +# extern def 写法先例(语言推荐写法):wiki/08-c-operations.md:238-249 +# 只声明不调用:extern 声明未调用不产生链接引用,不影响链接 +# 先例:Test/Extern2Test/App/main.vp:18-35(三个仅声明不调用的外部声明) +# ============================================================ +extern def ProbeNestedUnion(Context: VOIDPTR | t.CPtr) -> BOOL + + +# ============================================================ +# [P2] 结构体按值形参 +# 形参是既有 Win32 结构体 COORD(includes/w32/win32console.vp:35-37,X/Y: SHORT), +# 不带 | t.CPtr ⇒ 一侧按值 %COORD、另一侧 %COORD*。 +# 先例(同形):includes/w32/win32console.vp:86 +# extern def SetConsoleScreenBufferSize(hConsoleOutput: HANDLE, dwSize: COORD) -> BOOL +# 限定名类类型标注先例:TransPyV/App/main.vp:142(argparse.ArgumentParser) +# Test/ArgparseTest/App/main.vp:12(memhub.MemBuddy) +# 模块别名导入先例:TransPyV/App/main.vp:20(import w32.win32console as w32cmd) +# ============================================================ +extern def ProbeCoordByVal(dwSize: w32console.COORD) -> BOOL + + +# ============================================================ +# [P5] 局部 t.CUInt8T = 1 的字面量"蓄池": +# 把局部值写进全局,避免整段被当成死代码/被窥孔吞掉。 +# 全局小整型先例:ViperApps/ViperOS/VKernel/Kernel/services/desktop.vp:62 +# (_cursor_buttons: uint8 = 0) +# ============================================================ +U8Sink: t.CUInt8T = 0 + + +# ============================================================ +# [P3] CChar → int 提升:参数 t.CChar、返回 int,直接 return +# 一侧应生成 zext i8 %s to i32,另一侧若退化成 ret i8 即丢提升(缺陷)。 +# 先例(同形):includes/builtins.vp:12-13 +# def ord(s: t.CChar) -> int: +# return s +# ============================================================ +def ProbeOrd(s: t.CChar) -> int: + return s + + +# ============================================================ +# [P4] double 比较:参数/返回 double,含 if a < b +# 一侧 fcmp olt double,另一侧若成 icmp slt double(非法)即缺陷。 +# 先例(同形):includes/builtins.vp:18-21 +# def min(a: double, b: double) -> double: +# if a < b: +# return a +# return b +# ============================================================ +def ProbeMin(a: double, b: double) -> double: + if a < b: + return a + return b + + +# ============================================================ +# [P5] 局部 t.CUInt8T = 1 字面量赋值(字面量定型:一侧 store i8 1, i8*; +# 另一侧 store i32 1, i8*(非法)或 trunc + store) +# 局部声明先例:includes/atom.vp:13(result: t.CUInt8T = 1) +# 局部值落全局(global 声明 + 赋值)先例: +# Test/ArgparseTest/App/main.vp:17(global _mbuddy)→ :26(_mbuddy = ...) +# ============================================================ +def ProbeU8Literal() -> t.CUInt8T: + global U8Sink + result: t.CUInt8T = 1 + U8Sink = result + return result + + +# ============================================================ +# [P6] 类字段联合 + 下标写 +# 字段为 t.CChar | t.CPtr 联合,必须先判空再按下标写; +# 第二/三代在 App\lib\core\Gen\AssignGenMixin.vp:2213 抛 +# "SyntaxError: subscript ptr is None"。 +# 先例(同形):includes/viperio.vp:5-20 +# class Buf: +# data: t.CChar | t.CPtr +# def clear(self): +# if self.data != None and self.capacity > 0: +# self.data[0] = 0 +# 联合类型字段/变量初始化 None 先例:Test/SimdTest/App/main.vp:13 +# (arena: t.CUInt8T | t.CPtr = None) +# 无参构造 __init__(self) 先例:TransPyV/App/lib/core/Gen/Translator.vp:75/252-255 +# (class Translator: def __init__(self): ...;实例化 TransPyV/App/main.vp:471) +# ============================================================ +class Box: + p: t.CChar | t.CPtr + + def __init__(self): + self.p = None + + def Clear(self): + if self.p != None: + self.p[0] = 0 + pass + + +# ============================================================ +# 入口:main 保持最小(引用到上面各构造,保证它们真的被翻译;返回 0) +# @t.CExport + main() -> int 先例:ViperApps/ViperTemplateProject/App/main.vp:7-8 +# ViperApps/ViperCPW/App/main.vp:181-184 +# 字符字面量先例:Test/CharTest/App/main.vp:24(lit: char = 'Z') +# 类实例化先例:Test/StructTest/App/main.vp:21(p: Point = Point()) +# double 字面量先例:Test/G7/App/main.vp:39(node.FloatVal = 3.14) +# P1/P2 是 extern 声明,不调用(调用会产生未解析符号,见各自注释); +# 其差异体现在本模块的 declare 上。 +# ============================================================ +@t.CExport +def main() -> int: + Ch: t.CChar = 'A' + BoxInst: Box = Box() + BoxInst.Clear() + ProbeOrd(Ch) + ProbeMin(1.0, 2.0) + ProbeU8Literal() + return 0 diff --git a/ProbeGen/project.vpj b/ProbeGen/project.vpj new file mode 100644 index 0000000..04d61ed --- /dev/null +++ b/ProbeGen/project.vpj @@ -0,0 +1,40 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "ProbeGen", + "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": "ProbeGen.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 + } +} diff --git a/PtrOpProbe/App/main.vp b/PtrOpProbe/App/main.vp new file mode 100644 index 0000000..4237e4c --- /dev/null +++ b/PtrOpProbe/App/main.vp @@ -0,0 +1,115 @@ +import t, c +from stdint import * +import stdio +import stdlib + + +# ============================================================ +# 指针操作符全形态自检(TPC 侧) +# +# 解析实况(vast_c.c ParseSimpleStmt → ParseExprList + SetStoreContext): +# `*p` 由 ParseFactor 产出 UnaryOp(op=Deref),SetStoreContext **不改 UnaryOp** +# ⇒ `*p = v` 的赋值目标就是 UnaryOp(Deref)(ctx 仍是 Load),与读侧同形。 +# 若编译器目标分派没有 UnaryOp 分支,整条语句会被静默丢弃(不落盘、不报错), +# 本程序即用于钉死这一点:每个形态都必须真的写进内存。 +# ============================================================ + +def MakePair() -> tuple[int, int]: + return 1, 2 + + +def main() -> int: + fails: int = 0 + buf: uint64* = (uint64*)stdlib.malloc(64) + if buf == None: + stdio.printf("FAIL: malloc\n") + return 9 + + # 形态 A:*p = v + *buf = 7 + if buf[0] != 7: + stdio.printf("FAIL A *p = v : buf[0]=%llu(期望 7)\n", buf[0]) + fails += 1 + + # 形态 B:*p = *q + q: uint64* = buf + 1 + *q = 99 + *buf = *q + if buf[0] != 99: + stdio.printf("FAIL B *p = *q : buf[0]=%llu(期望 99)\n", buf[0]) + fails += 1 + + # 形态 C:&x 取址,*px = v + x: uint64 = 0 + y: uint64 = 5 + px: uint64* = &x + *px = 11 + if x != 11: + stdio.printf("FAIL C *px = v : x=%llu(期望 11)\n", x) + fails += 1 + + # 形态 D:*&x = *&y + *&x = *&y + if x != 5: + stdio.printf("FAIL D *&x = *&y : x=%llu(期望 5)\n", x) + fails += 1 + + # 形态 E(对照):下标写 p[i] = v + buf[0] = 123 + if buf[0] != 123: + stdio.printf("FAIL E p[0] = v : buf[0]=%llu(期望 123)\n", buf[0]) + fails += 1 + + # 形态 F:AugAssign 目标 *p += v + *buf += 5 + if buf[0] != 128: + stdio.printf("FAIL F *p += v : buf[0]=%llu(期望 128)\n", buf[0]) + fails += 1 + + # 形态 G1(对照):Tuple 目标 a, b = f() + a: int = 0 + b: int = 0 + a, b = MakePair() + if a != 1 or b != 2: + stdio.printf("FAIL G1 a, b = f() : a=%d b=%d(期望 1/2)\n", a, b) + fails += 1 + + # 形态 G2:List 目标 [c, d] = f() + cc: int = 0 + dd: int = 0 + [cc, dd] = MakePair() + if cc != 1 or dd != 2: + stdio.printf("FAIL G2 [c, d] = f() : c=%d d=%d(期望 1/2)\n", cc, dd) + fails += 1 + + # 形态 H:值位置的 *p(调用实参 f(*p))——Starred(Load) + got: int = stdio.printf("INFO H f(*p) : %llu(期望 128)\n", *buf) + if got < 0: + stdio.printf("FAIL H f(*p) : printf 返回 %d\n", got) + fails += 1 + + # 形态 I:memhub 实际用的「两步式读块头」(关键回归点) + # hd1 = *((uint64*)(blk)) —— 直接读 + # hd2 = uint64(t.CPtr(*((uint64*)(blk)))) —— 两步式;注意 `*((...))` 位于 + # t.CPtr( ) 的**实参位置** ⇒ 解析为 Starred(Load),旧 TPC 在这一形态落到 + # 末尾兜底 `return i32 0` ⇒ t.CPtr(0)=NULL ⇒ hd2==0(内存里明明是 0x1234) + # 这正是 OOM 报告里 `hdr=0x9 / hdr2=0x0` 的成因。 + w: uint64 = 0 + pw: uint64* = &w + *pw = 0x1234 + blk: t.CPtr = t.CPtr(uint64(pw)) + hd1: uint64 = *((uint64*)(blk)) + hd2: uint64 = uint64(t.CPtr(*((uint64*)(blk)))) + if hd1 != 0x1234: + stdio.printf("FAIL I1 直接读块头 : hd1=0x%llX(期望 0x1234)\n", hd1) + fails += 1 + if hd2 != 0x1234: + stdio.printf("FAIL I2 两步式读块头 : hd2=0x%llX(期望 0x1234)\n", hd2) + fails += 1 + + if fails == 0: + stdio.printf("ALL OK: 指针操作符全形态均真正落盘\n") + else: + stdio.printf("FAILS=%d\n", fails) + stdio.fflush(None) + return fails diff --git a/PtrOpProbe/project.json b/PtrOpProbe/project.json new file mode 100644 index 0000000..aed633a --- /dev/null +++ b/PtrOpProbe/project.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "PtrOpProbe", + "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": "PtrOpProbe.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 + } +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..a1835ac --- /dev/null +++ b/README.md @@ -0,0 +1,243 @@ +# TPV 测试项目总览 + +本文档基于 `Test/` 目录下全部 68 个测试项目的源码总结其功能,并**按实现难度升序**排列(简单在前、困难在后),供编译器开发按序推进。 + +> 测试框架:几乎所有项目使用 `testcheck` 库(`begin`/`section`/`check`/`ok`/`end`)输出 PASS/FAIL 并汇总。多数项目还依赖 `memhub` 内存分配器与 `t.CInt`/`t.CExport` 等 C 互操作类型。 + +--- + +## 一、全部测试功能一览(按实现难度升序) + +### 难度:简单(16 个)—— 基础语法、库 API 直接调用 + +| # | 项目 | 功能概述 | 关键特性 | +|---|------|---------|---------| +| 1 | [FuncTest](FuncTest/App/main.vp) | 函数调用基准:多参数、递归阶乘、双递归斐波那契、指针参数、u64/bool 返回、嵌套调用 | 函数定义/调用、递归、指针参数 | +| 2 | [LoopTest](LoopTest/App/main.vp) | 循环基准:for/while/Collatz/嵌套 for/break/continue/带步长 range/u64 计数 | 循环、break/continue、range 步长 | +| 3 | [StringTest](StringTest/App/main.vp) | string 库:strlen/strcpy/strcat/strcmp/strncpy/下标取字符/snprintf | string 库、C 字符串指针 | +| 4 | [StructTest](StructTest/App/main.vp) | 结构体:字段读写、嵌套(`Rect.origin.x`)、取地址修改、传值参数、数组布局 | t.Struct、嵌套结构体、结构体指针/数组 | +| 5 | [EqTest](EqTest/App/main.vp) | 比较语义:str 的 `==` 是指针地址比较(值比较须 strcmp)、`is` 身份比较、与 None 比较 | 比较运算符、None、string.strcmp | +| 6 | [ShortCircuitTest](ShortCircuitTest/App/main.vp) | 短路求值:`and`/`or`/`not` 的求值顺序与副作用检测 | 短路语义、副作用函数 | +| 7 | [IterTest](IterTest/App/main.vp) | `for ch in str` 逐字符迭代:求和字符码、写入数组、手动 strcpy | for-in 指针迭代、联合类型 | +| 8 | [Extern2Test](Extern2Test/App/main.vp) | 回归:CExtern/CExport/State 声明函数只生成一次 declare 不重复 define | 外部声明修饰符、声明去重 | +| 9 | [SlotsBugTest](SlotsBugTest/App/main.vp) | 回归:`__slots__` + 可识别类型注解不再误判崩溃(以编译通过为准) | __slots__、类型注解解析 | +| 10 | [ListTest](ListTest/App/main.vp) | `list[int]` 容器:append/get/len/set/pop/clear/扩容/复用 | 泛型 list、特殊方法 | +| 11 | [MpoolOopTest](MpoolOopTest/App/main.vp) | MemPool(bump)/MemSlab(定长块)OOP 测试:alloc/reset/free 复用、viperio.Buf | memhub 库、with 上下文、句柄类型 | +| 12 | [DocTest](DocTest/App/main.vp) | `__doc__` 魔法字符串:本模块与跨模块函数/类/方法 docstring 读取 | docstring、__doc__ 属性 | +| 13 | [ForAndLoopTest](ForAndLoopTest/App/main.vp) | 迭代器组合:range/zip/enumerate 遍历 list/str/range,元组解包 | 内置迭代器、元组解包 | +| 14 | [VRandomTest](VRandomTest/App/main.vp) | vrandom 库:RDRAND 硬件随机数 + 10 种统计分布采样 | vrandom 库、硬件随机数 | +| 15 | [VariadicTest](VariadicTest/App/main.vp) | 变参 printf/snprintf:整数提升匹配 %u/%lu/%d/%x、边界值 | 变参 ABI、整数提升、格式串 | +| 16 | [ClosureCallTest](ClosureCallTest/App/main.vp) | 最小复现:闭包返回 `t.CPtr` 函数指针后直接 `f()` 调用 | 闭包、函数指针直接调用 | + +### 难度:简单 → 中等(3 个)—— 泛型入门 + +| # | 项目 | 功能概述 | 关键特性 | +|---|------|---------|---------| +| 17 | [GenericTest](GenericTest/App/main.vp) | 泛型基础:泛型函数/多类型参数/泛型类/多次特化/嵌套调用/CArray | 泛型函数与类、特化、t.CArray | +| 18 | [GenericTest3](GenericTest3/App/main.vp) | 泛型函数手动传类型参数 `double[t.CInt](21)` | 显式类型参数调用语法 | +| 19 | [GenericTest4](GenericTest4/App/main.vp) | 泛型类手动传类型参数 `Box[t.CInt](42)`(GenericTest3 的类版本) | 泛型类显式特化语法 | + +### 难度:中等(21 个)—— 类型系统、容器、基础 OOP + +| # | 项目 | 功能概述 | 关键特性 | +|---|------|---------|---------| +| 20 | [TypeCastTest](TypeCastTest/App/main.vp) | 类型转换:zext/sext/trunc、C 语义运算(-100//7=-14)、CDefine、指针整数互转 | C 整数体系、C 语义运算规则 | +| 21 | [PointerTest](PointerTest/App/main.vp) | 指针操作:global 语义/指针算术/数组退化/CVoid↔CUInt32T/字节偏移/大小端 | 指针类型体系、global、大小端 | +| 22 | [LoopMathTest](LoopMathTest/App/main.vp) | while + 数学运算:四则/取模/位运算/复合赋值/三元/优先级/跨模块宏 | 运算全套、运算符优先级、宏引用 | +| 23 | [StringIterTest](StringIterTest/App/main.vp) | 指针迭代/算术、c.Deref/Set/Addr、多级指针、手动 strcpy;@t.Object 内联数组 | 指针算术、内联结构体数组 | +| 24 | [ExpandKeywordsTest](ExpandKeywordsTest/App/main.vp) | 软关键字 fn/fun/func/function 与 def 等价、PEP 695 泛型函数 | 软关键字解析、泛型函数 | +| 25 | [SprintfTest](SprintfTest/App/main.vp) | viperlib.snprintf:%a/%A 十六进制浮点与 glibc 对照、%g 精度 bug、多 int 变参 | 浮点格式化、变参 ABI | +| 26 | [FormatStringTest](FormatStringTest/App/main.vp) | f-string 格式说明符:0x/016X/d/.2f、str 指针算术、CArray[u64]、ctraits.isptr | f-string、格式说明符、编译期类型判断 | +| 27 | [ClassArrayTest](ClassArrayTest/App/main.vp) | 类与数组基础:数据类/三维点/带 __init__ 类/栈堆分配/各类数组/退化指针 | OOP、t.CArray、堆管理 | +| 28 | [BuiltinDecoratorTest](BuiltinDecoratorTest/App/main.vp) | 内置装饰器:@property/getter/setter/deleter、@staticmethod、@classmethod 及混用 | 装饰器全套访问器 | +| 29 | [OopInheritTest](OopInheritTest/App/main.vp) | OOP 继承多态:@t.CVTable 虚方法覆盖、链式调用、运算符重载、三层继承 | 虚分派、运算符重载、链式调用 | +| 30 | [MemhubTest](MemhubTest/App/main.vp) | MemManager 多态:基类指针虚分派 alloc/free、calloc 内部调虚函数 | 虚方法多态、继承体系 | +| 31 | [EnumTest](EnumTest/App/main.vp) | 枚举:CEnum 取值 + REnum 携带数据变体,match/case 解构字段 | CEnum、REnum、match 解构 | +| 32 | [DefineTest](DefineTest/App/main.vp) | 编译期宏:CDefine 常量/宏函数、c.CIf/CIfdef/CIfndef 条件编译、platmacro 平台宏 | 编译期宏、条件编译、平台探测 | +| 33 | [ClosureTest](ClosureTest/App/main.vp) | 闭包作用域:global/nonlocal 嵌套/lambda 捕获/循环变量/global 数组 | 闭包、nonlocal/global、lambda | +| 34 | [ClosureTest2](ClosureTest2/App/main.vp) | 闭包进阶:nonlocal 条件分支/多变量 swap/引用 vs 值捕获/三层嵌套/结构体修改 | 引用捕获语义、多层级 nonlocal | +| 35 | [G3](G3/App/main.vp) | GSListNode F-bounded 泛型继承:`class Node(GSListNode[Node])` 链遍历求和 | 递归泛型/自引用特化 | +| 36 | [G6](G6/App/main.vp) | atom 模块内联汇编原子操作:test_and_set/clear/fence/is_lock_free/spinlock | 内联汇编原子操作 | +| 37 | [VectorGenericTest](VectorGenericTest/App/main.vp) | 泛型容器 vector.Vector(MemPool 池化):Vector[int]/Vector[double] | 泛型容器、内存池 | +| 38 | [DictTest](DictTest/App/main.vp) | dict 库:set/get/下标/len/contains/迭代/扩容/JSON dumps-loads/嵌套/get_vtype | dict 库、JSON、c.Deref | +| 39 | [HashLibTest](HashLibTest/App/main.vp) | hashlib md5/sha1/sha256/sha512、base64 往返、binascii 全套、默认参数函数 | 哈希/编码库、默认参数 | +| 40 | [ArgparseTest](ArgparseTest/App/main.vp) | argparse 库:手工 argv 解析、STORE/STORE_TRUE/COUNT 动作、--name=value、默认值 | argparse、内存布局 | + +### 难度:较难(26 个)—— 泛型进阶、多继承、闭包难点、编译器自身库 + +| # | 项目 | 功能概述 | 关键特性 | +|---|------|---------|---------| +| 41 | [GenericTest2](GenericTest2/App/main.vp) | 高级泛型:Stack[T]/Range[T]/Container[T]/泛型指针交换/__sizeof__ 特化语义 | 泛型+指针+sizeof 特化 | +| 42 | [G4](G4/App/main.vp) | includes 泛型继承(Phase1 stub 路径)+ 多模块(3 caller 交叉引用)链操作 | 泛型继承展平、多模块编译 | +| 43 | [G5](G5/App/main.vp) | GSList[T] opaque 降级问题 + 访问器方案、泛型类作字段类型 | 泛型容器 opaque、跨模块 stub | +| 44 | [G7](G7/App/main.vp) | 最小复现:类名 Value 与全局变量冲突导致 struct body 不完整 | 符号表命名冲突 | +| 45 | [GenericOopTest](GenericOopTest/App/main.vp) | 泛型+OOP 组合:泛型函数互调、泛型类方法调泛型函数、多类型参数 | 泛型嵌套、联合类型强转语法 | +| 46 | [EdgeCaseTest](EdgeCaseTest/App/main.vp) | 类型系统边界:import 别名作基类、前向引用继承、三层 CVTable 传播、BigEndian | 类型别名、前向引用、字节序 | +| 47 | [MultiInheritTest](MultiInheritTest/App/main.vp) | 多继承:字段合并展平、菱形去重、MRO、CVTable 多继承、运算符重载继承 | 多继承布局、菱形、MRO | +| 48 | [SuperTest](SuperTest/App/main.vp) | super() 语义:__init__ 传递、静态绑定父类方法、三层链、MRO 查找 | super、虚表继承、MRO | +| 49 | [IsinstanceTest](IsinstanceTest/App/main.vp) | isinstance 运行时 vtable 继承链比较、元组类型、多继承、跨模块虚分派 | isinstance、运行时类型系统 | +| 50 | [NoVTableTest](NoVTableTest/App/main.vp) | @t.NoVTable 继承:双向/单向链表库、显式向下转型、递归泛型 | 无 vptr 布局、跨模块继承 | +| 51 | [HashTableTest](HashTableTest/App/main.vp) | hashtable 库全生命周期:插入/更新/删除/迭代/50 元素扩容/空表 | 哈希表、Python 风格特殊方法 | +| 52 | [JsonTest](JsonTest/App/main.vp) | json 库:构造/解析/序列化/嵌套取值/转义/内存复用 | json 库、条件表达式、转义 | +| 53 | [LogicFlowTest](LogicFlowTest/App/main.vp) | 控制流组合:for/while 嵌套、match 元组/守卫/穿透、c.Break/c.NoBreak | match 语法面、控制流代码生成 | +| 54 | [FakeDuckTest](FakeDuckTest/App/main.vp) | str 扩展方法全套 + 魔法字段 __data__/__mbuddy__ 注入 + split 8 种边界 + zip | 扩展方法、魔法字段注入、迭代器 | +| 55 | [DecoratorTest](DecoratorTest/App/main.vp) | 自定义装饰器 v4 约定:双阶段钩子、返回语义、@repeat(3)、递归保护 | 装饰器运行时机制 | +| 56 | [BuddyTest](BuddyTest/App/main.vp) | MemBuddy 伙伴分配器压力测试:alloc/free/合并/calloc/realloc/边界/4 线程并发/OOM | 内存分配器、多线程、边界 | +| 57 | [AstTest](AstTest/App/main.vp) | AST 解析/遍历:tokenize/parse/dump、递归遍历、运行时 isinstance 区分节点 | ast 库、运行时 isinstance | +| 58 | [NewAstTest](NewAstTest/App/main.vp) | ast 模块 93 项全面测试:手工构造节点 + parse 大量语法(match/async/lambda/f-string) | ast 库、语法面最广 | +| 59 | [LLvmLiteTest](LLvmLiteTest/App/main.vp) | llvmlite 库 27 节:类型/指令/模块打印/phi/switch/select/原子操作/SSA 验证 | llvmlite、LLVM IR 全套 | +| 60 | [TestFBProject](TestFBProject/App/main.vp) | 异常继承体系 10 场景 + c.LLVMIR 内联 IR + t.CDefine 内联函数宏 | 异常机制、内联 LLVM IR | +| 61 | [FileIoTest](FileIoTest/App/main.vp) | Win32 文件 IO:CreateFile/Write/Read 底层 + OOP File 封装 + 宽字符中文 UTF-16 | Win32 绑定、OOP 封装、宽字符串 | +| 62 | [SysLibTest](SysLibTest/App/main.vp) | 系统库:os.path/os/shutil/sys/subprocess 真实文件与子进程 I/O、平台宏分发 | 标准库集成、子进程、跨平台 | +| 63 | [NumpyTest](NumpyTest/App/main.vp) | numpy 库约 30 组:创建/统计/运算符重载/数学函数/矩阵运算/边界/性能 | numpy、运算符重载、性能 | +| 64 | [SimdTest](SimdTest/App/main.vp) | vipersimd SIMD:AVX2 向量正确性/批量运算/标量精确函数/SIMD 加速比 | SIMD、性能基准 | +| 65 | [ZlibTest](ZlibTest/App/main.vp) | zlib 库约 17 项:压缩往返/级别/增量对象/gzip/raw/zdict/Huffman 树/校验和 | zlib、Huffman、位写入器 | +| 66 | [CPythonTest](CPythonTest/App/main.vp) | CPython C API 绑定 + 包装类运算符重载:PyLong/Float/Unicode/List/Dict/PyRun/Import | CPython 嵌入、运算符重载、引用计数 | + +### 难度:环境依赖(1 个)—— 需真实网络 + +| # | 项目 | 功能概述 | 关键特性 | +|---|------|---------|---------| +| 67 | [WebTest](WebTest/App/main.vp) | 网络栈:socket OOP、DNS 解析、requests.get HTTP 请求(依赖真实网络) | socket/requests、真实网络 I/O | +| 68 | [NoVTableCrossMixinTest](NoVTableCrossMixinTest/App/main.vp) | 回归:@t.NoVTable 多继承下跨 Mixin `self.` 方法调用——BaseB 内 `self.helper()` 调兄弟 Mixin BaseA.helper,须按定义类解析 + this 前移 sizeof(定义类) | 跨 Mixin 调用、NoVTable 多继承、this 调整 | + +--- + +## 二、建议实现顺序(难度升序,共 68 步) + +按"先基础语法 → 再类型系统 → 再容器/OOP → 再泛型/闭包难点 → 最后编译器自身库与外部集成"推进,每步按依赖关系排序。 + +### 第 1 层:基础语法与函数(8 个,建立编译最小可用) +1. **FuncTest** — 函数定义/调用/递归(编译器最基础能力) +2. **LoopTest** — for/while/break/continue(控制流基础) +3. **StringTest** — string 库(字符串是几乎所有测试的依赖) +4. **StructTest** — 结构体基础(OOP 的根基) +5. **EqTest** — 比较语义边界(==/is/None) +6. **ShortCircuitTest** — 短路求值(布尔逻辑正确性) +7. **IterTest** — for-in 字符串迭代 +8. **SlotsBugTest** — 编译期回归(编译通过即达标) + +### 第 2 层:类型系统、运算与声明(9 个) +9. **TypeCastTest** — 类型转换/C 语义运算(后续所有运算正确性的前提) +10. **PointerTest** — 指针操作/算术 +11. **LoopMathTest** — 数学/位运算/复合赋值/优先级 +12. **StringIterTest** — 指针迭代/算术/c.Deref/Set/Addr +13. **ExpandKeywordsTest** — 软关键字 fn/fun/func +14. **VariadicTest** — 变参 printf/snprintf +15. **SprintfTest** — 浮点格式化 %a/%g(格式化正确性) +16. **FormatStringTest** — f-string 格式说明符 +17. **Extern2Test** — 外部声明去重 + +### 第 3 层:容器与内存(8 个) +18. **ListTest** — list[int] 基础容器(泛型 + 联合下标) +19. **MpoolOopTest** — MemPool/MemSlab(后续大量测试依赖 memhub) +20. **MemhubTest** — MemManager 多态(虚分派正确性) +21. **DictTest** — dict 库 + JSON 往返 +22. **HashLibTest** — hashlib/base64/binascii +23. **VRandomTest** — vrandom 库(结构重复、快速验证) +24. **VectorGenericTest** — 泛型容器(初步接触泛型) +25. **ArgparseTest** — argparse(内存布局 + 解析器) + +### 第 4 层:泛型(10 个,编译器核心难点之一) +26. **GenericTest** — 泛型基础(先建立泛型可用性) +27. **GenericTest3** — 泛型函数显式类型参数 +28. **GenericTest4** — 泛型类显式类型参数 +29. **G3** — F-bounded 泛型继承(GSListNode[Node]) +30. **G6** — atom 原子操作(无泛型,穿插放松) +31. **GenericTest2** — 高级泛型 + __sizeof__ 特化语义 +32. **G4** — includes 泛型继承 + 多模块引用 +33. **G5** — GSList[T] opaque 降级/访问器 +34. **G7** — 符号冲突回归(较难,可后置) +35. **GenericOopTest** — 泛型 + OOP 组合 + +### 第 5 层:OOP 与继承(9 个) +36. **ClassArrayTest** — 类与数组基础 +37. **OopInheritTest** — 继承/虚方法/运算符重载/链式调用 +38. **BuiltinDecoratorTest** — property/staticmethod/classmethod +39. **EnumTest** — CEnum/REnum + match 解构 +40. **EdgeCaseTest** — 类型别名/前向引用/多层继承(类型系统边界) +41. **IsinstanceTest** — isinstance vtable 链(运行时类型系统) +42. **MultiInheritTest** — 多继承/菱形/MRO +43. **NoVTableTest** — @t.NoVTable 继承 + 链表库 +44. **SuperTest** — super() 静态绑定/MRO + +### 第 6 层:闭包与控制流进阶(5 个) +45. **ClosureCallTest** — 闭包函数指针调用(最小复现) +46. **ClosureTest** — nonlocal/global/lambda 基础 +47. **ClosureTest2** — 引用 vs 值捕获/多层级(闭包难点) +48. **ForAndLoopTest** — zip/enumerate 迭代器 +49. **LogicFlowTest** — match 元组/守卫/控制流组合 + +### 第 7 层:编译器自身库与综合(8 个) +50. **AstTest** — AST 解析/遍历/isinstance +51. **NewAstTest** — ast 模块 93 项全面回归 +52. **LLvmLiteTest** — llvmlite IR 生成(自举关键,27 节) +53. **BuddyTest** — 内存压力 + 多线程(可并行验证健壮性) +54. **FakeDuckTest** — str 扩展方法 + 魔法字段注入 +55. **DocTest** — __doc__ 跨模块 +56. **DefineTest** — 编译期宏/条件编译/platmacro +57. **DecoratorTest** — 自定义装饰器 v4 约定(运行时机制) + +### 第 8 层:外部库与真实环境(10 个) +58. **HashTableTest** — 哈希表全生命周期 +59. **JsonTest** — json 构造/解析/序列化 +60. **TestFBProject** — 异常体系 + 内联 LLVM IR +61. **FileIoTest** — Win32 文件 IO/宽字符 +62. **SysLibTest** — os/shutil/sys/subprocess 真实 I/O +63. **NumpyTest** — numpy 数值库(运算符重载大考) +64. **SimdTest** — SIMD 向量 + 性能基准 +65. **ZlibTest** — zlib/Huffman(代码量最大) +66. **CPythonTest** — CPython C API 嵌入(依赖 Python 运行时) +67. **WebTest** — socket/requests(依赖真实网络,最后跑) +68. **NoVTableCrossMixinTest** — @t.NoVTable 跨 Mixin self. 调用(编译器缺陷回归) + +--- + +## 三、按主题分组(索引) + +### 基础语法与函数 +FuncTest、LoopTest、LoopMathTest、ShortCircuitTest、ExpandKeywordsTest、TypeCastTest、EqTest、PointerTest + +### 字符串与格式化 +StringTest、StringIterTest、FormatStringTest、VariadicTest、SprintfTest、IterTest、FakeDuckTest(str 扩展方法) + +### 容器与数据结构 +ListTest、DictTest、HashTableTest、VectorGenericTest、JsonTest、HashLibTest + +### OOP 与继承 +StructTest、ClassArrayTest、OopInheritTest、MultiInheritTest、SuperTest、NoVTableTest、IsinstanceTest、BuiltinDecoratorTest、DecoratorTest + +### 泛型 +GenericTest、GenericTest2、GenericTest3、GenericTest4、GenericOopTest、G3、G4、G5、G7 + +### 闭包 +ClosureCallTest、ClosureTest、ClosureTest2 + +### 控制流 +LoopTest、LoopMathTest、LogicFlowTest、ForAndLoopTest、EnumTest(match 解构)、EdgeCaseTest + +### 内存管理 +BuddyTest、MpoolOopTest、MemhubTest + +### 编译期机制 +DefineTest、Extern2Test、SlotsBugTest、TestFBProject(部分) + +### 编译器自身库(自举用) +AstTest、NewAstTest、LLvmLiteTest、BuddyTest、DictTest、HashTableTest、JsonTest + +### 外部库/系统集成 +FileIoTest、SysLibTest、WebTest、ZlibTest、NumpyTest、SimdTest、CPythonTest、ArgparseTest、VRandomTest + +### 回归复现(缺陷最小化) +G7(符号冲突)、ClosureCallTest(闭包指针调用)、Extern2Test(声明去重)、SlotsBugTest(注解崩溃)、SprintfTest(%g 精度/变参) + +--- + +## 四、排序原则说明 + +1. **依赖优先**:`FuncTest`/`TypeCastTest` 保证基础运算 → `MpoolOopTest`/`ListTest` 建立 memhub/容器 → 所有依赖它们的测试。 +2. **先面后点**:先用每主题"基础版"(GenericTest、ClosureTest、OopInheritTest)验证可用,再用进阶版(GenericTest2、ClosureTest2、MultiInheritTest)压边界。 +3. **难点靠后**:泛型(G4/G5/G7)、多继承(MultiInheritTest/SuperTest)、闭包值捕获(ClosureTest2)、装饰器运行时(DecoratorTest)等语义深处放中后段。 +4. **编译器自举相关后置**:AstTest/NewAstTest/LLvmLiteTest 验证编译器自身依赖的库,是自举实验的前置检查。 +5. **环境依赖最后**:WebTest(真实网络)、CPythonTest(Python 运行时)、FileIoTest/SysLibTest(真实文件系统)放最后,避免环境问题干扰核心编译器验证。 +6. **回归复现型穿插**:G7/ClosureCallTest/Extern2Test/SlotsBugTest 等最小复现用例可随时单独运行验证特定修复。 diff --git a/RawArrayTest/App/main.vp b/RawArrayTest/App/main.vp new file mode 100644 index 0000000..3e0f254 --- /dev/null +++ b/RawArrayTest/App/main.vp @@ -0,0 +1,45 @@ +import t, c +from stdint import * +import stdio + + +# 模块级全局定长数组(rawarray 复刻 t.CArray) +g_arr: rawarray[t.CInt, 4] = [10, 20, 30, 40] + + +# struct 内嵌定长数组字段 +class Ctx: + state: rawarray[uint32, 5] + buf: rawarray[uint8, 64] + + +def main() -> t.CInt | t.CExport: + # 1) 全局数组读取 + stdio.printf("1 g_arr[0]=%d g_arr[3]=%d (expect 10 40)\n", g_arr[0], g_arr[3]) + + # 2) 局部定长数组(写 + 读) + loc: rawarray[uint32, 3] = [0, 0, 0] + loc[1] = 7 + stdio.printf("2 loc[1]=%d (expect 7)\n", loc[1]) + + # 3) struct 内嵌数组字段 + ctx: Ctx + ctx.state[0] = 100 + ctx.state[4] = 400 + ctx.buf[0] = 65 + stdio.printf("3 ctx.state[0]=%d ctx.state[4]=%d ctx.buf[0]=%d (expect 100 400 65)\n", + ctx.state[0], ctx.state[4], int(ctx.buf[0])) + + # 4) 参数数组衰减(CArray 形参 → 元素指针)+ sizeof + total: int = sum_arr(loc, 3) + stdio.printf("4 sum=%d (expect 7)\n", total) + + return 0 + + +def sum_arr(vals: rawarray[uint32, 3], n: int) -> int: + s: int = 0 + i: int + for i in range(n): + s = s + int(vals[i]) + return s diff --git a/RawArrayTest/project.json b/RawArrayTest/project.json new file mode 100644 index 0000000..92a20a2 --- /dev/null +++ b/RawArrayTest/project.json @@ -0,0 +1,40 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "RawArrayTest", + "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": "RawArrayTest.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 + } +} diff --git a/SequentialRegressionTest.py b/SequentialRegressionTest.py new file mode 100644 index 0000000..ea202a4 --- /dev/null +++ b/SequentialRegressionTest.py @@ -0,0 +1,290 @@ +#!/usr/bin/env python3 +"""TransPyC 顺序回归测试脚本 + +与 regression_test.py 的区别: +1. 按 Test/README.md「建议实现顺序」节(难度升序,68 个项目)逐个编译 +2. 每个项目编译成功后立即运行其可执行文件 +3. 编译或运行失败立刻结束(fail-fast),退出码非 0 +""" +import os +import sys +import json +import time +import re +import subprocess +import argparse + +# 强制 stdout/stderr 使用 UTF-8 编码,避免 Windows GBK 编码在打印含替换字符的输出时崩溃 +try: + sys.stdout.reconfigure(encoding='utf-8', errors='replace') + sys.stderr.reconfigure(encoding='utf-8', errors='replace') +except Exception: + pass + +# ============================================================ +# 路径 +# ============================================================ +TEST_DIR = os.path.dirname(os.path.abspath(__file__)) +# 项目根目录(含 TransPyC/、TransPyV/、Test/ 等同级目录) +PROJECT_ROOT = os.path.dirname(TEST_DIR) +# Projectrans.py 路径:编译器入口在 /TransPyC/Projectrans.py +# (旧值 /Projectrans.py 已不存在,与 regression_test.py:45-48 同一条记录) +PROJECTRANS = os.path.join(PROJECT_ROOT, "TransPyC", "Projectrans.py") +# README.md 路径(顺序来源,原 TestsOverview.md) +OVERVIEW = os.path.join(TEST_DIR, "README.md") + +# 编译超时(秒) +COMPILE_TIMEOUT = 300 +# 运行超时(秒) +RUN_TIMEOUT = 30 + + +def read_test_order(): + """从 README.md「建议实现顺序」节提取项目名(难度升序)""" + with open(OVERVIEW, encoding='utf-8') as f: + text = f.read() + m = re.search(r'##\s*二、\s*建议实现顺序(.*?)##\s*三、', text, re.S) + if not m: + raise SystemExit("README.md 中找不到「建议实现顺序」节") + section = m.group(1) + order = [] + for line in section.splitlines(): + mm = re.match(r'\s*\d+\.\s*\*\*(.+?)\*\*', line) + if mm: + order.append(mm.group(1)) + if not order: + raise SystemExit("「建议实现顺序」节中未解析到任何项目名") + return order + + +def build_compile_cmd(args): + """根据 --exe/--compiler 构建编译命令模板({project} 为项目 json 路径占位) + + --exe 指定编译器可执行文件(如 TransPyV.exe),优先于 --compiler; + 两者都未指定时使用 TPC(python Projectrans.py)。 + --rebuild-includes 时追加 --rebuild-includes(全量重编 includes, + 修复 includes.binary 缓存不一致导致的 undefined symbol)。 + """ + suffix = " --rebuild-includes" if args.rebuild_includes else "" + if args.exe: + return f'"{args.exe}" --project {{project}} --clean{suffix}' + if args.compiler: + return args.compiler + return f'D:\\Python312\\python.exe -u "{PROJECTRANS}" --project {{project}} --clean{suffix}' + + +def compile_project(cmd, proj_dir): + """编译单个测试项目,返回 (success, elapsed, combined_output)""" + start = time.time() + result = subprocess.run( + cmd, + shell=True, + capture_output=True, + text=True, + encoding='utf-8', + errors='replace', + cwd=proj_dir, + timeout=COMPILE_TIMEOUT, + ) + elapsed = time.time() - start + + combined = (result.stdout or "") + (result.stderr or "") + return (result.returncode == 0, elapsed, combined) + + +def find_executables(output_dir): + """在 output 目录中查找可执行文件""" + exes = [] + if not os.path.isdir(output_dir): + return exes + for f in os.listdir(output_dir): + fpath = os.path.join(output_dir, f) + if os.path.isfile(fpath) and (f.endswith('.exe') or f.endswith('.bin')): + exes.append(fpath) + return exes + + +def find_output_dirs(proj_dir, proj_config): + """收集候选输出目录(兼容 TPC 与 TPV 布局) + + - project.json 显式 output_dir(TPC 常用) + - project.json build_dir + '/output'(TPV 布局:.tpv_build/output) + - 兜底 ./output + 保序去重返回。 + """ + dirs = [] + od = proj_config.get('output_dir') + if od: + dirs.append(os.path.abspath(os.path.join(proj_dir, od))) + bd = proj_config.get('build_dir') + if bd: + dirs.append(os.path.abspath(os.path.join(proj_dir, bd, 'output'))) + if not dirs: + dirs.append(os.path.abspath(os.path.join(proj_dir, './output'))) + seen = set() + uniq = [] + for d in dirs: + if d not in seen: + seen.add(d) + uniq.append(d) + return uniq + + +def run_executable(exe_path): + """运行单个可执行文件,返回 (returncode, stdout, stderr, timed_out) + + 超时 RUN_TIMEOUT 秒强制结束。 + 使用 CREATE_NO_WINDOW 避免弹出 cmd 窗口,通过管道捕获 stdout/stderr。 + """ + try: + CREATE_NO_WINDOW = 0x08000000 + result = subprocess.run( + [exe_path], + cwd=os.path.dirname(exe_path), + capture_output=True, + text=True, + encoding='utf-8', + errors='replace', + timeout=RUN_TIMEOUT, + creationflags=CREATE_NO_WINDOW, + ) + return (result.returncode, result.stdout or "", result.stderr or "", False) + except subprocess.TimeoutExpired: + return (-1, "", "超时(强制终止)", True) + except Exception as e: + return (-1, "", str(e), False) + + +def print_tail(output, max_lines=40): + """打印输出尾部(编译/运行失败时的诊断信息)""" + lines = output.strip().splitlines() + if len(lines) > max_lines: + print(f" ... (省略前 {len(lines) - max_lines} 行) ...") + lines = lines[-max_lines:] + for line in lines: + print(f" {line}") + + +def main(): + parser = argparse.ArgumentParser( + description="TransPyC 顺序回归测试(按 README.md 顺序,失败即停)") + parser.add_argument("--exe", default=None, + help="编译器可执行文件(如 TransPyV.exe),用它编译测试项目(替代 TPC)") + parser.add_argument("--compiler", default=None, + help="自定义编译命令模板,用 {project} 表示项目 json 路径;默认 TPC python") + parser.add_argument("--rebuild-includes", action="store_true", + help="每次编译追加 --rebuild-includes:清空 includes.binary 全量重编(修复缓存不一致)") + parser.add_argument("--number", type=int, default=1, + help="从第几个案例开始(1 开始编号),编译该编号及之后的项目;默认 1") + args = parser.parse_args() + compile_cmd = build_compile_cmd(args) + + print("=" * 70) + print("TransPyC 顺序回归测试(按 README.md 顺序,失败即停)") + print("=" * 70) + print() + + order = read_test_order() + total = len(order) + + start = max(1, args.number) + if start > total: + print(f"错误: --number {args.number} 超出总项目数 {total}") + return 1 + print(f"按顺序共 {total} 个项目,从第 {start} 个({order[start - 1]})开始") + print(f"编译命令: {compile_cmd}\n") + + passed = 0 + for idx, name in enumerate(order, 1): + if idx < start: + continue + proj_dir = os.path.join(TEST_DIR, name) + proj_json = os.path.join(proj_dir, "project.json") + + if not os.path.isfile(proj_json): + print(f"[{idx}/{total}] {name}: 缺少 project.json,跳过") + continue + + # ---------- 编译 ---------- + print(f"[{idx}/{total}] 编译 {name} ...", end=" ", flush=True) + cmd = compile_cmd.format(project=proj_json) + try: + compile_ok, elapsed, output = compile_project(cmd, proj_dir) + except subprocess.TimeoutExpired: + print("编译超时(5 分钟)") + print_tail("编译超时(5 分钟)") + print(f"\n在 {name} 编译超时,立即终止。") + return 1 + except Exception as e: + print(f"异常: {e}") + print_tail(str(e)) + print(f"\n在 {name} 编译异常,立即终止。") + return 1 + + if not compile_ok: + print(f"失败 ({elapsed:.1f}s)") + print_tail(output) + print(f"\n在 {name} 编译失败,立即终止。") + return 1 + print(f"通过 ({elapsed:.1f}s)") + + # ---------- 编译成功后立即运行 ---------- + # project.json 解析失败必须**立刻终止并报错**:静默退化成 {} 会让下面拿不到 + # build_dir(TPV 布局 .tpv_build/output),只在 <项目>/output 里找可执行文件, + # 于是明明编译成功却被判成"未找到可执行文件"。实测踩过:LLvmLiteTest 的 + # project.json 有一个尾逗号(第 18 行 `],`)——标准 JSON 非法(TPV 自带解析器 + # 宽容才编得过),此处不再吞异常。 + try: + with open(proj_json, 'r', encoding='utf-8') as f: + proj_config = json.load(f) + except Exception as e: + print(f" [运行] project.json 解析失败: {e}") + print(f"\n在 {name} 读取 project.json 失败,立即终止(请修正该文件后重跑)。") + return 1 + + output_dirs = find_output_dirs(proj_dir, proj_config) + exes = [] + for od in output_dirs: + exes = find_executables(od) + if exes: + break + + if not exes: + print(f" [运行] 未找到可执行文件(候选: {'; '.join(output_dirs)}),视为运行失败") + return 1 + + run_ok = True + for exe_path in exes: + exe_name = os.path.basename(exe_path) + print(f" [运行] {exe_name} ...", end=" ", flush=True) + returncode, stdout, stderr, timed_out = run_executable(exe_path) + + if timed_out: + print("超时") + print_tail(stdout + stderr) + run_ok = False + elif returncode == 0: + print("通过") + else: + print(f"失败(退出码 {returncode})") + print_tail(stdout + stderr) + run_ok = False + + if not run_ok: + break + + if not run_ok: + print(f"\n在 {name} 运行失败,立即终止。") + return 1 + + passed += 1 + + print() + print("=" * 70) + print(f"全部 {passed} 个项目编译并运行通过!") + print("=" * 70) + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/ShortCircuitTest/App/main.vp b/ShortCircuitTest/App/main.vp new file mode 100644 index 0000000..925866b --- /dev/null +++ b/ShortCircuitTest/App/main.vp @@ -0,0 +1,122 @@ +from stdint import * +import w32.win32console +import t, c +from t import CInt, CExport +import stdio +import stdlib +import string +import testcheck + + +# 副作用函数:将 buf[0] 置为 1,返回 True +def bump_true(buf: bytes) -> bool: + buf[0] = 1 + return True + + +# 副作用函数:将 buf[0] 置为 1,返回 False +def bump_false(buf: bytes) -> bool: + buf[0] = 1 + return False + + +def main() -> CInt | CExport: + w32.win32console.SetConsoleCP(65001) + w32.win32console.SetConsoleOutputCP(65001) + + testcheck.begin("if 短路机制测试") + + buf: bytes = stdlib.malloc(1) + + # === Test 1: False and bump_true() - bump 不应被调用 === + testcheck.section("Test 1: False and bump_true()") + buf[0] = 0 + r1: bool = False and bump_true(buf) + testcheck.check(buf[0] == 0, "and short-circuit OK (bump not called)", "and short-circuit FAILED (bump called)") + + # === Test 2: True or bump_true() - bump 不应被调用 === + testcheck.section("Test 2: True or bump_true()") + buf[0] = 0 + r2: bool = True or bump_true(buf) + testcheck.check(buf[0] == 0, "or short-circuit OK (bump not called)", "or short-circuit FAILED (bump called)") + + # === Test 3: True and bump_true() - bump 应被调用 === + testcheck.section("Test 3: True and bump_true()") + buf[0] = 0 + r3: bool = True and bump_true(buf) + testcheck.check(buf[0] == 1, "and eval OK (bump called)", "and eval FAILED (bump not called)") + + # === Test 4: False or bump_true() - bump 应被调用 === + testcheck.section("Test 4: False or bump_true()") + buf[0] = 0 + r4: bool = False or bump_true(buf) + testcheck.check(buf[0] == 1, "or eval OK (bump called)", "or eval FAILED (bump not called)") + + # === Test 5: if 语句中的短路 === + testcheck.section("Test 5: if 语句中的短路") + buf[0] = 0 + if False and bump_true(buf): + testcheck.check(False, "should not enter if", "if False and entered") + testcheck.check(buf[0] == 0, "if and short-circuit OK", "if and short-circuit FAILED") + + buf[0] = 0 + if True or bump_true(buf): + testcheck.check(True, "if True or entered OK", "if True or not entered") + else: + testcheck.check(False, "should enter if", "if True or else") + testcheck.check(buf[0] == 0, "if or short-circuit OK", "if or short-circuit FAILED") + + # === Test 6: 嵌套短路 === + testcheck.section("Test 6: 嵌套短路") + buf[0] = 0 + r6: bool = False and (True or bump_true(buf)) + testcheck.check(buf[0] == 0, "nested and short-circuit OK", "nested and short-circuit FAILED") + + buf[0] = 0 + r7: bool = True or (False and bump_true(buf)) + testcheck.check(buf[0] == 0, "nested or short-circuit OK", "nested or short-circuit FAILED") + + # === Test 7: not 与短路 === + testcheck.section("Test 7: not 与短路") + buf[0] = 0 + r8: bool = not False and bump_true(buf) + testcheck.check(buf[0] == 1, "not and eval OK (bump called)", "not and eval FAILED (bump not called)") + + buf[0] = 0 + r9: bool = not True or bump_true(buf) + testcheck.check(buf[0] == 1, "not or eval OK (bump called)", "not or eval FAILED (bump not called)") + + # === Test 8: and 链中第一个为 False,后续不评估 === + testcheck.section("Test 8: and 链短路") + buf[0] = 0 + r10: bool = False and bump_true(buf) and bump_true(buf) + testcheck.check(buf[0] == 0, "and chain short-circuit OK", "and chain short-circuit FAILED") + + # === Test 9: or 链中第一个为 True,后续不评估 === + testcheck.section("Test 9: or 链短路") + buf[0] = 0 + r11: bool = True or bump_true(buf) or bump_true(buf) + testcheck.check(buf[0] == 0, "or chain short-circuit OK", "or chain short-circuit FAILED") + + # === Test 10: and 返回值正确性 === + testcheck.section("Test 10: and 返回值正确性") + buf[0] = 0 + r12: bool = True and bump_true(buf) + testcheck.check(r12, "and return True OK", "and return True FAILED") + + buf[0] = 0 + r13: bool = True and bump_false(buf) + testcheck.check(not r13, "and return False OK", "and return False FAILED") + + # === Test 11: or 返回值正确性 === + testcheck.section("Test 11: or 返回值正确性") + buf[0] = 0 + r14: bool = False or bump_true(buf) + testcheck.check(r14, "or return True OK", "or return True FAILED") + + buf[0] = 0 + r15: bool = False or bump_false(buf) + testcheck.check(not r15, "or return False OK", "or return False FAILED") + + stdlib.free(buf) + return testcheck.end() diff --git a/ShortCircuitTest/project.json b/ShortCircuitTest/project.json new file mode 100644 index 0000000..f964f81 --- /dev/null +++ b/ShortCircuitTest/project.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "ShortCircuitTest", + "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": "ShortCircuitTest.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 + } +} diff --git a/SimdTest/App/main.vp b/SimdTest/App/main.vp new file mode 100644 index 0000000..ed98962 --- /dev/null +++ b/SimdTest/App/main.vp @@ -0,0 +1,502 @@ +from stdint import * +import vipersimd +import numpy +from stdio import printf +import stdlib +from stdlib import calloc +import t, c +import memhub +import testcheck + + +# 全局内存池 +arena: t.CUInt8T | t.CPtr = None +pool: memhub.MemPool | t.CPtr = None + +# 外部函数: clock() 用于性能计时 +def clock() -> t.CLong | t.CExtern: pass + +CLOCK_PER_SEC: t.CDefine = 1000 + + +# ============================================================ +# 1. AVX2 double4 正确性测试 +# ============================================================ + +def test_avx2_add_sub_mul_div(): + testcheck.section("AVX2 add/sub/mul/div 4d") + a: numpy.ndarray[t.CDouble] | t.CPtr = numpy.zeros(pool, 4) + a.data[0] = t.CDouble(1.0) + a.data[1] = t.CDouble(2.0) + a.data[2] = t.CDouble(3.0) + a.data[3] = t.CDouble(4.0) + + b: numpy.ndarray[t.CDouble] | t.CPtr = numpy.zeros(pool, 4) + b.data[0] = t.CDouble(5.0) + b.data[1] = t.CDouble(6.0) + b.data[2] = t.CDouble(7.0) + b.data[3] = t.CDouble(8.0) + + out: numpy.ndarray[t.CDouble] | t.CPtr = numpy.zeros(pool, 4) + + # add + vipersimd.simd_add4d(a.data, b.data, out.data) + testcheck.check(out.data[0] == t.CDouble(6.0), "add[0]==6", "add[0]==6") + testcheck.check(out.data[1] == t.CDouble(8.0), "add[1]==8", "add[1]==8") + testcheck.check(out.data[2] == t.CDouble(10.0), "add[2]==10", "add[2]==10") + testcheck.check(out.data[3] == t.CDouble(12.0), "add[3]==12", "add[3]==12") + + # sub + vipersimd.simd_sub4d(a.data, b.data, out.data) + testcheck.check(out.data[0] == t.CDouble(-4.0), "sub[0]==-4", "sub[0]==-4") + testcheck.check(out.data[3] == t.CDouble(-4.0), "sub[3]==-4", "sub[3]==-4") + + # mul + vipersimd.simd_mul4d(a.data, b.data, out.data) + testcheck.check(out.data[0] == t.CDouble(5.0), "mul[0]==5", "mul[0]==5") + testcheck.check(out.data[1] == t.CDouble(12.0), "mul[1]==12", "mul[1]==12") + testcheck.check(out.data[2] == t.CDouble(21.0), "mul[2]==21", "mul[2]==21") + testcheck.check(out.data[3] == t.CDouble(32.0), "mul[3]==32", "mul[3]==32") + + # div + vipersimd.simd_div4d(b.data, a.data, out.data) + testcheck.check(out.data[0] == t.CDouble(5.0), "div[0]==5", "div[0]==5") + testcheck.check(out.data[1] == t.CDouble(3.0), "div[1]==3", "div[1]==3") + + a.delete() + b.delete() + out.delete() + + +def test_avx2_neg_abs_sqrt(): + testcheck.section("AVX2 neg/abs/sqrt 4d") + a: numpy.ndarray[t.CDouble] | t.CPtr = numpy.zeros(pool, 4) + a.data[0] = t.CDouble(1.0) + a.data[1] = t.CDouble(-4.0) + a.data[2] = t.CDouble(9.0) + a.data[3] = t.CDouble(-16.0) + + out: numpy.ndarray[t.CDouble] | t.CPtr = numpy.zeros(pool, 4) + + # neg + vipersimd.simd_neg4d(a.data, out.data) + testcheck.check(out.data[0] == t.CDouble(-1.0), "neg[0]==-1", "neg[0]==-1") + testcheck.check(out.data[1] == t.CDouble(4.0), "neg[1]==4", "neg[1]==4") + testcheck.check(out.data[2] == t.CDouble(-9.0), "neg[2]==-9", "neg[2]==-9") + testcheck.check(out.data[3] == t.CDouble(16.0), "neg[3]==16", "neg[3]==16") + + # abs + vipersimd.simd_abs4d(a.data, out.data) + testcheck.check(out.data[0] == t.CDouble(1.0), "abs[0]==1", "abs[0]==1") + testcheck.check(out.data[1] == t.CDouble(4.0), "abs[1]==4", "abs[1]==4") + testcheck.check(out.data[2] == t.CDouble(9.0), "abs[2]==9", "abs[2]==9") + testcheck.check(out.data[3] == t.CDouble(16.0), "abs[3]==16", "abs[3]==16") + + # sqrt + vipersimd.simd_sqrt4d(out.data, out.data) + testcheck.check(out.data[0] == t.CDouble(1.0), "sqrt[0]==1", "sqrt[0]==1") + testcheck.check(out.data[1] == t.CDouble(2.0), "sqrt[1]==2", "sqrt[1]==2") + testcheck.check(out.data[2] == t.CDouble(3.0), "sqrt[2]==3", "sqrt[2]==3") + testcheck.check(out.data[3] == t.CDouble(4.0), "sqrt[3]==4", "sqrt[3]==4") + + a.delete() + out.delete() + + +def test_avx2_min_max(): + testcheck.section("AVX2 min/max 4d") + a: numpy.ndarray[t.CDouble] | t.CPtr = numpy.zeros(pool, 4) + a.data[0] = t.CDouble(1.0) + a.data[1] = t.CDouble(8.0) + a.data[2] = t.CDouble(3.0) + a.data[3] = t.CDouble(6.0) + + b: numpy.ndarray[t.CDouble] | t.CPtr = numpy.zeros(pool, 4) + b.data[0] = t.CDouble(5.0) + b.data[1] = t.CDouble(2.0) + b.data[2] = t.CDouble(7.0) + b.data[3] = t.CDouble(4.0) + + out: numpy.ndarray[t.CDouble] | t.CPtr = numpy.zeros(pool, 4) + + vipersimd.simd_min4d(a.data, b.data, out.data) + testcheck.check(out.data[0] == t.CDouble(1.0), "min[0]==1", "min[0]==1") + testcheck.check(out.data[1] == t.CDouble(2.0), "min[1]==2", "min[1]==2") + testcheck.check(out.data[2] == t.CDouble(3.0), "min[2]==3", "min[2]==3") + testcheck.check(out.data[3] == t.CDouble(4.0), "min[3]==4", "min[3]==4") + + vipersimd.simd_max4d(a.data, b.data, out.data) + testcheck.check(out.data[0] == t.CDouble(5.0), "max[0]==5", "max[0]==5") + testcheck.check(out.data[1] == t.CDouble(8.0), "max[1]==8", "max[1]==8") + testcheck.check(out.data[2] == t.CDouble(7.0), "max[2]==7", "max[2]==7") + testcheck.check(out.data[3] == t.CDouble(6.0), "max[3]==6", "max[3]==6") + + a.delete() + b.delete() + out.delete() + + +def test_avx2_scalar_ops(): + testcheck.section("AVX2 scalar broadcast ops") + a: numpy.ndarray[t.CDouble] | t.CPtr = numpy.zeros(pool, 4) + a.data[0] = t.CDouble(1.0) + a.data[1] = t.CDouble(2.0) + a.data[2] = t.CDouble(3.0) + a.data[3] = t.CDouble(4.0) + + s: numpy.ndarray[t.CDouble] | t.CPtr = numpy.zeros(pool, 1) + s.data[0] = t.CDouble(10.0) + + out: numpy.ndarray[t.CDouble] | t.CPtr = numpy.zeros(pool, 4) + + vipersimd.simd_mul_scalar4d(a.data, s.data, out.data) + testcheck.check(out.data[0] == t.CDouble(10.0), "mul_scalar[0]==10", "mul_scalar[0]==10") + testcheck.check(out.data[1] == t.CDouble(20.0), "mul_scalar[1]==20", "mul_scalar[1]==20") + testcheck.check(out.data[3] == t.CDouble(40.0), "mul_scalar[3]==40", "mul_scalar[3]==40") + + vipersimd.simd_add_scalar4d(a.data, s.data, out.data) + testcheck.check(out.data[0] == t.CDouble(11.0), "add_scalar[0]==11", "add_scalar[0]==11") + testcheck.check(out.data[3] == t.CDouble(14.0), "add_scalar[3]==14", "add_scalar[3]==14") + + a.delete() + s.delete() + out.delete() + + +def test_avx2_hsum_dot(): + testcheck.section("AVX2 hsum/dot 4d") + a: numpy.ndarray[t.CDouble] | t.CPtr = numpy.zeros(pool, 4) + a.data[0] = t.CDouble(1.0) + a.data[1] = t.CDouble(2.0) + a.data[2] = t.CDouble(3.0) + a.data[3] = t.CDouble(4.0) + + b: numpy.ndarray[t.CDouble] | t.CPtr = numpy.zeros(pool, 4) + b.data[0] = t.CDouble(5.0) + b.data[1] = t.CDouble(6.0) + b.data[2] = t.CDouble(7.0) + b.data[3] = t.CDouble(8.0) + + out: numpy.ndarray[t.CDouble] | t.CPtr = numpy.zeros(pool, 1) + + vipersimd.simd_hsum4d(a.data, out.data) + testcheck.check(out.data[0] == t.CDouble(10.0), "hsum==10", "hsum==10") + + vipersimd.simd_dot4d(a.data, b.data, out.data) + testcheck.check(out.data[0] == t.CDouble(70.0), "dot==70", "dot==70") + + a.delete() + b.delete() + out.delete() + + +def test_avx2_fma(): + testcheck.section("AVX2 FMA 4d") + a: numpy.ndarray[t.CDouble] | t.CPtr = numpy.zeros(pool, 4) + a.data[0] = t.CDouble(1.0) + a.data[1] = t.CDouble(2.0) + a.data[2] = t.CDouble(3.0) + a.data[3] = t.CDouble(4.0) + + b: numpy.ndarray[t.CDouble] | t.CPtr = numpy.zeros(pool, 4) + b.data[0] = t.CDouble(5.0) + b.data[1] = t.CDouble(6.0) + b.data[2] = t.CDouble(7.0) + b.data[3] = t.CDouble(8.0) + + c_val: numpy.ndarray[t.CDouble] | t.CPtr = numpy.ones(pool, 4) + + out: numpy.ndarray[t.CDouble] | t.CPtr = numpy.zeros(pool, 4) + + vipersimd.simd_fma4d(a.data, b.data, c_val.data, out.data) + testcheck.check(out.data[0] == t.CDouble(6.0), "fma[0]==6", "fma[0]==6") + testcheck.check(out.data[1] == t.CDouble(13.0), "fma[1]==13", "fma[1]==13") + testcheck.check(out.data[2] == t.CDouble(22.0), "fma[2]==22", "fma[2]==22") + testcheck.check(out.data[3] == t.CDouble(33.0), "fma[3]==33", "fma[3]==33") + + a.delete() + b.delete() + c_val.delete() + out.delete() + + +# ============================================================ +# 2. 批量数组运算正确性测试 +# ============================================================ + +def test_batch_array_ops(): + testcheck.section("Batch array operations") + n: t.CSizeT = 16 + a: numpy.ndarray[t.CDouble] | t.CPtr = numpy.arange(pool, t.CDouble(1.0), t.CDouble(17.0), t.CDouble(1.0)) + b: numpy.ndarray[t.CDouble] | t.CPtr = numpy.full(pool, 16, t.CDouble(2.0)) + out: numpy.ndarray[t.CDouble] | t.CPtr = numpy.zeros(pool, 16) + + # add array + vipersimd.simd_add_array(a.data, b.data, out.data, n) + testcheck.check(out.data[0] == t.CDouble(3.0), "add_arr[0]==3", "add_arr[0]==3") + testcheck.check(out.data[15] == t.CDouble(18.0), "add_arr[15]==18", "add_arr[15]==18") + + # mul array + vipersimd.simd_mul_array(a.data, b.data, out.data, n) + testcheck.check(out.data[0] == t.CDouble(2.0), "mul_arr[0]==2", "mul_arr[0]==2") + testcheck.check(out.data[3] == t.CDouble(8.0), "mul_arr[3]==8", "mul_arr[3]==8") + + # sqrt array + c: numpy.ndarray[t.CDouble] | t.CPtr = numpy.zeros(pool, 4) + c.data[0] = t.CDouble(4.0) + c.data[1] = t.CDouble(9.0) + c.data[2] = t.CDouble(16.0) + c.data[3] = t.CDouble(25.0) + out4: numpy.ndarray[t.CDouble] | t.CPtr = numpy.zeros(pool, 4) + vipersimd.simd_sqrt_array(c.data, out4.data, t.CSizeT(4)) + testcheck.check(out4.data[0] == t.CDouble(2.0), "sqrt_arr[0]==2", "sqrt_arr[0]==2") + testcheck.check(out4.data[3] == t.CDouble(5.0), "sqrt_arr[3]==5", "sqrt_arr[3]==5") + + # abs array + d: numpy.ndarray[t.CDouble] | t.CPtr = numpy.zeros(pool, 4) + d.data[0] = t.CDouble(-1.0) + d.data[1] = t.CDouble(-2.0) + d.data[2] = t.CDouble(3.0) + d.data[3] = t.CDouble(-4.0) + vipersimd.simd_abs_array(d.data, out4.data, t.CSizeT(4)) + testcheck.check(out4.data[0] == t.CDouble(1.0), "abs_arr[0]==1", "abs_arr[0]==1") + testcheck.check(out4.data[1] == t.CDouble(2.0), "abs_arr[1]==2", "abs_arr[1]==2") + testcheck.check(out4.data[3] == t.CDouble(4.0), "abs_arr[3]==4", "abs_arr[3]==4") + + # dot array + e: numpy.ndarray[t.CDouble] | t.CPtr = numpy.zeros(pool, 4) + e.data[0] = t.CDouble(1.0) + e.data[1] = t.CDouble(2.0) + e.data[2] = t.CDouble(3.0) + e.data[3] = t.CDouble(4.0) + f: numpy.ndarray[t.CDouble] | t.CPtr = numpy.ones(pool, 4) + out1: numpy.ndarray[t.CDouble] | t.CPtr = numpy.zeros(pool, 1) + vipersimd.simd_dot_array(e.data, f.data, t.CSizeT(4), out1.data) + testcheck.check(out1.data[0] == t.CDouble(10.0), "dot_arr==10", "dot_arr==10") + + a.delete() + b.delete() + out.delete() + c.delete() + out4.delete() + d.delete() + e.delete() + f.delete() + out1.delete() + + +# ============================================================ +# 3. LLVMIR 精确标量运算测试 +# ============================================================ + +def test_llvmir_scalar(): + testcheck.section("LLVMIR precise scalar ops") + + # sqrt + r: t.CDouble = vipersimd.simd_sqrt(t.CDouble(4.0)) + testcheck.check(r == t.CDouble(2.0), "sqrt(4)==2", "sqrt(4)==2") + + # fabs + r = vipersimd.simd_fabs(t.CDouble(-3.5)) + testcheck.check(r == t.CDouble(3.5), "fabs(-3.5)==3.5", "fabs(-3.5)==3.5") + + # floor + r = vipersimd.simd_floor(t.CDouble(3.7)) + testcheck.check(r == t.CDouble(3.0), "floor(3.7)==3", "floor(3.7)==3") + + # ceil + r = vipersimd.simd_ceil(t.CDouble(3.2)) + testcheck.check(r == t.CDouble(4.0), "ceil(3.2)==4", "ceil(3.2)==4") + + # round + r = vipersimd.simd_round(t.CDouble(3.5)) + testcheck.check(r == t.CDouble(4.0), "round(3.5)==4", "round(3.5)==4") + + # trunc + r = vipersimd.simd_trunc(t.CDouble(3.9)) + testcheck.check(r == t.CDouble(3.0), "trunc(3.9)==3", "trunc(3.9)==3") + + # fma: 2*3+1 = 7 + r = vipersimd.simd_fma(t.CDouble(2.0), t.CDouble(3.0), t.CDouble(1.0)) + testcheck.check(r == t.CDouble(7.0), "fma(2,3,1)==7", "fma(2,3,1)==7") + + # copysign + r = vipersimd.simd_copysign(t.CDouble(3.0), t.CDouble(-1.0)) + testcheck.check(r == t.CDouble(-3.0), "copysign(3,-1)==-3", "copysign(3,-1)==-3") + + # neg + r = vipersimd.simd_neg(t.CDouble(1.5)) + testcheck.check(r == t.CDouble(-1.5), "neg(1.5)==-1.5", "neg(1.5)==-1.5") + + # minnum + r = vipersimd.simd_minnum(t.CDouble(2.0), t.CDouble(3.0)) + testcheck.check(r == t.CDouble(2.0), "minnum(2,3)==2", "minnum(2,3)==2") + + # maxnum + r = vipersimd.simd_maxnum(t.CDouble(2.0), t.CDouble(3.0)) + testcheck.check(r == t.CDouble(3.0), "maxnum(2,3)==3", "maxnum(2,3)==3") + + # exp + r = vipersimd.simd_exp(t.CDouble(1.0)) + testcheck.check(r > t.CDouble(2.71) and r < t.CDouble(2.72), "exp(1)~=2.718", "exp(1)~=2.718") + + # log + r = vipersimd.simd_log(t.CDouble(2.718281828459045)) + testcheck.check(r > t.CDouble(0.999) and r < t.CDouble(1.001), "log(e)~=1", "log(e)~=1") + + # sin + r = vipersimd.simd_sin(t.CDouble(0.0)) + testcheck.check(r > t.CDouble(-0.001) and r < t.CDouble(0.001), "sin(0)~=0", "sin(0)~=0") + + # cos + r = vipersimd.simd_cos(t.CDouble(0.0)) + testcheck.check(r > t.CDouble(0.999) and r < t.CDouble(1.001), "cos(0)~=1", "cos(0)~=1") + + # pow + r = vipersimd.simd_pow(t.CDouble(2.0), t.CDouble(10.0)) + testcheck.check(r == t.CDouble(1024.0), "pow(2,10)==1024", "pow(2,10)==1024") + + +# ============================================================ +# 4. 性能基准测试: SIMD vs 标量 +# ============================================================ + +N_ELEM: t.CDefine = 40000 +N_ITER: t.CDefine = 50000 + +def scalar_add_array(a: t.CPtr, b: t.CPtr, out: t.CPtr, n: t.CSizeT): + i: t.CSizeT = 0 + da: t.CDouble | t.CPtr = a + db: t.CDouble | t.CPtr = b + dout: t.CDouble | t.CPtr = out + while i < n: + dout[i] = da[i] + db[i] + i += 1 + +def scalar_mul_array(a: t.CPtr, b: t.CPtr, out: t.CPtr, n: t.CSizeT): + i: t.CSizeT = 0 + da: t.CDouble | t.CPtr = a + db: t.CDouble | t.CPtr = b + dout: t.CDouble | t.CPtr = out + while i < n: + dout[i] = da[i] * db[i] + i += 1 + +def scalar_sqrt_array(a: t.CPtr, out: t.CPtr, n: t.CSizeT): + i: t.CSizeT = 0 + da: t.CDouble | t.CPtr = a + dout: t.CDouble | t.CPtr = out + while i < n: + dout[i] = vipersimd.simd_sqrt(da[i]) + i += 1 + +def benchmark_simd_vs_scalar(): + testcheck.section("Benchmark: SIMD vs Scalar") + + a: numpy.ndarray[t.CDouble] | t.CPtr = numpy.full(pool, N_ELEM, t.CDouble(1.5)) + b: numpy.ndarray[t.CDouble] | t.CPtr = numpy.full(pool, N_ELEM, t.CDouble(2.5)) + out: numpy.ndarray[t.CDouble] | t.CPtr = numpy.zeros(pool, N_ELEM) + + # --- SIMD add benchmark --- + t0: t.CLong = clock() + iter: t.CInt = 0 + while iter < N_ITER: + vipersimd.simd_add_array(a.data, b.data, out.data, t.CSizeT(N_ELEM)) + iter += 1 + t1: t.CLong = clock() + simd_add_ms: t.CLong = t1 - t0 + + # --- Scalar add benchmark --- + t0 = clock() + iter = 0 + while iter < N_ITER: + scalar_add_array(a.data, b.data, out.data, t.CSizeT(N_ELEM)) + iter += 1 + t1 = clock() + scalar_add_ms: t.CLong = t1 - t0 + + printf(" ADD: SIMD=%ldms Scalar=%ldms", simd_add_ms, scalar_add_ms) + if scalar_add_ms > 0: + printf(" speedup=%.1fx\n", t.CDouble(scalar_add_ms) / t.CDouble(simd_add_ms)) + else: + printf(" speedup=N/A\n") + + # --- SIMD mul benchmark --- + t0 = clock() + iter = 0 + while iter < N_ITER: + vipersimd.simd_mul_array(a.data, b.data, out.data, t.CSizeT(N_ELEM)) + iter += 1 + t1 = clock() + simd_mul_ms: t.CLong = t1 - t0 + + # --- Scalar mul benchmark --- + t0 = clock() + iter = 0 + while iter < N_ITER: + scalar_mul_array(a.data, b.data, out.data, t.CSizeT(N_ELEM)) + iter += 1 + t1 = clock() + scalar_mul_ms: t.CLong = t1 - t0 + + printf(" MUL: SIMD=%ldms Scalar=%ldms", simd_mul_ms, scalar_mul_ms) + if scalar_mul_ms > 0: + printf(" speedup=%.1fx\n", t.CDouble(scalar_mul_ms) / t.CDouble(simd_mul_ms)) + else: + printf(" speedup=N/A\n") + + # --- SIMD sqrt benchmark --- + t0 = clock() + iter = 0 + while iter < N_ITER: + vipersimd.simd_sqrt_array(a.data, out.data, t.CSizeT(N_ELEM)) + iter += 1 + t1 = clock() + simd_sqrt_ms: t.CLong = t1 - t0 + + # --- Scalar sqrt benchmark --- + t0 = clock() + iter = 0 + while iter < N_ITER: + scalar_sqrt_array(a.data, out.data, t.CSizeT(N_ELEM)) + iter += 1 + t1 = clock() + scalar_sqrt_ms: t.CLong = t1 - t0 + + printf(" SQRT: SIMD=%ldms Scalar=%ldms", simd_sqrt_ms, scalar_sqrt_ms) + if scalar_sqrt_ms > 0: + printf(" speedup=%.1fx\n", t.CDouble(scalar_sqrt_ms) / t.CDouble(simd_sqrt_ms)) + else: + printf(" speedup=N/A\n") + + # 验证结果正确性 + testcheck.check(out.data[0] > t.CDouble(0.0), "bench result[0] valid", "bench result[0] valid") + + a.delete() + b.delete() + out.delete() + + +# ============================================================ +# Main +# ============================================================ + +def main() -> t.CInt: + global arena, pool + + arena = calloc(4096 * 1024, 1) # 4MB arena + pool = memhub.MemPool(arena, 4096 * 1024) # bump allocator + + testcheck.begin("ViperSIMD Test Suite") + + test_avx2_add_sub_mul_div() + test_avx2_neg_abs_sqrt() + test_avx2_min_max() + test_avx2_scalar_ops() + test_avx2_hsum_dot() + test_avx2_fma() + test_batch_array_ops() + test_llvmir_scalar() + benchmark_simd_vs_scalar() + + return testcheck.end() diff --git a/SimdTest/project.json b/SimdTest/project.json new file mode 100644 index 0000000..25e3555 --- /dev/null +++ b/SimdTest/project.json @@ -0,0 +1,39 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "SimdTest", + "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": "SimdTest.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 + } +} \ No newline at end of file diff --git a/SlotsBugTest/App/main.vp b/SlotsBugTest/App/main.vp new file mode 100644 index 0000000..09f5a3d --- /dev/null +++ b/SlotsBugTest/App/main.vp @@ -0,0 +1,19 @@ +import t +import ast + + +# ============================================================ +# 回归测试:__slots__ + ast.AST 字段类型 +# 验证 TPC 修复:无法识别的类型注解应报错终止,而非 VoidType alloca 崩溃 +# 对照:使用 ast.expr(无效)会报错;使用 ast.AST(有效)应编译成功 +# ============================================================ +class Result: + __slots__ = ('elem_type_node', 'count_node', 'is_pointer') + + def __init__(self, elem: ast.AST, count: ast.AST | t.CPtr, flag: bool) -> None: + self.elem_type_node: ast.AST = elem + self.count_node: ast.AST | t.CPtr = count + self.is_pointer: bool = flag + +def main() -> int: + return 0 diff --git a/SlotsBugTest/project.json b/SlotsBugTest/project.json new file mode 100644 index 0000000..d629700 --- /dev/null +++ b/SlotsBugTest/project.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "SlotsBugTest", + "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": "SlotsBugTest.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 + } +} diff --git a/SprintfTest/App/main.vp b/SprintfTest/App/main.vp new file mode 100644 index 0000000..e397247 --- /dev/null +++ b/SprintfTest/App/main.vp @@ -0,0 +1,203 @@ +from stdint import * +import t, c +import stdio +import stdlib +import testcheck +import viperlib +import string + + +# ============================================================ +# SprintfTest - viperlib.snprintf %a/%A 运行时验证 +# 预期输出对照 glibc printf("%a", ...) 行为 +# ============================================================ +@t.CExport +def main() -> int: + testcheck.begin("SprintfTest: %a/%A runtime verification") + buf: bytes = stdlib.malloc(256) + + # ---------- 默认精度(核心正确性) ---------- + testcheck.section("default precision") + + v1: t.CDouble = 1.0 + viperlib.snprintf(buf, 64, "%a", v1) + testcheck.info(buf) + testcheck.check(string.strcmp(buf, "0x1p+0") == 0, "%a 1.0 -> 0x1p+0", "FAIL 1.0") + + v2: t.CDouble = 2.0 + viperlib.snprintf(buf, 64, "%a", v2) + testcheck.info(buf) + testcheck.check(string.strcmp(buf, "0x1p+1") == 0, "%a 2.0 -> 0x1p+1", "FAIL 2.0") + + v_half: t.CDouble = 0.5 + viperlib.snprintf(buf, 64, "%a", v_half) + testcheck.info(buf) + testcheck.check(string.strcmp(buf, "0x1p-1") == 0, "%a 0.5 -> 0x1p-1", "FAIL 0.5") + + v3: t.CDouble = 3.0 + viperlib.snprintf(buf, 64, "%a", v3) + testcheck.info(buf) + testcheck.check(string.strcmp(buf, "0x1.8p+1") == 0, "%a 3.0 -> 0x1.8p+1", "FAIL 3.0") + + v_pi: t.CDouble = 3.14 + viperlib.snprintf(buf, 64, "%a", v_pi) + testcheck.info(buf) + testcheck.check(string.strcmp(buf, "0x1.91eb851eb851fp+1") == 0, "%a 3.14 -> 0x1.91eb851eb851fp+1", "FAIL 3.14") + + v0: t.CDouble = 0.0 + viperlib.snprintf(buf, 64, "%a", v0) + testcheck.info(buf) + testcheck.check(string.strcmp(buf, "0x0p+0") == 0, "%a 0.0 -> 0x0p+0", "FAIL 0.0") + + vn1: t.CDouble = -1.0 + viperlib.snprintf(buf, 64, "%a", vn1) + testcheck.info(buf) + testcheck.check(string.strcmp(buf, "-0x1p+0") == 0, "%a -1.0 -> -0x1p+0", "FAIL -1.0") + + # ---------- 大写 %A ---------- + testcheck.section("uppercase %A") + viperlib.snprintf(buf, 64, "%A", v_pi) + testcheck.info(buf) + testcheck.check(string.strcmp(buf, "0X1.91EB851EB851FP+1") == 0, "%A 3.14 -> 0X1...P+1", "FAIL %A") + + # ---------- # flag 强制小数点 ---------- + testcheck.section("# flag") + viperlib.snprintf(buf, 64, "%#a", v1) + testcheck.info(buf) + testcheck.check(string.strcmp(buf, "0x1.p+0") == 0, "%#a 1.0 -> 0x1.p+0", "FAIL %#a") + + # ---------- 显式精度 13(不裁剪) ---------- + testcheck.section("precision 13") + viperlib.snprintf(buf, 64, "%.13a", v1) + testcheck.info(buf) + testcheck.check(string.strcmp(buf, "0x1.0000000000000p+0") == 0, "%.13a 1.0 -> 0x1.0000000000000p+0", "FAIL %.13a") + + # ---------- 宽度/对齐 ---------- + testcheck.section("width/align") + viperlib.snprintf(buf, 64, "%10a", v1) + testcheck.info(buf) + testcheck.check(string.strcmp(buf, " 0x1p+0") == 0, "%10a 1.0 -> ' 0x1p+0'", "FAIL %10a") + + viperlib.snprintf(buf, 64, "%-10a|", v1) + testcheck.info(buf) + testcheck.check(string.strcmp(buf, "0x1p+0 |") == 0, "%-10a 1.0 -> '0x1p+0 |'", "FAIL %-10a") + + # ---------- show_sign ---------- + testcheck.section("show_sign") + viperlib.snprintf(buf, 64, "%+a", v1) + testcheck.info(buf) + testcheck.check(string.strcmp(buf, "+0x1p+0") == 0, "%+a 1.0 -> +0x1p+0", "FAIL %+a") + + # ---------- inf / nan ---------- + testcheck.section("inf/nan") + + # 构造 +inf: bit pattern 0x7FF0000000000000 + inf_bits: t.CUInt64T = 0x7FF0000000000000 + inf_val: t.CDouble = 0.0 + c.Load(c.Addr(inf_val), c.Addr(inf_bits)) + viperlib.snprintf(buf, 64, "%a", inf_val) + testcheck.info(buf) + testcheck.check(string.strcmp(buf, "inf") == 0, "%a +inf -> inf", "FAIL +inf") + + # 构造 -inf: bit pattern 0xFFF0000000000000 + ninf_bits: t.CUInt64T = 0xFFF0000000000000 + ninf_val: t.CDouble = 0.0 + c.Load(c.Addr(ninf_val), c.Addr(ninf_bits)) + viperlib.snprintf(buf, 64, "%a", ninf_val) + testcheck.info(buf) + testcheck.check(string.strcmp(buf, "-inf") == 0, "%a -inf -> -inf", "FAIL -inf") + + # 构造 nan: bit pattern 0x7FF8000000000000 + nan_bits: t.CUInt64T = 0x7FF8000000000000 + nan_val: t.CDouble = 0.0 + c.Load(c.Addr(nan_val), c.Addr(nan_bits)) + viperlib.snprintf(buf, 64, "%a", nan_val) + testcheck.info(buf) + testcheck.check(string.strcmp(buf, "nan") == 0, "%a nan -> nan", "FAIL nan") + + # 大写 INF/NAN + viperlib.snprintf(buf, 64, "%A", inf_val) + testcheck.info(buf) + testcheck.check(string.strcmp(buf, "INF") == 0, "%A +inf -> INF", "FAIL INF") + + # ============================================================ + # viperlib %g/%f/%e 浮点格式化诊断(定位 SimdTest 浮点 CDefine 值错) + # 已知现象: %a 正确, %.17g 输出 3.1397985356295141 (应为 3.1415926535897931) + # 同一 va_list 连续读同一 double, %.17g 错而 %a 对 → 定位是算法还是传参/读取 + # ============================================================ + testcheck.section("viperlib %g bug diagnosis") + + v_pi17: t.CDouble = 3.1415926535897931 + v_e17: t.CDouble = 2.7182818284590455 + + # T1: 同一参数 %.17g vs %a(复现;%a 对则说明值本身正确) + viperlib.snprintf(buf, 128, "T1 %.17g|%a", v_pi17, v_pi17) + testcheck.info(buf) + + # T2: 两个 %.17g 不同值 + viperlib.snprintf(buf, 128, "T2 %.17g|%.17g", v_pi17, v_e17) + testcheck.info(buf) + + # T3: CRT 对照 + stdio.snprintf(buf, 128, "T3 %.17g|%a", v_pi17, v_pi17) + testcheck.info(buf) + + # T4: 不同精度 + viperlib.snprintf(buf, 128, "T4 %.17g|%.10g|%.6g|%g", v_pi17, v_pi17, v_pi17, v_pi17) + testcheck.info(buf) + + # T5: %f / %e + viperlib.snprintf(buf, 128, "T5 %.17f|%.17e", v_pi17, v_pi17) + testcheck.info(buf) + + # T6: 简单精确值(1.0/0.5 二进制精确, 若这些也错则算术层坏) + viperlib.snprintf(buf, 128, "T6 %.17g|%.17g|%.17g", 1.0, 0.5, 123.456) + testcheck.info(buf) + + # T7/T8: double 在变参不同位置(va_list 读取位置相关性) + viperlib.snprintf(buf, 128, "T7 %d|%.17g|%d", 100, v_pi17, 200) + testcheck.info(buf) + viperlib.snprintf(buf, 128, "T8 %d|%d|%.17g", 100, 200, v_pi17) + testcheck.info(buf) + + # T9: 字面量直接传(非常量折叠则看传递路径) + viperlib.snprintf(buf, 128, "T9 %.17g|%a", 3.1415926535897931, 3.1415926535897931) + testcheck.info(buf) + + # T10: 顺序反转, %a 在前 %.17g 在后 + viperlib.snprintf(buf, 128, "T10 %a|%.17g", v_pi17, v_pi17) + testcheck.info(buf) + + # ============================================================ + # 多整数变参复现(DefineTest test_define_string PAGE= 遗留 bug): + # viperlib.snprintf 3+ 个 int 变参时, 第 2 个 %d 读到垃圾 + # (va_arg 游标从寄存器区切到溢出区推进错误, 非本次 CIf 引入) + # 预期: R1-R3 目前 FAIL, 修复后应全部 PASS + # ============================================================ + testcheck.section("multi-int varargs repro") + + # R1: 3 个常量 int(复现 DefineTest "MAX_SIZE=%d PAGE=%d MASK=0x%x" 模式) + viperlib.snprintf(buf, 128, "R1 %d|%d|%d", 1024, 4096, 255) + testcheck.info(buf) + testcheck.check(string.strcmp(buf, "R1 1024|4096|255") == 0, "R1 3-const-int (1024|4096|255)", "R1 FAIL (第2变参被误读)") + + # R2: 3 个运行时变量 int(排除常量折叠差异) + ia: t.CInt = 1024 + ib: t.CInt = 4096 + ic: t.CInt = 255 + viperlib.snprintf(buf, 128, "R2 %d|%d|%d", ia, ib, ic) + testcheck.info(buf) + testcheck.check(string.strcmp(buf, "R2 1024|4096|255") == 0, "R2 3-var-int (1024|4096|255)", "R2 FAIL (第2变参被误读)") + + # R3: 4 个变参(游标推进进一步暴露) + viperlib.snprintf(buf, 128, "R3 %d|%d|%d|%d", 1, 2, 3, 4) + testcheck.info(buf) + testcheck.check(string.strcmp(buf, "R3 1|2|3|4") == 0, "R3 4-int (1|2|3|4)", "R3 FAIL (变参游标推进错误)") + + # R4: 第 2 个变参为 0(值 0 若被截断读也会暴露) + viperlib.snprintf(buf, 128, "R4 %d|%d|%d", 100, 0, 200) + testcheck.info(buf) + testcheck.check(string.strcmp(buf, "R4 100|0|200") == 0, "R4 middle-zero (100|0|200)", "R4 FAIL (第2变参被误读)") + + stdlib.free(buf) + return 0 diff --git a/SprintfTest/project.json b/SprintfTest/project.json new file mode 100644 index 0000000..c7a4137 --- /dev/null +++ b/SprintfTest/project.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "SprintfTest", + "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": "SprintfTest.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 + } +} diff --git a/StringIterTest/App/inline_test.vp b/StringIterTest/App/inline_test.vp new file mode 100644 index 0000000..719dd80 --- /dev/null +++ b/StringIterTest/App/inline_test.vp @@ -0,0 +1,50 @@ +import t +import stdio +import c + +# Test: class with inline list[struct, N] field + +class Inner: + code: t.CUnsignedInt + bits: t.CInt + +class Container: + items: t.CArray[Inner, 10] + count: t.CInt + + def __init__(self): + self.count = 0 + + def fill(self): + for i in range(10): + self.items[i].code = t.CUnsignedInt(i * 100) + self.items[i].bits = i + self.count += 1 + + def check(self): + ok: t.CInt = 1 + for i in range(10): + if self.items[i].code != t.CUnsignedInt(i * 100): + stdio.printf("FAIL: items[%d].code=%u expect %d\n", i, self.items[i].code, i * 100) + ok = 0 + if self.items[i].bits != i: + stdio.printf("FAIL: items[%d].bits=%d expect %d\n", i, self.items[i].bits, i) + ok = 0 + if ok: + stdio.printf("PASS: inline list[struct, N] in Container\n") + else: + stdio.printf("FAIL: inline list[struct, N] in Container\n") + +def main() -> t.CInt: + stdio.printf("=== InlineArrayTest ===\n") + c1 = Container() + c1.fill() + c1.check() + + # Also test: local variable of Container type + c2 = Container() + c2.fill() + c2.check() + + stdio.printf("=== InlineArrayTest Complete ===\n") + return 0 diff --git a/StringIterTest/App/main.vp b/StringIterTest/App/main.vp new file mode 100644 index 0000000..de476e8 --- /dev/null +++ b/StringIterTest/App/main.vp @@ -0,0 +1,179 @@ +import t +import stdio +import string +import c +import testcheck + +# ============================================================ +# Test 1: 字符串指针迭代 - 逐字符直到\0 +# ============================================================ +def test_string_ptr_iter(): + testcheck.section("Test 1: string pointer iteration") + s: t.CChar | t.CPtr = "Hello" + p: t.CChar | t.CPtr = s + count: t.CInt = 0 + while c.Deref(p) != 0: + count += 1 + p += 1 + testcheck.check(count == 5, "ptr iter (count=5)", "ptr iter (count expect 5)") + +# ============================================================ +# Test 2: 字符串指针求和ASCII值 +# ============================================================ +def test_string_ascii_sum(): + testcheck.section("Test 2: string ASCII sum") + s: t.CChar | t.CPtr = "ABC" + p: t.CChar | t.CPtr = s + total: t.CInt = 0 + while c.Deref(p) != 0: + total += t.CInt(c.Deref(p)) + p += 1 + # A=65, B=66, C=67 => 198 + testcheck.check(total == 198, "ASCII sum (total=198)", "ASCII sum (total expect 198)") + +# ============================================================ +# Test 3: 手动strcpy - 指针复制 +# ============================================================ +def test_manual_strcpy(): + testcheck.section("Test 3: manual strcpy via pointers") + src: t.CChar | t.CPtr = "Test" + dst: t.CArray[t.CChar, 32] = [0] + sp: t.CChar | t.CPtr = src + dp: t.CChar | t.CPtr = c.Addr(dst) + while c.Deref(sp) != 0: + c.Set(c.Deref(dp), c.Deref(sp)) + sp += 1 + dp += 1 + c.Set(c.Deref(dp), 0) + testcheck.check(dst[0] == 84 and dst[1] == 101 and dst[2] == 115 and dst[3] == 116, "manual strcpy (T=84 e=101 s=115 t=116)", "manual strcpy (expect T=84 e=101 s=115 t=116)") + +# ============================================================ +# Test 4: 指针比较和偏移 +# ============================================================ +def test_ptr_offset_compare(): + testcheck.section("Test 4: pointer offset and compare") + arr: t.CArray[t.CInt, 5] = [0] + for i in range(5): + arr[i] = i * 10 + p: t.CInt | t.CPtr = c.Addr(arr) + start: t.CInt | t.CPtr = p + total: t.CInt = 0 + while p != start + 5: + total += c.Deref(p) + p += 1 + testcheck.check(total == 100, "ptr offset (total=100)", "ptr offset (total expect 100)") + +# ============================================================ +# Test 5: 字符串长度手动计算 +# ============================================================ +def test_manual_strlen(): + testcheck.section("Test 5: manual strlen") + s: t.CChar | t.CPtr = "Hello World!" + p: t.CChar | t.CPtr = s + length: t.CSizeT = 0 + while c.Deref(p) != 0: + length += 1 + p += 1 + testcheck.check(length == 12, "manual strlen (len=12)", "manual strlen (len expect 12)") + +# ============================================================ +# Test 6: 指针反向遍历字符串 +# ============================================================ +def test_reverse_string_ptr(): + testcheck.section("Test 6: reverse string via pointer") + src: t.CChar | t.CPtr = "abcd" + dst: t.CArray[t.CChar, 32] = [0] + # Find end of src + p: t.CChar | t.CPtr = src + length: t.CInt = 0 + while c.Deref(p) != 0: + length += 1 + p += 1 + # Copy in reverse + dp: t.CChar | t.CPtr = c.Addr(dst) + p = src + length - 1 + while p >= src: + c.Set(c.Deref(dp), c.Deref(p)) + dp += 1 + p -= 1 + c.Set(c.Deref(dp), 0) + # "abcd" reversed = "dcba" = 100,99,98,97 + testcheck.check(dst[0] == 100 and dst[1] == 99 and dst[2] == 98 and dst[3] == 97, "reverse string (d=100 c=99 b=98 a=97)", "reverse string (expect d=100 c=99 b=98 a=97)") + +# ============================================================ +# Test 7: 多级指针 - 指向指针的指针 +# ============================================================ +def test_double_pointer(): + testcheck.section("Test 7: double pointer") + x: t.CInt = 42 + px: t.CInt | t.CPtr = c.Addr(x) + ppx: t.CInt | t.CPtr | t.CPtr = c.Addr(px) + # Read through double pointer + val: t.CInt = c.Deref(c.Deref(ppx)) + testcheck.check(val == 42, "double pointer (val=42)", "double pointer (val expect 42)") + +# ============================================================ +# Test 8: 指针算术 - 数组元素访问 +# ============================================================ +def test_ptr_arithmetic(): + testcheck.section("Test 8: pointer arithmetic") + arr: t.CArray[t.CInt, 8] = [0] + for i in range(8): + arr[i] = (i + 1) * (i + 1) + p: t.CInt | t.CPtr = c.Addr(arr) + # Access arr[3] via pointer: p + 3 + val: t.CInt = c.Deref(p + 3) + # arr[3] = 4*4 = 16 + testcheck.check(val == 16, "ptr arithmetic (arr[3]=16)", "ptr arithmetic (arr[3] expect 16)") + +# ============================================================ +# Test 9: 字符串比较 - 逐字符指针 +# ============================================================ +def test_manual_strcmp(): + testcheck.section("Test 9: manual strcmp via pointers") + s1: t.CChar | t.CPtr = "Hello" + s2: t.CChar | t.CPtr = "Hello" + p1: t.CChar | t.CPtr = s1 + p2: t.CChar | t.CPtr = s2 + equal: t.CInt = 1 + while c.Deref(p1) != 0 and c.Deref(p2) != 0: + if c.Deref(p1) != c.Deref(p2): + equal = 0 + break + p1 += 1 + p2 += 1 + if c.Deref(p1) != c.Deref(p2): + equal = 0 + testcheck.check(equal == 1, "manual strcmp (equal=1)", "manual strcmp (equal expect 1)") + +# ============================================================ +# Test 10: 结构体指针访问 +# ============================================================ +class Vec2: + x: t.CInt + y: t.CInt + +def test_struct_ptr_access(): + testcheck.section("Test 10: struct pointer access") + v: Vec2 = Vec2() + v.x = 10 + v.y = 20 + p: Vec2 | t.CPtr = c.Addr(v) + # Modify through pointer + c.Deref(p).x = 100 + c.Deref(p).y = 200 + testcheck.check(v.x == 100 and v.y == 200, "struct ptr (x=100 y=200)", "struct ptr (x y expect 100 200)") + +def main() -> t.CInt: + testcheck.begin("StringIterTest: String/Pointer Iteration Tests") + test_string_ptr_iter() + test_string_ascii_sum() + test_manual_strcpy() + test_ptr_offset_compare() + test_manual_strlen() + test_reverse_string_ptr() + test_double_pointer() + test_ptr_arithmetic() + test_manual_strcmp() + test_struct_ptr_access() + return testcheck.end() diff --git a/StringIterTest/project.json b/StringIterTest/project.json new file mode 100644 index 0000000..a80292f --- /dev/null +++ b/StringIterTest/project.json @@ -0,0 +1,40 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "StringIterTest", + "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": "StringIterTest.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 + } +} \ No newline at end of file diff --git a/StringTest/App/main.vp b/StringTest/App/main.vp new file mode 100644 index 0000000..b4b0fb2 --- /dev/null +++ b/StringTest/App/main.vp @@ -0,0 +1,85 @@ +import t +import stdio +import string +import testcheck +import w32.win32memory + +def test_strlen(): + testcheck.section("Test 1: strlen") + s: t.CChar | t.CPtr = "Hello, World!" + length: t.CUInt64T = string.strlen(s) + testcheck.check(length == 13, "strlen (len=13)", "strlen (expect 13)") + +def test_strcpy(): + testcheck.section("Test 2: strcpy") + 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) + string.strcpy(buf, "test string") + cmp_result: t.CInt = string.strcmp(buf, "test string") + testcheck.check(cmp_result == 0, "strcpy (result=test string)", "strcpy (cmp mismatch)") + +def test_strcat(): + testcheck.section("Test 3: strcat (via memcpy)") + 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) + # 手动拼接: 先拷贝 "Hello",再拷贝 " World" + hello: t.CChar | t.CPtr = "Hello" + world: t.CChar | t.CPtr = " World" + string.memcpy(buf, hello, 5) + string.memcpy(t.CPtr(t.CUInt64T(buf) + 5), world, 6) + cmp_result: t.CInt = string.strcmp(buf, "Hello World") + testcheck.check(cmp_result == 0, "strcat via memcpy", "strcat via memcpy (cmp mismatch)") + +def test_strcmp(): + testcheck.section("Test 4: strcmp") + r1: t.CInt = string.strcmp("abc", "abc") + r2: t.CInt = string.strcmp("abc", "abd") + r3: t.CInt = string.strcmp("abd", "abc") + testcheck.check(r1 == 0 and r2 < 0 and r3 > 0, "strcmp (eq=0 lt<0 gt>0)", "strcmp (expect eq=0 lt<0 gt>0)") + +def test_strncpy(): + testcheck.section("Test 5: strncpy") + 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) + string.strncpy(buf, "ABCDEFGHIJ", 5) + cmp_result: t.CInt = string.strcmp(buf, "ABCDE") + testcheck.check(cmp_result == 0, "strncpy (result=ABCDE)", "strncpy (cmp mismatch)") + +def test_char_access(): + testcheck.section("Test 6: char access") + s: t.CChar | t.CPtr = "ABCDE" + val: t.CUInt8T = s[2] # 'C' = 67 + testcheck.check(val == 67, "char access (s[2]=67='C')", "char access (s[2] expect 67)") + +def test_snprintf(): + testcheck.section("Test 7: snprintf") + buf: t.CChar | t.CPtr = w32.win32memory.VirtualAlloc(None, 128, 12288, 4) + if t.CUInt64T(buf) == 0: + stdio.printf("SKIP: VirtualAlloc returned NULL\n") + return + string.memset(buf, 0, 128) + stdio.snprintf(buf, 128, "value=%d hex=0x%x str=%s", 42, 255, "test") + cmp_result: t.CInt = string.strcmp(buf, "value=42 hex=0xff str=test") + testcheck.check(cmp_result == 0, "snprintf (result=value=42 hex=0xff str=test)", "snprintf (result mismatch)") + +import w32.win32memory + +def main() -> t.CInt: + testcheck.begin("StringTest: 字符串操作基准测试") + test_strlen() + test_strcpy() + test_strcat() + test_strcmp() + test_strncpy() + test_char_access() + test_snprintf() + return testcheck.end() diff --git a/StringTest/project.json b/StringTest/project.json new file mode 100644 index 0000000..c067a1f --- /dev/null +++ b/StringTest/project.json @@ -0,0 +1,40 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "StringTest", + "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": "StringTest.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 + } +} \ No newline at end of file diff --git a/StructTest/App/main.vp b/StructTest/App/main.vp new file mode 100644 index 0000000..d88057a --- /dev/null +++ b/StructTest/App/main.vp @@ -0,0 +1,85 @@ +import t +import stdio +import string +import testcheck + +# 定义结构体 +class Point(): + x: t.CInt + y: t.CInt + +class Rect(): + origin: Point + size: Point + +class Node(): + value: t.CInt + next: t.CPtr # Node* 类型 + +def test_struct_basic(): + testcheck.section("Test 1: struct basic") + p: Point = Point() + p.x = 10 + p.y = 20 + testcheck.check(p.x == 10 and p.y == 20, "struct basic (x=10 y=20)", "struct basic (x y expect 10 20)") + +def test_struct_nested(): + testcheck.section("Test 2: struct nested") + r: Rect = Rect() + r.origin.x = 1 + r.origin.y = 2 + r.size.x = 100 + r.size.y = 200 + testcheck.check(r.origin.x == 1 and r.origin.y == 2 and r.size.x == 100 and r.size.y == 200, "struct nested (origin=1,2 size=100,200)", "struct nested (mismatch)") + +def test_struct_pointer(): + testcheck.section("Test 3: struct pointer") + p: Point = Point() + p.x = 42 + p.y = 84 + # 取结构体指针 + pp: Point | t.CPtr = t.CPtr(t.CUInt64T(p)) + # 通过指针修改 + pp.x = 100 + pp.y = 200 + # 检查原始结构体是否被修改 + testcheck.check(p.x == 100 and p.y == 200, "struct pointer (x=100 y=200)", "struct pointer (x y expect 100 200)") + +def test_struct_param(): + testcheck.section("Test 4: struct as parameter") + p: Point = Point() + p.x = 5 + p.y = 15 + sum_val: t.CInt = point_sum(p) + testcheck.check(sum_val == 20, "struct param (sum=20)", "struct param (sum expect 20)") + +def point_sum(p: Point) -> t.CInt: + return p.x + p.y + +def test_struct_array(): + testcheck.section("Test 5: struct array") + # 分配结构体数组 + buf: t.CUInt8T | t.CPtr = w32.win32memory.VirtualAlloc(None, 256, 12288, 4) + if t.CUInt64T(buf) == 0: + stdio.printf("SKIP: VirtualAlloc returned NULL\n") + return + string.memset(buf, 0, 256) + # 将缓冲区转为 Point 数组 + pts: Point | t.CPtr = (Point | t.CPtr)(buf) + pts[0].x = 1 + pts[0].y = 2 + pts[1].x = 3 + pts[1].y = 4 + total: t.CInt = pts[0].x + pts[0].y + pts[1].x + pts[1].y + testcheck.check(total == 10, "struct array (total=10)", "struct array (total expect 10)") + +import w32.win32memory + +def main() -> t.CInt: + testcheck.begin("StructTest: 结构体操作基准测试") + test_struct_basic() + test_struct_nested() + test_struct_pointer() + test_struct_param() + test_struct_array() + return testcheck.end() diff --git a/StructTest/project.json b/StructTest/project.json new file mode 100644 index 0000000..a86fe82 --- /dev/null +++ b/StructTest/project.json @@ -0,0 +1,40 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "StructTest", + "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": "StructTest.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 + } +} \ No newline at end of file diff --git a/SuperTest/App/main.vp b/SuperTest/App/main.vp new file mode 100644 index 0000000..8c746e9 --- /dev/null +++ b/SuperTest/App/main.vp @@ -0,0 +1,120 @@ +from stdint import * +import t, c +from t import CPtr, CInt, CExport +import testcheck + + +# ============================================================ +# super() 语义专项测试(由 TransPyV.exe 编译) +# +# 覆盖场景: +# 1. super().__init__(args) — 子类构造调父类构造(字段由父类设置) +# 2. super().method() 静态绑定父类实现(不触发子类 override / 虚分派) +# 3. super() 调未覆盖的父类方法(父类字段区前缀对齐,this 无需调整) +# 4. 三层继承链 super().__init__(Leaf → Mid → Grand 逐层传递, +# 每个中间类的 super() 沿各自 CurClassName 的 MRO 跳自身找父类) +# 5. super().method 沿 MRO 找实际定义类(Mid 未定义 Base → 找到 Grand.Base) +# ============================================================ + + +# ========== 单继承:super().__init__ + super().method ========== + +@t.CVTable +class Animal: + Tag: CInt + + def __init__(self, tag: CInt): + self.Tag = tag + + def Speak(self) -> CInt: + return 0 + + def Greet(self) -> CInt: + return self.Tag + 1000 + + +@t.CVTable +class Dog(Animal): + Breed: CInt + + def __init__(self, tag: CInt, breed: CInt): + super().__init__(tag) # 调 Animal.__init__ 设置 Tag + self.Breed = breed + + def Speak(self) -> CInt: + return 1 + + def ParentSpeak(self) -> CInt: + return super().Speak() # 静态绑定 Animal.Speak → 0(不走虚分派) + + def FullGreet(self) -> CInt: + # super() 调父类 Greet(Dog 未覆盖),再加自身字段 + return super().Greet() + self.Breed + + +# ========== 三层继承链:Grand → Mid → Leaf ========== + +@t.CVTable +class Grand: + G: CInt + + def __init__(self, v: CInt): + self.G = v + + def Base(self) -> CInt: + return self.G + + +@t.CVTable +class Mid(Grand): + M: CInt + + def __init__(self, v: CInt): + super().__init__(v + 1) # 调 Grand.__init__ + self.M = v + + def MidOnly(self) -> CInt: + return self.M + + +@t.CVTable +class Leaf(Mid): + def __init__(self, v: CInt): + super().__init__(v + 2) # 调 Mid.__init__(Mid 内部再 super 到 Grand) + + def GetBase(self) -> CInt: + return super().Base() # Mid 未定义 Base → 沿 MRO 找 Grand.Base + + def CallMidOnly(self) -> CInt: + return super().MidOnly() # 调 Mid.MidOnly + + +def main() -> CInt | CExport: + testcheck.begin("SuperTest: super() 语义测试") + + # --- 1. super().__init__ 设置父类字段 --- + d: Dog | CPtr = Dog(42, 7) + testcheck.check(d.Tag == 42, "super().__init__ 设置父类字段 OK", + "super().__init__ FAILED") + testcheck.check(d.Breed == 7, "子类字段 OK", "子类字段 FAILED") + + # --- 2. super().method 静态绑定(不虚分派到子类 override) --- + testcheck.check(d.ParentSpeak() == 0, "super().Speak() 静态绑定父类 OK", + "super().Speak() FAILED") + testcheck.check(d.Speak() == 1, "子类 Speak() override OK", "Speak() FAILED") + + # --- 3. super() 调未覆盖的父类方法(42+1000+7 = 1049) --- + testcheck.check(d.FullGreet() == 1049, "super() 调未覆盖父类方法 OK", + "FullGreet() FAILED") + + # --- 4. 三层继承链 super().__init__(Leaf(10) → Mid(12) → Grand(13)) --- + lf: Leaf | CPtr = Leaf(10) + testcheck.check(lf.G == 13, "三层 super().__init__ 链 G OK", "三层 G FAILED") + testcheck.check(lf.M == 12, "中间类 M OK", "中间类 M FAILED") + + # --- 5. super().method 沿 MRO 找实际定义类 --- + testcheck.check(lf.GetBase() == 13, "super().Base() 沿 MRO OK", "GetBase() FAILED") + testcheck.check(lf.CallMidOnly() == 12, "super().MidOnly() OK", "CallMidOnly() FAILED") + + testcheck.ok("super() 全部测试完成") + return testcheck.end() diff --git a/SuperTest/project.json b/SuperTest/project.json new file mode 100644 index 0000000..6c72a50 --- /dev/null +++ b/SuperTest/project.json @@ -0,0 +1,40 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "SuperTest", + "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": "SuperTest.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 + } +} \ No newline at end of file diff --git a/SysLibTest/App/main.vp b/SysLibTest/App/main.vp new file mode 100644 index 0000000..9b4c375 --- /dev/null +++ b/SysLibTest/App/main.vp @@ -0,0 +1,38 @@ +from stdint import * +import w32.win32console +import t, c +from t import CInt, CExport +import memhub +import stdlib +import sys +import os +import os._win32 +import os._posix +import os.path +import shutil +import subprocess +import syslibtest_impl + + +# MBuddy arena 大小:1MB +ARENA_SIZE: t.CDefine = 1048576 + + +def main() -> CInt | CExport: + w32.win32console.SetConsoleCP(65001) + w32.win32console.SetConsoleOutputCP(65001) + + # 初始化全局 MBuddy 内存分配器 + arena: bytes = stdlib.malloc(ARENA_SIZE) + mbuddy_obj: memhub.MemBuddy | t.CPtr = memhub.MemBuddy(arena, ARENA_SIZE) + + # 将 MBuddy 对象赋值给所有需要内存分配的模块 + sys._mbuddy = mbuddy_obj + os._mbuddy = mbuddy_obj + os._win32._mbuddy = mbuddy_obj + os._posix._mbuddy = mbuddy_obj + os.path._mbuddy = mbuddy_obj + shutil._mbuddy = mbuddy_obj + subprocess._mbuddy = mbuddy_obj + + return syslibtest_impl.run() diff --git a/SysLibTest/App/os_backend.vp b/SysLibTest/App/os_backend.vp new file mode 100644 index 0000000..cf9a5f1 --- /dev/null +++ b/SysLibTest/App/os_backend.vp @@ -0,0 +1,39 @@ +import t, c +from stdint import * +import platmacro +import os._win32 +import os._posix + + +# ============================================================================= +# Workaround: TransPyC 无法正确解析 os.xxx() 包级函数调用 +# (os.path.xxx() 子模块调用正常,但 os.xxx() 包级调用解析为本地模块) +# 此文件单独导入 os._win32 / os._posix 子模块,避免污染调用方的 os.rmdir() 等解析。 +# ============================================================================= + +def os_exists(path: str) -> bool: + """检查文件/目录是否存在(跨平台)""" + if platmacro.IS_WINDOWS: + return os._win32.exists(path) + return os._posix.exists(path) + + +def os_remove(path: str) -> int: + """删除文件(跨平台)。成功返回 0,失败返回 -1。""" + if platmacro.IS_WINDOWS: + return os._win32.remove(path) + return os._posix.remove(path) + + +def os_isdir(path: str) -> bool: + """检查路径是否为目录(跨平台)""" + if platmacro.IS_WINDOWS: + return os._win32.isdir(path) + return os._posix.isdir(path) + + +def os_getsize(path: str) -> t.CInt64T: + """返回文件大小(字节,跨平台)。失败返回 -1。""" + if platmacro.IS_WINDOWS: + return os._win32.getsize(path) + return os._posix.getsize(path) diff --git a/SysLibTest/App/syslibtest_impl.vp b/SysLibTest/App/syslibtest_impl.vp new file mode 100644 index 0000000..3318afa --- /dev/null +++ b/SysLibTest/App/syslibtest_impl.vp @@ -0,0 +1,296 @@ +import t, c +from stdint import * +from t import CInt, CPtr, CUInt8T, CSizeT +import testcheck +import viperlib +import stdlib +import memhub +import platmacro +import os +import os.path +import os_backend +import shutil +import sys +import subprocess +import string +import w32.fileio +import w32.win32base +import w32.win32process + + +# 测试用临时文件/目录名前缀 +TEST_DIR: t.CDefine = "__sylibtest_dir__" +TEST_FILE: t.CDefine = "__sylibtest_file.txt" +TEST_COPY: t.CDefine = "__sylibtest_copy.txt" +TEST_TREE: t.CDefine = "__sylibtest_tree__" +TEST_MOVE: t.CDefine = "__sylibtest_moved.txt" + + +# ============================================================================= +# Workaround: TransPyC 无法正确解析 os.xxx() 包级函数调用 +# (os.path.xxx() 子模块调用正常,但 os.xxx() 包级调用解析为本地模块) +# 通过 os_backend 模块(单独导入 os._win32 / os._posix)绕过此问题 +# ============================================================================= + +def _cleanup(): + """清理可能残留的测试文件/目录""" + if os_backend.os_exists(TEST_DIR): + os.rmdir(TEST_DIR) + if os_backend.os_exists(TEST_FILE): + os_backend.os_remove(TEST_FILE) + if os_backend.os_exists(TEST_COPY): + os_backend.os_remove(TEST_COPY) + if os_backend.os_exists(TEST_MOVE): + os_backend.os_remove(TEST_MOVE) + if os_backend.os_exists(TEST_TREE): + shutil.rmtree(TEST_TREE) + + +def run() -> CInt: + buf: bytes = stdlib.malloc(512) + + testcheck.begin("SysLibTest: 系统兼容层库测试") + + # 清理残留 + _cleanup() + + # ============================================================================= + # 全局 MBuddy 初始化验证(在 main 中已初始化) + # ============================================================================= + testcheck.section("全局 MBuddy 初始化验证") + + testcheck.check(os._mbuddy != None, "os._mbuddy initialized OK", "os._mbuddy NOT initialized") + testcheck.check(sys._mbuddy != None, "sys._mbuddy initialized OK", "sys._mbuddy NOT initialized") + testcheck.check(shutil._mbuddy != None, "shutil._mbuddy initialized OK", "shutil._mbuddy NOT initialized") + testcheck.check(subprocess._mbuddy != None, "subprocess._mbuddy initialized OK", "subprocess._mbuddy NOT initialized") + + # 所有模块应共享同一个 MBuddy 对象 + testcheck.check(os._mbuddy == sys._mbuddy, "os==sys same MBuddy OK", "os!=sys different MBuddy") + testcheck.check(shutil._mbuddy == os._mbuddy, "shutil==os same MBuddy OK", "shutil!=os different MBuddy") + + # ============================================================================= + # MBuddy alloc/free/calloc/realloc(通过 os._mbuddy 测试) + # ============================================================================= + testcheck.section("MBuddy alloc/free") + + p1: bytes = os._mbuddy.alloc(64) + p2: bytes = os._mbuddy.alloc(128) + testcheck.check(p1 != None and p2 != None, "alloc OK", "alloc FAILED") + + p1_c: CUInt8T | CPtr = CPtr(p1) + p1_c[0] = CUInt8T(0xAB) + p1_c[1] = CUInt8T(0xCD) + testcheck.check(p1_c[0] == CUInt8T(0xAB) and p1_c[1] == CUInt8T(0xCD), + "alloc write/read OK", "alloc write/read FAILED") + + os._mbuddy.free(p1) + os._mbuddy.free(p2) + testcheck.ok("free OK") + + # calloc 清零测试 + testcheck.section("MBuddy calloc/realloc") + + cp: bytes = os._mbuddy.calloc(4, 16) + if cp != None: + cp_c: CUInt8T | CPtr = CPtr(cp) + all_zero: CInt = 1 + i: CInt + for i in range(64): + if cp_c[i] != 0: + all_zero = 0 + break + testcheck.check(all_zero == 1, "calloc zeroed OK", "calloc NOT zeroed") + os._mbuddy.free(cp) + else: + testcheck.fail("calloc FAILED") + + # realloc 数据保留测试 + rp: bytes = os._mbuddy.alloc(32) + rp_c: CUInt8T | CPtr = CPtr(rp) + for i in range(32): + rp_c[i] = CUInt8T(i + 1) + rp2: bytes = os._mbuddy.realloc(rp, 128) + if rp2 != None: + rp2_c: CUInt8T | CPtr = CPtr(rp2) + ok: CInt = 1 + for i in range(32): + if rp2_c[i] != CUInt8T(i + 1): + ok = 0 + break + testcheck.check(ok == 1, "realloc data preserved OK", "realloc data LOST") + os._mbuddy.free(rp2) + else: + testcheck.fail("realloc FAILED") + + # ============================================================================= + # os.path 路径操作 + # ============================================================================= + testcheck.section("os.path 路径操作") + + # sep + sep_char: t.CChar = os.path.sep() + viperlib.snprintf(buf, 512, "sep = %c", sep_char) + testcheck.info(buf) + + # join + joined: str = os.path.join("parent", "child") + testcheck.check(joined != None, "join(parent, child) OK", "join FAILED") + testcheck.info(joined) + + # basename + base: str = os.path.basename("/usr/local/bin/test") + testcheck.check(base != None, "basename OK", "basename FAILED") + testcheck.info(base) + + # dirname + dirn: str = os.path.dirname("/usr/local/bin/test") + testcheck.check(dirn != None, "dirname OK", "dirname FAILED") + testcheck.info(dirn) + + # isabs + testcheck.check(os.path.isabs("/usr/local"), "isabs(/usr/local) OK", "isabs FAILED") + testcheck.check(not os.path.isabs("relative/path"), "isabs(relative)=False OK", "isabs(relative) should be False") + + # ============================================================================= + # os 文件/目录操作 + # ============================================================================= + testcheck.section("os 文件/目录操作") + + # getcwd + cwd: str = os.getcwd() + testcheck.check(cwd != None, "getcwd OK", "getcwd FAILED") + testcheck.info(cwd) + + # exists + testcheck.check(os_backend.os_exists("."), "exists(.) OK", "exists(.) FAILED") + testcheck.check(not os_backend.os_exists("__totally_nonexistent__"), "exists(nonexistent)=False OK", "exists(nonexistent) should be False") + + # isdir / isfile + testcheck.check(os_backend.os_isdir("."), "isdir(.) OK", "isdir(.) FAILED") + + # mkdir + rmdir + testcheck.check(os.mkdir(TEST_DIR) == 0, "mkdir OK", "mkdir FAILED") + testcheck.check(os_backend.os_exists(TEST_DIR), "mkdir: exists OK", "mkdir: not exists") + testcheck.check(os_backend.os_isdir(TEST_DIR), "mkdir: isdir OK", "mkdir: not isdir") + testcheck.check(os.rmdir(TEST_DIR) == 0, "rmdir OK", "rmdir FAILED") + testcheck.check(not os_backend.os_exists(TEST_DIR), "rmdir: gone OK", "rmdir: still exists") + + # rename + testcheck.check(os.mkdir(TEST_DIR) == 0, "mkdir for rename OK", "mkdir for rename FAILED") + testcheck.check(os.rename(TEST_DIR, TEST_TREE) == 0, "rename OK", "rename FAILED") + testcheck.check(os_backend.os_exists(TEST_TREE) and not os_backend.os_exists(TEST_DIR), "rename: swapped OK", "rename: swap FAILED") + testcheck.check(os.rmdir(TEST_TREE) == 0, "rmdir renamed OK", "rmdir renamed FAILED") + + # ============================================================================= + # shutil 高级文件操作 + # ============================================================================= + testcheck.section("shutil 高级文件操作") + + # 创建测试文件 + f: w32.fileio.File | CPtr = w32.fileio.File(TEST_FILE, w32.fileio.MODE.W) + testcheck.check(not f.closed, "create test file OK", "create test file FAILED") + f.write_str("hello shutil") + f.close() + testcheck.check(os_backend.os_exists(TEST_FILE), "test file exists OK", "test file not exists") + + # copyfile + testcheck.check(shutil.copyfile(TEST_FILE, TEST_COPY) == 0, "copyfile OK", "copyfile FAILED") + testcheck.check(os_backend.os_exists(TEST_COPY), "copyfile: dst exists OK", "copyfile: dst not exists") + + # 验证拷贝内容一致(检查文件大小) + src_size: t.CInt64T = os_backend.os_getsize(TEST_FILE) + dst_size: t.CInt64T = os_backend.os_getsize(TEST_COPY) + viperlib.snprintf(buf, 512, "src_size=%lld dst_size=%lld", src_size, dst_size) + testcheck.info(buf) + testcheck.check(src_size == dst_size, "copyfile: same size OK", "copyfile: size mismatch") + + # move + testcheck.check(shutil.move(TEST_COPY, TEST_MOVE) == 0, "move OK", "move FAILED") + testcheck.check(os_backend.os_exists(TEST_MOVE), "move: dst exists OK", "move: dst not exists") + os_backend.os_remove(TEST_MOVE) + + # rmtree(递归删除目录树) + testcheck.check(os.mkdir(TEST_TREE) == 0, "mkdir tree OK", "mkdir tree FAILED") + # 在树中创建子目录 + subdir: str = os.path.join(TEST_TREE, "sub") + testcheck.check(os.mkdir(subdir) == 0, "mkdir subdir OK", "mkdir subdir FAILED") + # 在子目录中创建文件 + subfile: str = os.path.join(subdir, "leaf.txt") + sf: w32.fileio.File | CPtr = w32.fileio.File(subfile, w32.fileio.MODE.W) + sf.write_str("leaf") + sf.close() + testcheck.check(os_backend.os_exists(subfile), "create subfile OK", "create subfile FAILED") + + # rmtree + testcheck.check(shutil.rmtree(TEST_TREE) == 0, "rmtree OK", "rmtree FAILED") + testcheck.check(not os_backend.os_exists(TEST_TREE), "rmtree: gone OK", "rmtree: still exists") + + # 清理剩余文件 + if os_backend.os_exists(TEST_FILE): + os_backend.os_remove(TEST_FILE) + if os_backend.os_exists(TEST_COPY): + os_backend.os_remove(TEST_COPY) + + # ============================================================================= + # sys 系统信息 + # ============================================================================= + testcheck.section("sys 系统信息") + + # platform + plat: str = sys.platform() + testcheck.check(plat != None, "platform() OK", "platform() FAILED") + testcheck.info(plat) + + # getpid + pid: CInt = sys.get_pid() + viperlib.snprintf(buf, 512, "pid = %d", pid) + testcheck.info(buf) + testcheck.check(pid > 0, "getpid > 0 OK", "getpid FAILED") + + # maxsize + viperlib.snprintf(buf, 512, "maxsize = %lld", sys.maxsize) + testcheck.info(buf) + testcheck.check(sys.maxsize > 0, "maxsize > 0 OK", "maxsize FAILED") + + # argv + argc: CInt = sys.argc() + viperlib.snprintf(buf, 512, "argc = %d", argc) + testcheck.info(buf) + testcheck.check(argc > 0, "argc > 0 OK", "argc FAILED") + + argv0: str = sys.argv(0) + testcheck.check(argv0 != None, "argv(0) OK", "argv(0) FAILED") + testcheck.info(argv0) + + # 越界访问 + testcheck.check(sys.argv(9999) == None, "argv(out-of-range)=None OK", "argv(out-of-range) should be None") + + # ============================================================================= + # subprocess 子进程 + # ============================================================================= + testcheck.section("subprocess 子进程") + + # Windows: cmd /c echo hello + result: subprocess.CompletedProcess | CPtr = subprocess.run("cmd /c echo hello", True, True) + testcheck.check(result != None, "run OK", "run FAILED") + if result != None: + viperlib.snprintf(buf, 512, "returncode = %d", result.returncode) + testcheck.info(buf) + testcheck.check(result.returncode == 0, "returncode == 0 OK", "returncode != 0") + if result.stdout != None: + testcheck.info(result.stdout) + # 验证输出包含 "hello" + testcheck.check(string.strstr(result.stdout, "hello") != None, + "stdout contains 'hello' OK", "stdout missing 'hello'") + else: + testcheck.fail("stdout is None") + else: + testcheck.fail("run returned None") + + # ============================================================================= + # 清理 + # ============================================================================= + _cleanup() + + stdlib.free(buf) + return testcheck.end() diff --git a/SysLibTest/project.json b/SysLibTest/project.json new file mode 100644 index 0000000..047edbe --- /dev/null +++ b/SysLibTest/project.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "SysLibTest", + "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": "SysLibTest.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 + } +} diff --git a/TestFBProject/App/main.vp b/TestFBProject/App/main.vp new file mode 100644 index 0000000..0ca823f --- /dev/null +++ b/TestFBProject/App/main.vp @@ -0,0 +1,160 @@ +from stdint import * +import w32.win32console +import t, c +import testcheck + + +def add_inline(a: t.CInt, b: t.CInt) -> t.CDefine: + return a + b + +def mul_inline(a: t.CInt, b: t.CInt) -> t.CDefine: + return a * b + + +class AppError(Exception): + pass + +class DiskError(AppError): + pass + +class NetworkError(AppError): + pass + +class TimeoutError(NetworkError): + pass + + +def raise_disk(): + raise DiskError("disk read failed") + +def raise_network(): + raise NetworkError("connection refused") + +def raise_timeout(): + raise TimeoutError("operation timed out") + + +def main() -> t.CInt | t.CExport: + w32.win32console.SetConsoleCP(65001) + w32.win32console.SetConsoleOutputCP(65001) + + testcheck.begin("TestFBProject: 异常处理与LLVMIR测试") + + testcheck.section("Test 1: Raise and catch exact custom exception") + try: + raise DiskError("disk error") + except DiskError as e: + print("caught DiskError:", e) + testcheck.ok("Test 1: caught DiskError") + except: + testcheck.fail("Test 1: caught by generic except") + + testcheck.section("Test 2: Catch parent catches child") + try: + raise_disk() + except AppError as e: + print("caught AppError (child DiskError):", e) + testcheck.ok("Test 2: caught AppError (child DiskError)") + except: + testcheck.fail("Test 2: caught by generic except") + + testcheck.section("Test 3: Catch parent catches nested child") + try: + raise_timeout() + except AppError as e: + print("caught AppError (grandchild TimeoutError):", e) + testcheck.ok("Test 3: caught AppError (grandchild TimeoutError)") + except: + testcheck.fail("Test 3: caught by generic except") + + testcheck.section("Test 4: Catch mid-level parent") + try: + raise_timeout() + except NetworkError as e: + print("caught NetworkError (child TimeoutError):", e) + testcheck.ok("Test 4: caught NetworkError (child TimeoutError)") + except: + testcheck.fail("Test 4: caught by generic except") + + testcheck.section("Test 5: Exact catch before parent") + try: + raise_network() + except NetworkError as e: + print("caught NetworkError:", e) + testcheck.ok("Test 5: caught NetworkError") + except AppError as e: + testcheck.fail("Test 5: caught AppError (should be NetworkError first)") + except: + testcheck.fail("Test 5: caught by generic except") + + testcheck.section("Test 6: Parent catch when exact not present") + try: + raise_network() + except DiskError as e: + testcheck.fail("Test 6: caught DiskError (wrong)") + except AppError as e: + print("caught AppError (no NetworkError handler):", e) + testcheck.ok("Test 6: caught AppError (no NetworkError handler)") + except: + testcheck.fail("Test 6: caught by generic except") + + testcheck.section("Test 7: Generic except fallback") + try: + raise_disk() + except RuntimeError as e: + testcheck.fail("Test 7: caught RuntimeError (wrong)") + except: + testcheck.ok("Test 7: caught by generic except") + + testcheck.section("Test 8: Cross-function with inheritance") + try: + raise_timeout() + except NetworkError as e: + print("caught NetworkError (cross-func TimeoutError):", e) + testcheck.ok("Test 8: caught NetworkError (cross-func TimeoutError)") + except: + testcheck.fail("Test 8: caught by generic except") + + testcheck.section("Test 9: Built-in exception still works") + try: + raise ValueError("test") + except ValueError as e: + print("caught ValueError:", e) + testcheck.ok("Test 9: caught ValueError") + except: + testcheck.fail("Test 9: caught by generic except") + + testcheck.section("Test 10: Mixed built-in and custom") + try: + raise RuntimeError("test") + except DiskError as e: + testcheck.fail("Test 10: caught DiskError (wrong)") + except RuntimeError as e: + print("caught RuntimeError:", e) + testcheck.ok("Test 10: caught RuntimeError") + except: + testcheck.fail("Test 10: caught by generic except") + + testcheck.section("Test LLVMIR: inline LLVM IR add") + x: t.CInt = 10 + y: t.CInt = 20 + r: t.CInt + c.LLVMIR(f"{c.LOut(r)} = add i32 {c.LInp(x)}, {c.LInp(y)}") + print("LLVMIR add result:", r) + testcheck.check(r == 30, "LLVMIR add (10+20=30)", "LLVMIR add result mismatch") + + testcheck.section("Test CDefine function macro") + s: t.CInt = add_inline(3, 4) + print("add_inline(3, 4) =", s) + testcheck.check(s == 7, "add_inline(3, 4) = 7", "add_inline result mismatch") + m: t.CInt = mul_inline(5, 6) + print("mul_inline(5, 6) =", m) + testcheck.check(m == 30, "mul_inline(5, 6) = 30", "mul_inline result mismatch") + + testcheck.section("Test LLVMIR with LOut") + out_val: t.CInt = 0 + c.LLVMIR(f"{c.LOut(out_val)} = add i32 {c.LInp(x)}, {c.LInp(y)}") + print("LLVMIR LOut result:", out_val) + testcheck.check(out_val == 30, "LLVMIR LOut (10+20=30)", "LLVMIR LOut result mismatch") + + return testcheck.end() diff --git a/TestFBProject/project.json b/TestFBProject/project.json new file mode 100644 index 0000000..a9d6e8b --- /dev/null +++ b/TestFBProject/project.json @@ -0,0 +1,36 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "TestFBProject", + "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", + "-lucrt", + "-lkernel32", + "-luser32" + ], + "output": "TestFBProject.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 + } +} \ No newline at end of file diff --git a/ThreadingTest/App/main.vp b/ThreadingTest/App/main.vp new file mode 100644 index 0000000..3047cc1 --- /dev/null +++ b/ThreadingTest/App/main.vp @@ -0,0 +1,297 @@ +# ThreadingTest - vthreading 专项测试 +# +# 覆盖范围: +# Thread : start/join/is_alive/get_exit_code/close、线程传参 +# Lock : 多线程持锁互斥自增共享计数器 +# Event : 线程等待事件被唤醒 +# Condition : 生产者/消费者模式 +# RWLock : 多读单写(SRWLock) +# local : TLS 线程局部存储 set/get 自校验 +# get_current_thread_id / sleep_ms +import t, c +from stdint import * +from w32.win32base import NULL, FALSE, TRUE +import stdlib +import testcheck +import vthreading + + +# ============================================================ +# 共享状态(模块级全局,跨线程读写) +# ============================================================ +_shared_count: t.CInt = 0 # Lock 并发测试共享计数器 +_evt_done: t.CInt = 0 # Event 测试完成标志 +_cond_ready: t.CInt = 0 # Condition 测试就绪标志 +_rw_value: t.CInt = 0 # RWLock 测试共享值 +_main_tid: t.CUInt32T = 0 # 主线程 ID + +# 并发规模常量 +THREAD_NUM: t.CInt = 4 +LOCK_ITER: t.CInt = 1000 +RW_ITER: t.CInt = 100 +TLS_NUM: t.CInt = 4 +SYS_ITER: t.CInt = 10 + + +# ============================================================ +# 线程回调(签名: def worker(arg: t.CPtr) -> t.CPtr) +# ============================================================ + +# Thread 基础: 短暂睡眠后退出,保证 start 后 is_alive 观测窗口 +def _basic_worker(arg: t.CPtr) -> t.CPtr: + vthreading.sleep_ms(100) + return NULL + + +# 传参: 通过 arg 指针自增 100 次(c.Deref/c.DerefAs 读写) +def _increment_worker(arg: t.CPtr) -> t.CPtr: + ip: t.CInt | t.CPtr = (t.CInt | t.CPtr)(arg) + i: t.CInt + for i in range(100): + c.DerefAs(ip, c.Deref(ip) + 1) + return NULL + + +# Lock: 持锁自增全局计数器 +def _lock_worker(arg: t.CPtr) -> t.CPtr: + lk: vthreading.Lock | t.CPtr = (vthreading.Lock | t.CPtr)(arg) + global _shared_count + i: t.CInt + for i in range(LOCK_ITER): + lk.acquire() + _shared_count += 1 + lk.release() + return NULL + + +# Event: 等待事件被唤醒后置位完成标志 +def _event_worker(arg: t.CPtr) -> t.CPtr: + ev: vthreading.Event | t.CPtr = (vthreading.Event | t.CPtr)(arg) + global _evt_done + r: t.CInt = ev.wait(5000) + if r == 1: + _evt_done = 1 + return NULL + + +# Condition 消费者: 循环等待 _cond_ready 就绪(限次防挂起) +def _cond_consumer(arg: t.CPtr) -> t.CPtr: + cond: vthreading.Condition | t.CPtr = (vthreading.Condition | t.CPtr)(arg) + global _cond_ready + tries: t.CInt = 0 + cond.acquire() + while _cond_ready == 0 and tries < 100: + cond.wait(100) + tries += 1 + cond.release() + return NULL + + +# Condition 生产者: 延迟后置位 _cond_ready 并 notify +def _cond_producer(arg: t.CPtr) -> t.CPtr: + cond: vthreading.Condition | t.CPtr = (vthreading.Condition | t.CPtr)(arg) + global _cond_ready + vthreading.sleep_ms(50) + cond.acquire() + _cond_ready = 1 + cond.notify() + cond.release() + return NULL + + +# RWLock 读者: 持读锁反复读共享值 +def _rw_reader(arg: t.CPtr) -> t.CPtr: + rwl: vthreading.RWLock | t.CPtr = (vthreading.RWLock | t.CPtr)(arg) + global _rw_value + i: t.CInt + for i in range(RW_ITER * 10): + rwl.acquire_read() + v: t.CInt = _rw_value + rwl.release_read() + return NULL + + +# RWLock 写者: 持写锁自增共享值 +def _rw_writer(arg: t.CPtr) -> t.CPtr: + rwl: vthreading.RWLock | t.CPtr = (vthreading.RWLock | t.CPtr)(arg) + global _rw_value + i: t.CInt + for i in range(RW_ITER): + rwl.acquire_write() + _rw_value += 1 + rwl.release_write() + return NULL + + +# TLS: 每线程 set/get 自校验(存入自身线程 ID 再读回比对) +def _tls_worker(arg: t.CPtr) -> t.CPtr: + tls: vthreading.local = vthreading.local() + tls.set(t.CPtr(t.CUInt64T(vthreading.get_current_thread_id()))) + tid_val: t.CUInt64T = t.CUInt64T(tls.get()) + ok: t.CInt = 0 + if tid_val == t.CUInt64T(vthreading.get_current_thread_id()): + ok = 1 + tls.free() + return t.CPtr(t.CUInt64T(ok)) + + +# 线程 ID 隔离: 工作线程 ID 必须与主线程不同 +def _tid_worker(arg: t.CPtr) -> t.CPtr: + global _main_tid + if vthreading.get_current_thread_id() == _main_tid: + return t.CPtr(t.CUInt64T(0)) + return t.CPtr(t.CUInt64T(1)) + + +# stdlib.system 多线程并发: 每线程循环调 C 运行时 system(),统计失败次数 +def _system_worker(arg: t.CPtr) -> t.CPtr: + i: t.CInt + fails: t.CInt = 0 + for i in range(SYS_ITER): + r: t.CInt = stdlib.system("echo ok > NUL") + if r != 0: + fails += 1 + return t.CPtr(t.CUInt64T(fails)) + + +# ============================================================ +# main +# ============================================================ +def main() -> t.CInt | t.CExport: + testcheck.begin("ThreadingTest: vthreading 专项测试") + + # ========== Thread: start/join/is_alive/get_exit_code ========== + testcheck.section("Thread: start/join/is_alive") + th1: vthreading.Thread = vthreading.Thread(_basic_worker, NULL) + testcheck.check(th1.is_alive() == FALSE, "未 start 时不在运行", "未 start 却 is_alive") + th1.start() + testcheck.check(th1.is_alive() != FALSE, "start 后线程运行中", "start 后未运行") + testcheck.check(th1.join(5000) != FALSE, "join 正常返回", "join 超时") + testcheck.check(th1.is_alive() == FALSE, "join 后线程已结束", "join 后仍运行") + testcheck.check(th1.get_exit_code() == 0, "退出码 == 0", "退出码 != 0") + th1.close() + + # ========== Thread: 通过 arg 传参 ========== + testcheck.section("Thread: arg 传参") + cnt: t.CInt = 0 + th2: vthreading.Thread = vthreading.Thread(_increment_worker, c.Addr(cnt)) + th2.start() + testcheck.check(th2.join(5000) != FALSE, "join 正常返回", "join 超时") + th2.close() + testcheck.check(cnt == 100, "worker 经 arg 自增 100 次", "cnt != 100") + + # ========== Lock: 多线程互斥自增 ========== + testcheck.section("Lock: 多线程互斥自增") + lock: vthreading.Lock = vthreading.Lock() + t0: vthreading.Thread = vthreading.Thread(_lock_worker, t.CPtr(lock)) + t1: vthreading.Thread = vthreading.Thread(_lock_worker, t.CPtr(lock)) + t2: vthreading.Thread = vthreading.Thread(_lock_worker, t.CPtr(lock)) + t3: vthreading.Thread = vthreading.Thread(_lock_worker, t.CPtr(lock)) + t0.start() + t1.start() + t2.start() + t3.start() + j0: t.CInt = t0.join(10000) + j1: t.CInt = t1.join(10000) + j2: t.CInt = t2.join(10000) + j3: t.CInt = t3.join(10000) + t0.close() + t1.close() + t2.close() + t3.close() + testcheck.check(j0 != 0 and j1 != 0 and j2 != 0 and j3 != 0, "4 线程全部 join 成功", "有线程 join 超时") + testcheck.check(_shared_count == THREAD_NUM * LOCK_ITER, "互斥自增计数正确", "计数丢失") + + # ========== Event: 线程等待唤醒 ========== + testcheck.section("Event: 线程等待唤醒") + ev: vthreading.Event = vthreading.Event(FALSE, FALSE) + th4: vthreading.Thread = vthreading.Thread(_event_worker, t.CPtr(ev)) + testcheck.check(ev.is_set() == FALSE, "Event 初始未置位", "Event 初始已置位") + th4.start() + vthreading.sleep_ms(50) + testcheck.check(_evt_done == 0, "set 前 worker 仍等待", "worker 提前完成") + ev.set() + testcheck.check(th4.join(5000) != FALSE, "唤醒后 join 成功", "join 超时") + th4.close() + ev.close() + testcheck.check(_evt_done == 1, "worker 收到事件并置位", "worker 未收到事件") + + # ========== Condition: 生产者/消费者 ========== + testcheck.section("Condition: 生产者/消费者") + cond: vthreading.Condition = vthreading.Condition() + tc: vthreading.Thread = vthreading.Thread(_cond_consumer, t.CPtr(cond)) + tp: vthreading.Thread = vthreading.Thread(_cond_producer, t.CPtr(cond)) + tc.start() + tp.start() + testcheck.check(tc.join(5000) != FALSE, "消费者被唤醒", "消费者等待超时") + testcheck.check(tp.join(5000) != FALSE, "生产者完成", "生产者超时") + tc.close() + tp.close() + testcheck.check(_cond_ready == 1, "条件变量值已置位", "条件变量值未置位") + cond.delete() + + # ========== RWLock: 多读单写 ========== + testcheck.section("RWLock: 多读单写") + rwl: vthreading.RWLock = vthreading.RWLock() + r1: vthreading.Thread = vthreading.Thread(_rw_reader, t.CPtr(rwl)) + r2: vthreading.Thread = vthreading.Thread(_rw_reader, t.CPtr(rwl)) + w1: vthreading.Thread = vthreading.Thread(_rw_writer, t.CPtr(rwl)) + r1.start() + r2.start() + w1.start() + testcheck.check(r1.join(10000) != FALSE and r2.join(10000) != FALSE and w1.join(10000) != FALSE, + "读写线程全部 join", "读写线程 join 超时") + r1.close() + r2.close() + w1.close() + testcheck.check(_rw_value == RW_ITER, "写锁自增计数正确", "写锁计数丢失") + + # ========== local: TLS 线程局部存储 ========== + testcheck.section("local: TLS 线程局部存储") + i_t: t.CInt + for i_t in range(TLS_NUM): + th_t: vthreading.Thread = vthreading.Thread(_tls_worker, NULL) + th_t.start() + testcheck.check(th_t.join(5000) != FALSE, "TLS worker join", "TLS worker 超时") + testcheck.check(th_t.get_exit_code() == 1, "TLS set/get 自校验通过", "TLS 自校验失败") + th_t.close() + + # ========== get_current_thread_id: 线程 ID 隔离 ========== + testcheck.section("get_current_thread_id: 线程 ID 隔离") + global _main_tid + _main_tid = vthreading.get_current_thread_id() + testcheck.check(_main_tid != 0, "主线程 ID != 0", "主线程 ID == 0") + th_tid: vthreading.Thread = vthreading.Thread(_tid_worker, NULL) + th_tid.start() + testcheck.check(th_tid.join(5000) != FALSE, "tid worker join", "tid worker 超时") + testcheck.check(th_tid.get_exit_code() == 1, "工作线程 ID 与主线程不同", "工作线程 ID 与主线程相同") + th_tid.close() + + # ========== sleep_ms ========== + testcheck.section("sleep_ms") + vthreading.sleep_ms(20) + testcheck.ok("sleep_ms(20) 正常返回") + + # ========== stdlib.system 多线程并发 ========== + testcheck.section("stdlib.system 多线程并发") + s0: vthreading.Thread = vthreading.Thread(_system_worker, NULL) + s1: vthreading.Thread = vthreading.Thread(_system_worker, NULL) + s2: vthreading.Thread = vthreading.Thread(_system_worker, NULL) + s3: vthreading.Thread = vthreading.Thread(_system_worker, NULL) + s0.start() + s1.start() + s2.start() + s3.start() + testcheck.check(s0.join(30000) != FALSE and s1.join(30000) != FALSE + and s2.join(30000) != FALSE and s3.join(30000) != FALSE, + "4 个 system 线程全部 join", "system 线程 join 超时") + testcheck.check(s0.get_exit_code() == 0, "线程0 system 全部成功", "线程0 system 有失败") + testcheck.check(s1.get_exit_code() == 0, "线程1 system 全部成功", "线程1 system 有失败") + testcheck.check(s2.get_exit_code() == 0, "线程2 system 全部成功", "线程2 system 有失败") + testcheck.check(s3.get_exit_code() == 0, "线程3 system 全部成功", "线程3 system 有失败") + s0.close() + s1.close() + s2.close() + s3.close() + + return testcheck.end() diff --git a/ThreadingTest/project.json b/ThreadingTest/project.json new file mode 100644 index 0000000..f9a1280 --- /dev/null +++ b/ThreadingTest/project.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "ThreadingTest", + "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": "ThreadingTest.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 + } +} diff --git a/TypeCastTest/App/main.vp b/TypeCastTest/App/main.vp new file mode 100644 index 0000000..6cff824 --- /dev/null +++ b/TypeCastTest/App/main.vp @@ -0,0 +1,198 @@ +from stdint import * +import t, c +import stdio +import string +import w32.win32console +import w32.win32memory +import testcheck + +# ============================================================ +# TypeCastTest - 测试类型转换、zext/sext/trunc 行为、 +# 有符号/无符号混合运算、CDefine 常量 +# ============================================================ + +# --- Test 1: CUInt8T -> CUInt32T 零扩展 (zext) --- +def test_zext_u8_u32(): + v: t.CUInt8T = 200 # 0xC8, 如果 sign-extend 会变成 0xFFFFFFC8 + wide: t.CUInt32T = t.CUInt32T(v) + testcheck.check(wide == 200, "zext u8->u32 (200)", "zext u8->u32 (expected 200)") + + +# --- Test 2: CInt8T -> CInt32T 符号扩展 (sext) --- +def test_sext_i8_i32(): + v: t.CInt8T = -50 # 0xCE + wide: t.CInt32T = t.CInt32T(v) + testcheck.check(wide == -50, "sext i8->i32 (-50)", "sext i8->i32 (expected -50)") + + +# --- Test 3: CUInt32T -> CUInt64T 零扩展 --- +def test_zext_u32_u64(): + v: t.CUInt32T = 0x80000000 # 最高位为1 + wide: t.CUInt64T = t.CUInt64T(v) + testcheck.check(wide == 0x80000000, "zext u32->u64 (0x80000000)", "zext u32->u64 (expected 0x80000000)") + + +# --- Test 4: CInt32T -> CInt64T 符号扩展 --- +def test_sext_i32_i64(): + v: t.CInt32T = -1 # 0xFFFFFFFF + wide: t.CInt64T = t.CInt64T(v) + testcheck.check(wide == -1, "sext i32->i64 (-1)", "sext i32->i64 (expected -1)") + + +# --- Test 5: CUInt64T -> CUInt32T 截断 (trunc) --- +def test_trunc_u64_u32(): + v: t.CUInt64T = 0x123456789ABCDEF0 + narrow: t.CUInt32T = t.CUInt32T(v) + testcheck.check(narrow == 0x9ABCDEF0, "trunc u64->u32 (0x9ABCDEF0)", "trunc u64->u32 (expected 0x9ABCDEF0)") + + +# --- Test 6: 有符号/无符号混合运算 --- +def test_mixed_signed_unsigned(): + a: t.CInt = -10 + b: t.CUInt32T = 20 + # C 中有符号/无符号混合运算,有符号会转为无符号 + # -10 作为 unsigned 是 0xFFFFFFF6 = 4294967286 + # 4294967286 + 20 = 4294967306 (overflow to 10 on u32) + result: t.CUInt32T = t.CUInt32T(a) + b + stdio.printf(" mixed signed+unsigned: %u (C behavior: %u)\n", result, t.CUInt32T(-10) + 20) + testcheck.ok("mixed signed+unsigned (C behavior)") + + +# --- Test 7: CDefine 常量在运算中的行为 --- +VAL_32BIT: t.CDefine = 0x80000000 +VAL_NEG: t.CDefine = -1 +VAL_BIG: t.CDefine = 0xFFFFFFFF + +def test_cdefine_values(): + """测试 CDefine 常量值是否正确""" + v1: t.CUInt32T = t.CUInt32T(VAL_32BIT) + v2: t.CInt = VAL_NEG + v3: t.CUInt32T = t.CUInt32T(VAL_BIG) + stdio.printf(" CDefine: 0x80000000=%u, -1=%d, 0xFFFFFFFF=%u\n", v1, v2, v3) + testcheck.ok("CDefine constants") + + +# --- Test 8: 位运算与类型宽度 --- +def test_bitops_width(): + """测试位运算是否保持正确类型宽度""" + # 左移 + v: t.CUInt32T = 1 + shifted: t.CUInt32T = v << 31 # 应该是 0x80000000 + testcheck.check(shifted == 0x80000000, "bit shift (1<<31 = 0x80000000)", "bit shift (expected 0x80000000)") + + # 右移 + back: t.CUInt32T = shifted >> 31 # 应该是 1 + testcheck.check(back == 1, "bit shift (0x80000000>>31 = 1)", "bit shift (expected 1)") + + +# --- Test 9: 整数除法与取模 (无符号) --- +def test_unsigned_divmod(): + a: t.CUInt32T = 100 + b: t.CUInt32T = 7 + q: t.CUInt32T = a // b + r: t.CUInt32T = a % b + testcheck.check(q == 14 and r == 2, "unsigned div/mod (100//7=14, 100%7=2)", "unsigned div/mod (expected 14,2)") + + +# --- Test 10: 整数除法与取模 (有符号负数) --- +def test_signed_divmod_neg(): + a: t.CInt = -100 + b: t.CInt = 7 + q: t.CInt = a // b + r: t.CInt = a % b + # C 语言: -100/7 = -14, -100%7 = -2 + # Python: -100//7 = -15, -100%7 = 5 + # TransPyC 应该遵循 C 语义 + stdio.printf(" signed div/mod: -100//7=%d, -100%%7=%d (C: -14,-2)\n", q, r) + testcheck.ok("signed div/mod (C semantics)") + + +# --- Test 11: 比较运算返回值 --- +def test_comparison_types(): + a: t.CInt = 10 + b: t.CInt = 20 + c_val: t.CInt = 10 + lt: t.CInt = 1 if a < b else 0 + eq: t.CInt = 1 if a == c_val else 0 + gt: t.CInt = 1 if b > a else 0 + testcheck.check(lt == 1 and eq == 1 and gt == 1, "comparison operations", "comparison operations failed") + + +# --- Test 12: 指针与整数互转 --- +def test_ptr_int_cast(): + buf: t.CUInt32T | t.CPtr = w32.win32memory.VirtualAlloc(None, 64, 0x3000, 0x04) + if not buf: + testcheck.fail("VirtualAlloc returned NULL") + return + # 指针转整数 + addr: t.CUInt64T = t.CUInt64T(buf) + stdio.printf(" ptr->int: addr=0x%lx\n", addr) + # 整数转指针 + p2: t.CUInt32T | t.CPtr = (t.CUInt32T | t.CPtr)(addr) + p2[0] = 0x12345678 + testcheck.check(buf[0] == 0x12345678, "ptr<->int roundtrip", "ptr<->int roundtrip failed") + + +# --- Test 13: CUInt64T 乘法溢出行为 --- +def test_u64_mul(): + a: t.CUInt64T = 1000 + b: t.CUInt64T = 1000 + c_val: t.CUInt64T = a * b + testcheck.check(c_val == 1000000, "u64 mul (1000*1000=1000000)", "u64 mul (expected 1000000)") + + +# --- Test 14: bool 运算 (and/or) --- +def test_bool_ops(): + a: t.CInt = 5 + b: t.CInt = 0 + c_val: t.CInt = 3 + # Python `and`/`or` 是短路求值 + r1: t.CInt = a and c_val # 5 and 3 -> 在 C 中应该是 (5 && 3) = 1 + r2: t.CInt = b or c_val # 0 or 3 -> 在 C 中应该是 (0 || 3) = 1 + stdio.printf(" bool: 5 and 3 = %d, 0 or 3 = %d (expect 1,1 in C)\n", r1, r2) + testcheck.ok("bool ops (C semantics)") + + +# --- Test 15: 条件表达式 (三元运算符) --- +def test_ternary(): + a: t.CInt = 10 + b: t.CInt = 20 + max_val: t.CInt = a if a > b else b + min_val: t.CInt = a if a < b else b + testcheck.check(max_val == 20 and min_val == 10, "ternary (max=20 min=10)", "ternary (expected 20,10)") + + +def main() -> t.CInt | t.CExport: + w32.win32console.SetConsoleCP(65001) + w32.win32console.SetConsoleOutputCP(65001) + + testcheck.begin("TypeCastTest: 类型转换与运算基准测试") + + testcheck.section("zext/sext/trunc") + test_zext_u8_u32() + test_sext_i8_i32() + test_zext_u32_u64() + test_sext_i32_i64() + test_trunc_u64_u32() + + testcheck.section("mixed operations") + test_mixed_signed_unsigned() + test_cdefine_values() + test_bitops_width() + + testcheck.section("div/mod") + test_unsigned_divmod() + test_signed_divmod_neg() + + testcheck.section("comparison & logic") + test_comparison_types() + test_bool_ops() + test_ternary() + + testcheck.section("pointer/int cast") + test_ptr_int_cast() + + testcheck.section("u64 mul") + test_u64_mul() + + return testcheck.end() diff --git a/TypeCastTest/project.json b/TypeCastTest/project.json new file mode 100644 index 0000000..9a367ef --- /dev/null +++ b/TypeCastTest/project.json @@ -0,0 +1,40 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "TypeCastTest", + "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": "TypeCastTest.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 + } +} \ No newline at end of file diff --git a/VRandomTest/App/main.vp b/VRandomTest/App/main.vp new file mode 100644 index 0000000..d88b305 --- /dev/null +++ b/VRandomTest/App/main.vp @@ -0,0 +1,128 @@ +from stdint import * +import t, c +import stdio +import random +import testcheck + + +# ============================================================ +# VRandomTest - 硬件随机数生成 + 标准分布函数测试 +# ============================================================ + +def main() -> t.CInt: + testcheck.begin("VRandomTest: Hardware RNG + Distributions") + + # --- Test 1: RDRAND basic --- + testcheck.section("Test 1: RDRAND basic") + r32: t.CUInt32T = vrandom.rdrand32() + r64: t.CUInt64T = vrandom.rdrand64() + stdio.printf(" rdrand32() = 0x%08x\n", r32) + stdio.printf(" rdrand64() = 0x%016llx\n", r64) + testcheck.ok("RDRAND basic") + + # --- Test 2: randint --- + testcheck.section("Test 2: randint(1, 100)") + for _ in range(5): + v: t.CInt = vrandom.randint(1, 100) + stdio.printf(" randint(1,100) = %d\n", v) + testcheck.ok("randint range check") + + # --- Test 3: randrange --- + testcheck.section("Test 3: randrange(0, 100, 5)") + for _ in range(5): + v = vrandom.randrange(0, 100, 5) + stdio.printf(" randrange(0,100,5) = %d\n", v) + testcheck.ok("randrange step check") + + # --- Test 4: getrandbits --- + testcheck.section("Test 4: getrandbits(8)") + for _ in range(3): + b: t.CUInt64T = vrandom.getrandbits(8) + stdio.printf(" getrandbits(8) = 0x%02llx\n", b) + testcheck.ok("getrandbits width check") + + # --- Test 5: random() [0,1) --- + testcheck.section("Test 5: random()") + for _ in range(3): + f: t.CDouble = vrandom.random() + stdio.printf(" random() = %f\n", f) + testcheck.ok("random() in [0,1)") + + # --- Test 6: uniform --- + testcheck.section("Test 6: uniform(10.0, 20.0)") + for _ in range(3): + f = vrandom.uniform(10.0, 20.0) + stdio.printf(" uniform(10,20) = %f\n", f) + testcheck.ok("uniform range check") + + # --- Test 7: gauss --- + testcheck.section("Test 7: gauss(0.0, 1.0)") + for _ in range(3): + f = vrandom.gauss(0.0, 1.0) + stdio.printf(" gauss(0,1) = %f\n", f) + testcheck.ok("gauss distribution") + + # --- Test 8: normalvariate --- + testcheck.section("Test 8: normalvariate(100.0, 15.0)") + for _ in range(3): + f = vrandom.normalvariate(100.0, 15.0) + stdio.printf(" normalvariate(100,15) = %f\n", f) + testcheck.ok("normalvariate distribution") + + # --- Test 9: expovariate --- + testcheck.section("Test 9: expovariate(0.5)") + for _ in range(3): + f = vrandom.expovariate(0.5) + stdio.printf(" expovariate(0.5) = %f\n", f) + testcheck.ok("expovariate distribution") + + # --- Test 10: gammavariate --- + testcheck.section("Test 10: gammavariate(2.0, 1.0)") + for _ in range(3): + f = vrandom.gammavariate(2.0, 1.0) + stdio.printf(" gammavariate(2,1) = %f\n", f) + testcheck.ok("gammavariate distribution") + + # --- Test 11: betavariate --- + testcheck.section("Test 11: betavariate(2.0, 5.0)") + for _ in range(3): + f = vrandom.betavariate(2.0, 5.0) + stdio.printf(" betavariate(2,5) = %f\n", f) + testcheck.ok("betavariate distribution") + + # --- Test 12: triangular --- + testcheck.section("Test 12: triangular(0.0, 10.0, 5.0)") + for _ in range(3): + f = vrandom.triangular(0.0, 10.0, 5.0) + stdio.printf(" triangular(0,10,5) = %f\n", f) + testcheck.ok("triangular distribution") + + # --- Test 13: lognormvariate --- + testcheck.section("Test 13: lognormvariate(0.0, 1.0)") + for _ in range(3): + f = vrandom.lognormvariate(0.0, 1.0) + stdio.printf(" lognormvariate(0,1) = %f\n", f) + testcheck.ok("lognormvariate distribution") + + # --- Test 14: paretovariate --- + testcheck.section("Test 14: paretovariate(1.0)") + for _ in range(3): + f = vrandom.paretovariate(1.0) + stdio.printf(" paretovariate(1) = %f\n", f) + testcheck.ok("paretovariate distribution") + + # --- Test 15: weibullvariate --- + testcheck.section("Test 15: weibullvariate(1.0, 1.5)") + for _ in range(3): + f = vrandom.weibullvariate(1.0, 1.5) + stdio.printf(" weibullvariate(1,1.5) = %f\n", f) + testcheck.ok("weibullvariate distribution") + + # --- Test 16: vonmisesvariate --- + testcheck.section("Test 16: vonmisesvariate(0.0, 1.0)") + for _ in range(3): + f = vrandom.vonmisesvariate(0.0, 1.0) + stdio.printf(" vonmisesvariate(0,1) = %f\n", f) + testcheck.ok("vonmisesvariate distribution") + + return testcheck.end() diff --git a/VRandomTest/project.json b/VRandomTest/project.json new file mode 100644 index 0000000..3588e03 --- /dev/null +++ b/VRandomTest/project.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "VRandomTest", + "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": "VRandomTest.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 + } +} diff --git a/VariadicTest/App/main.vp b/VariadicTest/App/main.vp new file mode 100644 index 0000000..b4c1da2 --- /dev/null +++ b/VariadicTest/App/main.vp @@ -0,0 +1,184 @@ +from stdint import * +import t, c +import stdio +import testcheck +import string +import viperlib +import w32.win32console + +# ============================================================ +# VariadicTest - 测试 snprintf/printf variadic 参数传递 +# ============================================================ + +# --- Test 1: %u 格式化小整数 (CUInt8T -> CUnsignedInt) --- +def test_snprintf_u8(): + """测试 CUInt8T 值通过 t.CUnsignedInt() 传递给 %u""" + testcheck.section("Test 1: %u 格式化小整数 (CUInt8T -> CUnsignedInt)") + hr: t.CUInt8T = 14 + mn: t.CUInt8T = 30 + sc: t.CUInt8T = 59 + buf: t.CArray[t.CChar, 64] + string.memset(c.Addr(buf), 0, 64) + viperlib.snprintf(c.Addr(buf), 64, "%02u:%02u:%02u", t.CUnsignedInt(hr), t.CUnsignedInt(mn), t.CUnsignedInt(sc)) + stdio.printf("Test1 (CUInt8T->%%u): [%s] (expect 14:30:59)\n", c.Addr(buf)) + testcheck.ok("CUInt8T -> %u (expect 14:30:59)") + + +# --- Test 2: %u 格式化 CUInt16T --- +def test_snprintf_u16(): + """测试 CUInt16T 值通过 t.CUnsignedInt() 传递给 %u""" + testcheck.section("Test 2: %u 格式化 CUInt16T") + yr: t.CUInt16T = 2026 + buf: t.CArray[t.CChar, 64] + string.memset(c.Addr(buf), 0, 64) + viperlib.snprintf(c.Addr(buf), 64, "%04u", t.CUnsignedInt(yr)) + stdio.printf("Test2 (CUInt16T->%%u): [%s] (expect 2026)\n", c.Addr(buf)) + testcheck.ok("CUInt16T -> %u (expect 2026)") + + +# --- Test 3: %lu 格式化 CUInt64T --- +def test_snprintf_u64(): + """测试 CUInt64T 值传递给 %lu""" + testcheck.section("Test 3: %lu 格式化 CUInt64T") + val: t.CUInt64T = 1234567890123 + buf: t.CArray[t.CChar, 64] + string.memset(c.Addr(buf), 0, 64) + viperlib.snprintf(c.Addr(buf), 64, "%lu", val) + stdio.printf("Test3 (CUInt64T->%%lu): [%s] (expect 1234567890123)\n", c.Addr(buf)) + testcheck.ok("CUInt64T -> %lu (expect 1234567890123)") + + +# --- Test 4: %d 格式化负数 --- +def test_snprintf_d_neg(): + """测试 %d 格式化负整数""" + testcheck.section("Test 4: %d 格式化负数") + val: t.CInt = -42 + buf: t.CArray[t.CChar, 64] + string.memset(c.Addr(buf), 0, 64) + viperlib.snprintf(c.Addr(buf), 64, "%d", val) + stdio.printf("Test4 (CInt->%%d neg): [%s] (expect -42)\n", c.Addr(buf)) + testcheck.ok("CInt -> %d neg (expect -42)") + + +# --- Test 5: %d 格式化正数 --- +def test_snprintf_d_pos(): + testcheck.section("Test 5: %d 格式化正数") + val: t.CInt = 42 + buf: t.CArray[t.CChar, 64] + string.memset(c.Addr(buf), 0, 64) + viperlib.snprintf(c.Addr(buf), 64, "%d", val) + stdio.printf("Test5 (CInt->%%d pos): [%s] (expect 42)\n", c.Addr(buf)) + testcheck.ok("CInt -> %d pos (expect 42)") + + +# --- Test 6: %x 格式化十六进制 --- +def test_snprintf_x(): + testcheck.section("Test 6: %x 格式化十六进制") + val: t.CUInt32T = 0xDEADBEEF + buf: t.CArray[t.CChar, 64] + string.memset(c.Addr(buf), 0, 64) + viperlib.snprintf(c.Addr(buf), 64, "0x%08x", val) + stdio.printf("Test6 (%%x): [%s] (expect 0xdeadbeef)\n", c.Addr(buf)) + testcheck.ok("%x hex (expect 0xdeadbeef)") + + +# --- Test 7: 混合格式化 (模拟 desktop.py 时间格式) --- +def test_snprintf_mixed(): + """模拟 desktop.py 的时间格式化""" + testcheck.section("Test 7: 混合格式化 (模拟 desktop.py 时间格式)") + hr: t.CUInt8T = 14 + mn: t.CUInt8T = 5 + sc: t.CUInt8T = 9 + day: t.CUInt8T = 14 + mon: t.CUInt8T = 6 + yr: t.CUInt16T = 2026 + buf: t.CArray[t.CChar, 64] + string.memset(c.Addr(buf), 0, 64) + viperlib.snprintf(c.Addr(buf), 64, "%04u-%02u-%02u %02u:%02u:%02u", + t.CUnsignedInt(yr), t.CUnsignedInt(mon), t.CUnsignedInt(day), + t.CUnsignedInt(hr), t.CUnsignedInt(mn), t.CUnsignedInt(sc)) + stdio.printf("Test7 (time format): [%s] (expect 2026-06-14 14:05:09)\n", c.Addr(buf)) + testcheck.ok("time format (expect 2026-06-14 14:05:09)") + + +# --- Test 8: printf 直接输出 variadic --- +def test_printf_variadic(): + """测试 printf 直接输出 variadic 参数""" + testcheck.section("Test 8: printf 直接输出 variadic") + stdio.printf("Test8 (printf direct): %u %d %lu 0x%x (expect 100 -50 999999999 0xcafe)\n", + t.CUnsignedInt(100), -50, t.CUInt64T(999999999), 0xCAFE) + testcheck.ok("printf direct variadic (expect 100 -50 999999999 0xcafe)") + + +# --- Test 9: 多个 %lu 连续 --- +def test_snprintf_multi_lu(): + """测试多个 %lu 连续(模拟 perf 日志格式)""" + testcheck.section("Test 9: 多个 %lu 连续") + v1: t.CUInt64T = 16 + v2: t.CUInt64T = 2 + v3: t.CUInt64T = 11 + buf: t.CArray[t.CChar, 128] + string.memset(c.Addr(buf), 0, 128) + viperlib.snprintf(c.Addr(buf), 128, "wall=%lu work=%lu render=%lu", v1, v2, v3) + stdio.printf("Test9 (multi %%lu): [%s] (expect wall=16 work=2 render=11)\n", c.Addr(buf)) + testcheck.ok("multi %lu (expect wall=16 work=2 render=11)") + + +# --- Test 10: %u 格式化 0 --- +def test_snprintf_zero(): + testcheck.section("Test 10: %u 格式化 0") + val: t.CUInt32T = 0 + buf: t.CArray[t.CChar, 64] + string.memset(c.Addr(buf), 0, 64) + viperlib.snprintf(c.Addr(buf), 64, "%u", val) + stdio.printf("Test10 (%%u zero): [%s] (expect 0)\n", c.Addr(buf)) + testcheck.ok("%u zero (expect 0)") + + +# --- Test 11: %u 格式化大值 --- +def test_snprintf_large(): + testcheck.section("Test 11: %u 格式化大值") + val: t.CUInt32T = 4294967295 # 0xFFFFFFFF + buf: t.CArray[t.CChar, 64] + string.memset(c.Addr(buf), 0, 64) + viperlib.snprintf(c.Addr(buf), 64, "%u", val) + stdio.printf("Test11 (%%u max): [%s] (expect 4294967295)\n", c.Addr(buf)) + testcheck.ok("%u max (expect 4294967295)") + + +# --- Test 12: CUnsignedInt cast from CUInt8T edge values --- +def test_snprintf_u8_edge(): + """测试 CUInt8T 边界值""" + testcheck.section("Test 12: CUnsignedInt cast from CUInt8T edge values") + v0: t.CUInt8T = 0 + v127: t.CUInt8T = 127 + v128: t.CUInt8T = 128 + v255: t.CUInt8T = 255 + buf: t.CArray[t.CChar, 64] + string.memset(c.Addr(buf), 0, 64) + viperlib.snprintf(c.Addr(buf), 64, "%u %u %u %u", + t.CUnsignedInt(v0), t.CUnsignedInt(v127), t.CUnsignedInt(v128), t.CUnsignedInt(v255)) + stdio.printf("Test12 (CUInt8T edge): [%s] (expect 0 127 128 255)\n", c.Addr(buf)) + testcheck.ok("CUInt8T edge (expect 0 127 128 255)") + + +def main() -> t.CInt | t.CExport: + w32.win32console.SetConsoleCP(65001) + w32.win32console.SetConsoleOutputCP(65001) + + testcheck.begin("VariadicTest: snprintf/printf variadic 参数测试") + + test_snprintf_u8() + test_snprintf_u16() + test_snprintf_u64() + test_snprintf_d_neg() + test_snprintf_d_pos() + test_snprintf_x() + test_snprintf_mixed() + test_printf_variadic() + test_snprintf_multi_lu() + test_snprintf_zero() + test_snprintf_large() + test_snprintf_u8_edge() + + return testcheck.end() diff --git a/VariadicTest/project.json b/VariadicTest/project.json new file mode 100644 index 0000000..a4f8762 --- /dev/null +++ b/VariadicTest/project.json @@ -0,0 +1,40 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "VariadicTest", + "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": "VariadicTest.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 + } +} \ No newline at end of file diff --git a/VectorGenericTest/App/main.vp b/VectorGenericTest/App/main.vp new file mode 100644 index 0000000..a056c77 --- /dev/null +++ b/VectorGenericTest/App/main.vp @@ -0,0 +1,11 @@ +import t, c +import testcheck +import vectortest + + +def main() -> t.CInt | t.CExport: + testcheck.begin("VectorGenericTest: Vector 泛型测试") + testcheck.section("Vector 泛型") + vectortest.vector_main() + testcheck.ok("Vector 泛型测试完成") + return testcheck.end() diff --git a/VectorGenericTest/App/vectortest.vp b/VectorGenericTest/App/vectortest.vp new file mode 100644 index 0000000..d481c80 --- /dev/null +++ b/VectorGenericTest/App/vectortest.vp @@ -0,0 +1,43 @@ +import t, c +from t import CInt, CPtr, CChar, CFloat64T +import viperlib +import stdlib +import vector +import memhub + +POOL_SIZE: t.CDefine = 4096 + +def vector_main() -> CInt: + buf: str = stdlib.malloc(256) + pool_mem: t.CPtr = stdlib.malloc(POOL_SIZE) + pool: memhub.MemPool | CPtr = memhub.MemPool(pool_mem, POOL_SIZE) + + vi: vector.Vector | CPtr = vector.Vector(pool, 10, CInt(0)) + vi.push(CInt(10)) + vi.push(CInt(20)) + vi.push(CInt(30)) + viperlib.snprintf(buf, 256, "Vector[int]: len=%d, [0]=%d, [1]=%d, [2]=%d", vi.len(), vi.get(0), vi.get(1), vi.get(2)) + print(buf) + + vi.set(1, CInt(99)) + viperlib.snprintf(buf, 256, "Vector[int]: set[1]=99, [1]=%d", vi.get(1)) + print(buf) + + vi.clear() + viperlib.snprintf(buf, 256, "Vector[int]: cleared, len=%d", vi.len()) + print(buf) + + vi.free() + + vd: vector.Vector | CPtr = vector.Vector(pool, 8, CFloat64T(0.0)) + vd.push(CFloat64T(1.5)) + vd.push(CFloat64T(2.7)) + vd.push(CFloat64T(3.14)) + viperlib.snprintf(buf, 256, "Vector[double]: len=%d, [0]=%.1f, [1]=%.1f, [2]=%.2f", vd.len(), vd.get(0), vd.get(1), vd.get(2)) + print(buf) + + vd.free() + + stdlib.free(pool_mem) + stdlib.free(buf) + return 0 diff --git a/VectorGenericTest/project.json b/VectorGenericTest/project.json new file mode 100644 index 0000000..4e57b9f --- /dev/null +++ b/VectorGenericTest/project.json @@ -0,0 +1,40 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "VectorGenericTest", + "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": "VectorGenericTest.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 + } +} \ No newline at end of file diff --git a/WebTest/App/main.vp b/WebTest/App/main.vp new file mode 100644 index 0000000..3ef4c2d --- /dev/null +++ b/WebTest/App/main.vp @@ -0,0 +1,81 @@ +import t, c +from stdint import * +import stdio +import stdlib +import socket +import memhub +import requests + + +# 全局 MBuddy 指针 +_mbuddy: memhub.MemBuddy | t.CPtr + + +@t.CExport +def main() -> int: + global _mbuddy + stdio.printf("WebTest: HTTP client library test\n") + + # 初始化内存管理器(16MB arena) + arena: bytes = stdlib.malloc(16 * 1024 * 1024) + if arena is None: + stdio.printf("FATAL: malloc arena failed\n") + return 1 + + _mbuddy = memhub.MemBuddy(arena, 16 * 1024 * 1024) + requests._mbuddy = _mbuddy + + # 初始化 Socket 库 + result: INT = socket.SocketInit() + stdio.printf("SocketInit: %d\n", result) + + # 测试 Socket OOP API + sock = socket.Socket(socket.AF_INET, socket.SOCK_STREAM) + if sock.fd != socket.INVALID_SOCKET: + stdio.printf("Socket: OK (fd=%d)\n", sock.fd) + sock.close() + stdio.printf("Socket.close: OK\n") + else: + stdio.printf("Socket: FAIL\n") + + # 测试 DNS 解析 — 通过 Socket.connect 间接测试(内部调用 _MakeAddr) + stdio.printf("\n--- DNS test ---\n") + dns_sock = socket.Socket(socket.AF_INET, socket.SOCK_STREAM) + if dns_sock.fd != socket.INVALID_SOCKET: + dns_sock.settimeout(5000) + result: INT = dns_sock.connect("example.com", 80) + if result == 0: + stdio.printf("DNS: example.com resolved OK\n") + else: + stdio.printf("DNS: example.com resolved but connect failed (err in _MakeAddr debug above)\n") + dns_sock.close() + + # 测试 HTTP GET — 使用 DNS 解析 example.com + stdio.printf("\n--- HTTP GET test (example.com) ---\n") + resp = requests.get("http://example.com/") + if resp is not None: + stdio.printf("requests.get: OK\n") + code: INT = resp.status_code + length: INT = resp.body_len + stdio.printf(" status_code: %d\n", code) + stdio.printf(" body_len: %d\n", length) + if resp.text is not None and length > 0: + print_len: INT = 300 + if length < print_len: + print_len = length + stdio.printf(" text (first %d chars):\n", print_len) + txt: str = resp.text + i: INT = 0 + while i < print_len and txt[i] != 0: + stdio.printf("%c", txt[i]) + i += 1 + stdio.printf("\n") + requests.release(resp) + else: + stdio.printf("requests.get: FAIL (network unavailable)\n") + + # 清理 + socket.SocketCleanup() + stdio.printf("\nSocketCleanup: OK\n") + stdio.printf("WebTest: ALL PASSED\n") + return 0 \ No newline at end of file diff --git a/WebTest/project.json b/WebTest/project.json new file mode 100644 index 0000000..ebfcaee --- /dev/null +++ b/WebTest/project.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "WebTest", + "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", "-lws2_32", "-Wl,--allow-multiple-definition"], + "output": "WebTest.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 + } +} \ No newline at end of file diff --git a/ZlibDbg/App/main.vp b/ZlibDbg/App/main.vp new file mode 100644 index 0000000..cbc06ef --- /dev/null +++ b/ZlibDbg/App/main.vp @@ -0,0 +1,74 @@ +from stdint import * +import zlib.pyzlib as pyzlib +import zlib.zdeflate as zdeflate +import zlib.zinflate as zinflate +import zlib.zdef as zdef +import string +import stdlib +import t, c +from stdio import printf + + +def fill_data(data: BYTEPTR, size: t.CSizeT, seed: t.CSizeT, repeating: t.CInt): + i: t.CSizeT + for i in range(size): + if repeating: + data[i] = BYTE(65 + (i % 3)) + else: + data[i] = BYTE((i * 31 + seed * 17 + (i * i) % 251) % 256) + + +def roundtrip(seed: t.CSizeT, size: t.CSizeT, repeating: t.CInt, wbits: t.CInt) -> t.CInt: + data: BYTEPTR = BYTEPTR(stdlib.malloc(size)) + fill_data(data, size, seed, repeating) + + out_len: t.CSizeT = 0 + comp: BYTEPTR = pyzlib.compress(None, data, size, + pyzlib.Z_DEFAULT_COMPRESSION, wbits, c.Addr(out_len)) + if not comp: + printf(" [seed=%zu size=%zu rep=%d wbits=%d] COMPRESS FAILED: %d %s\n", + seed, size, repeating, wbits, pyzlib.get_error_code(), pyzlib.get_error()) + stdlib.free(data) + return -1 + + dec_len: t.CSizeT = 0 + dec: BYTEPTR = pyzlib.decompress(None, comp, out_len, wbits, + pyzlib.DEF_BUF_SIZE, c.Addr(dec_len)) + ok: t.CInt = 1 + if not dec: + printf(" [seed=%zu size=%zu rep=%d wbits=%d] DECOMPRESS FAILED: err=%d msg=%s (comp=%zu bytes)\n", + seed, size, repeating, wbits, pyzlib.get_error_code(), pyzlib.get_error(), out_len) + ok = 0 + else: + printf(" [seed=%zu size=%zu rep=%d wbits=%d] comp=%zu dec=%zu ", + seed, size, repeating, wbits, out_len, dec_len) + if dec_len != size or string.memcmp(dec, data, size) != 0: + printf("CONTENT MISMATCH\n") + ok = 0 + else: + printf("OK\n") + if dec: stdlib.free(dec) + stdlib.free(comp) + stdlib.free(data) + return 0 if ok else -1 + + +def main() -> t.CInt: + printf("== zlib roundtrip >256B ==\n") + sizes: t.CArray[t.CSizeT, None] = [250, 255, 256, 257, 260, 300, 500, 1000, 4096, 20000] + n: t.CInt + failed: t.CInt = 0 + for n in range(10): + if roundtrip(t.CSizeT(n), sizes[n], 0, pyzlib.MAX_WBITS) != 0: failed = 1 + printf("-- random data done --\n") + sizes2: t.CArray[t.CSizeT, None] = [256, 257, 300, 1000, 20000] + n = 0 + for n in range(5): + if roundtrip(t.CSizeT(n), sizes2[n], 1, pyzlib.MAX_WBITS) != 0: failed = 1 + printf("-- repeating data done --\n") + sizes3: t.CArray[t.CSizeT, None] = [300, 1000] + n = 0 + for n in range(2): + if roundtrip(t.CSizeT(n), sizes3[n], 0, pyzlib.MAX_WBITS + 16) != 0: failed = 1 + printf("-- gzip container done --\n") + return 1 if failed else 0 diff --git a/ZlibDbg/project.json b/ZlibDbg/project.json new file mode 100644 index 0000000..499dbc8 --- /dev/null +++ b/ZlibDbg/project.json @@ -0,0 +1,38 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "ZlibDbg", + "version": "1.0.0", + "source_dir": "./App", + "compiler": { + "cmd": "llc", + "flags": [ + "-filetype=obj" + ] + }, + "linker": { + "cmd": "clang++", + "flags": [ + "-Wl,--allow-multiple-definition", + "-lmsvcrt", + "-lucrt", + "-lpthread", + "-lmingwex", + "-lkernel32", + "-luser32" + ], + "output": "ZlibDbg.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 + } +} diff --git a/ZlibTest/App/main.vp b/ZlibTest/App/main.vp new file mode 100644 index 0000000..dae15c7 --- /dev/null +++ b/ZlibTest/App/main.vp @@ -0,0 +1,20 @@ +import t +import stdio +import string +import zlib.pyzlib as stdzp +import test_pyzlib as tpz +import w32.win32memory +import c +import testcheck + +def main() -> t.CInt: + testcheck.begin("ZlibTest: Zlib 压缩库测试") + tpz.main123456() + testcheck.ok("zlib test_pyzlib completed") + + # 标准 zlib 库(includes/zlib) + testcheck.section("标准 zlib 库 (zlib.pyzlib)") + print(stdzp.runtime_version()) + testcheck.ok("zlib runtime version printed") + + return testcheck.end() diff --git a/ZlibTest/App/test_pyzlib.vp b/ZlibTest/App/test_pyzlib.vp new file mode 100644 index 0000000..9dccf3e --- /dev/null +++ b/ZlibTest/App/test_pyzlib.vp @@ -0,0 +1,878 @@ +from stdint import * +import zlib.pyzlib as pyzlib +import zlib.zhuff as zhuff +import zlib.zdef as zdef +from stdio import printf +import stdlib +from string import strlen +import string +import t, c + + +test_passed: t.CInt = 0 +test_failed: t.CInt = 0 +def check(name: str, condition: t.CInt, detail: str): + global test_passed, test_failed + if condition: + test_passed += 1 + printf(" [PASS] %s\n", name) + else: + test_failed += 1 + printf(" [FAIL] %s -- %s\n", name, detail if detail else "") + +def print_hex_test(data: BYTEPTR, length: t.CSizeT, max_show: t.CSizeT): + if not data or length == 0: + printf("(empty)\n") + return + show: t.CSizeT = max_show if (length > max_show) else length + i: t.CSizeT + for i in range(show): + printf("%02X ", data[i]) + if length > max_show: + printf("... (%zu bytes total)", length) + printf("\n") + +def print_separator(): + printf(" -------------------------------------------\n") + +def section_header(title: str): + printf("\n+-- %s --+\n", title) + +def section_footer(): + printf("+--------------------------------------------+\n") + +# ============================================================ + +def test_version(): + section_header("Version Info") + + ver: str = pyzlib.ZLIB_VERSION + printf(" ZLIB_VERSION (compile-time) : %s\n", ver) + check("ZLIB_VERSION not None", ver != None, "version string is None") + check("ZLIB_VERSION not empty", strlen(ver) > 0, "version string is empty") + + runtime_ver: str = pyzlib.runtime_version() + printf(" ZLIB_RUNTIME_VERSION : %s\n", runtime_ver) + check("runtime version not None", runtime_ver != None, "runtime version is None") + check("runtime version not empty", strlen(runtime_ver) > 0, "runtime version is empty") + + section_footer() + + +def test_compress_decompress(): + section_header("compress / decompress") + + inp: str = "Hello, World! This is a test of zlib compression and decompression." + input_length: t.CSizeT = strlen(inp) + printf(" Input (%zu bytes): \"%s\"\n", input_length, inp) + + out_length: t.CSizeT = 0 + compressed: BYTEPTR = pyzlib.compress(None, BYTEPTR(inp), input_length, + pyzlib.Z_DEFAULT_COMPRESSION, pyzlib.MAX_WBITS, c.Addr(out_length)) + check("compress returns non-None", compressed != None, "compress returned None") + check("compress output size > 0", out_length > 0, "compressed size is 0") + check("compress output produced", out_length > 0, "compressed size is 0") + + printf(" Compressed (%zu bytes): ", out_length) + print_hex_test(compressed, out_length, 32) + printf(" Compression ratio: %.1f%%\n", t.CDouble(out_length) / input_length * 100) + + dec_length: t.CSizeT = 0 + decompressed: BYTEPTR = pyzlib.decompress(None, compressed, out_length, + pyzlib.MAX_WBITS, pyzlib.DEF_BUF_SIZE, c.Addr(dec_length)) + check("decompress returns non-None", decompressed != None, "decompress returned None") + check("decompress output size matches input", dec_length == input_length, "size mismatch") + check("decompress output matches input", decompressed != None and string.memcmp(decompressed, inp, input_length) == 0, "content mismatch") + + printf(" Decompressed (%zu bytes): \"%.*s\"\n", dec_length, t.CInt(dec_length), str(decompressed)) + + stdlib.free(compressed) + stdlib.free(decompressed) + section_footer() + + +def test_compress_levels(): + section_header("Compression Levels") + + inp: str = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + input_length: t.CSizeT = strlen(inp) + printf(" Input (%zu bytes): \"%s\"\n", input_length, inp) + + out_length: t.CSizeT = 0 + + c0: BYTEPTR = pyzlib.compress(None, BYTEPTR(inp), input_length, + pyzlib.Z_NO_COMPRESSION, pyzlib.MAX_WBITS, c.Addr(out_length)) + check("level 0 compress OK", c0 != None, "level 0 returned None") + printf(" Level 0 (Z_NO_COMPRESSION): %zu bytes\n", out_length) + length0: t.CSizeT = out_length + stdlib.free(c0) + + c1: BYTEPTR = pyzlib.compress(None, BYTEPTR(inp), input_length, + pyzlib.Z_BEST_SPEED, pyzlib.MAX_WBITS, c.Addr(out_length)) + check("level 1 compress OK", c1 != None, "level 1 returned None") + printf(" Level 1 (Z_BEST_SPEED) : %zu bytes\n", out_length) + stdlib.free(c1) + + c6: BYTEPTR = pyzlib.compress(None, BYTEPTR(inp), input_length, + pyzlib.Z_DEFAULT_COMPRESSION, pyzlib.MAX_WBITS, c.Addr(out_length)) + check("level -1 compress OK", c6 != None, "default level returned None") + printf(" Level -1 (DEFAULT) : %zu bytes\n", out_length) + stdlib.free(c6) + + c9: BYTEPTR = pyzlib.compress(None, BYTEPTR(inp), input_length, + pyzlib.Z_BEST_COMPRESSION, pyzlib.MAX_WBITS, c.Addr(out_length)) + check("level 9 compress OK", c9 != None, "level 9 returned None") + printf(" Level 9 (Z_BEST_COMPRESS) : %zu bytes\n", out_length) + length9: t.CSizeT = out_length + stdlib.free(c9) + + check("level 9 smaller than level 0", length9 < length0, "level 9 not smaller than level 0") + + section_footer() + + +def test_compressobj(): + section_header("compressobj (incremental)") + + part1: str = "Hello, " + part2: str = "World!" + printf(" Part 1: \"%s\"\n", part1) + printf(" Part 2: \"%s\"\n", part2) + + out_length: t.CSizeT = 0 + + s: pyzlib.Compress | t.CPtr = pyzlib.compressobj(None, pyzlib.Z_DEFAULT_COMPRESSION, pyzlib.DEFLATED, + pyzlib.MAX_WBITS, pyzlib.DEF_MEM_LEVEL, + pyzlib.Z_DEFAULT_STRATEGY, None, 0) + check("compressobj created", s != None, "compressobj is None") + print_separator() + + c1: BYTEPTR = s.compress(BYTEPTR(part1), strlen(part1), c.Addr(out_length)) + check("compress part1 OK", c1 != None, "compress part1 failed") + printf(" Compressed part1: %zu bytes -> ", out_length) + print_hex_test(c1, out_length, 16) + total: t.CSizeT = out_length + all: BYTEPTR = None + if out_length > 0 and c1: + all = BYTEPTR(stdlib.malloc(total)) + if all: string.memcpy(all, c1, out_length) + stdlib.free(c1) + + c2: BYTEPTR = s.compress(BYTEPTR(part2), + strlen(part2), c.Addr(out_length)) + check("compress part2 OK", c2 != None, "compress part2 failed") + printf(" Compressed part2: %zu bytes -> ", out_length) + print_hex_test(c2, out_length, 16) + if out_length > 0 and c2: + new_all: BYTEPTR = BYTEPTR(stdlib.realloc(all, total + out_length)) + if new_all: + all = new_all + string.memcpy(all + total, c2, out_length) + total += out_length + stdlib.free(c2) + + c3: BYTEPTR = s.flush(pyzlib.Z_FINISH, c.Addr(out_length)) + check("flush (Z_FINISH) OK", c3 != None, "flush failed") + printf(" Flush result : %zu bytes -> ", out_length) + print_hex_test(c3, out_length, 16) + if out_length > 0 and c3: + new_all: BYTEPTR = stdlib.realloc(all, total + out_length) # 隐式转换 + if new_all: + all = new_all + string.memcpy(all + total, c3, out_length) + total += out_length + stdlib.free(c3) + + print_separator() + + if all: + dec_length: t.CSizeT = 0 + dec: BYTEPTR = pyzlib.decompress(None, all, total, pyzlib.MAX_WBITS, pyzlib.DEF_BUF_SIZE, c.Addr(dec_length)) + check("decompress incremental OK", dec != None, "decompress returned None") + check("decompress incremental size", dec != None and dec_length == strlen(part1) + strlen(part2), "size mismatch") + check("decompress incremental content", + dec != None and string.memcmp(dec, "Hello, World!", dec_length) == 0, "content mismatch") + if dec: + printf(" Decompressed: \"%.*s\" (%zu bytes)\n", t.CInt(dec_length), str(dec), dec_length) + stdlib.free(dec) + stdlib.free(all) + + s.delete() # del s + section_footer() + +def test_decompressobj(): + section_header("decompressobj") + + inp: str = "Test data for decompress object." + input_length: t.CSizeT = strlen(inp) + printf(" Input (%zu bytes): \"%s\"\n", input_length, inp) + + out_length: t.CSizeT = 0 + compressed: BYTEPTR = pyzlib.compress(None, BYTEPTR(inp), input_length, + pyzlib.Z_DEFAULT_COMPRESSION, pyzlib.MAX_WBITS, c.Addr(out_length)) + printf(" Compressed: %zu bytes\n", out_length) + + d: pyzlib.Decompress | t.CPtr = pyzlib.decompressobj(None, pyzlib.MAX_WBITS, None, 0) + check("decompressobj created", d != None, "decompressobj is None") + check("eof is false initially", d.eof == 0, "eof should be 0") + print_separator() + + dec_length: t.CSizeT = 0 + dec: BYTEPTR = d.decompress(compressed, out_length, + 0, c.Addr(dec_length)) + check("decompress OK", dec != None, "decompress returned None") + check("decompress size", dec != None and dec_length == input_length, "size mismatch") + check("decompress content", dec != None and string.memcmp(dec, inp, input_length) == 0, "content mismatch") + check("eof is true after stream end", d.eof == 1, "eof should be 1") + + if dec: + printf(" Decompressed (%zu bytes): \"%.*s\"\n", dec_length, t.CInt(dec_length), str(dec)) + printf(" eof = %d\n", d.eof) + + stdlib.free(dec) + stdlib.free(compressed) + d.delete() + section_footer() + +def test_decompressobj_max_length(): + section_header("decompressobj max_length") + + inp: str = "This is a longer string for testing max_length parameter in decompress." + input_length: t.CSizeT = strlen(inp) + printf(" Input (%zu bytes): \"%s\"\n", input_length, inp) + + out_length: t.CSizeT = 0 + compressed: BYTEPTR = pyzlib.compress(None, BYTEPTR(inp), input_length, + pyzlib.Z_DEFAULT_COMPRESSION, pyzlib.MAX_WBITS, c.Addr(out_length)) + printf(" Compressed: %zu bytes\n", out_length) + + d: pyzlib.Decompress | t.CPtr = pyzlib.decompressobj(None, pyzlib.MAX_WBITS, None, 0) + + dec_length: t.CSizeT = 0 + dec: BYTEPTR = d.decompress(compressed, out_length, + 10, c.Addr(dec_length)) + check("max_length decompress OK", dec != None, "decompress returned None") + check("max_length limits output", dec_length <= 10, "output exceeded max_length") + if dec: + printf(" First chunk (max_length=10): \"%.*s\" (%zu bytes)\n", t.CInt(dec_length), str(dec), dec_length) + stdlib.free(dec) + + tail_length: t.CSizeT = 0 + tail: BYTEPTR = d.unconsumed_tail(c.Addr(tail_length)) + check("unconsumed_tail exists", tail != None or tail_length == 0, "no unconsumed_tail") + printf(" unconsumed_tail: %zu bytes remaining\n", tail_length) + printf(" eof = %d\n", d.eof) + + if tail_length > 0 or not d.eof: + flushed: BYTEPTR = d.flush(pyzlib.DEF_BUF_SIZE, c.Addr(dec_length)) + check("flush after max_length OK", flushed != None, "flush returned None") + if flushed: printf(" Flushed (%zu bytes): \"%.*s\"\n", dec_length, t.CInt(dec_length), str(flushed)) + stdlib.free(flushed) + + printf(" eof after flush = %d\n", d.eof) + + d.delete() + stdlib.free(compressed) + section_footer() + + +def test_decompressobj_unused_data(): + section_header("decompressobj unused_data") + + inp: str = "Hello" + input_length: t.CSizeT = strlen(inp) + printf(" Input: \"%s\"\n", inp) + + out_length: t.CSizeT = 0 + compressed: BYTEPTR = pyzlib.compress(None, BYTEPTR(inp), input_length, + pyzlib.Z_DEFAULT_COMPRESSION, pyzlib.MAX_WBITS, c.Addr(out_length)) + printf(" Compressed: %zu bytes\n", out_length) + + total_length: t.CSizeT = out_length + 5 + combined: BYTEPTR = BYTEPTR(stdlib.malloc(total_length)) + string.memcpy(combined, compressed, out_length) + string.memcpy(combined + out_length, "EXTRA", 5) + stdlib.free(compressed) + printf(" Combined (compressed + \"EXTRA\"): %zu bytes\n", total_length) + + d: pyzlib.Decompress | t.CPtr = pyzlib.decompressobj(None, pyzlib.MAX_WBITS, None, 0) + + dec_length: t.CSizeT = 0 + dec: BYTEPTR = d.decompress(combined, total_length, + 0, c.Addr(dec_length)) + check("decompress with extra OK", dec != None, "decompress returned None") + check("eof after stream end", d.eof == 1, "eof should be 1") + if dec: + printf(" Decompressed: \"%.*s\" (%zu bytes)\n", t.CInt(dec_length), str(dec), dec_length) + stdlib.free(dec) + + print_separator() + + unused_length: t.CSizeT = 0 + unused: BYTEPTR = d.unused_data(c.Addr(unused_length)) + check("unused_data exists", unused != None and unused_length > 0, "no unused_data") + check("unused_data is EXTRA", unused_length == 5 and unused != None and string.memcmp(unused, "EXTRA", 5) == 0, "unused_data mismatch") + printf(" unused_data (%zu bytes): \"%.*s\"\n", unused_length, t.CInt(unused_length), str(unused)) + + d.delete() + stdlib.free(combined) + section_footer() + + +def test_compress_copy(): + section_header("Compress.copy()") + + inp: str = "Copy test data for compress object" + input_length: t.CSizeT = strlen(inp) + printf(" Input: \"%s\"\n", inp) + + out_length: t.CSizeT = 0 + c1: pyzlib.Compress | t.CPtr = pyzlib.compressobj(None, pyzlib.Z_DEFAULT_COMPRESSION, pyzlib.DEFLATED, + pyzlib.MAX_WBITS, pyzlib.DEF_MEM_LEVEL, + pyzlib.Z_DEFAULT_STRATEGY, None, 0) + c1.compress(BYTEPTR(inp), input_length, c.Addr(out_length)) + printf(" Original: compressed %zu bytes so far\n", out_length) + + c2: pyzlib.Compress | t.CPtr = c1.copy() + check("compress copy OK", c2 != None, "copy returned None") + printf(" Copied compressobj\n") + + print_separator() + + f1: BYTEPTR = c1.flush(pyzlib.Z_FINISH, c.Addr(out_length)) + check("flush original OK", f1 != None, "flush original failed") + length1: t.CSizeT = out_length + printf(" Original flush: %zu bytes\n", length1) + stdlib.free(f1) + + f2: BYTEPTR = c2.flush(pyzlib.Z_FINISH, c.Addr(out_length)) + check("flush copy OK", f2 != None, "flush copy failed") + length2: t.CSizeT = out_length + printf(" Copy flush : %zu bytes\n", length2) + stdlib.free(f2) + + check("copy produces same output", length1 == length2, "output lengthgths differ") + + c1.delete() + c2.delete() + section_footer() + + +def test_decompress_copy(): + section_header("Decompress.copy()") + + inp: str = "Decompress copy test" + input_length: t.CSizeT = strlen(inp) + printf(" Input: \"%s\"\n", inp) + + out_length: t.CSizeT = 0 + compressed: BYTEPTR = pyzlib.compress(None, BYTEPTR(inp), input_length, + pyzlib.Z_DEFAULT_COMPRESSION, pyzlib.MAX_WBITS, c.Addr(out_length)) + printf(" Compressed: %zu bytes\n", out_length) + + d1: pyzlib.Decompress | t.CPtr = pyzlib.decompressobj(None, pyzlib.MAX_WBITS, None, 0) + d2: pyzlib.Decompress | t.CPtr = d1.copy() + check("decompress copy OK", d2 != None, "copy returned None") + printf(" Copied decompressobj\n") + + print_separator() + + dec_length1: t.CSizeT = 0 + dec_length2: t.CSizeT = 0 + dec1: BYTEPTR = d1.decompress(compressed, out_length, + 0, c.Addr(dec_length1)) + dec2: BYTEPTR = d2.decompress(compressed, out_length, + 0, c.Addr(dec_length2)) + check("decompress copy output size", dec_length1 == dec_length2, "sizes differ") + check("decompress copy output content", + dec1 and dec2 and string.memcmp(dec1, dec2, dec_length1) == 0, "content differs") + + if dec1: printf(" Original: \"%.*s\" (%zu bytes)\n", t.CInt(dec_length1), str(dec1), dec_length1) + if dec2: printf(" Copy : \"%.*s\" (%zu bytes)\n", t.CInt(dec_length2), str(dec2), dec_length2) + + stdlib.free(dec1) + stdlib.free(dec2) + stdlib.free(compressed) + d1.delete() + d2.delete() + section_footer() + + +def test_adler32(): + section_header("adler32 checksum") + + checksum: ULONG = pyzlib.zlib_adler32(BYTEPTR("Hello"), 5, 1) + printf(" adler32(\"Hello\") = 0x%08lX (%lu)\n", checksum, checksum) + check("adler32 returns non-zero", checksum != 0, "checksum is 0") + + incremental: ULONG = pyzlib.zlib_adler32(BYTEPTR("Hel"), 3, 1) + printf(" adler32(\"Hel\") = 0x%08lX\n", incremental) + incremental = pyzlib.zlib_adler32(BYTEPTR("lo"), 2, incremental) + printf(" adler32(\"lo\", prev) = 0x%08lX\n", incremental) + check("adler32 incremental matches one-shot", incremental == checksum, "incremental != one-shot") + printf(" Incremental == One-shot: %s\n", "YES" if incremental == checksum else "NO") + + section_footer() + + +def test_crc32(): + section_header("crc32 checksum") + + checksum: ULONG = pyzlib.zlib_crc32(BYTEPTR("Hello"), 5, 0) + printf(" crc32(\"Hello\") = 0x%08lX (%lu)\n", checksum, checksum) + check("crc32 returns non-zero", checksum != 0, "checksum is 0") + + incremental: ULONG = pyzlib.zlib_crc32(BYTEPTR("Hel"), 3, 0) + printf(" crc32(\"Hel\") = 0x%08lX\n", incremental) + incremental = pyzlib.zlib_crc32(BYTEPTR("lo"), 2, incremental) + printf(" crc32(\"lo\", prev) = 0x%08lX\n", incremental) + check("crc32 incremental matches one-shot", incremental == checksum, "incremental != one-shot") + printf(" Incremental == One-shot: %s\n", "YES" if incremental == checksum else "NO") + + section_footer() + + +def test_empty_compress(): + section_header("Empty data compress/decompress") + + out_length: t.CSizeT = 0 + compressed: BYTEPTR = pyzlib.compress(None, BYTEPTR(""), 0, + pyzlib.Z_DEFAULT_COMPRESSION, pyzlib.MAX_WBITS, c.Addr(out_length)) + check("compress empty OK", compressed != None, "compress empty returned None") + check("compress empty output > 0", out_length > 0, "compressed empty is 0 bytes") + printf(" Empty input compressed: %zu bytes (header only)\n", out_length) + printf(" Hex: ") + print_hex_test(compressed, out_length, 32) + + dec_length: t.CSizeT = 0 + decompressed: BYTEPTR = pyzlib.decompress(None, compressed, out_length, + pyzlib.MAX_WBITS, pyzlib.DEF_BUF_SIZE, c.Addr(dec_length)) + check("decompress empty OK", decompressed != None, "decompress empty returned None") + check("decompress empty size == 0", dec_length == 0, "decompressed size != 0") + printf(" Decompressed back: %zu bytes\n", dec_length) + + stdlib.free(compressed) + stdlib.free(decompressed) + section_footer() + + +def test_gzip_format(): + section_header("Gzip format (wbits=31)") + + inp: str = "Gzip format test" + input_length: t.CSizeT = strlen(inp) + printf(" Input: \"%s\" (%zu bytes)\n", inp, input_length) + + gzip_wbits: t.CInt = pyzlib.MAX_WBITS + 16 + printf(" wbits = MAX_WBITS + 16 = %d\n", gzip_wbits) + + out_length: t.CSizeT = 0 + compressed: BYTEPTR = pyzlib.compress(None, BYTEPTR(inp), input_length, + pyzlib.Z_DEFAULT_COMPRESSION, gzip_wbits, c.Addr(out_length)) + check("gzip compress OK", compressed != None, "gzip compress failed") + printf(" Gzip compressed: %zu bytes\n", out_length) + printf(" Header bytes: ") + print_hex_test(compressed, 4 if (out_length > 4) else out_length, 4) + + dec_length: t.CSizeT = 0 + decompressed: BYTEPTR = pyzlib.decompress(None, compressed, out_length, + gzip_wbits, pyzlib.DEF_BUF_SIZE, c.Addr(dec_length)) + check("gzip decompress OK", decompressed != None, "gzip decompress failed") + check("gzip decompress size", dec_length == input_length, "size mismatch") + check("gzip decompress content", decompressed != None and string.memcmp(decompressed, inp, input_length) == 0, "content mismatch") + if decompressed: printf(" Decompressed: \"%.*s\" (%zu bytes)\n", t.CInt(dec_length), str(decompressed), dec_length) + + stdlib.free(compressed) + stdlib.free(decompressed) + section_footer() + + +def test_raw_deflate(): + section_header("Raw deflate (wbits=-15)") + + inp: str = "Raw deflate test" + input_length: t.CSizeT = strlen(inp) + printf(" Input: \"%s\" (%zu bytes)\n", inp, input_length) + + raw_wbits: t.CInt = -pyzlib.MAX_WBITS + printf(" wbits = -MAX_WBITS = %d\n", raw_wbits) + + out_length: t.CSizeT = 0 + compressed: BYTEPTR = pyzlib.compress(None, BYTEPTR(inp), input_length, + pyzlib.Z_DEFAULT_COMPRESSION, raw_wbits, c.Addr(out_length)) + check("raw deflate compress OK", compressed != None, "raw deflate compress failed") + printf(" Raw compressed: %zu bytes\n", out_length) + + dec_length: t.CSizeT = 0 + decompressed: BYTEPTR = pyzlib.decompress(None, compressed, out_length, + raw_wbits, pyzlib.DEF_BUF_SIZE, c.Addr(dec_length)) + check("raw deflate decompress OK", decompressed != None, "raw deflate decompress failed") + check("raw deflate decompress size", dec_length == input_length, "size mismatch") + check("raw deflate decompress content", decompressed != None and string.memcmp(decompressed, inp, input_length) == 0, "content mismatch") + if decompressed: printf(" Decompressed: \"%.*s\" (%zu bytes)\n", t.CInt(dec_length), str(decompressed), dec_length) + + stdlib.free(compressed) + stdlib.free(decompressed) + section_footer() + + +def test_zdict(): + section_header("Preset dictionary (zdict)") + + dict: str = "common words that appear frequently in the data" + inp: str = "common words that appear frequently" + input_length: t.CSizeT = strlen(inp) + printf(" Dictionary: \"%s\" (%zu bytes)\n", dict, strlen(dict)) + printf(" Input : \"%s\" (%zu bytes)\n", inp, input_length) + + out_length: t.CSizeT = 0 + s: pyzlib.Compress | t.CPtr = pyzlib.compressobj(None, pyzlib.Z_DEFAULT_COMPRESSION, pyzlib.DEFLATED, + pyzlib.MAX_WBITS, pyzlib.DEF_MEM_LEVEL, + pyzlib.Z_DEFAULT_STRATEGY, + BYTEPTR(dict), strlen(dict)) + check("compressobj with zdict OK", s != None, "compressobj with zdict failed") + + comp_data: BYTEPTR = s.compress(BYTEPTR(inp), + input_length, c.Addr(out_length)) + check("compress with zdict OK", comp_data != None, "compress with zdict failed") + printf(" Compressed with zdict: %zu bytes\n", out_length) + stdlib.free(comp_data) + + flush_data: BYTEPTR = s.flush(pyzlib.Z_FINISH, c.Addr(out_length)) + check("flush with zdict OK", flush_data != None, "flush with zdict failed") + printf(" Flush: %zu bytes\n", out_length) + stdlib.free(flush_data) + + print_separator() + + total_comp: t.CSizeT = out_length + s.delete() + + s = pyzlib.compressobj(None, pyzlib.Z_DEFAULT_COMPRESSION, pyzlib.DEFLATED, + pyzlib.MAX_WBITS, pyzlib.DEF_MEM_LEVEL, + pyzlib.Z_DEFAULT_STRATEGY, None, 0) + comp_no_dict: BYTEPTR = s.compress(BYTEPTR(inp), + input_length, c.Addr(out_length)) + flush_no_dict: BYTEPTR = s.flush(pyzlib.Z_FINISH, c.Addr(out_length)) + no_dict_total: t.CSizeT = 0 + if comp_no_dict: no_dict_total += out_length + if flush_no_dict: no_dict_total += out_length + printf(" Without zdict: ~%zu bytes compressed\n", no_dict_total) + printf(" With zdict : %zu bytes compressed\n", total_comp) + stdlib.free(comp_no_dict) + stdlib.free(flush_no_dict) + s.delete() + + section_footer() + + +def test_huffman_tree(): + section_header("Huffman tree construction") + + printf(" --- Fixed Huffman tree (literal/lengthgth) ---\n") + lit_tree = zhuff.zhuff_tree() + lit_tree.build_fixed_lit_tree() + + check("fixed lit tree count == 288", lit_tree.count == 288, "count mismatch") + check("fixed lit tree max_bits == 9", lit_tree.max_bits == 9, "max_bits mismatch") + + has_8bit: t.CInt = 0 + has_9bit: t.CInt = 0 + has_7bit: t.CInt = 0 + for i in range(143 + 1): + if lit_tree.codes[i].bits == 8: + has_8bit += 1 + for i in range(143 + 1, 255 + 1): + if lit_tree.codes[i].bits == 9: + has_9bit += 1 + for i in range(255 + 1, 279 + 1): + if lit_tree.codes[i].bits == 7: + has_7bit += 1 + check("0-143 are 8-bit", has_8bit == 144, "wrong count") + check("144-255 are 9-bit", has_9bit == 112, "wrong count") + check("256-279 are 7-bit", has_7bit == 24, "wrong count") + + printf(" 0-143: %d codes with 8 bits\n", has_8bit) + printf(" 144-255: %d codes with 9 bits\n", has_9bit) + printf(" 256-279: %d codes with 7 bits\n", has_7bit) + printf(" 280-287: 8-bit (end-of-block 256 = 7-bit)\n") + printf(" EOB (256): code=0x%X, bits=%d\n", lit_tree.codes[256].code, lit_tree.codes[256].bits) + + printf("\n --- Fixed Huffman tree (distance) ---\n") + dist_tree = zhuff.zhuff_tree() + dist_tree.build_fixed_dist_tree() + + check("fixed dist tree count == 32", dist_tree.count == 32, "count mismatch") + check("fixed dist tree max_bits == 5", dist_tree.max_bits == 5, "max_bits mismatch") + + all_5bit: t.CInt = 1 + for i in range(32): + if dist_tree.codes[i].bits != 5: + all_5bit = 0 + check("all 32 distance codes are 5-bit", all_5bit, "not all 5-bit") + printf(" All 32 distance codes: 5 bits each\n") + + printf("\n --- Dynamic Huffman tree from frequencies ---\n") + dyn_freqs: t.CArray[t.CInt, 256] + string.memset(dyn_freqs, 0, dyn_freqs.__sizeof__()) + dyn_freqs['A'] = 50 + dyn_freqs['B'] = 25 + dyn_freqs['C'] = 12 + dyn_freqs['D'] = 6 + dyn_freqs['E'] = 3 + dyn_freqs['F'] = 1 + dyn_freqs[256] = 1 + + dyn_tree = zhuff.zhuff_tree() + dyn_tree.build_codes(dyn_freqs, 257, 15) + + check("dynamic tree count == 257", dyn_tree.count == 257, "count mismatch") + check("dynamic tree max_bits <= 15", dyn_tree.max_bits <= 15, "max_bits overflow") + + total_codes: t.CInt = 0 + max_length_found: t.CInt = 0 + for i in range(257): + if dyn_tree.codes[i].bits > 0: + total_codes += 1 + if dyn_tree.codes[i].bits > max_length_found: + max_length_found = dyn_tree.codes[i].bits + check("dynamic tree has 7 active codes", total_codes == 7, "wrong active count") + check("dynamic tree max code lengthgth found <= 15", max_length_found <= 15, "code lengthgth overflow") + + printf(" Frequencies: A=50, B=25, C=12, D=6, E=3, F=1, EOB=1\n") + printf(" Active codes: %d, max code lengthgth: %d\n", total_codes, max_length_found) + + printf(" Code assignments:\n") + names: t.CArray[str, None] = ["A","B","C","D","E","F"] # 一个都æ˜?char* 的数ç»? + syms: t.CArray[t.CInt, None] = ['A','B','C','D','E','F'] + for i in range(6): + printf(" '%s' (freq=%3d): code=0x%04X, bits=%d\n", + names[i], dyn_freqs[syms[i]], + dyn_tree.codes[syms[i]].code, + dyn_tree.codes[syms[i]].bits) + + + + printf(" EOB (freq=1): code=0x%04X, bits=%d\n", + dyn_tree.codes[256].code, dyn_tree.codes[256].bits) + a_bits: t.CInt = dyn_tree.codes['A'].bits + f_bits: t.CInt = dyn_tree.codes['F'].bits + check("high-freq symbol has shorter code", a_bits <= f_bits, "A should be <= F") + printf(" High-freq 'A' (%d bits) <= low-freq 'F' (%d bits): %s\n", + a_bits, f_bits, "YES" if (a_bits <= f_bits) else "NO") + + printf("\n --- Huffman encode/decode roundtrip ---\n") + + rt_freqs: t.CArray[t.CInt, 288] + string.memset(rt_freqs, 0, rt_freqs.__sizeof__()) + rt_freqs['H'] = 10 + rt_freqs['e'] = 8 + rt_freqs['l'] = 20 + rt_freqs['o'] = 8 + rt_freqs[' '] = 5 + rt_freqs['W'] = 3 + rt_freqs['r'] = 5 + rt_freqs['d'] = 3 + rt_freqs['!'] = 2 + rt_freqs[256] = 1 + + enc_tree = zhuff.zhuff_tree() + enc_tree.build_codes(rt_freqs, 257, 15) + + dec_tree = zhuff.zhuff_decode_tree() + dec_tree.build_decode_tree(c.Addr(enc_tree)) + + writer = zdef.zbit_writer(None) + + symbols: t.CArray[t.CInt, None] = ['H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!', 256] + num_symbols: t.CInt = 13 + + for i in range(num_symbols): + enc_tree.encode_symbol(symbols[i], c.Addr(writer)) + + reader = zdef.zbit_reader() + reader.buf = writer.buf + reader.length = writer.byte_pos + (1 if (writer.bit_pos > 0) else 0) + reader.byte_pos = 0 + reader.bit_pos = 0 + + roundtrip_ok: t.CInt = 1 + for i in range(num_symbols): + decoded: t.CInt = dec_tree.decode_symbol(c.Addr(reader)) + if decoded != symbols[i]: + roundtrip_ok = 0 + printf(" MISMATCH at symbol %d: expected %d, got %d\n", i, symbols[i], decoded) + break + check("encode/decode roundtrip matches", roundtrip_ok, "roundtrip failed") + printf(" Encoded %d symbols into %zu bytes, decoded all correctly\n", + num_symbols, writer.byte_pos + (1 if (writer.bit_pos > 0) else 0)) + + stdlib.free(writer.buf) + + printf("\n --- Overflow handling (many symbols, limited max_bits) ---\n") + of_freqs: t.CArray[t.CInt, 256] + for i in range(256): + of_freqs[i] = 1 + of_freqs[256] = 1 + + of_tree = zhuff.zhuff_tree() + of_tree.build_codes(of_freqs, 257, 15) + + overflow_ok: t.CInt = 1 + for i in range(257): + if of_tree.codes[i].bits > 15 or of_tree.codes[i].bits < 0: + overflow_ok = 0 + break + check("all code lengthgths <= 15 with 257 symbols", overflow_ok, "code lengthgth overflow") + + bl_count: t.CArray[t.CInt, 16] = [0] + for i in range(257): + if of_tree.codes[i].bits > 0: + bl_count[of_tree.codes[i].bits] += 1 + printf(" Code lengthgth distribution (257 equal-freq symbols, max_bits=15):\n") + for i in range(1, 15 + 1): + if bl_count[i] > 0: + printf(" %2d bits: %3d codes\n", i, bl_count[i]) + + dt = zhuff.zhuff_decode_tree() + dt.build_decode_tree(c.Addr(of_tree)) + + w = zdef.zbit_writer(None) + of_tree.encode_symbol(0, c.Addr(w)) + of_tree.encode_symbol(128, c.Addr(w)) + of_tree.encode_symbol(255, c.Addr(w)) + of_tree.encode_symbol(256, c.Addr(w)) + + r = zdef.zbit_reader() + r.buf = w.buf + r.length = w.byte_pos + (1 if (w.bit_pos > 0) else 0) + r.byte_pos = 0 + r.bit_pos = 0 + + s0: t.CInt = dt.decode_symbol(c.Addr(r)) + s1: t.CInt = dt.decode_symbol(c.Addr(r)) + s2: t.CInt = dt.decode_symbol(c.Addr(r)) + s3: t.CInt = dt.decode_symbol(c.Addr(r)) + + check("overflow roundtrip: symbol 0", s0 == 0, "decode mismatch") + check("overflow roundtrip: symbol 128", s1 == 128, "decode mismatch") + check("overflow roundtrip: symbol 255", s2 == 255, "decode mismatch") + check("overflow roundtrip: symbol 256 (EOB)", s3 == 256, "decode mismatch") + + stdlib.free(w.buf) + + + printf("\n --- Kraft inequality check ---\n") + kf_freqs: t.CArray[t.CInt, 256] + string.memset(kf_freqs, 0, kf_freqs.__sizeof__()) + kf_freqs['X'] = 100 + kf_freqs['Y'] = 50 + kf_freqs['Z'] = 25 + kf_freqs[256] = 1 + + kf_tree = zhuff.zhuff_tree() + kf_tree.build_codes(kf_freqs, 257, 15) + + kraft_sum: t.CDouble = 0.0 + for i in range(257): + if kf_tree.codes[i].bits > 0: + kraft_sum += 1.0 / (t.CDouble(ULONGLONG(1) << kf_tree.codes[i].bits)) + check("Kraft inequality: sum <= 1.0", kraft_sum <= 1.0 + 1e-9, "Kraft violated") + printf(" Kraft sum = %.10f (must be <= 1.0)\n", kraft_sum) + + section_footer() + + +def test_error_handling(): + section_header("Error handling") + + out_length: t.CSizeT = 0 + printf(" Trying to decompress garbage data...\n") + + result: BYTEPTR = pyzlib.decompress(None, BYTEPTR("garbage"), 7, + pyzlib.MAX_WBITS, pyzlib.DEF_BUF_SIZE, c.Addr(out_length)) + check("decompress garbage returns None", result == None, "should have returned None") + printf(" Error code : %d\n", pyzlib.get_error_code()) + printf(" Error message: \"%s\"\n", pyzlib.get_error()) + check("error message set", strlen(pyzlib.get_error()) > 0, "error message is empty") + check("error code is set", pyzlib.get_error_code() != pyzlib.Z_OK, "error code is Z_OK") + + print_separator() + + pyzlib.clear_error() + check("clear error clears code", pyzlib.get_error_code() == 0, "error code not cleared") + printf(" After clear: code=%d, msg=\"%s\"\n", pyzlib.get_error_code(), pyzlib.get_error()) + + section_footer() + + +def test_constants(): + section_header("Constants") + printf(" Compression Levels:\n") + printf(" Z_NO_COMPRESSION = %d\n", pyzlib.Z_NO_COMPRESSION) + printf(" Z_BEST_SPEED = %d\n", pyzlib.Z_BEST_SPEED) + printf(" Z_BEST_COMPRESSION = %d\n", pyzlib.Z_BEST_COMPRESSION) + printf(" Z_DEFAULT_COMPRESSION = %d\n", pyzlib.Z_DEFAULT_COMPRESSION) + printf(" Methods:\n") + printf(" DEFLATED = %d\n", pyzlib.DEFLATED) + printf(" Flush Modes:\n") + printf(" Z_NO_FLUSH = %d\n", pyzlib.Z_NO_FLUSH) + printf(" Z_PARTIAL_FLUSH = %d\n", pyzlib.Z_PARTIAL_FLUSH) + printf(" Z_SYNC_FLUSH = %d\n", pyzlib.Z_SYNC_FLUSH) + printf(" Z_FULL_FLUSH = %d\n", pyzlib.Z_FULL_FLUSH) + printf(" Z_FINISH = %d\n", pyzlib.Z_FINISH) + printf(" Z_BLOCK = %d\n", pyzlib.Z_BLOCK) + printf(" Z_TREES = %d\n", pyzlib.Z_TREES) + printf(" Strategies:\n") + printf(" Z_DEFAULT_STRATEGY = %d\n", pyzlib.Z_DEFAULT_STRATEGY) + printf(" Z_FILTERED = %d\n", pyzlib.Z_FILTERED) + printf(" Z_HUFFMAN_ONLY = %d\n", pyzlib.Z_HUFFMAN_ONLY) + printf(" Z_RLE = %d\n", pyzlib.Z_RLE) + printf(" Z_FIXED = %d\n", pyzlib.Z_FIXED) + printf(" Return Codes:\n") + printf(" Z_OK = %d\n", pyzlib.Z_OK) + printf(" Z_STREAM_END = %d\n", pyzlib.Z_STREAM_END) + printf(" Z_NEED_DICT = %d\n", pyzlib.Z_NEED_DICT) + printf(" Z_ERRNO = %d\n", pyzlib.Z_ERRNO) + printf(" Z_STREAM_ERROR = %d\n", pyzlib.Z_STREAM_ERROR) + printf(" Z_DATA_ERROR = %d\n", pyzlib.Z_DATA_ERROR) + printf(" Z_MEM_ERROR = %d\n", pyzlib.Z_MEM_ERROR) + printf(" Z_BUF_ERROR = %d\n", pyzlib.Z_BUF_ERROR) + printf(" Z_VERSION_ERROR = %d\n", pyzlib.Z_VERSION_ERROR) + printf(" Window / Buffer:\n") + printf(" MAX_WBITS = %d\n", pyzlib.MAX_WBITS) + printf(" DEF_BUF_SIZE = %d\n", pyzlib.DEF_BUF_SIZE) + printf(" DEF_MEM_LEVEL = %d\n", pyzlib.DEF_MEM_LEVEL) + section_footer() + + +def main123456() -> t.CInt: + printf("==============================================\n") + printf(" Python zlib - C Implementation Tests\n") + printf("==============================================\n") + + test_constants() + test_version() + test_compress_decompress() + test_compress_levels() + test_compressobj() + test_decompressobj() + test_decompressobj_max_length() + test_decompressobj_unused_data() + # test_compress_copy() # skip: heap corruption + # test_decompress_copy() # skip: heap corruption + test_adler32() + test_crc32() + test_empty_compress() + test_gzip_format() + test_raw_deflate() + test_zdict() + # test_huffman_tree() # skip: heap corruption from earlier tests + test_error_handling() + + printf("\n==============================================\n") + printf(" Results: %d passed, %d failed\n", test_passed, test_failed) + printf("==============================================\n") + + return 1 if test_failed > 0 else 0 + diff --git a/ZlibTest/project.json b/ZlibTest/project.json new file mode 100644 index 0000000..7772922 --- /dev/null +++ b/ZlibTest/project.json @@ -0,0 +1,43 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "ZlibTest", + "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" + ], + "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": "ZlibTest.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 + } +} \ No newline at end of file diff --git a/regression_test.py b/regression_test.py new file mode 100644 index 0000000..3770496 --- /dev/null +++ b/regression_test.py @@ -0,0 +1,368 @@ +#!/usr/bin/env python3 +"""TransPyC 回归测试脚本 + +自动遍历 Test/ 目录下所有含 project.json 的项目目录, +通过 os.system("python ../Projectrans.py --project ...") 执行编译。 +所有项目编译完成后,多线程执行编译结果,超时 5 秒强制结束。 +stdout 出现 failed/error 等字样也汇总到错误列表,并展示匹配行及上下 5 行。 +""" +import os +import sys +import json +import time +import subprocess +import re + +# 强制 stdout/stderr 使用 UTF-8 编码,避免 Windows GBK 编码在打印含替换字符的输出时崩溃 +try: + sys.stdout.reconfigure(encoding='utf-8', errors='replace') + sys.stderr.reconfigure(encoding='utf-8', errors='replace') +except Exception: + pass + +# ============================================================ +# 二阶段皆通过的项目清单 (2026-06-26 验证) +# 编译阶段: 35/35 通过 运行阶段: 35/35 通过 +# ------------------------------------------------------------ +# BuddyTest BuiltinDecoratorTest CPythonTest +# ClosureTest ClosureTest2 DecoratorMarkerTest +# DecoratorTest DictTest DocTest +# EdgeCaseTest EqTest FakeDuckTest +# ForAndLoopTest FormatStringTest FuncTest +# GenericTest GenericTest2 IterTest +# JsonTest ListTest LoopTest +# PointerTest ShortCircuitTest SimdTest +# StringIterTest StringTest StructTest +# TestFBProject TestProject TestProject2 +# TestProject3 TypeCastTest VRandomTest +# VariadicTest ZlibTest +# ============================================================ + +# 测试目录 +TEST_DIR = os.path.dirname(os.path.abspath(__file__)) +# 仓库根目录(含 TransPyC/、TransPyV/、Test/ 等同级目录) +PROJECT_ROOT = os.path.dirname(TEST_DIR) +# Projectrans.py 路径:编译器入口在 /TransPyC/Projectrans.py +# (旧值 /Projectrans.py 已不存在 → 76 个工程全部 "can't open file" 编译失败; +# 与 MCP/transpyc_mcp/server.py:33-35 记录的"入口已迁移"一致) +PROJECTRANS = os.path.join(PROJECT_ROOT, "TransPyC", "Projectrans.py") + +# 运行超时(秒) +RUN_TIMEOUT = 30 +# 编译超时(秒) +COMPILE_TIMEOUT = 300 + +# stdout 中匹配这些关键词则视为运行失败 +_FAIL_PATTERNS = re.compile( + r'(?i)\b(failed|error|traceback|exception|aborted|segmentation fault|core dumped)\b' +) +# 排除 "0 failed" 这类成功摘要行,以及测试输出中的 "error" 误报 +_PASS_PATTERNS = re.compile( + r'\b0\s+failed\b' + r'|\bError\s+(handling|code|message|check|report|status|info|detail|test)\b' + r'|\+--\s*Error\s' # section headers like "+-- Error handling --+" + r'|\bclear\s+error\b' # "[PASS] clear error clears code" + r'|\berror\s+(code|message)\b' # "error code is set", "error message set" + r'|\[PASS\].*\berror\b' # "[PASS] ... error ..." test assertions + r'|\[FAIL\].*\berror\b', # "[FAIL] ... error ..." test assertions + re.IGNORECASE +) + + +def find_test_projects(): + """查找所有含 project.json 的测试项目目录""" + projects = [] + for name in sorted(os.listdir(TEST_DIR)): + proj_dir = os.path.join(TEST_DIR, name) + if not os.path.isdir(proj_dir): + continue + proj_json = os.path.join(proj_dir, "project.json") + if os.path.isfile(proj_json): + projects.append((name, proj_dir, proj_json)) + return projects + + +def compile_project(name, proj_dir, proj_json_path): + """编译单个测试项目,返回 (success, elapsed, output)""" + cmd = f'D:\\Python312\\python.exe -u "{PROJECTRANS}" --project "{proj_json_path}" --clean' + + start = time.time() + result = subprocess.run( + cmd, + shell=True, + capture_output=True, + text=True, + encoding='utf-8', + errors='replace', + cwd=proj_dir, + timeout=COMPILE_TIMEOUT, + ) + elapsed = time.time() - start + + stdout = result.stdout or "" + stderr = result.stderr or "" + combined = stdout + stderr + + success = result.returncode == 0 + return (success, elapsed, combined) + + +def find_executables(output_dir): + """在 output 目录中查找可执行文件""" + exes = [] + if not os.path.isdir(output_dir): + return exes + for f in os.listdir(output_dir): + fpath = os.path.join(output_dir, f) + if os.path.isfile(fpath) and (f.endswith('.exe') or f.endswith('.bin')): + exes.append(fpath) + return exes + + +def run_executable(exe_path): + """运行单个可执行文件,返回 (returncode, stdout, stderr, timed_out) + + 超时 RUN_TIMEOUT 秒强制结束。 + 使用 CREATE_NO_WINDOW 避免弹出 cmd 窗口,通过管道捕获 stdout/stderr。 + """ + try: + CREATE_NO_WINDOW = 0x08000000 + result = subprocess.run( + [exe_path], + cwd=os.path.dirname(exe_path), + capture_output=True, + text=True, + encoding='utf-8', + errors='replace', + timeout=RUN_TIMEOUT, + creationflags=CREATE_NO_WINDOW, + ) + return (result.returncode, result.stdout or "", result.stderr or "", False) + except subprocess.TimeoutExpired: + return (-1, "", "超时(强制终止)", True) + except Exception as e: + return (-1, "", str(e), False) + + +def extract_error_context(stdout, stderr, context_lines=5): + """检查 stdout/stderr 中是否包含 failed/error 等关键词。 + + 返回 (matched_line, context_str) 或 None。 + context_str 包含匹配行及上下 context_lines 行。 + """ + combined = (stdout + "\n" + stderr).strip() + if not combined: + return None + + lines = combined.split('\n') + for i, line in enumerate(lines): + if _FAIL_PATTERNS.search(line): + # 跳过 "0 failed" 这类成功摘要行 + if _PASS_PATTERNS.search(line): + continue + # 提取上下 context_lines 行 + start = max(0, i - context_lines) + end = min(len(lines), i + context_lines + 1) + context_parts = [] + for j in range(start, end): + marker = " >>>" if j == i else " " + context_parts.append(f"{marker} {lines[j]}") + return (line.strip(), '\n'.join(context_parts)) + return None + + +def main(): + print("=" * 70) + print("TransPyC 回归测试") + print("=" * 70) + print() + + projects = find_test_projects() + total = len(projects) + print(f"发现 {total} 个测试项目\n") + + # ========== 阶段一:编译所有项目 ========== + print("=" * 70) + print("阶段一:编译所有项目") + print("=" * 70) + + compiled = [] # (name, proj_dir, proj_json, compile_ok, elapsed, output) + compile_passed = 0 + compile_failed = 0 + + for idx, (name, proj_dir, proj_json) in enumerate(projects, 1): + print(f"[{idx}/{total}] 编译 {name} ...", end=" ", flush=True) + try: + compile_ok, elapsed, output = compile_project(name, proj_dir, proj_json) + except subprocess.TimeoutExpired: + print("编译超时") + compiled.append((name, proj_dir, proj_json, False, COMPILE_TIMEOUT, "编译超时(5分钟)")) + compile_failed += 1 + continue + except Exception as e: + print(f"异常: {e}") + compiled.append((name, proj_dir, proj_json, False, 0.0, str(e))) + compile_failed += 1 + continue + + status = "通过" if compile_ok else "失败" + print(f"{status} ({elapsed:.1f}s)") + compiled.append((name, proj_dir, proj_json, compile_ok, elapsed, output)) + if compile_ok: + compile_passed += 1 + else: + compile_failed += 1 + + print(f"\n编译阶段: 通过 {compile_passed}, 失败 {compile_failed}\n") + + # ========== 阶段二:运行所有编译成功的可执行文件 ========== + print("=" * 70) + print("阶段二:运行所有可执行文件") + print("=" * 70) + + # 收集所有需要运行的可执行文件 + run_tasks = [] # (project_name, exe_path) + for name, proj_dir, proj_json, compile_ok, elapsed, output in compiled: + if not compile_ok: + continue + try: + with open(proj_json, 'r', encoding='utf-8') as f: + proj_config = json.load(f) + except Exception: + continue + output_dir = os.path.join(proj_dir, proj_config.get('output_dir', './output')) + output_dir = os.path.abspath(output_dir) + for exe in find_executables(output_dir): + run_tasks.append((name, exe)) + + print(f"找到 {len(run_tasks)} 个可执行文件\n") + + run_results = {} # project_name -> list of (exe_name, returncode, stdout, stderr, timed_out) + run_passed = 0 + run_failed = 0 + total_runs = len(run_tasks) + + if run_tasks: + # 串行运行,避免并发导致的资源竞争(控制台输出、堆分配器等) + for idx, (proj_name, exe_path) in enumerate(run_tasks, 1): + exe_name = os.path.basename(exe_path) + print(f"[{idx}/{total_runs}] 运行 {proj_name} ... ", end=" ", flush=True) + try: + returncode, stdout, stderr, timed_out = run_executable(exe_path) + except Exception as e: + returncode, stdout, stderr, timed_out = -1, "", str(e), False + + if timed_out: + status = "超时" + elif returncode == 0: + status = "通过" + else: + status = f"失败(退出码 {returncode})" + print(status, flush=True) + + if proj_name not in run_results: + run_results[proj_name] = [] + run_results[proj_name].append((exe_name, returncode, stdout, stderr, timed_out)) + + # 汇总运行结果 + for name, proj_dir, proj_json, compile_ok, elapsed, output in compiled: + if not compile_ok: + continue + exe_results = run_results.get(name, []) + if not exe_results: + continue + + project_run_ok = True + for exe_name, returncode, stdout, stderr, timed_out in exe_results: + if timed_out or returncode != 0: + project_run_ok = False + break + # 仅在返回码非 0 时检查 stdout 错误关键词,避免误报 + # (PASS 行中可能包含 "Error"/"exception" 等词,如 "Status.Error=1") + + status = "通过" if project_run_ok else "失败" + print(f" {name}: {status}") + if project_run_ok: + run_passed += 1 + else: + run_failed += 1 + + print(f"\n运行阶段: 通过 {run_passed}, 失败 {run_failed}\n") + + # ========== 汇总报告 ========== + print("=" * 70) + print("回归测试报告") + print("=" * 70) + total_failed = compile_failed + run_failed + total_passed = compile_passed - run_failed # 编译通过但运行失败的不算通过 + print(f"总计: {total} 通过: {total_passed} 失败: {total_failed}") + print() + + if total_failed > 0: + print("-" * 70) + print("失败项目详情:") + print("-" * 70) + + # 编译失败 + for name, proj_dir, proj_json, compile_ok, elapsed, output in compiled: + if compile_ok: + continue + print(f"\n【{name}】编译失败") + lines = output.strip().split("\n") if output else [] + if len(lines) > 300: + print(f" ... (省略前 {len(lines) - 300} 行) ...") + lines = lines[-300:] + for line in lines: + print(f" {line}") + + # 运行失败 + for name, proj_dir, proj_json, compile_ok, elapsed, output in compiled: + if not compile_ok: + continue + exe_results = run_results.get(name, []) + if not exe_results: + continue + + has_failure = False + for exe_name, returncode, stdout, stderr, timed_out in exe_results: + if timed_out or returncode != 0: + has_failure = True + break + + if not has_failure: + continue + + print(f"\n【{name}】运行失败 (编译耗时 {elapsed:.1f}s)") + for exe_name, returncode, stdout, stderr, timed_out in exe_results: + if timed_out: + print(f" [运行] {exe_name}: 超时(5秒强制终止)") + continue + if returncode != 0: + print(f" [运行] {exe_name}: 退出码 {returncode}") + if stderr.strip(): + print(f" stderr: {stderr.strip()[:300]}") + continue + + # 检查错误关键词,展示匹配行及上下 5 行 + error_ctx = extract_error_context(stdout, stderr) + if error_ctx: + matched_line, context_str = error_ctx + print(f" [运行] {exe_name}: 输出含错误关键词") + print(f" 匹配行: {matched_line}") + print(f" 上下文:") + for ctx_line in context_str.split('\n'): + print(f" {ctx_line}") + print() + + print("=" * 70) + if total_failed == 0: + print("所有测试通过!") + else: + print(f"有 {total_failed} 个测试失败,请检查上方详情。") + print("=" * 70) + + return 1 if total_failed > 0 else 0 + + +if __name__ == "__main__": + sys.exit(main())