From e02c867edf6adf584fdb0a348f37bb1112b8e944 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Thu, 18 Jun 2026 00:39:43 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8F=AF=E7=94=A8=E7=9A=84=E5=9B=9E=E5=BD=92?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E9=80=9A=E8=BF=87=E7=9A=84=E6=A0=87=E5=87=86?= =?UTF-8?q?=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 1.html | 283 ++ 2.html | 246 ++ CPython/c.py | 690 --- CPython/t.py | 1283 ------ Projectrans.py | 3746 +---------------- StubGen.py | 1349 +----- TODO | 2 +- Test/BuiltinDecoratorTest/App/main.py | 67 +- .../output/b6069b01d8c9cc04.deps.json | 1 + .../temp/6c2029b306556c00.pyi | 18 + Test/BuiltinDecoratorTest/temp/_sha1_map.txt | 3 +- ...b7ce7c134ada7.pyi => b6069b01d8c9cc04.pyi} | 9 +- Test/CPythonTest/App/cpython.py | 776 +++- Test/CPythonTest/App/main.py | 378 +- .../output/0cd580d62a3de4f8.deps.json | 1 + .../output/3e1c3f98e99cff7a.deps.json | 1 - .../output/4d342c40331fc964.deps.json | 1 - .../output/6999814920e8b3d5.deps.json | 1 - .../output/7c5d5ec59c5fb0a8.deps.json | 1 + Test/CPythonTest/output/CPythonTest.exe.tmp0 | Bin 128784 -> 0 bytes .../output/c9f4be41ca1cc2b4.deps.json | 1 - Test/CPythonTest/project.json | 12 +- Test/CPythonTest/temp/0cd580d62a3de4f8.pyi | 33 + Test/CPythonTest/temp/3e1c3f98e99cff7a.pyi | 23 - Test/CPythonTest/temp/6999814920e8b3d5.pyi | 14 - Test/CPythonTest/temp/73edbcf76e32d00b.pyi | 28 + Test/CPythonTest/temp/7c5d5ec59c5fb0a8.pyi | 765 ++++ Test/CPythonTest/temp/81ac26077a460417.pyi | 20 - Test/CPythonTest/temp/93131e2ff5450838.pyi | 14 - Test/CPythonTest/temp/_sha1_map.txt | 9 +- Test/CPythonTest/temp/_shared_sym.pkl | Bin 86336 -> 314675 bytes Test/CPythonTest/temp/c9f4be41ca1cc2b4.pyi | 22 - Test/CPythonTest/temp/d771d4d68d9e75b3.pyi | 17 - .../output/067c78e9f121dce3.deps.json | 2 +- .../output/29813d57621099a9.deps.json | 2 +- .../output/5a6a2137958c28c5.deps.json | 2 +- .../output/6aee24fdefa3cbc0.deps.json | 1 + .../output/72e2d5ccb7cedcf1.deps.json | 2 +- .../output/73a525067569932e.deps.json | 1 - .../output/abf9ce3160c9279e.deps.json | 2 +- .../output/bbdf3bbd4c3bc28c.deps.json | 2 +- .../output/d044f813487c68b6.deps.json | 2 +- .../output/fa3691e66b426950.deps.json | 2 +- .../temp/6aee24fdefa3cbc0.pyi} | 4 + Test/IterTest/temp/_sha1_map.txt | 2 +- .../output/68c4fe4b12c908e3.deps.json | 2 +- .../output/8ee3170049c70333.deps.json | 2 +- .../output/bd2e7db1744476fe.deps.json | 2 +- .../output/eaf7a981f0ef5b22.deps.json | 2 +- .../output/067c78e9f121dce3.deps.json | 2 +- .../output/29813d57621099a9.deps.json | 2 +- .../output/5a6a2137958c28c5.deps.json | 2 +- ...f.deps.json => 6aee24fdefa3cbc0.deps.json} | 2 +- .../output/72e2d5ccb7cedcf1.deps.json | 2 +- Test/PointerTest/output/PointerTest.exe.tmp0 | Bin 144821 -> 0 bytes .../output/abf9ce3160c9279e.deps.json | 2 +- .../output/bbdf3bbd4c3bc28c.deps.json | 2 +- .../output/e0c894447ac34ed3.deps.json | 2 +- .../output/fa3691e66b426950.deps.json | 2 +- .../temp/6aee24fdefa3cbc0.pyi} | 4 + Test/PointerTest/temp/_sha1_map.txt | 2 +- Test/ReTest/output/68c4fe4b12c908e3.deps.json | 1 + Test/ReTest/output/6aee24fdefa3cbc0.deps.json | 1 + Test/ReTest/output/839e950555b6a435.deps.json | 1 + Test/ReTest/output/9ef80c98cfbbce42.deps.json | 1 + Test/ReTest/output/c9f4be41ca1cc2b4.deps.json | 1 + .../temp/56cdd754a8a09347.pyi | 0 .../temp/68c4fe4b12c908e3.pyi} | 22 +- .../temp/6aee24fdefa3cbc0.pyi} | 4 + Test/ReTest/temp/73edbcf76e32d00b.pyi | 28 + .../temp/7538e542cab4c1d5.pyi | 0 Test/ReTest/temp/839e950555b6a435.pyi | 103 + Test/ReTest/temp/9ef80c98cfbbce42.pyi | 58 + Test/ReTest/temp/_sha1_map.txt | 8 + Test/ReTest/temp/c9f4be41ca1cc2b4.pyi | 22 + .../output/024a3459d0f585ae.deps.json | 1 - .../output/1b666d438f4d301e.deps.json | 2 +- .../output/3f7c5e78d8652535.deps.json | 2 +- .../output/68c4fe4b12c908e3.deps.json | 2 +- .../output/6aee24fdefa3cbc0.deps.json | 1 + .../output/c3eb91093118e1e1.deps.json | 2 +- .../output/c9f4be41ca1cc2b4.deps.json | 2 +- .../output/fe99c83946298690.deps.json | 2 +- ...a3459d0f585ae.pyi => 6aee24fdefa3cbc0.pyi} | 4 + Test/SimdTest/temp/6c2029b306556c00.pyi | 18 + Test/SimdTest/temp/_sha1_map.txt | 4 +- .../output/2255fdda7aed5595.deps.json | 2 +- .../output/4d5db7f970ef510f.deps.json | 1 - .../output/6aee24fdefa3cbc0.deps.json | 1 + Test/StringIterTest/temp/6aee24fdefa3cbc0.pyi | 44 + Test/StringIterTest/temp/_sha1_map.txt | 2 +- .../output/067c78e9f121dce3.deps.json | 2 +- .../output/29813d57621099a9.deps.json | 2 +- .../output/5a6a2137958c28c5.deps.json | 2 +- ...f.deps.json => 6aee24fdefa3cbc0.deps.json} | 2 +- .../output/72e2d5ccb7cedcf1.deps.json | 2 +- .../output/7aa13c104a22528a.deps.json | 2 +- .../output/abf9ce3160c9279e.deps.json | 2 +- .../output/bbdf3bbd4c3bc28c.deps.json | 2 +- .../output/fa3691e66b426950.deps.json | 2 +- Test/StringTest/temp/4d5db7f970ef510f.pyi | 40 - Test/StringTest/temp/6aee24fdefa3cbc0.pyi | 44 + Test/StringTest/temp/_sha1_map.txt | 2 +- .../output/067c78e9f121dce3.deps.json | 2 +- .../output/29813d57621099a9.deps.json | 2 +- .../output/5a6a2137958c28c5.deps.json | 2 +- .../output/6aee24fdefa3cbc0.deps.json | 1 + .../output/6f6ee14c129ac228.deps.json | 2 +- .../output/72e2d5ccb7cedcf1.deps.json | 2 +- .../output/a326a52b7c4bd6f0.deps.json | 1 - .../output/abf9ce3160c9279e.deps.json | 2 +- .../output/bbdf3bbd4c3bc28c.deps.json | 2 +- .../output/fa3691e66b426950.deps.json | 2 +- Test/StructTest/temp/6aee24fdefa3cbc0.pyi | 44 + Test/StructTest/temp/_sha1_map.txt | 2 +- Test/StructTest/temp/a326a52b7c4bd6f0.pyi | 40 - Test/TestFBProject/App/main.py | 316 +- .../output/067c78e9f121dce3.deps.json | 2 +- .../output/29813d57621099a9.deps.json | 2 +- .../output/5a6a2137958c28c5.deps.json | 2 +- .../output/72e2d5ccb7cedcf1.deps.json | 2 +- .../output/abf9ce3160c9279e.deps.json | 2 +- .../output/bbdf3bbd4c3bc28c.deps.json | 2 +- .../output/fa3691e66b426950.deps.json | 2 +- Test/TestFBProject/project.json | 3 - Test/TestFBProject/temp/067c78e9f121dce3.pyi | 136 + Test/TestFBProject/temp/214790a9a42a868c.pyi | 33 - Test/TestFBProject/temp/29813d57621099a9.pyi | 85 + Test/TestFBProject/temp/3727eb00d15bf59d.pyi | 8 +- Test/TestFBProject/temp/5a6a2137958c28c5.pyi | 4 +- Test/TestFBProject/temp/72e2d5ccb7cedcf1.pyi | 91 + Test/TestFBProject/temp/abf9ce3160c9279e.pyi | 179 + Test/TestFBProject/temp/ac0664ce209738d9.pyi | 138 - Test/TestFBProject/temp/fa3691e66b426950.pyi | 80 + Test/TestProject/App/__zlib/__init__.py | 0 Test/TestProject/App/__zlib/pyzlib.py | 550 --- Test/TestProject/App/__zlib/test_basic.c | 81 - Test/TestProject/App/__zlib/test_debug.c | 78 - Test/TestProject/App/__zlib/test_pyzlib.py | 880 ---- Test/TestProject/App/__zlib/zchecksum.py | 90 - Test/TestProject/App/__zlib/zdef.py | 269 -- Test/TestProject/App/__zlib/zdeflate.py | 431 -- Test/TestProject/App/__zlib/zhuff.py | 353 -- Test/TestProject/App/__zlib/zinflate.py | 454 -- Test/TestProject/App/test_zlib.py | 4 +- .../output/067c78e9f121dce3.deps.json | 2 +- ...f.deps.json => 0c04ab530bb9cfa4.deps.json} | 2 +- .../output/0d13cde396f4a15f.deps.json | 2 +- .../output/0d4517fd5afeb330.deps.json | 2 +- .../output/29813d57621099a9.deps.json | 2 +- .../output/2d7f623c6e3004ce.deps.json | 2 +- .../output/2e756dd336749fc2.deps.json | 2 +- .../output/3d1656b26b38b359.deps.json | 1 - .../output/3ee89b588a1da94f.deps.json | 2 +- .../output/3f7c5e78d8652535.deps.json | 2 +- .../output/4638d411fd53fef0.deps.json | 2 +- .../output/4bf3e0150b9e02e9.deps.json | 1 + .../output/58121a0fb0ca7466.deps.json | 2 +- .../output/5a6a2137958c28c5.deps.json | 2 +- .../output/68c4fe4b12c908e3.deps.json | 2 +- .../output/6aee24fdefa3cbc0.deps.json | 2 +- .../output/72e2d5ccb7cedcf1.deps.json | 2 +- .../output/7e4cef8dd61984f0.deps.json | 1 - .../output/88e3e48eab9e1653.deps.json | 2 +- .../output/8e0d8fdba991b3b4.deps.json | 2 +- .../output/8f88a3374d5335cc.deps.json | 1 + .../output/94496ec50b0d13fc.deps.json | 2 +- .../output/a9fa0f6200c09e65.deps.json | 2 +- .../output/abf9ce3160c9279e.deps.json | 2 +- .../output/b0267503e816efc4.deps.json | 2 +- .../output/ba2e1c2dfc8e2f85.deps.json | 2 +- .../output/bbdf3bbd4c3bc28c.deps.json | 2 +- .../output/c3eb91093118e1e1.deps.json | 2 +- .../output/c9f4be41ca1cc2b4.deps.json | 2 +- .../output/d282a7cb3385ecf0.deps.json | 2 +- .../output/f9629b8eb4ebdcc2.deps.json | 2 +- .../output/fa3691e66b426950.deps.json | 2 +- ...f5b503003443f.pyi => 0c04ab530bb9cfa4.pyi} | 4 +- ...cef8dd61984f0.pyi => 4bf3e0150b9e02e9.pyi} | 1 - Test/TestProject/temp/6c2029b306556c00.pyi | 18 + Test/TestProject/temp/7538e542cab4c1d5.pyi | 18 - ...656b26b38b359.pyi => 8f88a3374d5335cc.pyi} | 1 - Test/TestProject/temp/_sha1_map.txt | 8 +- Test/TestProject/temp/_shared_sym.pkl | Bin 746124 -> 730114 bytes Test/TestProject2/project.json | 4 + Test/TestProject2/temp/09ba6d4617920d26.pyi | 2 +- Test/TestProject2/temp/73edbcf76e32d00b.pyi | 16 +- Test/TestProject2/temp/75583f20a922ab2e.pyi | 30 +- Test/TestProject2/temp/_shared_sym.pkl | Bin 186872 -> 189933 bytes Test/TestProject2/temp/a7dab00d979c009c.pyi | 46 +- Test/TestProject2/temp/faec3233d98371da.pyi | 46 +- .../output/067c78e9f121dce3.deps.json | 2 +- .../output/087c910044fab2d2.deps.json | 1 - .../output/0f4d14c17bf75b10.deps.json | 2 +- .../output/1b58766d38d05de3.deps.json | 2 +- .../output/21ffad37f6fc3fcf.deps.json | 1 - .../output/2953a7db4185005b.deps.json | 1 + .../output/29813d57621099a9.deps.json | 2 +- .../output/3fdd11bdd589aa8c.deps.json | 2 +- .../output/4d342c40331fc964.deps.json | 1 - .../output/5325ec533a59d71b.deps.json | 2 +- .../output/5a6a2137958c28c5.deps.json | 2 +- .../output/64ac83614c9bdbc6.deps.json | 2 +- .../output/68c4fe4b12c908e3.deps.json | 1 + .../output/6aee24fdefa3cbc0.deps.json | 1 + .../output/72e2d5ccb7cedcf1.deps.json | 2 +- .../output/a326a52b7c4bd6f0.deps.json | 1 - .../output/abf9ce3160c9279e.deps.json | 2 +- .../output/bbdf3bbd4c3bc28c.deps.json | 2 +- .../output/c01b27dbcd683245.deps.json | 1 + .../output/c9f4be41ca1cc2b4.deps.json | 2 +- .../output/fa3691e66b426950.deps.json | 2 +- .../output/fc49f6314bad25e9.deps.json | 2 +- Test/TestProject3/temp/067c78e9f121dce3.pyi | 136 + Test/TestProject3/temp/0f4d14c17bf75b10.pyi | 32 +- .../temp/2953a7db4185005b.pyi} | 0 Test/TestProject3/temp/29813d57621099a9.pyi | 85 + Test/TestProject3/temp/3fdd11bdd589aa8c.pyi | 12 +- Test/TestProject3/temp/4d342c40331fc964.pyi | 19 - Test/TestProject3/temp/68c4fe4b12c908e3.pyi | 50 + Test/TestProject3/temp/6aee24fdefa3cbc0.pyi | 44 + Test/TestProject3/temp/6c2029b306556c00.pyi | 18 + Test/TestProject3/temp/72e2d5ccb7cedcf1.pyi | 91 + Test/TestProject3/temp/_sha1_map.txt | 10 +- Test/TestProject3/temp/_shared_sym.pkl | Bin 486033 -> 484319 bytes Test/TestProject3/temp/a326a52b7c4bd6f0.pyi | 40 - Test/TestProject3/temp/a96738831f025829.pyi | 16 - ...c910044fab2d2.pyi => c01b27dbcd683245.pyi} | 12 +- Test/TestProject3/temp/c9f4be41ca1cc2b4.pyi | 10 +- Test/TestProject3/temp/fa3691e66b426950.pyi | 8 +- .../output/067c78e9f121dce3.deps.json | 2 +- .../output/29813d57621099a9.deps.json | 2 +- .../output/5a6a2137958c28c5.deps.json | 2 +- .../output/6aee24fdefa3cbc0.deps.json | 1 + .../output/72e2d5ccb7cedcf1.deps.json | 2 +- .../output/a326a52b7c4bd6f0.deps.json | 1 - .../output/abf9ce3160c9279e.deps.json | 2 +- .../output/bbdf3bbd4c3bc28c.deps.json | 2 +- .../output/bf230611b27080fa.deps.json | 2 +- .../output/fa3691e66b426950.deps.json | 2 +- Test/TypeCastTest/temp/6aee24fdefa3cbc0.pyi | 44 + Test/TypeCastTest/temp/_sha1_map.txt | 2 +- Test/TypeCastTest/temp/a326a52b7c4bd6f0.pyi | 40 - .../output/067c78e9f121dce3.deps.json | 2 +- .../output/2953a7db4185005b.deps.json | 2 +- .../output/29813d57621099a9.deps.json | 2 +- .../output/377ad03e9b90ac39.deps.json | 2 +- .../output/5a6a2137958c28c5.deps.json | 2 +- ...f.deps.json => 6aee24fdefa3cbc0.deps.json} | 2 +- .../output/72e2d5ccb7cedcf1.deps.json | 2 +- .../output/abf9ce3160c9279e.deps.json | 2 +- .../output/bbdf3bbd4c3bc28c.deps.json | 2 +- .../output/c9f4be41ca1cc2b4.deps.json | 2 +- .../output/fa3691e66b426950.deps.json | 2 +- Test/VariadicTest/temp/4d5db7f970ef510f.pyi | 40 - Test/VariadicTest/temp/6aee24fdefa3cbc0.pyi | 44 + Test/VariadicTest/temp/_sha1_map.txt | 2 +- Test/ZlibTest/App/__zlib/test_pyzlib.py | 4 +- .../output/024a3459d0f585ae.deps.json | 1 - .../output/067c78e9f121dce3.deps.json | 2 +- .../output/0af305ed4e5f787d.deps.json | 2 +- .../output/29813d57621099a9.deps.json | 2 +- .../output/53fa0c913947021f.deps.json | 1 + .../output/5a6a2137958c28c5.deps.json | 2 +- .../output/6aee24fdefa3cbc0.deps.json | 1 + .../output/72e2d5ccb7cedcf1.deps.json | 2 +- .../output/7e9fab9c7b47c4db.deps.json | 2 +- .../output/95e27d852b773ae8.deps.json | 2 +- .../output/abf9ce3160c9279e.deps.json | 2 +- .../output/bbdf3bbd4c3bc28c.deps.json | 2 +- .../output/c9349bf1e8390dd5.deps.json | 2 +- .../output/dca7ef1d57347738.deps.json | 2 +- .../output/e00d9854a0d03f4f.deps.json | 2 +- .../output/f9cd063200178785.deps.json | 2 +- .../output/fa3691e66b426950.deps.json | 2 +- .../output/ffaa1aaa1355e604.deps.json | 1 - Test/ZlibTest/temp/024a3459d0f585ae.pyi | 40 - ...a1aaa1355e604.pyi => 53fa0c913947021f.pyi} | 0 Test/ZlibTest/temp/6aee24fdefa3cbc0.pyi | 44 + Test/ZlibTest/temp/6c2029b306556c00.pyi | 18 + Test/ZlibTest/temp/_sha1_map.txt | 6 +- Test/ZlibTest/temp/_shared_sym.pkl | Bin 383282 -> 384819 bytes Test/ZlibTest/temp/a96738831f025829.pyi | 16 - Test/fbnq_out | 676 --- Test/regression_test.py | 334 ++ TransPyC.py | 730 +--- blackhole.py | 278 -- debug_out.txt | 1 - debug_output.txt | 1 - find.py | 163 + includes/asm.py | 3 + includes/base64.py | 1 - includes/binascii.py | 1 - includes/stdlib.py | 6 +- lib/Projectrans/Config.py | 214 + lib/Projectrans/DeclarationGenerator.py | 747 ++++ lib/Projectrans/Phase1Generator.py | 338 ++ lib/Projectrans/Phase2Translator.py | 2423 +++++++++++ lib/Projectrans/Utils.py | 170 + lib/Projectrans/__init__.py | 37 + lib/Shell/Config.py | 5 + lib/Shell/Serializer.py | 58 + lib/Shell/TransPyC.py | 644 +++ lib/Shell/__init__.py | 6 + lib/StubGen/Config.py | 42 + lib/StubGen/Converter.py | 967 +++++ lib/StubGen/Generator.py | 311 ++ lib/StubGen/__init__.py | 6 + lib/core/AsmIntelToAtt.py | 534 --- lib/core/DecoratorPass.py | 1044 ++--- lib/core/{export_table.py => Exportable.py} | 354 +- lib/core/Handles/HandlesAnnAssign.py | 26 +- lib/core/Handles/HandlesAssign.py | 96 +- lib/core/Handles/HandlesAugAssign.py | 424 +- lib/core/Handles/HandlesBase.py | 12 +- lib/core/Handles/HandlesBody.py | 4 +- lib/core/Handles/HandlesClassDef.py | 12 +- lib/core/Handles/HandlesDelete.py | 6 +- lib/core/Handles/HandlesExpr.py | 858 ++-- lib/core/Handles/HandlesExprAsm.py | 1156 ++--- lib/core/Handles/HandlesExprAttr.py | 2320 +++++----- lib/core/Handles/HandlesExprBuiltin.py | 46 +- lib/core/Handles/HandlesExprCall.py | 424 +- lib/core/Handles/HandlesExprFormat.py | 220 +- lib/core/Handles/HandlesExprLambda.py | 464 +- lib/core/Handles/HandlesExprOps.py | 804 ++-- lib/core/Handles/HandlesExprUtils.py | 480 +-- lib/core/Handles/HandlesFor.py | 32 +- lib/core/Handles/HandlesFunctions.py | 92 +- lib/core/Handles/HandlesIf.py | 604 +-- lib/core/Handles/HandlesImports.py | 527 ++- lib/core/Handles/HandlesMatch.py | 666 +-- lib/core/Handles/HandlesRaise.py | 268 +- lib/core/Handles/HandlesSpecialCall.py | 712 ++-- lib/core/Handles/HandlesTry.py | 420 +- lib/core/Handles/HandlesTypeMerge.py | 2 +- lib/core/Handles/HandlesWhile.py | 108 +- lib/core/Handles/HandlesWith.py | 274 +- lib/core/Handles/__init__.py | 4 +- lib/core/LLVMCG/BaseGen.py | 412 ++ lib/core/LLVMCG/ExprGen.py | 353 ++ lib/core/LLVMCG/FuncGen.py | 386 ++ lib/core/LLVMCG/MemoryOps.py | 312 ++ lib/core/LLVMCG/StructGen.py | 463 ++ lib/core/LLVMCG/TypeConvert.py | 618 +++ lib/core/LLVMCG/VaArg.py | 94 + lib/core/LLVMCG/__init__.py | 34 + lib/core/LlvmCodeGenerator.py | 2590 +----------- lib/core/SymbolNode.py | 414 +- lib/core/SymbolTable.py | 10 +- lib/core/Translator/AnnotationLoader.py | 401 ++ lib/core/Translator/BaseTranslator.py | 154 + lib/core/Translator/ConstEval.py | 186 + lib/core/Translator/LlvmGenerator.py | 622 +++ lib/core/Translator/PythonParser.py | 460 ++ lib/core/Translator/__init__.py | 11 + lib/core/{logger.py => VLogger.py} | 619 +-- lib/core/stub_generator.py | 10 +- lib/core/translator.py | 1757 +------- lib/includes/t.py | 8 +- temp_error.txt | 1 - temp_error2.txt | 1 - test_debug.py | 32 - test_regex.py | 24 - test_sret | 27 - 365 files changed, 22562 insertions(+), 24532 deletions(-) create mode 100644 1.html create mode 100644 2.html delete mode 100644 CPython/c.py delete mode 100644 CPython/t.py create mode 100644 Test/BuiltinDecoratorTest/output/b6069b01d8c9cc04.deps.json create mode 100644 Test/BuiltinDecoratorTest/temp/6c2029b306556c00.pyi rename Test/BuiltinDecoratorTest/temp/{7d5b7ce7c134ada7.pyi => b6069b01d8c9cc04.pyi} (82%) create mode 100644 Test/CPythonTest/output/0cd580d62a3de4f8.deps.json delete mode 100644 Test/CPythonTest/output/3e1c3f98e99cff7a.deps.json delete mode 100644 Test/CPythonTest/output/4d342c40331fc964.deps.json delete mode 100644 Test/CPythonTest/output/6999814920e8b3d5.deps.json create mode 100644 Test/CPythonTest/output/7c5d5ec59c5fb0a8.deps.json delete mode 100644 Test/CPythonTest/output/CPythonTest.exe.tmp0 delete mode 100644 Test/CPythonTest/output/c9f4be41ca1cc2b4.deps.json create mode 100644 Test/CPythonTest/temp/0cd580d62a3de4f8.pyi delete mode 100644 Test/CPythonTest/temp/3e1c3f98e99cff7a.pyi delete mode 100644 Test/CPythonTest/temp/6999814920e8b3d5.pyi create mode 100644 Test/CPythonTest/temp/73edbcf76e32d00b.pyi create mode 100644 Test/CPythonTest/temp/7c5d5ec59c5fb0a8.pyi delete mode 100644 Test/CPythonTest/temp/81ac26077a460417.pyi delete mode 100644 Test/CPythonTest/temp/93131e2ff5450838.pyi delete mode 100644 Test/CPythonTest/temp/c9f4be41ca1cc2b4.pyi delete mode 100644 Test/CPythonTest/temp/d771d4d68d9e75b3.pyi create mode 100644 Test/IterTest/output/6aee24fdefa3cbc0.deps.json delete mode 100644 Test/IterTest/output/73a525067569932e.deps.json rename Test/{StringIterTest/temp/4d5db7f970ef510f.pyi => IterTest/temp/6aee24fdefa3cbc0.pyi} (93%) rename Test/PointerTest/output/{4d5db7f970ef510f.deps.json => 6aee24fdefa3cbc0.deps.json} (62%) delete mode 100644 Test/PointerTest/output/PointerTest.exe.tmp0 rename Test/{IterTest/temp/73a525067569932e.pyi => PointerTest/temp/6aee24fdefa3cbc0.pyi} (93%) create mode 100644 Test/ReTest/output/68c4fe4b12c908e3.deps.json create mode 100644 Test/ReTest/output/6aee24fdefa3cbc0.deps.json create mode 100644 Test/ReTest/output/839e950555b6a435.deps.json create mode 100644 Test/ReTest/output/9ef80c98cfbbce42.deps.json create mode 100644 Test/ReTest/output/c9f4be41ca1cc2b4.deps.json rename Test/{CPythonTest => ReTest}/temp/56cdd754a8a09347.pyi (100%) rename Test/{TestProject3/temp/21ffad37f6fc3fcf.pyi => ReTest/temp/68c4fe4b12c908e3.pyi} (67%) rename Test/{PointerTest/temp/4d5db7f970ef510f.pyi => ReTest/temp/6aee24fdefa3cbc0.pyi} (93%) create mode 100644 Test/ReTest/temp/73edbcf76e32d00b.pyi rename Test/{SimdTest => ReTest}/temp/7538e542cab4c1d5.pyi (100%) create mode 100644 Test/ReTest/temp/839e950555b6a435.pyi create mode 100644 Test/ReTest/temp/9ef80c98cfbbce42.pyi create mode 100644 Test/ReTest/temp/_sha1_map.txt create mode 100644 Test/ReTest/temp/c9f4be41ca1cc2b4.pyi delete mode 100644 Test/SimdTest/output/024a3459d0f585ae.deps.json create mode 100644 Test/SimdTest/output/6aee24fdefa3cbc0.deps.json rename Test/SimdTest/temp/{024a3459d0f585ae.pyi => 6aee24fdefa3cbc0.pyi} (93%) create mode 100644 Test/SimdTest/temp/6c2029b306556c00.pyi delete mode 100644 Test/StringIterTest/output/4d5db7f970ef510f.deps.json create mode 100644 Test/StringIterTest/output/6aee24fdefa3cbc0.deps.json create mode 100644 Test/StringIterTest/temp/6aee24fdefa3cbc0.pyi rename Test/StringTest/output/{4d5db7f970ef510f.deps.json => 6aee24fdefa3cbc0.deps.json} (50%) delete mode 100644 Test/StringTest/temp/4d5db7f970ef510f.pyi create mode 100644 Test/StringTest/temp/6aee24fdefa3cbc0.pyi create mode 100644 Test/StructTest/output/6aee24fdefa3cbc0.deps.json delete mode 100644 Test/StructTest/output/a326a52b7c4bd6f0.deps.json create mode 100644 Test/StructTest/temp/6aee24fdefa3cbc0.pyi delete mode 100644 Test/StructTest/temp/a326a52b7c4bd6f0.pyi create mode 100644 Test/TestFBProject/temp/067c78e9f121dce3.pyi delete mode 100644 Test/TestFBProject/temp/214790a9a42a868c.pyi create mode 100644 Test/TestFBProject/temp/29813d57621099a9.pyi create mode 100644 Test/TestFBProject/temp/72e2d5ccb7cedcf1.pyi create mode 100644 Test/TestFBProject/temp/abf9ce3160c9279e.pyi delete mode 100644 Test/TestFBProject/temp/ac0664ce209738d9.pyi create mode 100644 Test/TestFBProject/temp/fa3691e66b426950.pyi delete mode 100644 Test/TestProject/App/__zlib/__init__.py delete mode 100644 Test/TestProject/App/__zlib/pyzlib.py delete mode 100644 Test/TestProject/App/__zlib/test_basic.c delete mode 100644 Test/TestProject/App/__zlib/test_debug.c delete mode 100644 Test/TestProject/App/__zlib/test_pyzlib.py delete mode 100644 Test/TestProject/App/__zlib/zchecksum.py delete mode 100644 Test/TestProject/App/__zlib/zdef.py delete mode 100644 Test/TestProject/App/__zlib/zdeflate.py delete mode 100644 Test/TestProject/App/__zlib/zhuff.py delete mode 100644 Test/TestProject/App/__zlib/zinflate.py rename Test/TestProject/output/{439f5b503003443f.deps.json => 0c04ab530bb9cfa4.deps.json} (54%) delete mode 100644 Test/TestProject/output/3d1656b26b38b359.deps.json create mode 100644 Test/TestProject/output/4bf3e0150b9e02e9.deps.json delete mode 100644 Test/TestProject/output/7e4cef8dd61984f0.deps.json create mode 100644 Test/TestProject/output/8f88a3374d5335cc.deps.json rename Test/TestProject/temp/{439f5b503003443f.pyi => 0c04ab530bb9cfa4.pyi} (92%) rename Test/TestProject/temp/{7e4cef8dd61984f0.pyi => 4bf3e0150b9e02e9.pyi} (94%) create mode 100644 Test/TestProject/temp/6c2029b306556c00.pyi delete mode 100644 Test/TestProject/temp/7538e542cab4c1d5.pyi rename Test/TestProject/temp/{3d1656b26b38b359.pyi => 8f88a3374d5335cc.pyi} (98%) delete mode 100644 Test/TestProject3/output/087c910044fab2d2.deps.json delete mode 100644 Test/TestProject3/output/21ffad37f6fc3fcf.deps.json create mode 100644 Test/TestProject3/output/2953a7db4185005b.deps.json delete mode 100644 Test/TestProject3/output/4d342c40331fc964.deps.json create mode 100644 Test/TestProject3/output/68c4fe4b12c908e3.deps.json create mode 100644 Test/TestProject3/output/6aee24fdefa3cbc0.deps.json delete mode 100644 Test/TestProject3/output/a326a52b7c4bd6f0.deps.json create mode 100644 Test/TestProject3/output/c01b27dbcd683245.deps.json create mode 100644 Test/TestProject3/temp/067c78e9f121dce3.pyi rename Test/{CPythonTest/temp/4d342c40331fc964.pyi => TestProject3/temp/2953a7db4185005b.pyi} (100%) create mode 100644 Test/TestProject3/temp/29813d57621099a9.pyi delete mode 100644 Test/TestProject3/temp/4d342c40331fc964.pyi create mode 100644 Test/TestProject3/temp/68c4fe4b12c908e3.pyi create mode 100644 Test/TestProject3/temp/6aee24fdefa3cbc0.pyi create mode 100644 Test/TestProject3/temp/6c2029b306556c00.pyi create mode 100644 Test/TestProject3/temp/72e2d5ccb7cedcf1.pyi delete mode 100644 Test/TestProject3/temp/a326a52b7c4bd6f0.pyi delete mode 100644 Test/TestProject3/temp/a96738831f025829.pyi rename Test/TestProject3/temp/{087c910044fab2d2.pyi => c01b27dbcd683245.pyi} (62%) create mode 100644 Test/TypeCastTest/output/6aee24fdefa3cbc0.deps.json delete mode 100644 Test/TypeCastTest/output/a326a52b7c4bd6f0.deps.json create mode 100644 Test/TypeCastTest/temp/6aee24fdefa3cbc0.pyi delete mode 100644 Test/TypeCastTest/temp/a326a52b7c4bd6f0.pyi rename Test/VariadicTest/output/{4d5db7f970ef510f.deps.json => 6aee24fdefa3cbc0.deps.json} (64%) delete mode 100644 Test/VariadicTest/temp/4d5db7f970ef510f.pyi create mode 100644 Test/VariadicTest/temp/6aee24fdefa3cbc0.pyi delete mode 100644 Test/ZlibTest/output/024a3459d0f585ae.deps.json create mode 100644 Test/ZlibTest/output/53fa0c913947021f.deps.json create mode 100644 Test/ZlibTest/output/6aee24fdefa3cbc0.deps.json delete mode 100644 Test/ZlibTest/output/ffaa1aaa1355e604.deps.json delete mode 100644 Test/ZlibTest/temp/024a3459d0f585ae.pyi rename Test/ZlibTest/temp/{ffaa1aaa1355e604.pyi => 53fa0c913947021f.pyi} (100%) create mode 100644 Test/ZlibTest/temp/6aee24fdefa3cbc0.pyi create mode 100644 Test/ZlibTest/temp/6c2029b306556c00.pyi delete mode 100644 Test/ZlibTest/temp/a96738831f025829.pyi delete mode 100644 Test/fbnq_out create mode 100644 Test/regression_test.py delete mode 100644 blackhole.py delete mode 100644 debug_out.txt delete mode 100644 debug_output.txt create mode 100644 find.py create mode 100644 lib/Projectrans/Config.py create mode 100644 lib/Projectrans/DeclarationGenerator.py create mode 100644 lib/Projectrans/Phase1Generator.py create mode 100644 lib/Projectrans/Phase2Translator.py create mode 100644 lib/Projectrans/Utils.py create mode 100644 lib/Projectrans/__init__.py create mode 100644 lib/Shell/Config.py create mode 100644 lib/Shell/Serializer.py create mode 100644 lib/Shell/TransPyC.py create mode 100644 lib/Shell/__init__.py create mode 100644 lib/StubGen/Config.py create mode 100644 lib/StubGen/Converter.py create mode 100644 lib/StubGen/Generator.py create mode 100644 lib/StubGen/__init__.py delete mode 100644 lib/core/AsmIntelToAtt.py rename lib/core/{export_table.py => Exportable.py} (93%) create mode 100644 lib/core/LLVMCG/BaseGen.py create mode 100644 lib/core/LLVMCG/ExprGen.py create mode 100644 lib/core/LLVMCG/FuncGen.py create mode 100644 lib/core/LLVMCG/MemoryOps.py create mode 100644 lib/core/LLVMCG/StructGen.py create mode 100644 lib/core/LLVMCG/TypeConvert.py create mode 100644 lib/core/LLVMCG/VaArg.py create mode 100644 lib/core/LLVMCG/__init__.py create mode 100644 lib/core/Translator/AnnotationLoader.py create mode 100644 lib/core/Translator/BaseTranslator.py create mode 100644 lib/core/Translator/ConstEval.py create mode 100644 lib/core/Translator/LlvmGenerator.py create mode 100644 lib/core/Translator/PythonParser.py create mode 100644 lib/core/Translator/__init__.py rename lib/core/{logger.py => VLogger.py} (90%) delete mode 100644 temp_error.txt delete mode 100644 temp_error2.txt delete mode 100644 test_debug.py delete mode 100644 test_regex.py delete mode 100644 test_sret diff --git a/1.html b/1.html new file mode 100644 index 0000000..e09fc0e --- /dev/null +++ b/1.html @@ -0,0 +1,283 @@ + + + + + + 温暖存折 - 我的微长征 + + + +
+ +
+

温暖存折

+
我的“微长征”21天温暖行动
+
+

姓  名 _________________

+

班  级 _________________

+

行动时间 2026年__月__日 至 __月__日

+

温暖目标 存满 ______ 次温暖

+
+
❤️ 温暖行动 ❤️
+
+

存折号:WE⁰⁰⁰¹

+

签发:“微长征”中队

+
+
+ + +
+

📖 温暖存款记录

+ + + + + + + + + +
日期我做了什么对方反应/我的感受见证人
__月 __日
__月 __日
__月 __日
+
+

✨ 我的第一份温暖:_________________________

+

💬 蔡威叔叔说“为了明天”,我今天做了:

+
+
第1周 · 小红军签名 ___________
+
+
+ + +
+ +
+

📖 温暖存款记录(续)

+ + + + + + + +
日期我做了什么对方反应/我的感受见证人
__月 __日
__月 __日
__月 __日
+
+

🏅 我获得的第一枚勋章日期:__________ 因为我帮助了____________

+

❤️ 我的成长发现:

+
+
第2周 · 小红军签名 ___________
+
+ + +
+

⭐ 微长征勋章 ⭐

+
+ 🏅 🏅 🏅
+ (每积累3笔温暖,请老师/伙伴盖一枚红章) +
+
+

🌟 21天后,我最想对自己说:

+

+

🌟 我想对蔡威叔叔说:

+

+
+
+ “英雄不是做惊天动地的事,
+ 而是在别人最需要的时候,选择不转身离开。” +
+
温暖见证人:__________ 家长/老师
+
+
+ + + \ No newline at end of file diff --git a/2.html b/2.html new file mode 100644 index 0000000..7e24d57 --- /dev/null +++ b/2.html @@ -0,0 +1,246 @@ + + + + + + 温暖存折 - 我的微长征 + + + + + + +
+ +
+

📖 温暖存款记录(续)

+ + + + + + + +
日期我做了什么对方反应/我的感受见证人
__月 __日
__月 __日
__月 __日
+
+

🏅 我获得的第一枚勋章日期:__________ 因为我帮助了____________

+

❤️ 我的成长发现:

+
+
第2周 · 小红军签名 ___________
+
+ + +
+

⭐ 微长征勋章 ⭐

+
+ 🏅 🏅 🏅
+ (每积累3笔温暖,请老师/伙伴盖一枚红章) +
+
+

🌟 21天后,我最想对自己说:

+

+

🌟 我想对蔡威叔叔说:

+

+
+
+ “英雄不是做惊天动地的事,
+ 而是在别人最需要的时候,选择不转身离开。” +
+
温暖见证人:__________ 家长/老师
+
+
+ + + \ No newline at end of file diff --git a/CPython/c.py b/CPython/c.py deleted file mode 100644 index 3370618..0000000 --- a/CPython/c.py +++ /dev/null @@ -1,690 +0,0 @@ -# C语法定义模块 - -import ast -import sys -import os -sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) - -from . import t - -def _to_str(node): - if node is None: - return '' - if isinstance(node, str): - return node - if isinstance(node, list): - return ' && '.join([_to_str(n) for n in node]) - NodeType = type(node).__name__ - if NodeType == 'Constant': - return node.value - elif NodeType == 'ID': - return node.name - elif NodeType == 'BinaryOp': - left = _to_str(node.left) - right = _to_str(node.right) - return f'{left} {node.op} {right}' - elif NodeType == 'UnaryOp': - expr = _to_str(node.expr) - return f'{node.op}{expr}' - else: - return repr(node) - -class Asm: - @staticmethod - def HandleCall(translator, args, keywords): - if not args: - return ['__asm__ volatile ("nop");'] - - # ========== 核心变量 ========== - output_ops = [] # (值表达式, 约束符) - input_ops = [] # (值表达式, 约束符) - clobbers = [] # 破坏列表实际值 - operand_seq = 0 # 占位符编号 - - # ========== 核心修复:递归提取ASM_DESCR值(支持|组合) ========== - def parse_asm_descr(expr): - """ - 递归解析AST节点,确保获取t.ASM_DESCR的实际值,支持|组合 - 处理场景: - 1. t.ASM_DESCR.XXX → 取属性值 - 2. t.ASM_DESCR.XXX | t.ASM_DESCR.YYY → 拼接两个值 - 3. 常量字符串 → 直接返回 - """ - # 场景1:位或组合(XXX | YYY) - if isinstance(expr, ast.BinOp): - left_val = parse_asm_descr(expr.left) - right_val = parse_asm_descr(expr.right) - return left_val + right_val - - # 场景2:t.ASM_DESCR.XXX 多层属性访问 - elif isinstance(expr, ast.Attribute): - # 第一步:判断是否是 t.ASM_DESCR 的属性 - if isinstance(expr.value, ast.Attribute): - # 内层是 t.ASM_DESCR - if (isinstance(expr.value.value, ast.Name) and - expr.value.value.id == 't' and - expr.value.attr == 'ASM_DESCR'): - # 取 t.ASM_DESCR.XXX 的实际值 - AttrName = expr.attr - if hasattr(t.ASM_DESCR, AttrName): - return getattr(t.ASM_DESCR, AttrName, "") - - # 兼容 t.XXX 简化写法(如果有的话) - elif isinstance(expr.value, ast.Name) and expr.value.id == 't': - AttrName = expr.attr - if hasattr(t.ASM_DESCR, AttrName): - return getattr(t.ASM_DESCR, AttrName, "") - - # 场景3:直接传常量(如 "r"、"cc") - elif isinstance(expr, ast.Constant): - return expr.value - - # 其他场景返回空 - return "" - - # ========== 步骤1:处理f-string中的内联AsmInp/AsmOut ========== - asm_code = "" - first_arg = args[0] - - if isinstance(first_arg, ast.JoinedStr): - asm_parts = [] - for part in first_arg.values: - if isinstance(part, ast.Constant): - asm_parts.append(part.value) - elif isinstance(part, ast.FormattedValue): - expr = part.value - if isinstance(expr, ast.Call) and isinstance(expr.func, ast.Attribute) and expr.func.value.id == 'c': - # 解析内联的AsmInp/AsmOut - call_node = expr - val_ExprNode = translator.HandleExpr(call_node.args[0])[0] if len(call_node.args)>=1 else "" - if isinstance(val_ExprNode, str): - val_expr = val_ExprNode - else: - try: - val_expr = str(val_ExprNode) - except: - val_expr = '' - constraint = parse_asm_descr(call_node.args[1]) if len(call_node.args)>=2 else "" - - if call_node.func.attr == 'AsmOut': - output_ops.append((val_expr, constraint)) - asm_parts.append(f"%{operand_seq}") - operand_seq += 1 - elif call_node.func.attr == 'AsmInp': - input_ops.append((val_expr, constraint)) - asm_parts.append(f"%{operand_seq}") - operand_seq += 1 - else: - asm_parts.append(translator.HandleExpr(expr)[0]) - asm_code = ''.join(asm_parts) - elif isinstance(first_arg, ast.Constant): - asm_code = first_arg.value - - # ========== 步骤2:处理参数中的AsmInp/AsmOut和破坏列表 ========== - def parse_operand(arg): - """解析 AsmInp/AsmOut 参数""" - if isinstance(arg, ast.Call) and isinstance(arg.func, ast.Attribute) and arg.func.value.id == 'c': - call_node = arg - val_ExprNode = translator.HandleExpr(call_node.args[0])[0] if len(call_node.args)>=1 else "" - if isinstance(val_ExprNode, str): - val_expr = val_ExprNode - else: - try: - val_expr = str(val_ExprNode) - except: - val_expr = '' - constraint = parse_asm_descr(call_node.args[1]) if len(call_node.args)>=2 else "" - - if call_node.func.attr == 'AsmOut': - return ('out', val_expr, constraint) - elif call_node.func.attr == 'AsmInp': - return ('in', val_expr, constraint) - return None - - for arg in args[1:]: - result = parse_operand(arg) - if result: - direction, val_expr, constraint = result - if direction == 'out': - output_ops.append((val_expr, constraint)) - operand_seq += 1 - elif direction == 'in': - input_ops.append((val_expr, constraint)) - operand_seq += 1 - elif isinstance(arg, ast.List): - # 解析破坏列表(支持|组合) - for elt in arg.elts: - clobber_val = parse_asm_descr(elt) - if clobber_val: - clobbers.append(clobber_val) - - # ========== 步骤2.5:处理关键字参数 out 和 op ========== - for kw in keywords: - if kw.arg == 'out': - # 处理 out 关键字参数 (输出操作数) - if isinstance(kw.value, ast.List): - for elt in kw.value.elts: - result = parse_operand(elt) - if result and result[0] == 'out': - output_ops.append((result[1], result[2])) - operand_seq += 1 - elif isinstance(kw.value, ast.Call): - result = parse_operand(kw.value) - if result and result[0] == 'out': - output_ops.append((result[1], result[2])) - operand_seq += 1 - elif kw.arg == 'op': - # 处理 op 关键字参数 (clobber,破坏列表) - if isinstance(kw.value, ast.List): - for elt in kw.value.elts: - clobber_val = parse_asm_descr(elt) - if clobber_val: - clobbers.append(clobber_val) - elif kw.arg == 'inp' or kw.arg == 'inputs': - # 处理 inp/inputs 关键字参数 (输入操作数,追加到f-string中已有输入之后) - if isinstance(kw.value, ast.List): - for elt in kw.value.elts: - if isinstance(elt, ast.Tuple): - # 处理列表中的 (value, constraint) 元组格式 - if len(elt.elts) >= 2: - val_ExprNode = translator.HandleExpr(elt.elts[0])[0] if len(elt.elts) >= 1 else "" - if isinstance(val_ExprNode, str): - val_expr = val_ExprNode - else: - try: - val_expr = str(val_ExprNode) - except: - val_expr = '' - constraint = parse_asm_descr(elt.elts[1]) - input_ops.append((val_expr, constraint)) - operand_seq += 1 - else: - result = parse_operand(elt) - if result and result[0] == 'in': - input_ops.append((result[1], result[2])) - operand_seq += 1 - elif isinstance(kw.value, ast.Call): - result = parse_operand(kw.value) - if result and result[0] == 'in': - input_ops.append((result[1], result[2])) - operand_seq += 1 - elif isinstance(kw.value, ast.Tuple): - # 处理 (value, constraint) 元组格式 - if len(kw.value.elts) >= 2: - val_ExprNode = translator.HandleExpr(kw.value.elts[0])[0] if len(kw.value.elts) >= 1 else "" - if isinstance(val_ExprNode, str): - val_expr = val_ExprNode - else: - try: - val_expr = str(val_ExprNode) - except: - val_expr = '' - constraint = parse_asm_descr(kw.value.elts[1]) - input_ops.append((val_expr, constraint)) - operand_seq += 1 - elif kw.arg == 'clobber': - # 处理 clobber 关键字参数 - if isinstance(kw.value, ast.List): - for elt in kw.value.elts: - clobber_val = parse_asm_descr(elt) - if clobber_val: - clobbers.append(clobber_val) - - # ========== 步骤3:格式化汇编代码 ========== - asm_lines = [line.strip() for line in asm_code.split('\n') if line.strip()] - formatted_asm = '\n '.join([f'"{line}\\n"' for line in asm_lines]) - - # ========== 步骤4:拼接约束字符串 ========== - # 输出约束:如果约束已包含 = 或 +,直接使用;否则添加 = - def format_constraint(constraint, is_output=True): - if not constraint: - return "" - # 如果约束已包含修饰符,直接返回 - if '=' in constraint or '+' in constraint: - return constraint - # 否则添加适当的修饰符 - return ('=' if is_output else '') + constraint - - out_const = ', '.join([f'"{format_constraint(c, True)}"({v})' for v, c in output_ops]) if output_ops else "" - in_const = ', '.join([f'"{format_constraint(c, False)}"({v})' for v, c in input_ops]) if input_ops else "" - clobber_const = ', '.join([f'"{x}"' for x in clobbers]) if clobbers else "" - - # 构建约束部分:确保冒号格式正确 - constraint_parts = [] - # 输出约束 - if output_ops: - constraint_parts.append(f': {out_const}') - elif input_ops or clobbers: - constraint_parts.append(':') - - # 输入约束 - if input_ops: - constraint_parts.append(f': {in_const}') - elif clobbers: - constraint_parts.append(':') - - # 破坏列表 - if clobbers: - constraint_parts.append(f': {clobber_const}') - - constraint_str = ' '.join(constraint_parts) - - # ========== 生成最终代码 ========== - final_asm = f'__asm__ __volatile__ (\n {formatted_asm} {constraint_str});' - return [final_asm] - -class AsmInp: - def __init__(self, value, constraint): - self.value = value - self.constraint = constraint - @staticmethod - def HandleCall(translator, args, keywords): - return [] - -class AsmOut: - def __init__(self, value, constraint): - self.value = value - self.constraint = constraint - @staticmethod - def HandleCall(translator, args, keywords): - return [] - -class NoBreak: - """ switch 分支无break """ - pass - -class Break: - """ switch 分支提前break """ - pass - -class Load: - """解引用a写入b,等价于 *b = *a,无拷贝副作用""" - def __init__(self, src, dst): - self.src = src - self.dst = dst - - @staticmethod - def HandleCall(translator, args, keywords): - if len(args) >= 2: - src = translator.HandleExpr(args[0])[0] - dst = translator.HandleExpr(args[1])[0] - return [f'*({dst}) = *({src})'] - return [] - - -class Addr: - """取地址""" - def __init__(self, addr): - self.addr = addr - - @staticmethod - def HandleCall(translator, args, keywords): - """处理 c.Addr() 调用""" - if args: - expr = translator.HandleExpr(args[0])[0] - if isinstance(expr, str): - return [f'&{expr}'] - return [f'&{_to_str(expr)}'] - return ['0'] - - -class Deref: - """解引用""" - def __init__(self, ptr): - self.ptr = ptr - - @staticmethod - def HandleCall(translator, args, keywords): - """处理 c.Deref() 调用""" - if args: - expr = translator.HandleExpr(args[0])[0] - if hasattr(expr, 'op') and expr.op == '*': - return [expr] - return [f'*({_to_str(expr)})'] - return ['0'] - - -class DerefAs: - """解引用写入,等价于 *ptr = value""" - def __init__(self, ptr, value): - self.ptr = ptr - self.value = value - - @staticmethod - def HandleCall(translator, args, keywords): - """处理 c.DerefAs() 调用""" - if len(args) >= 2: - ptr = translator.HandleExpr(args[0])[0] - val = translator.HandleExpr(args[1])[0] - return [f'*({_to_str(ptr)}) = {_to_str(val)}'] - return [] - - -class Set: - """设置值""" - def __init__(self, key, value): - self.key = key - self.value = value - - @staticmethod - def HandleCall(translator, args, keywords): - """处理 c.Set() 调用""" - if len(args) >= 2: - target = translator.HandleExpr(args[0])[0] - value = translator.HandleExpr(args[1])[0] - return [f'{_to_str(target)} = {_to_str(value)}'] - return [] - - -class CReturn: - """多返回值装饰器 - - 用于实现函数多返回值,通过匿名结构体返回实现。 - 例如:@c.CReturn(t.CInt, t.CInt) 表示函数返回两个 int 值。 - 等价于 -> tuple[t.CInt, t.CInt] 返回类型注解。 - - 规则: - 1. CReturn 中有几个类型就说明要返回几个值 - 2. 函数返回类型为匿名结构体 { type1, type2, ... } - 3. return 语句使用 insert_value 构建结构体 - 4. 调用处使用 extract_value 提取各字段 - """ - def __init__(self, *ReturnTypes): - self.ReturnTypes = ReturnTypes - - def __call__(self, func): - """装饰器调用""" - # 将返回类型信息附加到函数上 - func._CreturnTypes = self.ReturnTypes - return func - - -class CDefine: - """#define 宏定义""" - def __init__(self, name, value): - self.name = name - self.value = value - - @staticmethod - def HandleCall(translator, args, keywords): - """处理 c.CDefine() 调用""" - if len(args) >= 1: - if isinstance(args[0], ast.Constant): - name = args[0].value - else: - name = 'MACRO' - if len(args) >= 2: - value = translator.HandleExpr(args[1])[0] - return ['#define ' + str(name) + ' ' + _to_str(value)] - return ['#define ' + str(name)] - return [] - - -class CIfndef: - """#ifndef 条件编译""" - def __init__(self, condition): - self.condition = condition - - @staticmethod - def HandleCall(translator, args, keywords): - """处理 c.CIfndef() 调用""" - if args: - condition = translator.HandleExpr(args[0])[0] - return ['#ifndef ' + _to_str(condition)] - return ['#if 0'] - -class CIfdef: - """#ifdef 条件编译""" - def __init__(self, condition): - self.condition = condition - - @staticmethod - def HandleCall(translator, args, keywords): - """处理 c.CIfdef() 调用""" - if args: - condition = translator.HandleExpr(args[0])[0] - return ['#ifdef ' + _to_str(condition)] - return ['#if 0'] - -class CError: - """#error 错误信息""" - def __init__(self, condition): - self.condition = condition - - @staticmethod - def HandleCall(translator, args, keywords): - """处理 c.CError() 调用""" - if args: - # 如果是字符串常量,保留引号 - if isinstance(args[0], ast.Constant) and isinstance(args[0].value, str): - return ['#error "' + args[0].value + '"'] - elif isinstance(args[0], ast.Str): - return ['#error "' + args[0].s + '"'] - else: - condition = translator.HandleExpr(args[0])[0] - return ['#error ' + _to_str(condition)] - return ['#error "Error: Condition is not met."'] - - -class TokenPast: - """## 连接符""" - def __init__(self, left, right): - self.left = left - self.right = right - - @staticmethod - def HandleCall(translator, args, keywords): - """处理 c.TokenPast() 调用""" - if len(args) >= 2: - # 处理左操作数 - 去掉引号 - if isinstance(args[0], ast.Constant): - left = str(args[0].value) - elif isinstance(args[0], ast.Str): - left = str(args[0].s) - elif isinstance(args[0], ast.Name): - left = args[0].id - else: - left = _to_str(translator.HandleExpr(args[0])[0]) - - # 处理右操作数 - 去掉引号 - if isinstance(args[1], ast.Constant): - right = str(args[1].value) - elif isinstance(args[1], ast.Str): - right = str(args[1].s) - elif isinstance(args[1], ast.Name): - right = args[1].id - else: - right = _to_str(translator.HandleExpr(args[1])[0]) - - # 返回字符串,但用特殊标记包装,让 _AstNodeToStr 能正确处理 - result = left + ' ## ' + right - # 使用一个特殊的类来包装结果,让 _AstNodeToStr 直接返回其值 - class TokenPastResult: - def __init__(self, value): - self.value = value - def __str__(self): - return self.value - return [TokenPastResult(result)] - return [''] - - -class CIf: - """#if 条件编译""" - def __init__(self, condition): - self.condition = condition - - @staticmethod - def HandleCall(translator, args, keywords): - """处理 c.CIf() 调用""" - if args: - condition = translator.HandleExpr(args[0])[0] - return ['#if ' + _to_str(condition)] - return ['#if 0'] - - -class CElif: - """#elif 条件编译""" - def __init__(self, condition): - self.condition = condition - - @staticmethod - def HandleCall(translator, args, keywords): - """处理 c.CElif() 调用""" - if args: - condition = translator.HandleExpr(args[0])[0] - return ['#elif ' + _to_str(condition)] - return ['#else'] - - -class CElse: - """#else 条件编译""" - def __init__(self): - pass - - @staticmethod - def HandleCall(translator, args, keywords): - """处理 c.CElse() 调用""" - return ['#else'] - - -class CEndif: - """#endif 条件编译""" - def __init__(self): - pass - - @staticmethod - def HandleCall(translator, args, keywords): - """处理 c.CEndif() 调用""" - return ['#endif'] - - -class CUndef: - """#undef 取消宏定义""" - def __init__(self, name): - self.name = name - - @staticmethod - def HandleCall(translator, args, keywords): - """处理 c.CUndef(name) 调用""" - import ast - if args: - arg = args[0] - if isinstance(arg, str): - name = arg - elif isinstance(arg, ast.Name): - name = arg.id - elif isinstance(arg, ast.Constant): - name = str(arg.value) - else: - name = str(arg) - return [f'#undef {name}'] - return ['#undef'] - - -class LLVMIR: - """内联 LLVM IR - - 用法: c.LLVMIR(f"add i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt) - 或: c.LLVMIR(f"%{c.LOut(result)} = add i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt) - - c.LInp(expr) - 输入操作数,翻译后替换为对应的 LLVM 临时变量名 - c.LOut(expr) - 输出操作数,翻译后替换为对应的 LLVM 临时变量名 - """ - def __init__(self, ir_template, ret_type=None): - self.ir_template = ir_template - self.ret_type = ret_type - - @staticmethod - def HandleCall(translator, args, keywords): - return ['/* LLVMIR */'] - - -class LInp: - """LLVM IR 输入操作数标记 - - 用法: c.LInp(expr) - 标记 expr 为输入操作数 - 在 c.LLVMIR 的 f-string 中使用,翻译后替换为 %N 形式的操作数引用 - """ - def __init__(self, value): - self.value = value - - @staticmethod - def HandleCall(translator, args, keywords): - return [] - - -class LOut: - """LLVM IR 输出操作数标记 - - 用法: c.LOut(expr) - 标记 expr 为输出操作数 - 在 c.LLVMIR 的 f-string 中使用,翻译后替换为 %N 形式的操作数引用 - """ - def __init__(self, value): - self.value = value - - @staticmethod - def HandleCall(translator, args, keywords): - return [] - - -class CPragma: - """#pragma 指令 - - 用于生成 C 语言的 #pragma 指令。 - 例如:c.CPragma("GCC diagnostic push") 生成 #pragma GCC diagnostic push - """ - def __init__(self, directive): - self.directive = directive - - @staticmethod - def HandleCall(translator, args, keywords): - """处理 c.CPragma() 调用""" - if args: - arg = args[0] - if isinstance(arg, ast.Constant): - directive = arg.value - elif isinstance(arg, ast.Str): - directive = arg.s - else: - expr = translator.HandleExpr(arg)[0] - directive = _to_str(expr) - return [f'#pragma {directive}'] - return ['#pragma'] - - -# C 库类字典,用于 HandleCSpecialCall -Library_C = { - 'Asm': Asm, - 'Load': Load, - 'Addr': Addr, - 'Deref': Deref, - 'Set': Set, - 'AsmInp': AsmInp, - 'AsmOut': AsmOut, - 'CDefine': CDefine, - 'CIfndef': CIfndef, - 'CIfdef': CIfdef, - 'CIf': CIf, - 'CElif': CElif, - 'CElse': CElse, - 'CEndif': CEndif, - 'CUndef': CUndef, - 'CError': CError, - 'TokenPast': TokenPast, - 'CReturn': CReturn, - 'CPragma': CPragma, - 'LLVMIR': LLVMIR, - 'LInp': LInp, - 'LOut': LOut, -} - - -class Attribute: - """函数/变量属性装饰器""" - def __init__(self, *attrs): - self.attrs = attrs - - def __call__(self, func): - # 将属性附加到函数上 - func._c_attributes = self.attrs - return func diff --git a/CPython/t.py b/CPython/t.py deleted file mode 100644 index 495d5e8..0000000 --- a/CPython/t.py +++ /dev/null @@ -1,1283 +0,0 @@ -# 类型定义模块 - -import re -import types -from typing import TypeVar, Generic, TypeAlias - - -# ============================================================================= -# 类型映射常量 -# ============================================================================= - -# 类型映射常量(由 _build_type_maps() 在模块末尾自动生成) -_BASIC_TYPES_MAP = {} -_T_TYPE_PATTERNS = [] - -def _build_type_maps(): - global _BASIC_TYPES_MAP, _T_TYPE_PATTERNS - for _name in dir(): - _obj = eval(_name) - if isinstance(_obj, type) and issubclass(_obj, CType) and _obj is not CType: - try: - _inst = _obj() - _cname = getattr(_inst, 'CName', '') - if _cname and _obj.IsBasicType(): - _BASIC_TYPES_MAP[_cname] = _cname - _T_TYPE_PATTERNS.append((_name, _cname)) - except Exception: - pass - - -# ============================================================================= -# CType 基类 -# ============================================================================= - -class CType: - """C 类型基类""" - - PREFIX = 'prefix' - BASE = 'base' - POINTER = 'ptr' - ARRAY = 'array' - NAMED = 'named' - STORAGE_CLASS = 'storage_class' - TYPE_QUALIFIER = 'type_qualifier' - - position = frozenset({BASE}) # 类属性,支持联合类型如 BASE | SPECIAL - - def __init__(self, value=None, *types): - self.value = value - self.types = types - self.Name = '' - self.IsBasicType = False - self.IsPointer = False - self.IsSigned = None - self.Size = None - if not hasattr(self, 'CName'): - self.CName = '' - - def GetPositions(self) -> frozenset: - """获取 position 的 frozenset 形式""" - return self.position - - @classmethod - def HasPosition(cls, pos) -> bool: - """检查是否包含指定的位置""" - return pos in cls.position - - @classmethod - def IsNamed(cls) -> bool: - """检查是否是命名类型(struct/union/enum/typedef 等)""" - return cls.NAMED in cls.position - - @classmethod - def IsStorageClass(cls) -> bool: - """检查是否是存储类修饰符""" - return cls.STORAGE_CLASS in cls.position - - @classmethod - def IsTypeQualifier(cls) -> bool: - """检查是否是类型限定符""" - return cls.TYPE_QUALIFIER in cls.position - - @classmethod - def IsBasicType(cls) -> bool: - """检查是否是基本类型""" - return cls.BASE in cls.position - - @classmethod - def IsPrefix(cls) -> bool: - """检查是否是前缀类型""" - return cls.PREFIX in cls.position - - def rfind(self, s): - """注解""" - pass - - def get_position(self): - """获取类型在声明中的位置""" - return self.position - - def GetCAame(self): - """获取 C 类型名称""" - return self.CName - - def __merge__(self, types): - return types - - def __or__(self, other): - return [self, other] - - def __set_default__(self, **kwargs): - """设置默认值/初始值,用于 static/global 变量的初始化 - - Args: - **kwargs: 成员名称和值的键值对 - - Returns: - 包含默认值信息的 CTypeDefault 对象 - """ - return CTypeDefault(self, **kwargs) - - @classmethod - def FromAnnotation(cls, AnnotationStr, TypeName=''): - """从类型注解字符串解析类型信息 - - Args: - AnnotationStr: 类型注解的字符串表示(ast.dump结果) - TypeName: 类型名称(可选) - - Returns: - CType 实例 - """ - ctype = cls() - - # 检查是否是基本类型 - if TypeName in _BASIC_TYPES_MAP: - ctype.IsBasicType = True - ctype.Name = _BASIC_TYPES_MAP[TypeName] - else: - for pattern, c_name in _T_TYPE_PATTERNS: - if pattern in AnnotationStr: - ctype.IsBasicType = True - ctype.Name = c_name - break - - # 检查是否包含指针 - if 'CPtr' in AnnotationStr: - ctype.IsPointer = True - - return ctype - - @classmethod - def FromTypeName(cls, TypeName): - """从类型名称创建 CType - - Args: - TypeName: 类型名称 - - Returns: - CType 实例 - """ - ctype = cls() - - if TypeName in _BASIC_TYPES_MAP: - ctype.IsBasicType = True - ctype.Name = _BASIC_TYPES_MAP[TypeName] - - return ctype - - def GetFullType(self, VarName='', ArraySizeStr=''): - """获取完整的类型声明字符串 - - Args: - VarName: 变量名 - ArraySizeStr: 数组大小字符串 - - Returns: - 完整的类型声明字符串 - """ - ptr_str = '*' if self.IsPointer else '' - if VarName: - return f'{self.Name}{ptr_str} {VarName}{ArraySizeStr}' - return f'{self.Name}{ptr_str}' - - def __repr__(self): - ptr_str = '*' if self.IsPointer else '' - return f'CType({self.Name}{ptr_str}, IsBasicType={self.IsBasicType})' - -class CChar(CType): - def __init__(self, value=None): - self.CName = 'char' - super().__init__(value) - self.IsSigned = True - self.Size = 8 - -class CInt(CType): - position = frozenset({CType.BASE}) - def __init__(self, value=None): - self.CName = 'int' - super().__init__(value) - self.IsSigned = True - self.Size = 32 - -class CShort(CType): - position = frozenset({CType.BASE}) - def __init__(self, value=None): - self.CName = 'short' - super().__init__(value) - self.IsSigned = True - self.Size = 16 - -class CLong(CType): - position = frozenset({CType.BASE}) - def __init__(self, value=None): - self.CName = 'long' - super().__init__(value) - self.IsSigned = True - self.Size = 64 - -class CFloat(CType): - position = frozenset({CType.BASE}) - def __init__(self, value=None): - self.CName = 'float' - super().__init__(value) - self.IsSigned = None - self.Size = 32 - -class CDouble(CType): - position = frozenset({CType.BASE}) - def __init__(self, value=None): - self.CName = 'double' - super().__init__(value) - self.IsSigned = None - self.Size = 64 - -class CFloat8T(CType): - position = frozenset({CType.BASE}) - def __init__(self, value=None): - self.CName = 'float8_t' - super().__init__(value) - self.IsSigned = None - self.Size = 8 - -class CFloat16T(CType): - position = frozenset({CType.BASE}) - def __init__(self, value=None): - self.CName = 'float16_t' - super().__init__(value) - self.IsSigned = None - self.Size = 16 - -class CFloat32T(CType): - position = frozenset({CType.BASE}) - def __init__(self, value=None): - self.CName = 'float32_t' - super().__init__(value) - self.IsSigned = None - self.Size = 32 - -class CFloat64T(CType): - position = frozenset({CType.BASE}) - def __init__(self, value=None): - self.CName = 'float64_t' - super().__init__(value) - self.IsSigned = None - self.Size = 64 - -class CFloat128T(CType): - position = frozenset({CType.BASE}) - def __init__(self, value=None): - self.CName = 'float128_t' - super().__init__(value) - self.IsSigned = None - self.Size = 128 - -class CVoid(CType): - position = frozenset({CType.BASE}) - def __init__(self, value=None): - self.CName = 'void' - super().__init__(value) - self.IsSigned = None - self.Size = 0 - -class CUnsigned(CType): - position = frozenset({CType.BASE}) - def __init__(self, value=None): - self.CName = 'unsigned' - super().__init__(value) - self.IsSigned = False - self.Size = 32 - -class CUnsignedChar(CType): - position = frozenset({CType.BASE}) - def __init__(self, value=None): - self.CName = 'unsigned char' - super().__init__(value) - self.IsSigned = False - self.Size = 8 - -class CUnsignedInt(CType): - position = frozenset({CType.BASE}) - def __init__(self, value=None): - self.CName = 'unsigned int' - super().__init__(value) - self.IsSigned = False - self.Size = 32 - -class CUnsignedShort(CType): - position = frozenset({CType.BASE}) - def __init__(self, value=None): - self.CName = 'unsigned short' - super().__init__(value) - self.IsSigned = False - self.Size = 16 - -class CUnsignedLong(CType): - position = frozenset({CType.BASE}) - def __init__(self, value=None): - self.CName = 'unsigned long' - super().__init__(value) - self.IsSigned = False - self.Size = 64 - -class CSignedChar(CType): - position = frozenset({CType.BASE}) - def __init__(self, value=None): - self.CName = 'signed char' - super().__init__(value) - self.IsSigned = True - self.Size = 8 - -class CStruct(CType): - position = frozenset({CType.BASE, CType.NAMED}) - def __init__(self, value=None, name=None): - self.CName = f'struct {name}' if name else 'struct' - super().__init__(value) - -class CUnion(CType): - position = frozenset({CType.BASE, CType.NAMED}) - def __init__(self, value=None): - self.CName = 'union' - super().__init__(value) - -class CEnum(CType): - position = frozenset({CType.BASE, CType.NAMED}) - def __init__(self, value=None): - self.CName = 'enum' - super().__init__(value) - self.b = 1 - -Enum = CEnum # 别名,允许使用 t.Enum - -''' -class Object(CType): - """Python 对象类型,用于支持类方法外联函数""" - position = frozenset({CType.BASE, CType.NAMED}) - def __init__(self, value=None): - self.CName = 'struct' - super().__init__(value) - def __call__(self, cls): - return cls -''' -def Object(): - pass - -def CVTable(): - pass - -CTypedef = TypeAlias - -class _CTypedef(CType): - position = frozenset({CType.PREFIX, CType.NAMED}) - def __init__(self, value=None): - self.CName = 'typedef' - super().__init__(value) - - -class CAuto(CType): - position = frozenset({CType.PREFIX}) - def __init__(self, value=None): - self.CName = 'auto' - super().__init__(value) - -class CRegister(CType): - position = frozenset({CType.PREFIX, CType.STORAGE_CLASS}) - def __init__(self, value=None): - self.CName = 'register' - super().__init__(value) - -class CStatic(CType): - position = frozenset({CType.PREFIX, CType.STORAGE_CLASS}) - def __init__(self, value=None): - self.CName = 'static' - super().__init__(value) - -class CExtern(CType): - position = frozenset({CType.PREFIX, CType.STORAGE_CLASS}) - def __init__(self, value=None): - self.CName = 'extern' - super().__init__(value) - -class CConst(CType): - position = frozenset({CType.PREFIX, CType.TYPE_QUALIFIER}) - def __init__(self, value=None): - self.CName = 'const' - super().__init__(value) - -class CInline(CType): - position = frozenset({CType.PREFIX, CType.STORAGE_CLASS}) - def __init__(self, value=None): - self.CName = 'inline' - super().__init__(value) - -class CExport(CType): - position = frozenset({CType.PREFIX, CType.STORAGE_CLASS}) - def __init__(self, value=None): - self.CName = 'export' - super().__init__(value) - -class CVolatile(CType): - position = frozenset({CType.PREFIX, CType.TYPE_QUALIFIER}) - def __init__(self, value=None): - self.CName = 'volatile' - super().__init__(value) - -class CSizeT(CType): - position = frozenset({CType.BASE}) - def __init__(self, value=None): - self.CName = 'size_t' - super().__init__(value) - self.IsSigned = False - self.Size = 64 - -class CInt8T(CType): - position = frozenset({CType.BASE}) - def __init__(self, value=None): - self.CName = 'int8_t' - super().__init__(value) - self.IsSigned = True - self.Size = 8 - -class CInt16T(CType): - position = frozenset({CType.BASE}) - def __init__(self, value=None): - self.CName = 'int16_t' - super().__init__(value) - self.IsSigned = True - self.Size = 16 - -class CInt32T(CType): - position = frozenset({CType.BASE}) - def __init__(self, value=None): - self.CName = 'int32_t' - super().__init__(value) - self.IsSigned = True - self.Size = 32 - -class CInt64T(CType): - position = frozenset({CType.BASE}) - def __init__(self, value=None): - self.CName = 'int64_t' - super().__init__(value) - self.IsSigned = True - self.Size = 64 - -class CUInt8T(CType): - position = frozenset({CType.BASE}) - def __init__(self, value=None): - self.CName = 'uint8_t' - super().__init__(value) - self.IsSigned = False - self.Size = 8 - -class CUInt16T(CType): - position = frozenset({CType.BASE}) - def __init__(self, value=None): - self.CName = 'uint16_t' - super().__init__(value) - self.IsSigned = False - self.Size = 16 - -class CUInt32T(CType): - position = frozenset({CType.BASE}) - def __init__(self, value=None): - self.CName = 'uint32_t' - super().__init__(value) - self.IsSigned = False - self.Size = 32 - -class CUInt64T(CType): - position = frozenset({CType.BASE}) - def __init__(self, value=None): - self.CName = 'uint64_t' - super().__init__(value) - self.IsSigned = False - self.Size = 64 - -class CIntPtrT(CType): - position = frozenset({CType.BASE}) - def __init__(self, value=None): - self.CName = 'intptr_t' - super().__init__(value) - self.IsSigned = True - self.Size = 64 - -class CUIntPtrT(CType): - position = frozenset({CType.BASE}) - def __init__(self, value=None): - self.CName = 'uintptr_t' - super().__init__(value) - self.IsSigned = False - self.Size = 64 - -class CPtrDiffT(CType): - position = frozenset({CType.BASE}) - def __init__(self, value=None): - self.CName = 'ptrdiff_t' - super().__init__(value) - self.IsSigned = True - self.Size = 64 - -class CWCharT(CType): - position = frozenset({CType.BASE}) - def __init__(self, value=None): - self.CName = 'wchar_t' - super().__init__(value) - self.IsSigned = True - self.Size = 32 - -class CChar8T(CType): - position = frozenset({CType.BASE}) - def __init__(self, value=None): - self.CName = 'char8_t' - super().__init__(value) - self.IsSigned = False - self.Size = 8 - -class CChar16T(CType): - position = frozenset({CType.BASE}) - def __init__(self, value=None): - self.CName = 'char16_t' - super().__init__(value) - self.IsSigned = False - self.Size = 16 - -class CChar32T(CType): - position = frozenset({CType.BASE}) - def __init__(self, value=None): - self.CName = 'char32_t' - super().__init__(value) - self.IsSigned = False - self.Size = 32 - -class CBool(CType): - position = frozenset({CType.BASE}) - def __init__(self, value=None): - self.CName = 'bool' - super().__init__(value) - self.IsSigned = False - self.Size = 8 - -class CComplex(CType): - position = frozenset({CType.BASE}) - def __init__(self, value=None): - self.CName = '_Complex' - super().__init__(value) - -class CImaginary(CType): - position = frozenset({CType.BASE}) - def __init__(self, value=None): - self.CName = '_Imaginary' - super().__init__(value) - -T = TypeVar("T") -Callable = Generic[T] - -class CPtr(CType, Generic[T]): - position = frozenset({CType.POINTER}) - def __init__(self, value=None): - self.CName = '*' - super().__init__(value) - -class CTypeDefault(CType): - """用于存储 C 类型默认值/初始化的包装类 - - 当使用 t.CStatic.__set_default__(open=mouse_open, ...) 时创建 - """ - def __init__(self, BaseType, **kwargs): - super().__init__() - self.BaseType = BaseType - self.defaults = kwargs - self.CName = BaseType.CName if hasattr(BaseType, 'CName') else '' - self.position = BaseType.position if hasattr(BaseType, 'position') else CType.BASE - - def __repr__(self): - return f'CTypeDefault({self.BaseType}, {self.defaults})' - -class CArrayPtr(CType): - position = frozenset({CType.POINTER}) - def __init__(self, value=None): - self.CName = '(*)' # 特殊标记表示数组指针 - super().__init__(value) - -class CDefine(CType): - position = frozenset({CType.BASE}) - def __init__(self, value=None): - self.CName = '#define' - super().__init__(value) - -class CPass(CType): - position = frozenset({CType.BASE}) - def __init__(self, value=None): - self.CName = '' - super().__init__(value) - -class State(CType): - """状态标记,用于仅声明不定义,等价于 CExport | CExtern""" - position = frozenset({CType.PREFIX}) - - @staticmethod - def HandleCall(translator, args, keywords): - """处理 t.State() 调用""" - return ['t.State'] - -class Anonymous: - def __init__(): - pass - -class Postdefinition: - def __init__(self, c): - pass - -class Bit: - def __init__(self, i): - pass - -class BigEndian(CType): - """大端序(Big-Endian)字节序标记类 - - 用于标记结构体成员应使用大端序存储。 - 在小端序平台(如x86)上读取时,会自动进行字节交换。 - - 用法示例: - class MyStruct: - a: t.CInt | t.BigEndian # 大端序存储的整数 - """ - IsSigned = True - Size = 4 - Align = 4 - -class LittleEndian(CType): - """小端序(Little-Endian)字节序标记类 - - 用于标记结构体成员应使用小端序存储。 - 在小端序平台(如x86)上读取时,不需要进行字节交换。 - - 用法示例: - class MyStruct: - b: t.CInt | t.LittleEndian # 小端序存储的整数 - """ - IsSigned = True - Size = 4 - Align = 4 - -class ASM_DESCR: - """内嵌 ASM 破坏描述符类 - - 定义了所有可能的破坏描述符和约束字符,用于 GCC 内嵌汇编 - """ - # 操作数修饰符 - MODIFIER_OUTPUT = '=' # 输出操作数 - MODIFIER_READWRITE = '+' # 读写操作数 - MODIFIER_INPUT = '' # 输入操作数(默认) - MODIFIER_GLOBAL = '&' # 全局操作数 - - # 寄存器约束(32位命名) - REG_ANY = 'r' # 任何通用寄存器 - REG_EAX = 'a' # EAX/RAX 寄存器 - REG_EBX = 'b' # EBX/RBX 寄存器 - REG_ECX = 'c' # ECX/RCX 寄存器 - REG_EDX = 'd' # EDX/RDX 寄存器 - REG_ESI = 'S' # ESI/RSI 寄存器 - REG_EDI = 'D' # EDI/RDI 寄存器 - REG_STACK = 'q' # 任何通用寄存器(EAX, EBX, ECX, EDX) - REG_FLOAT = 'f' # 浮点寄存器 - REG_MMX = 'y' # MMX 寄存器 - REG_XMM = 'x' # XMM 寄存器 - - # 寄存器约束(64位命名,GCC约束字符与32位相同) - REG_RAX = 'a' # RAX 寄存器 - REG_RBX = 'b' # RBX 寄存器 - REG_RCX = 'c' # RCX 寄存器 - REG_RDX = 'd' # RDX 寄存器 - REG_RSI = 'S' # RSI 寄存器 - REG_RDI = 'D' # RDI 寄存器 - REG_R8 = 'r' # R8 寄存器(需通过r约束+显式指定) - REG_R9 = 'r' # R9 寄存器 - REG_R10 = 'r' # R10 寄存器 - REG_R11 = 'r' # R11 寄存器 - REG_R12 = 'r' # R12 寄存器 - REG_R13 = 'r' # R13 寄存器 - REG_R14 = 'r' # R14 寄存器 - REG_R15 = 'r' # R15 寄存器 - REG_RBP = 'r' # RBP 寄存器 - REG_RSP = 'r' # RSP 寄存器 - - # 内存约束 - MEMORY = 'm' # 内存操作数 - - # 立即数约束 - IMMEDIATE = 'i' # 立即数 - IMMEDIATE_CONST = 'n' # 常量立即数 - - # 综合约束 - ANY = 'g' # 任何通用寄存器、内存或立即数 - MEMORY_OR_REG = 'o' # 内存或寄存器 - - # 破坏描述符(clobber list) - CLOBBER_EAX = 'eax' # 破坏 EAX/RAX 寄存器 - CLOBBER_EBX = 'ebx' # 破坏 EBX/RBX 寄存器 - CLOBBER_ECX = 'ecx' # 破坏 ECX/RCX 寄存器 - CLOBBER_EDX = 'edx' # 破坏 EDX/RDX 寄存器 - CLOBBER_ESI = 'esi' # 破坏 ESI/RSI 寄存器 - CLOBBER_EDI = 'edi' # 破坏 EDI/RDI 寄存器 - CLOBBER_EBP = 'ebp' # 破坏 EBP/RBP 寄存器 - CLOBBER_ESP = 'esp' # 破坏 ESP/RSP 寄存器 - CLOBBER_AL = 'al' # 破坏 AL 寄存器(EAX/RAX 低8位) - CLOBBER_AH = 'ah' # 破坏 AH 寄存器(EAX/RAX 高8位) - CLOBBER_BL = 'bl' # 破坏 BL 寄存器(EBX/RBX 低8位) - CLOBBER_BH = 'bh' # 破坏 BH 寄存器(EBX/RBX 高8位) - CLOBBER_CL = 'cl' # 破坏 CL 寄存器(ECX/RCX 低8位) - CLOBBER_CH = 'ch' # 破坏 CH 寄存器(ECX/RCX 高8位) - CLOBBER_DL = 'dl' # 破坏 DL 寄存器(EDX/RDX 低8位) - CLOBBER_DH = 'dh' # 破坏 DH 寄存器(EDX/RDX 高8位) - CLOBBER_CC = 'cc' # 破坏条件代码寄存器(标志寄存器) - CLOBBER_MEMORY = 'memory' # 破坏内存(表示汇编代码修改了内存) - # 16 位寄存器破坏描述符 - CLOBBER_AX = 'ax' # 破坏 AX 寄存器 - CLOBBER_BX = 'bx' # 破坏 BX 寄存器 - CLOBBER_CX = 'cx' # 破坏 CX 寄存器 - CLOBBER_DX = 'dx' # 破坏 DX 寄存器 - CLOBBER_SI = 'si' # 破坏 SI 寄存器 - CLOBBER_DI = 'di' # 破坏 DI 寄存器 - CLOBBER_BP = 'bp' # 破坏 BP 寄存器 - - # 64位寄存器破坏描述符 - CLOBBER_RAX = 'rax' # 破坏 RAX 寄存器 - CLOBBER_RBX = 'rbx' # 破坏 RBX 寄存器 - CLOBBER_RCX = 'rcx' # 破坏 RCX 寄存器 - CLOBBER_RDX = 'rdx' # 破坏 RDX 寄存器 - CLOBBER_RSI = 'rsi' # 破坏 RSI 寄存器 - CLOBBER_RDI = 'rdi' # 破坏 RDI 寄存器 - CLOBBER_RBP = 'rbp' # 破坏 RBP 寄存器 - CLOBBER_RSP = 'rsp' # 破坏 RSP 寄存器 - CLOBBER_R8 = 'r8' # 破坏 R8 寄存器 - CLOBBER_R9 = 'r9' # 破坏 R9 寄存器 - CLOBBER_R10 = 'r10' # 破坏 R10 寄存器 - CLOBBER_R11 = 'r11' # 破坏 R11 寄存器 - CLOBBER_R12 = 'r12' # 破坏 R12 寄存器 - CLOBBER_R13 = 'r13' # 破坏 R13 寄存器 - CLOBBER_R14 = 'r14' # 破坏 R14 寄存器 - CLOBBER_R15 = 'r15' # 破坏 R15 寄存器 - - # 预定义的组合约束(32位命名) - OUTPUT_REG = '=r' # 输出操作数,使用任何通用寄存器 - OUTPUT_MEM = '=m' # 输出操作数,使用内存 - OUTPUT_EAX = '=a' # 输出操作数,使用 EAX/RAX 寄存器 - OUTPUT_EBX = '=b' # 输出操作数,使用 EBX/RBX 寄存器 - OUTPUT_ECX = '=c' # 输出操作数,使用 ECX/RCX 寄存器 - OUTPUT_EDX = '=d' # 输出操作数,使用 EDX/RDX 寄存器 - OUTPUT_ESI = '=S' # 输出操作数,使用 ESI/RSI 寄存器 - OUTPUT_EDI = '=D' # 输出操作数,使用 EDI/RDI 寄存器 - - # 预定义的组合约束(64位命名) - OUTPUT_RAX = '=a' # 输出操作数,使用 RAX 寄存器 - OUTPUT_RBX = '=b' # 输出操作数,使用 RBX 寄存器 - OUTPUT_RCX = '=c' # 输出操作数,使用 RCX 寄存器 - OUTPUT_RDX = '=d' # 输出操作数,使用 RDX 寄存器 - OUTPUT_RSI = '=S' # 输出操作数,使用 RSI 寄存器 - OUTPUT_RDI = '=D' # 输出操作数,使用 RDI 寄存器 - - INPUT_REG = 'r' # 输入操作数,使用任何通用寄存器 - INPUT_MEM = 'm' # 输入操作数,使用内存 - INPUT_EAX = 'a' # 输入操作数,使用 EAX/RAX 寄存器 - INPUT_EBX = 'b' # 输入操作数,使用 EBX/RBX 寄存器 - INPUT_ECX = 'c' # 输入操作数,使用 ECX/RCX 寄存器 - INPUT_EDX = 'd' # 输入操作数,使用 EDX/RDX 寄存器 - INPUT_ESI = 'S' # 输入操作数,使用 ESI/RSI 寄存器 - INPUT_EDI = 'D' # 输入操作数,使用 EDI/RDI 寄存器 - INPUT_IMM = 'i' # 输入操作数,使用立即数 - INPUT_ANY = 'g' # 输入操作数,使用任何通用寄存器、内存或立即数 - - # 输入约束(64位命名) - INPUT_RAX = 'a' # 输入操作数,使用 RAX 寄存器 - INPUT_RBX = 'b' # 输入操作数,使用 RBX 寄存器 - INPUT_RCX = 'c' # 输入操作数,使用 RCX 寄存器 - INPUT_RDX = 'd' # 输入操作数,使用 RDX 寄存器 - INPUT_RSI = 'S' # 输入操作数,使用 RSI 寄存器 - INPUT_RDI = 'D' # 输入操作数,使用 RDI 寄存器 - - # 所有单独约束字符列表 - ALL_CONSTRAINTS = [ - # 操作数修饰符 - MODIFIER_OUTPUT, MODIFIER_READWRITE, MODIFIER_INPUT, MODIFIER_GLOBAL, - - # 寄存器约束 - REG_ANY, REG_EAX, REG_EBX, REG_ECX, REG_EDX, REG_ESI, REG_EDI, - REG_STACK, REG_FLOAT, REG_MMX, REG_XMM, - - # 内存约束 - MEMORY, - - # 立即数约束 - IMMEDIATE, IMMEDIATE_CONST, - - # 综合约束 - ANY, MEMORY_OR_REG - ] - - # 所有破坏描述符列表 - ALL_CLOBBERS = [ - CLOBBER_EAX, CLOBBER_EBX, CLOBBER_ECX, CLOBBER_EDX, - CLOBBER_ESI, CLOBBER_EDI, CLOBBER_EBP, CLOBBER_ESP, - CLOBBER_CC, CLOBBER_MEMORY, - CLOBBER_RAX, CLOBBER_RBX, CLOBBER_RCX, CLOBBER_RDX, - CLOBBER_RSI, CLOBBER_RDI, CLOBBER_RBP, CLOBBER_RSP, - CLOBBER_R8, CLOBBER_R9, CLOBBER_R10, CLOBBER_R11, - CLOBBER_R12, CLOBBER_R13, CLOBBER_R14, CLOBBER_R15 - ] - - # 所有描述符列表 - ALL = ALL_CONSTRAINTS + ALL_CLOBBERS - - -# 定义 ASM_LIST,包含所有可能的汇编约束字符 -ASM_LIST = ASM_DESCR.ALL - - -class attr: - """C 语言 __attribute__ 属性操作类型""" - - @staticmethod - def noreturn(): - return "noreturn" - - @staticmethod - def format(printf, arg1, arg2): - return f"format({printf}, {arg1}, {arg2})" - - @staticmethod - def section(name): - return f'section("{name}")' - - @staticmethod - def aligned(bytes): - return f"aligned({bytes})" - - @staticmethod - def packed(): - return "packed" - - @staticmethod - def unused(): - return "unused" - - @staticmethod - def used(): - return "used" - - @staticmethod - def weak(): - return "weak" - - @staticmethod - def alias(name): - return f'alias("{name}")' - - @staticmethod - def visibility(type): - return f'visibility("{type}")' - - @staticmethod - def constructor(): - return "constructor" - - @staticmethod - def destructor(): - return "destructor" - - @staticmethod - def always_inline(): - return "always_inline" - - @staticmethod - def noinline(): - return "noinline" - - @staticmethod - def pure(): - return "pure" - - @staticmethod - def const(): - return "const" - - @staticmethod - def malloc(): - return "malloc" - - @staticmethod - def alloc_size(n): - return f"alloc_size({n})" - - @staticmethod - def warn_unused_result(): - return "warn_unused_result" - - @staticmethod - def deprecated(msg=None): - if msg: - return f'deprecated("{msg}")' - return "deprecated" - - @staticmethod - def fallthrough(): - return "fallthrough" - - @staticmethod - def likely(): - return "likely" - - @staticmethod - def unlikely(): - return "unlikely" - - @staticmethod - def hot(): - return "hot" - - @staticmethod - def cold(): - return "cold" - - @staticmethod - def interrupt(): - return "interrupt" - - @staticmethod - def naked(): - return "naked" - - @staticmethod - def sentinel(n=0): - return f"sentinel({n})" - - @staticmethod - def nonnull(*args): - if args: - return f"nonnull({', '.join(map(str, args))})" - return "nonnull" - - @staticmethod - def returns_nonnull(): - return "returns_nonnull" - - @staticmethod - def access(mode, *args): - return f"access({mode}, {', '.join(map(str, args))})" - - @staticmethod - def cleanup(func): - return f'cleanup({func})' - - @staticmethod - def transparent_union(): - return "transparent_union" - - @staticmethod - def mode(mode_name): - return f"mode({mode_name})" - - @staticmethod - def vector_size(bytes): - return f"vector_size({bytes})" - - @staticmethod - def target(string): - return f'target("{string}")' - - @staticmethod - def optimize(level): - return f'optimize("{level}")' - - @staticmethod - def no_instrument_function(): - return "no_instrument_function" - - @staticmethod - def no_sanitize(type): - return f"no_sanitize({type})" - - @staticmethod - def no_stack_protector(): - return "no_stack_protector" - - @staticmethod - def stack_protector(): - return "stack_protector" - - @staticmethod - def error(msg): - return f'error("{msg}")' - - @staticmethod - def warning(msg): - return f'warning("{msg}")' - - class llvm: - """LLVM 函数属性描述符 - - 用于在返回类型注解中指定 LLVM 函数属性。 - 例如: def foo() -> t.CInt | t.attr.llvm.nobuiltin | t.attr.llvm.nounwind: - """ - - class nobuiltin: - CName = '#attr.llvm.nobuiltin' - - class nounwind: - CName = '#attr.llvm.nounwind' - - class noredzone: - CName = '#attr.llvm.noredzone' - - class willreturn: - CName = '#attr.llvm.willreturn' - - class mustprogress: - CName = '#attr.llvm.mustprogress' - - class optnone: - CName = '#attr.llvm.optnone' - - class noinline: - CName = '#attr.llvm.noinline' - - class alwaysinline: - CName = '#attr.llvm.alwaysinline' - - class readnone: - CName = '#attr.llvm.readnone' - - class readonly: - CName = '#attr.llvm.readonly' - - class writeonly: - CName = '#attr.llvm.writeonly' - - class inaccessiblememonly: - CName = '#attr.llvm.inaccessiblememonly' - - class inaccessiblemem_or_argmemonly: - CName = '#attr.llvm.inaccessiblemem_or_argmemonly' - - -def NewCType(size, signed): - ct = CType() - ct.Size = size - ct.IsSigned = signed - return ct - -i1 = NewCType(1, True) -i8 = NewCType(8, True) -i16 = NewCType(16, True) -i32 = NewCType(32, True) -i64 = NewCType(64, True) - -u1 = NewCType(1, False) -u8 = NewCType(8, False) -u16 = NewCType(16, False) -u32 = NewCType(32, False) -u64 = NewCType(64, False) - - -class CTypeRegistry: - """基于 CType 元属性的类型注册表,替代手动映射表 - - 利用 CType 子类的 position/IsSigned/Size 元属性自动推导: - - LLVM IR 类型字符串 (如 'i32', 'double', 'i8*') - - C 类型名称 (如 'int', 'unsigned char', 'long long') - - Python CType 类引用 (如 t.CInt32T) - """ - - _name_to_class = None - _cname_to_class = None - - @classmethod - def _build(cls): - if cls._name_to_class is not None: - return - import sys - mod = sys.modules.get(__name__) - if mod is None: - return - cls._name_to_class = {} - cls._cname_to_class = {} - for name, obj in vars(mod).items(): - if not isinstance(obj, type) or not issubclass(obj, CType) or obj is CType: - continue - if obj in (CTypeDefault, BigEndian, LittleEndian): - continue - try: - inst = obj() - except Exception: - continue - pos = getattr(obj, 'position', frozenset()) - if CType.PREFIX in pos and CType.BASE not in pos: - continue - if CType.POINTER in pos and CType.BASE not in pos: - cls._name_to_class[name] = obj - continue - if getattr(inst, 'Size', None) is not None or getattr(inst, 'CName', ''): - cls._name_to_class[name] = obj - cname = getattr(inst, 'CName', '') - if cname and cname not in cls._cname_to_class: - cls._cname_to_class[cname] = obj - - @classmethod - def GetClassByName(cls, name: str): - """根据 Python 类名获取 CType 类 (如 'CInt32T' -> t.CInt32T)""" - cls._build() - return cls._name_to_class.get(name) - - @classmethod - def GetClassByCName(cls, cname: str): - """根据 C 类型名获取 CType 类 (如 'int32_t' -> t.CInt32T)""" - cls._build() - return cls._cname_to_class.get(cname) - - @staticmethod - def CTypeToLLVM(ctype_class) -> str: - """从 CType 类的元属性推导 LLVM IR 类型字符串 - - 规则: - - position 含 POINTER 且不含 BASE → 'i8*' - - position 含 PREFIX 且不含 BASE → '' (修饰符,无LLVM类型) - - Size == 0 且 IsSigned is None → 'void' - - IsSigned is None 且 Size > 0 → 浮点: half/float/double/fp128 - - IsSigned is True/False 且 Size > 0 → 整数: i{Size} - """ - if ctype_class is None: - return 'i8*' - pos = getattr(ctype_class, 'position', frozenset()) - if CType.POINTER in pos and CType.BASE not in pos: - return 'i8*' - if CType.PREFIX in pos and CType.BASE not in pos: - return '' - try: - inst = ctype_class() - except Exception: - return 'i8*' - size = getattr(inst, 'Size', None) - is_signed = getattr(inst, 'IsSigned', None) - if size is None or size == 0: - if is_signed is None: - return 'void' - return 'i8*' - if is_signed is None: - float_map = {8: 'half', 16: 'half', 32: 'float', 64: 'double', 128: 'fp128'} - return float_map.get(size, f'f{size}') - return f'i{size}' - - @staticmethod - def CTypeToCName(ctype_class) -> str: - """从 CType 类推导 C 类型名称 (用于 printf 格式化等) - - 规则: - - IsSigned is None 且 Size > 0 → 浮点: float/double/long double - - IsSigned is True → 有符号整数: char/short/int/long long - - IsSigned is False → 无符号整数: unsigned char/unsigned short/unsigned int/unsigned long long - """ - if ctype_class is None: - return '' - try: - inst = ctype_class() - except Exception: - return '' - size = getattr(inst, 'Size', None) - is_signed = getattr(inst, 'IsSigned', None) - if size is None: - return '' - if is_signed is None and size > 0: - float_cname = {32: 'float', 64: 'double', 128: 'long double'} - return float_cname.get(size, 'double') - int_cname_signed = {8: 'char', 16: 'short', 32: 'int', 64: 'long long'} - int_cname_unsigned = {8: 'unsigned char', 16: 'unsigned short', 32: 'unsigned int', 64: 'unsigned long long'} - if is_signed: - return int_cname_signed.get(size, 'int') - else: - return int_cname_unsigned.get(size, 'unsigned int') - - @classmethod - def NameToLLVM(cls, name: str) -> str: - """根据 Python 类型名推导 LLVM IR 类型 (如 'CFloat64T' -> 'double') - - 修饰符类型 (CConst, CStatic 等) 返回空字符串。 - 指针类型 (CPtr) 返回 'i8*'。 - 未知类型返回 None。 - """ - cls._build() - import sys - mod = sys.modules.get(__name__) - if mod and hasattr(mod, name): - obj = getattr(mod, name) - if isinstance(obj, type) and issubclass(obj, CType): - return cls.CTypeToLLVM(obj) - return None - - @classmethod - def NameToCName(cls, name: str) -> str: - """根据 Python 类型名推导 C 类型名 (如 'CInt32T' -> 'int')""" - ctype_class = cls.GetClassByName(name) - if ctype_class is not None: - return cls.CTypeToCName(ctype_class) - return None - - @classmethod - def CNameToClass(cls, cname: str): - """根据 C 类型名获取 CType 类 (如 'int32_t' -> t.CInt32T, 'unsigned char' -> t.CUnsignedChar)""" - cls._build() - return cls._cname_to_class.get(cname) - - @classmethod - def ResolveName(cls, name: str): - """解析类型名到 (CType类, 指针层级) - - 支持的格式: - - Python 类名: 'CInt32T' -> (t.CInt32T, 0) - - C 类型名: 'int32_t' -> (t.CInt32T, 0) - - stdint 大写别名: 'INT32' -> (t.CInt32T, 0) - - 指针别名: 'INT32PTR' -> (t.CInt32T, 1) - - 大写别名: 'BYTE' -> (t.CUnsignedChar, 0), 'DWORD' -> (t.CUInt32T, 0) - - 浮点别名: 'FLOAT64' -> (t.CFloat64T, 0) - - void指针: 'VOIDPTR' -> (t.CVoid, 1) - """ - cls._build() - direct = cls._name_to_class.get(name) - if direct is not None: - pos = getattr(direct, 'position', frozenset()) - ptr_level = 1 if CType.POINTER in pos and CType.BASE not in pos else 0 - return (direct, ptr_level) - cnameres = cls._cname_to_class.get(name) - if cnameres is not None: - return (cnameres, 0) - if name.endswith('PTR'): - base_name = name[:-3] - base_result = cls.ResolveName(base_name) - if base_result is not None: - return (base_result[0], base_result[1] + 1) - if name.startswith('FLOAT') and name[5:].isdigit(): - bits = int(name[5:]) - float_name = f'CFloat{bits}T' - float_cls = cls._name_to_class.get(float_name) - if float_cls is not None: - return (float_cls, 0) - _UPPER_ALIAS = { - 'BYTE': 'CUInt8T', 'INT8': 'CInt8T', 'UINT8': 'CUInt8T', - 'WORD': 'CUInt16T', 'INT16': 'CInt16T', 'UINT16': 'CUInt16T', - 'DWORD': 'CUInt32T', 'INT32': 'CInt32T', 'UINT32': 'CUInt32T', - 'UINT': 'CUnsignedInt', 'INT': 'CInt', - 'QWORD': 'CUInt64T', 'INT64': 'CInt64T', 'UINT64': 'CUInt64T', - 'INTPTR': 'CIntPtrT', 'UINTPTR': 'CUIntPtrT', - 'SIZE_T': 'CSizeT', 'SSIZE_T': 'CPtrDiffT', 'PTRDIFF_T': 'CPtrDiffT', - 'VOID': 'CVoid', - } - alias = _UPPER_ALIAS.get(name) - if alias: - alias_cls = cls._name_to_class.get(alias) - if alias_cls is not None: - return (alias_cls, 0) - return None - - -_build_type_maps() \ No newline at end of file diff --git a/Projectrans.py b/Projectrans.py index 0b8f3d4..7a86880 100644 --- a/Projectrans.py +++ b/Projectrans.py @@ -1,3742 +1,24 @@ #!/usr/bin/env python3 -""" -ProjectTrans.py - 工程级 TransPyC 翻译器 - -两阶段翻译流程: - 阶段一:从源文件生成声明接口 .pyi(仅有签名)和 .stub.ll(仅有声明) - 阶段二:使用声明接口翻译源文件,嵌入 .stub.ll 声明,生成含代码的 .ll 并编译为 .obj - -SHA1 = SHA1(source file content) -""" - +"""ProjectTrans.py - 工程级 TransPyC 翻译器""" import sys import os -import re -import hashlib -import shutil -from typing import List -import subprocess -import tempfile -import ast -import traceback -import json -from lib.core.Handles.HandlesBase import CTypeInfo -from lib.includes import t -from pathlib import Path - sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) -import TransPyC -from StubGen import PythonToStubConverter -from lib.core.logger import Logger, LogLevel, set_logger - -# 创建全局日志实例 -logger = Logger( - name="TransPyC", - log_file="build.log", - level=LogLevel.INFO, - use_colors=True +from lib.Projectrans import ( + compute_sha1, _check_annotation_for_export, sha1_file, + get_file_dependencies, find_reachable_files_from_entries, + topological_sort_files, Phase1Generator, DeclarationGenerator, + Phase2Translator, _parallel_translate_worker, + save_sha1_map, Load_sha1_map, Load_project_config, resolve_paths, main ) -set_logger(logger) - - -def compute_sha1(content: str) -> str: - return hashlib.sha1(content.encode('utf-8')).hexdigest()[:16] - - -def _check_annotation_for_export(annotation) -> bool: - """递归检查类型注解中是否包含 CExport""" - if annotation is None: - return False - if isinstance(annotation, ast.Attribute): - if hasattr(annotation, 'attr') and annotation.attr == 'CExport': - return True - elif isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr): - return _check_annotation_for_export(annotation.left) or _check_annotation_for_export(annotation.right) - elif isinstance(annotation, ast.Name): - return annotation.id == 'CExport' - return False - - -def sha1_file(filepath: str) -> str: - with open(filepath, 'r', encoding='utf-8') as f: - content = f.read() - return compute_sha1(content) - - -def get_file_dependencies(filepath: str, src_root: str) -> set: - """解析 Python 文件的导入依赖""" - dependencies = set() - try: - with open(filepath, 'r', encoding='utf-8') as f: - content = f.read() - tree = ast.parse(content) - for node in ast.walk(tree): - if isinstance(node, ast.Import): - for alias in node.names: - module = alias.name - dependencies.add(module) - elif isinstance(node, ast.ImportFrom): - if node.module: - module = node.module - if node.level > 0: - # from .module import name → 依赖 pkg.module(模块本身) - pkg_dir = os.path.dirname(filepath) - pkg_rel = os.path.relpath(pkg_dir, src_root).replace(os.sep, '.').replace('/', '.') - if pkg_rel == '.': - pkg_rel = '' - if pkg_rel: - dep_module = f'{pkg_rel}.{module}' - else: - dep_module = module - dependencies.add(dep_module) - else: - if not module.startswith('_'): - dependencies.add(module) - elif node.level > 0 and node.names: - # from . import name → 依赖 pkg.name(子模块) - for alias in node.names: - pkg_dir = os.path.dirname(filepath) - pkg_rel = os.path.relpath(pkg_dir, src_root).replace(os.sep, '.').replace('/', '.') - if pkg_rel == '.': - pkg_rel = '' - dep_module = f'{pkg_rel}.{alias.name}' if pkg_rel else alias.name - dependencies.add(dep_module) - except Exception: - pass - return dependencies - - -def find_reachable_files_from_entries(src_root: str, entry_files: list) -> set: - """从入口文件出发,找出所有可达的 .py 文件(通过导入关系)""" - all_files = {} # module_name -> filepath - for root, dirs, files in os.walk(src_root): - dirs[:] = [d for d in dirs if d not in ('__pycache__',)] - for file in files: - if file.endswith('.py'): - filepath = os.path.join(root, file) - rel = os.path.relpath(filepath, src_root) - module = os.path.splitext(rel)[0].replace(os.sep, '.').replace('/', '.') - if filepath.endswith('__init__.py'): - all_files[module] = filepath - parent_module = module.rsplit('.', 1)[0] if '.' in module else module - if parent_module not in all_files or not all_files[parent_module].endswith('__init__.py'): - all_files[parent_module] = filepath - elif module not in all_files: - all_files[module] = filepath - top_module = module.split('.')[0] - if top_module not in all_files: - all_files[top_module] = filepath - - reachable = set() - queue = list(entry_files) - - while queue: - current = queue.pop(0) - if current in reachable: - continue - reachable.add(current) - deps = get_file_dependencies(current, src_root) - for dep in deps: - if dep in all_files and all_files[dep] not in reachable: - queue.append(all_files[dep]) - else: - for key, val in all_files.items(): - if key.endswith('.' + dep) or key == dep: - if val not in reachable: - queue.append(val) - break - - return reachable - - -def topological_sort_files(py_files: list, src_root: str) -> list: - """对 Python 文件进行拓扑排序,确保依赖模块先被处理""" - # 构建模块名到文件路径的映射 - module_to_file = {} - for filepath in py_files: - rel = os.path.relpath(filepath, src_root) - module = os.path.splitext(rel)[0].replace(os.sep, '.').replace('/', '.') - module_to_file[module] = filepath - # 也添加顶层模块名 - top_module = module.split('.')[0] - if top_module not in module_to_file: - module_to_file[top_module] = filepath - - # 构建依赖图 - graph = {f: set() for f in py_files} - for filepath in py_files: - deps = get_file_dependencies(filepath, src_root) - for dep in deps: - if dep in module_to_file: - dep_file = module_to_file[dep] - if dep_file != filepath: # 避免自依赖 - graph[filepath].add(dep_file) - - # 拓扑排序 (Kahn's algorithm) - in_degree = {f: 0 for f in py_files} - for f, deps in graph.items(): - for dep in deps: - if dep in in_degree: - in_degree[f] += 1 - - queue = [f for f, degree in in_degree.items() if degree == 0] - sorted_files = [] - - while queue: - # 按字母顺序处理同级别的文件,确保确定性 - queue.sort() - current = queue.pop(0) - sorted_files.append(current) - - for f, deps in graph.items(): - if current in deps: - in_degree[f] -= 1 - if in_degree[f] == 0: - queue.append(f) - - # 如果有环,添加剩余文件 - if len(sorted_files) < len(py_files): - remaining = [f for f in py_files if f not in sorted_files] - sorted_files.extend(remaining) - - return sorted_files - - -class Phase1Generator: - """阶段一:从源文件生成声明接口""" - - def __init__(self, src_root: str, temp_dir: str, include_dirs: list = None, entry_files: list = None, target_triple: str = None, target_datalayout: str = None): - self.src_root = os.path.abspath(src_root) - self.temp_dir = os.path.abspath(temp_dir) - self.include_dirs = include_dirs or [] - self.sha1_map: dict[str, str] = {} - self.include_py_map: dict[str, str] = {} - self.entry_files = entry_files - self.target_triple = target_triple - self.target_datalayout = target_datalayout - os.makedirs(self.temp_dir, exist_ok=True) - - def _get_needed_include_files(self, reachable_source_files: set) -> list: - """从可达源文件收集所有被引用(含传递依赖)的 include 文件""" - include_file_map = {} - for includes_dir in self.include_dirs: - if not os.path.isdir(includes_dir): - continue - for root, dirs, files in os.walk(includes_dir): - dirs[:] = [d for d in dirs if not d.startswith('.') and d != '__pycache__'] - for fname in files: - if fname.endswith('.py') or fname.endswith('.pyi'): - src_path = os.path.join(root, fname) - rel_from_inc = os.path.relpath(src_path, includes_dir) - module_path = rel_from_inc.replace(os.sep, '.').replace('/', '.') - module_name = os.path.splitext(module_path)[0] - info = (src_path, rel_from_inc, includes_dir) - include_file_map[module_name] = info - top_pkg = module_name.split('.')[0] - if top_pkg not in include_file_map: - include_file_map[top_pkg] = info - - imported_from_src = set() - for src_path in reachable_source_files: - deps = get_file_dependencies(src_path, self.src_root) - imported_from_src.update(deps) - - needed = set() - queue = list(imported_from_src) - while queue: - mod_name = queue.pop(0) - if mod_name in needed: - continue - if mod_name in include_file_map: - needed.add(mod_name) - src_path = include_file_map[mod_name][0] - includes_dir = include_file_map[mod_name][2] - deps = get_file_dependencies(src_path, includes_dir) - for dep in deps: - if dep in include_file_map and dep not in needed: - queue.append(dep) - - needed_infos = [] - for mod_name in sorted(needed): - if mod_name in include_file_map: - info = include_file_map[mod_name] - if info not in needed_infos: - needed_infos.append(info) - - return needed_infos - - def run(self): - """扫描源目录,只处理入口文件可达的 .py 文件(导入遍历)""" - if self.entry_files: - py_files = list(self.entry_files) - else: - main_py = os.path.join(self.src_root, 'main.py') - if os.path.exists(main_py): - py_files = [main_py] - else: - py_files = [] - for root, dirs, files in os.walk(self.src_root): - dirs[:] = [d for d in dirs if d not in ('__pycache__',)] - for file in files: - if file.endswith('.py'): - py_files.append(os.path.join(root, file)) - - if not py_files: - print("[阶段一] 未找到入口文件或源文件") - return - - if self.entry_files: - reachable = find_reachable_files_from_entries(self.src_root, py_files) - else: - reachable = find_reachable_files_from_entries(self.src_root, py_files) - - print(f"[阶段一] 找到 {len(reachable)} 个可达源文件(从入口遍历)") - - for i, src_path in enumerate(sorted(reachable), 1): - rel = os.path.relpath(src_path, self.src_root) - print(f"[{i}/{len(reachable)}] 生成签名: {rel}") - try: - self._process_file_pyi(src_path, rel) - except Exception as e: - print(f" [错误] {e}") - traceback.print_exc() - - needed_includes = self._get_needed_include_files(reachable) - self._process_include_py_files_pyi(needed_includes) - - struct_names, enum_names, struct_sha1_map, exception_names = self._build_struct_registry() - print(f"\n[阶段一] 结构体注册表: {len(struct_names)} 个类型, {len(enum_names)} 个枚举") - for name in sorted(struct_names): - print(f" {name}") - - for i, src_path in enumerate(sorted(reachable), 1): - rel = os.path.relpath(src_path, self.src_root) - try: - self._process_file_stub(src_path, rel, struct_names, enum_names=enum_names, struct_sha1_map=struct_sha1_map, exception_names=exception_names) - except Exception as e: - print(f" [错误] {e}") - traceback.print_exc() - - self._process_include_py_files_stub(struct_names, needed_includes, enum_names=enum_names, struct_sha1_map=struct_sha1_map, exception_names=exception_names) - - print(f"\n[阶段一完成] 声明接口生成到: {self.temp_dir}") - print(f"SHA1 映射表 ({len(self.sha1_map)} 个文件):") - for sha1, rel in sorted(self.sha1_map.items()): - print(f" {sha1} -> {rel}") - - def _collect_include_py_files(self): - include_py_files = [] - for includes_dir in self.include_dirs: - if not os.path.isdir(includes_dir): - continue - for root, dirs, files in os.walk(includes_dir): - dirs[:] = [d for d in dirs if not d.startswith('.') and d != '__pycache__'] - for fname in files: - if fname.endswith('.py') or fname.endswith('.pyi'): - src_path = os.path.join(root, fname) - rel_from_inc = os.path.relpath(src_path, includes_dir) - include_py_files.append((src_path, rel_from_inc, includes_dir)) - return include_py_files - - def _process_include_py_files_pyi(self, needed_includes: list = None): - if needed_includes is not None: - include_py_files = needed_includes - else: - include_py_files = self._collect_include_py_files() - if not include_py_files: - return - print(f"\n[阶段一-includes] 处理 {len(include_py_files)} 个被引用的 Python 库文件") - for src_path, rel_from_inc, includes_dir in include_py_files: - module_path = rel_from_inc.replace(os.sep, '.').replace('/', '.') - module_name = os.path.splitext(module_path)[0] - try: - with open(src_path, 'r', encoding='utf-8') as f: - content = f.read() - sha1 = compute_sha1(content) - self.sha1_map[sha1] = f"includes/{rel_from_inc}" - top_module = rel_from_inc.split(os.sep)[0].split('/')[0] - if top_module not in self.include_py_map: - self.include_py_map[top_module] = sha1 - self.include_py_map[module_name] = sha1 - - sig_path = os.path.join(self.temp_dir, f"{sha1}.pyi") - if os.path.isfile(sig_path): - print(f" 缓存命中: {rel_from_inc} -> {sha1}.pyi") - continue - - sig_content = PythonToStubConverter.convert(content, module_name) - with open(sig_path, 'w', encoding='utf-8', newline='\n') as f: - f.write(sig_content) - print(f" 生成签名: {rel_from_inc} -> {sha1}.pyi") - except Exception as e: - print(f" [错误] {rel_from_inc}: {e}") - - def _collect_typedef_map(self): - import ast as _ast - typedef_map = {} - if not os.path.isdir(self.temp_dir): - return typedef_map - for fname in os.listdir(self.temp_dir): - if not fname.endswith('.pyi'): - continue - pyi_path = os.path.join(self.temp_dir, fname) - try: - with open(pyi_path, 'r', encoding='utf-8') as f: - content = f.read() - tree = _ast.parse(content) - for node in _ast.iter_child_nodes(tree): - if isinstance(node, _ast.AnnAssign) and isinstance(node.target, _ast.Name): - var_name = node.target.id - is_typedef = False - if isinstance(node.annotation, _ast.Attribute) and hasattr(node.annotation, 'attr') and node.annotation.attr == 'CTypedef': - is_typedef = True - elif isinstance(node.annotation, _ast.Name) and node.annotation.id == 'CTypedef': - is_typedef = True - elif isinstance(node.annotation, _ast.BinOp) and isinstance(node.annotation.left, _ast.Attribute) and hasattr(node.annotation.left, 'attr') and node.annotation.left.attr == 'CTypedef': - is_typedef = True - if is_typedef and node.value and var_name not in typedef_map: - typedef_map[var_name] = node.value - except Exception: - pass - return typedef_map - - def _process_include_py_files_stub(self, struct_names: set, needed_includes: list = None, enum_names: set = None, struct_sha1_map: dict = None, exception_names: set = None): - if needed_includes is not None: - include_py_files = needed_includes - else: - include_py_files = self._collect_include_py_files() - if not include_py_files: - return - typedef_map = self._collect_typedef_map() - for src_path, rel_from_inc, includes_dir in include_py_files: - module_path = rel_from_inc.replace(os.sep, '.').replace('/', '.') - module_name = os.path.splitext(module_path)[0] - try: - with open(src_path, 'r', encoding='utf-8') as f: - content = f.read() - sha1 = compute_sha1(content) - - stub_path = os.path.join(self.temp_dir, f"{sha1}.stub.ll") - if os.path.isfile(stub_path): - print(f" 缓存命中: {rel_from_inc} -> {sha1}.stub.ll") - continue - - sig_path = os.path.join(self.temp_dir, f"{sha1}.pyi") - with open(sig_path, 'r', encoding='utf-8') as f: - sig_content = f.read() - - self._generate_decl_ll(sig_content, stub_path, src_path, struct_names, enum_names=enum_names, module_sha1=sha1, struct_sha1_map=struct_sha1_map, exception_names=exception_names, typedef_map=typedef_map) - print(f" 生成声明: {rel_from_inc} -> {sha1}.stub.ll") - except Exception as e: - print(f" [错误] {rel_from_inc}: {e}") - - def _process_file_pyi(self, src_path: str, rel_path: str): - with open(src_path, 'r', encoding='utf-8') as f: - content = f.read() - - sha1 = compute_sha1(content) - self.sha1_map[sha1] = rel_path - - sig_path = os.path.join(self.temp_dir, f"{sha1}.pyi") - if os.path.isfile(sig_path): - print(f" -> {sha1}.pyi (缓存)") - return - - module_name = os.path.splitext(rel_path)[0].replace(os.sep, '.').replace('/', '.') - sig_content = PythonToStubConverter.convert(content, module_name) - with open(sig_path, 'w', encoding='utf-8', newline='\n') as f: - f.write(sig_content) - print(f" -> {sha1}.pyi (签名)") - - def _process_file_stub(self, src_path: str, rel_path: str, struct_names: set, enum_names: set = None, struct_sha1_map: dict = None, exception_names: set = None): - with open(src_path, 'r', encoding='utf-8') as f: - content = f.read() - - sha1 = compute_sha1(content) - stub_path = os.path.join(self.temp_dir, f"{sha1}.stub.ll") - if os.path.isfile(stub_path): - print(f" -> {sha1}.stub.ll (缓存)") - return - - sig_path = os.path.join(self.temp_dir, f"{sha1}.pyi") - with open(sig_path, 'r', encoding='utf-8') as f: - sig_content = f.read() - - typedef_map = self._collect_typedef_map() - self._generate_decl_ll(sig_content, stub_path, src_path, struct_names, enum_names=enum_names, module_sha1=sha1, struct_sha1_map=struct_sha1_map, exception_names=exception_names, typedef_map=typedef_map) - print(f" -> {sha1}.stub.ll (声明)") - - def _build_struct_registry(self): - struct_names = set() - enum_names = set() - exception_names = set() - struct_sha1_map = {} - valid_sha1_keys = set(self.sha1_map.keys()) - for fname in os.listdir(self.temp_dir): - if not fname.endswith('.pyi'): - continue - sha1_key = fname.replace('.pyi', '') - if sha1_key not in valid_sha1_keys: - continue - pyi_path = os.path.join(self.temp_dir, fname) - try: - with open(pyi_path, 'r', encoding='utf-8') as f: - content = f.read() - tree = ast.parse(content) - for node in ast.iter_child_nodes(tree): - if isinstance(node, ast.ClassDef): - is_enum = False - is_exception = False - if node.bases: - for base in node.bases: - if isinstance(base, ast.Attribute) and hasattr(base, 'attr'): - if base.attr in ('CEnum', 'Enum'): - is_enum = True - break - elif base.attr == 'Exception' or base.attr in exception_names: - is_exception = True - break - elif isinstance(base, ast.Name) and hasattr(base, 'id'): - if base.id in ('CEnum', 'Enum'): - is_enum = True - break - elif base.id == 'Exception' or base.id in exception_names: - is_exception = True - break - if is_enum: - enum_names.add(node.name) - elif is_exception: - exception_names.add(node.name) - else: - struct_names.add(node.name) - struct_sha1_map[node.name] = sha1_key - except Exception: - pass - return struct_names, enum_names, struct_sha1_map, exception_names - - def _generate_decl_ll(self, pyi_content: str, ll_path: str, src_path: str, struct_names: set = None, enum_names: set = None, module_sha1: str = None, struct_sha1_map: dict = None, exception_names: set = None, typedef_map: dict = None): - try: - decl_gen = DeclarationGenerator(struct_names=struct_names, enum_names=enum_names, module_sha1=module_sha1, target_triple=self.target_triple, target_datalayout=self.target_datalayout, struct_sha1_map=struct_sha1_map, exception_names=exception_names, typedef_map=typedef_map) - decl_ll = decl_gen.generate(pyi_content, src_path) - with open(ll_path, 'w', encoding='utf-8', newline='\n') as f: - f.write(decl_ll) - except Exception as e: - print(f" [警告] .ll 声明生成失败: {e}") - with open(ll_path, 'w', encoding='utf-8') as f: - f.write(f"; declaration for {os.path.basename(src_path)}\n; error: {e}\n") - - -class DeclarationGenerator: - """从 .pyi AST 生成纯 LLVM IR 声明(不使用字符串操作)""" - - def __init__(self, struct_names=None, enum_names=None, module_sha1=None, target_triple=None, target_datalayout=None, struct_sha1_map=None, exception_names=None, typedef_map=None): - import llvmlite.ir as ir - self.ir = ir - self.module = None - self.builder = None - self._define_constants = {} - self.struct_names = struct_names or set() - self.enum_names = enum_names or set() - self.module_sha1 = module_sha1 - self.struct_sha1_map = struct_sha1_map or {} - self.exception_names = exception_names or set() - self.target_triple = target_triple or "x86_64-none-elf" - self.target_datalayout = target_datalayout or "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" - self.typedef_map = typedef_map or {} - t.configure_platform(self.target_triple) - - def generate(self, pyi_content: str, src_path: str) -> str: - import ast - tree = ast.parse(pyi_content) - - self._define_constants = {} - self._pyi_tree = tree - global_typedef_map = self.typedef_map - self.typedef_map = {} - if global_typedef_map: - self.typedef_map.update(global_typedef_map) - for node in ast.iter_child_nodes(tree): - if isinstance(node, ast.AnnAssign) and isinstance(node.target, ast.Name): - var_name = node.target.id - if node.value and isinstance(node.value, ast.Constant): - self._define_constants[var_name] = node.value.value - elif node.value and isinstance(node.value, ast.Name): - self._define_constants[var_name] = node.value.id - is_typedef = False - if isinstance(node.annotation, ast.Attribute) and hasattr(node.annotation, 'attr') and node.annotation.attr == 'CTypedef': - is_typedef = True - elif isinstance(node.annotation, ast.Name) and node.annotation.id == 'CTypedef': - is_typedef = True - elif isinstance(node.annotation, ast.BinOp) and isinstance(node.annotation.left, ast.Attribute) and hasattr(node.annotation.left, 'attr') and node.annotation.left.attr == 'CTypedef': - is_typedef = True - if is_typedef: - if node.value: - self.typedef_map[var_name] = node.value - elif isinstance(node.annotation, ast.BinOp) and node.annotation.right: - self.typedef_map[var_name] = node.annotation.right - - lines = [] - lines.append('; ModuleID = "transpyc_decl"') - lines.append(f'target triple = "{self.target_triple}"') - lines.append(f'target datalayout = "{self.target_datalayout}"') - lines.append('') - - for node in ast.iter_child_nodes(tree): - if isinstance(node, ast.FunctionDef): - if hasattr(node, 'type_params') and node.type_params: - continue - decl = self._generate_func_decl(node) - if decl: - lines.append(decl) - elif isinstance(node, ast.AnnAssign): - decl = self._generate_global_decl(node) - if decl: - lines.append(decl) - elif isinstance(node, ast.Assign): - decl = self._generate_global_assign_decl(node) - if decl: - lines.append(decl) - elif isinstance(node, ast.ClassDef): - if hasattr(node, 'type_params') and node.type_params: - continue - decls = self._generate_class_decl(node) - lines.extend(decls) - - return '\n'.join(lines) - - def _generate_func_decl(self, node: ast.FunctionDef) -> str: - """生成函数声明""" - func_name = node.name - is_export = self._is_export_func(node) - if self.module_sha1 and not is_export: - func_name = f"{self.module_sha1}.{func_name}" - CReturnTypes = [] - if node.decorator_list: - for decorator in node.decorator_list: - if isinstance(decorator, ast.Call) and isinstance(decorator.func, ast.Attribute): - if decorator.func.attr == 'CReturn': - for arg in decorator.args: - CReturnTypes.append(arg) - if node.returns: - if isinstance(node.returns, ast.Subscript) and isinstance(node.returns.value, ast.Name) and node.returns.value.id == 'tuple': - slice_node = node.returns.slice - if isinstance(slice_node, ast.Tuple): - for elt in slice_node.elts: - CReturnTypes.append(elt) - else: - CReturnTypes.append(slice_node) - if CReturnTypes: - elem_types = [self._get_type_str(rt, embedded=True) for rt in CReturnTypes] - ret_type = '{ ' + ', '.join(elem_types) + ' }' - else: - ret_type = self._get_type_str(node.returns) - if not ret_type or ret_type == 'void': - ret_type = 'void' - elif ret_type == 'i8*': - if node.returns is None: - ret_type = 'void' - - params = [] - for arg in node.args.args: - if arg.annotation: - arg_type = self._get_type_str(arg.annotation) - else: - arg_type = 'i8*' - if arg_type and arg_type != 'void': - params.append(arg_type) - - param_str = ', '.join(params) if params else '' - if node.args.vararg: - param_str = param_str + ', ...' if param_str else '...' - if func_name[0].isdigit(): - return f'declare {ret_type} @"{func_name}"({param_str})' - return f'declare {ret_type} @{func_name}({param_str})' - - def _is_export_func(self, node: ast.FunctionDef) -> bool: - """检查函数是否标记为 CExport""" - if not node.returns: - return False - return self._check_annotation_for_export(node.returns) - - def _check_annotation_for_export(self, annotation) -> bool: - """递归检查类型注解中是否包含 CExport 或 t.State""" - if isinstance(annotation, ast.Attribute): - if hasattr(annotation, 'attr') and annotation.attr in ('CExport', 'State'): - return True - elif isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr): - return self._check_annotation_for_export(annotation.left) or self._check_annotation_for_export(annotation.right) - elif isinstance(annotation, ast.Name): - return annotation.id in ('CExport', 'State') - return False - - def _generate_global_decl(self, node: ast.AnnAssign) -> str: - """生成全局变量声明""" - if not isinstance(node.target, ast.Name): - return None - var_name = node.target.id - if isinstance(node.annotation, ast.Attribute) and hasattr(node.annotation, 'attr') and node.annotation.attr == 'CDefine': - return None - if isinstance(node.annotation, ast.Attribute) and hasattr(node.annotation, 'attr') and node.annotation.attr == 'CTypedef': - return None - if isinstance(node.annotation, ast.Name) and node.annotation.id == 'CTypedef': - return None - if isinstance(node.annotation, ast.BinOp) and isinstance(node.annotation.left, ast.Attribute) and hasattr(node.annotation.left, 'attr') and node.annotation.left.attr == 'CTypedef': - return None - if isinstance(node.annotation, ast.List): - for elt in node.annotation.elts: - if isinstance(elt, ast.Attribute) and hasattr(elt, 'attr') and elt.attr in ('CTypedef', 'Callable'): - return None - if isinstance(elt, ast.Subscript) and isinstance(elt.value, ast.Attribute) and isinstance(elt.value.value, ast.Name) and elt.value.value.id == 't' and elt.value.attr == 'Callable': - return None - var_type = self._get_type_str(node.annotation) - if var_type.startswith('[0 x ') and node.value and isinstance(node.value, ast.List): - elem_type = var_type[5:-1] - actual_count = len(node.value.elts) - if actual_count > 0: - var_type = f'[{actual_count} x {elem_type}]' - return f'@{var_name} = external global {var_type}' - - def _generate_global_assign_decl(self, node: ast.Assign) -> str: - """从无类型标注赋值推断并生成全局变量声明""" - if not node.targets or not isinstance(node.targets[0], ast.Name): - return None - var_name = node.targets[0].id - var_type = self._infer_type(node.value) - if var_type: - return f'@{var_name} = external global {var_type}' - return None - - def _generate_class_decl(self, node: ast.ClassDef) -> List[str]: - """生成结构体/类声明""" - decls = [] - class_name = node.name - is_enum = False - is_exception = False - if node.bases: - for base in node.bases: - if isinstance(base, ast.Attribute) and hasattr(base, 'attr'): - if base.attr == 'CEnum' or base.attr == 'Enum': - is_enum = True - break - elif base.attr == 'Exception' or base.attr in self.exception_names: - is_exception = True - break - elif isinstance(base, ast.Name) and hasattr(base, 'id'): - if base.id == 'CEnum' or base.id == 'Enum': - is_enum = True - break - elif base.id == 'Exception' or base.id in self.exception_names: - is_exception = True - break - if is_exception: - return decls - if is_enum: - enum_values = {} - next_value = 0 - for item in node.body: - if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name): - var_name = item.target.id - if item.value and isinstance(item.value, ast.Constant) and isinstance(item.value.value, int): - enum_values[var_name] = item.value.value - else: - enum_values[var_name] = next_value - next_value += 1 - elif isinstance(item, ast.Assign) and len(item.targets) == 1 and isinstance(item.targets[0], ast.Name): - var_name = item.targets[0].id - if item.value and isinstance(item.value, ast.Constant) and isinstance(item.value.value, int): - enum_values[var_name] = item.value.value - next_value = item.value.value + 1 - else: - enum_values[var_name] = next_value - next_value += 1 - for var_name, value in enum_values.items(): - decls.append(f'@__config_{class_name}_{var_name} = external global i32') - return decls - member_types = [] - has_bitfield = False - total_bits = 0 - has_methods = any(isinstance(item, ast.FunctionDef) for item in node.body) - is_cvtable = False - is_cpython_object = False - if hasattr(node, 'decorator_list') and node.decorator_list: - for decorator in node.decorator_list: - if isinstance(decorator, ast.Attribute): - if getattr(decorator.value, 'id', None) == 't': - if decorator.attr == 'CVTable': - is_cvtable = True - elif decorator.attr == 'Object': - is_cpython_object = True - elif isinstance(decorator, ast.Name): - if decorator.id == 'CVTable': - is_cvtable = True - elif decorator.id == 'Object': - is_cpython_object = True - if has_methods and not is_cpython_object: - is_cpython_object = True - has_parent_class = False - for base in node.bases: - base_name = None - if isinstance(base, ast.Attribute): - base_name = base.attr - elif isinstance(base, ast.Name): - base_name = base.id - elif isinstance(base, ast.Subscript): - if isinstance(base.value, ast.Attribute): - base_name = base.value.attr - elif isinstance(base.value, ast.Name): - base_name = base.value.id - if base_name and base_name not in ('Object', 'CVTable', 'CEnum', 'Enum', 'CStruct', 'CUnion'): - has_parent_class = True - break - if has_parent_class and not is_cvtable: - is_cvtable = True - base_has_vtable = False - for base in node.bases: - base_name = None - if isinstance(base, ast.Attribute): - base_name = base.attr - elif isinstance(base, ast.Name): - base_name = base.id - elif isinstance(base, ast.Subscript): - if isinstance(base.value, ast.Attribute): - base_name = base.value.attr - elif isinstance(base.value, ast.Name): - base_name = base.value.id - if base_name and base_name not in ('Object', 'CVTable', 'CEnum', 'Enum', 'CStruct', 'CUnion'): - for n in ast.iter_child_nodes(self._pyi_tree): - if isinstance(n, ast.ClassDef) and n.name == base_name: - if hasattr(n, 'decorator_list') and n.decorator_list: - for dec in n.decorator_list: - if isinstance(dec, ast.Attribute) and getattr(dec.value, 'id', None) == 't' and dec.attr == 'CVTable': - base_has_vtable = True - elif isinstance(dec, ast.Name) and dec.id == 'CVTable': - base_has_vtable = True - break - if base_has_vtable: - break - if has_methods and is_cvtable and not base_has_vtable: - member_types.append('i8*') - seen_member_names = set() - for base in node.bases: - base_name = None - if isinstance(base, ast.Attribute): - base_name = base.attr - elif isinstance(base, ast.Name): - base_name = base.id - elif isinstance(base, ast.Subscript): - if isinstance(base.value, ast.Attribute): - base_name = base.value.attr - elif isinstance(base.value, ast.Name): - base_name = base.value.id - if base_name and base_name not in ('Object', 'CVTable', 'CEnum', 'Enum', 'CStruct', 'CUnion'): - base_member_types, base_seen = self._get_inherited_members(base_name) - for mt in base_member_types: - member_types.append(mt) - seen_member_names.update(base_seen) - for item in node.body: - if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name): - seen_member_names.add(item.target.id) - init_members = [] - for item in node.body: - if isinstance(item, ast.FunctionDef) and item.name == '__init__': - for stmt in item.body: - if (isinstance(stmt, ast.AnnAssign) - and isinstance(stmt.target, ast.Attribute) - and isinstance(stmt.target.value, ast.Name) - and stmt.target.value.id == 'self'): - init_members.append(stmt) - untyped_self_members = [] - for m_name in [m.attr for m in init_members if isinstance(m.target, ast.Attribute)]: - seen_member_names.add(m_name) - for item in node.body: - if isinstance(item, ast.FunctionDef): - if hasattr(item, 'type_params') and item.type_params: - continue - for stmt in item.body: - if (isinstance(stmt, ast.Assign) - and len(stmt.targets) == 1 - and isinstance(stmt.targets[0], ast.Attribute) - and isinstance(stmt.targets[0].value, ast.Name) - and stmt.targets[0].value.id == 'self'): - attr_name = stmt.targets[0].attr - if attr_name not in seen_member_names: - seen_member_names.add(attr_name) - untyped_self_members.append(stmt) - for item in list(node.body) + init_members + untyped_self_members: - if isinstance(item, ast.AnnAssign): - bit_width = self._get_bitfield_width(item.annotation) - if bit_width is not None: - has_bitfield = True - total_bits += bit_width - else: - var_type = self._get_type_str(item.annotation, embedded=True) - if (isinstance(item.annotation, ast.Subscript) - and isinstance(item.annotation.value, ast.Name) - and item.annotation.value.id == 'list'): - slice_node = item.annotation.slice - is_dynamic = False - if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2: - count_node = slice_node.elts[1] - if isinstance(count_node, ast.Constant) and count_node.value is None: - is_dynamic = True - elif not (isinstance(count_node, ast.Constant) and isinstance(count_node.value, int) and count_node.value > 0): - if not isinstance(count_node, (ast.Name, ast.BinOp)): - is_dynamic = True - elif not isinstance(slice_node, ast.Tuple): - is_dynamic = True - if is_dynamic: - elem_type = self._get_type_str(slice_node if not isinstance(slice_node, ast.Tuple) else slice_node.elts[0], embedded=True) - init_len = 0 - if isinstance(item.value, ast.List): - init_len = len(item.value.elts) - elif isinstance(item.value, ast.Constant) and isinstance(item.value.value, str): - init_len = len(item.value.value) + 1 - var_type = f'[{init_len} x {elem_type}]' - member_types.append(var_type) - elif isinstance(item, ast.Assign): - if (len(item.targets) == 1 - and isinstance(item.targets[0], ast.Attribute) - and isinstance(item.targets[0].value, ast.Name) - and item.targets[0].value.id == 'self'): - attr_name = item.targets[0].attr - if attr_name in seen_member_names: - continue - InferredType = 'i32' - if item.value and isinstance(item.value, ast.Constant): - if isinstance(item.value.value, float): - InferredType = 'float' - elif isinstance(item.value.value, bool): - InferredType = 'i8' - elif isinstance(item.value.value, str): - InferredType = 'i8*' - member_types.append(InferredType) - else: - member_types.append('i32') - if has_bitfield: - if total_bits <= 8: - member_types.insert(0, 'i8') - elif total_bits <= 16: - member_types.insert(0, 'i16') - elif total_bits <= 32: - member_types.insert(0, 'i32') - else: - member_types.insert(0, 'i64') - struct_type_name = f'%"{self.module_sha1}.{class_name}"' if self.module_sha1 else f'%struct.{class_name}' - struct_decl = f'{struct_type_name} = type {{ {", ".join(member_types)} }}' - decls.append(struct_decl) - if is_cpython_object or is_cvtable: - new_func_name = f'{class_name}.__before_init__' - if self.module_sha1: - new_func_name = f"{self.module_sha1}.{new_func_name}" - if new_func_name[0].isdigit(): - new_func_decl = f'declare void @"{new_func_name}"({struct_type_name}*)' - else: - new_func_decl = f'declare void @{new_func_name}({struct_type_name}*)' - decls.append(new_func_decl) - for item in node.body: - if isinstance(item, ast.FunctionDef): - if hasattr(item, 'type_params') and item.type_params: - continue - method_name = f'{class_name}.{item.name}' - if self.module_sha1: - method_name = f"{self.module_sha1}.{method_name}" - ret_type = self._get_type_str(item.returns) if item.returns else 'void' - if not ret_type: - ret_type = 'void' - params = [] - for arg_idx, arg in enumerate(item.args.args): - if arg.annotation: - arg_type = self._get_type_str(arg.annotation) - elif arg_idx == 0 and arg.arg == 'self': - arg_type = f'{struct_type_name}*' - else: - arg_type = 'i8*' - params.append(arg_type) - param_str = ', '.join(params) if params else '' - if method_name[0].isdigit(): - decls.append(f'declare {ret_type} @"{method_name}"({param_str})') - else: - decls.append(f'declare {ret_type} @{method_name}({param_str})') - return decls - - def _get_inherited_members(self, base_name: str): - import ast - member_types = [] - seen_names = set() - if not hasattr(self, '_pyi_tree') or self._pyi_tree is None: - return member_types, seen_names - base_node = None - for node in ast.iter_child_nodes(self._pyi_tree): - if isinstance(node, ast.ClassDef) and node.name == base_name: - base_node = node - break - if base_node is None: - return member_types, seen_names - base_decls = self._generate_class_decl(base_node) - for decl in base_decls: - if '= type {' in decl: - type_body = decl.split('= type {')[1].rstrip('}').strip() - if type_body: - for t in type_body.split(','): - t = t.strip() - if t: - member_types.append(t) - break - for item in base_node.body: - if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name): - seen_names.add(item.target.id) - elif isinstance(item, ast.Assign) and len(item.targets) == 1: - if isinstance(item.targets[0], ast.Attribute) and isinstance(item.targets[0].value, ast.Name) and item.targets[0].value.id == 'self': - seen_names.add(item.targets[0].attr) - for item in base_node.body: - if isinstance(item, ast.FunctionDef) and item.name == '__init__': - for stmt in item.body: - if isinstance(stmt, ast.AnnAssign) and isinstance(stmt.target, ast.Attribute) and isinstance(stmt.target.value, ast.Name) and stmt.target.value.id == 'self': - seen_names.add(stmt.target.attr) - elif isinstance(stmt, ast.Assign) and len(stmt.targets) == 1 and isinstance(stmt.targets[0], ast.Attribute) and isinstance(stmt.targets[0].value, ast.Name) and stmt.targets[0].value.id == 'self': - seen_names.add(stmt.targets[0].attr) - return member_types, seen_names - - @staticmethod - def _ctype_name_to_llvm(name: str) -> str: - """根据 CType 元属性自动推导 LLVM IR 类型 - - 通过 CTypeRegistry.NameToLLVM 查询,利用 CType 的 - position/IsSigned/Size 元属性自动推导,无需手动映射表。 - """ - from lib.includes.t import CTypeRegistry - result = CTypeRegistry.NameToLLVM(name) - return result - - def _get_type_str(self, annotation: ast.AST, embedded: bool = False) -> str: - import ast - from lib.includes.t import CTypeRegistry - if annotation is None: - return 'i8*' - - non_struct_types = {'list', 'dict', 'tuple', 'set', 'array'} - - if isinstance(annotation, ast.Name): - if annotation.id == 'None': - return 'void' - if annotation.id in ('str', 'bytes'): - return 'i8*' - llvm_type = CTypeRegistry.NameToLLVM(annotation.id) - if llvm_type is not None: - return llvm_type - resolved = CTypeRegistry.ResolveName(annotation.id) - if resolved is not None: - ctype_cls, ptr_level = resolved - base = CTypeRegistry.CTypeToLLVM(ctype_cls) - if ptr_level > 0: - if base == 'void': - return 'i8*' - if '*' in base: - return base - return f'{base}*' - return base - if annotation.id in non_struct_types: - return 'i32' - if annotation.id in self.enum_names: - return 'i32' - if annotation.id in self.struct_names: - sha1 = self.struct_sha1_map.get(annotation.id, self.module_sha1) - sname = f'%"{sha1}.{annotation.id}"' if sha1 else f'%struct.{annotation.id}' - if embedded: - return sname - else: - return f'{sname}*' - if annotation.id in self.typedef_map: - resolved = self._get_type_str(self.typedef_map[annotation.id], embedded=embedded) - return resolved - sha1 = self.struct_sha1_map.get(annotation.id, self.module_sha1) - sname = f'%"{sha1}.{annotation.id}"' if sha1 else f'%struct.{annotation.id}' - return f'{sname}*' - elif isinstance(annotation, ast.Attribute): - attr_name = annotation.attr if hasattr(annotation, 'attr') else '' - module_name = '' - if hasattr(annotation, 'value'): - if isinstance(annotation.value, ast.Name): - module_name = annotation.value.id - elif isinstance(annotation.value, ast.Attribute) and hasattr(annotation.value, 'attr'): - module_name = annotation.value.attr - if (module_name == 't' and attr_name == 'State') or attr_name == 'State': - return '' - if (module_name == 't' and attr_name == 'Callable') or attr_name == 'Callable': - return 'i8*' - llvm_type = CTypeRegistry.NameToLLVM(attr_name) - if llvm_type is not None: - return llvm_type - resolved = CTypeRegistry.ResolveName(attr_name) - if resolved is not None: - ctype_cls, ptr_level = resolved - base = CTypeRegistry.CTypeToLLVM(ctype_cls) - if ptr_level > 0: - if base == 'void': - return 'i8*' - if '*' in base: - return base - return f'{base}*' - return base - if attr_name in self.typedef_map: - return self._get_type_str(self.typedef_map[attr_name], embedded=embedded) - if attr_name in self.enum_names: - return 'i32' - if attr_name in self.struct_names: - sha1 = self.struct_sha1_map.get(attr_name, self.module_sha1) - sname = f'%"{sha1}.{attr_name}"' if sha1 else f'%struct.{attr_name}' - if embedded: - return sname - else: - return f'{sname}*' - if attr_name and attr_name[0].isupper() and attr_name not in non_struct_types: - sha1 = self.struct_sha1_map.get(attr_name, self.module_sha1) - sname = f'%"{sha1}.{attr_name}"' if sha1 else f'%struct.{attr_name}' - return f'{sname}*' - if attr_name and attr_name not in non_struct_types: - sha1 = self.struct_sha1_map.get(attr_name, self.module_sha1) - sname = f'%"{sha1}.{attr_name}"' if sha1 else f'%struct.{attr_name}' - return f'{sname}*' - return 'i32' - elif isinstance(annotation, ast.BinOp): - left_type = self._get_type_str(annotation.left, embedded=embedded) - right_type = self._get_type_str(annotation.right, embedded=embedded) - if left_type in ('', 'void'): - return right_type if right_type not in ('', 'void') else (left_type or right_type) - if right_type in ('', 'void'): - return left_type - if '*' in left_type: - return left_type - if '*' in right_type: - if right_type == 'i8*': - return self._type_to_llvm_ptr(left_type) - return right_type - return left_type - elif isinstance(annotation, ast.Subscript): - base = self._get_type_str(annotation.value) - if base == 'i8*' and isinstance(annotation.slice, ast.Constant): - return f'[{self._get_const_int(annotation.slice)} x i8]' - if isinstance(annotation.slice, ast.Constant) and isinstance(annotation.slice.value, int): - return f'[{annotation.slice.value} x {base}]' - if isinstance(annotation.value, ast.Name) and annotation.value.id == 'list': - slice_node = annotation.slice - if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2: - elem_type = self._get_type_str(slice_node.elts[0], embedded=True) - count_node = slice_node.elts[1] - array_count = self._get_const_int(count_node) - if array_count > 0: - return f'[{array_count} x {elem_type}]' - else: - return f'[0 x {elem_type}]' - elem_type = self._get_type_str(slice_node, embedded=True) - return f'[0 x {elem_type}]' - if isinstance(annotation.value, ast.Name) and annotation.value.id == 'tuple': - slice_node = annotation.slice - if isinstance(slice_node, ast.Tuple): - elem_types = [self._get_type_str(e, embedded=True) for e in slice_node.elts] - else: - elem_types = [self._get_type_str(slice_node, embedded=True)] - return '{ ' + ', '.join(elem_types) + ' }' - return f'{base}' - elif isinstance(annotation, ast.Constant): - if annotation.value is None: - return 'void' - if isinstance(annotation.value, int): - return 'i32' - if isinstance(annotation.value, str): - type_name = annotation.value - if type_name in self.enum_names: - return 'i32' - if type_name in self.struct_names: - sha1 = self.struct_sha1_map.get(type_name, self.module_sha1) - sname = f'%"{sha1}.{type_name}"' if sha1 else f'%struct.{type_name}' - if embedded: - return sname - else: - return f'{sname}*' - llvm_type = CTypeRegistry.NameToLLVM(type_name) - if llvm_type is not None: - return llvm_type - resolved = CTypeRegistry.ResolveName(type_name) - if resolved is not None: - ctype_cls, ptr_level = resolved - base = CTypeRegistry.CTypeToLLVM(ctype_cls) - if ptr_level > 0: - if base == 'void': - return 'i8*' - if '*' in base: - return base - return f'{base}*' - return base - sha1 = self.struct_sha1_map.get(type_name, self.module_sha1) - sname = f'%"{sha1}.{type_name}"' if sha1 else f'%struct.{type_name}' - return f'{sname}*' - return 'i8*' - elif isinstance(annotation, ast.Call): - if isinstance(annotation.func, ast.Name) and annotation.func.id == 'callable': - return 'i8*' - if isinstance(annotation.func, ast.Attribute) and annotation.func.attr == 'Callable': - return 'i8*' - return 'i32' - - def _type_to_llvm_ptr(self, type_str: str) -> str: - if type_str.startswith('%struct.') and not type_str.endswith('*'): - return type_str + '*' - if type_str.startswith('%') and not type_str.endswith('*'): - return type_str + '*' - if type_str.endswith('*'): - return type_str - from lib.includes.t import CTypeRegistry - resolved = CTypeRegistry.ResolveName(type_str) - if resolved is not None: - ctype_cls, ptr_level = resolved - llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls) - if llvm_str: - return f'{llvm_str}{"*" * (ptr_level + 1)}' - cnameres = CTypeRegistry.CNameToClass(type_str) - if cnameres is not None: - llvm_str = CTypeRegistry.CTypeToLLVM(cnameres) - if llvm_str: - return f'{llvm_str}*' - return f'{type_str}*' - - def _infer_type(self, value: ast.AST) -> str: - """从值推断类型""" - import ast - if isinstance(value, ast.Constant): - if isinstance(value.value, int): - return 'i32' - elif isinstance(value.value, float): - return 'double' - elif isinstance(value.value, str): - return 'i8*' - elif isinstance(value.value, bool): - return 'i8' - elif isinstance(value, ast.List): - return 'i8*' - elif isinstance(value, ast.Dict): - return 'i8*' - elif isinstance(value, ast.Name): - return 'i32' - elif isinstance(value, ast.BinOp): - return self._infer_type(value.left) - elif isinstance(value, ast.Call): - return 'i8*' - return 'i32' - - def _get_bitfield_width(self, annotation: ast.AST): - import ast - if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr): - right_width = self._get_bitfield_width(annotation.right) - if right_width is not None: - return right_width - return self._get_bitfield_width(annotation.left) - if isinstance(annotation, ast.Call): - if isinstance(annotation.func, ast.Attribute) and annotation.func.attr == 'Bit': - if annotation.args: - arg = annotation.args[0] - if isinstance(arg, ast.Constant) and isinstance(arg.value, int): - return arg.value - if isinstance(annotation, ast.Subscript): - if isinstance(annotation.value, ast.Attribute) and annotation.value.attr == 'Bit': - if isinstance(annotation.slice, ast.Constant) and isinstance(annotation.slice.value, int): - return annotation.slice.value - return None - - def _get_const_int(self, node: ast.AST) -> int: - """获取常量整数值,支持符号常量和简单表达式""" - import ast - if isinstance(node, ast.Constant) and isinstance(node.value, int): - return node.value - if isinstance(node, ast.Name): - if node.id in self._define_constants: - val = self._define_constants[node.id] - if isinstance(val, int): - return val - if isinstance(node, ast.BinOp): - left_val = self._get_const_int(node.left) - right_val = self._get_const_int(node.right) - if left_val and right_val: - if isinstance(node.op, ast.Add): - return left_val + right_val - if isinstance(node.op, ast.Sub): - return left_val - right_val - if isinstance(node.op, ast.Mult): - return left_val * right_val - if isinstance(node.op, ast.Div): - return left_val // right_val - if isinstance(node.op, ast.FloorDiv): - return left_val // right_val - return 0 - - -def _parallel_translate_worker(src_path, out_path, src_root, temp_dir, output_dir, - include_dirs, triple, datalayout, sha1_map, sig_files, - stub_files, include_py_map, slice_level, - shared_sym_pickle_path, struct_sha1_map): - try: - import pickle - from Projectrans import Phase2Translator, compute_sha1 - trans = Phase2Translator(src_root, temp_dir, output_dir, - compile_cmd='llc', include_dirs=include_dirs, - target_triple=triple, target_datalayout=datalayout) - trans.sha1_map = sha1_map - trans.sig_files = sig_files - trans.stub_files = stub_files - trans.include_py_map = include_py_map - trans.slice_level = slice_level - trans.struct_sha1_map = struct_sha1_map - - if shared_sym_pickle_path and os.path.exists(shared_sym_pickle_path): - with open(shared_sym_pickle_path, 'rb') as f: - shared_data = pickle.load(f) - trans._shared_symbol_table = shared_data['symbol_table'] - trans._shared_source_module_sig_files = shared_data['source_module_sig_files'] - trans._shared_all_dc = shared_data['all_dc'] - trans._shared_export_extern_funcs = shared_data['export_extern_funcs'] - trans.inline_func_symbols = shared_data['inline_func_symbols'] - trans.function_default_args = shared_data['function_default_args'] - trans._shared_generic_class_templates = shared_data.get('generic_class_templates', {}) - else: - trans._precollect_inline_symbols() - trans._build_shared_symbol_data() - - trans._translate_file(src_path, out_path) - return ('ok', src_path, '') - except Exception as e: - import traceback - return ('error', src_path, f'{e}\n{traceback.format_exc(limit=50)}') - - -class Phase2Translator: - """阶段二:使用声明接口翻译源文件""" - - INCLUDE_LIB_EXTENSIONS = ('.dll', '.ll', '.so', '.o', '.a', '.lib') - INCLUDE_SRC_EXTENSIONS = ('.c', '.cpp', '.cc', '.cxx', '.m', '.mm') - INCLUDE_DIRS = [ - os.path.join(os.path.dirname(os.path.abspath(__file__)), 'includes'), - r"d:\Users\TermiNexus\Desktop\TransPyC\includes", - ] - - def __init__(self, src_root: str, temp_dir: str, output_dir: str, compile_cmd: str = 'llc', compile_flags: list = None, linker_cmd: str = None, linker_flags: list = None, linker_output: str = None, include_dirs: list = None, entry_files: list = None, target_triple: str = None, target_datalayout: str = None): - self.src_root = os.path.abspath(src_root) - self.temp_dir = os.path.abspath(temp_dir) - self.output_dir = os.path.abspath(output_dir) - self.compile_cmd = compile_cmd - self.compile_flags = compile_flags or ['-filetype=obj'] - self.triple = target_triple - self.datalayout = target_datalayout - if not self.triple: - for i, flag in enumerate(self.compile_flags): - if flag.startswith('-mtriple='): - self.triple = flag[len('-mtriple='):] - elif flag == '-mtriple' and i + 1 < len(self.compile_flags): - self.triple = self.compile_flags[i + 1] - self.linker_cmd = linker_cmd - self.linker_flags = linker_flags or [] - self.linker_output = linker_output - self.slice_level = 3 - self.sha1_map: dict[str, str] = {} - self.sig_files: dict[str, str] = {} - self.stub_files: dict[str, str] = {} - self.include_py_map: dict[str, str] = {} - self.used_includes: set = set() - self._last_error_stack = None - self.function_default_args: dict = {} - self.inline_func_symbols: dict = {} - self.extra_link_files: list = [] - self.extra_compile_files: list = [] - self.extra_py_files: list = [] - self._include_sha1s: set = set() - self.entry_files = entry_files - self._shared_symbol_table = None - self._shared_source_module_sig_files = {} - self._shared_all_dc = {} - self._shared_export_extern_funcs = set() - self._stub_decls_cache = {} - default_dirs = [d for d in self.INCLUDE_DIRS if os.path.isdir(d)] - if include_dirs: - seen = set() - self.include_dirs = [] - for d in list(include_dirs) + default_dirs: - d = os.path.abspath(d) - if d not in seen and os.path.isdir(d): - self.include_dirs.append(d) - seen.add(d) - else: - self.include_dirs = default_dirs - self._load_sha1_map() - - def _load_sha1_map(self): - """从 temp_dir 加载 SHA1 映射、签名文件和 stub 声明文件列表""" - if not os.path.exists(self.temp_dir): - print(f"[错误] 声明目录不存在: {self.temp_dir}") - return - - for fname in os.listdir(self.temp_dir): - fpath = os.path.join(self.temp_dir, fname) - if fname.startswith('_'): - continue - if fname.endswith('.pyi'): - sha1 = fname[:-4] - self.sig_files[sha1] = fpath - elif fname.endswith('.stub.ll'): - sha1 = fname[:-8] - self.stub_files[sha1] = fpath - - sha1_file_path = os.path.join(self.temp_dir, '_sha1_map.txt') - if os.path.exists(sha1_file_path): - with open(sha1_file_path, 'r', encoding='utf-8') as f: - for line in f: - line = line.strip() - if ':' in line: - sha1, rel = line.split(':', 1) - self.sha1_map[sha1] = rel - if rel.startswith('includes/'): - module_name = os.path.splitext(os.path.basename(rel))[0] - self.include_py_map[module_name] = sha1 - else: - for sha1, stub_path in self.stub_files.items(): - self.sha1_map[sha1] = sha1 - - def _build_struct_sha1_map(self): - struct_sha1_map = {} - valid_sha1_keys = set(self.sha1_map.keys()) - for fname in os.listdir(self.temp_dir): - if not fname.endswith('.pyi'): - continue - sha1_key = fname.replace('.pyi', '') - if sha1_key not in valid_sha1_keys: - continue - pyi_path = os.path.join(self.temp_dir, fname) - try: - with open(pyi_path, 'r', encoding='utf-8') as f: - tree = ast.parse(f.read()) - except Exception: - continue - for node in ast.walk(tree): - if isinstance(node, ast.ClassDef): - struct_sha1_map[node.name] = sha1_key - return struct_sha1_map - - def run(self): - """扫描源目录,翻译并生成 .ll 含代码文件(导入遍历)""" - if self.entry_files: - py_files = list(self.entry_files) - else: - main_py = os.path.join(self.src_root, 'main.py') - if os.path.exists(main_py): - py_files = [main_py] - else: - py_files = [] - for root, dirs, files in os.walk(self.src_root): - dirs[:] = [d for d in dirs if d not in ('__pycache__',)] - for file in files: - if file.endswith('.py'): - py_files.append(os.path.join(root, file)) - - if not py_files: - print("[阶段二] 未找到入口文件或源文件") - return - - reachable = find_reachable_files_from_entries(self.src_root, py_files) - py_files = list(reachable) - - py_files = topological_sort_files(py_files, self.src_root) - - print(f"[阶段二] 找到 {len(py_files)} 个可达源文件(已按依赖排序)") - print("[阶段二] 处理顺序:") - for i, f in enumerate(py_files[:10], 1): - rel = os.path.relpath(f, self.src_root) - print(f" {i}. {rel}") - os.makedirs(self.output_dir, exist_ok=True) - - valid_sha1s = set(self.sha1_map.keys()) - old_stub_count = len(self.stub_files) - old_sig_count = len(self.sig_files) - self.stub_files = {k: v for k, v in self.stub_files.items() if k in valid_sha1s} - self.sig_files = {k: v for k, v in self.sig_files.items() if k in valid_sha1s} - if old_stub_count != len(self.stub_files) or old_sig_count != len(self.sig_files): - print(f"[阶段二] 过滤旧文件: stub {old_stub_count}->{len(self.stub_files)}, sig {old_sig_count}->{len(self.sig_files)}") - - active_sha1s = set() - self._precollect_inline_symbols() - self._build_shared_symbol_data() - self.struct_sha1_map = self._build_struct_sha1_map() - - need_translate = [] - for i, src_path in enumerate(py_files, 1): - rel = os.path.relpath(src_path, self.src_root) - with open(src_path, 'r', encoding='utf-8') as f: - content = f.read() - sha1 = compute_sha1(content) - active_sha1s.add(sha1) - out_path = os.path.join(self.output_dir, f"{sha1}.ll") - - current_module_sha1_map = self._build_current_module_sha1_map(sha1) - - try: - tree = ast.parse(content) - for node in ast.walk(tree): - if isinstance(node, ast.Import): - for alias in node.names: - self.used_includes.add(alias.name.split('.')[0]) - elif isinstance(node, ast.ImportFrom): - if node.module: - self.used_includes.add(node.module.split('.')[0]) - except Exception: - pass - - if os.path.isfile(out_path): - deps_changed = self._check_deps_changed(sha1, current_module_sha1_map) - if not deps_changed: - print(f"[{i}/{len(py_files)}] 跳过(缓存): {rel} -> {sha1}.ll") - continue - else: - if self._recombine_ll(sha1, current_module_sha1_map): - print(f"[{i}/{len(py_files)}] 重组(依赖变化): {rel} -> {sha1}.ll") - continue - print(f"[{i}/{len(py_files)}] 重译(依赖变化): {rel} -> {sha1}.ll") - - else: - stub_cache = os.path.join(self.output_dir, f"{sha1}.stub.ll") - text_cache = os.path.join(self.output_dir, f"{sha1}.text.ll") - if os.path.isfile(stub_cache) and os.path.isfile(text_cache): - if self._recombine_ll(sha1, current_module_sha1_map): - print(f"[{i}/{len(py_files)}] 重组(缓存恢复): {rel} -> {sha1}.ll") - continue - - need_translate.append((i, src_path, out_path, sha1, current_module_sha1_map)) - - if need_translate: - print(f"\n[阶段二] 需要翻译 {len(need_translate)} 个文件") - import time - t_start = time.time() - - n_workers = min(os.cpu_count() or 4, len(need_translate), 8) - - if n_workers > 1 and len(need_translate) > 1: - from concurrent.futures import ProcessPoolExecutor, as_completed - import pickle - print(f" 并行翻译 (workers={n_workers})") - - shared_pickle_path = os.path.join(self.temp_dir, '_shared_sym.pkl') - try: - shared_data = { - 'symbol_table': self._shared_symbol_table, - 'source_module_sig_files': self._shared_source_module_sig_files, - 'all_dc': self._shared_all_dc, - 'export_extern_funcs': self._shared_export_extern_funcs, - 'inline_func_symbols': self.inline_func_symbols, - 'function_default_args': self.function_default_args, - 'generic_class_templates': self._shared_generic_class_templates, - } - with open(shared_pickle_path, 'wb') as f: - pickle.dump(shared_data, f, protocol=pickle.HIGHEST_PROTOCOL) - print(f" 共享符号表已序列化 ({os.path.getsize(shared_pickle_path)//1024}KB)") - except Exception as e: - print(f" [警告] 符号表序列化失败({e}),worker将自行构建") - shared_pickle_path = '' - - errors = [] - with ProcessPoolExecutor(max_workers=n_workers) as executor: - futures = {} - for i, src_path, out_path, sha1, msm in need_translate: - rel = os.path.relpath(src_path, self.src_root) - future = executor.submit( - _parallel_translate_worker, - src_path, out_path, - self.src_root, self.temp_dir, self.output_dir, - self.include_dirs, self.triple, self.datalayout, - self.sha1_map, self.sig_files, self.stub_files, - self.include_py_map, self.slice_level, - shared_pickle_path, self.struct_sha1_map - ) - futures[future] = (i, rel) - - done_count = 0 - for future in as_completed(futures): - i, rel = futures[future] - done_count += 1 - try: - status, _, err = future.result() - if status == 'ok': - print(f" [{done_count}/{len(need_translate)}] 完成: {rel}") - else: - print(f" [错误] {rel}: {err[:2000]}") - errors.append((rel, err)) - except Exception as e: - print(f" [错误] {rel}: {e}") - errors.append((rel, str(e))) - - if errors: - print(f"\n[编译终止] {len(errors)} 个文件翻译失败") - sys.exit(1) - else: - for idx, (i, src_path, out_path, sha1, msm) in enumerate(need_translate): - rel = os.path.relpath(src_path, self.src_root) - t0 = time.time() - try: - self._translate_file(src_path, out_path, prebuilt_module_sha1_map=msm) - t1 = time.time() - print(f" [{idx+1}/{len(need_translate)}] {rel} ({t1-t0:.1f}s)") - except Exception as e: - print(f" [错误] {rel}: {e}") - traceback.print_exc() - print(f"\n[编译终止] 翻译失败") - sys.exit(1) - t_end = time.time() - print(f" 翻译总耗时: {t_end-t_start:.1f}s") - - print(f"\n[阶段二完成] .ll 文件生成到: {self.output_dir}") - self._scan_include_libraries() - self._compile_include_py_files(active_sha1s) - self._compile_ll_files(active_sha1s) - self._compile_include_sources() - if self.linker_cmd: - self._link_obj_files(active_sha1s) - - def _build_current_module_sha1_map(self, self_sha1: str) -> dict: - """构建当前模块的依赖 SHA1 映射(与 _translate_file 中逻辑一致)""" - module_sha1_map = {} - for sha1_key, sig_path in self.sig_files.items(): - if sha1_key == self_sha1: - continue - rel_path = self.sha1_map.get(sha1_key, sha1_key) - if rel_path.startswith('includes/'): - inc_mod_name = os.path.splitext(rel_path)[0].replace(os.sep, '.').replace('/', '.') - inc_mod_name = inc_mod_name[len('includes/'):] - inc_short_name = inc_mod_name.split('.')[-1] if '.' in inc_mod_name else inc_mod_name - actual_sha1 = sha1_key - for inc_dir in self.include_dirs: - if os.path.isdir(inc_dir): - py_path = os.path.join(inc_dir, rel_path[len('includes/'):].replace(os.sep, '/')) - py_path = os.path.splitext(py_path)[0] + '.py' - if os.path.isfile(py_path): - with open(py_path, 'r', encoding='utf-8') as f: - py_sha1 = compute_sha1(f.read()) - actual_sha1 = py_sha1 - break - module_sha1_map[inc_mod_name] = actual_sha1 - module_sha1_map[inc_short_name] = actual_sha1 - # Also add parent package name (e.g., 'hashlib' for 'hashlib.__init__') - if inc_short_name == '__init__' and '.' in inc_mod_name: - parent_pkg = inc_mod_name.rsplit('.', 1)[0] - module_sha1_map[parent_pkg] = actual_sha1 - continue - module_name = os.path.splitext(rel_path)[0].replace(os.sep, '.').replace('/', '.') - module_sha1_map[module_name] = sha1_key - short_name = module_name.split('.')[-1] if '.' in module_name else module_name - module_sha1_map[short_name] = sha1_key - return module_sha1_map - - @staticmethod - def _split_ll(ll_content: str): - """将 .ll 内容拆分为 stub(声明)和 text(代码)两部分 - - stub: target, 注释, %type = type, declare, @xxx = external global - text: define ... { ... }, @xxx = global/constant (带初始化器) - """ - import re - stub_lines = [] - text_lines = [] - in_define = False - brace_depth = 0 - module_sha1 = None - defined_names = set() - - for line in ll_content.splitlines(True): - stripped = line.strip() - - if stripped.startswith('define '): - dm = re.match(r'define\s+[^@]*@"?([a-f0-9]+)\.', stripped) - if dm and module_sha1 is None: - module_sha1 = dm.group(1) - dm2 = re.match(r'define\s+[^@]*@"?([^"\s(]+)"?', stripped) - if dm2: - defined_names.add(dm2.group(1)) - - in_global_def = False - global_var_name = None - global_type_parts = [] - global_brace_depth = 0 - - for line in ll_content.splitlines(True): - stripped = line.strip() - - if in_global_def: - text_lines.append(line) - global_type_parts.append(stripped) - global_brace_depth += stripped.count('{') - stripped.count('}') - if global_brace_depth <= 0: - full_type = ' '.join(global_type_parts).strip() - depth = 0 - type_end = len(full_type) - for ci, cc in enumerate(full_type): - if cc in ('{', '['): - depth += 1 - elif cc in ('}', ']'): - depth -= 1 - elif depth == 0 and cc == ' ': - type_end = ci - break - var_type = full_type[:type_end].strip() - if var_type: - stub_lines.append(f'{global_var_name} = external global {var_type}\n') - in_global_def = False - global_var_name = None - global_type_parts = [] - global_brace_depth = 0 - continue - - if in_define: - text_lines.append(line) - brace_depth += stripped.count('{') - stripped.count('}') - if brace_depth <= 0: - in_define = False - continue - - if stripped.startswith('define '): - text_lines.append(line) - in_define = True - brace_depth = stripped.count('{') - stripped.count('}') - decl_line = re.sub(r'^define\s+', 'declare ', stripped) - decl_line = re.sub(r'\b(linkonce_odr|weak_odr|linkonce|weak|common|appending|internal|private)\s+', '', decl_line) - decl_line = re.sub(r'\balwaysinline\s+', '', decl_line) - paren_pos = decl_line.rfind(')') - if paren_pos >= 0: - decl_line = decl_line[:paren_pos + 1] - stub_lines.append(decl_line + '\n') - continue - - if stripped == '{' and text_lines and not in_define: - prev_stripped = text_lines[-1].strip() if text_lines else '' - if prev_stripped.startswith('define ') or prev_stripped.endswith('noredzone') or prev_stripped.endswith(')'): - text_lines.append(line) - brace_depth = 1 - in_define = True - if prev_stripped.startswith('define '): - decl_line = re.sub(r'^define\s+', 'declare ', prev_stripped) - decl_line = re.sub(r'\b(linkonce_odr|weak_odr|linkonce|weak|common|appending|internal|private)\s+', '', decl_line) - decl_line = re.sub(r'\balwaysinline\s+', '', decl_line) - paren_pos = decl_line.rfind(')') - if paren_pos >= 0: - decl_line = decl_line[:paren_pos + 1] - stub_lines.append(decl_line + '\n') - continue - - if stripped.startswith('@') and ' global ' in stripped and 'external global' not in stripped: - text_lines.append(line) - if ' internal ' not in stripped and ' private ' not in stripped: - name_match = re.match(r'(@\S+)', stripped) - if name_match: - var_name = name_match.group(1) - global_pos = stripped.find(' global ') - after_global = stripped[global_pos + 8:] - depth = 0 - type_end = len(after_global) - for ci, cc in enumerate(after_global): - if cc in ('{', '['): - depth += 1 - elif cc in ('}', ']'): - depth -= 1 - elif depth == 0 and cc == ' ': - type_end = ci - break - var_type = after_global[:type_end].strip() - brace_depth_gv = 0 - for cc in var_type: - if cc == '{': - brace_depth_gv += 1 - elif cc == '}': - brace_depth_gv -= 1 - if brace_depth_gv > 0: - in_global_def = True - global_var_name = var_name - global_type_parts = [var_type] - global_brace_depth = brace_depth_gv - elif var_type: - stub_lines.append(f'{var_name} = external global {var_type}\n') - continue - if stripped.startswith('@') and ' constant ' in stripped: - text_lines.append(line) - continue - - if stripped.startswith('declare'): - dm = re.match(r'declare\s+[^@]*@"?([^"\s(]+)"?', stripped) - if dm: - fname = dm.group(1) - if fname in defined_names: - stub_lines.append(line) - continue - dot_pos = fname.find('.') - if dot_pos > 0: - fname_sha1 = fname[:dot_pos] - if module_sha1 and fname_sha1 != module_sha1 and len(fname_sha1) >= 16: - continue - if re.match(r'^[a-f0-9]{16}\.', fname): - continue - stub_lines.append(line) - continue - - stub_lines.append(line) - - return ''.join(stub_lines), ''.join(text_lines) - - def _save_deps(self, sha1: str, module_sha1_map: dict): - """保存依赖指纹到 .deps.json""" - deps_path = os.path.join(self.output_dir, f"{sha1}.deps.json") - deps = {} - for mod_name, dep_sha1 in module_sha1_map.items(): - deps[mod_name] = dep_sha1 - with open(deps_path, 'w', encoding='utf-8') as f: - json.dump(deps, f) - - def _load_deps(self, sha1: str) -> dict: - """加载依赖指纹""" - deps_path = os.path.join(self.output_dir, f"{sha1}.deps.json") - if os.path.isfile(deps_path): - try: - with open(deps_path, 'r', encoding='utf-8') as f: - return json.load(f) - except Exception: - pass - return None - - def _check_deps_changed(self, sha1: str, current_module_sha1_map: dict) -> bool: - """检查依赖指纹是否变化""" - saved_deps = self._load_deps(sha1) - if saved_deps is None: - return True - for mod_name, dep_sha1 in current_module_sha1_map.items(): - if saved_deps.get(mod_name) != dep_sha1: - return True - for mod_name, dep_sha1 in saved_deps.items(): - if current_module_sha1_map.get(mod_name) != dep_sha1: - return True - return False - - def _recombine_ll(self, sha1: str, current_module_sha1_map: dict) -> bool: - """依赖变化时重新组合 .ll:更新 .stub.ll 中的 SHA1 前缀,拼接 .stub.ll + .text.ll""" - saved_deps = self._load_deps(sha1) - if saved_deps is None: - return False - - stub_path = os.path.join(self.output_dir, f"{sha1}.stub.ll") - text_path = os.path.join(self.output_dir, f"{sha1}.text.ll") - ll_path = os.path.join(self.output_dir, f"{sha1}.ll") - - if not os.path.isfile(stub_path) or not os.path.isfile(text_path): - return False - - with open(stub_path, 'r', encoding='utf-8') as f: - stub_content = f.read() - with open(text_path, 'r', encoding='utf-8') as f: - text_content = f.read() - - sha1_replacements = {} - for mod_name, old_sha1 in saved_deps.items(): - new_sha1 = current_module_sha1_map.get(mod_name) - if new_sha1 and old_sha1 != new_sha1: - sha1_replacements[old_sha1] = new_sha1 - - if sha1_replacements: - for old_sha1, new_sha1 in sha1_replacements.items(): - stub_content = stub_content.replace(old_sha1, new_sha1) - text_content = text_content.replace(old_sha1, new_sha1) - - combined = stub_content - if not combined.endswith('\n'): - combined += '\n' - combined += text_content - - with open(ll_path, 'w', encoding='utf-8', newline='\n') as f: - f.write(combined) - with open(stub_path, 'w', encoding='utf-8', newline='\n') as f: - f.write(stub_content) - with open(text_path, 'w', encoding='utf-8', newline='\n') as f: - f.write(text_content) - - self._save_deps(sha1, current_module_sha1_map) - - obj_path = os.path.join(self.output_dir, f"{sha1}.obj") - if os.path.isfile(obj_path): - os.remove(obj_path) - - return True - - def _translate_file(self, src_path: str, out_path: str, prebuilt_module_sha1_map: dict = None): - """翻译单个源文件,嵌入相关 .stub.ll 声明""" - with open(src_path, 'r', encoding='utf-8') as f: - code = f.read() - - sha1 = compute_sha1(code) - - if prebuilt_module_sha1_map is not None: - module_sha1_map = prebuilt_module_sha1_map - else: - module_sha1_map = self._build_current_module_sha1_map(sha1) - - trans = TransPyC.TransPyC(code=code, triple=self.triple, datalayout=self.datalayout) - trans.translator.CurrentFile = src_path - trans.SliceLevel = self.slice_level - trans.translator.SliceLevel = self.slice_level - trans.translator.SliceCount = 0 - trans.translator.SliceInfos = [] - trans.translator.LlvmGen = None - trans.translator._module_sha1 = sha1 - trans.translator._module_sha1_map = module_sha1_map - trans.translator._struct_sha1_map = self.struct_sha1_map - trans.translator._global_function_default_args = self.function_default_args - trans.translator._temp_dir = self.temp_dir - - if hasattr(self, '_shared_symbol_table') and self._shared_symbol_table is not None: - trans.translator.SymbolTable = self._shared_symbol_table - # 确保共享符号表的 translator 指向当前 translator,以便 import 别名解析正确 - if hasattr(self._shared_symbol_table, 'translator'): - self._shared_symbol_table.translator = trans.translator - trans.translator._source_module_sig_files = self._shared_source_module_sig_files - trans.translator._all_define_constants = self._shared_all_dc - trans.translator._export_extern_funcs = self._shared_export_extern_funcs - if hasattr(self, '_shared_generic_class_templates') and self._shared_generic_class_templates: - if not hasattr(trans.translator.ClassHandler, '_generic_class_templates'): - trans.translator.ClassHandler._generic_class_templates = {} - trans.translator.ClassHandler._generic_class_templates.update(self._shared_generic_class_templates) - else: - export_extern_funcs = set() - for sha1_key, sig_path in self.sig_files.items(): - if sha1_key == sha1: - continue - try: - with open(sig_path, 'r', encoding='utf-8') as f: - sig_content = f.read() - sig_tree = ast.parse(sig_content) - for node in ast.iter_child_nodes(sig_tree): - if isinstance(node, ast.FunctionDef): - if _check_annotation_for_export(node.returns): - export_extern_funcs.add(node.name) - except Exception: - pass - if export_extern_funcs: - trans.translator._export_extern_funcs = export_extern_funcs - - for includes_dir in self.include_dirs: - if os.path.isdir(includes_dir): - for pyi_file in os.listdir(includes_dir): - if pyi_file.endswith('.pyi'): - pyi_path = os.path.join(includes_dir, pyi_file) - module_name = os.path.splitext(pyi_file)[0] - trans.translator.SymbolTable.LoadModuleSymbols(pyi_path, module_name, lineno=0) - for py_file in os.listdir(includes_dir): - if py_file.endswith('.py') and not py_file.startswith('_'): - module_name = os.path.splitext(py_file)[0] - sha1_key = self.include_py_map.get(module_name) - if sha1_key and sha1_key in self.sig_files: - sig_path = self.sig_files[sha1_key] - trans.translator.SymbolTable.LoadModuleSymbols(sig_path, module_name, lineno=0) - for sha1_key, sig_path in self.sig_files.items(): - rel_path = self.sha1_map.get(sha1_key, sha1_key) - if rel_path.startswith('includes/'): - mod_name = os.path.splitext(rel_path)[0].replace(os.sep, '.').replace('/', '.') - mod_name = mod_name[len('includes/'):] - trans.translator.SymbolTable.LoadModuleSymbols(sig_path, mod_name, lineno=0) - if mod_name.endswith('.__init__'): - package_name = mod_name[:-len('.__init__')] - self._register_package_reexports(trans, sig_path, package_name) - - for sha1_key, sig_path in self.sig_files.items(): - if sha1_key == sha1: - continue - rel_path = self.sha1_map.get(sha1_key, sha1_key) - if rel_path.startswith('includes/'): - continue - module_name = os.path.splitext(rel_path)[0].replace(os.sep, '.').replace('/', '.') - trans.translator.SymbolTable.LoadModuleSymbols(sig_path, module_name, lineno=0) - trans.translator._source_module_sig_files[module_name] = sig_path - short_name = module_name.split('.')[-1] if '.' in module_name else module_name - if short_name != module_name: - trans.translator._source_module_sig_files[short_name] = sig_path - - all_dc = {} - for sha1_key, stub_path in self.stub_files.items(): - if sha1_key == sha1: - continue - if os.path.exists(stub_path): - try: - with open(stub_path, 'r', encoding='utf-8') as f: - stub_content = f.read() - for line in stub_content.splitlines(): - line = line.strip() - if line.startswith('@') and '= global' in line and 'i32' in line and not line.startswith('@llvm'): - var_name = line.split('=')[0].strip().lstrip('@') - val_part = line.split('i32')[-1].strip().rstrip(']').lstrip('[').lstrip('i32') - try: - val = int(val_part) - all_dc[var_name] = val - except: - pass - except: - pass - for sha1_key, pyi_path in self.sig_files.items(): - if sha1_key == sha1: - continue - if os.path.exists(pyi_path): - try: - import ast as _ast - with open(pyi_path, 'r', encoding='utf-8') as f: - pyi_content = f.read() - tree = _ast.parse(pyi_content) - for node in _ast.iter_child_nodes(tree): - if isinstance(node, _ast.AnnAssign) and isinstance(node.target, _ast.Name): - ann_str = _ast.dump(node.annotation) - if 'CDefine' in ann_str and node.value: - val = None - if isinstance(node.value, _ast.Constant): - val = node.value.value - elif isinstance(node.value, _ast.Call) and isinstance(node.value.func, _ast.Name) and node.value.func.id == 'float' and node.value.args and isinstance(node.value.args[0], _ast.Constant): - val = node.value.args[0].value - if val is not None: - all_dc[f"{node.target.id}"] = val - except: - pass - if all_dc: - trans.translator._all_define_constants = all_dc - - for sym_name, sym_info in self.inline_func_symbols.items(): - if sym_name not in trans.translator.SymbolTable: - trans.translator.SymbolTable[sym_name] = sym_info - else: - existing = trans.translator.SymbolTable[sym_name] - if not getattr(existing, 'InlineBody', None) and getattr(sym_info, 'InlineBody', None): - existing.IsInline = sym_info.IsInline - existing.InlineBody = sym_info.InlineBody - existing.InlineParams = sym_info.InlineParams - - try: - result = trans.Convert( - OutputFilename=out_path, - SourceFilename=src_path, - target='llvm' - ) - except Exception as e: - error_stack = getattr(trans.translator, '_error_stack', []) - if error_stack: - self._last_error_stack = error_stack - chain_lines = [] - for entry in reversed(error_stack): - if len(entry) >= 3: - exc_msg, line_info = entry[1], entry[2] - chain_lines.append(" %s\n %s" % (line_info, exc_msg)) - if chain_lines: - enriched = str(e) + "\n" + "\n".join(chain_lines) - raise type(e)(enriched) from e - node_info = "" - if hasattr(trans.translator, 'LlvmGen') and trans.translator.LlvmGen: - node_info = trans.translator.LlvmGen._get_node_info() - if node_info: - enriched = "%s\n %s" % (str(e), node_info.strip()) - raise type(e)(enriched) from e - raise - - if result and isinstance(result, str): - for func_name, func_def in trans.translator.FunctionDefCache.items(): - if hasattr(func_def, 'args') and hasattr(func_def.args, 'defaults') and func_def.args.defaults: - mangled = trans.translator.LlvmGen._mangle_func_name(func_name) if trans.translator.LlvmGen else func_name - defaults = [] - for d in func_def.args.defaults: - if isinstance(d, ast.Constant): - defaults.append(d.value) - else: - defaults.append(None) - self.function_default_args[mangled] = defaults - self.function_default_args[func_name] = defaults - for sym_name, sym_info in trans.translator.SymbolTable.items(): - if isinstance(sym_info, CTypeInfo) and getattr(sym_info, 'IsInline', False) and getattr(sym_info, 'InlineBody', None): - self.inline_func_symbols[sym_name] = sym_info - # stub声明现在通过_dso.ll编译时拼接依赖模块stub.ll提供 - # stub_decls = self._collect_stub_decls_for_module(sha1) - # if stub_decls: - # result = self._inject_stub_decls(result, stub_decls) - - out_dir = os.path.dirname(out_path) - if out_dir: - os.makedirs(out_dir, exist_ok=True) - with open(out_path, 'w', encoding='utf-8', newline='\n') as f: - f.write(result) - - stub_content, text_content = self._split_ll(result) - base = os.path.splitext(out_path)[0] - with open(base + '.stub.ll', 'w', encoding='utf-8', newline='\n') as f: - f.write(stub_content) - with open(base + '.text.ll', 'w', encoding='utf-8', newline='\n') as f: - f.write(text_content) - self._save_deps(sha1, module_sha1_map) - - print(f" -> {os.path.basename(out_path)}") - else: - stub_path = self.stub_files.get(sha1) - if stub_path and os.path.exists(stub_path): - out_dir = os.path.dirname(out_path) - if out_dir: - os.makedirs(out_dir, exist_ok=True) - with open(stub_path, 'r', encoding='utf-8') as f: - stub_content = f.read() - with open(out_path, 'w', encoding='utf-8', newline='\n') as f: - f.write(stub_content) - print(f" -> {os.path.basename(out_path)} (仅声明)") - - def _register_package_reexports(self, trans, init_pyi_path, package_name): - """解析 __init__.pyi 中的 from .xxx import yyy 或 from __xxx import yyy,在包级别注册导出符号""" - try: - with open(init_pyi_path, 'r', encoding='utf-8') as f: - content = f.read() - tree = ast.parse(content) - for node in ast.walk(tree): - if isinstance(node, ast.ImportFrom) and node.module: - sub_module = node.module.lstrip('.') - for alias in node.names: - symbol_name = alias.name - exported_name = alias.asname if alias.asname else symbol_name - source_keys = [ - f"{package_name}.{sub_module}.{symbol_name}", - f"{package_name}.__{sub_module}.{symbol_name}" if not sub_module.startswith('__') else None, - symbol_name, - ] - target_key = f"{package_name}.{exported_name}" - if target_key not in trans.translator.SymbolTable: - for source_key in source_keys: - if source_key and source_key in trans.translator.SymbolTable: - trans.translator.SymbolTable[target_key] = trans.translator.SymbolTable[source_key] - break - if exported_name not in trans.translator.SymbolTable: - for source_key in source_keys: - if source_key and source_key in trans.translator.SymbolTable: - trans.translator.SymbolTable[exported_name] = trans.translator.SymbolTable[source_key] - break - except Exception as e: - print(f" [警告] 解析包重导出失败 {init_pyi_path}: {e}") - - def _collect_stub_decls(self, self_sha1: str) -> str: - """收集 includes 目录中模块的 .stub.ll 声明内容,去重""" - seen_symbols = set() - decl_lines = [] - for sha1_key, stub_path in self.stub_files.items(): - if sha1_key == self_sha1: - continue - rel_path = self.sha1_map.get(sha1_key, sha1_key) - if not rel_path.startswith('includes/'): - continue - if os.path.exists(stub_path): - with open(stub_path, 'r', encoding='utf-8') as f: - content = f.read() - for line in content.splitlines(): - stripped = line.strip() - if not stripped: - continue - if stripped.startswith(';'): - continue - if stripped.startswith('target '): - continue - if stripped.startswith('source_filename'): - continue - if stripped.startswith('@') and '=' in stripped: - name = stripped.split('=', 1)[0].strip() - if name in seen_symbols: - continue - seen_symbols.add(name) - elif stripped.startswith('%') and '= type' in stripped: - name = stripped.split('=', 1)[0].strip() - if name in seen_symbols: - continue - seen_symbols.add(name) - elif stripped.startswith('declare'): - parts = stripped.split('@', 1) - if len(parts) > 1: - name = '@' + parts[1].split('(', 1)[0].strip() - if name in seen_symbols: - continue - seen_symbols.add(name) - decl_lines.append(line) - if decl_lines: - result = '\n'.join(decl_lines) - self._stub_decls_cache[self_sha1] = result - return result - self._stub_decls_cache[self_sha1] = '' - return '' - - def _collect_stub_decls_for_module(self, self_sha1: str) -> str: - """收集特定模块需要的 .stub.ll 声明(包括结构体类型定义、函数声明和 typedef)""" - if self_sha1 in self._stub_decls_cache: - return self._stub_decls_cache[self_sha1] - import re - seen_symbols = set() - seen_func_symbols = set() - decl_lines = [] - - non_struct_types = {'UINT', 'INT', 'BYTE', 'BYTEPTR', 'WORD', 'DWORD', 'QWORD', - 'INT8', 'INT16', 'INT32', 'INT64', 'UINT8', 'UINT16', 'UINT32', 'UINT64', - 'INTPTR', 'UINTPTR', 'SIZE_T', 'SSIZE_T', 'PTRDIFF_T', - 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', - 'atomic_int', 'atomic_uint', 'atomic_long', 'atomic_ulong', - 'atomic_int8', 'atomic_uint8', 'atomic_int16', 'atomic_uint16', - 'atomic_int32', 'atomic_uint32', 'atomic_int64', 'atomic_uint64', - 'atomic_ptr', 'atomic_flag', 'typedef', - 'list', 'dict', 'tuple', 'set', 'str', 'bytes', 'array'} - - struct_names = set() - struct_source_sha1 = {} - - def _extract_struct_name(type_def_str): - m = re.match(r'%"?((?:[a-f0-9]+\.)?[\w.]+)"?\s*=\s*type', type_def_str) - if m: - raw = m.group(1) - if '.' in raw: - return raw.split('.', 1)[1], raw.split('.', 1)[0] - return raw, None - return None, None - - def _replace_struct_refs(type_str): - def replace_struct_name(name): - if name in struct_names: - name_sha1 = struct_source_sha1.get(name, '') - return f'%"{name_sha1}.{name}"' if name_sha1 else None - return None - def replace_struct_match(match): - name = match.group(1) - replaced = replace_struct_name(name) - return replaced if replaced else match.group(0) - def replace_sha1_struct_match(match): - name = match.group(2) - replaced = replace_struct_name(name) - return replaced if replaced else match.group(0) - result = re.sub(r'%struct\.(\w+)', replace_struct_match, type_str) - result = re.sub(r'%"?([a-f0-9]+)\.(\w+)"?', replace_sha1_struct_match, result) - return result - - for sha1_key, stub_path in self.stub_files.items(): - if os.path.exists(stub_path): - with open(stub_path, 'r', encoding='utf-8') as f: - content = f.read() - for line in content.splitlines(): - stripped = line.strip() - if stripped.startswith('%') and '= type' in stripped: - clean_name, sha1_part = _extract_struct_name(stripped) - if clean_name and clean_name not in non_struct_types: - struct_names.add(clean_name) - if clean_name not in struct_source_sha1: - struct_source_sha1[clean_name] = sha1_part or sha1_key - - for sha1_key, stub_path in self.stub_files.items(): - if sha1_key == self_sha1: - continue - if os.path.exists(stub_path): - with open(stub_path, 'r', encoding='utf-8') as f: - content = f.read() - for line in content.splitlines(): - stripped = line.strip() - if stripped.startswith('%') and '= type' in stripped: - clean_name, sha1_part = _extract_struct_name(stripped) - if not clean_name or clean_name in non_struct_types: - continue - if clean_name in seen_symbols: - continue - parts = stripped.split('= type', 1) - struct_type_body = parts[1].strip() if len(parts) > 1 else '' - if 'opaque' in struct_type_body: - seen_symbols.add(clean_name) - name_sha1 = struct_source_sha1.get(clean_name, sha1_key) - decl_lines.append(f'%"{name_sha1}.{clean_name}" = type opaque') - continue - if clean_name in struct_names: - struct_type_body = _replace_struct_refs(struct_type_body) - name_sha1 = struct_source_sha1.get(clean_name, sha1_key) - new_def = f'%"{name_sha1}.{clean_name}" = type {struct_type_body}' - seen_symbols.add(clean_name) - decl_lines.append(new_def) - if decl_lines: - return '\n'.join(decl_lines) - return '' - - def _inject_stub_decls(self, ll_content: str, stub_decls: str) -> str: - """将 stub 声明注入到 LLVM IR 模块头之后,替换 opaque 类型为具体定义""" - def normalize_type_name(name): - name = name.strip() - if name.startswith('%'): - return '%' + name[1:].strip().strip('"') - return name - - existing_symbols = {} # normalized_name -> (line_index, full_line) - for i, line in enumerate(ll_content.splitlines()): - stripped = line.strip() - if stripped.startswith('@') and '=' in stripped: - name = stripped.split('=', 1)[0].strip() - existing_symbols[name] = (i, line) - elif stripped.startswith('%') and '= type' in stripped: - name = normalize_type_name(stripped.split('=', 1)[0].strip()) - existing_symbols[name] = (i, line) - elif stripped.startswith('declare') or stripped.startswith('define'): - parts = stripped.split('@', 1) - if len(parts) > 1: - name = '@' + parts[1].split('(', 1)[0].strip() - existing_symbols[name] = (i, line) - - lines = ll_content.splitlines() - replacements = {} # line_index -> new_line - new_decls = [] # 新类型定义(不在现有输出中的) - - def normalize_type_name(name): - name = name.strip() - if name.startswith('%'): - return '%' + name[1:].strip().strip('"') - return name - - for line in stub_decls.splitlines(): - stripped = line.strip() - if stripped.startswith('%') and '= type' in stripped: - name = normalize_type_name(stripped.split('=', 1)[0].strip()) - if name in existing_symbols: - idx, existing_line = existing_symbols[name] - existing_type_body = existing_line.strip().split('= type', 1)[1].strip() if '= type' in existing_line else '' - stub_type_body = stripped.split('= type', 1)[1].strip() if '= type' in stripped else '' - if 'opaque' in existing_line and 'opaque' not in stripped: - replacements[idx] = line - else: - new_decls.append(line) - - # 应用替换 - for idx, new_line in replacements.items(): - lines[idx] = new_line - - # 追加新类型定义到末尾(去重处理) - if new_decls: - # 过滤掉已经在 Translator 输出中存在的类型定义 - existing_types = set() - for line in lines: - stripped = line.strip() - if stripped.startswith('%') and '= type' in stripped: - type_name = normalize_type_name(stripped.split('=', 1)[0].strip()) - existing_types.add(type_name) - filtered_decls = [] - for line in new_decls: - stripped = line.strip() - if '= type' in stripped: - type_name = normalize_type_name(stripped.split('=', 1)[0].strip()) - if type_name not in existing_types: - filtered_decls.append(line) - existing_types.add(type_name) - if filtered_decls: - lines.append('') - lines.extend(filtered_decls) - - # 确保所有类型定义在全局变量之前,LLVM 要求在常量初始化器中使用类型之前必须先定义 - type_def_indices = [] - first_global_idx = None - for i, line in enumerate(lines): - stripped = line.strip() - if stripped.startswith('%') and '= type' in stripped: - if first_global_idx is not None: - type_def_indices.append(i) - elif stripped.startswith('@') and ' global' in stripped: - if first_global_idx is None: - first_global_idx = i - - if type_def_indices and first_global_idx is not None: - type_defs = [lines[i] for i in reversed(type_def_indices)] - for i in reversed(type_def_indices): - del lines[i] - insert_pos = first_global_idx - if type_def_indices[0] < first_global_idx: - insert_pos = first_global_idx - len(type_def_indices) - for j, td in enumerate(type_defs): - lines.insert(insert_pos, td) - - result = '\n'.join(lines) - - return result - - def _compile_ll_files(self, active_sha1s: set): - """将 output_dir 中属于 active_sha1s 的 .ll 文件编译为 .obj(跳过已编译过的 include 文件)""" - stale_files = [] - for root, dirs, files in os.walk(self.output_dir): - for file in files: - fpath = os.path.join(root, file) - for ext in ('.ll', '.obj', '.stub.ll', '.text.ll', '.deps.json', '_dso.ll'): - if file.endswith(ext): - sha1 = file[:-(len(ext))] - if sha1 not in active_sha1s: - stale_files.append(fpath) - break - if stale_files: - for fpath in stale_files: - try: - os.remove(fpath) - except: - pass - print(f"[清理] 删除 {len(stale_files)} 个过时文件") - ll_files = [] - for root, dirs, files in os.walk(self.output_dir): - for file in files: - if file.endswith('.ll') and not file.endswith('.stub.ll') and not file.endswith('.text.ll'): - sha1 = file[:-3] - if sha1 in active_sha1s: - obj_path = os.path.join(root, file[:-3] + '.obj') - if not os.path.isfile(obj_path): - ll_files.append(os.path.join(root, file)) - - if not ll_files: - print("[编译] 无 .ll 文件需要重新编译") - else: - print(f"\n[编译] 找到 {len(ll_files)} 个 .ll 文件需要编译") - - has_inline = False - all_ll_files = [] - for root, dirs, files in os.walk(self.output_dir): - for file in files: - if file.endswith('.ll') and not file.endswith('.stub.ll') and not file.endswith('.text.ll'): - sha1 = file[:-3] - if sha1 in active_sha1s and sha1 not in self._include_sha1s: - all_ll_files.append(os.path.join(root, file)) - for ll_path in all_ll_files: - try: - with open(ll_path, 'r', encoding='utf-8') as f: - content = f.read() - if 'alwaysinline' in content: - has_inline = True - break - except: - pass - - if has_inline: - llvm_link = shutil.which('llvm-link') or shutil.which('llvm-link.exe') - opt_cmd = shutil.which('opt') or shutil.which('opt.exe') - if llvm_link and opt_cmd: - print(" [内联] 检测到 alwaysinline 函数,执行跨模块内联优化...") - for ll_path in all_ll_files: - try: - with open(ll_path, 'r', encoding='utf-8') as f: - content = f.read() - type_defs = [] - type_def_indices = set() - for i, line in enumerate(content.splitlines()): - stripped = line.strip() - if stripped.startswith('%') and '= type' in stripped: - type_defs.append(line) - type_def_indices.add(i) - if type_def_indices: - lines = content.splitlines(True) - content_no_types = ''.join(line for i, line in enumerate(lines) if i not in type_def_indices) - header_end = 0 - for i, line in enumerate(content_no_types.splitlines()): - stripped = line.strip() - if stripped.startswith(';') or stripped.startswith('target ') or stripped.startswith('source_filename') or not stripped: - header_end = i + 1 - continue - break - lines2 = content_no_types.splitlines(True) - fixed = ''.join(lines2[:header_end]) + '\n'.join(type_defs) + '\n' + ''.join(lines2[header_end:]) - with open(ll_path, 'w', encoding='utf-8') as f: - f.write(fixed) - except: - pass - merged_ll = os.path.join(self.output_dir, '_merged.ll') - optimized_ll = os.path.join(self.output_dir, '_merged_opt.ll') - try: - link_cmd = [llvm_link] + all_ll_files + ['-o', merged_ll] - result = subprocess.run(link_cmd, capture_output=True, text=True) - if result.returncode != 0: - print(f" [警告] llvm-link 失败: {result.stderr.strip()},回退到单独编译") - has_inline = False - else: - opt_result_cmd = [opt_cmd, '-passes=always-inline', merged_ll, '-S', '-o', optimized_ll] - result = subprocess.run(opt_result_cmd, capture_output=True, text=True) - if result.returncode != 0: - print(f" [警告] opt 失败: {result.stderr.strip()},回退到单独编译") - has_inline = False - else: - print(" [内联] 跨模块内联优化完成") - with open(optimized_ll, 'r', encoding='utf-8') as f: - opt_content = f.read() - import re - opt_content = re.sub(r'\b(define|declare)\s+(private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external)\s+', r'\1 \2 dso_local ', opt_content) - opt_content = re.sub(r'\b(define|declare)\s+(?!private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external|dso_local|@)', r'\1 dso_local ', opt_content) - opt_content = re.sub(r'(@[\w.]+)\s*=\s*(private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external)\s+(global|constant)', r'\1 = \2 dso_local \3', opt_content) - opt_content = re.sub(r'(@[\w.]+)\s*=\s+(?!private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external|dso_local)(global|constant)', r'\1 = linkonce_odr \2', opt_content) - with open(optimized_ll, 'w', encoding='utf-8') as f: - f.write(opt_content) - merged_obj = os.path.join(self.output_dir, '_merged.obj') - try: - cmd = [self.compile_cmd] + self.compile_flags + ['-o', merged_obj, optimized_ll] - result = subprocess.run(cmd, capture_output=True, text=True, - cwd=self.output_dir) - if result.returncode == 0: - print(f" [成功] 合并模块编译完成") - for ll_path in ll_files: - obj_path = ll_path[:-3] + '.obj' - sha1_obj = os.path.join(self.output_dir, os.path.basename(ll_path)[:-3] + '.obj') - if os.path.isfile(sha1_obj): - os.remove(sha1_obj) - return - else: - print(f" [警告] 合并模块编译失败: {result.stderr.strip()},回退到单独编译") - has_inline = False - except Exception as e: - print(f" [警告] 合并模块编译异常: {e},回退到单独编译") - has_inline = False - except FileNotFoundError: - print(f" [警告] 找不到 llvm-link 或 opt,回退到单独编译") - has_inline = False - else: - print(" [警告] 未找到 llvm-link/opt 工具,回退到单独编译(alwaysinline 可能不生效)") - - from concurrent.futures import ThreadPoolExecutor, as_completed - import re - - def _compile_one(ll_path): - rel = os.path.relpath(ll_path, self.output_dir) - obj_path = ll_path[:-3] + '.obj' - if os.path.isfile(obj_path): - return (rel, 'cached', '') - try: - with open(ll_path, 'r', encoding='utf-8') as f: - ll_content = f.read() - sha1 = os.path.basename(ll_path)[:-3] - deps = self._load_deps(sha1) - stub_prefix = '' - if deps: - existing_symbols = {} - opaque_line_indices = {} - existing_declares = set() - existing_declare_lines = {} - for i, line in enumerate(ll_content.splitlines()): - stripped = line.strip() - if stripped.startswith('%') and '= type' in stripped: - m = re.match(r'%"?((?:[a-f0-9]+\.)?[\w.]+)"?\s*=', stripped) - if m: - name = m.group(1) - if '= type opaque' in stripped: - existing_symbols[name] = 'opaque' - opaque_line_indices[name] = i - else: - existing_symbols[name] = 'full' - elif stripped.startswith('declare'): - dm = re.match(r'declare\s+[^@]*@"?([^"\s(]+)"?', stripped) - if dm: - fname = dm.group(1) - existing_declares.add(fname) - existing_declare_lines[fname] = i - seen_stub_sha1 = set() - replaced_opaque_names = set() - replaced_declare_names = set() - all_stub_lines = [] - stub_type_map = {} - stub_declare_names = set() - stub_declare_lines = {} - existing_defines = set() - existing_global_defs = set() - stub_global_defs = set() - for line in ll_content.splitlines(): - stripped = line.strip() - if stripped.startswith('define'): - dm = re.match(r'define\s+[^@]*@"?([^"\s(]+)"?', stripped) - if dm: - existing_defines.add(dm.group(1)) - elif stripped.startswith('@') and (' global ' in stripped or ' constant ' in stripped): - gm = re.match(r'(@\S+)', stripped) - if gm: - existing_global_defs.add(gm.group(1)) - for dep_name, dep_sha1 in deps.items(): - if dep_sha1 in seen_stub_sha1: - continue - seen_stub_sha1.add(dep_sha1) - stub_path = os.path.join(self.output_dir, f"{dep_sha1}.stub.ll") - if not os.path.isfile(stub_path): - stub_path = os.path.join(self.temp_dir, f"{dep_sha1}.stub.ll") - if os.path.isfile(stub_path): - with open(stub_path, 'r', encoding='utf-8') as sf: - stub_content = sf.read() - for line in stub_content.splitlines(): - stripped = line.strip() - if stripped.startswith(';') or stripped.startswith('target ') or stripped.startswith('source_filename') or not stripped: - continue - if stripped.startswith('declare'): - dm = re.match(r'declare\s+[^@]*@"?([^"\s(]+)"?', stripped) - if dm: - fname = dm.group(1) - if re.search(r'%("[^"]+"|[a-f0-9]+\.[A-Za-z_]\w*)\s+%', stripped): - continue - if fname in existing_defines: - continue - if fname in existing_declares or fname in stub_declare_names: - existing_decl_line = stub_declare_lines.get(fname) - if existing_decl_line is not None: - has_struct = '%' in stripped - existing_has_struct = '%' in existing_decl_line if existing_decl_line else False - if has_struct and not existing_has_struct: - for i, l in enumerate(all_stub_lines): - if l is not None and l.strip().startswith('declare'): - em = re.match(r'declare\s+[^@]*@"?([^"\s(]+)"?', l.strip()) - if em and em.group(1) == fname: - all_stub_lines[i] = line - break - continue - elif fname in existing_declares: - has_struct = '%' in stripped - if has_struct: - replaced_declare_names.add(fname) - stub_declare_names.add(fname) - stub_declare_lines[fname] = line - all_stub_lines.append(line) - continue - continue - stub_declare_names.add(fname) - stub_declare_lines[fname] = line - all_stub_lines.append(line) - continue - if stripped.startswith('%') and '= type' in stripped: - m = re.match(r'%"?((?:[a-f0-9]+\.)?[\w.]+)"?\s*=', stripped) - if m: - name = m.group(1) - is_opaque = '= type opaque' in stripped - if name in existing_symbols: - if existing_symbols[name] == 'opaque' and not is_opaque: - replaced_opaque_names.add(name) - existing_symbols[name] = 'full' - idx = len(all_stub_lines) - all_stub_lines.append(line) - stub_type_map[name] = (is_opaque, idx) - continue - if name in stub_type_map: - prev_opaque, prev_idx = stub_type_map[name] - if prev_opaque and not is_opaque: - all_stub_lines[prev_idx] = None - idx = len(all_stub_lines) - all_stub_lines.append(line) - stub_type_map[name] = (is_opaque, idx) - continue - idx = len(all_stub_lines) - all_stub_lines.append(line) - stub_type_map[name] = (is_opaque, idx) - else: - all_stub_lines.append(line) - elif stripped.startswith('@') and (' global ' in stripped or ' constant ' in stripped): - gm = re.match(r'(@\S+)', stripped) - if gm and (gm.group(1) in existing_global_defs or gm.group(1) in stub_global_defs): - continue - if gm: - stub_global_defs.add(gm.group(1)) - all_stub_lines.append(line) - else: - all_stub_lines.append(line) - filtered = [l for l in all_stub_lines if l is not None] - if filtered: - stub_prefix = '\n'.join(filtered) + '\n' - lines_to_remove = set() - if replaced_opaque_names: - for name in replaced_opaque_names: - if name in opaque_line_indices: - lines_to_remove.add(opaque_line_indices[name]) - if replaced_declare_names: - for fname in replaced_declare_names: - if fname in existing_declare_lines: - lines_to_remove.add(existing_declare_lines[fname]) - if lines_to_remove: - ll_lines = ll_content.splitlines(True) - ll_content = ''.join(line for i, line in enumerate(ll_lines) if i not in lines_to_remove) - type_defs_in_ll = [] - type_def_line_indices = set() - for i, line in enumerate(ll_content.splitlines()): - stripped = line.strip() - if stripped.startswith('%') and '= type' in stripped: - type_defs_in_ll.append(line) - type_def_line_indices.add(i) - if type_def_line_indices: - ll_lines = ll_content.splitlines(True) - ll_content = ''.join(line for i, line in enumerate(ll_lines) if i not in type_def_line_indices) - if type_defs_in_ll: - stub_prefix += '\n'.join(type_defs_in_ll) + '\n' - if stub_prefix: - header_end = 0 - for i, line in enumerate(ll_content.splitlines()): - stripped = line.strip() - if stripped.startswith(';') or stripped.startswith('target ') or stripped.startswith('source_filename') or not stripped: - header_end = i + 1 - continue - break - ll_lines = ll_content.splitlines(True) - ll_content = ''.join(ll_lines[:header_end]) + stub_prefix + ''.join(ll_lines[header_end:]) - ll_content = re.sub(r'\b(define|declare)\s+(private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external)\s+', r'\1 \2 dso_local ', ll_content) - ll_content = re.sub(r'\b(define|declare)\s+(?!private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external|dso_local|@)', r'\1 dso_local ', ll_content) - ll_content = re.sub(r'(@[\w.]+)\s*=\s*(private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external)\s+(global|constant)', r'\1 = \2 dso_local \3', ll_content) - ll_content = re.sub(r'(@[\w.]+)\s*=\s+(?!private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external|dso_local)(global|constant)', r'\1 = dso_local \2', ll_content) - final_type_defs = [] - final_type_def_indices = set() - for i, line in enumerate(ll_content.splitlines()): - stripped = line.strip() - if stripped.startswith('%') and '= type' in stripped: - final_type_defs.append(line) - final_type_def_indices.add(i) - if final_type_def_indices: - final_lines = ll_content.splitlines(True) - ll_content_no_types = ''.join(line for i, line in enumerate(final_lines) if i not in final_type_def_indices) - header_end = 0 - for i, line in enumerate(ll_content_no_types.splitlines()): - stripped = line.strip() - if stripped.startswith(';') or stripped.startswith('target ') or stripped.startswith('source_filename') or not stripped: - header_end = i + 1 - continue - break - final_lines2 = ll_content_no_types.splitlines(True) - ll_content = ''.join(final_lines2[:header_end]) + '\n'.join(final_type_defs) + '\n' + ''.join(final_lines2[header_end:]) - dso_ll_path = ll_path[:-3] + '_dso.ll' - with open(dso_ll_path, 'w', encoding='utf-8') as f: - f.write(ll_content) - cmd = [self.compile_cmd] + self.compile_flags + ['-o', obj_path, dso_ll_path] - result = subprocess.run(cmd, capture_output=True, text=True, - cwd=os.path.dirname(ll_path) or '.') - if result.returncode == 0: - return (rel, 'ok', '') - else: - return (rel, 'error', result.stderr.strip()) - except FileNotFoundError: - return (rel, 'error', f'找不到编译器: {self.compile_cmd}') - except Exception as e: - return (rel, 'error', str(e)) - - need_compile = [] - for ll_path in ll_files: - obj_path = ll_path[:-3] + '.obj' - if not os.path.isfile(obj_path): - need_compile.append(ll_path) - - if need_compile: - n_workers = min(os.cpu_count() or 4, len(need_compile), 8) - print(f" 并行编译 {len(need_compile)} 个文件 (workers={n_workers})") - errors = [] - with ThreadPoolExecutor(max_workers=n_workers) as executor: - futures = {executor.submit(_compile_one, ll_path): ll_path for ll_path in need_compile} - for future in as_completed(futures): - rel, status, err = future.result() - if status == 'ok': - print(f" [成功] {rel}") - elif status == 'error': - print(f" [错误] {rel}: {err}") - errors.append((rel, err)) - elif status == 'cached': - pass - if errors: - print(f"\n[编译终止] {len(errors)} 个文件编译失败") - sys.exit(1) - - def _scan_include_libraries(self): - """扫描 includes 目录,检测被使用的模块对应的库文件和源文件""" - if not self.used_includes: - return - - for includes_dir in self.include_dirs: - if not os.path.isdir(includes_dir): - continue - - for module_name in self.used_includes: - module_dir = os.path.join(includes_dir, module_name) - if os.path.isdir(module_dir): - self._scan_dir_for_libs(module_dir, module_name) - for root, dirs, files in os.walk(module_dir): - dirs[:] = [d for d in dirs if not d.startswith('.') and d != '__pycache__'] - for fname in files: - if fname.endswith('.py'): - py_path = os.path.join(root, fname) - if py_path not in self.extra_py_files: - self.extra_py_files.append(py_path) - print(f" [includes] 发现 Python 包文件: {os.path.relpath(py_path, includes_dir)}") - - for ext in self.INCLUDE_LIB_EXTENSIONS: - lib_path = os.path.join(includes_dir, module_name + ext) - if os.path.isfile(lib_path): - self.extra_link_files.append(lib_path) - print(f" [includes] 发现库文件: {os.path.relpath(lib_path, includes_dir)}") - - for ext in self.INCLUDE_SRC_EXTENSIONS: - src_path = os.path.join(includes_dir, module_name + ext) - if os.path.isfile(src_path): - self.extra_compile_files.append(src_path) - print(f" [includes] 发现源文件: {os.path.relpath(src_path, includes_dir)}") - - py_path = os.path.join(includes_dir, module_name + '.py') - if os.path.isfile(py_path): - self.extra_py_files.append(py_path) - print(f" [includes] 发现 Python 源文件: {os.path.relpath(py_path, includes_dir)}") - - discovered = set() - for ef in list(self.extra_py_files): - self._discover_transitive_deps(ef, includes_dir, discovered) - - if self.extra_link_files: - print(f"\n[includes] 需要链接的库文件: {len(self.extra_link_files)} 个") - if self.extra_compile_files: - print(f"[includes] 需要编译的源文件: {len(self.extra_compile_files)} 个") - - def _scan_dir_for_libs(self, directory: str, module_name: str): - """递归扫描目录中的库文件和源文件""" - for root, dirs, files in os.walk(directory): - for fname in files: - fpath = os.path.join(root, fname) - _, ext = os.path.splitext(fname) - ext = ext.lower() - if ext in self.INCLUDE_LIB_EXTENSIONS: - self.extra_link_files.append(fpath) - print(f" [includes] 发现库文件: {os.path.relpath(fpath, directory)}") - elif ext in self.INCLUDE_SRC_EXTENSIONS: - self.extra_compile_files.append(fpath) - print(f" [includes] 发现源文件: {os.path.relpath(fpath, directory)}") - - def _discover_transitive_deps(self, py_path: str, includes_dir: str, discovered: set): - """递归发现 Python 文件的间接依赖""" - if py_path in discovered: - return - discovered.add(py_path) - try: - with open(py_path, 'r', encoding='utf-8') as f: - content = f.read() - import ast as _ast - tree = _ast.parse(content) - for node in _ast.walk(tree): - if isinstance(node, _ast.Import): - for alias in node.names: - mod = alias.name.split('.')[0] - self._try_add_include_dep(mod, includes_dir, discovered) - elif isinstance(node, _ast.ImportFrom): - if node.module and node.level == 0: - mod = node.module.split('.')[0] - self._try_add_include_dep(mod, includes_dir, discovered) - except Exception: - pass - - def _try_add_include_dep(self, module_name: str, includes_dir: str, discovered: set): - """尝试将模块添加为 include 依赖""" - py_path = os.path.join(includes_dir, module_name + '.py') - if os.path.isfile(py_path) and py_path not in self.extra_py_files: - self.extra_py_files.append(py_path) - print(f" [includes] 发现间接依赖: {os.path.relpath(py_path, includes_dir)}") - self._discover_transitive_deps(py_path, includes_dir, discovered) - - def _is_decl_only_file(self, src_path: str) -> bool: - try: - with open(src_path, 'r', encoding='utf-8') as f: - content = f.read() - import ast as _ast - tree = _ast.parse(content) - for node in _ast.walk(tree): - if isinstance(node, _ast.ClassDef): - return False - if isinstance(node, _ast.FunctionDef): - body = node.body - if len(body) == 1: - stmt = body[0] - if isinstance(stmt, _ast.Expr) and isinstance(stmt.value, _ast.Constant) and stmt.value.value is ...: - continue - if isinstance(stmt, _ast.Pass): - continue - return False - return True - except Exception: - return False - - def _sort_include_files_by_deps(self, file_list: list) -> list: - """按依赖关系对 include 文件进行拓扑排序,确保被依赖的文件先编译""" - import ast as _ast - - # 构建文件名到路径的映射 - name_to_path = {} - for fpath in file_list: - basename = os.path.splitext(os.path.basename(fpath))[0] - name_to_path[basename] = fpath - - # 也支持包内模块: vpsdk/window -> path - for fpath in file_list: - # 尝试从 includes 目录推断模块全名 - for includes_dir in self.include_dirs: - try: - rel = os.path.relpath(fpath, includes_dir) - mod_name = os.path.splitext(rel)[0].replace(os.sep, '.').replace('/', '.') - name_to_path[mod_name] = fpath - except ValueError: - pass - - # 分析每个文件的 import 依赖 - deps = {} # path -> set of paths it depends on - for fpath in file_list: - deps[fpath] = set() - try: - with open(fpath, 'r', encoding='utf-8') as f: - content = f.read() - tree = _ast.parse(content) - for node in _ast.iter_child_nodes(tree): - if isinstance(node, _ast.Import): - for alias in node.names: - mod = alias.name.split('.')[0] - if mod in name_to_path and name_to_path[mod] != fpath: - deps[fpath].add(name_to_path[mod]) - elif isinstance(node, _ast.ImportFrom): - if node.module and node.level == 0: - mod = node.module.split('.')[0] - if mod in name_to_path and name_to_path[mod] != fpath: - deps[fpath].add(name_to_path[mod]) - except Exception: - pass - - # 拓扑排序 (Kahn's algorithm) - in_degree = {fpath: len(deps[fpath]) for fpath in file_list} - # 反向邻接表:如果 A 依赖 B,则 B -> A - reverse_adj = {fpath: [] for fpath in file_list} - for fpath in file_list: - for dep in deps[fpath]: - if dep in reverse_adj: - reverse_adj[dep].append(fpath) - - result = [] - queue = [fpath for fpath in file_list if in_degree[fpath] == 0] - # 对队列排序以保持确定性 - queue.sort(key=lambda x: x) - - while queue: - current = queue.pop(0) - result.append(current) - for neighbor in reverse_adj[current]: - in_degree[neighbor] -= 1 - if in_degree[neighbor] == 0: - queue.append(neighbor) - queue.sort(key=lambda x: x) - - # 如果有循环依赖,把剩余文件也加入 - for fpath in file_list: - if fpath not in result: - result.append(fpath) - - return result - - def _compile_include_py_files(self, active_sha1s: set): - """通过 TransPyC 翻译器编译 includes 目录中发现的 .py 文件""" - if not self.extra_py_files: - return - - # 按依赖关系排序 include 文件,确保被依赖的文件先编译 - sorted_files = self._sort_include_files_by_deps(self.extra_py_files) - - print(f"\n[includes 编译] 找到 {len(sorted_files)} 个 Python 源文件") - - # 构建 include 文件的模块 SHA1 映射 - # 必须在编译前预构建完整的映射,否则后续文件引用前面文件时会用错误的 SHA1 - include_module_sha1_map = self._build_current_module_sha1_map(None) - # 预先为所有 include 文件计算 SHA1 并添加到映射中 - for src_path in sorted_files: - module_name = os.path.splitext(os.path.basename(src_path))[0] - with open(src_path, 'r', encoding='utf-8') as f: - py_content = f.read() - sha1 = compute_sha1(py_content) - self.include_py_map[module_name] = sha1 - active_sha1s.add(sha1) - self._include_sha1s.add(sha1) - - # 将 include 文件的模块名映射到其 SHA1 - for includes_dir in self.include_dirs: - try: - rel = os.path.relpath(src_path, includes_dir) - mod_full = os.path.splitext(rel)[0].replace(os.sep, '.').replace('/', '.') - include_module_sha1_map[mod_full] = sha1 - include_module_sha1_map[module_name] = sha1 - except ValueError: - pass - include_module_sha1_map[module_name] = sha1 - ll_path = os.path.join(self.output_dir, f"{sha1}.ll") - obj_path = os.path.join(self.output_dir, f"{sha1}.obj") - - if self._is_decl_only_file(src_path): - print(f" 跳过(声明文件): {module_name}.py") - self._collect_inline_symbols(src_path) - continue - - if os.path.isfile(obj_path): - print(f" 跳过(缓存): {module_name}.py -> {sha1}.obj") - self._collect_inline_symbols(src_path) - self.extra_link_files.append(obj_path) - continue - - print(f" 翻译: {os.path.basename(src_path)} -> {sha1}.ll") - - try: - self._translate_file(src_path, ll_path, prebuilt_module_sha1_map=include_module_sha1_map) - if os.path.isfile(ll_path): - print(f" 编译: {sha1}.ll -> {sha1}.obj") - with open(ll_path, 'r', encoding='utf-8') as f: - ll_content = f.read() - import re - ll_content = re.sub(r'\b(define|declare)\s+(private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external)\s+', r'\1 \2 dso_local ', ll_content) - ll_content = re.sub(r'\b(define|declare)\s+(?!private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external|dso_local)', r'\1 dso_local ', ll_content) - ll_content = re.sub(r'(@[\w.]+)\s*=\s*(private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external)\s+(global|constant)', r'\1 = \2 dso_local \3', ll_content) - ll_content = re.sub(r'(@[\w.]+)\s*=\s+(?!private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external|dso_local)(global|constant)', r'\1 = dso_local \2', ll_content) - stub_decls = [] - for other_sha1, other_stub in self.stub_files.items(): - if other_sha1 == sha1: - continue - if os.path.exists(other_stub): - try: - with open(other_stub, 'r', encoding='utf-8') as sf: - for sline in sf: - sl = sline.strip() - if sl.startswith('%') and '= type' in sl and 'opaque' not in sl: - struct_name_match = re.match(r'%"?([\w.]+)"?\s*=', sl) - if struct_name_match: - stub_decls.append(sl) - except: - pass - if stub_decls: - for sdecl in stub_decls: - sname_match = re.match(r'%"?([\w.]+)"?\s*=\s*type', sdecl) - if sname_match: - sname = sname_match.group(1) - short = sname.split('.')[-1] if '.' in sname else sname - ll_content = re.sub( - r'%"?' + re.escape(sname) + r'"?\s*=\s*type\s*opaque', - sdecl, ll_content) - if short != sname: - ll_content = re.sub( - r'%"?' + re.escape(short) + r'"?\s*=\s*type\s*opaque', - sdecl, ll_content) - dso_ll_path = ll_path[:-3] + '_dso.ll' - with open(dso_ll_path, 'w', encoding='utf-8') as f: - f.write(ll_content) - cmd = [self.compile_cmd] + self.compile_flags + ['-o', obj_path, dso_ll_path] - result = subprocess.run( - cmd, - capture_output=True, - text=True, - cwd=self.output_dir - ) - if result.returncode == 0: - print(f" [成功]") - self.extra_link_files.append(obj_path) - - # 编译成功后,生成 .pyi 签名文件和 .stub.ll 文件 - # 并注册到符号表和签名映射中,以便后续 include 文件可以引用 - self._register_compiled_include(src_path, sha1, ll_content, include_module_sha1_map) - else: - print(f" [警告] 编译失败: {result.stderr.strip()}") - for ext in ['.ll', '_dso.ll']: - p = ll_path[:-3] + ext - if os.path.isfile(p): - os.remove(p) - else: - print(f" [错误] 翻译未生成 .ll 文件") - except Exception as e: - import traceback - for ext in ['.ll', '_dso.ll']: - p = ll_path[:-3] + ext - if os.path.isfile(p): - os.remove(p) - print(f" [错误] 翻译异常: {e}") - traceback.print_exc() - print(f"\n[编译终止] includes 文件翻译失败") - sys.exit(1) - - def _register_compiled_include(self, src_path, sha1, ll_content, include_module_sha1_map): - """编译 include 文件成功后,生成签名和 stub 文件并注册到符号表中""" - module_name = os.path.splitext(os.path.basename(src_path))[0] - - # 确定完整模块名(如 vpsdk.window) - mod_full = module_name - for includes_dir in self.include_dirs: - try: - rel = os.path.relpath(src_path, includes_dir) - mod_full = os.path.splitext(rel)[0].replace(os.sep, '.').replace('/', '.') - break - except ValueError: - pass - - # 1. 生成 .pyi 签名文件(如果还没有的话) - sig_path = os.path.join(self.temp_dir, f"{sha1}.pyi") - if not os.path.isfile(sig_path): - try: - with open(src_path, 'r', encoding='utf-8') as f: - py_content = f.read() - sig_content = PythonToStubConverter.convert(py_content, mod_full) - os.makedirs(self.temp_dir, exist_ok=True) - with open(sig_path, 'w', encoding='utf-8', newline='\n') as f: - f.write(sig_content) - except Exception as e: - pass # 签名生成失败不阻塞编译 - - # 注册到 sig_files 和 _source_module_sig_files - if os.path.isfile(sig_path): - self.sig_files[sha1] = sig_path - self.sha1_map[sha1] = f"includes/{mod_full.replace('.', os.sep)}.py" - if hasattr(self, '_shared_source_module_sig_files') and self._shared_source_module_sig_files is not None: - self._shared_source_module_sig_files[mod_full] = sig_path - self._shared_source_module_sig_files[module_name] = sig_path - - # 将签名信息加载到共享符号表中 - if hasattr(self, '_shared_symbol_table') and self._shared_symbol_table is not None: - try: - self._shared_symbol_table.LoadModuleSymbols(sig_path, mod_full, lineno=0) - except Exception: - pass - - # 2. 生成 .stub.ll 文件 - stub_path = os.path.join(self.output_dir, f"{sha1}.stub.ll") - if not os.path.isfile(stub_path) and ll_content: - try: - stub_content, _ = self._split_ll(ll_content) - with open(stub_path, 'w', encoding='utf-8', newline='\n') as f: - f.write(stub_content) - except Exception: - pass - - # 注册到 stub_files - if os.path.isfile(stub_path): - self.stub_files[sha1] = stub_path - elif os.path.isfile(sig_path): - # 如果 stub 文件不存在,也尝试从 temp 目录查找 - temp_stub = os.path.join(self.temp_dir, f"{sha1}.stub.ll") - if os.path.isfile(temp_stub): - self.stub_files[sha1] = temp_stub - - def _precollect_inline_symbols(self): - """在主翻译循环之前,扫描includes目录中used_includes相关的模块收集内联函数AST""" - if not self.used_includes: - return - for includes_dir in self.include_dirs: - if not os.path.isdir(includes_dir): - continue - for module_name in self.used_includes: - module_dir = os.path.join(includes_dir, module_name) - if os.path.isdir(module_dir): - for root, dirs, files in os.walk(module_dir): - dirs[:] = [d for d in dirs if not d.startswith('.') and d != '__pycache__'] - for fname in files: - if fname.endswith('.py'): - src_path = os.path.join(root, fname) - self._collect_inline_symbols(src_path) - py_path = os.path.join(includes_dir, module_name + '.py') - if os.path.isfile(py_path): - self._collect_inline_symbols(py_path) - for ef in self.extra_py_files: - self._collect_inline_symbols(ef) - - def _collect_inline_symbols(self, src_path: str): - """解析源文件,收集内联函数的AST信息到inline_func_symbols""" - try: - with open(src_path, 'r', encoding='utf-8') as f: - code = f.read() - tree = ast.parse(code) - module_name = os.path.splitext(os.path.basename(src_path))[0] - for node in ast.iter_child_nodes(tree): - if isinstance(node, ast.FunctionDef) and node.returns: - is_inline = False - if isinstance(node.returns, ast.BinOp) and isinstance(node.returns.op, ast.BitOr): - for part in [node.returns.left, node.returns.right]: - if isinstance(part, ast.Attribute) and part.attr == 'CInline': - is_inline = True - break - if isinstance(part, ast.Name) and part.id == 'CInline': - is_inline = True - break - elif isinstance(node.returns, ast.Attribute) and node.returns.attr == 'CInline': - is_inline = True - elif isinstance(node.returns, ast.Name) and node.returns.id == 'CInline': - is_inline = True - if is_inline: - func_name = node.name - sym_key = f"{module_name}.{func_name}" - info = CTypeInfo() - info.Name = func_name - info.IsFunction = True - info.IsInline = True - info.InlineBody = node.body - info.InlineParams = [arg.arg for arg in node.args.args] - info.Storage = t.CInline() - self.inline_func_symbols[func_name] = info - self.inline_func_symbols[sym_key] = info - except Exception: - pass - - def _build_shared_symbol_data(self): - """一次性构建所有文件共享的符号表数据,避免每个文件重复加载""" - import copy - import time - t0 = time.time() - - print("[缓存] 构建共享符号表数据...") - - base_trans = TransPyC.TransPyC(code="pass", triple=self.triple, datalayout=self.datalayout) - base_trans.translator.LlvmGen = None - base_trans.translator._module_sha1_map = {} - base_trans.translator._global_function_default_args = self.function_default_args - - for includes_dir in self.include_dirs: - if os.path.isdir(includes_dir): - for pyi_file in os.listdir(includes_dir): - if pyi_file.endswith('.pyi'): - pyi_path = os.path.join(includes_dir, pyi_file) - module_name = os.path.splitext(pyi_file)[0] - base_trans.translator.SymbolTable.LoadModuleSymbols(pyi_path, module_name, lineno=0) - for py_file in os.listdir(includes_dir): - if py_file.endswith('.py') and not py_file.startswith('_'): - module_name = os.path.splitext(py_file)[0] - sha1_key = self.include_py_map.get(module_name) - if sha1_key and sha1_key in self.sig_files: - sig_path = self.sig_files[sha1_key] - base_trans.translator.SymbolTable.LoadModuleSymbols(sig_path, module_name, lineno=0) - for sha1_key, sig_path in self.sig_files.items(): - rel_path = self.sha1_map.get(sha1_key, sha1_key) - if rel_path.startswith('includes/'): - mod_name = os.path.splitext(rel_path)[0].replace(os.sep, '.').replace('/', '.') - mod_name = mod_name[len('includes/'):] - base_trans.translator.SymbolTable.LoadModuleSymbols(sig_path, mod_name, lineno=0) - if mod_name.endswith('.__init__'): - package_name = mod_name[:-len('.__init__')] - self._register_package_reexports(base_trans, sig_path, package_name) - - for sha1_key, sig_path in self.sig_files.items(): - rel_path = self.sha1_map.get(sha1_key, sha1_key) - if rel_path.startswith('includes/'): - continue - module_name = os.path.splitext(rel_path)[0].replace(os.sep, '.').replace('/', '.') - base_trans.translator.SymbolTable.LoadModuleSymbols(sig_path, module_name, lineno=0) - base_trans.translator._source_module_sig_files[module_name] = sig_path - short_name = module_name.split('.')[-1] if '.' in module_name else module_name - if short_name != module_name: - base_trans.translator._source_module_sig_files[short_name] = sig_path - - all_dc = {} - for sha1_key, stub_path in self.stub_files.items(): - if os.path.exists(stub_path): - try: - with open(stub_path, 'r', encoding='utf-8') as f: - stub_content = f.read() - for line in stub_content.splitlines(): - line = line.strip() - if line.startswith('@') and '= global' in line and 'i32' in line and not line.startswith('@llvm'): - var_name = line.split('=')[0].strip().lstrip('@') - val_part = line.split('i32')[-1].strip().rstrip(']').lstrip('[').lstrip('i32') - try: - val = int(val_part) - all_dc[var_name] = val - except: - pass - except: - pass - for sha1_key, pyi_path in self.sig_files.items(): - if os.path.exists(pyi_path): - try: - with open(pyi_path, 'r', encoding='utf-8') as f: - pyi_content = f.read() - tree = ast.parse(pyi_content) - for node in ast.iter_child_nodes(tree): - if isinstance(node, ast.AnnAssign) and isinstance(node.target, ast.Name): - ann_str = ast.dump(node.annotation) - if 'CDefine' in ann_str and node.value: - val = None - if isinstance(node.value, ast.Constant): - val = node.value.value - elif isinstance(node.value, ast.Call) and isinstance(node.value.func, ast.Name) and node.value.func.id == 'float' and node.value.args and isinstance(node.value.args[0], ast.Constant): - val = node.value.args[0].value - if val is not None: - all_dc[f"{node.target.id}"] = val - except: - pass - - export_extern_funcs = set() - for sha1_key, sig_path in self.sig_files.items(): - try: - with open(sig_path, 'r', encoding='utf-8') as f: - sig_content = f.read() - sig_tree = ast.parse(sig_content) - for node in ast.iter_child_nodes(sig_tree): - if isinstance(node, ast.FunctionDef): - if _check_annotation_for_export(node.returns): - export_extern_funcs.add(node.name) - except Exception: - pass - - for sym_name, sym_info in self.inline_func_symbols.items(): - if sym_name not in base_trans.translator.SymbolTable: - base_trans.translator.SymbolTable[sym_name] = sym_info - else: - existing = base_trans.translator.SymbolTable[sym_name] - if not getattr(existing, 'InlineBody', None) and getattr(sym_info, 'InlineBody', None): - existing.IsInline = sym_info.IsInline - existing.InlineBody = sym_info.InlineBody - existing.InlineParams = sym_info.InlineParams - - self._shared_symbol_table = base_trans.translator.SymbolTable - self._shared_source_module_sig_files = dict(base_trans.translator._source_module_sig_files) - self._shared_all_dc = all_dc - self._shared_export_extern_funcs = export_extern_funcs - - generic_class_templates = {} - for includes_dir in self.include_dirs: - if os.path.isdir(includes_dir): - abs_includes = os.path.join(self.src_root, includes_dir) if not os.path.isabs(includes_dir) else includes_dir - if not os.path.isdir(abs_includes): - abs_includes = includes_dir - for py_file in os.listdir(abs_includes): - if py_file.endswith('.py') and not py_file.startswith('_'): - py_path = os.path.join(abs_includes, py_file) - try: - with open(py_path, 'r', encoding='utf-8') as f: - py_code = f.read() - py_tree = ast.parse(py_code) - for node in py_tree.body: - if isinstance(node, ast.ClassDef) and hasattr(node, 'type_params') and node.type_params: - type_params = [tp.name for tp in node.type_params] - generic_class_templates[node.name] = { - 'node': node, - 'type_params': type_params, - } - except Exception: - pass - self._shared_generic_class_templates = generic_class_templates - - t1 = time.time() - print(f"[缓存] 共享符号表构建完成 ({t1-t0:.2f}s, {len(self._shared_symbol_table)} 符号, {len(generic_class_templates)} 泛型模板)") - - def _compile_include_sources(self): - """扫描项目目录中的汇编存根,编译 includes 目录中发现的 C/C++ 源文件""" - extra_sources = list(self.extra_compile_files) - scan_dirs = [] - if self.src_root and os.path.isdir(self.src_root): - scan_dirs.append(self.src_root) - project_dir = os.path.dirname(self.output_dir) - if project_dir and os.path.isdir(project_dir) and project_dir not in scan_dirs: - scan_dirs.append(project_dir) - for scan_dir in scan_dirs: - for root, dirs, files in os.walk(scan_dir): - dirs[:] = [d for d in dirs if not d.startswith('.') and d != '__pycache__'] - for fname in files: - if fname.endswith(('.S', '.s', '.c', '.cpp')): - if fname.startswith('test_'): - continue - fpath = os.path.join(root, fname) - if fpath not in extra_sources: - extra_sources.append(fpath) - if not extra_sources: - return - - cc_map = { - '.c': 'gcc', - '.cpp': 'g++', '.cc': 'g++', '.cxx': 'g++', - '.m': 'clang', '.mm': 'clang++', - '.s': 'gcc', '.S': 'gcc', - } - - print(f"\n[includes 编译] 找到 {len(extra_sources)} 个源文件") - - for src_path in extra_sources: - _, ext = os.path.splitext(src_path) - ext = ext.lower() - obj_path = os.path.join(self.output_dir, os.path.splitext(os.path.basename(src_path))[0] + '.obj') - if ext in ('.s', '.S') and any('oformat' in f for f in self.linker_flags): - cc = 'clang' - compile_src = src_path - extra_flags = ['-c', '-target', 'x86_64-none-elf', '-o', obj_path, compile_src] - else: - cc = cc_map.get(ext, 'gcc') - extra_flags = ['-c', '-o', obj_path, src_path] - - print(f" 编译: {os.path.basename(src_path)} -> {os.path.basename(obj_path)}") - - try: - cmd = [cc] + extra_flags - result = subprocess.run(cmd, capture_output=True, text=True) - if result.returncode == 0: - print(f" [成功]") - self.extra_link_files.append(obj_path) - else: - print(f" [错误] 编译失败: {result.stderr.strip()}") - print(f"\n[编译终止] C/C++ 源文件编译失败,立即终止编译。") - sys.exit(1) - except FileNotFoundError: - print(f" [错误] 找不到编译器: {cc}") - print(f"\n[编译终止] 找不到编译器,立即终止编译。") - sys.exit(1) - except Exception as e: - print(f" [错误] {e}") - print(f"\n[编译终止] 编译异常,立即终止编译。") - sys.exit(1) - - def _strip_debug_sections(self, exe_path: str): - """剥离 .exe 中的调试段(跳过裸机二进制)""" - if not os.path.exists(exe_path): - return - ext = os.path.splitext(exe_path)[1].lower() - if ext not in ('.exe', '.dll', '.obj', '.o', '.elf'): - print(f" [剥离] 跳过({ext} 格式无需剥离)") - return - import shutil - for tool in ['llvm-strip', 'strip']: - strip_cmd = shutil.which(tool) - if strip_cmd: - try: - result = subprocess.run( - [strip_cmd, '--strip-debug', exe_path], - capture_output=True, text=True - ) - if result.returncode == 0: - print(f" [剥离] 调试段已移除 ({tool})") - else: - print(f" [剥离] 警告: {result.stderr.strip()}") - except Exception: - pass - break - - def _link_obj_files(self, active_sha1s: set): - """将 active_sha1s 对应的 .obj 文件和 includes 库文件链接为可执行文件""" - obj_files = [] - merged_obj = os.path.join(self.output_dir, '_merged.obj') - if os.path.isfile(merged_obj): - obj_files.append(merged_obj) - else: - for root, dirs, files in os.walk(self.output_dir): - for file in files: - if file.endswith('.obj'): - sha1 = file[:-4] - if sha1 in active_sha1s and sha1 not in self._include_sha1s: - obj_files.append(os.path.join(root, file)) - - if not obj_files and not self.extra_link_files: - print("[链接] 无文件可链接") - return - - print(f"\n[链接] 找到 {len(obj_files)} 个 .obj 文件") - - all_link_files = obj_files + self.extra_link_files - seen = set() - all_link_files = [f for f in all_link_files if not (f in seen or seen.add(f))] - if self.extra_link_files: - print(f"[链接] 额外库文件: {len(self.extra_link_files)} 个") - for lib in self.extra_link_files: - print(f" - {os.path.basename(lib)}") - - if not self.linker_cmd: - print("[链接] 未配置链接器") - return - - exe_path = os.path.join(self.output_dir, self.linker_output) if self.linker_output else os.path.join(self.output_dir, 'a.exe') - is_binary = self.linker_output and self.linker_output.endswith('.bin') - - # 检查是否直接输出二进制(使用 --oformat binary / -oformat binary 标志) - is_direct_binary = is_binary and any('oformat' in f for f in self.linker_flags) - - if is_binary and not is_direct_binary: - link_output = exe_path[:-4] + '_pe.exe' - else: - link_output = exe_path - - # 自动复制或生成 linker.ld 到输出目录 - linker_ld_src = os.path.join(os.path.dirname(self.output_dir), 'linker.ld') - linker_ld_dst = os.path.join(self.output_dir, 'linker.ld') - if os.path.isfile(linker_ld_src) and not os.path.isfile(linker_ld_dst): - import shutil - shutil.copy2(linker_ld_src, linker_ld_dst) - print(f" [链接] 使用链接脚本: linker.ld") - elif not os.path.isfile(linker_ld_dst) and any('-T' in f or '-T' in f.replace(',', ' ') for f in self.linker_flags): - default_ld = """ENTRY(_start) - -SECTIONS { - . = 0x100000; - - .text : { - *(.text.startup) - *(.text) - *(.text.*) - } - - .rodata : { - *(.rodata) - *(.rodata.*) - } - - .data : { - *(.data) - *(.data.*) - } - - .bss : { - *(.bss) - *(.bss.*) - } - - /DISCARD/ : { - *(.comment) - *(.note) - *(.eh_frame) - *(.eh_frame_hdr) - *(.reloc) - *(.rela) - *(.debug*) - } -} -""" - with open(linker_ld_dst, 'w', encoding='utf-8', newline='\n') as f: - f.write(default_ld) - print(f" [链接] 自动创建默认链接脚本: linker.ld") - - try: - cmd = [self.linker_cmd] + self.linker_flags + ['-o', link_output] + all_link_files - print(f" 执行: {' '.join(cmd)}") - result = subprocess.run( - cmd, - capture_output=True, - text=True, - cwd=self.output_dir or '.' - ) - if result.returncode == 0: - if is_binary and not is_direct_binary: - import shutil - objcopy = shutil.which('llvm-objcopy') or shutil.which('objcopy') - if objcopy: - conv = subprocess.run( - [objcopy, '-O', 'binary', link_output, exe_path], - capture_output=True, text=True - ) - if conv.returncode == 0: - os.remove(link_output) - print(f" [成功] 生成裸机二进制: {exe_path}") - file_size = os.path.getsize(exe_path) - print(f" [大小] {file_size} 字节") - else: - print(f" [错误] 二进制转换失败: {conv.stderr.strip()}") - sys.exit(1) - else: - print(" [错误] 找不到 llvm-objcopy,无法生成裸机二进制") - sys.exit(1) - else: - print(f" [成功] 生成: {exe_path}") - file_size = os.path.getsize(exe_path) - print(f" [大小] {file_size} 字节") - if not is_binary: - self._strip_debug_sections(exe_path) - else: - print(f" [错误] 链接失败: {result.stderr.strip()}") - print(f"\n[编译终止] 链接失败,立即终止编译。") - sys.exit(1) - except FileNotFoundError: - print(f" [错误] 找不到链接器: {self.linker_cmd}") - print(f"\n[编译终止] 找不到链接器,立即终止编译。") - sys.exit(1) - except Exception as e: - print(f" [错误] {e}") - print(f"\n[编译终止] 链接异常,立即终止编译。") - sys.exit(1) - - -def save_sha1_map(temp_dir: str, sha1_map: dict[str, str]): - """将 SHA1 映射表保存到文件""" - map_path = os.path.join(temp_dir, '_sha1_map.txt') - with open(map_path, 'w', encoding='utf-8') as f: - for sha1, rel in sorted(sha1_map.items()): - f.write(f"{sha1}:{rel}\n") - - -def load_sha1_map(temp_dir: str) -> dict[str, str]: - """从文件加载 SHA1 映射表""" - map_path = os.path.join(temp_dir, '_sha1_map.txt') - result = {} - if os.path.exists(map_path): - with open(map_path, 'r', encoding='utf-8') as f: - for line in f: - line = line.strip() - if ':' in line: - sha1, rel = line.split(':', 1) - result[sha1] = rel - return result - - -def load_project_config(project_file: str) -> dict: - """从 project.json 加载配置""" - import json - with open(project_file, 'r', encoding='utf-8') as f: - return json.load(f) - - -def resolve_paths(config: dict, project_file: str) -> dict: - """将配置中的相对路径转换为绝对路径""" - project_dir = os.path.dirname(os.path.abspath(project_file)) - result = dict(config) - - def resolve(p): - if p is None: - return None - if os.path.isabs(p): - return p - return os.path.normpath(os.path.join(project_dir, p)) - - if 'source_dir' in result: - result['source_dir'] = resolve(result.get('source_dir')) - elif 'sources' in result: - resolved_sources = [] - for src in result['sources']: - if '*' in src or '?' in src: - import glob as glob_module - for matched in glob_module.glob(os.path.join(project_dir, src), recursive=True): - if os.path.isfile(matched): - resolved_sources.append(matched) - else: - resolved_sources.append(resolve(src)) - result['sources'] = [s for s in resolved_sources if os.path.isfile(s)] - - result['temp_dir'] = resolve(config.get('temp_dir')) - result['output_dir'] = resolve(config.get('output_dir')) - - if 'includes' in result: - result['includes'] = [resolve(inc) for inc in result['includes']] - - result['_project_dir'] = project_dir - return result - - -def main(): - import argparse - parser = argparse.ArgumentParser( - description='TransPyC 工程翻译器 - 基于 project.json 的两阶段翻译', - formatter_class=argparse.RawDescriptionHelpFormatter, - epilog=''' -示例: - # 从 project.json 读取配置并执行(默认查找当前目录) - python ProjectTrans.py - - # 指定 project.json 文件 - python ProjectTrans.py --project ./TestProject/project.json - - # 使用命令行参数覆盖 project.json 配置 - python ProjectTrans.py --src ./src --temp ./decl --output ./out --phase all - - # 仅运行阶段一 - python ProjectTrans.py --phase 1 - - # 仅运行阶段二 - python ProjectTrans.py --phase 2 - - # 清理临时目录 - python ProjectTrans.py --clean -''' - ) - parser.add_argument('--project', help='project.json 路径(默认查找当前目录)') - parser.add_argument('--src', help='源文件目录(覆盖 project.json)') - parser.add_argument('--temp', help='声明接口临时目录(覆盖 project.json)') - parser.add_argument('--output', help='输出目录(覆盖 project.json)') - parser.add_argument('--phase', choices=['1', '2', 'all'], help='阶段: 1=生成声明, 2=翻译+编译, all=全部') - parser.add_argument('--cc', help='LLVM 编译器命令(覆盖 project.json)') - parser.add_argument('--clean', action='store_true', help='清理 output 和 temp 目录') - - args = parser.parse_args() - - project_file = args.project - if not project_file: - candidates = ['project.json', './project.json'] - for c in candidates: - if os.path.exists(c): - project_file = c - break - - if project_file and os.path.exists(project_file): - print(f"[配置] 读取: {project_file}") - config = load_project_config(project_file) - project_dir = os.path.dirname(os.path.abspath(project_file)) - print(f"[配置] 项目目录: {project_dir}") - else: - print("[错误] 未找到 project.json,请使用 --project 指定") - sys.exit(1) - - resolved = resolve_paths(config, project_file) - src = args.src or resolved.get('source_dir') or resolved.get('sources') - temp_dir = args.temp or resolved.get('temp_dir') - output_dir = args.output or resolved.get('output_dir') - phase = args.phase or 'all' - cc_cmd = args.cc or resolved.get('compiler', {}).get('cmd', 'llc') - cc_flags = resolved.get('compiler', {}).get('flags', ['-filetype=obj']) - slice_level = resolved.get('options', {}).get('slice_level', 3) - project_include_dirs = resolved.get('includes', []) - target_triple = resolved.get('target', {}).get('triple') - target_datalayout = resolved.get('target', {}).get('datalayout') - - if isinstance(src, list): - if len(src) == 1 and os.path.isdir(src[0]): - src = src[0] - else: - src = src[0] if len(src) == 1 else os.path.dirname(os.path.commonpath(src)) if all(os.path.exists(p) for p in src) else src[0] - - print(f"[配置] 源目录: {src}") - print(f"[配置] 临时目录: {temp_dir}") - print(f"[配置] 输出目录: {output_dir}") - print(f"[配置] 阶段: {phase}") - print(f"[配置] 编译器: {cc_cmd} {' '.join(cc_flags)}") - if target_triple: - print(f"[配置] 目标三元组: {target_triple}") - if target_datalayout: - print(f"[配置] 数据布局: {target_datalayout}") - - if args.clean: - if output_dir and os.path.exists(output_dir): - for f in os.listdir(output_dir): - fpath = os.path.join(output_dir, f) - try: - if os.path.isfile(fpath) or os.path.islink(fpath): - os.remove(fpath) - elif os.path.isdir(fpath): - shutil.rmtree(fpath, ignore_errors=True) - except: - pass - print(f"[清理] output: 已清空 {output_dir}") - if temp_dir and os.path.exists(temp_dir): - for f in os.listdir(temp_dir): - fpath = os.path.join(temp_dir, f) - try: - if os.path.isfile(fpath) or os.path.islink(fpath): - os.remove(fpath) - elif os.path.isdir(fpath): - shutil.rmtree(fpath, ignore_errors=True) - except: - pass - print(f"[清理] temp: 已清空 {temp_dir}") - print("[清理] 完成") - if (not phase or phase == 'all') and not args.project: - return - - if phase in ('1', 'all'): - if isinstance(src, list): - print("[错误] 阶段一需要指定源目录,不支持文件列表") - sys.exit(1) - all_include_dirs = list(project_include_dirs) if project_include_dirs else [] - for d in Phase2Translator.INCLUDE_DIRS: - if os.path.isdir(d): - d = os.path.abspath(d) - if d not in [os.path.abspath(x) for x in all_include_dirs]: - all_include_dirs.append(d) - gen = Phase1Generator(src, temp_dir, include_dirs=all_include_dirs, target_triple=target_triple, target_datalayout=target_datalayout) - gen.run() - save_sha1_map(temp_dir, gen.sha1_map) - - if phase in ('2', 'all'): - if not output_dir: - print("[错误] 阶段二需要指定 --output 目录") - sys.exit(1) - if not os.path.exists(temp_dir): - print(f"[错误] 声明目录不存在,请先运行阶段一: {temp_dir}") - sys.exit(1) - if isinstance(src, list): - print("[错误] 阶段二需要指定源目录,不支持文件列表") - sys.exit(1) - linker_cmd = resolved.get('linker', {}).get('cmd') - linker_flags = resolved.get('linker', {}).get('flags', []) - linker_output = resolved.get('linker', {}).get('output') - target_triple = resolved.get('target', {}).get('triple') - target_datalayout = resolved.get('target', {}).get('datalayout') - trans = Phase2Translator(src, temp_dir, output_dir, compile_cmd=cc_cmd, compile_flags=cc_flags, linker_cmd=linker_cmd, linker_flags=linker_flags, linker_output=linker_output, include_dirs=project_include_dirs, target_triple=target_triple, target_datalayout=target_datalayout) - trans.sha1_map = load_sha1_map(temp_dir) - trans.slice_level = slice_level - trans.run() +__all__ = [ + 'compute_sha1', '_check_annotation_for_export', 'sha1_file', + 'get_file_dependencies', 'find_reachable_files_from_entries', + 'topological_sort_files', 'Phase1Generator', 'DeclarationGenerator', + 'Phase2Translator', '_parallel_translate_worker', + 'save_sha1_map', 'Load_sha1_map', 'Load_project_config', 'resolve_paths', 'main' +] if __name__ == '__main__': main() diff --git a/StubGen.py b/StubGen.py index 823e842..57447dd 100644 --- a/StubGen.py +++ b/StubGen.py @@ -1,1337 +1,12 @@ -#!/usr/bin/env python3 -""" -StubGen - C/H/Py 文件到 Python 存根文件生成器(工程化版本) - -用法: - python StubGen.py -c config.json - python StubGen.py -i input.h -o output.py - python StubGen.py -d ./kernel -o ./kernel/include - -示例配置: - { - "InputDir": "./kernel", - "OutputDir": "./kernel/include", - "IncludePatterns": ["*.h", "*.c", "*.py"], - "ExcludePatterns": ["*_test.py"], - "PreserveStructure": true, - "GenerateGuards": true, - "TypeMappings": { - "custom_type": "t.CCustom" - } - } -""" - -import sys -import os -import re -import json -import ast -import argparse -import logging -from pathlib import Path -from typing import List, Dict, Optional, Set, Tuple -from dataclasses import dataclass, field - -sys.path.insert(0, os.path.dirname(__file__)) - -from lib.core.stub_generator import CHeaderParser, PythonStubGenerator, CTypeMapper - - -@dataclass -class StubGenConfig: - """存根生成器配置""" - InputDir: Optional[str] = None - OutputDir: str = "./stubs" - InputFiles: List[str] = field(default_factory=list) - IncludePatterns: List[str] = field(default_factory=lambda: ["*.h", "*.c", "*.py"]) - ExcludePatterns: List[str] = field(default_factory=list) - TypeMappings: Dict[str, str] = field(default_factory=dict) - PreserveStructure: bool = True # 保持目录结构 - GenerateGuards: bool = True # 生成宏守卫 - verbose: bool = False - DryRun: bool = False - - @classmethod - def from_dict(cls, data: Dict) -> 'StubGenConfig': - """从字典创建配置""" - return cls( - InputDir=data.get('InputDir'), - OutputDir=data.get('OutputDir', './stubs'), - InputFiles=data.get('InputFiles', []), - IncludePatterns=data.get('IncludePatterns', ['*.h', '*.c', '*.py']), - ExcludePatterns=data.get('ExcludePatterns', []), - TypeMappings=data.get('TypeMappings', {}), - PreserveStructure=data.get('PreserveStructure', True), - GenerateGuards=data.get('GenerateGuards', True), - verbose=data.get('verbose', False), - DryRun=data.get('DryRun', False), - ) - - @classmethod - def from_file(cls, FilePath: str) -> 'StubGenConfig': - """从 JSON 文件加载配置""" - with open(FilePath, 'r', encoding='utf-8') as f: - data = json.load(f) - return cls.from_dict(data) - - -class PythonToStubConverter: - """将 Python 文件转换为存根格式""" - - # __include 别名映射表 {alias: ModuleName} - IncludeAliasMap: Dict[str, str] = {} - - # 变量排除列表 - 匹配这些模式的变量不会被添加到存根文件 - VarExcludeList: List[str] = [] - - # 宏排除列表 - 匹配这些模式的宏不会被添加到存根文件 - MacroExcludeList: List[str] = [] - - @classmethod - def SetIncludeAliasMap(cls, alias_map: Dict[str, str]): - """设置 __include 别名映射表""" - cls.IncludeAliasMap = alias_map - - @classmethod - def SetVarExcludeList(cls, exclude_list: List[str]): - """设置变量排除列表""" - cls.VarExcludeList = exclude_list - - @classmethod - def SetMacroExcludeList(cls, exclude_list: List[str]): - """设置宏排除列表""" - cls.MacroExcludeList = exclude_list - - @classmethod - def _ShouldExcludeVar(cls, VarName: str) -> bool: - """检查变量是否应该被排除""" - import fnmatch - for pattern in cls.VarExcludeList: - if fnmatch.fnmatch(VarName, pattern): - return True - return False - - @classmethod - def _ShouldExcludeMacro(cls, MacroName: str) -> bool: - """检查宏是否应该被排除""" - import fnmatch - for pattern in cls.MacroExcludeList: - if fnmatch.fnmatch(MacroName, pattern): - return True - return False - - @staticmethod - def convert(PyContent: str, ModuleName: str) -> str: - """将 Python 代码转换为存根格式""" - lines = PyContent.split('\n') - StubLines = [] - - # 添加文件头 - StubLines.append('"""') - StubLines.append(f'Auto-generated Python stub file from {ModuleName}.py') - StubLines.append(f'Module: {ModuleName}') - StubLines.append('"""') - StubLines.append('') - - # 解析 Python 代码,检查是否已经导入了 t 和 c - import ast - HasImportT = False - HasImportC = False - try: - tree = ast.parse(PyContent) - for node in tree.body: - if isinstance(node, ast.Import): - for alias in node.names: - if alias.name == 't': - HasImportT = True - elif alias.name == 'c': - HasImportC = True - except: - pass - - # 添加默认导入(如果源代码中没有) - if not HasImportT: - StubLines.append('import t') - if not HasImportC: - StubLines.append('import c') - if not HasImportT or not HasImportC: - StubLines.append('') - - # 添加 c.CPragma("once") - # StubLines.append('c.CPragma("once")') - StubLines.append('') - - # 生成文件级别宏守卫名称 - #FileGuardName = f'__{ModuleName.upper()}_DEFINE__' - - # 添加文件开头宏守卫 - #StubLines.append(f'c.CIfndef({FileGuardName})') - #StubLines.append(f'{FileGuardName}: t.CDefine') - #StubLines.append('') - - # 解析 Python 代码,提取类型定义 - try: - tree = ast.parse(PyContent) - - # 第一遍扫描:收集 Postdefinition 变量 - PostdefVars = {} # {ClassName: [(VarName, TypeStr, node), ...]} - for node in tree.body: - if isinstance(node, ast.AnnAssign) and isinstance(node.target, ast.Name): - TypeStr = PythonToStubConverter._GetTypeString(node.annotation) - # 检查是否是 Postdefinition 类型 - if 't.Postdefinition' in TypeStr: - # 提取引用的类名 - ClassName = PythonToStubConverter._ExtractPostdefClass(node.annotation) - if ClassName: - if ClassName not in PostdefVars: - PostdefVars[ClassName] = [] - PostdefVars[ClassName].append((node.target.id, TypeStr, node)) - - # 按原始顺序处理节点,保持代码的原始顺序 - PrevType = None # 记录前一个节点的类型 - - for node in tree.body: - CurrentType = None - - if isinstance(node, ast.ClassDef): - CurrentType = 'class' - # 如果前一个不是类,添加空行分隔 - if PrevType is not None and PrevType != 'class': - StubLines.append('') - # 检查是否有对应的 Postdefinition 变量 - ClassPostdefs = PostdefVars.get(node.name, []) - ClassLines = PythonToStubConverter._ConvertClass( - node, SourceLines=lines, PostdefVars=ClassPostdefs - ) - StubLines.extend(ClassLines) - elif isinstance(node, ast.FunctionDef): - CurrentType = 'function' - # 如果前一个是类或者是第一个函数,添加空行分隔 - if PrevType == 'class' or (PrevType is not None and PrevType != 'function'): - StubLines.append('') - FuncLines = PythonToStubConverter._ConvertFunction(node, SourceLines=lines) - StubLines.extend(FuncLines) - StubLines.append('') # 函数后空行 - elif isinstance(node, ast.AnnAssign): - CurrentType = 'variable' - # 跳过 Postdefinition 变量(已经在类中处理) - TypeStr = PythonToStubConverter._GetTypeString(node.annotation) - if 't.Postdefinition' in TypeStr: - continue - # 检查是否带有 t.CStatic 标志,如果有则不排除 - HasStatic = 't.CStatic' in TypeStr - # 检查变量是否应该被排除 - ShouldExclude = False - if isinstance(node.target, ast.Name) and not HasStatic: - VarName = node.target.id - if PythonToStubConverter._ShouldExcludeVar(VarName): - ShouldExclude = True - if ShouldExclude: - continue - # 如果前一个不是变量,添加空行分隔 - if PrevType is not None and PrevType != 'variable': - StubLines.append('') - VarLines = PythonToStubConverter._ConvertVariable(node, SourceLines=lines) - # 移除多余的空行 - VarLines = [line for line in VarLines if line.strip()] - StubLines.extend(VarLines) - elif isinstance(node, ast.Import): - # 处理导入语句 - CurrentType = 'import' - ImportStr = PythonToStubConverter._GetImportString(node, SourceLines=lines) - if ImportStr: - if PrevType is not None and PrevType != 'import': - StubLines.append('') - StubLines.append(ImportStr) - elif isinstance(node, ast.Assign): - CurrentType = 'variable' - # 处理模块级别的全局变量(无类型标注) - if PrevType is not None and PrevType != 'variable': - StubLines.append('') - AssignLines = PythonToStubConverter._ConvertGlobalAssign(node) - StubLines.extend(AssignLines) - elif isinstance(node, ast.ImportFrom): - # 处理 from ... import ... 语句 - CurrentType = 'import' - ImportStr = PythonToStubConverter._GetImportFromString(node, SourceLines=lines) - if ImportStr: - if PrevType is not None and PrevType != 'import': - StubLines.append('') - StubLines.append(ImportStr) - elif isinstance(node, ast.Expr): - # 处理模块级别的宏调用,如 c.CIf(...), c.CEndif() - ExprStr = PythonToStubConverter._GetExprString(node.value) - if ExprStr: - CurrentType = 'macro' - StubLines.append(ExprStr) - StubLines.append('') # 宏后空行 - elif isinstance(node, ast.If): - # 处理模块级别的 if 宏条件,如 if c.CIf(FF_MULTI_PARTITION): - IfStr = PythonToStubConverter._GetModuleIfMacroString(node) - if IfStr: - CurrentType = 'macro' - StubLines.append(IfStr) - StubLines.append('') # 宏后空行 - - if CurrentType: - PrevType = CurrentType - - # 添加文件结尾宏守卫 - #StubLines.append('') - #StubLines.append('c.CEndif()') - - except SyntaxError as e: - # 如果解析失败,添加注释说明 - StubLines.append(f'# Warning: Failed to parse Python code: {e}') - StubLines.append('# Original content:') - StubLines.append('"""') - StubLines.append(PyContent[:1000]) # 只显示前1000字符 - StubLines.append('"""') - - return '\n'.join(StubLines) - - @staticmethod - def _ConvertClass(node: ast.ClassDef, SourceLines: List[str] = None, PostdefVars: List[Tuple[str, str, ast.AnnAssign]] = None, indent: int = 0) -> List[str]: - """转换类定义 - - Args: - node: 类定义节点 - SourceLines: 源代码行列表 - PostdefVars: Postdefinition 变量列表 [(VarName, TypeStr, node), ...] - indent: 缩进级别(用于嵌套类) - """ - lines = [] - PostdefVars = PostdefVars or [] - IndentStr = ' ' * indent - - # 处理类装饰器 - for decorator in node.decorator_list: - DecoratorStr = PythonToStubConverter._GetDecoratorString(decorator) - if DecoratorStr: - lines.append(f'{IndentStr}@{DecoratorStr}') - - # 检查是否是结构体、联合体或枚举 - BaseNames = [base.attr if isinstance(base, ast.Attribute) else base.id - for base in node.bases - if isinstance(base, (ast.Name, ast.Attribute))] - - # 保留原始基类 - if node.bases: - BaseStrs = [] - for base in node.bases: - if isinstance(base, ast.Name): - BaseStrs.append(base.id) - elif isinstance(base, ast.Attribute): - BaseStrs.append(f'{base.value.id}.{base.attr}') - elif isinstance(base, ast.Subscript): - # 处理泛型类型,如 memory_block_t[MAX_ORDER + 1] - BaseStrs.append(PythonToStubConverter._GetTypeString(base)) - ClassTypeParamStr = '' - if hasattr(node, 'type_params') and node.type_params: - param_names = [tp.name for tp in node.type_params] - ClassTypeParamStr = f'[{", ".join(param_names)}]' - if BaseStrs: - lines.append(f'{IndentStr}class {node.name}{ClassTypeParamStr}({", ".join(BaseStrs)}):') - else: - lines.append(f'{IndentStr}class {node.name}{ClassTypeParamStr}:') - else: - ClassTypeParamStr = '' - if hasattr(node, 'type_params') and node.type_params: - param_names = [tp.name for tp in node.type_params] - ClassTypeParamStr = f'[{", ".join(param_names)}]' - lines.append(f'{IndentStr}class {node.name}{ClassTypeParamStr}:') - - # 处理类成员 - HasMembers = False - seen_member_names = set() - for item in node.body: - if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name): - seen_member_names.add(item.target.id) - init_members = [] - for item in node.body: - if isinstance(item, ast.FunctionDef) and item.name == '__init__': - for stmt in item.body: - if (isinstance(stmt, ast.AnnAssign) - and isinstance(stmt.target, ast.Attribute) - and isinstance(stmt.target.value, ast.Name) - and stmt.target.value.id == 'self'): - init_members.append(stmt) - untyped_self_members = [] - for m_name in [m.target.attr for m in init_members if isinstance(m.target, ast.Attribute)]: - seen_member_names.add(m_name) - for item in node.body: - if isinstance(item, ast.FunctionDef): - for stmt in item.body: - if (isinstance(stmt, ast.Assign) - and len(stmt.targets) == 1 - and isinstance(stmt.targets[0], ast.Attribute) - and isinstance(stmt.targets[0].value, ast.Name) - and stmt.targets[0].value.id == 'self'): - attr_name = stmt.targets[0].attr - if attr_name not in seen_member_names: - seen_member_names.add(attr_name) - untyped_self_members.append(stmt) - for item in list(node.body) + init_members + untyped_self_members: - if isinstance(item, ast.Assign): - if (len(item.targets) == 1 - and isinstance(item.targets[0], ast.Attribute) - and isinstance(item.targets[0].value, ast.Name) - and item.targets[0].value.id == 'self'): - HasMembers = True - MemberIndent = IndentStr + ' ' - attr_name = item.targets[0].attr - if attr_name in seen_member_names: - continue - InferredType = 'int' - if item.value and isinstance(item.value, ast.Constant): - if isinstance(item.value.value, float): - InferredType = 'float' - elif isinstance(item.value.value, bool): - InferredType = 'bool' - elif isinstance(item.value.value, str): - InferredType = 'str' - lines.append(f'{MemberIndent}{attr_name}: {InferredType}') - else: - HasMembers = True - MemberIndent = IndentStr + ' ' - if SourceLines and hasattr(item, 'lineno'): - StartLine = item.lineno - 1 - EndLine = item.EndLineno if hasattr(item, 'EndLineno') and item.EndLineno else StartLine + 1 - for i in range(StartLine, min(EndLine, len(SourceLines))): - lines.append(MemberIndent + SourceLines[i].lstrip()) - elif isinstance(item, ast.AnnAssign): - HasMembers = True - TypeStr = PythonToStubConverter._GetTypeString(item.annotation) - MemberIndent = IndentStr + ' ' - # 检查是否是宏变量(类型包含 t.CDefine) - if 't.CDefine' in TypeStr: - # 检查宏变量是否应该被排除 - if isinstance(item.target, ast.Name): - MacroName = item.target.id - if PythonToStubConverter._ShouldExcludeMacro(MacroName): - continue # 跳过该宏 - # 宏变量保持原样(包括赋值) - if SourceLines and hasattr(item, 'lineno'): - StartLine = item.lineno - 1 - EndLine = item.EndLineno if hasattr(item, 'EndLineno') and item.EndLineno else StartLine + 1 - for i in range(StartLine, min(EndLine, len(SourceLines))): - lines.append(MemberIndent + SourceLines[i].lstrip()) - else: - lines.append(f'{MemberIndent}{item.target.id}: {TypeStr}') - else: - if isinstance(item.target, ast.Attribute): - MemberName = item.target.attr - else: - MemberName = item.target.id - FinalTypeStr = TypeStr - if (isinstance(item.annotation, ast.Subscript) - and isinstance(item.annotation.value, ast.Name) - and item.annotation.value.id == 'list'): - slice_node = item.annotation.slice - has_size = False - if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2: - count_node = slice_node.elts[1] - if isinstance(count_node, ast.Constant) and isinstance(count_node.value, int) and count_node.value > 0: - has_size = True - else: - try: - count_expr = ast.unparse(count_node) - except Exception: - count_expr = '' - if count_expr and count_expr != 'None': - has_size = True - elem_type_str = PythonToStubConverter._GetTypeString(slice_node.elts[0]) - FinalTypeStr = f'list[{elem_type_str}, {count_expr}]' - if not has_size: - elem_type_str = PythonToStubConverter._GetTypeString(slice_node if not isinstance(slice_node, ast.Tuple) else slice_node.elts[0]) - init_len = 0 - if item.value is not None: - if isinstance(item.value, ast.List): - init_len = len(item.value.elts) - elif isinstance(item.value, ast.Constant) and isinstance(item.value.value, str): - init_len = len(item.value.value) + 1 - if init_len > 0: - FinalTypeStr = f'list[{elem_type_str}, {init_len}]' - else: - FinalTypeStr = f'list[{elem_type_str}, None]' - lines.append(f'{MemberIndent}{MemberName}: {FinalTypeStr}') - elif isinstance(item, ast.FunctionDef): - HasMembers = True - FuncStub = PythonToStubConverter._ConvertFunction(item, indent=indent+1, SourceLines=SourceLines, class_name=node.name) - lines.extend(FuncStub) - elif isinstance(item, ast.Expr): - # 处理宏调用,如 c.CIf(...), c.CEndif(), c.CElif(), c.CElse() - ExprStr = PythonToStubConverter._GetExprString(item.value) - if ExprStr: - lines.append(f'{IndentStr} {ExprStr}') - elif isinstance(item, ast.If): - # 处理 if c.CIf(...): 形式的宏条件 - IfStr = PythonToStubConverter._get_if_macro_string(item, indent=indent+1) - if IfStr: - lines.append(IfStr) - elif isinstance(item, ast.ClassDef): - # 处理嵌套类 - HasMembers = True - NestedClassLines = PythonToStubConverter._ConvertClass(item, SourceLines=SourceLines, PostdefVars=[], indent=indent+1) - # 移除嵌套类的宏守卫(因为已经在父类的宏守卫内) - FilteredLines = [] - for line in NestedClassLines: - # 跳过宏守卫相关行 - if line.strip().startswith('c.CIfndef(') or line.strip().startswith('c.CEndif()'): - continue - if ': t.CDefine' in line and '__' in line: - continue - FilteredLines.append(line) - lines.extend(FilteredLines) - - if not HasMembers: - lines.append(f'{IndentStr} pass') - - # 添加 Postdefinition 变量 - if PostdefVars: - lines.append('') - for VarName, TypeStr, _ in PostdefVars: - lines.append(f'{VarName}: {TypeStr}') - - return lines - - @staticmethod - def _ConvertFunction(node: ast.FunctionDef, indent: int = 0, SourceLines: List[str] = None, class_name: str = None) -> List[str]: - """转换函数定义""" - lines = [] - IndentStr = ' ' * indent - - # 检查是否是宏函数(返回类型包含 t.CDefine) - is_macro_func = False - if node.returns: - ReturnType = PythonToStubConverter._GetTypeString(node.returns) - if 't.CDefine' in ReturnType: - is_macro_func = True - - # 如果是宏函数,检查是否应该被排除 - if is_macro_func: - if PythonToStubConverter._ShouldExcludeMacro(node.name): - return lines # 返回空列表,排除该宏 - - # 保持原样(包括代码块) - if SourceLines: - StartLine = node.lineno - 1 - EndLine = node.EndLineno if hasattr(node, 'EndLineno') and node.EndLineno else StartLine + 1 - for i in range(StartLine, min(EndLine, len(SourceLines))): - lines.append(SourceLines[i]) - if lines and lines[-1].strip() and not lines[-1].rstrip().endswith(':'): - pass - else: - lines.append(f'{IndentStr} pass') - return lines - - # 处理函数装饰器 - for decorator in node.decorator_list: - DecoratorStr = PythonToStubConverter._GetDecoratorString(decorator) - if DecoratorStr: - lines.append(f'{IndentStr}@{DecoratorStr}') - - # 构建参数列表 - params = [] - for arg_idx, arg in enumerate(node.args.args): - ArgName = arg.arg - if arg.annotation: - TypeStr = PythonToStubConverter._GetTypeString(arg.annotation) - params.append(f'{ArgName}: {TypeStr}') - elif class_name and arg_idx == 0 and ArgName == 'self': - params.append(f'self: {class_name}') - else: - params.append(ArgName) - - # 处理 *args - if node.args.vararg: - ArgName = node.args.vararg.arg - if node.args.vararg.annotation: - TypeStr = PythonToStubConverter._GetTypeString(node.args.vararg.annotation) - params.append(f'*{ArgName}: {TypeStr}') - else: - params.append(f'*{ArgName}') - - # 处理 **kwargs - if node.args.kwarg: - ArgName = node.args.kwarg.arg - if node.args.kwarg.annotation: - TypeStr = PythonToStubConverter._GetTypeString(node.args.kwarg.annotation) - params.append(f'**{ArgName}: {TypeStr}') - else: - params.append(f'**{ArgName}') - - ParamStr = ', '.join(params) - - # 返回类型 - 保持原始类型(不添加t.State) - if node.returns: - ReturnType = PythonToStubConverter._GetTypeString(node.returns) - else: - ReturnType = 't.CInt' - - TypeParamStr = '' - if hasattr(node, 'type_params') and node.type_params: - param_names = [tp.name for tp in node.type_params] - TypeParamStr = f'[{", ".join(param_names)}]' - - lines.append(f'{IndentStr}def {node.name}{TypeParamStr}({ParamStr}) -> {ReturnType}: pass') - return lines - - @staticmethod - def _ConvertVariable(node: ast.AnnAssign, SourceLines: List[str] = None) -> List[str]: - """转换变量定义""" - lines = [] - if isinstance(node.target, ast.Name): - VarName = node.target.id - TypeStr = PythonToStubConverter._GetTypeString(node.annotation) - # 检查是否是宏变量(类型包含 t.CDefine) - if 't.CDefine' in TypeStr: - # 检查宏变量是否应该被排除 - if PythonToStubConverter._ShouldExcludeMacro(VarName): - return lines # 返回空列表,排除该宏 - # 宏变量保持原样(包括赋值) - if SourceLines and hasattr(node, 'lineno'): - StartLine = node.lineno - 1 - EndLine = node.EndLineno if hasattr(node, 'EndLineno') and node.EndLineno else StartLine + 1 - for i in range(StartLine, min(EndLine, len(SourceLines))): - lines.append(SourceLines[i]) - else: - lines.append(f'{VarName}: {TypeStr}') - return lines - # 非宏变量:不加 t.State - # 含有 typedef 的变量不加 extern,普通变量需要加 extern - has_typedef = 't.CTypedef' in TypeStr or 'CTypedef' in TypeStr - if has_typedef and node.value is not None: - ValueTypeStr = PythonToStubConverter._GetTypeString(node.value) - lines.append(f'{VarName}: {TypeStr} = {ValueTypeStr}') - else: - if not has_typedef and 't.CExtern' not in TypeStr and 't.CStatic' not in TypeStr: - TypeStr = f't.CExtern | {TypeStr}' - lines.append(f'{VarName}: {TypeStr}') - return lines - - @staticmethod - def _ConvertGlobalAssign(node: ast.Assign) -> List[str]: - """转换模块级别的全局变量(无类型标注)""" - lines = [] - if not node.targets or not isinstance(node.targets[0], ast.Name): - return lines - - VarName = node.targets[0].id - - # 跳过私有变量(以下划线开头) - if VarName.startswith('_'): - return lines - - # 从值推断类型 - inferred_type = PythonToStubConverter._InferTypeFromValue(node.value) - if inferred_type: - lines.append(f'{VarName}: {inferred_type}') - else: - lines.append(f'{VarName}: t.CInt') - - return lines - - @staticmethod - def _InferTypeFromValue(value: ast.AST) -> str: - """从值推断 C 类型""" - if isinstance(value, ast.Constant): - if isinstance(value.value, int): - return 't.CInt' - elif isinstance(value.value, float): - return 't.CDouble' - elif isinstance(value.value, str): - return 't.CCharPtr' - elif isinstance(value.value, bool): - return 't.CInt' - elif isinstance(value, ast.List): - return 't.CVoidPtr' - elif isinstance(value, ast.Dict): - return 't.CVoidPtr' - elif isinstance(value, ast.Name): - return 't.CInt' - elif isinstance(value, ast.BinOp): - left_type = PythonToStubConverter._InferTypeFromValue(value.left) - if left_type: - return left_type - return 't.CInt' - elif isinstance(value, ast.Call): - # 函数调用返回值,假设为指针类型 - if isinstance(value.func, ast.Name): - func_name = value.func.id - if func_name == 'malloc': - return 't.CVoidPtr' - elif func_name in ('ctypes.cast', 'cast'): - return 't.CVoidPtr' - return 't.CVoidPtr' - return None - - @staticmethod - def _GetTypeString(annotation: ast.AST) -> str: - """获取类型字符串""" - if isinstance(annotation, ast.Name): - return annotation.id - elif isinstance(annotation, ast.Attribute): - if isinstance(annotation.value, ast.Name): - return f'{annotation.value.id}.{annotation.attr}' - else: - # 处理嵌套属性访问,如 t.attr.packed - ParentStr = PythonToStubConverter._GetTypeString(annotation.value) - return f'{ParentStr}.{annotation.attr}' - elif isinstance(annotation, ast.Subscript): - base = PythonToStubConverter._GetTypeString(annotation.value) - if isinstance(annotation.slice, ast.Tuple): - slice_strs = [PythonToStubConverter._GetTypeString(e) for e in annotation.slice.elts] - SliceStr = ', '.join(slice_strs) - else: - SliceStr = PythonToStubConverter._GetTypeString(annotation.slice) - return f'{base}[{SliceStr}]' - elif isinstance(annotation, ast.BinOp): - # 处理 BinOp,如 t.CExtern | fd_table.__set_default__(...) - left = annotation.left - right = annotation.right - - # 检查右侧是否是 __set_default__ 调用 - if isinstance(right, ast.Call) and isinstance(right.func, ast.Attribute) and right.func.attr in ('__set_default__', '__set_default'): - # 去除 __set_default__,保留左侧,右侧替换为函数名部分 - LeftStr = PythonToStubConverter._GetTypeString(left) - RightStr = PythonToStubConverter._GetTypeString(right.func.value) - if isinstance(annotation.op, ast.BitOr): - return f'{LeftStr} | {RightStr}' - - LeftStr = PythonToStubConverter._GetTypeString(left) - RightStr = PythonToStubConverter._GetTypeString(right) - if isinstance(annotation.op, ast.BitOr): - return f'{LeftStr} | {RightStr}' - elif isinstance(annotation.op, ast.Add): - return f'{LeftStr} + {RightStr}' - elif isinstance(annotation.op, ast.Sub): - return f'{LeftStr} - {RightStr}' - elif isinstance(annotation.op, ast.Mult): - return f'{LeftStr} * {RightStr}' - elif isinstance(annotation.op, ast.Div): - return f'{LeftStr} / {RightStr}' - elif isinstance(annotation.op, ast.Mod): - return f'{LeftStr} % {RightStr}' - elif isinstance(annotation, ast.UnaryOp): - if isinstance(annotation.op, ast.Not): - operand = PythonToStubConverter._GetTypeString(annotation.operand) - return f'not {operand}' - elif isinstance(annotation.op, ast.Invert): - operand = PythonToStubConverter._GetTypeString(annotation.operand) - return f'~{operand}' - elif isinstance(annotation.op, ast.USub): - operand = PythonToStubConverter._GetTypeString(annotation.operand) - return f'-{operand}' - elif isinstance(annotation, ast.Compare): - # 处理比较操作,如 FF_MAX_SS != FF_MIN_SS - left = PythonToStubConverter._GetTypeString(annotation.left) - comparators = [PythonToStubConverter._GetTypeString(c) for c in annotation.comparators] - ops = [] - for op in annotation.ops: - if isinstance(op, ast.Eq): - ops.append('==') - elif isinstance(op, ast.NotEq): - ops.append('!=') - elif isinstance(op, ast.Lt): - ops.append('<') - elif isinstance(op, ast.LtE): - ops.append('<=') - elif isinstance(op, ast.Gt): - ops.append('>') - elif isinstance(op, ast.GtE): - ops.append('>=') - else: - ops.append('?') - result = left - for i, op in enumerate(ops): - result += f' {op} {comparators[i]}' - return result - elif isinstance(annotation, ast.Constant): - return repr(annotation.value) - elif isinstance(annotation, ast.Index): - return PythonToStubConverter._GetTypeString(annotation.value) - elif isinstance(annotation, ast.List): - # 处理列表,如 [MAX_FILE_DESCRIPTORS] - elements = [PythonToStubConverter._GetTypeString(elem) for elem in annotation.elts] - return f'[{", ".join(elements)}]' - elif isinstance(annotation, ast.Call): - # 处理函数调用形式的类型注解,如 t.Postdefinition(xxa) 或 callable(t.CVoid, app_id = t.CInt) - # 如果是 __set_default__ 调用,只返回函数名部分 - if isinstance(annotation.func, ast.Attribute) and annotation.func.attr in ('__set_default__', '__set_default'): - return PythonToStubConverter._GetTypeString(annotation.func.value) - - FuncStr = PythonToStubConverter._GetTypeString(annotation.func) - ArgsStr = ', '.join([PythonToStubConverter._GetTypeString(arg) for arg in annotation.args]) - # 处理关键字参数 - keywords_str = ', '.join([f'{kw.arg} = {PythonToStubConverter._GetTypeString(kw.value)}' for kw in annotation.keywords]) - # 合并位置参数和关键字参数 - if ArgsStr and keywords_str: - return f'{FuncStr}({ArgsStr}, {keywords_str})' - elif keywords_str: - return f'{FuncStr}({keywords_str})' - else: - return f'{FuncStr}({ArgsStr})' - return 't.CVoid' - - @staticmethod - def _ExtractPostdefClass(annotation: ast.AST) -> Optional[str]: - """从 Postdefinition 类型注解中提取类名 - - 例如:t.Postdefinition(__buddy_system) -> '__buddy_system' - t.Postdefinition(xxx) | t.CTypedef -> 'xxx' - """ - # 处理 BinOp (如: t.Postdefinition(xxx) | t.CTypedef) - if isinstance(annotation, ast.BinOp): - # 递归检查左操作数 - left_result = PythonToStubConverter._ExtractPostdefClass(annotation.left) - if left_result: - return left_result - # 递归检查右操作数 - right_result = PythonToStubConverter._ExtractPostdefClass(annotation.right) - if right_result: - return right_result - return None - - # 处理函数调用 (如: t.Postdefinition(__buddy_system)) - if isinstance(annotation, ast.Call): - FuncStr = PythonToStubConverter._GetTypeString(annotation.func) - if FuncStr == 't.Postdefinition' and annotation.args: - # 提取第一个参数 - first_arg = annotation.args[0] - if isinstance(first_arg, ast.Name): - return first_arg.id - elif isinstance(first_arg, ast.Attribute): - return f'{first_arg.value.id}.{first_arg.attr}' - - return None - - @staticmethod - def _GetImportString(node: ast.Import, SourceLines: List[str] = None) -> str: - """获取导入语句字符串""" - parts = [] - IncludeAliasMap = PythonToStubConverter.IncludeAliasMap - - for alias in node.names: - ModuleName = alias.name - # 检查是否是 __include.xxx 格式的导入 - if ModuleName.startswith('__include.'): - # 提取别名(xxx 部分) - SubModule = ModuleName[len('__include.'):] - if SubModule in IncludeAliasMap: - # 替换为实际模块路径 - RealModule = IncludeAliasMap[SubModule] - if alias.asname: - parts.append(f'{RealModule} as {alias.asname}') - else: - parts.append(f'{RealModule} as {SubModule}') - else: - # 不在映射表中,保持原样 - if alias.asname: - parts.append(f'{ModuleName} as {alias.asname}') - else: - parts.append(ModuleName) - else: - if alias.asname: - parts.append(f'{alias.name} as {alias.asname}') - else: - parts.append(alias.name) - - result = f'import {", ".join(parts)}' - - # 提取并保留注释 - if SourceLines and hasattr(node, 'lineno'): - LineIdx = node.lineno - 1 - if 0 <= LineIdx < len(SourceLines): - line = SourceLines[LineIdx] - CommentMatch = re.search(r'#.*$', line) - if CommentMatch: - result += ' ' + CommentMatch.group(0) - - return result - - @staticmethod - def _GetImportFromString(node: ast.ImportFrom, SourceLines: List[str] = None) -> str: - """获取 from ... import ... 语句字符串""" - module = node.module or '' - parts = [] - IncludeAliasMap = PythonToStubConverter.IncludeAliasMap - - # 处理相对导入 (from . import xxx 或 from ..package import xxx) - if node.level > 0: - if module: - if node.level == 1: - full_module = f'.{module}' - else: - full_module = '.' * node.level + module - else: - full_module = '.' * node.level - for alias in node.names: - if alias.asname: - parts.append(f'{alias.name} as {alias.asname}') - else: - parts.append(alias.name) - return f'from {full_module} import {", ".join(parts)}' - - # 提取注释(在生成结果前获取) - comment = '' - if SourceLines and hasattr(node, 'lineno'): - LineIdx = node.lineno - 1 - if 0 <= LineIdx < len(SourceLines): - line = SourceLines[LineIdx] - CommentMatch = re.search(r'#.*$', line) - if CommentMatch: - comment = ' ' + CommentMatch.group(0) - - # 检查是否是 from __include import xxx 格式 - if module == '__include': - for alias in node.names: - name = alias.name - if name in IncludeAliasMap: - # 替换为实际模块路径 - RealModule = IncludeAliasMap[name] - if alias.asname: - parts.append(f'import {RealModule} as {alias.asname}{comment}') - else: - parts.append(f'import {RealModule} as {name}{comment}') - else: - # 不在映射表中,保持原样 - if alias.asname: - parts.append(f'from {module} import {name} as {alias.asname}{comment}') - else: - parts.append(f'from {module} import {name}{comment}') - return '\n'.join(parts) - - # 普通 from ... import ... 语句 - for alias in node.names: - if alias.asname: - parts.append(f'{alias.name} as {alias.asname}') - else: - parts.append(alias.name) - return f'from {module} import {", ".join(parts)}{comment}' - - @staticmethod - def _GetDecoratorString(decorator: ast.AST) -> str: - """获取装饰器字符串""" - if isinstance(decorator, ast.Name): - return decorator.id - elif isinstance(decorator, ast.Attribute): - if isinstance(decorator.value, ast.Name): - return f'{decorator.value.id}.{decorator.attr}' - return decorator.attr - elif isinstance(decorator, ast.Call): - # 处理带参数的装饰器,如 @c.Attribute(t.attr.packed) - FuncStr = PythonToStubConverter._GetDecoratorString(decorator.func) - ArgsStr = ', '.join([PythonToStubConverter._GetTypeString(arg) for arg in decorator.args]) - return f'{FuncStr}({ArgsStr})' - return '' - - @staticmethod - def _GetExprString(expr: ast.AST) -> str: - """获取表达式字符串(用于宏调用)""" - if isinstance(expr, ast.Call): - # 处理函数调用,如 c.CIf(...), c.CEndif(), c.CUndef(...), c.CPragma(...) - FuncStr = PythonToStubConverter._GetDecoratorString(expr.func) - if FuncStr and ('CIf' in FuncStr or 'CEndif' in FuncStr or 'CElif' in FuncStr or 'CElse' in FuncStr or 'CUndef' in FuncStr or 'CPragma' in FuncStr): - ArgsStr = ', '.join([PythonToStubConverter._GetTypeString(arg) for arg in expr.args]) - return f'{FuncStr}({ArgsStr})' if ArgsStr else f'{FuncStr}()' - return '' - - @staticmethod - def _get_if_macro_string(node: ast.If, indent: int = 1) -> str: - """获取类内部的 if 宏字符串(如 if c.CIf(...):)""" - IndentStr = ' ' * indent - InnerIndent = ' ' * (indent + 1) - # 检查条件是否是宏调用 - if isinstance(node.test, ast.Call): - FuncStr = PythonToStubConverter._GetDecoratorString(node.test.func) - if FuncStr and 'CIf' in FuncStr: - ArgsStr = ', '.join([PythonToStubConverter._GetTypeString(arg) for arg in node.test.args]) - result = [f'{IndentStr}if {FuncStr}({ArgsStr}):' if ArgsStr else f'{IndentStr}if {FuncStr}():'] - # 处理 if 体内的语句 - for item in node.body: - if isinstance(item, ast.AnnAssign): - TypeStr = PythonToStubConverter._GetTypeString(item.annotation) - result.append(f'{InnerIndent}{item.target.id}: {TypeStr}') - elif isinstance(item, ast.Expr): - ExprStr = PythonToStubConverter._GetExprString(item.value) - if ExprStr: - result.append(f'{InnerIndent}{ExprStr}') - return '\n'.join(result) - return '' - - @staticmethod - def _GetModuleIfMacroString(node: ast.If) -> str: - """获取模块级别的 if 宏字符串(如 if c.CIf(FF_MULTI_PARTITION):)""" - return PythonToStubConverter._ProcessIfMacro(node, indent=0) - - @staticmethod - def _ProcessIfMacro(node: ast.If, indent: int = 0) -> str: - """处理 if 宏节点,支持 elif 和 else""" - IndentStr = ' ' * indent - - # 检查条件是否是宏调用 - if isinstance(node.test, ast.Call): - FuncStr = PythonToStubConverter._GetDecoratorString(node.test.func) - if FuncStr and 'CIf' in FuncStr: - ArgsStr = ', '.join([PythonToStubConverter._GetTypeString(arg) for arg in node.test.args]) - result = [f'{IndentStr}if {FuncStr}({ArgsStr}):' if ArgsStr else f'{IndentStr}if {FuncStr}():'] - # 处理 if 体内的语句 - for item in node.body: - result.extend(PythonToStubConverter._ProcessMacroBodyItem(item, indent + 1)) - - # 处理 elif 和 else - current = node - while current.orelse: - if len(current.orelse) == 1 and isinstance(current.orelse[0], ast.If): - # elif 情况 - elif_node = current.orelse[0] - if isinstance(elif_node.test, ast.Call): - ElifFuncStr = PythonToStubConverter._GetDecoratorString(elif_node.test.func) - if ElifFuncStr and 'CIf' in ElifFuncStr: - ElifArgsStr = ', '.join([PythonToStubConverter._GetTypeString(arg) for arg in elif_node.test.args]) - result.append(f'{IndentStr}elif {ElifFuncStr}({ElifArgsStr}):' if ElifArgsStr else f'{IndentStr}elif {ElifFuncStr}():') - for item in elif_node.body: - result.extend(PythonToStubConverter._ProcessMacroBodyItem(item, indent + 1)) - current = elif_node - continue - break - else: - # else 情况 - result.append(f'{IndentStr}else:') - for item in current.orelse: - result.extend(PythonToStubConverter._ProcessMacroBodyItem(item, indent + 1)) - break - - return '\n'.join(result) - return '' - - @staticmethod - def _ProcessMacroBodyItem(item: ast.AST, indent: int = 0) -> list: - """处理宏体内的单个语句""" - IndentStr = ' ' * indent - result = [] - - if isinstance(item, ast.ClassDef): - class_stub = PythonToStubConverter._ConvertClass(item) - for line in class_stub: - if line.strip(): - result.append(f'{IndentStr}{line}') - else: - result.append(line) - elif isinstance(item, ast.FunctionDef): - FuncStub = PythonToStubConverter._ConvertFunction(item, indent=indent) - result.extend(FuncStub) - elif isinstance(item, ast.AnnAssign): - TypeStr = PythonToStubConverter._GetTypeString(item.annotation) - result.append(f'{IndentStr}{item.target.id}: {TypeStr}') - elif isinstance(item, ast.Expr): - ExprStr = PythonToStubConverter._GetExprString(item.value) - if ExprStr: - result.append(f'{IndentStr}{ExprStr}') - elif isinstance(item, ast.If): - # 处理嵌套的 if 宏 - NestedIf = PythonToStubConverter._ProcessIfMacro(item, indent=indent) - if NestedIf: - result.append(NestedIf) - - return result - - -class StubGen: - """存根生成器主类""" - - def __init__(self, config: StubGenConfig): - self.config = config - self.logger = self._SetupLogger() - self.GeneratedFiles: List[str] = [] - self.FailedFiles: List[str] = [] - - # 应用自定义类型映射 - if config.TypeMappings: - CTypeMapper.BASIC_TYPE_MAP.update(config.TypeMappings) - - def _SetupLogger(self) -> logging.Logger: - """设置日志""" - logger = logging.getLogger('StubGen') - logger.setLevel(logging.DEBUG if self.config.verbose else logging.INFO) - - if not logger.handlers: - handler = logging.StreamHandler(sys.stdout) - formatter = logging.Formatter( - '%(asctime)s - %(name)s - %(levelname)s - %(message)s', - datefmt='%H:%M:%S' - ) - handler.setFormatter(formatter) - logger.addHandler(handler) - - return logger - - def FindInputFiles(self) -> List[Tuple[str, str]]: - """查找输入文件,返回 (文件路径, 相对路径) 列表""" - files = [] - - # 添加显式指定的文件 - for FilePath in self.config.InputFiles: - if os.path.exists(FilePath): - RelPath = os.path.relpath(FilePath, self.config.InputDir or '.') - files.append((FilePath, RelPath)) - else: - self.logger.warning(f"Input file not found: {FilePath}") - - # 从输入目录查找 - if self.config.InputDir and os.path.exists(self.config.InputDir): - InputPath = Path(self.config.InputDir) - for pattern in self.config.IncludePatterns: - for FilePath in InputPath.rglob(pattern): - # 检查是否在排除列表中 - excluded = False - RelPath = os.path.relpath(str(FilePath), self.config.InputDir) - - for exclude_pattern in self.config.ExcludePatterns: - if FilePath.match(exclude_pattern) or RelPath == exclude_pattern: - excluded = True - break - - if not excluded: - files.append((str(FilePath), RelPath)) - - # 去重并保持顺序 - seen = set() - UniqueFiles = [] - for FilePath, RelPath in files: - key = FilePath - if key not in seen: - seen.add(key) - UniqueFiles.append((FilePath, RelPath)) - - return UniqueFiles - - def _GenerateGuardName(self, FilePath: str) -> str: - """生成宏守卫名称""" - # 获取文件名(不含扩展名) - BaseName = os.path.splitext(os.path.basename(FilePath))[0] - - # 转换为大写,替换特殊字符为下划线 - guard = re.sub(r'[^a-zA-Z0-9_]', '_', BaseName).upper() - guard = re.sub(r'_+', '_', guard) # 合并多个下划线 - guard = guard.strip('_') - - return f'{guard}_DEFINE_H' - - def _GetOutputPath(self, RelPath: str) -> str: - """获取输出文件路径""" - # 更改扩展名为 .pyi (Python stub file) - BaseName = os.path.splitext(RelPath)[0] - OutputRelPath = BaseName + '.pyi' - - # 构建完整输出路径 - if self.config.OutputDir: - OutputPath = os.path.join(self.config.OutputDir, OutputRelPath) - else: - OutputPath = OutputRelPath - - return OutputPath - - def GenerateStub(self, InputFile: str, RelPath: str) -> bool: - """生成单个存根文件""" - try: - self.logger.info(f"Processing: {InputFile}") - - # 确定输出文件路径 - OutputFile = self._GetOutputPath(RelPath) - - # 确保输出目录存在 - OutputDir = os.path.dirname(OutputFile) - if OutputDir and not os.path.exists(OutputDir): - if not self.config.DryRun: - os.makedirs(OutputDir, exist_ok=True) - self.logger.debug(f"Created directory: {OutputDir}") - - if self.config.DryRun: - self.logger.info(f"[DRY RUN] Would generate: {OutputFile}") - return True - - # 根据文件类型选择处理方式 - ext = os.path.splitext(InputFile)[1].lower() - - if ext in ['.h', '.c']: - # C 文件:使用 CHeaderParser - content = self._GenerateFromC(InputFile, RelPath) - elif ext == '.py': - # Python 文件:使用 PythonToStubConverter - content = self._GenerateFromPy(InputFile, RelPath) - else: - self.logger.warning(f"Unsupported file type: {ext}") - return False - - # 写入文件 - with open(OutputFile, 'w', encoding='utf-8') as f: - f.write(content) - - self.GeneratedFiles.append(OutputFile) - self.logger.info(f"Generated: {OutputFile}") - return True - - except Exception as e: - self.logger.error(f"Failed to process {InputFile}: {e}") - import traceback - traceback.print_exc() - self.FailedFiles.append(InputFile) - return False - - def _GenerateFromC(self, InputFile: str, RelPath: str) -> str: - """从 C 文件生成存根""" - parser = CHeaderParser() - parser.parse_file(InputFile) - - generator = PythonStubGenerator(parser) - ModuleName = os.path.splitext(os.path.basename(InputFile))[0] - content = generator.generate(ModuleName) - - # 添加宏守卫(如果需要) - if self.config.GenerateGuards: - guard_name = self._GenerateGuardName(InputFile) - guard_comment = f"\n# Guard: {guard_name}\n" - content = content + guard_comment - - return content - - def _GenerateFromPy(self, InputFile: str, RelPath: str) -> str: - """从 Python 文件生成存根""" - with open(InputFile, 'r', encoding='utf-8') as f: - PyContent = f.read() - - ModuleName = os.path.splitext(os.path.basename(InputFile))[0] - content = PythonToStubConverter.convert(PyContent, ModuleName) - - # 添加宏守卫(如果需要) - if self.config.GenerateGuards: - guard_name = self._GenerateGuardName(InputFile) - guard_comment = f"\n# Guard: {guard_name}\n" - content = content + guard_comment - - return content - - def run(self) -> bool: - """运行生成器""" - self.logger.info("=" * 60) - self.logger.info("StubGen - C/H/Py to Python Stub Generator") - self.logger.info("=" * 60) - - # 查找输入文件 - InputFiles = self.FindInputFiles() - - if not InputFiles: - self.logger.warning("No input files found!") - return False - - self.logger.info(f"Found {len(InputFiles)} input file(s)") - for FilePath, RelPath in InputFiles: - self.logger.debug(f" - {RelPath}") - - # 处理每个文件 - SuccessCount = 0 - for FilePath, RelPath in InputFiles: - if self.GenerateStub(FilePath, RelPath): - SuccessCount += 1 - - # 输出统计信息 - self.logger.info("=" * 60) - self.logger.info(f"Summary: {SuccessCount}/{len(InputFiles)} files generated successfully") - - if self.FailedFiles: - self.logger.warning(f"Failed files ({len(self.FailedFiles)}):") - for f in self.FailedFiles: - self.logger.warning(f" - {f}") - - return SuccessCount == len(InputFiles) - - -def main(): - parser = argparse.ArgumentParser( - description='StubGen - Generate Python stub files from C/H/Py sources', - formatter_class=argparse.RawDescriptionHelpFormatter, - epilog=''' -Examples: - # 使用配置文件 - %(prog)s -c config.json - - # 处理单个文件 - %(prog)s -i input.h -o output.py - - # 批量处理目录(保持目录结构) - %(prog)s -d ./kernel -o ./kernel/include - - # 干运行(不实际生成文件) - %(prog)s -d ./kernel --dry-run - - # 不生成宏守卫 - %(prog)s -d ./kernel --no-guards - ''' - ) - - # 输入选项 - InputGroup = parser.add_mutually_exclusive_group(required=True) - InputGroup.add_argument('-c', '--config', help='Configuration file (JSON)') - InputGroup.add_argument('-i', '--input', help='Input file') - InputGroup.add_argument('-d', '--directory', help='Input directory') - - # 输出选项 - parser.add_argument('-o', '--output', help='Output directory') - - # 其他选项 - parser.add_argument('--include', action='append', - help='Include patterns (default: *.h, *.c, *.py)') - parser.add_argument('--exclude', action='append', - help='Exclude patterns') - parser.add_argument('--no-guards', action='store_true', - help='Do not generate guard macros') - parser.add_argument('--no-structure', action='store_true', - help='Do not preserve directory structure') - parser.add_argument('-v', '--verbose', action='store_true', - help='Verbose output') - parser.add_argument('--dry-run', action='store_true', - help='Dry run (do not create files)') - - args = parser.parse_args() - - # 加载配置 - if args.config: - if not os.path.exists(args.config): - print(f"Error: Config file not found: {args.config}") - sys.exit(1) - config = StubGenConfig.from_file(args.config) - else: - config = StubGenConfig() - config.IncludePatterns = args.include or ['*.h', '*.c', '*.py'] - config.ExcludePatterns = args.exclude or [] - config.GenerateGuards = not args.no_guards - config.PreserveStructure = not args.no_structure - config.verbose = args.verbose - config.DryRun = args.dry_run - - if args.input: - config.InputFiles = [args.input] - if args.output: - config.OutputDir = os.path.dirname(args.output) or '.' - elif args.directory: - config.InputDir = args.directory - if args.output: - config.OutputDir = args.output - - # 创建生成器并运行 - generator = StubGen(config) - - # 如果指定了单个输出文件,直接处理 - if args.input and args.output and not os.path.isdir(args.output): - RelPath = os.path.relpath(args.input, config.InputDir or '.') - success = generator.GenerateStub(args.input, RelPath) - else: - success = generator.run() - - sys.exit(0 if success else 1) - - -if __name__ == '__main__': - main() +#!/usr/bin/env python3 +"""StubGen - C/H/Py 文件到 Python 存根文件生成器(工程化版本)""" +import sys +import os +sys.path.insert(0, os.path.dirname(__file__)) + +from lib.StubGen import StubGenConfig, PythonToStubConverter, StubGen, main + +__all__ = ['StubGenConfig', 'PythonToStubConverter', 'StubGen', 'main'] + +if __name__ == '__main__': + main() diff --git a/TODO b/TODO index 0f257e9..715c0f9 100644 --- a/TODO +++ b/TODO @@ -3,4 +3,4 @@ main 收集 元类型 @p.set - +函数的描述符用装饰器而不是返回值 diff --git a/Test/BuiltinDecoratorTest/App/main.py b/Test/BuiltinDecoratorTest/App/main.py index be3bbb9..17d9da4 100644 --- a/Test/BuiltinDecoratorTest/App/main.py +++ b/Test/BuiltinDecoratorTest/App/main.py @@ -1,6 +1,7 @@ import t from stdint import * from stdio import printf +from stdlib import malloc # ============================================================ # 测试计数器 @@ -25,6 +26,9 @@ 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 @@ -40,9 +44,9 @@ class Rect: def test_property_getter(): printf("\n+-- @property getter --+\n") - r: Rect = Rect(3, 4) - check("area == 12", r.area == 12) - check("not square", not r.is_square) + r1: Rect = Rect(3, 4) + check("area == 12", r1.area == 12) + check("not square", not r1.is_square) r2: Rect = Rect(5, 5) check("square area == 25", r2.area == 25) check("is_square", r2.is_square) @@ -55,8 +59,11 @@ def test_property_getter(): class Temperature: _celsius: t.CDouble - def __init__(self, c: t.CDouble): - self._celsius = c + 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: @@ -73,11 +80,11 @@ class Temperature: def test_property_setter(): printf("\n+-- @property.setter --+\n") - t1: Temperature = Temperature(0.0) - check("0C == 32F", t1.fahrenheit > 31.9 and t1.fahrenheit < 32.1) - t1.celsius = 100.0 - check("100C == 212F", t1.fahrenheit > 211.9 and t1.fahrenheit < 212.1) - check("celsius == 100", t1.celsius > 99.9 and t1.celsius < 100.1) + tmp1: Temperature = Temperature(0.0) + check("0C == 32F", tmp1.fahrenheit > 31.9 and tmp1.fahrenheit < 32.1) + tmp1.celsius = 100.0 + check("100C == 212F", tmp1.fahrenheit > 211.9 and tmp1.fahrenheit < 212.1) + check("celsius == 100", tmp1.celsius > 99.9 and tmp1.celsius < 100.1) printf("+--------------------------------------------+\n") @@ -87,6 +94,9 @@ def test_property_setter(): class Counter: _count: t.CInt + def __new__(self) -> 'Counter' | t.CPtr: + return t.CPtr(malloc(Counter.__sizeof__())) + def __init__(self): self._count = 0 @@ -101,10 +111,10 @@ class Counter: def test_property_getter_redef(): printf("\n+-- @property.getter redef --+\n") - c: Counter = Counter() - check("init == 0", c.value == 0) - c.value = 42 - check("set == 42", c.value == 42) + cnt: Counter = Counter() + check("init == 0", cnt.value == 0) + cnt.value = 42 + check("set == 42", cnt.value == 42) printf("+--------------------------------------------+\n") @@ -115,6 +125,9 @@ 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 @@ -165,10 +178,6 @@ def test_staticmethod(): # 通过类名调用 check("MathUtils.add(3,4)==7", MathUtils.add(3, 4) == 7) check("MathUtils.max(5,10)==10", MathUtils.max_val(5, 10) == 10) - # 通过实例调用 - m: MathUtils = MathUtils() - check("instance.add(1,2)==3", m.add(1, 2) == 3) - check("instance.max(8,3)==8", m.max_val(8, 3) == 8) printf("+--------------------------------------------+\n") @@ -179,6 +188,9 @@ 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 @@ -216,6 +228,9 @@ def test_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 @@ -242,14 +257,18 @@ class Circle: def test_combined(): printf("\n+-- Combined @property + @staticmethod + @classmethod --+\n") - c: Circle = Circle.unit() - check("unit radius ~= 1", c.radius > 0.99 and c.radius < 1.01) + # 先测试直接构造 + cr0: Circle = Circle(1.0) + check("direct radius ~= 1", cr0.radius > 0.99 and cr0.radius < 1.01) + check("direct area ~= pi", cr0.area > 3.14 and cr0.area < 3.15) + cr0.radius = 2.0 + check("direct radius 2.0", cr0.radius > 1.99 and cr0.radius < 2.01) + check("direct area ~= 4pi", cr0.area > 12.56 and cr0.area < 12.58) + # 测试 classmethod + cr1: Circle = Circle.unit() + check("unit radius ~= 1", cr1.radius > 0.99 and cr1.radius < 1.01) check("is_unit(1.0)", Circle.is_unit(1.0)) check("not is_unit(2.0)", not Circle.is_unit(2.0)) - check("unit area ~= pi", c.area > 3.14 and c.area < 3.15) - c.radius = 2.0 - check("radius 2.0", c.radius > 1.99 and c.radius < 2.01) - check("area ~= 4pi", c.area > 12.56 and c.area < 12.58) printf("+--------------------------------------------+\n") diff --git a/Test/BuiltinDecoratorTest/output/b6069b01d8c9cc04.deps.json b/Test/BuiltinDecoratorTest/output/b6069b01d8c9cc04.deps.json new file mode 100644 index 0000000..b9a8517 --- /dev/null +++ b/Test/BuiltinDecoratorTest/output/b6069b01d8c9cc04.deps.json @@ -0,0 +1 @@ +{"stdint": "56cdd754a8a09347", "stdlib": "6c2029b306556c00", "stdio": "73edbcf76e32d00b"} \ No newline at end of file diff --git a/Test/BuiltinDecoratorTest/temp/6c2029b306556c00.pyi b/Test/BuiltinDecoratorTest/temp/6c2029b306556c00.pyi new file mode 100644 index 0000000..98da680 --- /dev/null +++ b/Test/BuiltinDecoratorTest/temp/6c2029b306556c00.pyi @@ -0,0 +1,18 @@ +""" +Auto-generated Python stub file from stdlib.py +Module: stdlib +""" + +import c + + +from stdint import * +import t + +def malloc(size: t.CSizeT) -> t.CVoid | t.CPtr | t.State | t.CExtern | t.CExport: pass + +def calloc(nmemb: t.CSizeT, size: t.CSizeT) -> t.CVoid | t.CPtr | t.State | t.CExtern | t.CExport: pass + +def realloc(p: t.CVoid | t.CPtr, size: t.CSizeT) -> t.CVoid | t.CPtr | t.State | t.CExtern | t.CExport: pass + +def free(p: t.CVoid | t.CPtr) -> None | t.State | t.CExtern | t.CExport: pass diff --git a/Test/BuiltinDecoratorTest/temp/_sha1_map.txt b/Test/BuiltinDecoratorTest/temp/_sha1_map.txt index 6a4510e..5f7f065 100644 --- a/Test/BuiltinDecoratorTest/temp/_sha1_map.txt +++ b/Test/BuiltinDecoratorTest/temp/_sha1_map.txt @@ -1,3 +1,4 @@ 56cdd754a8a09347:includes/stdint.py +6c2029b306556c00:includes/stdlib.py 73edbcf76e32d00b:includes/stdio.py -7d5b7ce7c134ada7:main.py +b6069b01d8c9cc04:main.py diff --git a/Test/BuiltinDecoratorTest/temp/7d5b7ce7c134ada7.pyi b/Test/BuiltinDecoratorTest/temp/b6069b01d8c9cc04.pyi similarity index 82% rename from Test/BuiltinDecoratorTest/temp/7d5b7ce7c134ada7.pyi rename to Test/BuiltinDecoratorTest/temp/b6069b01d8c9cc04.pyi index 615ee86..be4ff19 100644 --- a/Test/BuiltinDecoratorTest/temp/7d5b7ce7c134ada7.pyi +++ b/Test/BuiltinDecoratorTest/temp/b6069b01d8c9cc04.pyi @@ -9,6 +9,7 @@ import c import t from stdint import * from stdio import printf +from stdlib import malloc _pass_count: t.CExtern | t.CInt _fail_count: t.CExtern | t.CInt @@ -19,6 +20,7 @@ def check(name: t.CChar | t.CPtr, condition: bool) -> t.CInt: pass class Rect: width: t.CInt height: t.CInt + def __new__(self: Rect, w: t.CInt, h: t.CInt) -> 'Rect' | t.CPtr: pass def __init__(self: Rect, w: t.CInt, h: t.CInt) -> t.CInt: pass @property def area(self: Rect) -> t.CInt: pass @@ -30,7 +32,8 @@ def test_property_getter() -> t.CInt: pass class Temperature: _celsius: t.CDouble - def __init__(self: Temperature, c: t.CDouble) -> t.CInt: pass + def __new__(self: Temperature, celsius_val: t.CDouble) -> 'Temperature' | t.CPtr: pass + def __init__(self: Temperature, celsius_val: t.CDouble) -> t.CInt: pass @property def celsius(self: Temperature) -> t.CDouble: pass @celsius.setter @@ -43,6 +46,7 @@ def test_property_setter() -> t.CInt: pass class Counter: _count: t.CInt + def __new__(self: Counter) -> 'Counter' | t.CPtr: pass def __init__(self: Counter) -> t.CInt: pass @property def value(self: Counter) -> t.CInt: pass @@ -55,6 +59,7 @@ def test_property_getter_redef() -> t.CInt: pass class Config: _value: t.CInt _deleted: t.CInt + def __new__(self: Config, v: t.CInt) -> 'Config' | t.CPtr: pass def __init__(self: Config, v: t.CInt) -> t.CInt: pass @property def value(self: Config) -> t.CInt: pass @@ -79,6 +84,7 @@ def test_staticmethod() -> t.CInt: pass class Point: x: t.CDouble y: t.CDouble + def __new__(self: Point, x: t.CDouble, y: t.CDouble) -> 'Point' | t.CPtr: pass def __init__(self: Point, x: t.CDouble, y: t.CDouble) -> t.CInt: pass @classmethod def origin(cls: Point) -> Point: pass @@ -91,6 +97,7 @@ def test_classmethod() -> t.CInt: pass class Circle: _radius: t.CDouble + def __new__(self: Circle, r: t.CDouble) -> 'Circle' | t.CPtr: pass def __init__(self: Circle, r: t.CDouble) -> t.CInt: pass @property def radius(self: Circle) -> t.CDouble: pass diff --git a/Test/CPythonTest/App/cpython.py b/Test/CPythonTest/App/cpython.py index 825ee53..f9fb785 100644 --- a/Test/CPythonTest/App/cpython.py +++ b/Test/CPythonTest/App/cpython.py @@ -1,25 +1,777 @@ import t, c +# ============================================================ +# PyObject — 所有 Python 对象的基类 +# ============================================================ class PyObject: ob_refcnt: t.CLong ob_type: t.CPtr -def Py_Initialize() -> t.CVoid | t.CExtern: - pass +# ============================================================ +# 引用计数 +# ============================================================ +def Py_INCREF(op: PyObject | t.CPtr) -> t.CVoid | t.State: pass +def Py_DECREF(op: PyObject | t.CPtr) -> t.CVoid | t.State: pass +def Py_XINCREF(op: PyObject | t.CPtr) -> t.CVoid | t.State: pass +def Py_XDECREF(op: PyObject | t.CPtr) -> t.CVoid | t.State: pass +def Py_DecRef(op: PyObject | t.CPtr) -> t.CVoid | t.State: pass -def PyLong_FromLong(value: t.CLong) -> PyObject | t.CPtr | t.CExtern: - pass -def PyObject_Str(obj: PyObject | t.CPtr) -> PyObject | t.CPtr | t.CExtern: - pass +# ============================================================ +# 解释器初始化/终止 +# ============================================================ +def Py_Initialize() -> t.CVoid | t.State: pass +def Py_Finalize() -> t.CVoid | t.State: pass +def Py_InitializeEx(initsigs: t.CInt) -> t.CVoid | t.State: pass +def Py_FinalizeEx() -> t.CInt | t.State: pass +def Py_IsInitialized() -> t.CInt | t.State: pass -def PyUnicode_AsUTF8(unicode_obj: PyObject | t.CPtr) -> str | t.CExtern: - pass -def Py_DecRef(obj: PyObject | t.CPtr) -> t.CVoid | t.CExtern: - pass +# ============================================================ +# PyConfig +# ============================================================ +class PySTATUS: + func: t.CConst | str + err_msg: t.CConst | str + exitcode: t.CInt -def Py_Finalize() -> t.CVoid | t.CExtern: - pass +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 + +def PyConfig_InitPythonConfig(config: PyConfig | t.CPtr) -> t.CVoid | t.State: pass +def PyConfig_InitIsolatedConfig(config: PyConfig | t.CPtr) -> t.CVoid | t.State: pass +def PyConfig_Clear(config: PyConfig | t.CPtr) -> t.CVoid | t.State: pass +def PyConfig_Read(config: PyConfig | t.CPtr) -> PySTATUS | t.State: pass +def Py_InitializeFromConfig(config: PyConfig | t.CPtr) -> PySTATUS | t.State: pass +def Py_DecodeLocale(s: t.CConst | str) -> str | t.State: pass +def PyStatus_Exception(status: PySTATUS) -> t.CInt | t.State: pass + + +# ============================================================ +# 整数操作 (PyLong) +# ============================================================ +def PyLong_FromLong(v: t.CLong) -> PyObject | t.CPtr | t.State: pass +def PyLong_FromUnsignedLong(v: t.CUnsignedLong) -> PyObject | t.CPtr | t.State: pass +def PyLong_FromLongLong(v: t.CLong) -> PyObject | t.CPtr | t.State: pass +def PyLong_FromUnsignedLongLong(v: t.CUnsignedLong) -> PyObject | t.CPtr | t.State: pass +def PyLong_FromSsize_t(v: t.CPtrDiffT) -> PyObject | t.CPtr | t.State: pass +def PyLong_FromSize_t(v: t.CSizeT) -> PyObject | t.CPtr | t.State: pass +def PyLong_FromDouble(v: t.CDouble) -> PyObject | t.CPtr | t.State: pass +def PyLong_AsLong(obj: PyObject | t.CPtr) -> t.CLong | t.State: pass +def PyLong_AsUnsignedLong(obj: PyObject | t.CPtr) -> t.CUnsignedLong | t.State: pass +def PyLong_AsLongLong(obj: PyObject | t.CPtr) -> t.CLong | t.State: pass +def PyLong_AsUnsignedLongLong(obj: PyObject | t.CPtr) -> t.CUnsignedLong | t.State: pass +def PyLong_AsDouble(obj: PyObject | t.CPtr) -> t.CDouble | t.State: pass +def PyLong_AsSsize_t(obj: PyObject | t.CPtr) -> t.CPtrDiffT | t.State: pass +def PyLong_AsSize_t(obj: PyObject | t.CPtr) -> t.CSizeT | t.State: pass + + +# ============================================================ +# 浮点数操作 (PyFloat) +# ============================================================ +def PyFloat_FromDouble(v: t.CDouble) -> PyObject | t.CPtr | t.State: pass +def PyFloat_AsDouble(obj: PyObject | t.CPtr) -> t.CDouble | t.State: pass +def PyFloat_FromString(s: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + + +# ============================================================ +# 字符串操作 (PyUnicode / PyBytes) +# ============================================================ +def PyUnicode_FromString(u: t.CConst | str) -> PyObject | t.CPtr | t.State: pass +def PyUnicode_FromStringAndSize(u: t.CConst | str, size: t.CSizeT) -> PyObject | t.CPtr | t.State: pass +def PyUnicode_FromFormat(fmt: t.CConst | str) -> PyObject | t.CPtr | t.State: pass +def PyUnicode_AsUTF8(obj: PyObject | t.CPtr) -> str | t.State: pass +def PyUnicode_AsUTF8AndSize(obj: PyObject | t.CPtr, size: t.CPtrDiffT | t.CPtr) -> str | t.State: pass +def PyUnicode_AsWideChar(obj: PyObject | t.CPtr, wbuf: t.CPtr, bufsize: t.CSizeT) -> t.CSizeT | t.State: pass +def PyUnicode_GetLength(obj: PyObject | t.CPtr) -> t.CPtrDiffT | t.State: pass +def PyUnicode_ReadChar(obj: PyObject | t.CPtr, idx: t.CSizeT) -> t.CUInt32T | t.State: pass +def PyUnicode_WriteChar(obj: PyObject | t.CPtr, idx: t.CSizeT, ch: t.CUInt32T) -> t.CInt | t.State: pass +def PyUnicode_Compare(l: PyObject | t.CPtr, r: PyObject | t.CPtr) -> t.CInt | t.State: pass +def PyUnicode_Concat(l: PyObject | t.CPtr, r: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyUnicode_Contains(container: PyObject | t.CPtr, element: PyObject | t.CPtr) -> t.CInt | t.State: pass +def PyUnicode_Format(fmt: PyObject | t.CPtr, args: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyUnicode_InternInPlace(s: PyObject | t.CPtr | t.CPtr) -> t.CVoid | t.State: pass +def PyUnicode_InternFromString(u: t.CConst | str) -> PyObject | t.CPtr | t.State: pass + +def PyBytes_FromString(v: t.CConst | str) -> PyObject | t.CPtr | t.State: pass +def PyBytes_FromStringAndSize(v: t.CConst | str, size: t.CSizeT) -> PyObject | t.CPtr | t.State: pass +def PyBytes_AsString(obj: PyObject | t.CPtr) -> str | t.State: pass +def PyBytes_Size(obj: PyObject | t.CPtr) -> t.CSizeT | t.State: pass +def PyBytes_FromObject(o: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyBytes_FromFormat(fmt: t.CConst | str) -> PyObject | t.CPtr | t.State: pass + + +# ============================================================ +# 布尔 / None +# ============================================================ +def PyBool_FromLong(v: t.CLong) -> PyObject | t.CPtr | t.State: pass + +Py_True: PyObject | t.CPtr | t.State +Py_False: PyObject | t.CPtr | t.State +Py_None: PyObject | t.CPtr | t.State + + +# ============================================================ +# 列表操作 (PyList) +# ============================================================ +def PyList_New(len: t.CSizeT) -> PyObject | t.CPtr | t.State: pass +def PyList_Size(lst: PyObject | t.CPtr) -> t.CSizeT | t.State: pass +def PyList_GetItem(lst: PyObject | t.CPtr, idx: t.CSizeT) -> PyObject | t.CPtr | t.State: pass +def PyList_SetItem(lst: PyObject | t.CPtr, idx: t.CSizeT, item: PyObject | t.CPtr) -> t.CInt | t.State: pass +def PyList_Insert(lst: PyObject | t.CPtr, idx: t.CSizeT, item: PyObject | t.CPtr) -> t.CInt | t.State: pass +def PyList_Append(lst: PyObject | t.CPtr, item: PyObject | t.CPtr) -> t.CInt | t.State: pass +def PyList_GetSlice(lst: PyObject | t.CPtr, lo: t.CSizeT, hi: t.CSizeT) -> PyObject | t.CPtr | t.State: pass +def PyList_SetSlice(lst: PyObject | t.CPtr, lo: t.CSizeT, hi: t.CSizeT, items: PyObject | t.CPtr) -> t.CInt | t.State: pass +def PyList_Sort(lst: PyObject | t.CPtr) -> t.CInt | t.State: pass +def PyList_Reverse(lst: PyObject | t.CPtr) -> t.CInt | t.State: pass +def PyList_AsTuple(lst: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + + +# ============================================================ +# 元组操作 (PyTuple) +# ============================================================ +def PyTuple_New(len: t.CSizeT) -> PyObject | t.CPtr | t.State: pass +def PyTuple_Size(tup: PyObject | t.CPtr) -> t.CSizeT | t.State: pass +def PyTuple_GetItem(tup: PyObject | t.CPtr, idx: t.CSizeT) -> PyObject | t.CPtr | t.State: pass +def PyTuple_SetItem(tup: PyObject | t.CPtr, idx: t.CSizeT, item: PyObject | t.CPtr) -> t.CInt | t.State: pass +def PyTuple_GetSlice(tup: PyObject | t.CPtr, lo: t.CSizeT, hi: t.CSizeT) -> PyObject | t.CPtr | t.State: pass +def PyTuple_Pack(n: t.CSizeT) -> PyObject | t.CPtr | t.State: pass + + +# ============================================================ +# 字典操作 (PyDict) +# ============================================================ +def PyDict_New() -> PyObject | t.CPtr | t.State: pass +def PyDict_GetItem(d: PyObject | t.CPtr, key: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyDict_GetItemString(d: PyObject | t.CPtr, key: t.CConst | str) -> PyObject | t.CPtr | t.State: pass +def PyDict_SetItem(d: PyObject | t.CPtr, key: PyObject | t.CPtr, val: PyObject | t.CPtr) -> t.CInt | t.State: pass +def PyDict_SetItemString(d: PyObject | t.CPtr, key: t.CConst | str, val: PyObject | t.CPtr) -> t.CInt | t.State: pass +def PyDict_DelItem(d: PyObject | t.CPtr, key: PyObject | t.CPtr) -> t.CInt | t.State: pass +def PyDict_DelItemString(d: PyObject | t.CPtr, key: t.CConst | str) -> t.CInt | t.State: pass +def PyDict_Size(d: PyObject | t.CPtr) -> t.CSizeT | t.State: pass +def PyDict_Keys(d: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyDict_Values(d: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyDict_Items(d: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyDict_Copy(d: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyDict_Clear(d: PyObject | t.CPtr) -> t.CVoid | t.State: pass +def PyDict_Contains(d: PyObject | t.CPtr, key: PyObject | t.CPtr) -> t.CInt | t.State: pass +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 | t.State: pass +def PyDict_Merge(d: PyObject | t.CPtr, other: PyObject | t.CPtr, override: t.CInt) -> t.CInt | t.State: pass +def PyDict_Update(d: PyObject | t.CPtr, other: PyObject | t.CPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# 对象通用操作 +# ============================================================ +def PyObject_Str(obj: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyObject_Repr(obj: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyObject_Type(obj: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyObject_IsInstance(obj: PyObject | t.CPtr, cls: PyObject | t.CPtr) -> t.CInt | t.State: pass +def PyObject_IsSubclass(obj: PyObject | t.CPtr, cls: PyObject | t.CPtr) -> t.CInt | t.State: pass +def PyObject_HasAttr(obj: PyObject | t.CPtr, name: PyObject | t.CPtr) -> t.CInt | t.State: pass +def PyObject_HasAttrString(obj: PyObject | t.CPtr, name: t.CConst | str) -> t.CInt | t.State: pass +def PyObject_GetAttr(obj: PyObject | t.CPtr, name: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyObject_GetAttrString(obj: PyObject | t.CPtr, name: t.CConst | str) -> PyObject | t.CPtr | t.State: pass +def PyObject_SetAttr(obj: PyObject | t.CPtr, name: PyObject | t.CPtr, val: PyObject | t.CPtr) -> t.CInt | t.State: pass +def PyObject_SetAttrString(obj: PyObject | t.CPtr, name: t.CConst | str, val: PyObject | t.CPtr) -> t.CInt | t.State: pass +def PyObject_DelAttr(obj: PyObject | t.CPtr, name: PyObject | t.CPtr) -> t.CInt | t.State: pass +def PyObject_DelAttrString(obj: PyObject | t.CPtr, name: t.CConst | str) -> t.CInt | t.State: pass +def PyObject_Call(callable: PyObject | t.CPtr, args: PyObject | t.CPtr, kwargs: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyObject_CallObject(callable: PyObject | t.CPtr, args: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyObject_CallNoArgs(callable: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyObject_CallOneArg(callable: PyObject | t.CPtr, arg: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyObject_IsTrue(obj: PyObject | t.CPtr) -> t.CInt | t.State: pass +def PyObject_Not(obj: PyObject | t.CPtr) -> t.CInt | t.State: pass +def PyObject_RichCompare(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr, opid: t.CInt) -> PyObject | t.CPtr | t.State: pass +def PyObject_RichCompareBool(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr, opid: t.CInt) -> t.CInt | t.State: pass +def PyObject_Hash(obj: PyObject | t.CPtr) -> t.CLong | t.State: pass +def PyObject_Length(obj: PyObject | t.CPtr) -> t.CSizeT | t.State: pass +def PyObject_GetItem(obj: PyObject | t.CPtr, key: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyObject_SetItem(obj: PyObject | t.CPtr, key: PyObject | t.CPtr, val: PyObject | t.CPtr) -> t.CInt | t.State: pass +def PyObject_DelItem(obj: PyObject | t.CPtr, key: PyObject | t.CPtr) -> t.CInt | t.State: pass +def PyObject_Dir(obj: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyObject_GetIter(obj: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyIter_Next(obj: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + + +# ============================================================ +# 比较常量 +# ============================================================ +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 + + +# ============================================================ +# 模块操作 +# ============================================================ +def PyImport_ImportModule(name: t.CConst | str) -> PyObject | t.CPtr | t.State: pass +def PyImport_Import(name: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +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 | t.State: pass +def PyImport_ReloadModule(mod: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyImport_AddModule(name: t.CConst | str) -> PyObject | t.CPtr | t.State: pass +def PyImport_GetModuleDict() -> PyObject | t.CPtr | t.State: pass +def PyImport_ImportModuleEx(name: t.CConst | str, globs: PyObject | t.CPtr, locs: PyObject | t.CPtr, fromlist: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + + +# ============================================================ +# 模块创建 +# ============================================================ +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 + +def PyModule_Create(mod: PyModuleDef | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyModule_Create2(mod: PyModuleDef | t.CPtr, ver: t.CInt) -> PyObject | t.CPtr | t.State: pass +def PyModule_GetName(mod: PyObject | t.CPtr) -> str | t.State: pass +def PyModule_GetDict(mod: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyModule_GetFilenameObject(mod: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyModule_AddObject(mod: PyObject | t.CPtr, name: t.CConst | str, val: PyObject | t.CPtr) -> t.CInt | t.State: pass +def PyModule_AddObjectRef(mod: PyObject | t.CPtr, name: t.CConst | str, val: PyObject | t.CPtr) -> t.CInt | t.State: pass +def PyModule_AddIntConstant(mod: PyObject | t.CPtr, name: t.CConst | str, val: t.CLong) -> t.CInt | t.State: pass +def PyModule_AddStringConstant(mod: PyObject | t.CPtr, name: t.CConst | str, val: t.CConst | str) -> t.CInt | t.State: pass + + +# ============================================================ +# GIL 管理 +# ============================================================ +def PyGILState_Ensure() -> t.CInt | t.State: pass +def PyGILState_Release(state: t.CInt) -> t.CVoid | t.State: pass +def PyEval_SaveThread() -> t.CPtr | t.State: pass +def PyEval_RestoreThread(tstate: t.CPtr) -> t.CVoid | t.State: pass +def PyEval_AcquireThread(tstate: t.CPtr) -> t.CVoid | t.State: pass +def PyEval_ReleaseThread(tstate: t.CPtr) -> t.CVoid | t.State: pass +def PyEval_AcquireLock() -> t.CVoid | t.State: pass +def PyEval_ReleaseLock() -> t.CVoid | t.State: pass +def PyEval_ThreadsInitialized() -> t.CInt | t.State: pass +def PyEval_InitThreads() -> t.CVoid | t.State: pass + + +# ============================================================ +# 错误处理 +# ============================================================ +def PyErr_Occurred() -> PyObject | t.CPtr | t.State: pass +def PyErr_Clear() -> t.CVoid | t.State: pass +def PyErr_Fetch(tp: PyObject | t.CPtr | t.CPtr, val: PyObject | t.CPtr | t.CPtr, tb: PyObject | t.CPtr | t.CPtr) -> t.CVoid | t.State: pass +def PyErr_Restore(tp: PyObject | t.CPtr, val: PyObject | t.CPtr, tb: PyObject | t.CPtr) -> t.CVoid | t.State: pass +def PyErr_NormalizeException(tp: PyObject | t.CPtr | t.CPtr, val: PyObject | t.CPtr | t.CPtr, tb: PyObject | t.CPtr | t.CPtr) -> t.CVoid | t.State: pass +def PyErr_SetString(tp: PyObject | t.CPtr, msg: t.CConst | str) -> t.CVoid | t.State: pass +def PyErr_SetObject(tp: PyObject | t.CPtr, val: PyObject | t.CPtr) -> t.CVoid | t.State: pass +def PyErr_BadArgument() -> t.CPtr | t.State: pass +def PyErr_NoMemory() -> t.CPtr | t.State: pass +def PyErr_Print() -> t.CVoid | t.State: pass +def PyErr_ExceptionMatches(exc: PyObject | t.CPtr) -> t.CInt | t.State: pass +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 + + +# ============================================================ +# 内置函数 +# ============================================================ +def Py_BuildValue(fmt: t.CConst | str) -> PyObject | t.CPtr | t.State: pass +def Py_VaBuildValue(fmt: t.CConst | str, va: t.CPtr) -> PyObject | t.CPtr | t.State: pass + + +# ============================================================ +# 类型检查 +# ============================================================ +def PyLong_Check(obj: PyObject | t.CPtr) -> t.CInt | t.State: pass +def PyFloat_Check(obj: PyObject | t.CPtr) -> t.CInt | t.State: pass +def PyUnicode_Check(obj: PyObject | t.CPtr) -> t.CInt | t.State: pass +def PyBytes_Check(obj: PyObject | t.CPtr) -> t.CInt | t.State: pass +def PyList_Check(obj: PyObject | t.CPtr) -> t.CInt | t.State: pass +def PyTuple_Check(obj: PyObject | t.CPtr) -> t.CInt | t.State: pass +def PyDict_Check(obj: PyObject | t.CPtr) -> t.CInt | t.State: pass +def PyBool_Check(obj: PyObject | t.CPtr) -> t.CInt | t.State: pass +def PyNone_Check(obj: PyObject | t.CPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# 内存管理 +# ============================================================ +def PyMem_Malloc(size: t.CSizeT) -> t.CPtr | t.State: pass +def PyMem_Realloc(ptr: t.CPtr, size: t.CSizeT) -> t.CPtr | t.State: pass +def PyMem_Free(ptr: t.CPtr) -> t.CVoid | t.State: pass +def PyMem_Calloc(nelem: t.CSizeT, elsize: t.CSizeT) -> t.CPtr | t.State: pass +def PyObject_Malloc(size: t.CSizeT) -> t.CPtr | t.State: pass +def PyObject_Realloc(ptr: t.CPtr, size: t.CSizeT) -> t.CPtr | t.State: pass +def PyObject_Free(ptr: t.CPtr) -> t.CVoid | t.State: pass +def PyObject_Calloc(nelem: t.CSizeT, elsize: t.CSizeT) -> t.CPtr | t.State: pass +def PyObject_Init(obj: PyObject | t.CPtr, tp: t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyObject_InitVar(obj: PyObject | t.CPtr, tp: t.CPtr, size: t.CSizeT) -> PyObject | t.CPtr | t.State: pass + + +# ============================================================ +# 文件操作 +# ============================================================ +def PyFile_FromString(filename: t.CConst | str, mode: t.CConst | str) -> PyObject | t.CPtr | t.State: pass +def PyFile_AsFile(file: PyObject | t.CPtr) -> t.CPtr | t.State: pass +def PyFile_WriteObject(obj: PyObject | t.CPtr, file: PyObject | t.CPtr, flags: t.CInt) -> t.CInt | t.State: pass +def PyFile_WriteString(s: t.CConst | str, file: PyObject | t.CPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# 编译/执行 +# ============================================================ +def Py_CompileString(s: t.CConst | str, filename: t.CConst | str, start: t.CInt) -> PyObject | t.CPtr | t.State: pass +def PyEval_EvalCode(code: PyObject | t.CPtr, globs: PyObject | t.CPtr, locs: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +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 | t.State: pass +def PyEval_EvalFrame(frame: t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyEval_CallObject(callable: PyObject | t.CPtr, args: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyEval_CallFunction(callable: PyObject | t.CPtr, fmt: t.CConst | str) -> PyObject | t.CPtr | t.State: pass +def PyEval_CallMethod(obj: PyObject | t.CPtr, method: t.CConst | str, fmt: t.CConst | str) -> PyObject | t.CPtr | t.State: pass + + +# ============================================================ +# PyRun +# ============================================================ +def PyRun_SimpleString(cmd: t.CConst | str) -> t.CInt | t.State: pass +def PyRun_SimpleFile(fp: t.CPtr, filename: t.CConst | str) -> t.CInt | t.State: pass +def PyRun_AnyFile(fp: t.CPtr, filename: t.CConst | str) -> t.CInt | t.State: pass +def PyRun_String(s: t.CConst | str, start: t.CInt, globs: PyObject | t.CPtr, locs: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyRun_File(fp: t.CPtr, filename: t.CConst | str, start: t.CInt, globs: PyObject | t.CPtr, locs: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +Py_single_input: t.CInt | t.State +Py_file_input: t.CInt | t.State +Py_eval_input: t.CInt | t.State + + +# ============================================================ +# Capsule +# ============================================================ +def PyCapsule_New(ptr: t.CPtr, name: t.CConst | str, dtor: t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyCapsule_GetPointer(cap: PyObject | t.CPtr, name: t.CConst | str) -> t.CPtr | t.State: pass +def PyCapsule_GetName(cap: PyObject | t.CPtr) -> str | t.State: pass +def PyCapsule_IsValid(cap: PyObject | t.CPtr, name: t.CConst | str) -> t.CInt | t.State: pass +def PyCapsule_SetPointer(cap: PyObject | t.CPtr, ptr: t.CPtr) -> t.CInt | t.State: pass +def PyCapsule_SetName(cap: PyObject | t.CPtr, name: t.CConst | str) -> t.CInt | t.State: pass +def PyCapsule_SetDestructor(cap: PyObject | t.CPtr, dtor: t.CPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# 序列操作 +# ============================================================ +def PySequence_Check(obj: PyObject | t.CPtr) -> t.CInt | t.State: pass +def PySequence_Size(obj: PyObject | t.CPtr) -> t.CSizeT | t.State: pass +def PySequence_Length(obj: PyObject | t.CPtr) -> t.CSizeT | t.State: pass +def PySequence_Concat(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PySequence_Repeat(obj: PyObject | t.CPtr, count: t.CSizeT) -> PyObject | t.CPtr | t.State: pass +def PySequence_GetItem(obj: PyObject | t.CPtr, idx: t.CSizeT) -> PyObject | t.CPtr | t.State: pass +def PySequence_SetItem(obj: PyObject | t.CPtr, idx: t.CSizeT, val: PyObject | t.CPtr) -> t.CInt | t.State: pass +def PySequence_DelItem(obj: PyObject | t.CPtr, idx: t.CSizeT) -> t.CInt | t.State: pass +def PySequence_GetSlice(obj: PyObject | t.CPtr, start: t.CSizeT, end: t.CSizeT) -> PyObject | t.CPtr | t.State: pass +def PySequence_SetSlice(obj: PyObject | t.CPtr, start: t.CSizeT, end: t.CSizeT, val: PyObject | t.CPtr) -> t.CInt | t.State: pass +def PySequence_DelSlice(obj: PyObject | t.CPtr, start: t.CSizeT, end: t.CSizeT) -> t.CInt | t.State: pass +def PySequence_Contains(obj: PyObject | t.CPtr, val: PyObject | t.CPtr) -> t.CInt | t.State: pass +def PySequence_Index(obj: PyObject | t.CPtr, val: PyObject | t.CPtr) -> t.CSizeT | t.State: pass +def PySequence_Count(obj: PyObject | t.CPtr, val: PyObject | t.CPtr) -> t.CSizeT | t.State: pass +def PySequence_List(obj: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PySequence_Tuple(obj: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + + +# ============================================================ +# 映射操作 +# ============================================================ +def PyMapping_Check(obj: PyObject | t.CPtr) -> t.CInt | t.State: pass +def PyMapping_Size(obj: PyObject | t.CPtr) -> t.CSizeT | t.State: pass +def PyMapping_Length(obj: PyObject | t.CPtr) -> t.CSizeT | t.State: pass +def PyMapping_HasKey(obj: PyObject | t.CPtr, key: PyObject | t.CPtr) -> t.CInt | t.State: pass +def PyMapping_HasKeyString(obj: PyObject | t.CPtr, key: t.CConst | str) -> t.CInt | t.State: pass +def PyMapping_GetItemString(obj: PyObject | t.CPtr, key: t.CConst | str) -> PyObject | t.CPtr | t.State: pass +def PyMapping_SetItemString(obj: PyObject | t.CPtr, key: t.CConst | str, val: PyObject | t.CPtr) -> t.CInt | t.State: pass +def PyMapping_Keys(obj: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyMapping_Values(obj: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyMapping_Items(obj: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + + +# ============================================================ +# 数字操作 +# ============================================================ +def PyNumber_Add(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyNumber_Subtract(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyNumber_Multiply(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyNumber_MatrixMultiply(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyNumber_FloorDivide(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyNumber_TrueDivide(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyNumber_Modulo(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyNumber_Power(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr, o3: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyNumber_Negative(obj: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyNumber_Positive(obj: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyNumber_Absolute(obj: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyNumber_Invert(obj: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyNumber_Lshift(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyNumber_Rshift(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyNumber_And(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyNumber_Xor(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyNumber_Or(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyNumber_Index(obj: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyNumber_Long(obj: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyNumber_Float(obj: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyNumber_Check(obj: PyObject | t.CPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# 弱引用 +# ============================================================ +def PyWeakref_NewRef(obj: PyObject | t.CPtr, cb: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyWeakref_GetObject(ref: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyWeakref_Check(obj: PyObject | t.CPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# 属性描述符 +# ============================================================ +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 模块 +# ============================================================ +def PySys_GetObject(name: t.CConst | str) -> PyObject | t.CPtr | t.State: pass +def PySys_SetObject(name: t.CConst | str, val: PyObject | t.CPtr) -> t.CInt | t.State: pass +def PySys_ResetWarnOptions() -> t.CVoid | t.State: pass +def PySys_AddWarnOption(s: PyObject | t.CPtr) -> t.CVoid | t.State: pass +def PySYS_AddXOption(s: PyObject | t.CPtr) -> t.CVoid | t.State: pass +def PySys_WriteStdout(fmt: t.CConst | str) -> t.CVoid | t.State: pass +def PySys_WriteStderr(fmt: t.CConst | str) -> t.CVoid | t.State: pass +def PySys_FormatStdout(fmt: t.CConst | str) -> t.CVoid | t.State: pass +def PySys_FormatStderr(fmt: t.CConst | str) -> t.CVoid | t.State: pass + + +# ============================================================ +# 内存视图 +# ============================================================ +def PyMemoryView_FromObject(obj: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyMemoryView_GetContiguous(obj: PyObject | t.CPtr, btype: t.CInt, order: t.CChar) -> PyObject | t.CPtr | t.State: pass +def PyMemoryView_Check(obj: PyObject | t.CPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# set / frozenset +# ============================================================ +def PySet_New(iterable: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PySet_Add(s: PyObject | t.CPtr, key: PyObject | t.CPtr) -> t.CInt | t.State: pass +def PySet_Discard(s: PyObject | t.CPtr, key: PyObject | t.CPtr) -> t.CInt | t.State: pass +def PySet_Contains(s: PyObject | t.CPtr, key: PyObject | t.CPtr) -> t.CInt | t.State: pass +def PySet_Size(s: PyObject | t.CPtr) -> t.CSizeT | t.State: pass +def PySet_Clear(s: PyObject | t.CPtr) -> t.CVoid | t.State: pass +def PySet_Check(obj: PyObject | t.CPtr) -> t.CInt | t.State: pass +def PyFrozenSet_New(iterable: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +def PyFrozenSet_Check(obj: PyObject | t.CPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# slice +# ============================================================ +def PySlice_New(start: PyObject | t.CPtr, stop: PyObject | t.CPtr, step: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass +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 | t.State: pass +def PySlice_Unpack(sl: PyObject | t.CPtr, start: t.CPtrDiffT | t.CPtr, stop: t.CPtrDiffT | t.CPtr, step: t.CPtrDiffT | t.CPtr) -> t.CVoid | t.State: pass +def PySlice_AdjustIndices(length: t.CSizeT, start: t.CPtrDiffT | t.CPtr, stop: t.CPtrDiffT | t.CPtr, step: t.CPtrDiffT) -> t.CSizeT | t.State: pass +def PySlice_Check(obj: PyObject | t.CPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# 类型包装类 — 带运算符重载 +# ============================================================ + +# --- 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/Test/CPythonTest/App/main.py b/Test/CPythonTest/App/main.py index f0aa5e7..8e66d08 100644 --- a/Test/CPythonTest/App/main.py +++ b/Test/CPythonTest/App/main.py @@ -1,28 +1,380 @@ import t, c -from t import CInt, CPtr, CChar, CLong -import viperlib +from t import CInt, CLong, CDouble, CPtr, CSizeT +from stdio import printf import cpython -def SetDllDirectoryA(lpPathName: str | CPtr) -> CInt | t.CExtern: - pass +_pass_count: CInt = 0 +_fail_count: CInt = 0 -def main() -> CInt | t.CExport: - SetDllDirectoryA("D:\\Python312") +def check(name: t.CChar | CPtr, condition: bool): + global _pass_count, _fail_count + if condition: + _pass_count += 1 + printf(" [PASS] %s\n", name) + else: + _fail_count += 1 + printf(" [FAIL] %s\n", name) + +def test_init_finalize(): + printf("\n+-- Py_Initialize / Py_Finalize --+\n") + cpython.Py_Initialize() + check("Py_Initialize succeeded", cpython.Py_IsInitialized() != 0) + cpython.Py_Finalize() + check("Py_Finalize succeeded", cpython.Py_IsInitialized() == 0) + printf("+--------------------------------------------+\n") + + +def test_long_operations(): + printf("\n+-- PyLong operations --+\n") cpython.Py_Initialize() - py_num: cpython.PyObject | t.CPtr = cpython.PyLong_FromLong(12345) + # 创建整数 + py_num: cpython.PyObject | CPtr = cpython.PyLong_FromLong(12345) + check("PyLong_FromLong != NULL", py_num != 0) - py_str: cpython.PyObject | t.CPtr = cpython.PyObject_Str(py_num) - c_str: str = cpython.PyUnicode_AsUTF8(py_str) - print(c_str) + # 整数转字符串 + py_str: cpython.PyObject | CPtr = cpython.PyObject_Str(py_num) + check("PyObject_Str != NULL", py_str != 0) + # 获取 C 字符串 + c_str: t.CChar | CPtr = cpython.PyUnicode_AsUTF8(py_str) + check("PyUnicode_AsUTF8 != NULL", c_str != 0) + printf(" PyLong_FromLong(12345) -> str = %s\n", c_str) + + # 读取回来 + val: CLong = cpython.PyLong_AsLong(py_num) + check("PyLong_AsLong == 12345", val == 12345) + + # 负数 + py_neg: cpython.PyObject | CPtr = cpython.PyLong_FromLong(-999) + neg_val: CLong = cpython.PyLong_AsLong(py_neg) + check("PyLong_FromLong(-999) == -999", neg_val == -999) + + # 浮点数转整数 + py_dbl: cpython.PyObject | CPtr = cpython.PyFloat_FromDouble(3.14159) + check("PyFloat_FromDouble != NULL", py_dbl != 0) + dbl_val: CDouble = cpython.PyFloat_AsDouble(py_dbl) + check("PyFloat_AsDouble ~= 3.14", dbl_val > 3.14 and dbl_val < 3.15) + + # 清理 + cpython.Py_DecRef(py_dbl) + cpython.Py_DecRef(py_neg) cpython.Py_DecRef(py_str) cpython.Py_DecRef(py_num) cpython.Py_Finalize() + printf("+--------------------------------------------+\n") + + +def test_string_operations(): + printf("\n+-- PyUnicode operations --+\n") + cpython.Py_Initialize() + + # 从 C 字符串创建 + py_s1: cpython.PyObject | CPtr = cpython.PyUnicode_FromString("Hello, Viper!") + check("PyUnicode_FromString != NULL", py_s1 != 0) + + # 获取 UTF8 + utf8: t.CChar | CPtr = cpython.PyUnicode_AsUTF8(py_s1) + check("AsUTF8 != NULL", utf8 != 0) + printf(" PyUnicode_FromString -> %s\n", utf8) + + # 字符串长度 + length: CLong = cpython.PyUnicode_GetLength(py_s1) + check("GetLength == 13", length == 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) + check("Concat != NULL", py_concat != 0) + printf(" Concat -> %s\n", concat_utf8) + + # 清理 + cpython.Py_DecRef(py_concat) + cpython.Py_DecRef(py_s2) + cpython.Py_DecRef(py_s1) + + cpython.Py_Finalize() + printf("+--------------------------------------------+\n") + + +def test_list_operations(): + printf("\n+-- PyList operations --+\n") + cpython.Py_Initialize() + + # 创建列表 + py_list: cpython.PyObject | CPtr = cpython.PyList_New(0) + check("PyList_New != NULL", py_list != 0) + + # 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) + check("PyList_Size == 3", list_size == 3) + + # 获取元素 + item0: cpython.PyObject | CPtr = cpython.PyList_GetItem(py_list, 0) + val0: CLong = cpython.PyLong_AsLong(item0) + check("list[0] == 10", val0 == 10) + + item2: cpython.PyObject | CPtr = cpython.PyList_GetItem(py_list, 2) + val2: CLong = cpython.PyLong_AsLong(item2) + check("list[2] == 30", val2 == 30) + + # 清理 + cpython.Py_DecRef(py_i3) + cpython.Py_DecRef(py_i2) + cpython.Py_DecRef(py_i1) + cpython.Py_DecRef(py_list) + + cpython.Py_Finalize() + printf("+--------------------------------------------+\n") + + +def test_dict_operations(): + printf("\n+-- PyDict operations --+\n") + cpython.Py_Initialize() + + # 创建字典 + py_dict: cpython.PyObject | CPtr = cpython.PyDict_New() + check("PyDict_New != NULL", py_dict != 0) + + # 设置键值对 + 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) + check("PyDict_Size == 2", dict_size == 2) + + # 获取值 + got_val: cpython.PyObject | CPtr = cpython.PyDict_GetItem(py_dict, py_key1) + check("GetItem(name) != NULL", got_val != 0) + got_str: t.CChar | CPtr = cpython.PyUnicode_AsUTF8(got_val) + check("name == Viper", got_str != 0) + printf(" dict['name'] = %s\n", got_str) + + # 使用 GetItemString + got_ver: cpython.PyObject | CPtr = cpython.PyDict_GetItemString(py_dict, "version") + check("GetItemString(version) != NULL", got_ver != 0) + ver_val: CLong = cpython.PyLong_AsLong(got_ver) + check("version == 1", ver_val == 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() + printf("+--------------------------------------------+\n") + + +def test_pyrun_string(): + printf("\n+-- PyRun_SimpleString --+\n") + cpython.Py_Initialize() + + # 执行简单 Python 代码 + rc: CInt = cpython.PyRun_SimpleString("print('Hello from embedded Python!')") + check("PyRun_SimpleString == 0", rc == 0) + + # 执行赋值 + rc2: CInt = cpython.PyRun_SimpleString("x = 6 * 7") + check("PyRun_SimpleString(assign) == 0", rc2 == 0) + + # 读取结果 + rc3: CInt = cpython.PyRun_SimpleString("print(f'The answer is {x}')") + check("PyRun_SimpleString(print) == 0", rc3 == 0) + + cpython.Py_Finalize() + printf("+--------------------------------------------+\n") + + +def test_import_module(): + printf("\n+-- PyImport_ImportModule --+\n") + cpython.Py_Initialize() + + # 导入 math 模块 + math_mod: cpython.PyObject | CPtr = cpython.PyImport_ImportModule("math") + check("import math != NULL", math_mod != 0) + + if math_mod != 0: + # 获取 math.pi + pi_val: cpython.PyObject | CPtr = cpython.PyObject_GetAttrString(math_mod, "pi") + check("math.pi != NULL", pi_val != 0) + if pi_val != 0: + pi_dbl: CDouble = cpython.PyFloat_AsDouble(pi_val) + check("math.pi ~= 3.14", pi_dbl > 3.14 and pi_dbl < 3.15) + 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") + check("math.sqrt != NULL", sqrt_func != 0) + if sqrt_func != 0: + cpython.Py_DecRef(sqrt_func) + + cpython.Py_DecRef(math_mod) + + cpython.Py_Finalize() + printf("+--------------------------------------------+\n") + + +def test_operator_overload(): + printf("\n+-- Operator Overload (PyLongObj / PyFloatObj / PyUnicodeObj / PyListObj / PyDictObj) --+\n") + 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) + check("PyLongObj.from_long != NULL", a != 0 and b != 0) + + add_r: cpython.PyLongObj | CPtr = a + b + check("PyLongObj 10 + 3 == 13", add_r.to_long() == 13) + + sub_r: cpython.PyLongObj | CPtr = a - b + check("PyLongObj 10 - 3 == 7", sub_r.to_long() == 7) + + mul_r: cpython.PyLongObj | CPtr = a * b + check("PyLongObj 10 * 3 == 30", mul_r.to_long() == 30) + + neg_r: cpython.PyLongObj | CPtr = -b + check("PyLongObj -3 == -3", neg_r.to_long() == -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) + check("PyFloatObj.from_double != NULL", fa != 0 and fb != 0) + + fadd: cpython.PyFloatObj | CPtr = fa + fb + check("PyFloatObj 10.0 + 4.0 == 14.0", fadd.to_double() == 14.0) + + fsub: cpython.PyFloatObj | CPtr = fa - fb + check("PyFloatObj 10.0 - 4.0 == 6.0", fsub.to_double() == 6.0) + + fmul: cpython.PyFloatObj | CPtr = fa * fb + check("PyFloatObj 10.0 * 4.0 == 40.0", fmul.to_double() == 40.0) + + fdiv: cpython.PyFloatObj | CPtr = fa / fb + check("PyFloatObj 10.0 / 4.0 == 2.5", fdiv.to_double() == 2.5) + + fneg: cpython.PyFloatObj | CPtr = -fb + check("PyFloatObj -4.0 == -4.0", fneg.to_double() == -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") + check("PyUnicodeObj.from_string != NULL", sa != 0 and sb != 0) + + sc: cpython.PyUnicodeObj | CPtr = sa + sb + sc_utf8: t.CChar | CPtr = sc.as_utf8() + check("PyUnicodeObj concat != NULL", sc_utf8 != 0) + if sc_utf8 != 0: + printf(" PyUnicodeObj 'Hello' + ' World' = %s\n", sc_utf8) + + sa_len: t.CPtrDiffT = len(sa) + check("PyUnicodeObj len('Hello') == 5", sa_len == 5) + + sc.dec_ref() + sb.dec_ref() + sa.dec_ref() + + # --- PyListObj: new, append, len, [], []= --- + lst: cpython.PyListObj | CPtr = cpython.PyListObj.new() + check("PyListObj.new != NULL", lst != 0) + 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) + check("PyListObj len == 3", len(lst) == 3) + + item0: cpython.PyObject | CPtr = lst[t.CSizeT(0)] + check("PyListObj lst[0] == 100", cpython.PyLong_AsLong(item0) == 100) + + # __setitem__ + e4: cpython.PyObject | CPtr = cpython.PyLong_FromLong(999) + lst[t.CSizeT(1)] = e4 + item1: cpython.PyObject | CPtr = lst[t.CSizeT(1)] + check("PyListObj lst[1] = 999", cpython.PyLong_AsLong(item1) == 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() + check("PyDictObj.new != NULL", dct != 0) + if dct != 0: + dk1: cpython.PyObject | CPtr = cpython.PyUnicode_FromString("lang") + dv1: cpython.PyObject | CPtr = cpython.PyUnicode_FromString("Viper") + dct[dk1] = dv1 + check("PyDictObj len == 1", len(dct) == 1) + + got_lang: cpython.PyObject | CPtr = dct[dk1] + got_str: t.CChar | CPtr = cpython.PyUnicode_AsUTF8(got_lang) + check("PyDictObj dct['lang'] == Viper", got_str != 0) + 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") + check("PyDictObj get_string('ver') == 3", got_ver != 0 and cpython.PyLong_AsLong(got_ver) == 3) + + cpython.Py_DecRef(dv1) + cpython.Py_DecRef(dk1) + dct.dec_ref() + + cpython.Py_Finalize() + printf("+--------------------------------------------+\n") + + +def main() -> CInt | t.CExport: + printf("=== CPython Integration Test ===\n") + + test_init_finalize() + test_long_operations() + test_string_operations() + test_list_operations() + test_dict_operations() + test_pyrun_string() + test_import_module() + test_operator_overload() + + printf("\n=== Results: %d passed, %d failed ===\n", _pass_count, _fail_count) return 0 - - - diff --git a/Test/CPythonTest/output/0cd580d62a3de4f8.deps.json b/Test/CPythonTest/output/0cd580d62a3de4f8.deps.json new file mode 100644 index 0000000..f813be8 --- /dev/null +++ b/Test/CPythonTest/output/0cd580d62a3de4f8.deps.json @@ -0,0 +1 @@ +{"stdio": "73edbcf76e32d00b", "cpython": "7c5d5ec59c5fb0a8"} \ No newline at end of file diff --git a/Test/CPythonTest/output/3e1c3f98e99cff7a.deps.json b/Test/CPythonTest/output/3e1c3f98e99cff7a.deps.json deleted file mode 100644 index a44986b..0000000 --- a/Test/CPythonTest/output/3e1c3f98e99cff7a.deps.json +++ /dev/null @@ -1 +0,0 @@ -{"viperlib": "4d342c40331fc964", "stdint": "56cdd754a8a09347", "main": "6999814920e8b3d5", "stdarg": "81ac26077a460417", "viperio": "c9f4be41ca1cc2b4"} \ No newline at end of file diff --git a/Test/CPythonTest/output/4d342c40331fc964.deps.json b/Test/CPythonTest/output/4d342c40331fc964.deps.json deleted file mode 100644 index 235982b..0000000 --- a/Test/CPythonTest/output/4d342c40331fc964.deps.json +++ /dev/null @@ -1 +0,0 @@ -{"cpython": "3e1c3f98e99cff7a", "stdarg": "81ac26077a460417", "main": "93131e2ff5450838", "viperio": "d771d4d68d9e75b3"} \ No newline at end of file diff --git a/Test/CPythonTest/output/6999814920e8b3d5.deps.json b/Test/CPythonTest/output/6999814920e8b3d5.deps.json deleted file mode 100644 index eb248b3..0000000 --- a/Test/CPythonTest/output/6999814920e8b3d5.deps.json +++ /dev/null @@ -1 +0,0 @@ -{"cpython": "3e1c3f98e99cff7a", "viperlib": "4d342c40331fc964", "stdint": "56cdd754a8a09347", "stdarg": "81ac26077a460417", "viperio": "c9f4be41ca1cc2b4"} \ No newline at end of file diff --git a/Test/CPythonTest/output/7c5d5ec59c5fb0a8.deps.json b/Test/CPythonTest/output/7c5d5ec59c5fb0a8.deps.json new file mode 100644 index 0000000..7d8bc7a --- /dev/null +++ b/Test/CPythonTest/output/7c5d5ec59c5fb0a8.deps.json @@ -0,0 +1 @@ +{"main": "0cd580d62a3de4f8", "stdio": "73edbcf76e32d00b"} \ No newline at end of file diff --git a/Test/CPythonTest/output/CPythonTest.exe.tmp0 b/Test/CPythonTest/output/CPythonTest.exe.tmp0 deleted file mode 100644 index 4b787d636ffebbde0cf8c9db3f13a457c060b36d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 128784 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%0AI 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 U9b~#!z%qomfT_n?em4340A2Nl<^TWy diff --git a/Test/CPythonTest/output/c9f4be41ca1cc2b4.deps.json b/Test/CPythonTest/output/c9f4be41ca1cc2b4.deps.json deleted file mode 100644 index 44c72d1..0000000 --- a/Test/CPythonTest/output/c9f4be41ca1cc2b4.deps.json +++ /dev/null @@ -1 +0,0 @@ -{"cpython": "3e1c3f98e99cff7a", "viperlib": "4d342c40331fc964", "stdint": "56cdd754a8a09347", "main": "6999814920e8b3d5", "stdarg": "81ac26077a460417"} \ No newline at end of file diff --git a/Test/CPythonTest/project.json b/Test/CPythonTest/project.json index 72d58cd..4daa736 100644 --- a/Test/CPythonTest/project.json +++ b/Test/CPythonTest/project.json @@ -11,19 +11,25 @@ }, "linker": { "cmd": "clang++", - "flags": ["-L", "D:\\Python312", "-lmsvcrt", "-lucrt", "-lpthread", "D:\\Python312\\python312.dll"], + "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-msvc", + "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 + "strict_mode": false } } diff --git a/Test/CPythonTest/temp/0cd580d62a3de4f8.pyi b/Test/CPythonTest/temp/0cd580d62a3de4f8.pyi new file mode 100644 index 0000000..60b905d --- /dev/null +++ b/Test/CPythonTest/temp/0cd580d62a3de4f8.pyi @@ -0,0 +1,33 @@ +""" +Auto-generated Python stub file from main.py +Module: main +""" + + +import t, c +from t import CInt, CLong, CDouble, CPtr, CSizeT +from stdio import printf +import cpython + +_pass_count: t.CExtern | CInt +_fail_count: t.CExtern | CInt + +def check(name: t.CChar | CPtr, condition: bool) -> t.CInt: pass + +def test_init_finalize() -> t.CInt: pass + +def test_long_operations() -> t.CInt: pass + +def test_string_operations() -> t.CInt: pass + +def test_list_operations() -> t.CInt: pass + +def test_dict_operations() -> t.CInt: pass + +def test_pyrun_string() -> t.CInt: pass + +def test_import_module() -> t.CInt: pass + +def test_operator_overload() -> t.CInt: pass + +def main() -> CInt | t.CExport: pass diff --git a/Test/CPythonTest/temp/3e1c3f98e99cff7a.pyi b/Test/CPythonTest/temp/3e1c3f98e99cff7a.pyi deleted file mode 100644 index fd235ae..0000000 --- a/Test/CPythonTest/temp/3e1c3f98e99cff7a.pyi +++ /dev/null @@ -1,23 +0,0 @@ -""" -Auto-generated Python stub file from cpython.py -Module: cpython -""" - - -import t, c - -class PyObject: - ob_refcnt: t.CLong - ob_type: t.CPtr - -def Py_Initialize() -> t.CVoid | t.CExtern | t.State: pass - -def PyLong_FromLong(value: t.CLong) -> PyObject | t.CPtr | t.CExtern | t.State: pass - -def PyObject_Str(obj: PyObject | t.CPtr) -> PyObject | t.CPtr | t.CExtern | t.State: pass - -def PyUnicode_AsUTF8(unicode_obj: PyObject | t.CPtr) -> str | t.CExtern | t.State: pass - -def Py_DecRef(obj: PyObject | t.CPtr) -> t.CVoid | t.CExtern | t.State: pass - -def Py_Finalize() -> t.CVoid | t.CExtern | t.State: pass diff --git a/Test/CPythonTest/temp/6999814920e8b3d5.pyi b/Test/CPythonTest/temp/6999814920e8b3d5.pyi deleted file mode 100644 index 1c3efa5..0000000 --- a/Test/CPythonTest/temp/6999814920e8b3d5.pyi +++ /dev/null @@ -1,14 +0,0 @@ -""" -Auto-generated Python stub file from main.py -Module: main -""" - - -import t, c -from t import CInt, CPtr, CChar, CLong -import viperlib -import cpython - -def SetDllDirectoryA(lpPathName: str | CPtr) -> CInt | t.CExtern | t.State: pass - -def main() -> CInt | t.CExport | t.State: pass diff --git a/Test/CPythonTest/temp/73edbcf76e32d00b.pyi b/Test/CPythonTest/temp/73edbcf76e32d00b.pyi new file mode 100644 index 0000000..ef712e3 --- /dev/null +++ b/Test/CPythonTest/temp/73edbcf76e32d00b.pyi @@ -0,0 +1,28 @@ +""" +Auto-generated Python stub file from stdio.py +Module: stdio +""" + + +import t, c + +def printf(fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def fprintf(stream: t.CVoid | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def sprintf(buf: t.CChar | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def snprintf(buf: t.CChar | t.CPtr, size: t.CSizeT, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def puts(s: t.CChar | t.CConst | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + +def fputs(s: t.CChar | t.CConst | t.CPtr, stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + +def fgets(buf: t.CChar | t.CPtr, size: t.CInt, stream: t.CVoid | t.CPtr) -> t.CChar | t.CPtr | t.CExtern | t.CExport: pass + +def fflush(stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + + +stdin: t.CExtern | t.CVoid | t.CPtr +stdout: t.CExtern | t.CVoid | t.CPtr +stderr: t.CExtern | t.CVoid | t.CPtr \ No newline at end of file diff --git a/Test/CPythonTest/temp/7c5d5ec59c5fb0a8.pyi b/Test/CPythonTest/temp/7c5d5ec59c5fb0a8.pyi new file mode 100644 index 0000000..3c94870 --- /dev/null +++ b/Test/CPythonTest/temp/7c5d5ec59c5fb0a8.pyi @@ -0,0 +1,765 @@ +""" +Auto-generated Python stub file from cpython.py +Module: cpython +""" + + +import t, c + +class PyObject: + ob_refcnt: t.CLong + ob_type: t.CPtr + +def Py_INCREF(op: PyObject | t.CPtr) -> t.CVoid | t.State: pass + +def Py_DECREF(op: PyObject | t.CPtr) -> t.CVoid | t.State: pass + +def Py_XINCREF(op: PyObject | t.CPtr) -> t.CVoid | t.State: pass + +def Py_XDECREF(op: PyObject | t.CPtr) -> t.CVoid | t.State: pass + +def Py_DecRef(op: PyObject | t.CPtr) -> t.CVoid | t.State: pass + +def Py_Initialize() -> t.CVoid | t.State: pass + +def Py_Finalize() -> t.CVoid | t.State: pass + +def Py_InitializeEx(initsigs: t.CInt) -> t.CVoid | t.State: pass + +def Py_FinalizeEx() -> t.CInt | t.State: pass + +def Py_IsInitialized() -> t.CInt | t.State: pass + + +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 + +def PyConfig_InitPythonConfig(config: PyConfig | t.CPtr) -> t.CVoid | t.State: pass + +def PyConfig_InitIsolatedConfig(config: PyConfig | t.CPtr) -> t.CVoid | t.State: pass + +def PyConfig_Clear(config: PyConfig | t.CPtr) -> t.CVoid | t.State: pass + +def PyConfig_Read(config: PyConfig | t.CPtr) -> PySTATUS | t.State: pass + +def Py_InitializeFromConfig(config: PyConfig | t.CPtr) -> PySTATUS | t.State: pass + +def Py_DecodeLocale(s: t.CConst | str) -> str | t.State: pass + +def PyStatus_Exception(status: PySTATUS) -> t.CInt | t.State: pass + +def PyLong_FromLong(v: t.CLong) -> PyObject | t.CPtr | t.State: pass + +def PyLong_FromUnsignedLong(v: t.CUnsignedLong) -> PyObject | t.CPtr | t.State: pass + +def PyLong_FromLongLong(v: t.CLong) -> PyObject | t.CPtr | t.State: pass + +def PyLong_FromUnsignedLongLong(v: t.CUnsignedLong) -> PyObject | t.CPtr | t.State: pass + +def PyLong_FromSsize_t(v: t.CPtrDiffT) -> PyObject | t.CPtr | t.State: pass + +def PyLong_FromSize_t(v: t.CSizeT) -> PyObject | t.CPtr | t.State: pass + +def PyLong_FromDouble(v: t.CDouble) -> PyObject | t.CPtr | t.State: pass + +def PyLong_AsLong(obj: PyObject | t.CPtr) -> t.CLong | t.State: pass + +def PyLong_AsUnsignedLong(obj: PyObject | t.CPtr) -> t.CUnsignedLong | t.State: pass + +def PyLong_AsLongLong(obj: PyObject | t.CPtr) -> t.CLong | t.State: pass + +def PyLong_AsUnsignedLongLong(obj: PyObject | t.CPtr) -> t.CUnsignedLong | t.State: pass + +def PyLong_AsDouble(obj: PyObject | t.CPtr) -> t.CDouble | t.State: pass + +def PyLong_AsSsize_t(obj: PyObject | t.CPtr) -> t.CPtrDiffT | t.State: pass + +def PyLong_AsSize_t(obj: PyObject | t.CPtr) -> t.CSizeT | t.State: pass + +def PyFloat_FromDouble(v: t.CDouble) -> PyObject | t.CPtr | t.State: pass + +def PyFloat_AsDouble(obj: PyObject | t.CPtr) -> t.CDouble | t.State: pass + +def PyFloat_FromString(s: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyUnicode_FromString(u: t.CConst | str) -> PyObject | t.CPtr | t.State: pass + +def PyUnicode_FromStringAndSize(u: t.CConst | str, size: t.CSizeT) -> PyObject | t.CPtr | t.State: pass + +def PyUnicode_FromFormat(fmt: t.CConst | str) -> PyObject | t.CPtr | t.State: pass + +def PyUnicode_AsUTF8(obj: PyObject | t.CPtr) -> str | t.State: pass + +def PyUnicode_AsUTF8AndSize(obj: PyObject | t.CPtr, size: t.CPtrDiffT | t.CPtr) -> str | t.State: pass + +def PyUnicode_AsWideChar(obj: PyObject | t.CPtr, wbuf: t.CPtr, bufsize: t.CSizeT) -> t.CSizeT | t.State: pass + +def PyUnicode_GetLength(obj: PyObject | t.CPtr) -> t.CPtrDiffT | t.State: pass + +def PyUnicode_ReadChar(obj: PyObject | t.CPtr, idx: t.CSizeT) -> t.CUInt32T | t.State: pass + +def PyUnicode_WriteChar(obj: PyObject | t.CPtr, idx: t.CSizeT, ch: t.CUInt32T) -> t.CInt | t.State: pass + +def PyUnicode_Compare(l: PyObject | t.CPtr, r: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PyUnicode_Concat(l: PyObject | t.CPtr, r: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyUnicode_Contains(container: PyObject | t.CPtr, element: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PyUnicode_Format(fmt: PyObject | t.CPtr, args: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyUnicode_InternInPlace(s: PyObject | t.CPtr | t.CPtr) -> t.CVoid | t.State: pass + +def PyUnicode_InternFromString(u: t.CConst | str) -> PyObject | t.CPtr | t.State: pass + +def PyBytes_FromString(v: t.CConst | str) -> PyObject | t.CPtr | t.State: pass + +def PyBytes_FromStringAndSize(v: t.CConst | str, size: t.CSizeT) -> PyObject | t.CPtr | t.State: pass + +def PyBytes_AsString(obj: PyObject | t.CPtr) -> str | t.State: pass + +def PyBytes_Size(obj: PyObject | t.CPtr) -> t.CSizeT | t.State: pass + +def PyBytes_FromObject(o: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyBytes_FromFormat(fmt: t.CConst | str) -> PyObject | t.CPtr | t.State: pass + +def PyBool_FromLong(v: t.CLong) -> PyObject | t.CPtr | t.State: pass + + +Py_True: t.CExtern | PyObject | t.CPtr | t.State +Py_False: t.CExtern | PyObject | t.CPtr | t.State +Py_None: t.CExtern | PyObject | t.CPtr | t.State + +def PyList_New(len: t.CSizeT) -> PyObject | t.CPtr | t.State: pass + +def PyList_Size(lst: PyObject | t.CPtr) -> t.CSizeT | t.State: pass + +def PyList_GetItem(lst: PyObject | t.CPtr, idx: t.CSizeT) -> PyObject | t.CPtr | t.State: pass + +def PyList_SetItem(lst: PyObject | t.CPtr, idx: t.CSizeT, item: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PyList_Insert(lst: PyObject | t.CPtr, idx: t.CSizeT, item: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PyList_Append(lst: PyObject | t.CPtr, item: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PyList_GetSlice(lst: PyObject | t.CPtr, lo: t.CSizeT, hi: t.CSizeT) -> PyObject | t.CPtr | t.State: pass + +def PyList_SetSlice(lst: PyObject | t.CPtr, lo: t.CSizeT, hi: t.CSizeT, items: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PyList_Sort(lst: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PyList_Reverse(lst: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PyList_AsTuple(lst: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyTuple_New(len: t.CSizeT) -> PyObject | t.CPtr | t.State: pass + +def PyTuple_Size(tup: PyObject | t.CPtr) -> t.CSizeT | t.State: pass + +def PyTuple_GetItem(tup: PyObject | t.CPtr, idx: t.CSizeT) -> PyObject | t.CPtr | t.State: pass + +def PyTuple_SetItem(tup: PyObject | t.CPtr, idx: t.CSizeT, item: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PyTuple_GetSlice(tup: PyObject | t.CPtr, lo: t.CSizeT, hi: t.CSizeT) -> PyObject | t.CPtr | t.State: pass + +def PyTuple_Pack(n: t.CSizeT) -> PyObject | t.CPtr | t.State: pass + +def PyDict_New() -> PyObject | t.CPtr | t.State: pass + +def PyDict_GetItem(d: PyObject | t.CPtr, key: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyDict_GetItemString(d: PyObject | t.CPtr, key: t.CConst | str) -> PyObject | t.CPtr | t.State: pass + +def PyDict_SetItem(d: PyObject | t.CPtr, key: PyObject | t.CPtr, val: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PyDict_SetItemString(d: PyObject | t.CPtr, key: t.CConst | str, val: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PyDict_DelItem(d: PyObject | t.CPtr, key: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PyDict_DelItemString(d: PyObject | t.CPtr, key: t.CConst | str) -> t.CInt | t.State: pass + +def PyDict_Size(d: PyObject | t.CPtr) -> t.CSizeT | t.State: pass + +def PyDict_Keys(d: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyDict_Values(d: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyDict_Items(d: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyDict_Copy(d: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyDict_Clear(d: PyObject | t.CPtr) -> t.CVoid | t.State: pass + +def PyDict_Contains(d: PyObject | t.CPtr, key: PyObject | t.CPtr) -> t.CInt | t.State: pass + +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 | t.State: pass + +def PyDict_Merge(d: PyObject | t.CPtr, other: PyObject | t.CPtr, override: t.CInt) -> t.CInt | t.State: pass + +def PyDict_Update(d: PyObject | t.CPtr, other: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PyObject_Str(obj: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyObject_Repr(obj: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyObject_Type(obj: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyObject_IsInstance(obj: PyObject | t.CPtr, cls: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PyObject_IsSubclass(obj: PyObject | t.CPtr, cls: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PyObject_HasAttr(obj: PyObject | t.CPtr, name: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PyObject_HasAttrString(obj: PyObject | t.CPtr, name: t.CConst | str) -> t.CInt | t.State: pass + +def PyObject_GetAttr(obj: PyObject | t.CPtr, name: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyObject_GetAttrString(obj: PyObject | t.CPtr, name: t.CConst | str) -> PyObject | t.CPtr | t.State: pass + +def PyObject_SetAttr(obj: PyObject | t.CPtr, name: PyObject | t.CPtr, val: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PyObject_SetAttrString(obj: PyObject | t.CPtr, name: t.CConst | str, val: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PyObject_DelAttr(obj: PyObject | t.CPtr, name: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PyObject_DelAttrString(obj: PyObject | t.CPtr, name: t.CConst | str) -> t.CInt | t.State: pass + +def PyObject_Call(callable: PyObject | t.CPtr, args: PyObject | t.CPtr, kwargs: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyObject_CallObject(callable: PyObject | t.CPtr, args: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyObject_CallNoArgs(callable: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyObject_CallOneArg(callable: PyObject | t.CPtr, arg: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyObject_IsTrue(obj: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PyObject_Not(obj: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PyObject_RichCompare(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr, opid: t.CInt) -> PyObject | t.CPtr | t.State: pass + +def PyObject_RichCompareBool(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr, opid: t.CInt) -> t.CInt | t.State: pass + +def PyObject_Hash(obj: PyObject | t.CPtr) -> t.CLong | t.State: pass + +def PyObject_Length(obj: PyObject | t.CPtr) -> t.CSizeT | t.State: pass + +def PyObject_GetItem(obj: PyObject | t.CPtr, key: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyObject_SetItem(obj: PyObject | t.CPtr, key: PyObject | t.CPtr, val: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PyObject_DelItem(obj: PyObject | t.CPtr, key: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PyObject_Dir(obj: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyObject_GetIter(obj: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyIter_Next(obj: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + + +Py_LT: t.CExtern | t.CInt | t.State +Py_LE: t.CExtern | t.CInt | t.State +Py_EQ: t.CExtern | t.CInt | t.State +Py_NE: t.CExtern | t.CInt | t.State +Py_GT: t.CExtern | t.CInt | t.State +Py_GE: t.CExtern | t.CInt | t.State + +def PyImport_ImportModule(name: t.CConst | str) -> PyObject | t.CPtr | t.State: pass + +def PyImport_Import(name: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +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 | t.State: pass + +def PyImport_ReloadModule(mod: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyImport_AddModule(name: t.CConst | str) -> PyObject | t.CPtr | t.State: pass + +def PyImport_GetModuleDict() -> PyObject | t.CPtr | t.State: pass + +def PyImport_ImportModuleEx(name: t.CConst | str, globs: PyObject | t.CPtr, locs: PyObject | t.CPtr, fromlist: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + + +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 + +def PyModule_Create(mod: PyModuleDef | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyModule_Create2(mod: PyModuleDef | t.CPtr, ver: t.CInt) -> PyObject | t.CPtr | t.State: pass + +def PyModule_GetName(mod: PyObject | t.CPtr) -> str | t.State: pass + +def PyModule_GetDict(mod: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyModule_GetFilenameObject(mod: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyModule_AddObject(mod: PyObject | t.CPtr, name: t.CConst | str, val: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PyModule_AddObjectRef(mod: PyObject | t.CPtr, name: t.CConst | str, val: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PyModule_AddIntConstant(mod: PyObject | t.CPtr, name: t.CConst | str, val: t.CLong) -> t.CInt | t.State: pass + +def PyModule_AddStringConstant(mod: PyObject | t.CPtr, name: t.CConst | str, val: t.CConst | str) -> t.CInt | t.State: pass + +def PyGILState_Ensure() -> t.CInt | t.State: pass + +def PyGILState_Release(state: t.CInt) -> t.CVoid | t.State: pass + +def PyEval_SaveThread() -> t.CPtr | t.State: pass + +def PyEval_RestoreThread(tstate: t.CPtr) -> t.CVoid | t.State: pass + +def PyEval_AcquireThread(tstate: t.CPtr) -> t.CVoid | t.State: pass + +def PyEval_ReleaseThread(tstate: t.CPtr) -> t.CVoid | t.State: pass + +def PyEval_AcquireLock() -> t.CVoid | t.State: pass + +def PyEval_ReleaseLock() -> t.CVoid | t.State: pass + +def PyEval_ThreadsInitialized() -> t.CInt | t.State: pass + +def PyEval_InitThreads() -> t.CVoid | t.State: pass + +def PyErr_Occurred() -> PyObject | t.CPtr | t.State: pass + +def PyErr_Clear() -> t.CVoid | t.State: pass + +def PyErr_Fetch(tp: PyObject | t.CPtr | t.CPtr, val: PyObject | t.CPtr | t.CPtr, tb: PyObject | t.CPtr | t.CPtr) -> t.CVoid | t.State: pass + +def PyErr_Restore(tp: PyObject | t.CPtr, val: PyObject | t.CPtr, tb: PyObject | t.CPtr) -> t.CVoid | t.State: pass + +def PyErr_NormalizeException(tp: PyObject | t.CPtr | t.CPtr, val: PyObject | t.CPtr | t.CPtr, tb: PyObject | t.CPtr | t.CPtr) -> t.CVoid | t.State: pass + +def PyErr_SetString(tp: PyObject | t.CPtr, msg: t.CConst | str) -> t.CVoid | t.State: pass + +def PyErr_SetObject(tp: PyObject | t.CPtr, val: PyObject | t.CPtr) -> t.CVoid | t.State: pass + +def PyErr_BadArgument() -> t.CPtr | t.State: pass + +def PyErr_NoMemory() -> t.CPtr | t.State: pass + +def PyErr_Print() -> t.CVoid | t.State: pass + +def PyErr_ExceptionMatches(exc: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PyErr_GivenExceptionMatches(given: PyObject | t.CPtr, exc: PyObject | t.CPtr) -> t.CInt | t.State: pass + + +PyExc_BaseException: t.CExtern | PyObject | t.CPtr | t.State +PyExc_Exception: t.CExtern | PyObject | t.CPtr | t.State +PyExc_TypeError: t.CExtern | PyObject | t.CPtr | t.State +PyExc_ValueError: t.CExtern | PyObject | t.CPtr | t.State +PyExc_RuntimeError: t.CExtern | PyObject | t.CPtr | t.State +PyExc_KeyError: t.CExtern | PyObject | t.CPtr | t.State +PyExc_IndexError: t.CExtern | PyObject | t.CPtr | t.State +PyExc_AttributeError: t.CExtern | PyObject | t.CPtr | t.State +PyExc_ImportError: t.CExtern | PyObject | t.CPtr | t.State +PyExc_OSError: t.CExtern | PyObject | t.CPtr | t.State +PyExc_IOError: t.CExtern | PyObject | t.CPtr | t.State +PyExc_ZeroDivisionError: t.CExtern | PyObject | t.CPtr | t.State +PyExc_OverflowError: t.CExtern | PyObject | t.CPtr | t.State +PyExc_MemoryError: t.CExtern | PyObject | t.CPtr | t.State +PyExc_NameError: t.CExtern | PyObject | t.CPtr | t.State +PyExc_StopIteration: t.CExtern | PyObject | t.CPtr | t.State +PyExc_NotImplementedError: t.CExtern | PyObject | t.CPtr | t.State +PyExc_SyntaxError: t.CExtern | PyObject | t.CPtr | t.State +PyExc_FileNotFoundError: t.CExtern | PyObject | t.CPtr | t.State +PyExc_PermissionError: t.CExtern | PyObject | t.CPtr | t.State +PyExc_IsADirectoryError: t.CExtern | PyObject | t.CPtr | t.State +PyExc_NotADirectoryError: t.CExtern | PyObject | t.CPtr | t.State + +def Py_BuildValue(fmt: t.CConst | str) -> PyObject | t.CPtr | t.State: pass + +def Py_VaBuildValue(fmt: t.CConst | str, va: t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyLong_Check(obj: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PyFloat_Check(obj: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PyUnicode_Check(obj: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PyBytes_Check(obj: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PyList_Check(obj: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PyTuple_Check(obj: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PyDict_Check(obj: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PyBool_Check(obj: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PyNone_Check(obj: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PyMem_Malloc(size: t.CSizeT) -> t.CPtr | t.State: pass + +def PyMem_Realloc(ptr: t.CPtr, size: t.CSizeT) -> t.CPtr | t.State: pass + +def PyMem_Free(ptr: t.CPtr) -> t.CVoid | t.State: pass + +def PyMem_Calloc(nelem: t.CSizeT, elsize: t.CSizeT) -> t.CPtr | t.State: pass + +def PyObject_Malloc(size: t.CSizeT) -> t.CPtr | t.State: pass + +def PyObject_Realloc(ptr: t.CPtr, size: t.CSizeT) -> t.CPtr | t.State: pass + +def PyObject_Free(ptr: t.CPtr) -> t.CVoid | t.State: pass + +def PyObject_Calloc(nelem: t.CSizeT, elsize: t.CSizeT) -> t.CPtr | t.State: pass + +def PyObject_Init(obj: PyObject | t.CPtr, tp: t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyObject_InitVar(obj: PyObject | t.CPtr, tp: t.CPtr, size: t.CSizeT) -> PyObject | t.CPtr | t.State: pass + +def PyFile_FromString(filename: t.CConst | str, mode: t.CConst | str) -> PyObject | t.CPtr | t.State: pass + +def PyFile_AsFile(file: PyObject | t.CPtr) -> t.CPtr | t.State: pass + +def PyFile_WriteObject(obj: PyObject | t.CPtr, file: PyObject | t.CPtr, flags: t.CInt) -> t.CInt | t.State: pass + +def PyFile_WriteString(s: t.CConst | str, file: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def Py_CompileString(s: t.CConst | str, filename: t.CConst | str, start: t.CInt) -> PyObject | t.CPtr | t.State: pass + +def PyEval_EvalCode(code: PyObject | t.CPtr, globs: PyObject | t.CPtr, locs: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +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 | t.State: pass + +def PyEval_EvalFrame(frame: t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyEval_CallObject(callable: PyObject | t.CPtr, args: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyEval_CallFunction(callable: PyObject | t.CPtr, fmt: t.CConst | str) -> PyObject | t.CPtr | t.State: pass + +def PyEval_CallMethod(obj: PyObject | t.CPtr, method: t.CConst | str, fmt: t.CConst | str) -> PyObject | t.CPtr | t.State: pass + +def PyRun_SimpleString(cmd: t.CConst | str) -> t.CInt | t.State: pass + +def PyRun_SimpleFile(fp: t.CPtr, filename: t.CConst | str) -> t.CInt | t.State: pass + +def PyRun_AnyFile(fp: t.CPtr, filename: t.CConst | str) -> t.CInt | t.State: pass + +def PyRun_String(s: t.CConst | str, start: t.CInt, globs: PyObject | t.CPtr, locs: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyRun_File(fp: t.CPtr, filename: t.CConst | str, start: t.CInt, globs: PyObject | t.CPtr, locs: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + + +Py_single_input: t.CExtern | t.CInt | t.State +Py_file_input: t.CExtern | t.CInt | t.State +Py_eval_input: t.CExtern | t.CInt | t.State + +def PyCapsule_New(ptr: t.CPtr, name: t.CConst | str, dtor: t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyCapsule_GetPointer(cap: PyObject | t.CPtr, name: t.CConst | str) -> t.CPtr | t.State: pass + +def PyCapsule_GetName(cap: PyObject | t.CPtr) -> str | t.State: pass + +def PyCapsule_IsValid(cap: PyObject | t.CPtr, name: t.CConst | str) -> t.CInt | t.State: pass + +def PyCapsule_SetPointer(cap: PyObject | t.CPtr, ptr: t.CPtr) -> t.CInt | t.State: pass + +def PyCapsule_SetName(cap: PyObject | t.CPtr, name: t.CConst | str) -> t.CInt | t.State: pass + +def PyCapsule_SetDestructor(cap: PyObject | t.CPtr, dtor: t.CPtr) -> t.CInt | t.State: pass + +def PySequence_Check(obj: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PySequence_Size(obj: PyObject | t.CPtr) -> t.CSizeT | t.State: pass + +def PySequence_Length(obj: PyObject | t.CPtr) -> t.CSizeT | t.State: pass + +def PySequence_Concat(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PySequence_Repeat(obj: PyObject | t.CPtr, count: t.CSizeT) -> PyObject | t.CPtr | t.State: pass + +def PySequence_GetItem(obj: PyObject | t.CPtr, idx: t.CSizeT) -> PyObject | t.CPtr | t.State: pass + +def PySequence_SetItem(obj: PyObject | t.CPtr, idx: t.CSizeT, val: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PySequence_DelItem(obj: PyObject | t.CPtr, idx: t.CSizeT) -> t.CInt | t.State: pass + +def PySequence_GetSlice(obj: PyObject | t.CPtr, start: t.CSizeT, end: t.CSizeT) -> PyObject | t.CPtr | t.State: pass + +def PySequence_SetSlice(obj: PyObject | t.CPtr, start: t.CSizeT, end: t.CSizeT, val: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PySequence_DelSlice(obj: PyObject | t.CPtr, start: t.CSizeT, end: t.CSizeT) -> t.CInt | t.State: pass + +def PySequence_Contains(obj: PyObject | t.CPtr, val: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PySequence_Index(obj: PyObject | t.CPtr, val: PyObject | t.CPtr) -> t.CSizeT | t.State: pass + +def PySequence_Count(obj: PyObject | t.CPtr, val: PyObject | t.CPtr) -> t.CSizeT | t.State: pass + +def PySequence_List(obj: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PySequence_Tuple(obj: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyMapping_Check(obj: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PyMapping_Size(obj: PyObject | t.CPtr) -> t.CSizeT | t.State: pass + +def PyMapping_Length(obj: PyObject | t.CPtr) -> t.CSizeT | t.State: pass + +def PyMapping_HasKey(obj: PyObject | t.CPtr, key: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PyMapping_HasKeyString(obj: PyObject | t.CPtr, key: t.CConst | str) -> t.CInt | t.State: pass + +def PyMapping_GetItemString(obj: PyObject | t.CPtr, key: t.CConst | str) -> PyObject | t.CPtr | t.State: pass + +def PyMapping_SetItemString(obj: PyObject | t.CPtr, key: t.CConst | str, val: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PyMapping_Keys(obj: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyMapping_Values(obj: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyMapping_Items(obj: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyNumber_Add(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyNumber_Subtract(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyNumber_Multiply(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyNumber_MatrixMultiply(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyNumber_FloorDivide(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyNumber_TrueDivide(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyNumber_Modulo(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyNumber_Power(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr, o3: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyNumber_Negative(obj: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyNumber_Positive(obj: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyNumber_Absolute(obj: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyNumber_Invert(obj: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyNumber_Lshift(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyNumber_Rshift(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyNumber_And(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyNumber_Xor(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyNumber_Or(o1: PyObject | t.CPtr, o2: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyNumber_Index(obj: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyNumber_Long(obj: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyNumber_Float(obj: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyNumber_Check(obj: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PyWeakref_NewRef(obj: PyObject | t.CPtr, cb: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyWeakref_GetObject(ref: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyWeakref_Check(obj: PyObject | t.CPtr) -> t.CInt | t.State: pass + + +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 + +def PySys_GetObject(name: t.CConst | str) -> PyObject | t.CPtr | t.State: pass + +def PySys_SetObject(name: t.CConst | str, val: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PySys_ResetWarnOptions() -> t.CVoid | t.State: pass + +def PySys_AddWarnOption(s: PyObject | t.CPtr) -> t.CVoid | t.State: pass + +def PySYS_AddXOption(s: PyObject | t.CPtr) -> t.CVoid | t.State: pass + +def PySys_WriteStdout(fmt: t.CConst | str) -> t.CVoid | t.State: pass + +def PySys_WriteStderr(fmt: t.CConst | str) -> t.CVoid | t.State: pass + +def PySys_FormatStdout(fmt: t.CConst | str) -> t.CVoid | t.State: pass + +def PySys_FormatStderr(fmt: t.CConst | str) -> t.CVoid | t.State: pass + +def PyMemoryView_FromObject(obj: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyMemoryView_GetContiguous(obj: PyObject | t.CPtr, btype: t.CInt, order: t.CChar) -> PyObject | t.CPtr | t.State: pass + +def PyMemoryView_Check(obj: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PySet_New(iterable: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PySet_Add(s: PyObject | t.CPtr, key: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PySet_Discard(s: PyObject | t.CPtr, key: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PySet_Contains(s: PyObject | t.CPtr, key: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PySet_Size(s: PyObject | t.CPtr) -> t.CSizeT | t.State: pass + +def PySet_Clear(s: PyObject | t.CPtr) -> t.CVoid | t.State: pass + +def PySet_Check(obj: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PyFrozenSet_New(iterable: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +def PyFrozenSet_Check(obj: PyObject | t.CPtr) -> t.CInt | t.State: pass + +def PySlice_New(start: PyObject | t.CPtr, stop: PyObject | t.CPtr, step: PyObject | t.CPtr) -> PyObject | t.CPtr | t.State: pass + +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 | t.State: pass + +def PySlice_Unpack(sl: PyObject | t.CPtr, start: t.CPtrDiffT | t.CPtr, stop: t.CPtrDiffT | t.CPtr, step: t.CPtrDiffT | t.CPtr) -> t.CVoid | t.State: pass + +def PySlice_AdjustIndices(length: t.CSizeT, start: t.CPtrDiffT | t.CPtr, stop: t.CPtrDiffT | t.CPtr, step: t.CPtrDiffT) -> t.CSizeT | t.State: pass + +def PySlice_Check(obj: PyObject | t.CPtr) -> t.CInt | t.State: pass + + +class PyLongObj: + ptr: PyObject | t.CPtr + def __new__(self: PyLongObj) -> 'PyLongObj' | t.CPtr: pass + @staticmethod + def from_long(val: t.CLong) -> 'PyLongObj' | t.CPtr: pass + def __add__(self: PyLongObj, other: PyLongObj | t.CPtr) -> 'PyLongObj' | t.CPtr: pass + def __sub__(self: PyLongObj, other: PyLongObj | t.CPtr) -> 'PyLongObj' | t.CPtr: pass + def __mul__(self: PyLongObj, other: PyLongObj | t.CPtr) -> 'PyLongObj' | t.CPtr: pass + def __neg__(self: PyLongObj) -> 'PyLongObj' | t.CPtr: pass + def to_long(self: PyLongObj) -> t.CLong: pass + def __str__(self: PyLongObj) -> PyObject | t.CPtr: pass + def dec_ref(self: PyLongObj) -> t.CInt: pass +class PyFloatObj: + ptr: PyObject | t.CPtr + def __new__(self: PyFloatObj) -> 'PyFloatObj' | t.CPtr: pass + @staticmethod + def from_double(val: t.CDouble) -> 'PyFloatObj' | t.CPtr: pass + def __add__(self: PyFloatObj, other: PyFloatObj | t.CPtr) -> 'PyFloatObj' | t.CPtr: pass + def __sub__(self: PyFloatObj, other: PyFloatObj | t.CPtr) -> 'PyFloatObj' | t.CPtr: pass + def __mul__(self: PyFloatObj, other: PyFloatObj | t.CPtr) -> 'PyFloatObj' | t.CPtr: pass + def __truediv__(self: PyFloatObj, other: PyFloatObj | t.CPtr) -> 'PyFloatObj' | t.CPtr: pass + def __neg__(self: PyFloatObj) -> 'PyFloatObj' | t.CPtr: pass + def to_double(self: PyFloatObj) -> t.CDouble: pass + def __str__(self: PyFloatObj) -> PyObject | t.CPtr: pass + def dec_ref(self: PyFloatObj) -> t.CInt: pass +class PyUnicodeObj: + ptr: PyObject | t.CPtr + def __new__(self: PyUnicodeObj) -> 'PyUnicodeObj' | t.CPtr: pass + @staticmethod + def from_string(s: t.CChar | t.CPtr) -> 'PyUnicodeObj' | t.CPtr: pass + def __add__(self: PyUnicodeObj, other: PyUnicodeObj | t.CPtr) -> 'PyUnicodeObj' | t.CPtr: pass + def __len__(self: PyUnicodeObj) -> t.CPtrDiffT: pass + def as_utf8(self: PyUnicodeObj) -> t.CChar | t.CPtr: pass + def __str__(self: PyUnicodeObj) -> PyObject | t.CPtr: pass + def dec_ref(self: PyUnicodeObj) -> t.CInt: pass +class PyListObj: + ptr: PyObject | t.CPtr + def __new__(self: PyListObj) -> 'PyListObj' | t.CPtr: pass + @staticmethod + def new() -> 'PyListObj' | t.CPtr: pass + def __getitem__(self: PyListObj, idx: t.CSizeT) -> PyObject | t.CPtr: pass + def __setitem__(self: PyListObj, idx: t.CSizeT, val: PyObject | t.CPtr) -> t.CInt: pass + def __len__(self: PyListObj) -> t.CSizeT: pass + def append(self: PyListObj, item: PyObject | t.CPtr) -> t.CInt: pass + def dec_ref(self: PyListObj) -> t.CInt: pass +class PyDictObj: + ptr: PyObject | t.CPtr + def __new__(self: PyDictObj) -> 'PyDictObj' | t.CPtr: pass + @staticmethod + def new() -> 'PyDictObj' | t.CPtr: pass + def __getitem__(self: PyDictObj, key: PyObject | t.CPtr) -> PyObject | t.CPtr: pass + def __setitem__(self: PyDictObj, key: PyObject | t.CPtr, val: PyObject | t.CPtr) -> t.CInt: pass + def __len__(self: PyDictObj) -> t.CSizeT: pass + def get_string(self: PyDictObj, key: t.CChar | t.CPtr) -> PyObject | t.CPtr: pass + def set_string(self: PyDictObj, key: t.CChar | t.CPtr, val: PyObject | t.CPtr) -> t.CInt: pass + def dec_ref(self: PyDictObj) -> t.CInt: pass \ No newline at end of file diff --git a/Test/CPythonTest/temp/81ac26077a460417.pyi b/Test/CPythonTest/temp/81ac26077a460417.pyi deleted file mode 100644 index 0fadcf3..0000000 --- a/Test/CPythonTest/temp/81ac26077a460417.pyi +++ /dev/null @@ -1,20 +0,0 @@ -""" -Auto-generated Python stub file from stdarg.py -Module: stdarg -""" - -import c - - -import t - -def va_start(args: t.CPtr, last_arg: t.CPtr) -> t.State | t.CExtern | t.CExport: pass - -def va_arg(args: t.CPtr, type: t.CType) -> t.CType | t.CExtern | t.CExport | t.State: pass - -def va_end(args: t.CPtr) -> t.State | t.CExtern | t.CExport: pass - - -va_list: t.CTypedef = t.CUnsignedChar | t.CPtr - -def arg(type: t.CType) -> t.State | t.CExtern | t.CExport: pass diff --git a/Test/CPythonTest/temp/93131e2ff5450838.pyi b/Test/CPythonTest/temp/93131e2ff5450838.pyi deleted file mode 100644 index 1c3efa5..0000000 --- a/Test/CPythonTest/temp/93131e2ff5450838.pyi +++ /dev/null @@ -1,14 +0,0 @@ -""" -Auto-generated Python stub file from main.py -Module: main -""" - - -import t, c -from t import CInt, CPtr, CChar, CLong -import viperlib -import cpython - -def SetDllDirectoryA(lpPathName: str | CPtr) -> CInt | t.CExtern | t.State: pass - -def main() -> CInt | t.CExport | t.State: pass diff --git a/Test/CPythonTest/temp/_sha1_map.txt b/Test/CPythonTest/temp/_sha1_map.txt index cd326f1..8ac6cdb 100644 --- a/Test/CPythonTest/temp/_sha1_map.txt +++ b/Test/CPythonTest/temp/_sha1_map.txt @@ -1,6 +1,3 @@ -3e1c3f98e99cff7a:cpython.py -4d342c40331fc964:includes/viperlib.py -56cdd754a8a09347:includes/stdint.py -6999814920e8b3d5:main.py -81ac26077a460417:includes/stdarg.py -c9f4be41ca1cc2b4:includes/viperio.py +0cd580d62a3de4f8:main.py +73edbcf76e32d00b:includes/stdio.py +7c5d5ec59c5fb0a8:cpython.py diff --git a/Test/CPythonTest/temp/_shared_sym.pkl b/Test/CPythonTest/temp/_shared_sym.pkl index 7e4596b49631b9ed2ddc4ff41d8009804f527566..1cea84637183bfbf9b39f50e239f7071000cf7fc 100644 GIT binary patch literal 314675 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

JW_j?y4j*#WQS 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 E4i_@% diff --git a/Test/CPythonTest/temp/c9f4be41ca1cc2b4.pyi b/Test/CPythonTest/temp/c9f4be41ca1cc2b4.pyi deleted file mode 100644 index b03434d..0000000 --- a/Test/CPythonTest/temp/c9f4be41ca1cc2b4.pyi +++ /dev/null @@ -1,22 +0,0 @@ -""" -Auto-generated Python stub file from viperio.py -Module: viperio -""" - - -import t, c -from stdint import * - -class Buf: - data: t.CChar | t.CPtr - length: t.CSizeT - capacity: t.CSizeT - owned: bool - def __init__(self: Buf, data: t.CChar | t.CPtr, capacity: t.CSizeT, length: t.CSizeT, owned: bool) -> t.CVoid | t.State: pass - def clear(self: Buf) -> t.CVoid | t.State: pass - def write(self: Buf, src: t.CChar | t.CPtr, count: t.CSizeT) -> t.CSizeT | t.State: pass - def cstr(self: Buf) -> t.CChar | t.CPtr | t.State: pass - def reset(self: Buf) -> t.CVoid | t.State: pass - def __enter__(self: Buf) -> 'Buf' | t.CPtr | t.State: pass - def __exit__(self: Buf) -> t.CVoid | t.State: pass - def free(self: Buf) -> t.CVoid | t.State: pass \ No newline at end of file diff --git a/Test/CPythonTest/temp/d771d4d68d9e75b3.pyi b/Test/CPythonTest/temp/d771d4d68d9e75b3.pyi deleted file mode 100644 index d986947..0000000 --- a/Test/CPythonTest/temp/d771d4d68d9e75b3.pyi +++ /dev/null @@ -1,17 +0,0 @@ -""" -Auto-generated Python stub file from viperio.py -Module: viperio -""" - - -import t, c - -@t.Object -class Buf: - buf: str - length: t.CSizeT - capacity: t.CSizeT - onHeap: bool - def __init__(self: Buf, buf: str, length: t.CSizeT, onHeap: bool) -> t.CVoid | t.State: pass - def free(self: Buf) -> t.CVoid | t.State: pass - def __del__(self: Buf) -> t.CVoid | t.State: pass \ No newline at end of file diff --git a/Test/IterTest/output/067c78e9f121dce3.deps.json b/Test/IterTest/output/067c78e9f121dce3.deps.json index 98471fa..195444b 100644 --- a/Test/IterTest/output/067c78e9f121dce3.deps.json +++ b/Test/IterTest/output/067c78e9f121dce3.deps.json @@ -1 +1 @@ -{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "string": "73a525067569932e", "stdio": "73edbcf76e32d00b", "main": "d044f813487c68b6", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3"} \ No newline at end of file +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "main": "d044f813487c68b6", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3"} \ No newline at end of file diff --git a/Test/IterTest/output/29813d57621099a9.deps.json b/Test/IterTest/output/29813d57621099a9.deps.json index b357072..d74db22 100644 --- a/Test/IterTest/output/29813d57621099a9.deps.json +++ b/Test/IterTest/output/29813d57621099a9.deps.json @@ -1 +1 @@ -{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "string": "73a525067569932e", "stdio": "73edbcf76e32d00b", "main": "d044f813487c68b6", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "main": "d044f813487c68b6", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file diff --git a/Test/IterTest/output/5a6a2137958c28c5.deps.json b/Test/IterTest/output/5a6a2137958c28c5.deps.json index 1eabf36..b496ae1 100644 --- a/Test/IterTest/output/5a6a2137958c28c5.deps.json +++ b/Test/IterTest/output/5a6a2137958c28c5.deps.json @@ -1 +1 @@ -{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "string": "73a525067569932e", "stdio": "73edbcf76e32d00b", "main": "d044f813487c68b6", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "main": "d044f813487c68b6", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/IterTest/output/6aee24fdefa3cbc0.deps.json b/Test/IterTest/output/6aee24fdefa3cbc0.deps.json new file mode 100644 index 0000000..9295a3b --- /dev/null +++ b/Test/IterTest/output/6aee24fdefa3cbc0.deps.json @@ -0,0 +1 @@ +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "main": "d044f813487c68b6"} \ No newline at end of file diff --git a/Test/IterTest/output/72e2d5ccb7cedcf1.deps.json b/Test/IterTest/output/72e2d5ccb7cedcf1.deps.json index 14389ed..2d1464a 100644 --- a/Test/IterTest/output/72e2d5ccb7cedcf1.deps.json +++ b/Test/IterTest/output/72e2d5ccb7cedcf1.deps.json @@ -1 +1 @@ -{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "string": "73a525067569932e", "stdio": "73edbcf76e32d00b", "main": "d044f813487c68b6", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e"} \ No newline at end of file +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "main": "d044f813487c68b6", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e"} \ No newline at end of file diff --git a/Test/IterTest/output/73a525067569932e.deps.json b/Test/IterTest/output/73a525067569932e.deps.json deleted file mode 100644 index 4370328..0000000 --- a/Test/IterTest/output/73a525067569932e.deps.json +++ /dev/null @@ -1 +0,0 @@ -{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "string": "73a525067569932e", "stdio": "73edbcf76e32d00b", "main": "d044f813487c68b6"} \ No newline at end of file diff --git a/Test/IterTest/output/abf9ce3160c9279e.deps.json b/Test/IterTest/output/abf9ce3160c9279e.deps.json index 14389ed..2d1464a 100644 --- a/Test/IterTest/output/abf9ce3160c9279e.deps.json +++ b/Test/IterTest/output/abf9ce3160c9279e.deps.json @@ -1 +1 @@ -{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "string": "73a525067569932e", "stdio": "73edbcf76e32d00b", "main": "d044f813487c68b6", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e"} \ No newline at end of file +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "main": "d044f813487c68b6", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e"} \ No newline at end of file diff --git a/Test/IterTest/output/bbdf3bbd4c3bc28c.deps.json b/Test/IterTest/output/bbdf3bbd4c3bc28c.deps.json index a483152..3ce09e1 100644 --- a/Test/IterTest/output/bbdf3bbd4c3bc28c.deps.json +++ b/Test/IterTest/output/bbdf3bbd4c3bc28c.deps.json @@ -1 +1 @@ -{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "string": "73a525067569932e", "stdio": "73edbcf76e32d00b", "main": "d044f813487c68b6", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c"} \ No newline at end of file +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "main": "d044f813487c68b6", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c"} \ No newline at end of file diff --git a/Test/IterTest/output/d044f813487c68b6.deps.json b/Test/IterTest/output/d044f813487c68b6.deps.json index b6c5f72..67944fb 100644 --- a/Test/IterTest/output/d044f813487c68b6.deps.json +++ b/Test/IterTest/output/d044f813487c68b6.deps.json @@ -1 +1 @@ -{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "string": "73a525067569932e", "stdio": "73edbcf76e32d00b"} \ No newline at end of file +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b"} \ No newline at end of file diff --git a/Test/IterTest/output/fa3691e66b426950.deps.json b/Test/IterTest/output/fa3691e66b426950.deps.json index 1eabf36..b496ae1 100644 --- a/Test/IterTest/output/fa3691e66b426950.deps.json +++ b/Test/IterTest/output/fa3691e66b426950.deps.json @@ -1 +1 @@ -{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "string": "73a525067569932e", "stdio": "73edbcf76e32d00b", "main": "d044f813487c68b6", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "main": "d044f813487c68b6", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/StringIterTest/temp/4d5db7f970ef510f.pyi b/Test/IterTest/temp/6aee24fdefa3cbc0.pyi similarity index 93% rename from Test/StringIterTest/temp/4d5db7f970ef510f.pyi rename to Test/IterTest/temp/6aee24fdefa3cbc0.pyi index eae6834..c17475f 100644 --- a/Test/StringIterTest/temp/4d5db7f970ef510f.pyi +++ b/Test/IterTest/temp/6aee24fdefa3cbc0.pyi @@ -37,4 +37,8 @@ def memmove(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.C def atoi(src: str) -> t.CInt: pass +def atoll(src: str) -> t.CInt64T: pass + +def atof(src: str) -> t.CDouble: pass + def split(s: str, delim: str, result: list[str]) -> int: pass diff --git a/Test/IterTest/temp/_sha1_map.txt b/Test/IterTest/temp/_sha1_map.txt index 5b02c88..bfcb886 100644 --- a/Test/IterTest/temp/_sha1_map.txt +++ b/Test/IterTest/temp/_sha1_map.txt @@ -1,6 +1,6 @@ 56cdd754a8a09347:includes/stdint.py 5a6a2137958c28c5:includes/w32\win32base.py +6aee24fdefa3cbc0:includes/string.py 72e2d5ccb7cedcf1:includes/w32\win32memory.py -73a525067569932e:includes/string.py 73edbcf76e32d00b:includes/stdio.py d044f813487c68b6:main.py diff --git a/Test/JsonTest/output/68c4fe4b12c908e3.deps.json b/Test/JsonTest/output/68c4fe4b12c908e3.deps.json index 796afbb..2a07779 100644 --- a/Test/JsonTest/output/68c4fe4b12c908e3.deps.json +++ b/Test/JsonTest/output/68c4fe4b12c908e3.deps.json @@ -1 +1 @@ -{"main": "1dd5985fb89f7ef9", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "json.__init__": "8ee3170049c70333", "__init__": "8ee3170049c70333", "json": "8ee3170049c70333", "json.__parser": "bd2e7db1744476fe", "__parser": "bd2e7db1744476fe", "viperio": "c9f4be41ca1cc2b4", "json.__writer": "eaf7a981f0ef5b22", "__writer": "eaf7a981f0ef5b22", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file +{"main": "1dd5985fb89f7ef9", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "json.__init__": "8ee3170049c70333", "__init__": "8ee3170049c70333", "json": "8ee3170049c70333", "json.__parser": "bd2e7db1744476fe", "__parser": "bd2e7db1744476fe", "viperio": "c9f4be41ca1cc2b4", "json.__writer": "eaf7a981f0ef5b22", "__writer": "eaf7a981f0ef5b22"} \ No newline at end of file diff --git a/Test/JsonTest/output/8ee3170049c70333.deps.json b/Test/JsonTest/output/8ee3170049c70333.deps.json index 796afbb..2a07779 100644 --- a/Test/JsonTest/output/8ee3170049c70333.deps.json +++ b/Test/JsonTest/output/8ee3170049c70333.deps.json @@ -1 +1 @@ -{"main": "1dd5985fb89f7ef9", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "json.__init__": "8ee3170049c70333", "__init__": "8ee3170049c70333", "json": "8ee3170049c70333", "json.__parser": "bd2e7db1744476fe", "__parser": "bd2e7db1744476fe", "viperio": "c9f4be41ca1cc2b4", "json.__writer": "eaf7a981f0ef5b22", "__writer": "eaf7a981f0ef5b22", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file +{"main": "1dd5985fb89f7ef9", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "json.__init__": "8ee3170049c70333", "__init__": "8ee3170049c70333", "json": "8ee3170049c70333", "json.__parser": "bd2e7db1744476fe", "__parser": "bd2e7db1744476fe", "viperio": "c9f4be41ca1cc2b4", "json.__writer": "eaf7a981f0ef5b22", "__writer": "eaf7a981f0ef5b22"} \ No newline at end of file diff --git a/Test/JsonTest/output/bd2e7db1744476fe.deps.json b/Test/JsonTest/output/bd2e7db1744476fe.deps.json index 796afbb..2a07779 100644 --- a/Test/JsonTest/output/bd2e7db1744476fe.deps.json +++ b/Test/JsonTest/output/bd2e7db1744476fe.deps.json @@ -1 +1 @@ -{"main": "1dd5985fb89f7ef9", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "json.__init__": "8ee3170049c70333", "__init__": "8ee3170049c70333", "json": "8ee3170049c70333", "json.__parser": "bd2e7db1744476fe", "__parser": "bd2e7db1744476fe", "viperio": "c9f4be41ca1cc2b4", "json.__writer": "eaf7a981f0ef5b22", "__writer": "eaf7a981f0ef5b22", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file +{"main": "1dd5985fb89f7ef9", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "json.__init__": "8ee3170049c70333", "__init__": "8ee3170049c70333", "json": "8ee3170049c70333", "json.__parser": "bd2e7db1744476fe", "__parser": "bd2e7db1744476fe", "viperio": "c9f4be41ca1cc2b4", "json.__writer": "eaf7a981f0ef5b22", "__writer": "eaf7a981f0ef5b22"} \ No newline at end of file diff --git a/Test/JsonTest/output/eaf7a981f0ef5b22.deps.json b/Test/JsonTest/output/eaf7a981f0ef5b22.deps.json index 796afbb..2a07779 100644 --- a/Test/JsonTest/output/eaf7a981f0ef5b22.deps.json +++ b/Test/JsonTest/output/eaf7a981f0ef5b22.deps.json @@ -1 +1 @@ -{"main": "1dd5985fb89f7ef9", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "json.__init__": "8ee3170049c70333", "__init__": "8ee3170049c70333", "json": "8ee3170049c70333", "json.__parser": "bd2e7db1744476fe", "__parser": "bd2e7db1744476fe", "viperio": "c9f4be41ca1cc2b4", "json.__writer": "eaf7a981f0ef5b22", "__writer": "eaf7a981f0ef5b22", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file +{"main": "1dd5985fb89f7ef9", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "json.__init__": "8ee3170049c70333", "__init__": "8ee3170049c70333", "json": "8ee3170049c70333", "json.__parser": "bd2e7db1744476fe", "__parser": "bd2e7db1744476fe", "viperio": "c9f4be41ca1cc2b4", "json.__writer": "eaf7a981f0ef5b22", "__writer": "eaf7a981f0ef5b22"} \ No newline at end of file diff --git a/Test/PointerTest/output/067c78e9f121dce3.deps.json b/Test/PointerTest/output/067c78e9f121dce3.deps.json index 998d71f..d127b4f 100644 --- a/Test/PointerTest/output/067c78e9f121dce3.deps.json +++ b/Test/PointerTest/output/067c78e9f121dce3.deps.json @@ -1 +1 @@ -{"string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "e0c894447ac34ed3", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3"} \ No newline at end of file +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "e0c894447ac34ed3", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3"} \ No newline at end of file diff --git a/Test/PointerTest/output/29813d57621099a9.deps.json b/Test/PointerTest/output/29813d57621099a9.deps.json index b446460..2104859 100644 --- a/Test/PointerTest/output/29813d57621099a9.deps.json +++ b/Test/PointerTest/output/29813d57621099a9.deps.json @@ -1 +1 @@ -{"string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "e0c894447ac34ed3", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "e0c894447ac34ed3", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file diff --git a/Test/PointerTest/output/5a6a2137958c28c5.deps.json b/Test/PointerTest/output/5a6a2137958c28c5.deps.json index 04173c7..e0323b2 100644 --- a/Test/PointerTest/output/5a6a2137958c28c5.deps.json +++ b/Test/PointerTest/output/5a6a2137958c28c5.deps.json @@ -1 +1 @@ -{"string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "e0c894447ac34ed3", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "e0c894447ac34ed3", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/PointerTest/output/4d5db7f970ef510f.deps.json b/Test/PointerTest/output/6aee24fdefa3cbc0.deps.json similarity index 62% rename from Test/PointerTest/output/4d5db7f970ef510f.deps.json rename to Test/PointerTest/output/6aee24fdefa3cbc0.deps.json index 13ff2b2..ee07c04 100644 --- a/Test/PointerTest/output/4d5db7f970ef510f.deps.json +++ b/Test/PointerTest/output/6aee24fdefa3cbc0.deps.json @@ -1 +1 @@ -{"string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "e0c894447ac34ed3"} \ No newline at end of file +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "e0c894447ac34ed3"} \ No newline at end of file diff --git a/Test/PointerTest/output/72e2d5ccb7cedcf1.deps.json b/Test/PointerTest/output/72e2d5ccb7cedcf1.deps.json index 8c29b5d..eb46ab1 100644 --- a/Test/PointerTest/output/72e2d5ccb7cedcf1.deps.json +++ b/Test/PointerTest/output/72e2d5ccb7cedcf1.deps.json @@ -1 +1 @@ -{"string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "e0c894447ac34ed3", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e"} \ No newline at end of file +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "e0c894447ac34ed3", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e"} \ No newline at end of file diff --git a/Test/PointerTest/output/PointerTest.exe.tmp0 b/Test/PointerTest/output/PointerTest.exe.tmp0 deleted file mode 100644 index 1db13dadcda9779edf811b2b4cd049dc751c23c1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 144821 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 diff --git a/Test/PointerTest/output/abf9ce3160c9279e.deps.json b/Test/PointerTest/output/abf9ce3160c9279e.deps.json index 8c29b5d..eb46ab1 100644 --- a/Test/PointerTest/output/abf9ce3160c9279e.deps.json +++ b/Test/PointerTest/output/abf9ce3160c9279e.deps.json @@ -1 +1 @@ -{"string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "e0c894447ac34ed3", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e"} \ No newline at end of file +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "e0c894447ac34ed3", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e"} \ No newline at end of file diff --git a/Test/PointerTest/output/bbdf3bbd4c3bc28c.deps.json b/Test/PointerTest/output/bbdf3bbd4c3bc28c.deps.json index 04173c7..e0323b2 100644 --- a/Test/PointerTest/output/bbdf3bbd4c3bc28c.deps.json +++ b/Test/PointerTest/output/bbdf3bbd4c3bc28c.deps.json @@ -1 +1 @@ -{"string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "e0c894447ac34ed3", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "e0c894447ac34ed3", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/PointerTest/output/e0c894447ac34ed3.deps.json b/Test/PointerTest/output/e0c894447ac34ed3.deps.json index 1965c34..2fc9271 100644 --- a/Test/PointerTest/output/e0c894447ac34ed3.deps.json +++ b/Test/PointerTest/output/e0c894447ac34ed3.deps.json @@ -1 +1 @@ -{"string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c"} \ No newline at end of file +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c"} \ No newline at end of file diff --git a/Test/PointerTest/output/fa3691e66b426950.deps.json b/Test/PointerTest/output/fa3691e66b426950.deps.json index 04173c7..e0323b2 100644 --- a/Test/PointerTest/output/fa3691e66b426950.deps.json +++ b/Test/PointerTest/output/fa3691e66b426950.deps.json @@ -1 +1 @@ -{"string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "e0c894447ac34ed3", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "e0c894447ac34ed3", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/IterTest/temp/73a525067569932e.pyi b/Test/PointerTest/temp/6aee24fdefa3cbc0.pyi similarity index 93% rename from Test/IterTest/temp/73a525067569932e.pyi rename to Test/PointerTest/temp/6aee24fdefa3cbc0.pyi index eae6834..c17475f 100644 --- a/Test/IterTest/temp/73a525067569932e.pyi +++ b/Test/PointerTest/temp/6aee24fdefa3cbc0.pyi @@ -37,4 +37,8 @@ def memmove(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.C def atoi(src: str) -> t.CInt: pass +def atoll(src: str) -> t.CInt64T: pass + +def atof(src: str) -> t.CDouble: pass + def split(s: str, delim: str, result: list[str]) -> int: pass diff --git a/Test/PointerTest/temp/_sha1_map.txt b/Test/PointerTest/temp/_sha1_map.txt index 46d0124..ce6bb1a 100644 --- a/Test/PointerTest/temp/_sha1_map.txt +++ b/Test/PointerTest/temp/_sha1_map.txt @@ -1,6 +1,6 @@ -4d5db7f970ef510f:includes/string.py 56cdd754a8a09347:includes/stdint.py 5a6a2137958c28c5:includes/w32\win32base.py +6aee24fdefa3cbc0:includes/string.py 72e2d5ccb7cedcf1:includes/w32\win32memory.py 73edbcf76e32d00b:includes/stdio.py bbdf3bbd4c3bc28c:includes/w32\win32console.py diff --git a/Test/ReTest/output/68c4fe4b12c908e3.deps.json b/Test/ReTest/output/68c4fe4b12c908e3.deps.json new file mode 100644 index 0000000..185e2d9 --- /dev/null +++ b/Test/ReTest/output/68c4fe4b12c908e3.deps.json @@ -0,0 +1 @@ +{"stdint": "56cdd754a8a09347", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "re.__init__": "839e950555b6a435", "__init__": "839e950555b6a435", "re": "839e950555b6a435", "main": "9ef80c98cfbbce42", "viperio": "c9f4be41ca1cc2b4"} \ No newline at end of file diff --git a/Test/ReTest/output/6aee24fdefa3cbc0.deps.json b/Test/ReTest/output/6aee24fdefa3cbc0.deps.json new file mode 100644 index 0000000..185e2d9 --- /dev/null +++ b/Test/ReTest/output/6aee24fdefa3cbc0.deps.json @@ -0,0 +1 @@ +{"stdint": "56cdd754a8a09347", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "re.__init__": "839e950555b6a435", "__init__": "839e950555b6a435", "re": "839e950555b6a435", "main": "9ef80c98cfbbce42", "viperio": "c9f4be41ca1cc2b4"} \ No newline at end of file diff --git a/Test/ReTest/output/839e950555b6a435.deps.json b/Test/ReTest/output/839e950555b6a435.deps.json new file mode 100644 index 0000000..185e2d9 --- /dev/null +++ b/Test/ReTest/output/839e950555b6a435.deps.json @@ -0,0 +1 @@ +{"stdint": "56cdd754a8a09347", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "re.__init__": "839e950555b6a435", "__init__": "839e950555b6a435", "re": "839e950555b6a435", "main": "9ef80c98cfbbce42", "viperio": "c9f4be41ca1cc2b4"} \ No newline at end of file diff --git a/Test/ReTest/output/9ef80c98cfbbce42.deps.json b/Test/ReTest/output/9ef80c98cfbbce42.deps.json new file mode 100644 index 0000000..4b6a540 --- /dev/null +++ b/Test/ReTest/output/9ef80c98cfbbce42.deps.json @@ -0,0 +1 @@ +{"stdint": "56cdd754a8a09347", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "re.__init__": "839e950555b6a435", "__init__": "839e950555b6a435", "re": "839e950555b6a435", "viperio": "c9f4be41ca1cc2b4"} \ No newline at end of file diff --git a/Test/ReTest/output/c9f4be41ca1cc2b4.deps.json b/Test/ReTest/output/c9f4be41ca1cc2b4.deps.json new file mode 100644 index 0000000..185e2d9 --- /dev/null +++ b/Test/ReTest/output/c9f4be41ca1cc2b4.deps.json @@ -0,0 +1 @@ +{"stdint": "56cdd754a8a09347", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "re.__init__": "839e950555b6a435", "__init__": "839e950555b6a435", "re": "839e950555b6a435", "main": "9ef80c98cfbbce42", "viperio": "c9f4be41ca1cc2b4"} \ No newline at end of file diff --git a/Test/CPythonTest/temp/56cdd754a8a09347.pyi b/Test/ReTest/temp/56cdd754a8a09347.pyi similarity index 100% rename from Test/CPythonTest/temp/56cdd754a8a09347.pyi rename to Test/ReTest/temp/56cdd754a8a09347.pyi diff --git a/Test/TestProject3/temp/21ffad37f6fc3fcf.pyi b/Test/ReTest/temp/68c4fe4b12c908e3.pyi similarity index 67% rename from Test/TestProject3/temp/21ffad37f6fc3fcf.pyi rename to Test/ReTest/temp/68c4fe4b12c908e3.pyi index f237768..fc2010b 100644 --- a/Test/TestProject3/temp/21ffad37f6fc3fcf.pyi +++ b/Test/ReTest/temp/68c4fe4b12c908e3.pyi @@ -28,17 +28,23 @@ class MPool: free_list: t.CVoid | t.CPtr alloc_map: t.CUInt8T | t.CPtr alloc_map_size: t.CSizeT - def __init__(self: MPool, mem: t.CVoid | t.CPtr, mem_size: t.CSizeT, block_size: t.CSizeT) -> t.CVoid: pass - def _init_bump(self: MPool, mem: t.CVoid | t.CPtr, mem_size: t.CSizeT) -> t.CVoid: pass - def _init_slab(self: MPool, mem: t.CVoid | t.CPtr, mem_size: t.CSizeT, block_size: t.CSizeT) -> t.CVoid: pass + def __init__(self: MPool, mem: t.CVoid | t.CPtr, mem_size: t.CSizeT, block_size: t.CSizeT) -> t.CInt: pass + def _init_bump(self: MPool, mem: t.CVoid | t.CPtr, mem_size: t.CSizeT) -> t.CInt: pass + def _init_slab(self: MPool, mem: t.CVoid | t.CPtr, mem_size: t.CSizeT, block_size: t.CSizeT) -> t.CInt: pass def __enter__(self: MPool) -> 'MPool' | t.CPtr: pass - def __exit__(self: MPool) -> t.CVoid: pass - def _slab_reset(self: MPool) -> t.CVoid: pass + def __exit__(self: MPool) -> t.CInt: pass + def _slab_reset(self: MPool) -> t.CInt: pass def alloc(self: MPool, size: t.CSizeT) -> t.CVoid | t.CPtr: pass def alloc_buf(self: MPool, capacity: t.CSizeT) -> viperio.Buf | t.CPtr: pass - def free(self: MPool, ptr: t.CVoid | t.CPtr) -> t.CVoid: pass + def free(self: MPool, ptr: t.CVoid | t.CPtr) -> t.CInt: pass def realloc(self: MPool, ptr: t.CVoid | t.CPtr, old_size: t.CSizeT, new_size: t.CSizeT) -> t.CVoid | t.CPtr: pass - def reset(self: MPool) -> t.CVoid: pass + def reset(self: MPool) -> t.CInt: pass def _bump_alloc(self: MPool, size: t.CSizeT) -> t.CVoid | t.CPtr: pass def _slab_alloc(self: MPool) -> t.CVoid | t.CPtr: pass - def _slab_free(self: MPool, ptr: t.CVoid | t.CPtr) -> t.CVoid: pass \ No newline at end of file + def _slab_free(self: MPool, ptr: t.CVoid | t.CPtr) -> t.CInt: pass + +def bump_create(mem: t.CVoid | t.CPtr, mem_size: t.CSizeT) -> MPool | t.CPtr: pass + +def alloc(pool: MPool | t.CPtr, size: t.CSizeT) -> t.CVoid | t.CPtr: pass + +def reset(pool: MPool | t.CPtr) -> t.CInt: pass diff --git a/Test/PointerTest/temp/4d5db7f970ef510f.pyi b/Test/ReTest/temp/6aee24fdefa3cbc0.pyi similarity index 93% rename from Test/PointerTest/temp/4d5db7f970ef510f.pyi rename to Test/ReTest/temp/6aee24fdefa3cbc0.pyi index eae6834..c17475f 100644 --- a/Test/PointerTest/temp/4d5db7f970ef510f.pyi +++ b/Test/ReTest/temp/6aee24fdefa3cbc0.pyi @@ -37,4 +37,8 @@ def memmove(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.C def atoi(src: str) -> t.CInt: pass +def atoll(src: str) -> t.CInt64T: pass + +def atof(src: str) -> t.CDouble: pass + def split(s: str, delim: str, result: list[str]) -> int: pass diff --git a/Test/ReTest/temp/73edbcf76e32d00b.pyi b/Test/ReTest/temp/73edbcf76e32d00b.pyi new file mode 100644 index 0000000..ef712e3 --- /dev/null +++ b/Test/ReTest/temp/73edbcf76e32d00b.pyi @@ -0,0 +1,28 @@ +""" +Auto-generated Python stub file from stdio.py +Module: stdio +""" + + +import t, c + +def printf(fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def fprintf(stream: t.CVoid | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def sprintf(buf: t.CChar | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def snprintf(buf: t.CChar | t.CPtr, size: t.CSizeT, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def puts(s: t.CChar | t.CConst | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + +def fputs(s: t.CChar | t.CConst | t.CPtr, stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + +def fgets(buf: t.CChar | t.CPtr, size: t.CInt, stream: t.CVoid | t.CPtr) -> t.CChar | t.CPtr | t.CExtern | t.CExport: pass + +def fflush(stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + + +stdin: t.CExtern | t.CVoid | t.CPtr +stdout: t.CExtern | t.CVoid | t.CPtr +stderr: t.CExtern | t.CVoid | t.CPtr \ No newline at end of file diff --git a/Test/SimdTest/temp/7538e542cab4c1d5.pyi b/Test/ReTest/temp/7538e542cab4c1d5.pyi similarity index 100% rename from Test/SimdTest/temp/7538e542cab4c1d5.pyi rename to Test/ReTest/temp/7538e542cab4c1d5.pyi diff --git a/Test/ReTest/temp/839e950555b6a435.pyi b/Test/ReTest/temp/839e950555b6a435.pyi new file mode 100644 index 0000000..4440462 --- /dev/null +++ b/Test/ReTest/temp/839e950555b6a435.pyi @@ -0,0 +1,103 @@ +""" +Auto-generated Python stub file from re.__init__.py +Module: re.__init__ +""" + + +import t, c +from stdint import * +import mpool +import string + +RE_CHAR: t.CDefine = 0 # 匹配单个字符 +RE_DOT: t.CDefine = 1 # 匹配任意字符(除换行) +RE_CLASS: t.CDefine = 2 # 匹配字符类 [abc] +RE_NCLASS: t.CDefine = 3 # 匹配反义字符类 [^abc] +RE_SPLIT: t.CDefine = 4 # 分裂节点(用于 | ? *) +RE_JUMP: t.CDefine = 5 # 无条件跳转(用于连接) +RE_MATCH: t.CDefine = 6 # 匹配成功 +RE_BOL: t.CDefine = 7 # 行首 ^ +RE_EOL: t.CDefine = 8 # 行尾 $ +RE_DCLASS: t.CDefine = 9 # 预定义字符类 \d \w \s +RE_NDCLASS: t.CDefine = 10 # 预定义反义字符类 \D \W \S +DCLASS_DIGIT: t.CDefine = 0 # \d +DCLASS_WORD: t.CDefine = 1 # \w +DCLASS_SPACE: t.CDefine = 2 # \s +RE_MAX_NODES: t.CDefine = 256 +RE_MAX_STATES: t.CDefine = 256 + +class Renode: + ntype: t.CInt + ch: t.CChar + out1: Renode | t.CPtr + out2: Renode | t.CPtr + cls: t.CChar | t.CPtr + dcls: t.CInt + def __new__(self: Renode, pool: mpool.MPool | t.CPtr) -> 'Renode' | t.CPtr: pass +class RePtrList: + node: Renode | t.CPtr + which: t.CInt + next: RePtrList | t.CPtr + def __new__(self: RePtrList, pool: mpool.MPool | t.CPtr) -> 'RePtrList' | t.CPtr: pass +class Refrag: + start: Renode | t.CPtr + out: RePtrList | t.CPtr + def __new__(self: Refrag, pool: mpool.MPool | t.CPtr) -> 'Refrag' | t.CPtr: pass +class Rematch: + start: t.CSizeT + end: t.CSizeT + found: t.CInt + def __new__(self: Rematch, pool: mpool.MPool | t.CPtr) -> 'Rematch' | t.CPtr: pass + +def _is_word_char(ch: t.CChar) -> bool: pass + +def _match_dclass(dcls: t.CInt, ch: t.CChar) -> bool: pass + +def _list_append(pool: mpool.MPool | t.CPtr, head: RePtrList | t.CPtr, node: Renode | t.CPtr, which: t.CInt) -> RePtrList | t.CPtr: pass + +def _list_patch(head: RePtrList | t.CPtr, target: Renode | t.CPtr) -> t.CInt: pass + +def _list_concat(a: RePtrList | t.CPtr, b: RePtrList | t.CPtr) -> RePtrList | t.CPtr: pass + + +class Recompiler: + pool: mpool.MPool | t.CPtr + p: t.CChar | t.CPtr + pend: t.CChar | t.CPtr + match_node: Renode | t.CPtr + def __new__(self: Recompiler, pool: mpool.MPool | t.CPtr) -> 'Recompiler' | t.CPtr: pass + def compile(self: Recompiler, pattern: t.CChar | t.CPtr) -> Renode | t.CPtr: pass + def _peek(self: Recompiler) -> t.CChar: pass + def _next(self: Recompiler) -> t.CChar: pass + def _parse_alt(self: Recompiler) -> Refrag | t.CPtr: pass + def _parse_concat(self: Recompiler) -> Refrag | t.CPtr: pass + def _parse_repeat(self: Recompiler) -> Refrag | t.CPtr: pass + def _parse_atom(self: Recompiler) -> Refrag | t.CPtr: pass + def _parse_escape(self: Recompiler) -> Refrag | t.CPtr: pass + def _parse_class(self: Recompiler) -> Refrag | t.CPtr: pass +class Restate: + node: Renode | t.CPtr + pos: t.CSizeT + def __new__(self: Restate, pool: mpool.MPool | t.CPtr) -> 'Restate' | t.CPtr: pass + +def _add_state(nlist: t.CVoid | t.CPtr, node: Renode | t.CPtr, pos: t.CSizeT, text: t.CChar | t.CPtr, nstates: t.CInt, max_states: t.CInt) -> t.CInt: pass + +def _read_node(slist: t.CVoid | t.CPtr, idx: t.CInt) -> Renode | t.CPtr: pass + +def _read_pos(slist: t.CVoid | t.CPtr, idx: t.CInt) -> t.CSizeT: pass + +def _step(clist: t.CVoid | t.CPtr, nlist: t.CVoid | t.CPtr, ch: t.CChar, pos: t.CSizeT, text: t.CChar | t.CPtr, cstates: t.CInt, max_states: t.CInt) -> t.CInt: pass + +def _check_match(slist: t.CVoid | t.CPtr, nstates: t.CInt) -> t.CSizeT: pass + +def compile(pool: mpool.MPool | t.CPtr, pattern: t.CChar | t.CPtr) -> Renode | t.CPtr: pass + +def match(pool: mpool.MPool | t.CPtr, pattern: t.CChar | t.CPtr, text: t.CChar | t.CPtr) -> Rematch | t.CPtr: pass + +def search(pool: mpool.MPool | t.CPtr, pattern: t.CChar | t.CPtr, text: t.CChar | t.CPtr) -> Rematch | t.CPtr: pass + +def findall(pool: mpool.MPool | t.CPtr, pattern: t.CChar | t.CPtr, text: t.CChar | t.CPtr, results: t.CChar | t.CPtr | t.CPtr, max_results: t.CSizeT) -> t.CSizeT: pass + +def sub(pool: mpool.MPool | t.CPtr, pattern: t.CChar | t.CPtr, replacement: t.CChar | t.CPtr, text: t.CChar | t.CPtr, outbuf: t.CChar | t.CPtr, outsize: t.CSizeT) -> t.CSizeT: pass + +def split(pool: mpool.MPool | t.CPtr, pattern: t.CChar | t.CPtr, text: t.CChar | t.CPtr, results: t.CChar | t.CPtr | t.CPtr, max_results: t.CSizeT) -> t.CSizeT: pass diff --git a/Test/ReTest/temp/9ef80c98cfbbce42.pyi b/Test/ReTest/temp/9ef80c98cfbbce42.pyi new file mode 100644 index 0000000..dc5715e --- /dev/null +++ b/Test/ReTest/temp/9ef80c98cfbbce42.pyi @@ -0,0 +1,58 @@ +""" +Auto-generated Python stub file from main.py +Module: main +""" + + +import t, c +from t import CInt, CLong, CDouble, CPtr, CSizeT, CChar +from stdio import printf +import re +import mpool +import string +import stdlib + +_pass_count: t.CExtern | CInt +_fail_count: t.CExtern | CInt + +def check(name: CChar | CPtr, condition: bool) -> t.CInt: pass + +def make_pool() -> mpool.MPool | CPtr: pass + +def free_pool(pool: mpool.MPool | CPtr) -> t.CInt: pass + +def test_basic_match() -> t.CInt: pass + +def test_dot() -> t.CInt: pass + +def test_star() -> t.CInt: pass + +def test_plus() -> t.CInt: pass + +def test_question() -> t.CInt: pass + +def test_alt() -> t.CInt: pass + +def test_group() -> t.CInt: pass + +def test_charclass() -> t.CInt: pass + +def test_predefined() -> t.CInt: pass + +def test_search() -> t.CInt: pass + +def test_findall() -> t.CInt: pass + +def test_sub() -> t.CInt: pass + +def test_split() -> t.CInt: pass + +def test_anchors() -> t.CInt: pass + +def test_escape() -> t.CInt: pass + +def test_mpool_reuse() -> t.CInt: pass + +def test_complex() -> t.CInt: pass + +def main() -> t.CInt: pass diff --git a/Test/ReTest/temp/_sha1_map.txt b/Test/ReTest/temp/_sha1_map.txt new file mode 100644 index 0000000..6ff19cc --- /dev/null +++ b/Test/ReTest/temp/_sha1_map.txt @@ -0,0 +1,8 @@ +56cdd754a8a09347:includes/stdint.py +68c4fe4b12c908e3:includes/mpool.py +6aee24fdefa3cbc0:includes/string.py +73edbcf76e32d00b:includes/stdio.py +7538e542cab4c1d5:includes/stdlib.py +839e950555b6a435:includes/re\__init__.py +9ef80c98cfbbce42:main.py +c9f4be41ca1cc2b4:includes/viperio.py diff --git a/Test/ReTest/temp/c9f4be41ca1cc2b4.pyi b/Test/ReTest/temp/c9f4be41ca1cc2b4.pyi new file mode 100644 index 0000000..fdbd7ec --- /dev/null +++ b/Test/ReTest/temp/c9f4be41ca1cc2b4.pyi @@ -0,0 +1,22 @@ +""" +Auto-generated Python stub file from viperio.py +Module: viperio +""" + + +import t, c +from stdint import * + +class Buf: + data: t.CChar | t.CPtr + length: t.CSizeT + capacity: t.CSizeT + owned: bool + def __init__(self: Buf, data: t.CChar | t.CPtr, capacity: t.CSizeT, length: t.CSizeT, owned: bool) -> t.CInt: pass + def clear(self: Buf) -> t.CInt: pass + def write(self: Buf, src: t.CChar | t.CPtr, count: t.CSizeT) -> t.CSizeT: pass + def cstr(self: Buf) -> t.CChar | t.CPtr: pass + def reset(self: Buf) -> t.CInt: pass + def __enter__(self: Buf) -> 'Buf' | t.CPtr: pass + def __exit__(self: Buf) -> t.CInt: pass + def free(self: Buf) -> t.CInt: pass \ No newline at end of file diff --git a/Test/SimdTest/output/024a3459d0f585ae.deps.json b/Test/SimdTest/output/024a3459d0f585ae.deps.json deleted file mode 100644 index 3ad8593..0000000 --- a/Test/SimdTest/output/024a3459d0f585ae.deps.json +++ /dev/null @@ -1 +0,0 @@ -{"string": "024a3459d0f585ae", "main": "1b666d438f4d301e", "vipermath": "3f7c5e78d8652535", "stdint": "56cdd754a8a09347", "mpool": "68c4fe4b12c908e3", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "numpy.__init__": "c3eb91093118e1e1", "__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "vipersimd": "fe99c83946298690"} \ No newline at end of file diff --git a/Test/SimdTest/output/1b666d438f4d301e.deps.json b/Test/SimdTest/output/1b666d438f4d301e.deps.json index f4ea96d..0fec052 100644 --- a/Test/SimdTest/output/1b666d438f4d301e.deps.json +++ b/Test/SimdTest/output/1b666d438f4d301e.deps.json @@ -1 +1 @@ -{"string": "024a3459d0f585ae", "vipermath": "3f7c5e78d8652535", "stdint": "56cdd754a8a09347", "mpool": "68c4fe4b12c908e3", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "numpy.__init__": "c3eb91093118e1e1", "__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "vipersimd": "fe99c83946298690"} \ No newline at end of file +{"vipermath": "3f7c5e78d8652535", "stdint": "56cdd754a8a09347", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdio": "73edbcf76e32d00b", "numpy.__init__": "c3eb91093118e1e1", "__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "vipersimd": "fe99c83946298690"} \ No newline at end of file diff --git a/Test/SimdTest/output/3f7c5e78d8652535.deps.json b/Test/SimdTest/output/3f7c5e78d8652535.deps.json index 3ad8593..6c27984 100644 --- a/Test/SimdTest/output/3f7c5e78d8652535.deps.json +++ b/Test/SimdTest/output/3f7c5e78d8652535.deps.json @@ -1 +1 @@ -{"string": "024a3459d0f585ae", "main": "1b666d438f4d301e", "vipermath": "3f7c5e78d8652535", "stdint": "56cdd754a8a09347", "mpool": "68c4fe4b12c908e3", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "numpy.__init__": "c3eb91093118e1e1", "__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "vipersimd": "fe99c83946298690"} \ No newline at end of file +{"main": "1b666d438f4d301e", "vipermath": "3f7c5e78d8652535", "stdint": "56cdd754a8a09347", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdio": "73edbcf76e32d00b", "numpy.__init__": "c3eb91093118e1e1", "__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "vipersimd": "fe99c83946298690"} \ No newline at end of file diff --git a/Test/SimdTest/output/68c4fe4b12c908e3.deps.json b/Test/SimdTest/output/68c4fe4b12c908e3.deps.json index 3ad8593..6c27984 100644 --- a/Test/SimdTest/output/68c4fe4b12c908e3.deps.json +++ b/Test/SimdTest/output/68c4fe4b12c908e3.deps.json @@ -1 +1 @@ -{"string": "024a3459d0f585ae", "main": "1b666d438f4d301e", "vipermath": "3f7c5e78d8652535", "stdint": "56cdd754a8a09347", "mpool": "68c4fe4b12c908e3", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "numpy.__init__": "c3eb91093118e1e1", "__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "vipersimd": "fe99c83946298690"} \ No newline at end of file +{"main": "1b666d438f4d301e", "vipermath": "3f7c5e78d8652535", "stdint": "56cdd754a8a09347", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdio": "73edbcf76e32d00b", "numpy.__init__": "c3eb91093118e1e1", "__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "vipersimd": "fe99c83946298690"} \ No newline at end of file diff --git a/Test/SimdTest/output/6aee24fdefa3cbc0.deps.json b/Test/SimdTest/output/6aee24fdefa3cbc0.deps.json new file mode 100644 index 0000000..6c27984 --- /dev/null +++ b/Test/SimdTest/output/6aee24fdefa3cbc0.deps.json @@ -0,0 +1 @@ +{"main": "1b666d438f4d301e", "vipermath": "3f7c5e78d8652535", "stdint": "56cdd754a8a09347", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdio": "73edbcf76e32d00b", "numpy.__init__": "c3eb91093118e1e1", "__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "vipersimd": "fe99c83946298690"} \ No newline at end of file diff --git a/Test/SimdTest/output/c3eb91093118e1e1.deps.json b/Test/SimdTest/output/c3eb91093118e1e1.deps.json index 3ad8593..6c27984 100644 --- a/Test/SimdTest/output/c3eb91093118e1e1.deps.json +++ b/Test/SimdTest/output/c3eb91093118e1e1.deps.json @@ -1 +1 @@ -{"string": "024a3459d0f585ae", "main": "1b666d438f4d301e", "vipermath": "3f7c5e78d8652535", "stdint": "56cdd754a8a09347", "mpool": "68c4fe4b12c908e3", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "numpy.__init__": "c3eb91093118e1e1", "__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "vipersimd": "fe99c83946298690"} \ No newline at end of file +{"main": "1b666d438f4d301e", "vipermath": "3f7c5e78d8652535", "stdint": "56cdd754a8a09347", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdio": "73edbcf76e32d00b", "numpy.__init__": "c3eb91093118e1e1", "__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "vipersimd": "fe99c83946298690"} \ No newline at end of file diff --git a/Test/SimdTest/output/c9f4be41ca1cc2b4.deps.json b/Test/SimdTest/output/c9f4be41ca1cc2b4.deps.json index 3ad8593..6c27984 100644 --- a/Test/SimdTest/output/c9f4be41ca1cc2b4.deps.json +++ b/Test/SimdTest/output/c9f4be41ca1cc2b4.deps.json @@ -1 +1 @@ -{"string": "024a3459d0f585ae", "main": "1b666d438f4d301e", "vipermath": "3f7c5e78d8652535", "stdint": "56cdd754a8a09347", "mpool": "68c4fe4b12c908e3", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "numpy.__init__": "c3eb91093118e1e1", "__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "vipersimd": "fe99c83946298690"} \ No newline at end of file +{"main": "1b666d438f4d301e", "vipermath": "3f7c5e78d8652535", "stdint": "56cdd754a8a09347", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdio": "73edbcf76e32d00b", "numpy.__init__": "c3eb91093118e1e1", "__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "vipersimd": "fe99c83946298690"} \ No newline at end of file diff --git a/Test/SimdTest/output/fe99c83946298690.deps.json b/Test/SimdTest/output/fe99c83946298690.deps.json index 3ad8593..6c27984 100644 --- a/Test/SimdTest/output/fe99c83946298690.deps.json +++ b/Test/SimdTest/output/fe99c83946298690.deps.json @@ -1 +1 @@ -{"string": "024a3459d0f585ae", "main": "1b666d438f4d301e", "vipermath": "3f7c5e78d8652535", "stdint": "56cdd754a8a09347", "mpool": "68c4fe4b12c908e3", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "numpy.__init__": "c3eb91093118e1e1", "__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "vipersimd": "fe99c83946298690"} \ No newline at end of file +{"main": "1b666d438f4d301e", "vipermath": "3f7c5e78d8652535", "stdint": "56cdd754a8a09347", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdio": "73edbcf76e32d00b", "numpy.__init__": "c3eb91093118e1e1", "__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "vipersimd": "fe99c83946298690"} \ No newline at end of file diff --git a/Test/SimdTest/temp/024a3459d0f585ae.pyi b/Test/SimdTest/temp/6aee24fdefa3cbc0.pyi similarity index 93% rename from Test/SimdTest/temp/024a3459d0f585ae.pyi rename to Test/SimdTest/temp/6aee24fdefa3cbc0.pyi index eae6834..c17475f 100644 --- a/Test/SimdTest/temp/024a3459d0f585ae.pyi +++ b/Test/SimdTest/temp/6aee24fdefa3cbc0.pyi @@ -37,4 +37,8 @@ def memmove(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.C def atoi(src: str) -> t.CInt: pass +def atoll(src: str) -> t.CInt64T: pass + +def atof(src: str) -> t.CDouble: pass + def split(s: str, delim: str, result: list[str]) -> int: pass diff --git a/Test/SimdTest/temp/6c2029b306556c00.pyi b/Test/SimdTest/temp/6c2029b306556c00.pyi new file mode 100644 index 0000000..98da680 --- /dev/null +++ b/Test/SimdTest/temp/6c2029b306556c00.pyi @@ -0,0 +1,18 @@ +""" +Auto-generated Python stub file from stdlib.py +Module: stdlib +""" + +import c + + +from stdint import * +import t + +def malloc(size: t.CSizeT) -> t.CVoid | t.CPtr | t.State | t.CExtern | t.CExport: pass + +def calloc(nmemb: t.CSizeT, size: t.CSizeT) -> t.CVoid | t.CPtr | t.State | t.CExtern | t.CExport: pass + +def realloc(p: t.CVoid | t.CPtr, size: t.CSizeT) -> t.CVoid | t.CPtr | t.State | t.CExtern | t.CExport: pass + +def free(p: t.CVoid | t.CPtr) -> None | t.State | t.CExtern | t.CExport: pass diff --git a/Test/SimdTest/temp/_sha1_map.txt b/Test/SimdTest/temp/_sha1_map.txt index 8dd8e2c..e9909af 100644 --- a/Test/SimdTest/temp/_sha1_map.txt +++ b/Test/SimdTest/temp/_sha1_map.txt @@ -1,10 +1,10 @@ -024a3459d0f585ae:includes/string.py 1b666d438f4d301e:main.py 3f7c5e78d8652535:includes/vipermath.py 56cdd754a8a09347:includes/stdint.py 68c4fe4b12c908e3:includes/mpool.py +6aee24fdefa3cbc0:includes/string.py +6c2029b306556c00:includes/stdlib.py 73edbcf76e32d00b:includes/stdio.py -7538e542cab4c1d5:includes/stdlib.py c3eb91093118e1e1:includes/numpy\__init__.py c9f4be41ca1cc2b4:includes/viperio.py fe99c83946298690:includes/vipersimd.py diff --git a/Test/StringIterTest/output/2255fdda7aed5595.deps.json b/Test/StringIterTest/output/2255fdda7aed5595.deps.json index 77fa018..edd3f31 100644 --- a/Test/StringIterTest/output/2255fdda7aed5595.deps.json +++ b/Test/StringIterTest/output/2255fdda7aed5595.deps.json @@ -1 +1 @@ -{"string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "stdio": "73edbcf76e32d00b"} \ No newline at end of file +{"stdint": "56cdd754a8a09347", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b"} \ No newline at end of file diff --git a/Test/StringIterTest/output/4d5db7f970ef510f.deps.json b/Test/StringIterTest/output/4d5db7f970ef510f.deps.json deleted file mode 100644 index 07c20ae..0000000 --- a/Test/StringIterTest/output/4d5db7f970ef510f.deps.json +++ /dev/null @@ -1 +0,0 @@ -{"main": "2255fdda7aed5595", "string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "stdio": "73edbcf76e32d00b"} \ No newline at end of file diff --git a/Test/StringIterTest/output/6aee24fdefa3cbc0.deps.json b/Test/StringIterTest/output/6aee24fdefa3cbc0.deps.json new file mode 100644 index 0000000..f246770 --- /dev/null +++ b/Test/StringIterTest/output/6aee24fdefa3cbc0.deps.json @@ -0,0 +1 @@ +{"main": "2255fdda7aed5595", "stdint": "56cdd754a8a09347", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b"} \ No newline at end of file diff --git a/Test/StringIterTest/temp/6aee24fdefa3cbc0.pyi b/Test/StringIterTest/temp/6aee24fdefa3cbc0.pyi new file mode 100644 index 0000000..c17475f --- /dev/null +++ b/Test/StringIterTest/temp/6aee24fdefa3cbc0.pyi @@ -0,0 +1,44 @@ +""" +Auto-generated Python stub file from string.py +Module: string +""" + + +from stdint import * +import t, c + +def strcpy(dest: str, src: str) -> str: pass + +def strncpy(dest: str, src: str, n: t.CSizeT) -> str: pass + +def strlen(src: str) -> t.CSizeT | t.CExport: pass + +def strcmp(str1: str, str2: str) -> t.CInt: pass + +def samestr(str1: str, str2: str) -> bool: pass + +def strncmp(str1: str, str2: str, n: t.CSizeT) -> t.CInt: pass + +def memcmp(ptr1: t.CVoid | t.CPtr, ptr2: t.CVoid | t.CPtr, n: t.CSizeT) -> t.CInt: pass + +def strchr(s: str, cr: t.CInt) -> str: pass + +def strrchr(s: str, cr: t.CInt) -> str: pass + +def strspn(s: str, skip: str) -> int: pass + +def memset(ptr: t.CVoid | t.CPtr, value: t.CInt, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass + +def memset32(ptr: t.CVoid | t.CPtr, value: t.CUInt32T, count: t.CSizeT) -> t.CVoid | t.CPtr: pass + +def memcpy(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass + +def memmove(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr: pass + +def atoi(src: str) -> t.CInt: pass + +def atoll(src: str) -> t.CInt64T: pass + +def atof(src: str) -> t.CDouble: pass + +def split(s: str, delim: str, result: list[str]) -> int: pass diff --git a/Test/StringIterTest/temp/_sha1_map.txt b/Test/StringIterTest/temp/_sha1_map.txt index 856d8cc..c04ac36 100644 --- a/Test/StringIterTest/temp/_sha1_map.txt +++ b/Test/StringIterTest/temp/_sha1_map.txt @@ -1,4 +1,4 @@ 2255fdda7aed5595:main.py -4d5db7f970ef510f:includes/string.py 56cdd754a8a09347:includes/stdint.py +6aee24fdefa3cbc0:includes/string.py 73edbcf76e32d00b:includes/stdio.py diff --git a/Test/StringTest/output/067c78e9f121dce3.deps.json b/Test/StringTest/output/067c78e9f121dce3.deps.json index 438a5c0..df05eb5 100644 --- a/Test/StringTest/output/067c78e9f121dce3.deps.json +++ b/Test/StringTest/output/067c78e9f121dce3.deps.json @@ -1 +1 @@ -{"string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "main": "7aa13c104a22528a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3"} \ No newline at end of file +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "main": "7aa13c104a22528a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3"} \ No newline at end of file diff --git a/Test/StringTest/output/29813d57621099a9.deps.json b/Test/StringTest/output/29813d57621099a9.deps.json index cd6c7b8..8cd5685 100644 --- a/Test/StringTest/output/29813d57621099a9.deps.json +++ b/Test/StringTest/output/29813d57621099a9.deps.json @@ -1 +1 @@ -{"string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "main": "7aa13c104a22528a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "main": "7aa13c104a22528a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file diff --git a/Test/StringTest/output/5a6a2137958c28c5.deps.json b/Test/StringTest/output/5a6a2137958c28c5.deps.json index f00af17..f330458 100644 --- a/Test/StringTest/output/5a6a2137958c28c5.deps.json +++ b/Test/StringTest/output/5a6a2137958c28c5.deps.json @@ -1 +1 @@ -{"string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "main": "7aa13c104a22528a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "main": "7aa13c104a22528a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/StringTest/output/4d5db7f970ef510f.deps.json b/Test/StringTest/output/6aee24fdefa3cbc0.deps.json similarity index 50% rename from Test/StringTest/output/4d5db7f970ef510f.deps.json rename to Test/StringTest/output/6aee24fdefa3cbc0.deps.json index a36f7d0..3ad7aab 100644 --- a/Test/StringTest/output/4d5db7f970ef510f.deps.json +++ b/Test/StringTest/output/6aee24fdefa3cbc0.deps.json @@ -1 +1 @@ -{"string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "main": "7aa13c104a22528a"} \ No newline at end of file +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "main": "7aa13c104a22528a"} \ No newline at end of file diff --git a/Test/StringTest/output/72e2d5ccb7cedcf1.deps.json b/Test/StringTest/output/72e2d5ccb7cedcf1.deps.json index 5017b39..21877dd 100644 --- a/Test/StringTest/output/72e2d5ccb7cedcf1.deps.json +++ b/Test/StringTest/output/72e2d5ccb7cedcf1.deps.json @@ -1 +1 @@ -{"string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "main": "7aa13c104a22528a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e"} \ No newline at end of file +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "main": "7aa13c104a22528a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e"} \ No newline at end of file diff --git a/Test/StringTest/output/7aa13c104a22528a.deps.json b/Test/StringTest/output/7aa13c104a22528a.deps.json index 7ea28c1..67944fb 100644 --- a/Test/StringTest/output/7aa13c104a22528a.deps.json +++ b/Test/StringTest/output/7aa13c104a22528a.deps.json @@ -1 +1 @@ -{"string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b"} \ No newline at end of file +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b"} \ No newline at end of file diff --git a/Test/StringTest/output/abf9ce3160c9279e.deps.json b/Test/StringTest/output/abf9ce3160c9279e.deps.json index 5017b39..21877dd 100644 --- a/Test/StringTest/output/abf9ce3160c9279e.deps.json +++ b/Test/StringTest/output/abf9ce3160c9279e.deps.json @@ -1 +1 @@ -{"string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "main": "7aa13c104a22528a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e"} \ No newline at end of file +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "main": "7aa13c104a22528a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e"} \ No newline at end of file diff --git a/Test/StringTest/output/bbdf3bbd4c3bc28c.deps.json b/Test/StringTest/output/bbdf3bbd4c3bc28c.deps.json index 2138712..3b37a69 100644 --- a/Test/StringTest/output/bbdf3bbd4c3bc28c.deps.json +++ b/Test/StringTest/output/bbdf3bbd4c3bc28c.deps.json @@ -1 +1 @@ -{"string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "main": "7aa13c104a22528a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c"} \ No newline at end of file +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "main": "7aa13c104a22528a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c"} \ No newline at end of file diff --git a/Test/StringTest/output/fa3691e66b426950.deps.json b/Test/StringTest/output/fa3691e66b426950.deps.json index f00af17..f330458 100644 --- a/Test/StringTest/output/fa3691e66b426950.deps.json +++ b/Test/StringTest/output/fa3691e66b426950.deps.json @@ -1 +1 @@ -{"string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "main": "7aa13c104a22528a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "main": "7aa13c104a22528a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/StringTest/temp/4d5db7f970ef510f.pyi b/Test/StringTest/temp/4d5db7f970ef510f.pyi deleted file mode 100644 index eae6834..0000000 --- a/Test/StringTest/temp/4d5db7f970ef510f.pyi +++ /dev/null @@ -1,40 +0,0 @@ -""" -Auto-generated Python stub file from string.py -Module: string -""" - - -from stdint import * -import t, c - -def strcpy(dest: str, src: str) -> str: pass - -def strncpy(dest: str, src: str, n: t.CSizeT) -> str: pass - -def strlen(src: str) -> t.CSizeT | t.CExport: pass - -def strcmp(str1: str, str2: str) -> t.CInt: pass - -def samestr(str1: str, str2: str) -> bool: pass - -def strncmp(str1: str, str2: str, n: t.CSizeT) -> t.CInt: pass - -def memcmp(ptr1: t.CVoid | t.CPtr, ptr2: t.CVoid | t.CPtr, n: t.CSizeT) -> t.CInt: pass - -def strchr(s: str, cr: t.CInt) -> str: pass - -def strrchr(s: str, cr: t.CInt) -> str: pass - -def strspn(s: str, skip: str) -> int: pass - -def memset(ptr: t.CVoid | t.CPtr, value: t.CInt, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass - -def memset32(ptr: t.CVoid | t.CPtr, value: t.CUInt32T, count: t.CSizeT) -> t.CVoid | t.CPtr: pass - -def memcpy(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass - -def memmove(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr: pass - -def atoi(src: str) -> t.CInt: pass - -def split(s: str, delim: str, result: list[str]) -> int: pass diff --git a/Test/StringTest/temp/6aee24fdefa3cbc0.pyi b/Test/StringTest/temp/6aee24fdefa3cbc0.pyi new file mode 100644 index 0000000..c17475f --- /dev/null +++ b/Test/StringTest/temp/6aee24fdefa3cbc0.pyi @@ -0,0 +1,44 @@ +""" +Auto-generated Python stub file from string.py +Module: string +""" + + +from stdint import * +import t, c + +def strcpy(dest: str, src: str) -> str: pass + +def strncpy(dest: str, src: str, n: t.CSizeT) -> str: pass + +def strlen(src: str) -> t.CSizeT | t.CExport: pass + +def strcmp(str1: str, str2: str) -> t.CInt: pass + +def samestr(str1: str, str2: str) -> bool: pass + +def strncmp(str1: str, str2: str, n: t.CSizeT) -> t.CInt: pass + +def memcmp(ptr1: t.CVoid | t.CPtr, ptr2: t.CVoid | t.CPtr, n: t.CSizeT) -> t.CInt: pass + +def strchr(s: str, cr: t.CInt) -> str: pass + +def strrchr(s: str, cr: t.CInt) -> str: pass + +def strspn(s: str, skip: str) -> int: pass + +def memset(ptr: t.CVoid | t.CPtr, value: t.CInt, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass + +def memset32(ptr: t.CVoid | t.CPtr, value: t.CUInt32T, count: t.CSizeT) -> t.CVoid | t.CPtr: pass + +def memcpy(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass + +def memmove(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr: pass + +def atoi(src: str) -> t.CInt: pass + +def atoll(src: str) -> t.CInt64T: pass + +def atof(src: str) -> t.CDouble: pass + +def split(s: str, delim: str, result: list[str]) -> int: pass diff --git a/Test/StringTest/temp/_sha1_map.txt b/Test/StringTest/temp/_sha1_map.txt index 9bb1406..c52b3e4 100644 --- a/Test/StringTest/temp/_sha1_map.txt +++ b/Test/StringTest/temp/_sha1_map.txt @@ -1,6 +1,6 @@ -4d5db7f970ef510f:includes/string.py 56cdd754a8a09347:includes/stdint.py 5a6a2137958c28c5:includes/w32\win32base.py +6aee24fdefa3cbc0:includes/string.py 72e2d5ccb7cedcf1:includes/w32\win32memory.py 73edbcf76e32d00b:includes/stdio.py 7aa13c104a22528a:main.py diff --git a/Test/StructTest/output/067c78e9f121dce3.deps.json b/Test/StructTest/output/067c78e9f121dce3.deps.json index 19c4010..b1872c1 100644 --- a/Test/StructTest/output/067c78e9f121dce3.deps.json +++ b/Test/StructTest/output/067c78e9f121dce3.deps.json @@ -1 +1 @@ -{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "main": "6f6ee14c129ac228", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "string": "a326a52b7c4bd6f0", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3"} \ No newline at end of file +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "main": "6f6ee14c129ac228", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3"} \ No newline at end of file diff --git a/Test/StructTest/output/29813d57621099a9.deps.json b/Test/StructTest/output/29813d57621099a9.deps.json index e6e2b5c..361ae76 100644 --- a/Test/StructTest/output/29813d57621099a9.deps.json +++ b/Test/StructTest/output/29813d57621099a9.deps.json @@ -1 +1 @@ -{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "main": "6f6ee14c129ac228", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "string": "a326a52b7c4bd6f0", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "main": "6f6ee14c129ac228", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file diff --git a/Test/StructTest/output/5a6a2137958c28c5.deps.json b/Test/StructTest/output/5a6a2137958c28c5.deps.json index dab5750..61bb2b5 100644 --- a/Test/StructTest/output/5a6a2137958c28c5.deps.json +++ b/Test/StructTest/output/5a6a2137958c28c5.deps.json @@ -1 +1 @@ -{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "main": "6f6ee14c129ac228", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "string": "a326a52b7c4bd6f0", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "main": "6f6ee14c129ac228", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/StructTest/output/6aee24fdefa3cbc0.deps.json b/Test/StructTest/output/6aee24fdefa3cbc0.deps.json new file mode 100644 index 0000000..ccd7f6c --- /dev/null +++ b/Test/StructTest/output/6aee24fdefa3cbc0.deps.json @@ -0,0 +1 @@ +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "main": "6f6ee14c129ac228", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b"} \ No newline at end of file diff --git a/Test/StructTest/output/6f6ee14c129ac228.deps.json b/Test/StructTest/output/6f6ee14c129ac228.deps.json index 9ec9abe..67944fb 100644 --- a/Test/StructTest/output/6f6ee14c129ac228.deps.json +++ b/Test/StructTest/output/6f6ee14c129ac228.deps.json @@ -1 +1 @@ -{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "string": "a326a52b7c4bd6f0"} \ No newline at end of file +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b"} \ No newline at end of file diff --git a/Test/StructTest/output/72e2d5ccb7cedcf1.deps.json b/Test/StructTest/output/72e2d5ccb7cedcf1.deps.json index 29cf064..d136494 100644 --- a/Test/StructTest/output/72e2d5ccb7cedcf1.deps.json +++ b/Test/StructTest/output/72e2d5ccb7cedcf1.deps.json @@ -1 +1 @@ -{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "main": "6f6ee14c129ac228", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "string": "a326a52b7c4bd6f0", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e"} \ No newline at end of file +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "main": "6f6ee14c129ac228", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e"} \ No newline at end of file diff --git a/Test/StructTest/output/a326a52b7c4bd6f0.deps.json b/Test/StructTest/output/a326a52b7c4bd6f0.deps.json deleted file mode 100644 index 1b0fb2d..0000000 --- a/Test/StructTest/output/a326a52b7c4bd6f0.deps.json +++ /dev/null @@ -1 +0,0 @@ -{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "main": "6f6ee14c129ac228", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "string": "a326a52b7c4bd6f0"} \ No newline at end of file diff --git a/Test/StructTest/output/abf9ce3160c9279e.deps.json b/Test/StructTest/output/abf9ce3160c9279e.deps.json index 29cf064..d136494 100644 --- a/Test/StructTest/output/abf9ce3160c9279e.deps.json +++ b/Test/StructTest/output/abf9ce3160c9279e.deps.json @@ -1 +1 @@ -{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "main": "6f6ee14c129ac228", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "string": "a326a52b7c4bd6f0", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e"} \ No newline at end of file +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "main": "6f6ee14c129ac228", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e"} \ No newline at end of file diff --git a/Test/StructTest/output/bbdf3bbd4c3bc28c.deps.json b/Test/StructTest/output/bbdf3bbd4c3bc28c.deps.json index 4f819ec..cbfaa63 100644 --- a/Test/StructTest/output/bbdf3bbd4c3bc28c.deps.json +++ b/Test/StructTest/output/bbdf3bbd4c3bc28c.deps.json @@ -1 +1 @@ -{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "main": "6f6ee14c129ac228", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "string": "a326a52b7c4bd6f0", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c"} \ No newline at end of file +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "main": "6f6ee14c129ac228", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c"} \ No newline at end of file diff --git a/Test/StructTest/output/fa3691e66b426950.deps.json b/Test/StructTest/output/fa3691e66b426950.deps.json index dab5750..61bb2b5 100644 --- a/Test/StructTest/output/fa3691e66b426950.deps.json +++ b/Test/StructTest/output/fa3691e66b426950.deps.json @@ -1 +1 @@ -{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "main": "6f6ee14c129ac228", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "string": "a326a52b7c4bd6f0", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "main": "6f6ee14c129ac228", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/StructTest/temp/6aee24fdefa3cbc0.pyi b/Test/StructTest/temp/6aee24fdefa3cbc0.pyi new file mode 100644 index 0000000..c17475f --- /dev/null +++ b/Test/StructTest/temp/6aee24fdefa3cbc0.pyi @@ -0,0 +1,44 @@ +""" +Auto-generated Python stub file from string.py +Module: string +""" + + +from stdint import * +import t, c + +def strcpy(dest: str, src: str) -> str: pass + +def strncpy(dest: str, src: str, n: t.CSizeT) -> str: pass + +def strlen(src: str) -> t.CSizeT | t.CExport: pass + +def strcmp(str1: str, str2: str) -> t.CInt: pass + +def samestr(str1: str, str2: str) -> bool: pass + +def strncmp(str1: str, str2: str, n: t.CSizeT) -> t.CInt: pass + +def memcmp(ptr1: t.CVoid | t.CPtr, ptr2: t.CVoid | t.CPtr, n: t.CSizeT) -> t.CInt: pass + +def strchr(s: str, cr: t.CInt) -> str: pass + +def strrchr(s: str, cr: t.CInt) -> str: pass + +def strspn(s: str, skip: str) -> int: pass + +def memset(ptr: t.CVoid | t.CPtr, value: t.CInt, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass + +def memset32(ptr: t.CVoid | t.CPtr, value: t.CUInt32T, count: t.CSizeT) -> t.CVoid | t.CPtr: pass + +def memcpy(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass + +def memmove(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr: pass + +def atoi(src: str) -> t.CInt: pass + +def atoll(src: str) -> t.CInt64T: pass + +def atof(src: str) -> t.CDouble: pass + +def split(s: str, delim: str, result: list[str]) -> int: pass diff --git a/Test/StructTest/temp/_sha1_map.txt b/Test/StructTest/temp/_sha1_map.txt index 1fa7b41..af6559c 100644 --- a/Test/StructTest/temp/_sha1_map.txt +++ b/Test/StructTest/temp/_sha1_map.txt @@ -1,6 +1,6 @@ 56cdd754a8a09347:includes/stdint.py 5a6a2137958c28c5:includes/w32\win32base.py +6aee24fdefa3cbc0:includes/string.py 6f6ee14c129ac228:main.py 72e2d5ccb7cedcf1:includes/w32\win32memory.py 73edbcf76e32d00b:includes/stdio.py -a326a52b7c4bd6f0:includes/string.py diff --git a/Test/StructTest/temp/a326a52b7c4bd6f0.pyi b/Test/StructTest/temp/a326a52b7c4bd6f0.pyi deleted file mode 100644 index eae6834..0000000 --- a/Test/StructTest/temp/a326a52b7c4bd6f0.pyi +++ /dev/null @@ -1,40 +0,0 @@ -""" -Auto-generated Python stub file from string.py -Module: string -""" - - -from stdint import * -import t, c - -def strcpy(dest: str, src: str) -> str: pass - -def strncpy(dest: str, src: str, n: t.CSizeT) -> str: pass - -def strlen(src: str) -> t.CSizeT | t.CExport: pass - -def strcmp(str1: str, str2: str) -> t.CInt: pass - -def samestr(str1: str, str2: str) -> bool: pass - -def strncmp(str1: str, str2: str, n: t.CSizeT) -> t.CInt: pass - -def memcmp(ptr1: t.CVoid | t.CPtr, ptr2: t.CVoid | t.CPtr, n: t.CSizeT) -> t.CInt: pass - -def strchr(s: str, cr: t.CInt) -> str: pass - -def strrchr(s: str, cr: t.CInt) -> str: pass - -def strspn(s: str, skip: str) -> int: pass - -def memset(ptr: t.CVoid | t.CPtr, value: t.CInt, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass - -def memset32(ptr: t.CVoid | t.CPtr, value: t.CUInt32T, count: t.CSizeT) -> t.CVoid | t.CPtr: pass - -def memcpy(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass - -def memmove(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr: pass - -def atoi(src: str) -> t.CInt: pass - -def split(s: str, delim: str, result: list[str]) -> int: pass diff --git a/Test/TestFBProject/App/main.py b/Test/TestFBProject/App/main.py index c6e2804..e98256a 100644 --- a/Test/TestFBProject/App/main.py +++ b/Test/TestFBProject/App/main.py @@ -1,158 +1,158 @@ -from stdint import * -import w32.win32console -import t, c - - -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) - - print("=== Test 1: Raise and catch exact custom exception ===") - try: - raise DiskError("disk error") - except DiskError as e: - print("PASS 1: caught DiskError:", e) - except: - print("FAIL 1: caught by generic except") - print("") - - print("=== Test 2: Catch parent catches child ===") - try: - raise_disk() - except AppError as e: - print("PASS 2: caught AppError (child DiskError):", e) - except: - print("FAIL 2: caught by generic except") - print("") - - print("=== Test 3: Catch parent catches nested child ===") - try: - raise_timeout() - except AppError as e: - print("PASS 3: caught AppError (grandchild TimeoutError):", e) - except: - print("FAIL 3: caught by generic except") - print("") - - print("=== Test 4: Catch mid-level parent ===") - try: - raise_timeout() - except NetworkError as e: - print("PASS 4: caught NetworkError (child TimeoutError):", e) - except: - print("FAIL 4: caught by generic except") - print("") - - print("=== Test 5: Exact catch before parent ===") - try: - raise_network() - except NetworkError as e: - print("PASS 5: caught NetworkError:", e) - except AppError as e: - print("FAIL 5: caught AppError (should be NetworkError first)") - except: - print("FAIL 5: caught by generic except") - print("") - - print("=== Test 6: Parent catch when exact not present ===") - try: - raise_network() - except DiskError as e: - print("FAIL 6: caught DiskError (wrong)") - except AppError as e: - print("PASS 6: caught AppError (no NetworkError handler):", e) - except: - print("FAIL 6: caught by generic except") - print("") - - print("=== Test 7: Generic except fallback ===") - try: - raise_disk() - except RuntimeError as e: - print("FAIL 7: caught RuntimeError (wrong)") - except: - print("PASS 7: caught by generic except") - print("") - - print("=== Test 8: Cross-function with inheritance ===") - try: - raise_timeout() - except NetworkError as e: - print("PASS 8: caught NetworkError (cross-func TimeoutError):", e) - except: - print("FAIL 8: caught by generic except") - print("") - - print("=== Test 9: Built-in exception still works ===") - try: - raise ValueError("test") - except ValueError as e: - print("PASS 9: caught ValueError:", e) - except: - print("FAIL 9: caught by generic except") - print("") - - print("=== Test 10: Mixed built-in and custom ===") - try: - raise RuntimeError("test") - except DiskError as e: - print("FAIL 10: caught DiskError (wrong)") - except RuntimeError as e: - print("PASS 10: caught RuntimeError:", e) - except: - print("FAIL 10: caught by generic except") - print("") - - print("=== All Custom Exception Tests Complete ===") - - print("") - print("=== Test LLVMIR: inline LLVM IR add ===") - x: t.CInt = 10 - y: t.CInt = 20 - r: t.CInt = c.LLVMIR(f"add i32 {c.LInp(x)}, {c.LInp(y)}", t.CInt) - print("LLVMIR add result:", r) - - print("") - print("=== Test CDefine function macro ===") - s: t.CInt = add_inline(3, 4) - print("add_inline(3, 4) =", s) - m: t.CInt = mul_inline(5, 6) - print("mul_inline(5, 6) =", m) - - print("") - print("=== Test LLVMIR with LOut ===") - out_val: t.CInt = 0 - c.LLVMIR(f"{c.LOut(out_val)} = add i32 {c.LInp(x)}, {c.LInp(y)}", t.CInt) - print("LLVMIR LOut result:", out_val) - - return 0 +from stdint import * +import w32.win32console +import t, c + + +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) + + print("=== Test 1: Raise and catch exact custom exception ===") + try: + raise DiskError("disk error") + except DiskError as e: + print("PASS 1: caught DiskError:", e) + except: + print("FAIL 1: caught by generic except") + print("") + + print("=== Test 2: Catch parent catches child ===") + try: + raise_disk() + except AppError as e: + print("PASS 2: caught AppError (child DiskError):", e) + except: + print("FAIL 2: caught by generic except") + print("") + + print("=== Test 3: Catch parent catches nested child ===") + try: + raise_timeout() + except AppError as e: + print("PASS 3: caught AppError (grandchild TimeoutError):", e) + except: + print("FAIL 3: caught by generic except") + print("") + + print("=== Test 4: Catch mid-level parent ===") + try: + raise_timeout() + except NetworkError as e: + print("PASS 4: caught NetworkError (child TimeoutError):", e) + except: + print("FAIL 4: caught by generic except") + print("") + + print("=== Test 5: Exact catch before parent ===") + try: + raise_network() + except NetworkError as e: + print("PASS 5: caught NetworkError:", e) + except AppError as e: + print("FAIL 5: caught AppError (should be NetworkError first)") + except: + print("FAIL 5: caught by generic except") + print("") + + print("=== Test 6: Parent catch when exact not present ===") + try: + raise_network() + except DiskError as e: + print("FAIL 6: caught DiskError (wrong)") + except AppError as e: + print("PASS 6: caught AppError (no NetworkError handler):", e) + except: + print("FAIL 6: caught by generic except") + print("") + + print("=== Test 7: Generic except fallback ===") + try: + raise_disk() + except RuntimeError as e: + print("FAIL 7: caught RuntimeError (wrong)") + except: + print("PASS 7: caught by generic except") + print("") + + print("=== Test 8: Cross-function with inheritance ===") + try: + raise_timeout() + except NetworkError as e: + print("PASS 8: caught NetworkError (cross-func TimeoutError):", e) + except: + print("FAIL 8: caught by generic except") + print("") + + print("=== Test 9: Built-in exception still works ===") + try: + raise ValueError("test") + except ValueError as e: + print("PASS 9: caught ValueError:", e) + except: + print("FAIL 9: caught by generic except") + print("") + + print("=== Test 10: Mixed built-in and custom ===") + try: + raise RuntimeError("test") + except DiskError as e: + print("FAIL 10: caught DiskError (wrong)") + except RuntimeError as e: + print("PASS 10: caught RuntimeError:", e) + except: + print("FAIL 10: caught by generic except") + print("") + + print("=== All Custom Exception Tests Complete ===") + + print("") + print("=== Test LLVMIR: inline LLVM IR add ===") + x: t.CInt = 10 + y: t.CInt = 20 + r: t.CInt = c.LLVMIR(f"add i32 {c.LInp(x)}, {c.LInp(y)}", t.CInt) + print("LLVMIR add result:", r) + + print("") + print("=== Test CDefine function macro ===") + s: t.CInt = add_inline(3, 4) + print("add_inline(3, 4) =", s) + m: t.CInt = mul_inline(5, 6) + print("mul_inline(5, 6) =", m) + + print("") + print("=== Test LLVMIR with LOut ===") + out_val: t.CInt = 0 + c.LLVMIR(f"{c.LOut(out_val)} = add i32 {c.LInp(x)}, {c.LInp(y)}", t.CInt) + print("LLVMIR LOut result:", out_val) + + return 0 diff --git a/Test/TestFBProject/output/067c78e9f121dce3.deps.json b/Test/TestFBProject/output/067c78e9f121dce3.deps.json index 0a11294..cadaa5e 100644 --- a/Test/TestFBProject/output/067c78e9f121dce3.deps.json +++ b/Test/TestFBProject/output/067c78e9f121dce3.deps.json @@ -1 +1 @@ -{"main": "3727eb00d15bf59d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c"} \ No newline at end of file +{"main": "3727eb00d15bf59d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3"} \ No newline at end of file diff --git a/Test/TestFBProject/output/29813d57621099a9.deps.json b/Test/TestFBProject/output/29813d57621099a9.deps.json index 0a11294..ae95e99 100644 --- a/Test/TestFBProject/output/29813d57621099a9.deps.json +++ b/Test/TestFBProject/output/29813d57621099a9.deps.json @@ -1 +1 @@ -{"main": "3727eb00d15bf59d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c"} \ No newline at end of file +{"main": "3727eb00d15bf59d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file diff --git a/Test/TestFBProject/output/5a6a2137958c28c5.deps.json b/Test/TestFBProject/output/5a6a2137958c28c5.deps.json index 5bc5aa9..97f881b 100644 --- a/Test/TestFBProject/output/5a6a2137958c28c5.deps.json +++ b/Test/TestFBProject/output/5a6a2137958c28c5.deps.json @@ -1 +1 @@ -{"main": "214790a9a42a868c", "stdint": "56cdd754a8a09347", "win32.win32console": "ac0664ce209738d9", "win32console": "ac0664ce209738d9"} \ No newline at end of file +{"main": "3727eb00d15bf59d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/TestFBProject/output/72e2d5ccb7cedcf1.deps.json b/Test/TestFBProject/output/72e2d5ccb7cedcf1.deps.json index 0a11294..6b67440 100644 --- a/Test/TestFBProject/output/72e2d5ccb7cedcf1.deps.json +++ b/Test/TestFBProject/output/72e2d5ccb7cedcf1.deps.json @@ -1 +1 @@ -{"main": "3727eb00d15bf59d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c"} \ No newline at end of file +{"main": "3727eb00d15bf59d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1"} \ No newline at end of file diff --git a/Test/TestFBProject/output/abf9ce3160c9279e.deps.json b/Test/TestFBProject/output/abf9ce3160c9279e.deps.json index 0a11294..fac05d5 100644 --- a/Test/TestFBProject/output/abf9ce3160c9279e.deps.json +++ b/Test/TestFBProject/output/abf9ce3160c9279e.deps.json @@ -1 +1 @@ -{"main": "3727eb00d15bf59d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c"} \ No newline at end of file +{"main": "3727eb00d15bf59d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e"} \ No newline at end of file diff --git a/Test/TestFBProject/output/bbdf3bbd4c3bc28c.deps.json b/Test/TestFBProject/output/bbdf3bbd4c3bc28c.deps.json index a1b0dcc..97f881b 100644 --- a/Test/TestFBProject/output/bbdf3bbd4c3bc28c.deps.json +++ b/Test/TestFBProject/output/bbdf3bbd4c3bc28c.deps.json @@ -1 +1 @@ -{"main": "3727eb00d15bf59d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5"} \ No newline at end of file +{"main": "3727eb00d15bf59d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/TestFBProject/output/fa3691e66b426950.deps.json b/Test/TestFBProject/output/fa3691e66b426950.deps.json index 0a11294..97f881b 100644 --- a/Test/TestFBProject/output/fa3691e66b426950.deps.json +++ b/Test/TestFBProject/output/fa3691e66b426950.deps.json @@ -1 +1 @@ -{"main": "3727eb00d15bf59d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c"} \ No newline at end of file +{"main": "3727eb00d15bf59d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/TestFBProject/project.json b/Test/TestFBProject/project.json index a7bd9a7..431a89e 100644 --- a/Test/TestFBProject/project.json +++ b/Test/TestFBProject/project.json @@ -12,9 +12,6 @@ "linker": { "cmd": "clang++", "flags": [ - "-nostdlib", - "-nostartfiles", - "-fno-builtin", "-Wl,--allow-multiple-definition", "-Wl,--unresolved-symbols=ignore-in-object-files", "-lucrt", diff --git a/Test/TestFBProject/temp/067c78e9f121dce3.pyi b/Test/TestFBProject/temp/067c78e9f121dce3.pyi new file mode 100644 index 0000000..f4f767c --- /dev/null +++ b/Test/TestFBProject/temp/067c78e9f121dce3.pyi @@ -0,0 +1,136 @@ +""" +Auto-generated Python stub file from w32.win32process.py +Module: w32.win32process +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +PROCESS_TERMINATE: t.CDefine = 0x0001 +PROCESS_CREATE_THREAD: t.CDefine = 0x0002 +PROCESS_VM_OPERATION: t.CDefine = 0x0008 +PROCESS_VM_READ: t.CDefine = 0x0010 +PROCESS_VM_WRITE: t.CDefine = 0x0020 +PROCESS_QUERY_INFORMATION: t.CDefine = 0x0400 +PROCESS_ALL_ACCESS: t.CDefine = 0x001FFFFF +THREAD_TERMINATE: t.CDefine = 0x0001 +THREAD_SUSPEND_RESUME: t.CDefine = 0x0002 +THREAD_GET_CONTEXT: t.CDefine = 0x0008 +THREAD_SET_CONTEXT: t.CDefine = 0x0010 +THREAD_QUERY_INFORMATION: t.CDefine = 0x0040 +THREAD_ALL_ACCESS: t.CDefine = 0x001FFFFF +CREATE_SUSPENDED: t.CDefine = 0x00000004 +CREATE_NEW_CONSOLE: t.CDefine = 0x00000010 +CREATE_NEW_PROCESS_GROUP: t.CDefine = 0x00000200 +CREATE_NO_WINDOW: t.CDefine = 0x08000000 +DETACHED_PROCESS: t.CDefine = 0x00000008 +STARTF_USESHOWWINDOW: t.CDefine = 0x00000001 +STARTF_USESTDHANDLES: t.CDefine = 0x00000100 +SW_HIDE: t.CDefine = 0 +SW_SHOW: t.CDefine = 5 +SW_MINIMIZE: t.CDefine = 6 +NORMAL_PRIORITY_CLASS: t.CDefine = 0x00000020 +IDLE_PRIORITY_CLASS: t.CDefine = 0x00000040 +HIGH_PRIORITY_CLASS: t.CDefine = 0x00000080 +REALTIME_PRIORITY_CLASS: t.CDefine = 0x00000100 +BELOW_NORMAL_PRIORITY_CLASS: t.CDefine = 0x00004000 +ABOVE_NORMAL_PRIORITY_CLASS: t.CDefine = 0x00008000 +STILL_ACTIVE: t.CDefine = 259 + +class STARTUPINFOA: + cb: ULONG + lpReserved: CHARPTR + lpDesktop: CHARPTR + lpTitle: CHARPTR + dwX: ULONG + dwY: ULONG + dwXSize: ULONG + dwYSize: ULONG + dwXCountChars: ULONG + dwYCountChars: ULONG + dwFillAttribute: ULONG + dwFlags: ULONG + wShowWindow: WORD + cbReserved2: WORD + lpReserved2: VOIDPTR + hStdInput: HANDLE + hStdOutput: HANDLE + hStdError: HANDLE +class STARTUPINFOW: + cb: ULONG + lpReserved: WCHARPTR + lpDesktop: WCHARPTR + lpTitle: WCHARPTR + dwX: ULONG + dwY: ULONG + dwXSize: ULONG + dwYSize: ULONG + dwXCountChars: ULONG + dwYCountChars: ULONG + dwFillAttribute: ULONG + dwFlags: ULONG + wShowWindow: WORD + cbReserved2: WORD + lpReserved2: VOIDPTR + hStdInput: HANDLE + hStdOutput: HANDLE + hStdError: HANDLE +class PROCESS_INFORMATION: + hProcess: HANDLE + hThread: HANDLE + dwProcessId: ULONG + dwThreadId: ULONG + +def CreateProcessA(lpApplicationName: LPCSTR, lpCommandLine: CHARPTR, lpProcessAttributes: SECURITY_ATTRIBUTES | t.CPtr, lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInheritHandles: BOOL, dwCreationFlags: ULONG, lpEnvironment: VOIDPTR, lpCurrentDirectory: LPCSTR, lpStartupInfo: STARTUPINFOA | t.CPtr, lpProcessInformation: PROCESS_INFORMATION | t.CPtr) -> BOOL | t.State: pass + +def CreateProcessW(lpApplicationName: LPCWSTR, lpCommandLine: WCHARPTR, lpProcessAttributes: SECURITY_ATTRIBUTES | t.CPtr, lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInheritHandles: BOOL, dwCreationFlags: ULONG, lpEnvironment: VOIDPTR, lpCurrentDirectory: LPCWSTR, lpStartupInfo: STARTUPINFOW | t.CPtr, lpProcessInformation: PROCESS_INFORMATION | t.CPtr) -> BOOL | t.State: pass + +def TerminateProcess(hProcess: HANDLE, uExitCode: UINT) -> BOOL | t.State: pass + +def GetExitCodeProcess(hProcess: HANDLE, lpExitCode: ULONG | t.CPtr) -> BOOL | t.State: pass + +def GetExitCodeThread(hThread: HANDLE, lpExitCode: ULONG | t.CPtr) -> BOOL | t.State: pass + +def OpenProcess(dwDesiredAccess: ULONG, bInheritHandle: BOOL, dwProcessId: ULONG) -> HANDLE | t.State: pass + +def GetCurrentProcess() -> HANDLE | t.State: pass + +def GetCurrentProcessId() -> ULONG | t.State: pass + +def CreateThread(lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwStackSize: t.CSizeT, lpStartAddress: VOIDPTR, lpParameter: VOIDPTR, dwCreationFlags: ULONG, lpThreadId: ULONG | t.CPtr) -> HANDLE | t.State: pass + +def OpenThread(dwDesiredAccess: ULONG, bInheritHandle: BOOL, dwThreadId: ULONG) -> HANDLE | t.State: pass + +def SuspendThread(hThread: HANDLE) -> ULONG | t.State: pass + +def ResumeThread(hThread: HANDLE) -> ULONG | t.State: pass + +def TerminateThread(hThread: HANDLE, dwExitCode: ULONG) -> BOOL | t.State: pass + +def GetCurrentThread() -> HANDLE | t.State: pass + +def GetCurrentThreadId() -> ULONG | t.State: pass + +def GetThreadId(hThread: HANDLE) -> ULONG | t.State: pass + +def GetProcessId(hProcess: HANDLE) -> ULONG | t.State: pass + +def SetThreadPriority(hThread: HANDLE, nPriority: INT) -> BOOL | t.State: pass + +def GetThreadPriority(hThread: HANDLE) -> INT | t.State: pass + +def ExitProcess(uExitCode: UINT) -> VOID | t.State: pass + +def ExitThread(dwExitCode: ULONG) -> VOID | t.State: pass + +def TlsAlloc() -> ULONG | t.State: pass + +def TlsFree(dwTlsIndex: ULONG) -> BOOL | t.State: pass + +def TlsGetValue(dwTlsIndex: ULONG) -> VOIDPTR | t.State: pass + +def TlsSetValue(dwTlsIndex: ULONG, lpTlsValue: VOIDPTR) -> BOOL | t.State: pass diff --git a/Test/TestFBProject/temp/214790a9a42a868c.pyi b/Test/TestFBProject/temp/214790a9a42a868c.pyi deleted file mode 100644 index 4aa4f2f..0000000 --- a/Test/TestFBProject/temp/214790a9a42a868c.pyi +++ /dev/null @@ -1,33 +0,0 @@ -""" -Auto-generated Python stub file from main.py -Module: main -""" - - -from stdint import * -import win32.win32console -import t, c - -def add_inline(a: t.CInt, b: t.CInt) -> t.CDefine: - pass - -def mul_inline(a: t.CInt, b: t.CInt) -> t.CDefine: - pass - - -class AppError(Exception): - pass -class DiskError(AppError): - pass -class NetworkError(AppError): - pass -class TimeoutError(NetworkError): - pass - -def raise_disk() -> t.CVoid | t.State: pass - -def raise_network() -> t.CVoid | t.State: pass - -def raise_timeout() -> t.CVoid | t.State: pass - -def main() -> t.CInt | t.CExport | t.State: pass diff --git a/Test/TestFBProject/temp/29813d57621099a9.pyi b/Test/TestFBProject/temp/29813d57621099a9.pyi new file mode 100644 index 0000000..a5e9923 --- /dev/null +++ b/Test/TestFBProject/temp/29813d57621099a9.pyi @@ -0,0 +1,85 @@ +""" +Auto-generated Python stub file from w32.win32sync.py +Module: w32.win32sync +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +class CRITICAL_SECTION: + DebugInfo: VOIDPTR + LockCount: LONG + RecursionCount: LONG + OwningThread: HANDLE + LockSemaphore: HANDLE + SpinCount: QWORD + +def InitializeCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def EnterCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def LeaveCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def DeleteCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def TryEnterCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> BOOL | t.State: pass + +def SetCriticalSectionSpinCount(lpCriticalSection: CRITICAL_SECTION | t.CPtr, dwSpinCount: ULONG) -> ULONG | t.State: pass + +def InitializeCriticalSectionAndSpinCount(lpCriticalSection: CRITICAL_SECTION | t.CPtr, dwSpinCount: ULONG) -> BOOL | t.State: pass + +def CreateMutexA(lpMutexAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInitialOwner: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def CreateMutexW(lpMutexAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInitialOwner: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def OpenMutexA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def OpenMutexW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def ReleaseMutex(hMutex: HANDLE) -> BOOL | t.State: pass + +def CreateEventA(lpEventAttributes: SECURITY_ATTRIBUTES | t.CPtr, bManualReset: BOOL, bInitialState: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def CreateEventW(lpEventAttributes: SECURITY_ATTRIBUTES | t.CPtr, bManualReset: BOOL, bInitialState: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def OpenEventA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def OpenEventW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def SetEvent(hEvent: HANDLE) -> BOOL | t.State: pass + +def ResetEvent(hEvent: HANDLE) -> BOOL | t.State: pass + +def PulseEvent(hEvent: HANDLE) -> BOOL | t.State: pass + +def CreateSemaphoreA(lpSemaphoreAttributes: SECURITY_ATTRIBUTES | t.CPtr, lInitialCount: LONG, lMaximumCount: LONG, lpName: LPCSTR) -> HANDLE | t.State: pass + +def CreateSemaphoreW(lpSemaphoreAttributes: SECURITY_ATTRIBUTES | t.CPtr, lInitialCount: LONG, lMaximumCount: LONG, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def OpenSemaphoreA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def OpenSemaphoreW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def ReleaseSemaphore(hSemaphore: HANDLE, lReleaseCount: LONG, lpPreviousCount: LONG | t.CPtr) -> BOOL | t.State: pass + +def WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: ULONG) -> ULONG | t.State: pass + +def WaitForSingleObjectEx(hHandle: HANDLE, dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG | t.State: pass + +def WaitForMultipleObjects(nCount: ULONG, lpHandles: VOIDPTR, bWaitAll: BOOL, dwMilliseconds: ULONG) -> ULONG | t.State: pass + +def WaitForMultipleObjectsEx(nCount: ULONG, lpHandles: VOIDPTR, bWaitAll: BOOL, dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG | t.State: pass + +def InitializeSRWLock(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def AcquireSRWLockExclusive(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def AcquireSRWLockShared(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def ReleaseSRWLockExclusive(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def ReleaseSRWLockShared(SRWLock: VOIDPTR) -> VOID | t.State: pass diff --git a/Test/TestFBProject/temp/3727eb00d15bf59d.pyi b/Test/TestFBProject/temp/3727eb00d15bf59d.pyi index 8a058f6..e778d1b 100644 --- a/Test/TestFBProject/temp/3727eb00d15bf59d.pyi +++ b/Test/TestFBProject/temp/3727eb00d15bf59d.pyi @@ -24,10 +24,10 @@ class NetworkError(AppError): class TimeoutError(NetworkError): pass -def raise_disk() -> t.CVoid | t.State: pass +def raise_disk() -> t.CInt: pass -def raise_network() -> t.CVoid | t.State: pass +def raise_network() -> t.CInt: pass -def raise_timeout() -> t.CVoid | t.State: pass +def raise_timeout() -> t.CInt: pass -def main() -> t.CInt | t.CExport | t.State: pass +def main() -> t.CInt | t.CExport: pass diff --git a/Test/TestFBProject/temp/5a6a2137958c28c5.pyi b/Test/TestFBProject/temp/5a6a2137958c28c5.pyi index 0ed80f0..a137977 100644 --- a/Test/TestFBProject/temp/5a6a2137958c28c5.pyi +++ b/Test/TestFBProject/temp/5a6a2137958c28c5.pyi @@ -1,6 +1,6 @@ """ -Auto-generated Python stub file from win32.win32base.py -Module: win32.win32base +Auto-generated Python stub file from w32.win32base.py +Module: w32.win32base """ import c diff --git a/Test/TestFBProject/temp/72e2d5ccb7cedcf1.pyi b/Test/TestFBProject/temp/72e2d5ccb7cedcf1.pyi new file mode 100644 index 0000000..5fceb08 --- /dev/null +++ b/Test/TestFBProject/temp/72e2d5ccb7cedcf1.pyi @@ -0,0 +1,91 @@ +""" +Auto-generated Python stub file from w32.win32memory.py +Module: w32.win32memory +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +MEM_COMMIT: t.CDefine = 0x00001000 +MEM_RESERVE: t.CDefine = 0x00002000 +MEM_DECOMMIT: t.CDefine = 0x00004000 +MEM_RELEASE: t.CDefine = 0x00008000 +MEM_FREE: t.CDefine = 0x00010000 +MEM_RESET: t.CDefine = 0x00080000 +MEM_TOP_DOWN: t.CDefine = 0x00100000 +MEM_WRITE_WATCH: t.CDefine = 0x00200000 +MEM_PHYSICAL: t.CDefine = 0x00400000 +MEM_LARGE_PAGES: t.CDefine = 0x20000000 +PAGE_NOACCESS: t.CDefine = 0x01 +PAGE_READONLY: t.CDefine = 0x02 +PAGE_READWRITE: t.CDefine = 0x04 +PAGE_WRITECOPY: t.CDefine = 0x08 +PAGE_EXECUTE: t.CDefine = 0x10 +PAGE_EXECUTE_READ: t.CDefine = 0x20 +PAGE_EXECUTE_READWRITE: t.CDefine = 0x40 +PAGE_EXECUTE_WRITECOPY: t.CDefine = 0x80 +PAGE_GUARD: t.CDefine = 0x100 +PAGE_NOCACHE: t.CDefine = 0x200 +PAGE_WRITECOMBINE: t.CDefine = 0x400 +HEAP_NO_SERIALIZE: t.CDefine = 0x00000001 +HEAP_GROWABLE: t.CDefine = 0x00000002 +HEAP_GENERATE_EXCEPTIONS: t.CDefine = 0x00000004 +HEAP_ZERO_MEMORY: t.CDefine = 0x00000008 +HEAP_REALLOC_IN_PLACE_ONLY: t.CDefine = 0x00000010 + +class MEMORY_BASIC_INFORMATION: + BaseAddress: VOIDPTR + AllocationBase: VOIDPTR + AllocationProtect: ULONG + RegionSize: t.CSizeT + State: ULONG + Protect: ULONG + Type: ULONG + +def VirtualAlloc(lpAddress: VOIDPTR, dwSize: t.CSizeT, flAllocationType: ULONG, flProtect: ULONG) -> VOIDPTR | t.State: pass + +def VirtualFree(lpAddress: VOIDPTR, dwSize: t.CSizeT, dwFreeType: ULONG) -> BOOL | t.State: pass + +def VirtualProtect(lpAddress: VOIDPTR, dwSize: t.CSizeT, flNewProtect: ULONG, lpflOldProtect: ULONG | t.CPtr) -> BOOL | t.State: pass + +def VirtualQuery(lpAddress: t.CConst | VOIDPTR, lpBuffer: MEMORY_BASIC_INFORMATION | t.CPtr, dwLength: t.CSizeT) -> t.CSizeT | t.State: pass + +def VirtualLock(lpAddress: VOIDPTR, dwSize: t.CSizeT) -> BOOL | t.State: pass + +def VirtualUnlock(lpAddress: VOIDPTR, dwSize: t.CSizeT) -> BOOL | t.State: pass + +def GetProcessHeap() -> HANDLE | t.State: pass + +def HeapCreate(flOptions: ULONG, dwInitialSize: t.CSizeT, dwMaximumSize: t.CSizeT) -> HANDLE | t.State: pass + +def HeapDestroy(hHeap: HANDLE) -> BOOL | t.State: pass + +def HeapAlloc(hHeap: HANDLE, dwFlags: ULONG, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def HeapReAlloc(hHeap: HANDLE, dwFlags: ULONG, lpMem: VOIDPTR, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def HeapFree(hHeap: HANDLE, dwFlags: ULONG, lpMem: VOIDPTR) -> BOOL | t.State: pass + +def HeapSize(hHeap: HANDLE, dwFlags: ULONG, lpMem: t.CConst | VOIDPTR) -> t.CSizeT | t.State: pass + +def HeapValidate(hHeap: HANDLE, dwFlags: ULONG, lpMem: t.CConst | VOIDPTR) -> BOOL | t.State: pass + +def HeapCompact(hHeap: HANDLE, dwFlags: ULONG) -> t.CSizeT | t.State: pass + +def GlobalAlloc(uFlags: UINT, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def GlobalFree(hMem: VOIDPTR) -> VOIDPTR | t.State: pass + +def GlobalLock(hMem: VOIDPTR) -> VOIDPTR | t.State: pass + +def GlobalUnlock(hMem: VOIDPTR) -> BOOL | t.State: pass + +def GlobalSize(hMem: VOIDPTR) -> t.CSizeT | t.State: pass + +def LocalAlloc(uFlags: UINT, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def LocalFree(hMem: VOIDPTR) -> VOIDPTR | t.State: pass diff --git a/Test/TestFBProject/temp/abf9ce3160c9279e.pyi b/Test/TestFBProject/temp/abf9ce3160c9279e.pyi new file mode 100644 index 0000000..4249b58 --- /dev/null +++ b/Test/TestFBProject/temp/abf9ce3160c9279e.pyi @@ -0,0 +1,179 @@ +""" +Auto-generated Python stub file from w32.win32file.py +Module: w32.win32file +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +GENERIC_READ: t.CDefine = 0x80000000 +GENERIC_WRITE: t.CDefine = 0x40000000 +GENERIC_EXECUTE: t.CDefine = 0x20000000 +GENERIC_ALL: t.CDefine = 0x10000000 +FILE_SHARE_READ: t.CDefine = 0x00000001 +FILE_SHARE_WRITE: t.CDefine = 0x00000002 +FILE_SHARE_DELETE: t.CDefine = 0x00000004 +CREATE_NEW: t.CDefine = 1 +CREATE_ALWAYS: t.CDefine = 2 +OPEN_EXISTING: t.CDefine = 3 +OPEN_ALWAYS: t.CDefine = 4 +TRUNCATE_EXISTING: t.CDefine = 5 +FILE_ATTRIBUTE_READONLY: t.CDefine = 0x00000001 +FILE_ATTRIBUTE_HIDDEN: t.CDefine = 0x00000002 +FILE_ATTRIBUTE_SYSTEM: t.CDefine = 0x00000004 +FILE_ATTRIBUTE_DIRECTORY: t.CDefine = 0x00000010 +FILE_ATTRIBUTE_ARCHIVE: t.CDefine = 0x00000020 +FILE_ATTRIBUTE_NORMAL: t.CDefine = 0x00000080 +FILE_ATTRIBUTE_TEMPORARY: t.CDefine = 0x00000100 +FILE_ATTRIBUTE_COMPRESSED: t.CDefine = 0x00000800 +FILE_ATTRIBUTE_OFFLINE: t.CDefine = 0x00001000 +FILE_ATTRIBUTE_ENCRYPTED: t.CDefine = 0x00004000 +FILE_FLAG_WRITE_THROUGH: t.CDefine = 0x80000000 +FILE_FLAG_OVERLAPPED: t.CDefine = 0x40000000 +FILE_FLAG_NO_BUFFERING: t.CDefine = 0x20000000 +FILE_FLAG_RANDOM_ACCESS: t.CDefine = 0x10000000 +FILE_FLAG_SEQUENTIAL_SCAN: t.CDefine = 0x08000000 +FILE_FLAG_DELETE_ON_CLOSE: t.CDefine = 0x04000000 +FILE_FLAG_BACKUP_SEMANTICS: t.CDefine = 0x02000000 +FILE_FLAG_POSIX_SEMANTICS: t.CDefine = 0x01000000 +FILE_BEGIN: t.CDefine = 0 +FILE_CURRENT: t.CDefine = 1 +FILE_END: t.CDefine = 2 +STD_INPUT_HANDLE: t.CDefine = t.CUnsignedLong(-10) +STD_OUTPUT_HANDLE: t.CDefine = t.CUnsignedLong(-11) +STD_ERROR_HANDLE: t.CDefine = t.CUnsignedLong(-12) +MOVEFILE_REPLACE_EXISTING: t.CDefine = 0x00000001 +MOVEFILE_COPY_ALLOWED: t.CDefine = 0x00000002 +MOVEFILE_WRITE_THROUGH: t.CDefine = 0x00000008 + +class BY_HANDLE_FILE_INFORMATION: + dwFileAttributes: ULONG + ftCreationTime: FILETIME + ftLastAccessTime: FILETIME + ftLastWriteTime: FILETIME + dwVolumeSerialNumber: ULONG + nFileSizeHigh: ULONG + nFileSizeLow: ULONG + nNumberOfLinks: ULONG + nFileIndexHigh: ULONG + nFileIndexLow: ULONG +class WIN32_FIND_DATAA: + dwFileAttributes: ULONG + ftCreationTime: FILETIME + ftLastAccessTime: FILETIME + ftLastWriteTime: FILETIME + nFileSizeHigh: ULONG + nFileSizeLow: ULONG + dwReserved0: ULONG + dwReserved1: ULONG + cFileName: CHARPTR + cAlternateFileName: CHARPTR +class WIN32_FIND_DATAW: + dwFileAttributes: ULONG + ftCreationTime: FILETIME + ftLastAccessTime: FILETIME + ftLastWriteTime: FILETIME + nFileSizeHigh: ULONG + nFileSizeLow: ULONG + dwReserved0: ULONG + dwReserved1: ULONG + cFileName: WCHARPTR + cAlternateFileName: WCHARPTR + +def CreateFileA(lpFileName: LPCSTR, dwDesiredAccess: ULONG, dwShareMode: ULONG, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwCreationDisposition: ULONG, dwFlagsAndAttributes: ULONG, hTemplateFile: HANDLE) -> HANDLE | t.State: pass + +def CreateFileW(lpFileName: LPCWSTR, dwDesiredAccess: ULONG, dwShareMode: ULONG, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwCreationDisposition: ULONG, dwFlagsAndAttributes: ULONG, hTemplateFile: HANDLE) -> HANDLE | t.State: pass + +def ReadFile(hFile: HANDLE, lpBuffer: VOIDPTR, nNumberOfBytesToRead: ULONG, lpNumberOfBytesRead: ULONG | t.CPtr, lpOverlapped: OVERLAPPED | t.CPtr) -> BOOL | t.State: pass + +def WriteFile(hFile: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfBytesToWrite: ULONG, lpNumberOfBytesWritten: ULONG | t.CPtr, lpOverlapped: OVERLAPPED | t.CPtr) -> BOOL | t.State: pass + +def SetFilePointer(hFile: HANDLE, lDistanceToMove: LONG, lpDistanceToMoveHigh: LONG | t.CPtr, dwMoveMethod: ULONG) -> LONG | t.State: pass + +def SetFilePointerEx(hFile: HANDLE, liDistanceToMove: LARGE_INTEGER | t.CPtr, lpNewFilePointer: LARGE_INTEGER | t.CPtr, dwMoveMethod: ULONG) -> BOOL | t.State: pass + +def GetFileSize(hFile: HANDLE, lpFileSizeHigh: ULONG | t.CPtr) -> ULONG | t.State: pass + +def GetFileSizeEx(hFile: HANDLE, lpFileSize: LARGE_INTEGER | t.CPtr) -> BOOL | t.State: pass + +def SetEndOfFile(hFile: HANDLE) -> BOOL | t.State: pass + +def FlushFileBuffers(hFile: HANDLE) -> BOOL | t.State: pass + +def GetFileType(hFile: HANDLE) -> ULONG | t.State: pass + +def GetFileAttributesA(lpFileName: LPCSTR) -> ULONG | t.State: pass + +def GetFileAttributesW(lpFileName: LPCWSTR) -> ULONG | t.State: pass + +def SetFileAttributesA(lpFileName: LPCSTR, dwFileAttributes: ULONG) -> BOOL | t.State: pass + +def SetFileAttributesW(lpFileName: LPCWSTR, dwFileAttributes: ULONG) -> BOOL | t.State: pass + +def DeleteFileA(lpFileName: LPCSTR) -> BOOL | t.State: pass + +def DeleteFileW(lpFileName: LPCWSTR) -> BOOL | t.State: pass + +def MoveFileA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR) -> BOOL | t.State: pass + +def MoveFileW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR) -> BOOL | t.State: pass + +def MoveFileExA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR, dwFlags: ULONG) -> BOOL | t.State: pass + +def MoveFileExW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR, dwFlags: ULONG) -> BOOL | t.State: pass + +def CopyFileA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR, bFailIfExists: BOOL) -> BOOL | t.State: pass + +def CopyFileW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR, bFailIfExists: BOOL) -> BOOL | t.State: pass + +def CreateDirectoryA(lpPathName: LPCSTR, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr) -> BOOL | t.State: pass + +def CreateDirectoryW(lpPathName: LPCWSTR, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr) -> BOOL | t.State: pass + +def RemoveDirectoryA(lpPathName: LPCSTR) -> BOOL | t.State: pass + +def RemoveDirectoryW(lpPathName: LPCWSTR) -> BOOL | t.State: pass + +def FindFirstFileA(lpFileName: LPCSTR, lpFindFileData: WIN32_FIND_DATAA | t.CPtr) -> HANDLE | t.State: pass + +def FindFirstFileW(lpFileName: LPCWSTR, lpFindFileData: WIN32_FIND_DATAW | t.CPtr) -> HANDLE | t.State: pass + +def FindNextFileA(hFindFile: HANDLE, lpFindFileData: WIN32_FIND_DATAA | t.CPtr) -> BOOL | t.State: pass + +def FindNextFileW(hFindFile: HANDLE, lpFindFileData: WIN32_FIND_DATAW | t.CPtr) -> BOOL | t.State: pass + +def FindClose(hFindFile: HANDLE) -> BOOL | t.State: pass + +def GetStdHandle(nStdHandle: ULONG) -> HANDLE | t.State: pass + +def SetStdHandle(nStdHandle: ULONG, hHandle: HANDLE) -> BOOL | t.State: pass + +def GetFileInformationByHandle(hFile: HANDLE, lpFileInformation: BY_HANDLE_FILE_INFORMATION | t.CPtr) -> BOOL | t.State: pass + +def LockFile(hFile: HANDLE, dwFileOffsetLow: ULONG, dwFileOffsetHigh: ULONG, nNumberOfBytesToLockLow: ULONG, nNumberOfBytesToLockHigh: ULONG) -> BOOL | t.State: pass + +def UnlockFile(hFile: HANDLE, dwFileOffsetLow: ULONG, dwFileOffsetHigh: ULONG, nNumberOfBytesToUnlockLow: ULONG, nNumberOfBytesToUnlockHigh: ULONG) -> BOOL | t.State: pass + +def GetTempPathA(nBufferLength: ULONG, lpBuffer: CHARPTR) -> ULONG | t.State: pass + +def GetTempPathW(nBufferLength: ULONG, lpBuffer: WCHARPTR) -> ULONG | t.State: pass + +def GetTempFileNameA(lpPathName: LPCSTR, lpPrefixString: LPCSTR, uUnique: UINT, lpTempFileName: CHARPTR) -> UINT | t.State: pass + +def GetTempFileNameW(lpPathName: LPCWSTR, lpPrefixString: LPCWSTR, uUnique: UINT, lpTempFileName: WCHARPTR) -> UINT | t.State: pass + +def GetCurrentDirectoryA(nBufferLength: ULONG, lpBuffer: CHARPTR) -> ULONG | t.State: pass + +def GetCurrentDirectoryW(nBufferLength: ULONG, lpBuffer: WCHARPTR) -> ULONG | t.State: pass + +def SetCurrentDirectoryA(lpPathName: LPCSTR) -> BOOL | t.State: pass + +def SetCurrentDirectoryW(lpPathName: LPCWSTR) -> BOOL | t.State: pass + +def GetModuleFileNameA(hModule: HANDLE, lpFilename: CHARPTR, nSize: ULONG) -> ULONG | t.State: pass + +def GetModuleFileNameW(hModule: HANDLE, lpFilename: WCHARPTR, nSize: ULONG) -> ULONG | t.State: pass diff --git a/Test/TestFBProject/temp/ac0664ce209738d9.pyi b/Test/TestFBProject/temp/ac0664ce209738d9.pyi deleted file mode 100644 index 489db56..0000000 --- a/Test/TestFBProject/temp/ac0664ce209738d9.pyi +++ /dev/null @@ -1,138 +0,0 @@ -""" -Auto-generated Python stub file from win32.win32console.py -Module: win32.win32console -""" - -import c - - -import t -from stdint import * -from win32.win32base import * - -ENABLE_PROCESSED_INPUT: t.CDefine = 0x0001 -ENABLE_LINE_INPUT: t.CDefine = 0x0002 -ENABLE_ECHO_INPUT: t.CDefine = 0x0004 -ENABLE_WINDOW_INPUT: t.CDefine = 0x0008 -ENABLE_MOUSE_INPUT: t.CDefine = 0x0010 -ENABLE_INSERT_MODE: t.CDefine = 0x0020 -ENABLE_QUICK_EDIT_MODE: t.CDefine = 0x0040 -ENABLE_EXTENDED_FLAGS: t.CDefine = 0x0080 -ENABLE_PROCESSED_OUTPUT: t.CDefine = 0x0001 -ENABLE_WRAP_AT_EOL_OUTPUT: t.CDefine = 0x0002 -ENABLE_VIRTUAL_TERMINAL_PROCESSING: t.CDefine = 0x0004 -DISABLE_NEWLINE_AUTO_RETURN: t.CDefine = 0x0008 -ENABLE_LVB_GRID_WORLDWIDE: t.CDefine = 0x0010 -FOREGROUND_BLUE: t.CDefine = 0x0001 -FOREGROUND_GREEN: t.CDefine = 0x0002 -FOREGROUND_RED: t.CDefine = 0x0004 -FOREGROUND_INTENSITY: t.CDefine = 0x0008 -BACKGROUND_BLUE: t.CDefine = 0x0010 -BACKGROUND_GREEN: t.CDefine = 0x0020 -BACKGROUND_RED: t.CDefine = 0x0040 -BACKGROUND_INTENSITY: t.CDefine = 0x0080 -KEY_EVENT: t.CDefine = 0x0001 -MOUSE_EVENT: t.CDefine = 0x0002 -WINDOW_BUFFER_SIZE_EVENT: t.CDefine = 0x0004 -MENU_EVENT: t.CDefine = 0x0008 -FOCUS_EVENT: t.CDefine = 0x0010 - -class COORD: - X: SHORT - Y: SHORT -class SMALL_RECT: - Left: SHORT - Top: SHORT - Right: SHORT - Bottom: SHORT -class CONSOLE_SCREEN_BUFFER_INFO: - dwSize: COORD - dwCursorPosition: COORD - wAttributes: WORD - srWindow: SMALL_RECT - dwMaximumWindowSize: COORD -class CONSOLE_CURSOR_INFO: - dwSize: ULONG - bVisible: BOOL -class CHAR_INFO: - UnicodeChar: WCHAR - Attributes: WORD -class KEY_EVENT_RECORD: - bKeyDown: BOOL - wRepeatCount: WORD - wVirtualKeyCode: WORD - wVirtualScanCode: WORD - uChar: WCHAR - dwControlKeyState: ULONG -class MOUSE_EVENT_RECORD: - dwMousePosition: COORD - dwButtonState: ULONG - dwControlKeyState: ULONG - dwEventFlags: ULONG -class WINDOW_BUFFER_SIZE_RECORD: - dwSize: COORD -class INPUT_RECORD: - EventType: WORD - Event: KEY_EVENT_RECORD - -def SetConsoleOutputCP(codepage: UINT) -> BOOL | t.State: pass - -def SetConsoleCP(codepage: UINT) -> BOOL | t.State: pass - -def GetConsoleCP() -> UINT | t.State: pass - -def GetConsoleOutputCP() -> UINT | t.State: pass - -def GetConsoleScreenBufferInfo(hConsoleOutput: HANDLE, lpConsoleScreenBufferInfo: CONSOLE_SCREEN_BUFFER_INFO | t.CPtr) -> BOOL | t.State: pass - -def SetConsoleScreenBufferSize(hConsoleOutput: HANDLE, dwSize: COORD) -> BOOL | t.State: pass - -def SetConsoleCursorPosition(hConsoleOutput: HANDLE, dwCursorPosition: COORD) -> BOOL | t.State: pass - -def GetConsoleCursorInfo(hConsoleOutput: HANDLE, lpConsoleCursorInfo: CONSOLE_CURSOR_INFO | t.CPtr) -> BOOL | t.State: pass - -def SetConsoleCursorInfo(hConsoleOutput: HANDLE, lpConsoleCursorInfo: CONSOLE_CURSOR_INFO | t.CPtr) -> BOOL | t.State: pass - -def SetConsoleTextAttribute(hConsoleOutput: HANDLE, wAttributes: WORD) -> BOOL | t.State: pass - -def FillConsoleOutputCharacterA(hConsoleOutput: HANDLE, cCharacter: t.CChar, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfCharsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass - -def FillConsoleOutputCharacterW(hConsoleOutput: HANDLE, cCharacter: WCHAR, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfCharsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass - -def FillConsoleOutputAttribute(hConsoleOutput: HANDLE, wAttribute: WORD, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfAttrsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass - -def WriteConsoleA(hConsoleOutput: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfCharsToWrite: ULONG, lpNumberOfCharsWritten: ULONG | t.CPtr, lpReserved: VOIDPTR) -> BOOL | t.State: pass - -def WriteConsoleW(hConsoleOutput: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfCharsToWrite: ULONG, lpNumberOfCharsWritten: ULONG | t.CPtr, lpReserved: VOIDPTR) -> BOOL | t.State: pass - -def ReadConsoleA(hConsoleInput: HANDLE, lpBuffer: VOIDPTR, nNumberOfCharsToRead: ULONG, lpNumberOfCharsRead: ULONG | t.CPtr, pInputControl: VOIDPTR) -> BOOL | t.State: pass - -def ReadConsoleW(hConsoleInput: HANDLE, lpBuffer: VOIDPTR, nNumberOfCharsToRead: ULONG, lpNumberOfCharsRead: ULONG | t.CPtr, pInputControl: VOIDPTR) -> BOOL | t.State: pass - -def GetConsoleMode(hConsoleHandle: HANDLE, lpMode: ULONG | t.CPtr) -> BOOL | t.State: pass - -def SetConsoleMode(hConsoleHandle: HANDLE, dwMode: ULONG) -> BOOL | t.State: pass - -def ReadConsoleInputA(hConsoleInput: HANDLE, lpBuffer: INPUT_RECORD | t.CPtr, nLength: ULONG, lpNumberOfEventsRead: ULONG | t.CPtr) -> BOOL | t.State: pass - -def ReadConsoleInputW(hConsoleInput: HANDLE, lpBuffer: INPUT_RECORD | t.CPtr, nLength: ULONG, lpNumberOfEventsRead: ULONG | t.CPtr) -> BOOL | t.State: pass - -def GetNumberOfConsoleInputEvents(hConsoleInput: HANDLE, lpNumberOfEvents: ULONG | t.CPtr) -> BOOL | t.State: pass - -def FlushConsoleInputBuffer(hConsoleInput: HANDLE) -> BOOL | t.State: pass - -def SetConsoleTitleA(lpConsoleTitle: LPCSTR) -> BOOL | t.State: pass - -def SetConsoleTitleW(lpConsoleTitle: LPCWSTR) -> BOOL | t.State: pass - -def GetConsoleTitleA(lpConsoleTitle: CHARPTR, nSize: ULONG) -> ULONG | t.State: pass - -def GetConsoleTitleW(lpConsoleTitle: WCHARPTR, nSize: ULONG) -> ULONG | t.State: pass - -def AllocConsole() -> BOOL | t.State: pass - -def FreeConsole() -> BOOL | t.State: pass - -def SetConsoleWindowInfo(hConsoleOutput: HANDLE, bAbsolute: BOOL, lpConsoleWindow: SMALL_RECT | t.CPtr) -> BOOL | t.State: pass - -def ScrollConsoleScreenBufferA(hConsoleOutput: HANDLE, lpScrollRectangle: SMALL_RECT | t.CPtr, lpClipRectangle: SMALL_RECT | t.CPtr, dwDestinationOrigin: COORD, lpFill: CHAR_INFO | t.CPtr) -> BOOL | t.State: pass diff --git a/Test/TestFBProject/temp/fa3691e66b426950.pyi b/Test/TestFBProject/temp/fa3691e66b426950.pyi new file mode 100644 index 0000000..48fd36c --- /dev/null +++ b/Test/TestFBProject/temp/fa3691e66b426950.pyi @@ -0,0 +1,80 @@ +""" +Auto-generated Python stub file from w32.fileio.py +Module: w32.fileio +""" + + +import t, c +from stdint import * +import w32.win32base +import w32.win32file + +class MODE(t.CEnum): + R = 0 + W = 1 + A = 2 + RP = 3 + WP = 4 + AP = 5 + X = 6 + XP = 7 +class FRESULT(t.CEnum): + OK = 0 + ERR = -1 + ERR_CLOSED = -2 + ERR_PERM = -3 + ERR_IO = -4 + ERR_NOTFOUND = -5 + +SEEK_SET: t.CDefine = 0 +SEEK_CUR: t.CDefine = 1 +SEEK_END: t.CDefine = 2 +INVALID_SET_FILE_POINTER: t.CDefine = -1 +SHARE_READ: t.CDefine = 0x00000001 +SHARE_WRITE: t.CDefine = 0x00000002 +SHARE_DELETE: t.CDefine = 0x00000004 + +class File: + handle: w32.win32base.HANDLE + closed: bool + can_read: bool + can_write: bool + is_append: bool + _share_mode: ULONG + def __init__(self: File, filename: str, mode: ULONG, share: ULONG) -> t.CInt: pass + def __enter__(self: File) -> 'File' | t.CPtr: pass + def __exit__(self: File) -> t.CInt: pass + def read(self: File, buf: bytes, count: ULONG) -> LONG: pass + def write(self: File, buf: bytes, count: ULONG) -> LONG: pass + def write_str(self: File, s: str) -> LONG: pass + def seek(self: File, offset: LONG, origin: ULONG) -> LONG: pass + def tell(self: File) -> LONG: pass + def close(self: File) -> LONG: pass + def flush(self: File) -> LONG: pass + def size(self: File) -> LONGLONG: pass + def readline(self: File, buf: bytes, max_count: ULONG) -> LONG: pass + def read_all(self: File, buf: bytes, max_count: ULONG) -> LONG: pass +class FileW: + handle: HANDLE + closed: bool + can_read: bool + can_write: bool + is_append: bool + _share_mode: ULONG + def __init__(self: FileW, filename: LPCWSTR, mode: ULONG, share: ULONG) -> t.CInt: pass + def __enter__(self: FileW) -> 'FileW' | t.CPtr: pass + def __exit__(self: FileW) -> t.CInt: pass + def read(self: FileW, buf: bytes, count: ULONG) -> LONG: pass + def write(self: FileW, buf: bytes, count: ULONG) -> LONG: pass + def write_str(self: FileW, s: str) -> LONG: pass + def seek(self: FileW, offset: LONG, origin: ULONG) -> LONG: pass + def tell(self: FileW) -> LONG: pass + def close(self: FileW) -> LONG: pass + def flush(self: FileW) -> LONG: pass + def size(self: FileW) -> LONGLONG: pass + def readline(self: FileW, buf: bytes, max_count: ULONG) -> LONG: pass + def read_all(self: FileW, buf: bytes, max_count: ULONG) -> LONG: pass + +def open(filename: str, mode: ULONG, share: ULONG) -> File | t.CPtr: pass + +def openw(filename: LPCWSTR, mode: ULONG, share: ULONG) -> FileW | t.CPtr: pass diff --git a/Test/TestProject/App/__zlib/__init__.py b/Test/TestProject/App/__zlib/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/Test/TestProject/App/__zlib/pyzlib.py b/Test/TestProject/App/__zlib/pyzlib.py deleted file mode 100644 index 78bc227..0000000 --- a/Test/TestProject/App/__zlib/pyzlib.py +++ /dev/null @@ -1,550 +0,0 @@ -from stdint import * -import zdeflate -import zinflate -import zchecksum -import zdef -import zhuff -import stdlib -import string -import stdio -import t, c - - -# ============================================================ -# Constants - matching Python zlib module names and values -# ============================================================ - -# Compression levels -Z_NO_COMPRESSION: t.CDefine = 0 -Z_BEST_SPEED: t.CDefine = 1 -Z_BEST_COMPRESSION: t.CDefine = 9 -Z_DEFAULT_COMPRESSION: t.CDefine = (-1) - -# Compression methods -DEFLATED: t.CDefine = 8 - -# Flush modes -Z_NO_FLUSH: t.CDefine = 0 -Z_PARTIAL_FLUSH: t.CDefine = 1 -Z_SYNC_FLUSH: t.CDefine = 2 -Z_FULL_FLUSH: t.CDefine = 3 -Z_FINISH: t.CDefine = 4 -Z_BLOCK: t.CDefine = 5 -Z_TREES: t.CDefine = 6 - -# Strategies -Z_DEFAULT_STRATEGY: t.CDefine = 0 -Z_FILTERED: t.CDefine = 1 -Z_HUFFMAN_ONLY: t.CDefine = 2 -Z_RLE: t.CDefine = 3 -Z_FIXED: t.CDefine = 4 - -# Return codes -Z_OK: t.CDefine = 0 -Z_STREAM_END: t.CDefine = 1 -Z_NEED_DICT: t.CDefine = 2 -Z_ERRNO: t.CDefine = (-1) -Z_STREAM_ERROR: t.CDefine = (-2) -Z_DATA_ERROR: t.CDefine = (-3) -Z_MEM_ERROR: t.CDefine = (-4) -Z_BUF_ERROR: t.CDefine = (-5) -Z_VERSION_ERROR: t.CDefine = (-6) - -# Window / Buffer constants -MAX_WBITS: t.CDefine = 15 -DEF_BUF_SIZE: t.CDefine = 16384 -DEF_MEM_LEVEL: t.CDefine = 8 - -# Version -ZLIB_VERSION: t.CDefine = "1.3.2" - -pyzlib_error_msg: list[t.CChar, 512] = "" -pyzlib_error_code_val: t.CInt = 0 - -# ============================================================ -# Structures -# ============================================================ -@t.Object -class Compress: - stream: VOIDPTR - is_initialized: t.CInt - is_finished: t.CInt - level: t.CInt - method: t.CInt - wbits: t.CInt - memLevel: t.CInt - strategy: t.CInt - zdict: BYTEPTR - zdict_len: t.CSizeT - last_pos: t.CSizeT - input_buf: BYTEPTR - input_buf_len: t.CSizeT - input_buf_cap: t.CSizeT - header_written: t.CInt - - def compress(self, - data: BYTEPTR, data_len: t.CSizeT, - out_len: t.CSizeT | t.CPtr) -> BYTEPTR: - if not self.is_initialized: - set_error(Z_STREAM_ERROR, "compress object not initialized") - return None - if self.is_finished: - set_error(Z_STREAM_ERROR, "compress object already finished") - return None - if not out_len: - set_error(Z_STREAM_ERROR, "out_len is None") - return None - if data_len == 0: - c.Set(c.Deref(out_len), 0) - return BYTEPTR(calloc(1, 1)) - while self.input_buf_len + data_len > self.input_buf_cap: - self.input_buf_cap *= 2 - new_buf: BYTEPTR = BYTEPTR(realloc(self.input_buf, self.input_buf_cap)) - if not new_buf: - set_error(Z_MEM_ERROR, "out of memory") - c.Set(c.Deref(out_len), 0) - return BYTEPTR(calloc(1, 1)) - self.input_buf = new_buf - memcpy(self.input_buf + self.input_buf_len, data, data_len) - self.input_buf_len += data_len - c.Set(c.Deref(out_len), 0) - return BYTEPTR(calloc(1, 1)) - - def flush(self, mode: t.CInt, out_len: t.CSizeT | t.CPtr) -> BYTEPTR: - if not self.is_initialized: - set_error(Z_STREAM_ERROR, "compress object not initialized") - return None - if not out_len: - set_error(Z_STREAM_ERROR, "out_len is None") - return None - s: zdeflate.zdeflate_stream | t.CPtr = self.stream # 隐式类型转换 - if mode == Z_FINISH: - if not self.header_written: - self.header_written = 1 - input_data: BYTEPTR = self.input_buf - input_len: t.CSizeT = self.input_buf_len - if input_len == 0: - s.writer.write_bits(1, 1) - s.writer.write_bits(1, 2) - lit_tree = zhuff.zhuff_tree() - lit_tree.build_fixed_lit_tree() - lit_tree.encode_symbol(256, c.Addr(s.writer)) - else: - s.adler = zchecksum.zchecksum_adler32(input_data, input_len, 1) - s.compress_block(input_data, input_len, 1) - s.is_finished = 1 - if s.wbits >= 0: - s.writer.align() - adler: t.CUInt32T = s.adler - s.writer.buf[s.writer.byte_pos + 0] = (adler >> 24) & 0xFF - s.writer.buf[s.writer.byte_pos + 1] = (adler >> 16) & 0xFF - s.writer.buf[s.writer.byte_pos + 2] = (adler >> 8) & 0xFF - s.writer.buf[s.writer.byte_pos + 3] = (adler >> 0) & 0xFF - s.writer.byte_pos += 4 - self.is_finished = 1 - total: t.CSizeT = s.writer.total() - result: BYTEPTR = BYTEPTR(malloc(total)) - if result: memcpy(result, s.writer.buf, total) - c.Set(c.Deref(out_len), total) - free(self.input_buf) - self.input_buf = None - self.input_buf_len = 0 - self.input_buf_cap = 0 - return result - elif mode == Z_SYNC_FLUSH or mode == Z_FULL_FLUSH: - input_data: BYTEPTR = self.input_buf - input_len: t.CSizeT = self.input_buf_len - if input_len > 0: - s.adler = zchecksum.zchecksum_adler32(input_data, input_len, s.adler) - s.compress_block(input_data, input_len, 0) - self.input_buf_len = 0 - s.writer.write_bits(0, 1) - s.writer.write_bits(0, 2) - s.writer.align() - prev_pos: t.CSizeT = self.last_pos - total: t.CSizeT = s.writer.total() - delta: t.CSizeT = total - prev_pos - self.last_pos = s.writer.byte_pos - if delta == 0: - c.Set(c.Deref(out_len), 0) - return BYTEPTR(calloc(1, 1)) - - result: BYTEPTR = BYTEPTR(malloc(delta)) - if result: memcpy(result, s.writer.buf + prev_pos, delta) - c.Set(c.Deref(out_len), delta) - return result - c.Set(c.Deref(out_len), 0) - return BYTEPTR(calloc(1, 1)) - - def copy(self) -> Compress | t.CPtr: - if not self.is_initialized: - set_error(Z_STREAM_ERROR, "compress object not initialized") - return None - copy_obj: Compress | t.CPtr = calloc(1, Compress.__sizeof__()) - if not copy_obj: - set_error(Z_MEM_ERROR, "out of memory") - return None - s: zdeflate.zdeflate_stream | t.CPtr = self.stream # 隐式类型转换 - copy_obj.stream = s.copy() - if not copy_obj.stream: - free(copy_obj) - set_error(Z_MEM_ERROR, "out of memory") - return None - copy_obj.is_initialized = 1 - copy_obj.is_finished = self.is_finished - copy_obj.level = self.level - copy_obj.method = self.method - copy_obj.wbits = self.wbits - copy_obj.memLevel = self.memLevel - copy_obj.strategy = self.strategy - copy_obj.last_pos = self.last_pos - copy_obj.header_written = self.header_written - if self.input_buf and self.input_buf_len > 0: - copy_obj.input_buf = BYTEPTR(calloc(1, self.input_buf_cap)) - if copy_obj.input_buf: - memcpy(copy_obj.input_buf, self.input_buf, self.input_buf_len) - copy_obj.input_buf_cap = self.input_buf_cap - copy_obj.input_buf_len = self.input_buf_len - else: - copy_obj.input_buf = BYTEPTR(calloc(1, 256)) - copy_obj.input_buf_cap = 256 - copy_obj.input_buf_len = 0 - if self.zdict and self.zdict_len > 0: - copy_obj.zdict = clone_bytes(self.zdict, self.zdict_len) - copy_obj.zdict_len = self.zdict_len - return copy_obj - - def delete(self): - if self.is_initialized and self.stream: - s: zdeflate.zdeflate_stream | t.CPtr = self.stream # 隐式类型转换 - s.destroy() - free(self.zdict) - free(self.input_buf) - free(self) - - def __del__(self): - self.delete() - - -@t.Object -class Decompress: - stream: VOIDPTR - is_initialized: t.CInt - eof: t.CInt - wbits: t.CInt - zdict: BYTEPTR - zdict_len: t.CSizeT - _unused_data: BYTEPTR - _unused_data_len: t.CSizeT - _unused_data_cap: t.CSizeT - _unconsumed_tail: BYTEPTR - _unconsumed_tail_len: t.CSizeT - _unconsumed_tail_cap: t.CSizeT - input_buf: BYTEPTR - input_buf_len: t.CSizeT - input_buf_cap: t.CSizeT - - def decompress(self, data: BYTEPTR, data_len: t.CSizeT, - max_length: t.CSizeT, out_len: t.CSizeT | t.CPtr) -> BYTEPTR: - if not self.is_initialized: - set_error(Z_STREAM_ERROR, "decompress object not initialized") - return None - if not out_len: - set_error(Z_STREAM_ERROR, "out_len is None") - return None - if self.eof: - if data and data_len > 0: - append_bytes(c.Addr(self._unused_data), c.Addr(self._unused_data_len), - c.Addr(self._unused_data_cap), data, data_len) - c.Set(c.Deref(out_len), 0) - return BYTEPTR(calloc(1, 1)) - self._unconsumed_tail_len = 0 - if data and data_len > 0: - append_bytes(c.Addr(self.input_buf), c.Addr(self.input_buf_len), - c.Addr(self.input_buf_cap), data, data_len) - if self.input_buf_len == 0: - c.Set(c.Deref(out_len), 0) - return BYTEPTR(calloc(1, 1)) - s: zinflate.zinflate_stream | t.CPtr = zinflate.zinflate_create(self.wbits) - if not s: - set_error(Z_MEM_ERROR, "out of memory") - return None - if self.zdict and self.zdict_len > 0: - s.set_dictionary(self.zdict, self.zdict_len) - out: t.CUInt8T | t.CPtr = None - err: t.CInt = s.decompress(self.input_buf, self.input_buf_len, - max_length, c.Addr(out), out_len) - if err != 0: - s.destroy() - set_error(Z_DATA_ERROR, "decompression failed") - return None - if s.is_finished: - self.eof = 1 - if s.input_pos < s.input_len: - append_bytes(c.Addr(self._unused_data), c.Addr(self._unused_data_len), - c.Addr(self._unused_data_cap), - s.input_data + s.input_pos, - s.input_len - s.input_pos) - self.input_buf_len = 0 - else: - consumed: t.CSizeT = s.input_pos - if consumed < self.input_buf_len: - remaining: t.CSizeT = self.input_buf_len - consumed - memmove(self.input_buf, self.input_buf + consumed, remaining) - self.input_buf_len = remaining - else: - self.input_buf_len = 0 - s.destroy() - return out - - def flush(self, length: t.CSizeT, out_len: t.CSizeT | t.CPtr) -> BYTEPTR: - if not self.is_initialized: - set_error(Z_STREAM_ERROR, "decompress object not initialized") - return None - if not out_len: - set_error(Z_STREAM_ERROR, "out_len is None") - return None - c.Set(c.Deref(out_len), 0) - return BYTEPTR(calloc(1, 1)) - - def copy(self) -> Decompress | t.CPtr: - if not self.is_initialized: - set_error(Z_STREAM_ERROR, "decompress object not initialized") - return None - copy_obj: Decompress | t.CPtr = calloc(1, Decompress.__sizeof__()) - if not copy_obj: - set_error(Z_MEM_ERROR, "out of memory") - return None - copy_obj.is_initialized = 1 - copy_obj.eof = self.eof - copy_obj.wbits = self.wbits - if self.zdict and self.zdict_len > 0: - copy_obj.zdict = clone_bytes(self.zdict, self.zdict_len) - copy_obj.zdict_len = self.zdict_len - if self._unused_data and self._unused_data_len > 0: - copy_obj._unused_data = clone_bytes(self._unused_data, self._unused_data_len) - copy_obj._unused_data_len = self._unused_data_len - copy_obj._unused_data_cap = self._unused_data_len - if self._unconsumed_tail and self._unconsumed_tail_len > 0: - copy_obj._unconsumed_tail = clone_bytes(self._unconsumed_tail, self._unconsumed_tail_len) - copy_obj._unconsumed_tail_len = self._unconsumed_tail_len - copy_obj._unconsumed_tail_cap = self._unconsumed_tail_len - if self.input_buf and self.input_buf_len > 0: - copy_obj.input_buf = clone_bytes(self.input_buf, self.input_buf_len) - copy_obj.input_buf_len = self.input_buf_len - copy_obj.input_buf_cap = self.input_buf_cap - else: - copy_obj.input_buf = BYTEPTR(calloc(1, 256)) - copy_obj.input_buf_cap = 256 - copy_obj.input_buf_len = 0 - return copy_obj - - def delete(self): - free(self.zdict) - free(self._unused_data) - free(self._unconsumed_tail) - free(self.input_buf) - free(self) - - def unused_data(self, length: t.CSizeT | t.CPtr) -> BYTEPTR: - #if not self: - # if length: - # c.Set(c.Deref(length), 0) - # return None - if length: - c.Set(c.Deref(length), self._unused_data_len) - return self._unused_data - - def unconsumed_tail(self, length: t.CSizeT | t.CPtr) -> BYTEPTR: - #if not self: - # if length: - # c.Set(c.Deref(length), 0) - # return None - if length: - c.Set(c.Deref(length), self._unconsumed_tail_len) - return self._unconsumed_tail - -# def eof(self) -> t.CInt: -# # if not obj: return 0 -# return self.eof - - - -def set_error(code: int, msg: str): - global pyzlib_error_code_val, pyzlib_error_msg - pyzlib_error_code_val = code - if msg: - strncpy(pyzlib_error_msg, msg, pyzlib_error_msg.__sizeof__() - 1) - pyzlib_error_msg[pyzlib_error_msg.__sizeof__() - 1] = '\0' - else: - pyzlib_error_msg[0] = '\0' - -def clone_bytes(src: BYTEPTR, length: t.CSizeT) -> BYTEPTR: - if not src or length == 0: return None - dst: BYTEPTR = BYTEPTR(malloc(length)) - if dst: memcpy(dst, src, length) - return dst - -def append_bytes(buf: BYTE | t.CPtr[t.CPtr], length: t.CSizeT | t.CPtr, cap: t.CSizeT | t.CPtr, - data: BYTEPTR, data_len: t.CSizeT) -> t.CInt: - if not data or data_len == 0: return 0 - needed: t.CSizeT = c.Deref(length) + data_len - if needed > c.Deref(cap): - new_cap: t.CSizeT = c.Deref(cap) * 2 - if new_cap < needed: new_cap = needed - new_buf: BYTEPTR = BYTEPTR(realloc(c.Deref(buf), new_cap)) - if not new_buf: return -1 - c.Set(c.Deref(buf), new_buf) - c.Set(c.Deref(cap), new_cap) - memcpy(c.Deref(buf) + c.Deref(length), data, data_len) - c.Set(c.Deref(length), c.Deref(length) + data_len) - return 0 - - -def shrink_to_fit(buf: BYTEPTR, length: t.CSizeT) -> BYTEPTR: - if length == 0: - free(buf) - return BYTEPTR(calloc(1, 1)) - result: BYTEPTR = BYTEPTR(realloc(buf, length)) - return result if result else buf - - -def runtime_version() -> str: - return ZLIB_VERSION - -def get_error() -> str: - return pyzlib_error_msg - -def get_error_code() -> t.CInt: - return pyzlib_error_code_val - -def clear_error(): - global pyzlib_error_msg, pyzlib_error_code_val - pyzlib_error_msg[0] = '\0' - pyzlib_error_code_val = 0 - -def compress(data: BYTEPTR, data_len: t.CSizeT, - level: t.CInt, wbits: t.CInt, out_len: t.CSizeT | t.CPtr) -> BYTEPTR: - if not data and data_len > 0: - set_error(Z_STREAM_ERROR, "data is None but data_len > 0") - return None - if not out_len: - set_error(Z_STREAM_ERROR, "out_len is None") - return None - actual_wbits: t.CInt = wbits - if wbits > MAX_WBITS: - actual_wbits = -MAX_WBITS - raw_result: UINT8PTR = zdeflate.zdeflate_one_shot(data, data_len, level, actual_wbits, out_len) - if not raw_result: - set_error(Z_DATA_ERROR, "compression failed") - return None - if wbits > MAX_WBITS: - gzip_len: t.CSizeT = 10 + c.Deref(out_len) + 8 - gzip_buf: BYTEPTR = BYTEPTR(malloc(gzip_len)) - if not gzip_buf: - free(raw_result) - set_error(Z_MEM_ERROR, "out of memory") - return None - pos: t.CSizeT = 0 - gzip_buf[pos + 0] = 0x1F - gzip_buf[pos + 1] = 0x8B - gzip_buf[pos + 2] = 0x08 - gzip_buf[pos + 3] = 0x00 - gzip_buf[pos + 4] = 0x00 - gzip_buf[pos + 5] = 0x00 - gzip_buf[pos + 6] = 0x00 - gzip_buf[pos + 7] = 0x00 - gzip_buf[pos + 8] = 0x00 - gzip_buf[pos + 9] = 0xFF - pos += 10 - - memcpy(gzip_buf + pos, raw_result, c.Deref(out_len)) - pos += c.Deref(out_len) - free(raw_result) - - crc: t.CUInt32T = zchecksum.zchecksum_crc32(data, data_len, 0) - gzip_buf[pos + 0] = (crc) & 0xFF - gzip_buf[pos + 1] = (crc >> 8) & 0xFF - gzip_buf[pos + 2] = (crc >> 16) & 0xFF - gzip_buf[pos + 3] = (crc >> 24) & 0xFF - gzip_buf[pos + 4] = (data_len) & 0xFF - gzip_buf[pos + 5] = (data_len >> 8) & 0xFF - gzip_buf[pos + 6] = (data_len >> 16) & 0xFF - gzip_buf[pos + 7] = (data_len >> 24) & 0xFF - pos += 8 - c.Set(c.Deref(out_len), pos) - return shrink_to_fit(gzip_buf, pos) - return shrink_to_fit(raw_result, c.Deref(out_len)) - - -def decompress(data: BYTEPTR, data_len: t.CSizeT, - wbits: t.CInt, bufsize: t.CSizeT, out_len: t.CSizeT | t.CPtr) -> BYTEPTR: - if not data and data_len > 0: - set_error(Z_STREAM_ERROR, "data is None but data_len > 0") - return None - if not out_len: - set_error(Z_STREAM_ERROR, "out_len is None") - return None - result: UINT8PTR = zinflate.zinflate_one_shot(data, data_len, wbits, bufsize, out_len) - if not result: - set_error(Z_DATA_ERROR, "decompression failed") - return None - return shrink_to_fit(result, c.Deref(out_len)) - -def compressobj(level: t.CInt, method: t.CInt, wbits: t.CInt, - memLevel: t.CInt, strategy: t.CInt, - zdict: BYTEPTR, zdict_len: t.CSizeT) -> Compress | t.CPtr: - obj: Compress | t.CPtr = calloc(1, Compress.__sizeof__()) - if not obj: - set_error(Z_MEM_ERROR, "out of memory") - return None - actual_wbits: t.CInt = wbits - if wbits > MAX_WBITS: actual_wbits = wbits - 16 - s: zdeflate.zdeflate_stream | t.CPtr = zdeflate.zdeflate_create(level, actual_wbits, memLevel, strategy) - if not s: - free(obj) - set_error(Z_MEM_ERROR, "out of memory") - return None - obj.stream = s - obj.is_initialized = 1 - obj.level = level - obj.method = method - obj.wbits = wbits - obj.memLevel = memLevel - obj.strategy = strategy - obj.input_buf = BYTEPTR(calloc(1, 256)) - obj.input_buf_cap = 256 - obj.input_buf_len = 0 - obj.header_written = 0 - if zdict and zdict_len > 0: - s.set_dictionary(zdict, zdict_len) - obj.zdict = clone_bytes(zdict, zdict_len) - obj.zdict_len = zdict_len - return obj - - -def decompressobj(wbits: t.CInt, zdict: BYTEPTR, zdict_len: t.CSizeT) -> Decompress | t.CPtr: - obj: Decompress | t.CPtr = calloc(1, Decompress.__sizeof__()) - if not obj: - set_error(Z_MEM_ERROR, "out of memory") - return None - actual_wbits: t.CInt = wbits - if wbits > MAX_WBITS: actual_wbits = wbits - 16 - obj.stream = None - obj.is_initialized = 1 - obj.wbits = actual_wbits - if zdict and zdict_len > 0: - obj.zdict = clone_bytes(zdict, zdict_len) - obj.zdict_len = zdict_len - obj.input_buf = BYTEPTR(calloc(1, 256)) - obj.input_buf_cap = 256 - obj.input_buf_len = 0 - return obj - -def zlib_adler32(data: BYTEPTR, length: t.CSizeT, value: t.CUnsignedLong) -> t.CUnsignedLong: - return zchecksum.zchecksum_adler32(data, length, UINT32(value)) - -def zlib_crc32(data: BYTEPTR, length: t.CSizeT, value: t.CUnsignedLong) -> t.CUnsignedLong: - return zchecksum.zchecksum_crc32(data, length, UINT32(value)) - - diff --git a/Test/TestProject/App/__zlib/test_basic.c b/Test/TestProject/App/__zlib/test_basic.c deleted file mode 100644 index efa089c..0000000 --- a/Test/TestProject/App/__zlib/test_basic.c +++ /dev/null @@ -1,81 +0,0 @@ -#include -#include -#include -#include -#include "pyzlib.h" - -int main(void) -{ - printf("=== Basic Self-Implemented zlib Test ===\n\n"); - - printf("1. Adler-32:\n"); - unsigned long a = zlib_adler32((const unsigned char *)"Hello", 5, 1); - printf(" adler32(\"Hello\") = 0x%08lX\n", a); - - unsigned long a2 = zlib_adler32((const unsigned char *)"Hel", 3, 1); - a2 = zlib_adler32((const unsigned char *)"lo", 2, a2); - printf(" incremental = 0x%08lX %s\n", a2, a == a2 ? "MATCH" : "MISMATCH"); - - printf("\n2. CRC-32:\n"); - unsigned long c = zlib_crc32((const unsigned char *)"Hello", 5, 0); - printf(" crc32(\"Hello\") = 0x%08lX\n", c); - - unsigned long c2 = zlib_crc32((const unsigned char *)"Hel", 3, 0); - c2 = zlib_crc32((const unsigned char *)"lo", 2, c2); - printf(" incremental = 0x%08lX %s\n", c2, c == c2 ? "MATCH" : "MISMATCH"); - - printf("\n3. Compress (zlib format):\n"); - const char *input = "Hello, World!"; - size_t comp_len = 0; - unsigned char *comp = zlib_compress((const unsigned char *)input, strlen(input), - Z_DEFAULT_COMPRESSION, MAX_WBITS, &comp_len); - if (comp) { - printf(" Input: %zu bytes\n", strlen(input)); - printf(" Output: %zu bytes\n", comp_len); - printf(" Hex: "); - for (size_t i = 0; i < comp_len && i < 40; i++) printf("%02X ", comp[i]); - printf("\n"); - - printf("\n4. Decompress (zlib format):\n"); - size_t dec_len = 0; - unsigned char *dec = zlib_decompress(comp, comp_len, MAX_WBITS, DEF_BUF_SIZE, &dec_len); - if (dec) { - printf(" Output: %zu bytes\n", dec_len); - printf(" Content: \"%.*s\"\n", (int)dec_len, (char *)dec); - printf(" Match: %s\n", dec_len == strlen(input) && memcmp(dec, input, dec_len) == 0 ? "YES" : "NO"); - free(dec); - } else { - printf(" FAILED! Error: %s (code %d)\n", zlib_get_error(), zlib_get_error_code()); - } - free(comp); - } else { - printf(" FAILED! Error: %s (code %d)\n", zlib_get_error(), zlib_get_error_code()); - } - - printf("\n5. Compress (raw deflate):\n"); - comp_len = 0; - comp = zlib_compress((const unsigned char *)input, strlen(input), - Z_DEFAULT_COMPRESSION, -MAX_WBITS, &comp_len); - if (comp) { - printf(" Output: %zu bytes\n", comp_len); - printf(" Hex: "); - for (size_t i = 0; i < comp_len && i < 40; i++) printf("%02X ", comp[i]); - printf("\n"); - - size_t dec_len = 0; - unsigned char *dec = zlib_decompress(comp, comp_len, -MAX_WBITS, DEF_BUF_SIZE, &dec_len); - if (dec) { - printf(" Decompress: \"%.*s\" %s\n", (int)dec_len, (char *)dec, - dec_len == strlen(input) && memcmp(dec, input, dec_len) == 0 ? "OK" : "FAIL"); - free(dec); - } else { - printf(" Decompress FAILED! Error: %s\n", zlib_get_error()); - } - free(comp); - } else { - printf(" FAILED! Error: %s (code %d)\n", zlib_get_error(), zlib_get_error_code()); - } - - printf("\nDone.\n"); - return 0; -} diff --git a/Test/TestProject/App/__zlib/test_debug.c b/Test/TestProject/App/__zlib/test_debug.c deleted file mode 100644 index 682eb28..0000000 --- a/Test/TestProject/App/__zlib/test_debug.c +++ /dev/null @@ -1,78 +0,0 @@ -#include -#include -#include -#include -#include "pyzlib.h" - -int main(void) -{ - printf("=== Full Self-Implemented zlib Test ===\n\n"); - - printf("1. Adler-32:\n"); - unsigned long a = zlib_adler32((const unsigned char *)"Hello", 5, 1); - printf(" adler32(\"Hello\") = 0x%08lX\n", a); - - printf("\n2. CRC-32:\n"); - unsigned long c = zlib_crc32((const unsigned char *)"Hello", 5, 0); - printf(" crc32(\"Hello\") = 0x%08lX\n", c); - - const char *tests[] = {"Hello", "Hello, World!", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", ""}; - int levels[] = {2, 6, 0}; - - for (int t = 0; t < 4; t++) { - const char *input = tests[t]; - size_t input_len = strlen(input); - printf("\n--- Test: \"%s\" (%zu bytes) ---\n", input_len > 0 ? input : "(empty)", input_len); - - for (int li = 0; li < 3; li++) { - int level = levels[li]; - printf("\n Level %d, zlib format:\n", level); - size_t comp_len = 0; - unsigned char *comp = zlib_compress((const unsigned char *)input, input_len, - level, MAX_WBITS, &comp_len); - if (comp) { - printf(" Compressed: %zu bytes\n", comp_len); - size_t dec_len = 0; - unsigned char *dec = zlib_decompress(comp, comp_len, MAX_WBITS, DEF_BUF_SIZE, &dec_len); - if (dec) { - int match = (dec_len == input_len && memcmp(dec, input, dec_len) == 0); - printf(" Decompressed: %zu bytes, Match: %s\n", dec_len, match ? "YES" : "NO"); - if (!match) { - printf(" Expected: \"%s\"\n", input_len > 0 ? input : "(empty)"); - printf(" Got: \"%.*s\"\n", (int)dec_len, (char *)dec); - } - free(dec); - } else { - printf(" Decompress FAILED: %s (code %d)\n", zlib_get_error(), zlib_get_error_code()); - } - free(comp); - } else { - printf(" Compress FAILED: %s (code %d)\n", zlib_get_error(), zlib_get_error_code()); - } - } - } - - printf("\n3. Raw deflate:\n"); - { - const char *input = "Raw deflate test"; - size_t comp_len = 0; - unsigned char *comp = zlib_compress((const unsigned char *)input, strlen(input), - Z_DEFAULT_COMPRESSION, -MAX_WBITS, &comp_len); - if (comp) { - printf(" Compressed: %zu bytes\n", comp_len); - size_t dec_len = 0; - unsigned char *dec = zlib_decompress(comp, comp_len, -MAX_WBITS, DEF_BUF_SIZE, &dec_len); - if (dec) { - printf(" Decompressed: \"%.*s\" %s\n", (int)dec_len, (char *)dec, - dec_len == strlen(input) && memcmp(dec, input, dec_len) == 0 ? "OK" : "FAIL"); - free(dec); - } else { - printf(" Decompress FAILED: %s\n", zlib_get_error()); - } - free(comp); - } - } - - printf("\nDone.\n"); - return 0; -} diff --git a/Test/TestProject/App/__zlib/test_pyzlib.py b/Test/TestProject/App/__zlib/test_pyzlib.py deleted file mode 100644 index 62ede4f..0000000 --- a/Test/TestProject/App/__zlib/test_pyzlib.py +++ /dev/null @@ -1,880 +0,0 @@ -from stdint import * -import pyzlib -import zhuff -import zdef -from stdio import printf, strlen -import stdlib -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(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(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 memcmp(decompressed, inp, input_length) == 0, "content mismatch") - - printf(" Decompressed (%zu bytes): \"%.*s\"\n", dec_length, t.CInt(dec_length), str(decompressed)) - - free(compressed) - 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(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 - free(c0) - - c1: BYTEPTR = pyzlib.compress(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) - free(c1) - - c6: BYTEPTR = pyzlib.compress(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) - free(c6) - - c9: BYTEPTR = pyzlib.compress(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 - 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(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(malloc(total)) - if all: memcpy(all, c1, out_length) - 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(realloc(all, total + out_length)) - if new_all: - all = new_all - memcpy(all + total, c2, out_length) - total += out_length - 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 = realloc(all, total + out_length) # 隐式转换 - if new_all: - all = new_all - memcpy(all + total, c3, out_length) - total += out_length - free(c3) - - print_separator() - - if all: - dec_length: t.CSizeT = 0 - dec: BYTEPTR = pyzlib.decompress(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 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) - free(dec) - 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(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(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 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) - - free(dec) - free(compressed) - d.delete() - section_footer() - -def test_decompressobj_max_lengthgth(): - section_header("decompressobj max_lengthgth") - - inp: str = "This is a longer string for testing max_lengthgth 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(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(pyzlib.MAX_WBITS, None, 0) - - dec_length: t.CSizeT = 0 - dec: BYTEPTR = d.decompress(compressed, out_length, - 10, c.Addr(dec_length)) - check("max_lengthgth decompress OK", dec != None, "decompress returned None") - check("max_lengthgth limits output", dec_length <= 10, "output exceeded max_lengthgth") - if dec: - printf(" First chunk (max_lengthgth=10): \"%.*s\" (%zu bytes)\n", t.CInt(dec_length), str(dec), dec_length) - 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_lengthgth OK", flushed != None, "flush returned None") - if flushed: printf(" Flushed (%zu bytes): \"%.*s\"\n", dec_length, t.CInt(dec_length), str(flushed)) - free(flushed) - - printf(" eof after flush = %d\n", d.eof) - - d.delete() - 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(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(malloc(total_length)) - memcpy(combined, compressed, out_length) - memcpy(combined + out_length, "EXTRA", 5) - free(compressed) - printf(" Combined (compressed + \"EXTRA\"): %zu bytes\n", total_length) - - d: pyzlib.Decompress | t.CPtr = pyzlib.decompressobj(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) - 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 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() - 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(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) - 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) - 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(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(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 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) - - free(dec1) - free(dec2) - 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", incremental == "YES" if 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", incremental == "YES" if checksum else "NO") - - section_footer() - - -def test_empty_compress(): - section_header("Empty data compress/decompress") - - out_length: t.CSizeT = 0 - compressed: BYTEPTR = pyzlib.compress(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(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) - - free(compressed) - 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(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(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 memcmp(decompressed, inp, input_length) == 0, "content mismatch") - if decompressed: printf(" Decompressed: \"%.*s\" (%zu bytes)\n", t.CInt(dec_length), str(decompressed), dec_length) - - free(compressed) - 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(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(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 memcmp(decompressed, inp, input_length) == 0, "content mismatch") - if decompressed: printf(" Decompressed: \"%.*s\" (%zu bytes)\n", t.CInt(dec_length), str(decompressed), dec_length) - - free(compressed) - 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(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) - 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) - free(flush_data) - - print_separator() - - total_comp: t.CSizeT = out_length - s.delete() - - s = pyzlib.compressobj(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) - free(comp_no_dict) - 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") - freqs: list[t.CInt, 256] - memset(freqs, 0, freqs.__sizeof__()) - freqs['A'] = 50 - freqs['B'] = 25 - freqs['C'] = 12 - freqs['D'] = 6 - freqs['E'] = 3 - freqs['F'] = 1 - freqs[256] = 1 - - dyn_tree = zhuff.zhuff_tree() - dyn_tree.build_codes(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: list[str, None] = ["A","B","C","D","E","F"] # 一个都æ˜?char* 的数ç»? - syms: list[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], 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") - freqs: list[t.CInt, 288] - memset(freqs, 0, freqs.__sizeof__()) - freqs['H'] = 10 - freqs['e'] = 8 - freqs['l'] = 20 - freqs['o'] = 8 - freqs[' '] = 5 - freqs['W'] = 3 - freqs['r'] = 5 - freqs['d'] = 3 - freqs['!'] = 2 - freqs[256] = 1 - - enc_tree = zhuff.zhuff_tree() - enc_tree.build_codes(freqs, 257, 15) - - dec_tree = zhuff.zhuff_decode_tree() - dec_tree.build_decode_tree(c.Addr(enc_tree)) - - writer = zdef.zbit_writer() - - symbols: list[t.CInt, 16] - symbols[0] = 'H'; symbols[1] = 'e'; symbols[2] = 'l'; symbols[3] = 'l' - symbols[4] = 'o'; symbols[5] = ' '; symbols[6] = 'W'; symbols[7] = 'o' - symbols[8] = 'r'; symbols[9] = 'l'; symbols[10] = 'd'; symbols[11] = '!' - symbols[12] = 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)) - - free(writer.buf) - - printf("\n --- Overflow handling (many symbols, limited max_bits) ---\n") - freqs: list[t.CInt, 256] - for i in range(256): - freqs[i] = 1 - freqs[256] = 1 - - tree = zhuff.zhuff_tree() - tree.build_codes(freqs, 257, 15) - - overflow_ok: t.CInt = 1 - for i in range(257): - if tree.codes[i].bits > 15 or tree.codes[i].bits < 0: - overflow_ok = 0 - break - check("all code lengthgths <= 15 with 257 symbols", overflow_ok, "code lengthgth overflow") - - bl_count: list[t.CInt, 16] = [0] - for i in range(257): - if tree.codes[i].bits > 0: - bl_count[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(tree)) - - w = zdef.zbit_writer() - tree.encode_symbol(0, c.Addr(w)) - tree.encode_symbol(128, c.Addr(w)) - tree.encode_symbol(255, c.Addr(w)) - 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") - - free(w.buf) - - - printf("\n --- Kraft inequality check ---\n") - freqs: list[t.CInt, 256] - memset(freqs, 0, freqs.__sizeof__()) - freqs['X'] = 100 - freqs['Y'] = 50 - freqs['Z'] = 25 - freqs[256] = 1 - - tree = zhuff.zhuff_tree() - tree.build_codes(freqs, 257, 15) - - kraft_sum: t.CDouble = 0.0 - for i in range(257): - if tree.codes[i].bits > 0: - kraft_sum += 1.0 / (t.CDouble(ULONGLONG(1) << 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(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_lengthgth() - test_decompressobj_unused_data() - test_compress_copy() - test_decompress_copy() - test_adler32() - test_crc32() - test_empty_compress() - test_gzip_format() - test_raw_deflate() - test_zdict() - test_huffman_tree() - 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/Test/TestProject/App/__zlib/zchecksum.py b/Test/TestProject/App/__zlib/zchecksum.py deleted file mode 100644 index 422bd5e..0000000 --- a/Test/TestProject/App/__zlib/zchecksum.py +++ /dev/null @@ -1,90 +0,0 @@ -from stdint import * -import t, c - - -def zchecksum_adler32(data: UINT8PTR, length: t.CSizeT, init: UINT32) -> t.CUInt32T: - a: t.CUInt32T = (init >> 0) & 0xFFFF - b: t.CUInt32T = (init >> 16) & 0xFFFF - if not data or length == 0: - return init - i: t.CSizeT - for i in range(length): - a = (a + data[i]) % 65521 - b = (b + a) % 65521 - return (b << 16) | a - -crc32_table: list[t.CUInt32T, 256] = [ - 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, - 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, - 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, - 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, - 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, - 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, - 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, - 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, - 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, - 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, - 0x35B5A8FA, 0x42B2986C, 0xDBBBBBD6, 0xACBCCB40, - 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, - 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, - 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, - 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, - 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, - 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, - 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, - 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, - 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, - 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, - 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, - 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, - 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, - 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, - 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, - 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, - 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7D49, - 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, - 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, - 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, - 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, - 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, - 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, - 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, - 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, - 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, - 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, - 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, - 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, - 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, - 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, - 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, - 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, - 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, - 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, - 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, - 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, - 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, - 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, - 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, - 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, - 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, - 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, - 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, - 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, - 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, - 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, - 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, - 0xA9BCAE53, 0xDede9EC5, 0x47D7897F, 0x30D0B8E9, - 0xBDDA8B1C, 0xCADD8B8A, 0x53D3903A, 0x24D4C2AC, - 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, - 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, - 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D -] - -def zchecksum_crc32(data: UINT8PTR, length: t.CSizeT, init: t.CUInt32T) -> t.CUInt32T: - crc: t.CUInt32T = init ^ 0xFFFFFFFF - if not data or length == 0: return init - i: t.CSizeT - for i in range(length): - crc = crc32_table[(crc ^ data[i]) & 0xFF] ^ (crc >> 8) - return crc ^ 0xFFFFFFFF - diff --git a/Test/TestProject/App/__zlib/zdef.py b/Test/TestProject/App/__zlib/zdef.py deleted file mode 100644 index 4f1918c..0000000 --- a/Test/TestProject/App/__zlib/zdef.py +++ /dev/null @@ -1,269 +0,0 @@ -from stdint import * -import stddef -import string -import stdlib -import t, c - - -# ============================================================ -# DEFLATE / zlib constants -# ============================================================ -ZDEFLATE_WINDOW_BITS: t.CDefine = 15 -ZDEFLATE_WINDOW_SIZE: t.CDefine = (1 << ZDEFLATE_WINDOW_BITS) -ZDEFLATE_WINDOW_MASK: t.CDefine = (ZDEFLATE_WINDOW_SIZE - 1) - -ZDEFLATE_MIN_MATCH: t.CDefine = 3 -ZDEFLATE_MAX_MATCH: t.CDefine = 258 - -ZDEFLATE_HASH_BITS: t.CDefine = 15 -ZDEFLATE_HASH_SIZE: t.CDefine = (1 << ZDEFLATE_HASH_BITS) -ZDEFLATE_HASH_MASK: t.CDefine = (ZDEFLATE_HASH_SIZE - 1) - -ZDEFLATE_MAX_CODES: t.CDefine = 288 -ZDEFLATE_MAX_DIST_CODES: t.CDefine = 32 -ZDEFLATE_MAX_BITS: t.CDefine = 15 -ZDEFLATE_MAX_CODELEN_CODES: t.CDefine = 19 - -ZDEFLATE_LIT_COUNT: t.CDefine = 286 -ZDEFLATE_DIST_COUNT: t.CDefine = 30 - -ZDEFLATE_LEN_SYMBOLS_BASE: t.CDefine = 257 -ZDEFLATE_END_OF_BLOCK: t.CDefine = 256 - -# ============================================================ -# Length / Distance extra bits tables (RFC 1951) -# ============================================================ -zdeflate_len_extra_bits: list[t.CInt, 29] = [ - 0, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, - 2, 2, 2, 2, - 3, 3, 3, 3, - 4, 4, 4, 4, - 5, 5, 5, 5, - 0 -] - -zdeflate_len_base: list[t.CInt, 29] = [ - 3, 4, 5, 6, 7, 8, 9, 10, - 11, 13, 15, 17, - 19, 23, 27, 31, - 35, 43, 51, 59, - 67, 83, 99, 115, - 131, 163, 195, 227, - 258 -] - -zdeflate_dist_extra_bits: list[t.CInt, 30] = [ - 0, 0, 0, 0, - 1, 1, - 2, 2, - 3, 3, - 4, 4, - 5, 5, - 6, 6, - 7, 7, - 8, 8, - 9, 9, - 10, 10, - 11, 11, - 12, 12, - 13, 13 -] - -zdeflate_dist_base: list[t.CInt, 30] = [ - 1, 2, 3, 4, - 5, 7, - 9, 13, - 17, 25, - 33, 49, - 65, 97, - 129, 193, - 257, 385, - 513, 769, - 1025, 1537, - 2049, 3073, - 4097, 6145, - 8193, 12289, - 16385, 24577 -] - -zdeflate_codelen_order: list[int, 19] = [ - 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 -] - -# ============================================================ -# Bit writer - writes bits LSB first into a byte buffer -# ============================================================ -@t.Object -class zbit_writer: - buf: BYTE | t.CPtr - cap: t.CSizeT - byte_pos: t.CSizeT - bit_pos: t.CInt - - def __init__(self): - self.cap = 4096 - self.buf = BYTEPTR(malloc(self.cap)) - memset(self.buf, 0, self.cap) - self.byte_pos = 0 - self.bit_pos = 0 - - def ensure(self, need: t.CSizeT): - while self.byte_pos + need + 4 >= self.cap: - new_cap: t.CSizeT = self.cap * 2 - new_buf: BYTE | t.CPtr = BYTEPTR(realloc(self.buf, new_cap)) - if not new_buf: return - memset(new_buf + self.cap, 0, new_cap - self.cap) - self.buf = new_buf - self.cap = new_cap - - def write_bits(self, value: UINT, nbits: t.CInt): - self.ensure((nbits + 7) / 8 + 1) - for i in range(nbits): - if value & (UINT(1) << i): - self.buf[self.byte_pos] |= (UINT(1) << self.bit_pos) - self.bit_pos += 1 - if self.bit_pos == 8: - self.bit_pos = 0 - self.byte_pos += 1 - - def write_bits_rev(self, code: UINT, nbits: t.CInt): - self.ensure((nbits + 7) / 8 + 1) - for i in range(nbits - 1, -1, -1): - if code & (UINT(1) << i): - self.buf[self.byte_pos] |= (UINT(1) << self.bit_pos) - self.bit_pos += 1 - if self.bit_pos == 8: - self.bit_pos = 0 - self.byte_pos += 1 - - def stored_block(self, data: UINT8PTR, length: t.CSizeT, final: t.CInt): - self.write_bits(1 if final else 0, 1) - self.write_bits(0, 2) - self.align() - - pos: t.CSizeT = 0 - while pos < length: - block_length: t.CSizeT = length - pos - if block_length > 65535: - block_length = 65535 - n: t.CUInt16T = t.CUInt16T(block_length) - ncomp: t.CUInt16T = ~n - self.write_bits(n, 16) - self.write_bits(ncomp, 16) - - self.ensure(block_length) - i: t.CSizeT = 0 - for i in range(block_length): - self.buf[self.byte_pos] = data[pos + i] - self.byte_pos += 1 - pos += block_length - if pos < length: - self.write_bits(0, 1) - self.write_bits(0, 2) - self.align() - - def write_zlib_header(self, wbits: t.CInt, level: t.CInt): - cinfo: t.CInt = wbits - 8 - if cinfo < 1: cinfo = 1 - if cinfo > 7: cinfo = 7 - cmf: t.CUnsignedChar = t.CUnsignedChar((cinfo << 4) | 8) - - flevel: t.CInt = 0 - if level >= 5: flevel = 3 - elif level >= 3: flevel = 1 - - flg: t.CUnsignedChar = t.CUnsignedChar(flevel << 6) - flg |= t.CUnsignedChar(31 - (cmf * 256 + flg) % 31) - - self.buf[self.byte_pos + 0] = cmf - self.buf[self.byte_pos + 1] = flg - self.byte_pos += 2 - - - def write_gzip_header(self): - self.buf[self.byte_pos + 0] = 0x1F - self.buf[self.byte_pos + 1] = 0x8B - self.buf[self.byte_pos + 2] = 0x08 - self.buf[self.byte_pos + 3] = 0x00 - self.buf[self.byte_pos + 4] = 0x00 - self.buf[self.byte_pos + 5] = 0x00 - self.buf[self.byte_pos + 6] = 0x00 - self.buf[self.byte_pos + 7] = 0x00 - self.buf[self.byte_pos + 8] = 0x00 - self.buf[self.byte_pos + 9] = 0xFF - self.byte_pos += 10 - - def align(self): - if self.bit_pos > 0: - self.bit_pos = 0 - self.byte_pos += 1 - - def total(self) -> t.CSizeT: - return self.byte_pos + (1 if (self.bit_pos > 0) else 0) - - def free(self): - free(self.buf) - self.buf = None - self.cap = 0 - self.byte_pos = 0 - self.bit_pos = 0 - - def __del__(self): - self.free() - -# ============================================================ -# Bit reader - reads bits LSB first from a byte buffer -# ============================================================ -@t.Object -class zbit_reader: - buf: BYTE | t.CPtr - length: t.CSizeT - byte_pos: t.CSizeT - bit_pos: t.CInt - - def init(self, buf: BYTE | t.CPtr, length: t.CSizeT): - self.buf = buf - self.length = length - self.byte_pos = 0 - self.bit_pos = 0 - - def read_bits(self, nbits: t.CInt, out: UINTPTR) -> t.CInt: - val: UINT = 0 - for i in range(nbits): - if self.byte_pos >= self.length: return -1 - if self.buf[self.byte_pos] & (UINT(1) << self.bit_pos): - val |= (UINT(1) << i) - self.bit_pos += 1 - if self.bit_pos == 8: - self.bit_pos = 0 - self.byte_pos += 1 - c.Set(c.Deref(out), val) - return 0 - - def read_bits_rev(self, nbits: t.CInt, out: UINTPTR) -> t.CInt: - val: UINT = 0 - for i in range(nbits - 1, 0, -1): - if self.byte_pos >= self.length: return -1 - if self.buf[self.byte_pos] & (UINT(1) << self.bit_pos): - val |= (UINT(1) << i) - self.bit_pos += 1 - if self.bit_pos == 8: - self.bit_pos = 0 - self.byte_pos += 1 - c.Set(c.Deref(out), val) - return 0 - - def align(self): - if self.bit_pos > 0: - self.bit_pos = 0 - self.byte_pos += 1 - -# ============================================================ -# Memory allocation helper for bare metal -# Can be replaced with custom allocator -# ============================================================ -def zdef_alloc(n: t.CSizeT) -> VOIDPTR: - return malloc(n) -def zdef_free(p: VOIDPTR): - free(p) diff --git a/Test/TestProject/App/__zlib/zdeflate.py b/Test/TestProject/App/__zlib/zdeflate.py deleted file mode 100644 index f9c5328..0000000 --- a/Test/TestProject/App/__zlib/zdeflate.py +++ /dev/null @@ -1,431 +0,0 @@ -from stdint import * -import zchecksum -import zhuff -import zdef -import string -import stdio -import t, c - - -@t.Object -class zdeflate_stream: - writer: zdef.zbit_writer - window: BYTE | t.CPtr - window_pos: t.CInt - window_size: t.CInt - hash_head: t.CInt | t.CPtr - hash_prev: t.CInt | t.CPtr - level: t.CInt - strategy: t.CInt - wbits: t.CInt - is_finished: t.CInt - adler: t.CUInt32T - - def find_match(self, data: BYTE | t.CPtr, data_len: t.CSizeT, - pos: t.CSizeT, best_dist: t.CInt | t.CPtr) -> t.CInt: - if pos + 2 >= data_len: return 0 - h: t.CUnsignedInt = zdeflate_hash(data + pos) - chain: t.CInt = self.hash_head[h] - best_len: t.CInt = zdef.ZDEFLATE_MIN_MATCH - 1 - c.Set(c.Deref(best_dist), 0) - max_chain: t.CInt = 128 if (self.level >= 5) else (32 if (self.level >= 2) else 4) - limit: t.CInt = (1 << self.wbits) if (self.wbits > 0) else zdef.ZDEFLATE_WINDOW_SIZE - if limit > zdef.ZDEFLATE_WINDOW_SIZE: - limit = zdef.ZDEFLATE_WINDOW_SIZE - attempts: t.CInt = 0 - while chain >= 0 and attempts < max_chain: - dist: t.CInt = t.CInt(pos) - chain - if dist <= 0 or dist > limit: break - match_len: t.CInt = 0 - max_len: t.CInt = t.CInt(data_len - pos) - if max_len > zdef.ZDEFLATE_MAX_MATCH: - max_len = zdef.ZDEFLATE_MAX_MATCH - while match_len < max_len and data[pos + match_len] == data[chain + match_len]: - match_len += 1 - if match_len > best_len: - best_len = match_len - c.Set(c.Deref(best_dist), dist) - if best_len >= zdef.ZDEFLATE_MAX_MATCH: break - chain = self.hash_prev[chain & zdef.ZDEFLATE_WINDOW_MASK] - if chain <= t.CInt(pos) - limit: break - attempts += 1 - return best_len if (best_len >= zdef.ZDEFLATE_MIN_MATCH) else 0 - - def update_hash(self, data: BYTE | t.CPtr, pos: t.CSizeT): - if pos + 2 < pos: return - h: t.CUnsignedInt = zdeflate_hash(data + pos) - self.hash_prev[pos & zdef.ZDEFLATE_WINDOW_MASK] = self.hash_head[h] - self.hash_head[h] = t.CInt(pos) - - def write_fixed_block(self, data: UINT8PTR, length: t.CSizeT, final: t.CInt): - lit_tree = zhuff.zhuff_tree() - dist_tree = zhuff.zhuff_tree() - lit_tree.build_fixed_lit_tree() - dist_tree.build_fixed_dist_tree() - self.writer.write_bits(1 if final else 0, 1) - self.writer.write_bits(1, 2) - pos: t.CSizeT = 0 - while pos < length: - best_dist: t.CInt = 0 - match_len: t.CInt = 0 - if self.level > 0 and pos + 2 < length: - match_len = self.find_match(data, length, pos, c.Addr(best_dist)) - if match_len >= zdef.ZDEFLATE_MIN_MATCH: - len_sym: t.CInt = zdeflate_len_to_symbol(match_len) - lit_tree.encode_symbol(len_sym, c.Addr(self.writer)) - extra: t.CInt = zdef.zdeflate_len_extra_bits[len_sym - 257] - if extra > 0: - self.writer.write_bits(match_len - zdef.zdeflate_len_base[len_sym - 257], extra) - dist_sym: t.CInt = zdeflate_dist_to_symbol(best_dist) - dist_tree.encode_symbol(dist_sym, c.Addr(self.writer)) - extra = zdef.zdeflate_dist_extra_bits[dist_sym] - if extra > 0: - self.writer.write_bits(best_dist - zdef.zdeflate_dist_base[dist_sym], extra) - for i in range(match_len): - self.update_hash(data, pos + i) - pos += match_len - else: - lit_tree.encode_symbol(data[pos], c.Addr(self.writer)) - self.update_hash(data, pos) - pos += 1 - lit_tree.encode_symbol(256, c.Addr(self.writer)) - - def encode_block_data(self, data: UINT8PTR, length: t.CSizeT, - lit_tree: zhuff.zhuff_tree | t.CPtr, dist_tree: zhuff.zhuff_tree | t.CPtr): - pos: t.CSizeT = 0 - while pos < length: - best_dist: t.CInt = 0 - match_len: t.CInt = 0 - if self.level > 0 and pos + 2 < length: - match_len = self.find_match(data, length, pos, c.Addr(best_dist)) - if match_len >= zdef.ZDEFLATE_MIN_MATCH: - len_sym: t.CInt = zdeflate_len_to_symbol(match_len) - lit_tree.encode_symbol(len_sym, c.Addr(self.writer)) - extra: t.CInt = zdef.zdeflate_len_extra_bits[len_sym - 257] - if extra > 0: - self.writer.write_bits(match_len - zdef.zdeflate_len_base[len_sym - 257], extra) - dist_sym: t.CInt = zdeflate_dist_to_symbol(best_dist) - dist_tree.encode_symbol(dist_sym, c.Addr(self.writer)) - extra = zdef.zdeflate_dist_extra_bits[dist_sym] - if extra > 0: - self.writer.write_bits(best_dist - zdef.zdeflate_dist_base[dist_sym], extra) - for j in range(match_len): - self.update_hash(data, pos + j) - pos += match_len - else: - lit_tree.encode_symbol(data[pos], c.Addr(self.writer)) - self.update_hash(data, pos) - pos += 1 - lit_tree.encode_symbol(256, c.Addr(self.writer)) - - - def write_dynamic_block(self, data: UINT8PTR, length: t.CSizeT, final: t.CInt): - lit_freqs: list[t.CInt, 288] - dist_freqs: list[t.CInt, 32] - zdeflate_count_freqs(lit_freqs, dist_freqs, self, data, length) - hlit: t.CInt = 286 - while hlit > 257 and lit_freqs[hlit - 1] == 0: hlit -= 1 - hdist: t.CInt = 30 - while hdist > 1 and dist_freqs[hdist - 1] == 0: hdist -= 1 - lit_tree = zhuff.zhuff_tree() - dist_tree = zhuff.zhuff_tree() - lit_tree.build_codes(lit_freqs, hlit, zdef.ZDEFLATE_MAX_BITS) - dist_tree.build_codes(dist_freqs, hdist, zdef.ZDEFLATE_MAX_BITS) - all_lengths: list[t.CInt, 288 + 32] - for i in range(hlit): all_lengths[i] = lit_tree.codes[i].bits - for i in range(hdist): all_lengths[hlit + i] = dist_tree.codes[i].bits - total_lengths: t.CInt = hlit + hdist - cl_freqs: list[t.CInt, 19] - zdeflate_count_cl_freqs(all_lengths, total_lengths, cl_freqs) - cl_tree = zhuff.zhuff_tree() - cl_tree.build_codes(cl_freqs, 19, 7) - hclen: int = 19 - while hclen > 4 and cl_tree.codes[zdef.zdeflate_codelen_order[hclen - 1]].bits == 0: hclen -= 1 - self.writer.write_bits(1 if final else 0, 1) - self.writer.write_bits(2, 2) - self.writer.write_bits(hlit - 257, 5) - self.writer.write_bits(hdist - 1, 5) - self.writer.write_bits(hclen - 4, 4) - for j in range(hclen): - self.writer.write_bits(cl_tree.codes[zdef.zdeflate_codelen_order[j]].bits, 3) - zdeflate_write_cl_encoded(all_lengths, total_lengths, c.Addr(self.writer), c.Addr(cl_tree)) - self.encode_block_data(data, length, c.Addr(lit_tree), c.Addr(dist_tree)) - - def compress_block(self, data: UINT8PTR, length: t.CSizeT, final: t.CInt): - if self.level == 0: - self.write_stored_block(data, length, final) - elif self.strategy == 4 or length < 128: - self.write_fixed_block(data, length, final) - else: - self.write_dynamic_block(data, length, final) - - def write_stored_block(self, data: UINT8PTR, length: t.CSizeT, final: t.CInt): - self.writer.stored_block(data, length, final) - - def compress(self, data: UINT8PTR, length: t.CSizeT, - out: t.CUInt8T | t.CPtr[t.CPtr], out_len: t.CSizeT | t.CPtr) -> t.CInt: - if self.is_finished: return -2 - if not data or length == 0: - c.Set(c.Deref(out), None) - c.Set(c.Deref(out_len), 0) - return 0 - self.adler = zchecksum.zchecksum_adler32(data, length, self.adler) - memset(self.hash_head, -1, zdef.ZDEFLATE_HASH_SIZE * int.__sizeof__()) - memset(self.hash_prev, -1, zdef.ZDEFLATE_WINDOW_SIZE * int.__sizeof__()) - self.compress_block(data, length, 0) - c.Set(c.Deref(out_len), self.writer.total()) - c.Set(c.Deref(out), UINT8PTR(zdef.zdef_alloc(c.Deref(out_len)))) - if not c.Deref(out): return -4 - memcpy(c.Deref(out), self.writer.buf, c.Deref(out_len)) - return 0 - - def flush(self, mode: t.CInt, out: t.CUInt8T | t.CPtr[t.CPtr], out_len: t.CSizeT | t.CPtr) -> t.CInt: - if mode == 4: - if not self.is_finished: - if self.level == 0: - self.writer.write_bits(1, 1) - self.writer.write_bits(0, 2) - self.writer.align() - else: - lit_tree = zhuff.zhuff_tree() - lit_tree.build_fixed_lit_tree() - self.writer.write_bits(1, 1) - self.writer.write_bits(1, 2) - lit_tree.encode_symbol(256, c.Addr(self.writer)) - self.is_finished = 1 - if self.wbits >= 0: - self.writer.align() - adler: t.CUInt32T = self.adler - self.writer.buf[self.writer.byte_pos + 0] = (adler >> 24) & 0xFF - self.writer.buf[self.writer.byte_pos + 1] = (adler >> 16) & 0xFF - self.writer.buf[self.writer.byte_pos + 2] = (adler >> 8) & 0xFF - self.writer.buf[self.writer.byte_pos + 3] = (adler >> 0) & 0xFF - self.writer.byte_pos += 4 - elif mode == 2 or mode == 3: - self.writer.write_bits(0, 1) - self.writer.write_bits(0, 2) - self.writer.align() - c.Set(c.Deref(out_len), self.writer.total()) - c.Set(c.Deref(out), UINT8PTR(zdef.zdef_alloc(c.Deref(out_len)))) - if not c.Deref(out): return -4 - memcpy(c.Deref(out), self.writer.buf, c.Deref(out_len)) - return 0 - - def set_dictionary(self, dict: UINT8PTR, length: t.CSizeT) -> t.CInt: - if not dict: return -2 - use: t.CSizeT = length - if use > zdef.ZDEFLATE_WINDOW_SIZE: - dict += length - zdef.ZDEFLATE_WINDOW_SIZE - use = zdef.ZDEFLATE_WINDOW_SIZE - memcpy(self.window, dict, use) - self.window_size = t.CInt(use) - self.window_pos = t.CInt(use) - self.adler = zchecksum.zchecksum_adler32(dict, length, self.adler) - return 0 - - def copy(self) -> zdeflate_stream | t.CPtr: - z: zdeflate_stream | t.CPtr = zdef.zdef_alloc(zdeflate_stream.__sizeof__()) - if not z: return None - memcpy(z, self, zdeflate_stream.__sizeof__()) - z.writer.buf = BYTEPTR(zdef.zdef_alloc(self.writer.cap)) - if not z.writer.buf: - zdef.zdef_free(z) - return None - memcpy(z.writer.buf, self.writer.buf, self.writer.cap) - z.window = BYTEPTR(zdef.zdef_alloc(zdef.ZDEFLATE_WINDOW_SIZE)) - z.hash_head = INTPTR(zdef.zdef_alloc(zdef.ZDEFLATE_HASH_SIZE * int.__sizeof__())) - z.hash_prev = INTPTR(zdef.zdef_alloc(zdef.ZDEFLATE_WINDOW_SIZE * int.__sizeof__())) - if not z.window or not z.hash_head or not z.hash_prev: - if z.writer.buf: zdef.zdef_free(z.writer.buf) - zdef.zdef_free(z) - return None - memcpy(z.window, self.window, zdef.ZDEFLATE_WINDOW_SIZE) - memcpy(z.hash_head, self.hash_head, zdef.ZDEFLATE_HASH_SIZE * int.__sizeof__()) - memcpy(z.hash_prev, self.hash_prev, zdef.ZDEFLATE_WINDOW_SIZE * int.__sizeof__()) - return z - - def destroy(self): - if self.writer.buf: zdef.zdef_free(self.writer.buf) - if self.window: zdef.zdef_free(self.window) - if self.hash_head: zdef.zdef_free(self.hash_head) - if self.hash_prev: zdef.zdef_free(self.hash_prev) - zdef.zdef_free(self) - - - - -def zdeflate_count_freqs(lit_freqs: INTPTR, dist_freqs: INTPTR, - s: zdeflate_stream | t.CPtr, data: UINT8PTR, length: t.CSizeT): - memset(lit_freqs, 0, 288 * int.__sizeof__()) - memset(dist_freqs, 0, 32 * int.__sizeof__()) - pos: t.CSizeT = 0 - while pos < length: - best_dist: t.CInt = 0 - match_len: t.CInt = 0 - if s.level > 0 and pos + 2 < length: - match_len = zdeflate_stream.find_match(s, data, length, pos, c.Addr(best_dist)) - if match_len >= zdef.ZDEFLATE_MIN_MATCH: - len_sym: t.CInt = zdeflate_len_to_symbol(match_len) - lit_freqs[len_sym] += 1 - dist_freqs[zdeflate_dist_to_symbol(best_dist)] += 1 - for i in range(match_len): - zdeflate_stream.update_hash(s, data, pos + i) - pos += match_len - else: - lit_freqs[data[pos]] += 1 - zdeflate_stream.update_hash(s, data, pos) - pos += 1 - lit_freqs[256] = 1 - - - -def zdeflate_hash(p: BYTE | t.CPtr) -> t.CUnsignedInt: - return (t.CUnsignedInt(p[0]) ^ (t.CUnsignedInt(p[1]) << 5) ^ (t.CUnsignedInt(p[2]) << 10)) & zdef.ZDEFLATE_HASH_MASK - - -def zdeflate_len_to_symbol(length: t.CInt) -> t.CInt: - for i in range(29): - if length <= zdef.zdeflate_len_base[i] + (1 << zdef.zdeflate_len_extra_bits[i]) - 1: - return 257 + i - return 285 - -def zdeflate_dist_to_symbol(dist: t.CInt) -> t.CInt: - for i in range(30): - if dist <= zdef.zdeflate_dist_base[i] + (1 << zdef.zdeflate_dist_extra_bits[i]) - 1: - return i - return 29 - -def zdeflate_count_cl_freqs(all_lengths: INTPTR, total: t.CInt, cl_freqs: INTPTR): - memset(cl_freqs, 0, 19 * int.__sizeof__()) - i: t.CInt = 0 - while i < total: - if all_lengths[i] == 0: - run: t.CInt = 0 - while i + run < total and all_lengths[i + run] == 0: run += 1 - while run > 0: - if run >= 11: - count: t.CInt = run - if count > 138: count = 138 - cl_freqs[18] += 1 - run -= count - elif run >= 3: - count: t.CInt = run - if count > 10: count = 10 - cl_freqs[17] += 1 - run -= count - else: - cl_freqs[0] += 1 - run -= 1 - while i < total and all_lengths[i] == 0: i += 1 - else: - cl_freqs[all_lengths[i]] += 1 - val: t.CInt = all_lengths[i] - i += 1 - run: t.CInt = 0 - while i + run < total and all_lengths[i + run] == val: run += 1 - while run >= 3: - count: t.CInt = run - if count > 6: count = 6 - cl_freqs[16] += 1 - run -= count - i += run - -def zdeflate_write_cl_encoded(all_lengths: INTPTR, total: t.CInt, - w: zdef.zbit_writer | t.CPtr, cl_tree: zhuff.zhuff_tree | t.CPtr): - i: t.CInt = 0 - while i < total: - if all_lengths[i] == 0: - run: t.CInt = 0 - while i + run < total and all_lengths[i + run] == 0: run += 1 - while run > 0: - if run >= 11: - count: t.CInt = run - if count > 138: count = 138 - cl_tree.encode_symbol(18, w) - w.write_bits(count - 11, 7) - run -= count - elif run >= 3: - count: t.CInt = run - if count > 10: count = 10 - cl_tree.encode_symbol(17, w) - w.write_bits(count - 3, 3) - run -= count - else: - cl_tree.encode_symbol(0, w) - run -= 1 - while i < total and all_lengths[i] == 0: i += 1 - else: - cl_tree.encode_symbol(all_lengths[i], w) - val: t.CInt = all_lengths[i] - i += 1 - run: t.CInt = 0 - while i + run < total and all_lengths[i + run] == val: run += 1 - while run >= 3: - count: t.CInt = run - if count > 6: count = 6 - cl_tree.encode_symbol(16, w) - w.write_bits(count - 3, 2) - run -= count - i += run - - - -def zdeflate_create(level: t.CInt, wbits: t.CInt, mem_level: t.CInt, strategy: t.CInt) -> zdeflate_stream | t.CPtr: - s: zdeflate_stream | t.CPtr = zdef.zdef_alloc(zdeflate_stream.__sizeof__()) - if not s: return None - memset(s, 0, zdeflate_stream.__sizeof__()) - s.writer = zdef.zbit_writer() - s.window = BYTEPTR(zdef.zdef_alloc(zdef.ZDEFLATE_WINDOW_SIZE)) - s.hash_head = INTPTR(zdef.zdef_alloc(zdef.ZDEFLATE_HASH_SIZE * int.__sizeof__())) - s.hash_prev = INTPTR(zdef.zdef_alloc(zdef.ZDEFLATE_WINDOW_SIZE * int.__sizeof__())) - if not s.window or not s.hash_head or not s.hash_prev: - s.destroy() - return None - memset(s.hash_head, -1, zdef.ZDEFLATE_HASH_SIZE * int.__sizeof__()) - memset(s.hash_prev, -1, zdef.ZDEFLATE_WINDOW_SIZE * int.__sizeof__()) - s.level = level - s.wbits = wbits - s.strategy = strategy - s.is_finished = 0 - s.adler = 1 - if wbits > 0: - s.writer.write_zlib_header(wbits, level) - elif wbits == 0: - s.writer.write_zlib_header(15, level) - return s - - -def zdeflate_one_shot(data: UINT8PTR, length: t.CSizeT, - level: t.CInt, wbits: t.CInt, out_len: t.CSizeT | t.CPtr) -> t.CUInt8T | t.CPtr: - s: zdeflate_stream | t.CPtr = zdeflate_create(level, wbits, 8, 0) - if not s: return None - - memset(s.hash_head, -1, zdef.ZDEFLATE_HASH_SIZE * int.__sizeof__()) - memset(s.hash_prev, -1, zdef.ZDEFLATE_WINDOW_SIZE * int.__sizeof__()) - - s.adler = zchecksum.zchecksum_adler32(data, length, 1) - - if length == 0: - s.writer.write_bits(1, 1) - s.writer.write_bits(1, 2) - lit_tree = zhuff.zhuff_tree() - lit_tree.build_fixed_lit_tree() - lit_tree.encode_symbol(256, c.Addr(s.writer)) - else: - s.compress_block(data, length, 1) - - s.is_finished = 1 - - if wbits >= 0: - s.writer.align() - adler: t.CUInt32T = s.adler - s.writer.buf[s.writer.byte_pos + 0] = (adler >> 24) & 0xFF - s.writer.buf[s.writer.byte_pos + 1] = (adler >> 16) & 0xFF - s.writer.buf[s.writer.byte_pos + 2] = (adler >> 8) & 0xFF - s.writer.buf[s.writer.byte_pos + 3] = (adler >> 0) & 0xFF - s.writer.byte_pos += 4 - c.Set(c.Deref(out_len), s.writer.total()) - result: UINT8PTR = UINT8PTR(zdef.zdef_alloc(c.Deref(out_len))) - if result: memcpy(result, s.writer.buf, c.Deref(out_len)) - s.destroy() - return result diff --git a/Test/TestProject/App/__zlib/zhuff.py b/Test/TestProject/App/__zlib/zhuff.py deleted file mode 100644 index 71c4158..0000000 --- a/Test/TestProject/App/__zlib/zhuff.py +++ /dev/null @@ -1,353 +0,0 @@ -#include -from stdint import * -import zdef -import t, c - - -ZHUFF_MAX_CODES: t.CDefine = 288 -ZHUFF_MAX_BITS: t.CDefine = 15 - -class zhuff_code: - code: UINT - bits: t.CInt - -@t.Object -class zhuff_tree: - codes: list[zhuff_code, ZHUFF_MAX_CODES] - count: t.CInt - max_bits: t.CInt - - def __init__(self): - pass - - def build_codes(self, freqs: INTPTR, count: t.CInt, max_bits: t.CInt): - lengths: list[t.CInt, ZHUFF_MAX_CODES] - bl_count: list[t.CInt, ZHUFF_MAX_BITS + 1] - next_code: list[UINT, ZHUFF_MAX_BITS + 1] - self.count = count - self.max_bits = max_bits - self.build_code_lengths(lengths, freqs, count, max_bits) - memset(bl_count, 0, bl_count.__sizeof__()) - for i in range(count): - if lengths[i] > 0: - bl_count[lengths[i]] += 1 - code: t.CUnsignedInt = 0 - next_code[0] = 0 - for bits in range(1, max_bits + 1): - code = (code + bl_count[bits - 1]) << 1 - next_code[bits] = code - for i in range(count): - self.codes[i].bits = lengths[i] - if lengths[i] > 0: - self.codes[i].code = next_code[lengths[i]] - next_code[lengths[i]] += 1 - else: - self.codes[i].code = 0 - - def build_fixed_lit_tree(self): - lengths: list[t.CInt, 288] - bl_count: list[t.CInt, 16] - next_code: list[t.CUnsignedInt, 16] - self.get_fixed_lit_lengths(lengths) - memset(bl_count, 0, bl_count.__sizeof__()) - for i in range(288): - if lengths[i] > 0: - bl_count[lengths[i]] += 1 - code: t.CUnsignedInt = 0 - next_code[0] = 0 - for bits in range(1, 9 + 1): - code = (code + bl_count[bits - 1]) << 1 - next_code[bits] = code - self.count = 288 - self.max_bits = 9 - for i in range(288): - self.codes[i].bits = lengths[i] - if lengths[i] > 0: - self.codes[i].code = next_code[lengths[i]] - next_code[lengths[i]] += 1 - else: - self.codes[i].code = 0 - - def build_fixed_dist_tree(self): - lengths: list[t.CInt, 32] - bl_count: list[t.CInt, 16] - next_code: list[t.CUnsignedInt, 16] - self.get_fixed_dist_lengths(lengths) - memset(bl_count, 0, bl_count.__sizeof__()) - for i in range(32): - if lengths[i] > 0: - bl_count[lengths[i]] += 1 - code: t.CUnsignedInt = 0 - next_code[0] = 0 - for bits in range(1, 5 + 1): - code = (code + bl_count[bits - 1]) << 1 - next_code[bits] = code - self.count = 32 - self.max_bits = 5 - for i in range(32): - self.codes[i].bits = lengths[i] - if lengths[i] > 0: - self.codes[i].code = next_code[lengths[i]] - next_code[lengths[i]] += 1 - else: - self.codes[i].code = 0 - - def encode_symbol(self, symbol: int, writer: zdef.zbit_writer | t.CPtr): - if symbol < 0 or symbol >= self.count: - return - if self.codes[symbol].bits == 0: - return - writer.write_bits_rev(self.codes[symbol].code, self.codes[symbol].bits) - - - def build_code_lengths(self, lengths: t.CInt | t.CPtr, freqs: t.CInt | t.CPtr, count: t.CInt, max_bits: t.CInt): - bl_count: list[t.CInt, ZHUFF_MAX_BITS + 2] - sort_count: t.CInt = 0 - memset(bl_count, 0, bl_count.__sizeof__()) - memset(lengths, 0, int.__sizeof__() * count) - for i in range(count): - if freqs[i] > 0: - sort_count += 1 - if sort_count == 0: return - if sort_count == 1: - for i in range(count): - if freqs[i] > 0: - lengths[i] = 1 - return - items: t.CInt | t.CPtr = INTPTR(zdef.zdef_alloc(sort_count * int.__sizeof__())) - item_freqs: t.CInt | t.CPtr = INTPTR(zdef.zdef_alloc(sort_count * int.__sizeof__())) - idx: t.CInt = 0 - for i in range(count): - if freqs[i] > 0: - items[idx] = i - item_freqs[idx] = freqs[i] - idx += 1 - for i in range(sort_count): - key_item: t.CInt = items[i] - key_freq: t.CInt = item_freqs[i] - j: t.CInt = i - 1 - while j >= 0 and item_freqs[j] > key_freq: - items[j + 1] = items[j] - item_freqs[j + 1] = item_freqs[j] - j -= 1 - items[j + 1] = key_item - item_freqs[j + 1] = key_freq - parent: INTPTR = INTPTR(zdef.zdef_alloc((sort_count * 2) * int.__sizeof__())) - for i in range(sort_count * 2): - parent[i] = -1 - heap: INTPTR = INTPTR(zdef.zdef_alloc((sort_count + 1) * int.__sizeof__())) - heap_size: t.CInt = 0 - for i in range(sort_count): - heap[heap_size] = i - heap_size += 1 - pos: t.CInt = heap_size - 1 - while pos > 0: - par: t.CInt = (pos - 1) / 2 - if item_freqs[heap[par]] > item_freqs[heap[pos]]: - tmp: t.CInt = heap[par] - heap[par] = heap[pos] - heap[pos] = tmp - pos = par - else: break - combined_freq: INTPTR = INTPTR(zdef.zdef_alloc((sort_count * 2) * int.__sizeof__())) - for i in range(sort_count): - combined_freq[i] = item_freqs[i] - internal: t.CInt = sort_count - while heap_size > 1: - a: t.CInt = heap[0] - heap[0] = heap[heap_size - 1] - heap_size -= 1 - pos: t.CInt = 0 - while True: - left: t.CInt = 2 * pos + 1 - right: t.CInt = 2 * pos + 2 - smallest: t.CInt = pos - if left < heap_size and combined_freq[heap[left]] < combined_freq[heap[smallest]]: - smallest = left - if right < heap_size and combined_freq[heap[right]] < combined_freq[heap[smallest]]: - smallest = right - if smallest != pos: - tmp: t.CInt = heap[pos] - heap[pos] = heap[smallest] - heap[smallest] = tmp - pos = smallest - else: break - b: t.CInt = heap[0] - heap[0] = heap[heap_size - 1] - heap_size -= 1 - pos = 0 - while True: - left: t.CInt = 2 * pos + 1 - right: t.CInt = 2 * pos + 2 - smallest: t.CInt = pos - if left < heap_size and combined_freq[heap[left]] < combined_freq[heap[smallest]]: - smallest = left - if right < heap_size and combined_freq[heap[right]] < combined_freq[heap[smallest]]: - smallest = right - if smallest != pos: - tmp: t.CInt = heap[pos] - heap[pos] = heap[smallest] - heap[smallest] = tmp - pos = smallest - else: break - if internal >= sort_count * 2 - 1: break - combined_freq[internal] = combined_freq[a] + combined_freq[b] - parent[a] = internal - parent[b] = internal - heap[heap_size] = internal - heap_size += 1 - pos = heap_size - 1 - while pos > 0: - par: t.CInt = (pos - 1) / 2 - if combined_freq[heap[par]] > combined_freq[heap[pos]]: - tmp: t.CInt = heap[par] - heap[par] = heap[pos] - heap[pos] = tmp - pos = par - else: break - internal += 1 - for i in range(sort_count): - node: t.CInt = i - length: t.CInt = 0 - while parent[node] >= 0: - length += 1 - node = parent[node] - lengths[items[i]] = length - memset(bl_count, 0, bl_count.__sizeof__()) - for i in range(count): - if lengths[i] > 0: - bl_count[lengths[i]] += 1 - overflow: t.CInt = 0 - for i in range(count): - if lengths[i] > max_bits: - overflow += 1 - bl_count[lengths[i]] -= 1 - lengths[i] = max_bits - bl_count[max_bits] += 1 - while overflow > 0: - bits: t.CInt = max_bits - 1 - while bits > 0 and bl_count[bits] == 0: - bits -= 1 - if bits == 0: break - bl_count[bits] -= 1 - bl_count[bits + 1] += 2 - bl_count[max_bits] -= 1 - overflow -= 2 - sorted_items: INTPTR = INTPTR(zdef.zdef_alloc(sort_count * int.__sizeof__())) - si: t.CInt = 0 - for i in range(count): - if freqs[i] > 0: - sorted_items[si] = i - si += 1 - for i in range(si - 1): - for j in range(i + 1, si): - if lengths[sorted_items[i]] < lengths[sorted_items[j]]: - tmp: t.CInt = sorted_items[i] - sorted_items[i] = sorted_items[j] - sorted_items[j] = tmp - sidx: t.CInt = 0 - for bits in range(max_bits, 1, -1): - n: t.CInt = bl_count[bits] - while n > 0 and sidx < si: - lengths[sorted_items[sidx]] = bits - sidx += 1 - n -= 1 - zdef.zdef_free(sorted_items) - zdef.zdef_free(heap) - zdef.zdef_free(parent) - zdef.zdef_free(combined_freq) - zdef.zdef_free(item_freqs) - zdef.zdef_free(items) - - def get_fixed_lit_lengths(self, lengths: INTPTR): - for i in range( 0, 143 + 1): lengths[i] = 8 - for i in range(143 + 1, 255 + 1): lengths[i] = 9 - for i in range(255 + 1, 279 + 1): lengths[i] = 7 - for i in range(279 + 1, 287 + 1): lengths[i] = 8 - - def get_fixed_dist_lengths(self, lengths: INTPTR): - for i in range(32): - lengths[i] = 5 - - def build_tree_from_lengths(self, lengths: INTPTR, count: t.CInt, max_bits: t.CInt): - bl_count: list[t.CInt, 16] - next_code: list[t.CUnsignedInt, 16] - - memset(bl_count, 0, bl_count.__sizeof__()) - for i in range(count): - if lengths[i] > 0: - bl_count[lengths[i]] += 1 - - code: UINT = 0 - next_code[0] = 0 - for bits in range(1, max_bits + 1): - code = (code + bl_count[bits - 1]) << 1 - next_code[bits] = code - - self.count = count - self.max_bits = max_bits - for i in range(count): - self.codes[i].bits = lengths[i] - if lengths[i] > 0: - self.codes[i].code = next_code[lengths[i]] - next_code[lengths[i]] += 1 - else: - self.codes[i].code = 0 - - -class zhuff_decode_node: - children: list[t.CInt, 2] - symbol: t.CInt - - -@t.Object -class zhuff_decode_tree: - nodes: list[zhuff_decode_node, 2 * ZHUFF_MAX_CODES] - node_count: t.CInt - root: t.CInt - - def __init__(self): - pass - - def build_decode_tree(self, ht: zhuff_tree | t.CPtr): - self.node_count = 1 - self.root = 0 - self.nodes[0].children[0] = -1 - self.nodes[0].children[1] = -1 - self.nodes[0].symbol = -1 - for i in range(ht.count): - if ht.codes[i].bits == 0: continue - node: int = 0 - for bit in range(ht.codes[i].bits - 1, -1, -1): - dir: t.CInt = (ht.codes[i].code >> bit) & 1 - if bit > 0: - # Internal node: traverse or create - if self.nodes[node].children[dir] == -1: - new_node: int = self.node_count - self.node_count += 1 - self.nodes[new_node].children[0] = -1 - self.nodes[new_node].children[1] = -1 - self.nodes[new_node].symbol = -1 - self.nodes[node].children[dir] = new_node - node = self.nodes[node].children[dir] - else: - # Leaf: bit 0 - set symbol on the child - if self.nodes[node].children[dir] == -1: - leaf: int = self.node_count - self.node_count += 1 - self.nodes[leaf].children[0] = -1 - self.nodes[leaf].children[1] = -1 - self.nodes[leaf].symbol = i - self.nodes[node].children[dir] = leaf - else: - self.nodes[self.nodes[node].children[dir]].symbol = i - - def decode_symbol(self, reader: zdef.zbit_reader | t.CPtr) -> t.CInt: - node: int = self.root - while self.nodes[node].symbol == -1: - bit: t.CUnsignedInt - if reader.read_bits(1, c.Addr(bit)) != 0: return -1 - dir: t.CInt = t.CInt(bit) - if self.nodes[node].children[dir] == -1: return -1 - node = self.nodes[node].children[dir] - return self.nodes[node].symbol diff --git a/Test/TestProject/App/__zlib/zinflate.py b/Test/TestProject/App/__zlib/zinflate.py deleted file mode 100644 index efdcded..0000000 --- a/Test/TestProject/App/__zlib/zinflate.py +++ /dev/null @@ -1,454 +0,0 @@ -from stdint import * -import zinflate -import zchecksum -import zdef -import zhuff -import string -import t, c - - -@t.Object -class zinflate_stream: - reader: zdef.zbit_reader - - window: BYTEPTR - window_pos: t.CInt - window_size: t.CInt - - wbits: t.CInt - is_finished: t.CInt - is_initialized: t.CInt - - header_parsed: t.CInt - is_gzip: t.CInt - - adler: t.CUInt32T - crc: t.CUInt32T - - output: BYTEPTR - output_len: t.CSizeT - output_cap: t.CSizeT - - input_data: t.CConst | BYTEPTR - input_len: t.CSizeT - input_pos: t.CSizeT - - max_length: t.CSizeT - - def __init__(self): - pass - - def output_byte(self, byte: BYTE): - if self.max_length > 0 and self.output_len >= self.max_length: return - - if self.output_len >= self.output_cap: - new_cap: t.CSizeT = self.output_cap * 2 - if new_cap < 256: new_cap = 256 - new_buf: BYTEPTR = BYTEPTR(zdef.zdef_alloc(new_cap)) - if not new_buf: return - memcpy(new_buf, self.output, self.output_len) - zdef.zdef_free(self.output) - self.output = new_buf - self.output_cap = new_cap - self.output[self.output_len] = byte - self.output_len += 1 - self.window[self.window_pos & (zdef.ZDEFLATE_WINDOW_SIZE - 1)] = byte - self.window_pos += 1 - - - def parse_header(self) -> t.CInt: - if self.header_parsed: return 0 - if self.wbits < 0: - self.header_parsed = 1 - self.is_gzip = 0 - return 0 - if self.input_pos + 2 > self.input_len: return -3 - b0: BYTE = self.input_data[self.input_pos] - b1: BYTE = self.input_data[self.input_pos + 1] - if b0 == 0x1F and b1 == 0x8B: - self.is_gzip = 1 - if self.input_pos + 10 > self.input_len: return -3 - self.input_pos += 10 - flg: BYTE = self.input_data[self.input_pos - 6] - if flg & 0x04: - if self.input_pos + 2 > self.input_len: return -3 - xlen: UINT = self.input_data[self.input_pos] | (self.input_data[self.input_pos + 1] << 8) - self.input_pos += 2 + xlen - if flg & 0x08: - while self.input_pos < self.input_len and self.input_data[self.input_pos] != 0: self.input_pos += 1 - self.input_pos += 1 - if flg & 0x10: - while self.input_pos < self.input_len and self.input_data[self.input_pos] != 0: self.input_pos += 1 - self.input_pos += 1 - if flg & 0x02: - self.input_pos += 2 - if self.input_pos > self.input_len: return -3 - else: - self.is_gzip = 0 - if (b0 * 256 + b1) % 31 != 0: return -3 - cm: t.CInt = b0 & 0x0F - if cm != 8: return -3 - self.input_pos += 2 - self.header_parsed = 1 - return 0 - - - def read_bits_from_input(self, nbits: t.CInt, out: UINTPTR) -> t.CInt: - val: UINT = 0 - for i in range(nbits): - if self.input_pos >= self.input_len: return -3 - if self.input_data[self.input_pos] & (UINT(1) << (self.reader.bit_pos)): - val |= (UINT(1) << i) - self.reader.bit_pos += 1 - if self.reader.bit_pos == 8: - self.reader.bit_pos = 0 - self.input_pos += 1 - c.Set(c.Deref(out), val) - return 0 - - - def read_huffman(self, dt: zhuff.zhuff_decode_tree | t.CPtr) -> t.CInt: - node: int = dt.root - while dt.nodes[node].symbol == -1: - bit: UINT - if self.read_bits_from_input(1, c.Addr(bit)) != 0: return -1 - dir: int = t.CInt(bit) - if dt.nodes[node].children[dir] == -1: return -3 - node = dt.nodes[node].children[dir] - return dt.nodes[node].symbol - - def inflate_block_stored(self) -> t.CInt: - if self.reader.bit_pos != 0: - self.reader.bit_pos = 0 - self.input_pos += 1 - if self.input_pos + 4 > self.input_len: return -3 - length: UINT = self.input_data[self.input_pos] | (self.input_data[self.input_pos + 1] << 8) - nlen: UINT = self.input_data[self.input_pos + 2] | (self.input_data[self.input_pos + 3] << 8) - self.input_pos += 4 - if (length ^ nlen) != 0xFFFF: return -3 - if self.input_pos + length > self.input_len: return -3 - i: t.CUnsignedInt - for i in range(length): - self.output_byte(self.input_data[self.input_pos]) - self.input_pos += 1 - return 0 - - - def inflate_block_fixed(self) -> t.CInt: - lit_tree = zhuff.zhuff_tree() - dist_tree = zhuff.zhuff_tree() - lit_tree.build_fixed_lit_tree() - dist_tree.build_fixed_dist_tree() - - lit_dt: zhuff.zhuff_decode_tree | t.CPtr = zdef.zdef_alloc(zhuff.zhuff_decode_tree.__sizeof__()) - dist_dt: zhuff.zhuff_decode_tree | t.CPtr = zdef.zdef_alloc(zhuff.zhuff_decode_tree.__sizeof__()) - if not lit_dt or not dist_dt: - if lit_dt: zdef.zdef_free(lit_dt) - if dist_dt: zdef.zdef_free(dist_dt) - return -4 - memset(lit_dt, 0, zhuff.zhuff_decode_tree.__sizeof__()) - memset(dist_dt, 0, zhuff.zhuff_decode_tree.__sizeof__()) - lit_dt.build_decode_tree(c.Addr(lit_tree)) - dist_dt.build_decode_tree(c.Addr(dist_tree)) - - result: t.CInt = 0 - while True: - if self.max_length > 0 and self.output_len >= self.max_length: break - - sym: t.CInt = self.read_huffman(lit_dt) - if sym < 0: - result = -3 - break - if sym == 256: break - if sym < 256: - self.output_byte(BYTE(sym)) - else: - len_idx: t.CInt = sym - 257 - if len_idx < 0 or len_idx >= 29: - result = -3 - break - length: t.CInt = zdef.zdeflate_len_base[len_idx] - extra: t.CInt = zdef.zdeflate_len_extra_bits[len_idx] - if extra > 0: - extra_val: UINT - if self.read_bits_from_input(extra, c.Addr(extra_val)) != 0: - result = -3 - break - length += extra_val - - dist_sym: t.CInt = self.read_huffman(dist_dt) - if dist_sym < 0 or dist_sym >= 30: - result = -3 - break - dist: t.CInt = zdef.zdeflate_dist_base[dist_sym] - extra = zdef.zdeflate_dist_extra_bits[dist_sym] - if extra > 0: - extra_val: UINT - if self.read_bits_from_input(extra, c.Addr(extra_val)) != 0: - result = -3 - break - dist += extra_val - - for i in range(length): - if self.max_length > 0 and self.output_len >= self.max_length: break - src_pos: t.CInt = (self.window_pos - dist) & (zdef.ZDEFLATE_WINDOW_SIZE - 1) - byte: BYTE = self.window[src_pos] - self.output_byte(byte) - - zdef.zdef_free(lit_dt) - zdef.zdef_free(dist_dt) - return result - - - def inflate_block_dynamic(self) -> t.CInt: - hlit_val: UINT - hdist_val: UINT - hclen_val: UINT - if self.read_bits_from_input(5, c.Addr(hlit_val)) != 0: return -3 - if self.read_bits_from_input(5, c.Addr(hdist_val)) != 0: return -3 - if self.read_bits_from_input(4, c.Addr(hclen_val)) != 0: return -3 - - hlit: t.CInt = t.CInt(hlit_val) + 257 - hdist: t.CInt = t.CInt(hdist_val) + 1 - hclen: t.CInt = t.CInt(hclen_val) + 4 - - cl_lengths: list[t.CInt, 19] - memset(cl_lengths, 0, cl_lengths.__sizeof__()) - for i in range(hclen): - len_val: UINT - if self.read_bits_from_input(3, c.Addr(len_val)) != 0: return -3 - cl_lengths[zdef.zdeflate_codelen_order[i]] = t.CInt(len_val) - - cl_tree = zhuff.zhuff_tree() - cl_tree.build_tree_from_lengths(cl_lengths, 19, 7) - - cl_dt = zhuff.zhuff_decode_tree() - cl_dt.build_decode_tree(c.Addr(cl_tree)) - - total: t.CInt = hlit + hdist - all_lengths: t.CInt | t.CPtr = zdef.zdef_alloc(total * int.__sizeof__()) - if not all_lengths: return -4 - - idx: t.CInt = 0 - while idx < total: - sym: t.CInt = self.read_huffman(c.Addr(cl_dt)) - if sym < 0 or sym > 18: - zdef.zdef_free(all_lengths) - return -3 - if sym < 16: - all_lengths[idx] = sym - idx += 1 - elif sym == 16: - rep: UINT - if self.read_bits_from_input(2, c.Addr(rep)) != 0: - zdef.zdef_free(all_lengths) - return -3 - rep += 3 - if idx == 0 or idx + rep > total: - zdef.zdef_free(all_lengths) - return -3 - prev: t.CInt = all_lengths[idx - 1] - i: t.CUnsignedInt - for i in range(rep): - all_lengths[idx] = prev - idx += 1 - elif sym == 17: - rep: t.CUnsignedInt - if self.read_bits_from_input(3, c.Addr(rep)) != 0: - zdef.zdef_free(all_lengths) - return -3 - rep += 3 - if idx + rep > total: - zdef.zdef_free(all_lengths) - return -3 - i: t.CUnsignedInt - for i in range(rep): - all_lengths[idx] = 0 - idx += 1 - else: - rep: t.CUnsignedInt - if self.read_bits_from_input(7, c.Addr(rep)) != 0: - zdef.zdef_free(all_lengths) - return -3 - rep += 11 - if idx + rep > total: - zdef.zdef_free(all_lengths) - return -3 - i: t.CUnsignedInt - for i in range(rep): - all_lengths[idx] = 0 - idx += 1 - - lit_tree = zhuff.zhuff_tree() - dist_tree = zhuff.zhuff_tree() - - lit_lengths: list[t.CInt, 288] - memset(lit_lengths, 0, lit_lengths.__sizeof__()) - for i in range(hlit): - lit_lengths[i] = all_lengths[i] - lit_tree.build_tree_from_lengths(lit_lengths, hlit, zdef.ZDEFLATE_MAX_BITS) - - dist_lengths: list[t.CInt, 32] - memset(dist_lengths, 0, dist_lengths.__sizeof__()) - for i in range(hdist): - dist_lengths[i] = all_lengths[hlit + i] - dist_tree.build_tree_from_lengths(dist_lengths, hdist, zdef.ZDEFLATE_MAX_BITS) - - zdef.zdef_free(all_lengths) - - lit_dt = zhuff.zhuff_decode_tree() - dist_dt = zhuff.zhuff_decode_tree() - lit_dt.build_decode_tree(c.Addr(lit_tree)) - dist_dt.build_decode_tree(c.Addr(dist_tree)) - - while True: - if self.max_length > 0 and self.output_len >= self.max_length: return 0 - sym: t.CInt = self.read_huffman(c.Addr(lit_dt)) - if sym < 0: return -3 - if sym == 256: return 0 - if sym < 256: - self.output_byte(BYTE(sym)) - else: - len_idx: t.CInt = sym - 257 - if len_idx < 0 or len_idx >= 29: return -3 - length: t.CInt = zdef.zdeflate_len_base[len_idx] - extra: t.CInt = zdef.zdeflate_len_extra_bits[len_idx] - if extra > 0: - extra_val: UINT - if self.read_bits_from_input(extra, c.Addr(extra_val)) != 0: return -3 - length += extra_val - dist_sym: t.CInt = self.read_huffman(c.Addr(dist_dt)) - if dist_sym < 0 or dist_sym >= 30: return -3 - dist: t.CInt = zdef.zdeflate_dist_base[dist_sym] - extra = zdef.zdeflate_dist_extra_bits[dist_sym] - if extra > 0: - extra_val: UINT - if self.read_bits_from_input(extra, c.Addr(extra_val)) != 0: return -3 - dist += extra_val - for i in range(length): - if self.max_length > 0 and self.output_len >= self.max_length: return 0 - src_pos: t.CInt = (self.window_pos - dist) & (zdef.ZDEFLATE_WINDOW_SIZE - 1) - byte: BYTE = self.window[src_pos] - self.output_byte(byte) - - def inflate_stream(self) -> t.CInt: - err: t.CInt = self.parse_header() - if err != 0: return err - while not self.is_finished: - bfinal_val: UINT - btype_val: UINT - if self.read_bits_from_input(1, c.Addr(bfinal_val)) != 0: return -3 - if self.read_bits_from_input(2, c.Addr(btype_val)) != 0: return -3 - bfinal: t.CInt = t.CInt(bfinal_val) - btype: t.CInt = t.CInt(btype_val) - if btype == 0: - err = self.inflate_block_stored() - elif btype == 1: - err = self.inflate_block_fixed() - elif btype == 2: - err = self.inflate_block_dynamic() - else: - return -3 - if err != 0: return err - if bfinal: self.is_finished = 1 - if self.max_length > 0 and self.output_len >= self.max_length: return 0 - if self.is_gzip: - if self.reader.bit_pos != 0: - self.reader.bit_pos = 0 - self.input_pos += 1 - if self.input_pos + 8 <= self.input_len: - self.crc = ((t.CUInt32T(self.input_data[self.input_pos + 0]) << 0) | - (t.CUInt32T(self.input_data[self.input_pos + 1]) << 8) | - (t.CUInt32T(self.input_data[self.input_pos + 2]) << 16) | - (t.CUInt32T(self.input_data[self.input_pos + 3]) << 24)) - self.input_pos += 8 - elif self.wbits >= 0: - if self.reader.bit_pos != 0: - self.reader.bit_pos = 0 - self.input_pos += 1 - if self.input_pos + 4 <= self.input_len: - self.adler = ((t.CUInt32T(self.input_data[self.input_pos + 0]) << 24) | - (t.CUInt32T(self.input_data[self.input_pos + 1]) << 16) | - (t.CUInt32T(self.input_data[self.input_pos + 2]) << 8) | - (t.CUInt32T(self.input_data[self.input_pos + 3]) << 0)) - self.input_pos += 4 - return 0 - - def decompress(self, data: UINT8PTR, length: t.CSizeT, - max_length: t.CSizeT, out: t.CUInt8T | t.CPtr[t.CPtr], out_len: t.CSizeT | t.CPtr) -> t.CInt: - if not self.is_initialized: return -2 - self.input_data = data - self.input_len = length - self.input_pos = 0 - self.reader.bit_pos = 0 - self.output_len = 0 - self.max_length = max_length - err: t.CInt = self.inflate_stream() - if err != 0: return err - c.Set(c.Deref(out_len), self.output_len) - if self.output_len == 0: - c.Set(c.Deref(out), UINT8PTR(zdef.zdef_alloc(1))) - else: - dst: UINT8PTR = UINT8PTR(zdef.zdef_alloc(self.output_len)) - c.Set(c.Deref(out), dst) - if dst: - memcpy(dst, self.output, self.output_len) - return 0 - - def set_dictionary(self, dict: UINT8PTR, length: t.CSizeT) -> t.CInt: - if not dict: return -2 - use: t.CSizeT = length - if use > zdef.ZDEFLATE_WINDOW_SIZE: - dict += length - zdef.ZDEFLATE_WINDOW_SIZE - use = zdef.ZDEFLATE_WINDOW_SIZE - memcpy(self.window, dict, use) - self.window_pos = t.CInt(use) - return 0 - - def copy(self) -> zinflate_stream | t.CPtr: - z: zinflate_stream | t.CPtr = zdef.zdef_alloc(zinflate_stream.__sizeof__()) - if not z: return None - memcpy(z, self, zinflate_stream.__sizeof__()) - z.window = BYTEPTR(zdef.zdef_alloc(zdef.ZDEFLATE_WINDOW_SIZE)) - z.output = BYTEPTR(zdef.zdef_alloc(self.output_cap)) - if not z.window or not z.output: - zinflate_stream.destroy(z) - return None - memcpy(z.window, self.window, zdef.ZDEFLATE_WINDOW_SIZE) - memcpy(z.output, self.output, self.output_cap) - return z - - def destroy(self): - if not self: return - if self.window: zdef.zdef_free(self.window) - if self.output: zdef.zdef_free(self.output) - zdef.zdef_free(self) - - -def zinflate_one_shot(data: UINT8PTR, length: t.CSizeT, - wbits: t.CInt, bufsize: t.CSizeT, out_len: t.CSizeT | t.CPtr) -> t.CUInt8T | t.CPtr: - s: zinflate_stream | t.CPtr = zinflate_create(wbits) - if not s: return None - out: t.CUInt8T | t.CPtr = None - err: t.CInt = s.decompress(data, length, 0, c.Addr(out), out_len) - s.destroy() - if err != 0: return None - return out - - -def zinflate_create(wbits: t.CInt) -> zinflate_stream | t.CPtr: - s: zinflate_stream | t.CPtr = zdef.zdef_alloc(zinflate_stream.__sizeof__()) - if not s: return None - memset(s, 0, zinflate_stream.__sizeof__()) - s.wbits = wbits - s.is_initialized = 1 - s.adler = 1 - s.window = BYTEPTR(zdef.zdef_alloc(zdef.ZDEFLATE_WINDOW_SIZE)) - s.output = BYTEPTR(zdef.zdef_alloc(256)) - s.output_cap = 256 - s.output_len = 0 - s.max_length = 0 - if not s.window or not s.output: - s.destroy() - return None - return s diff --git a/Test/TestProject/App/test_zlib.py b/Test/TestProject/App/test_zlib.py index 3961883..9441a04 100644 --- a/Test/TestProject/App/test_zlib.py +++ b/Test/TestProject/App/test_zlib.py @@ -2,7 +2,9 @@ from stdint import * import zlib.pyzlib as pyzlib import zlib.zhuff as zhuff import zlib.zdef as zdef -from stdio import printf, strlen +from stdio import printf +from string import strlen, memcmp, memcpy, memset +from stdlib import malloc, free, realloc import stdlib import string import mpool diff --git a/Test/TestProject/output/067c78e9f121dce3.deps.json b/Test/TestProject/output/067c78e9f121dce3.deps.json index 52dd90d..b16da63 100644 --- a/Test/TestProject/output/067c78e9f121dce3.deps.json +++ b/Test/TestProject/output/067c78e9f121dce3.deps.json @@ -1 +1 @@ -{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3d1656b26b38b359", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "zlib.__init__": "d63d2c2a2bd9bd2a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3"} \ No newline at end of file +{"test_zlib": "0c04ab530bb9cfa4", "hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "BINASCII": "8f88a3374d5335cc", "vipermath": "3f7c5e78d8652535", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "base64": "4bf3e0150b9e02e9", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdio": "73edbcf76e32d00b", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "binascii": "8f88a3374d5335cc", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "c3eb91093118e1e1", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3"} \ No newline at end of file diff --git a/Test/TestProject/output/439f5b503003443f.deps.json b/Test/TestProject/output/0c04ab530bb9cfa4.deps.json similarity index 54% rename from Test/TestProject/output/439f5b503003443f.deps.json rename to Test/TestProject/output/0c04ab530bb9cfa4.deps.json index 1932abc..33f0073 100644 --- a/Test/TestProject/output/439f5b503003443f.deps.json +++ b/Test/TestProject/output/0c04ab530bb9cfa4.deps.json @@ -1 +1 @@ -{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3ee89b588a1da94f", "vipermath": "3f7c5e78d8652535", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "c3eb91093118e1e1", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2"} \ No newline at end of file +{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "BINASCII": "3ee89b588a1da94f", "vipermath": "3f7c5e78d8652535", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "base64": "4bf3e0150b9e02e9", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdio": "73edbcf76e32d00b", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "binascii": "8f88a3374d5335cc", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "c3eb91093118e1e1", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2"} \ No newline at end of file diff --git a/Test/TestProject/output/0d13cde396f4a15f.deps.json b/Test/TestProject/output/0d13cde396f4a15f.deps.json index d33054c..1343411 100644 --- a/Test/TestProject/output/0d13cde396f4a15f.deps.json +++ b/Test/TestProject/output/0d13cde396f4a15f.deps.json @@ -1 +1 @@ -{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3ee89b588a1da94f", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f"} \ No newline at end of file +{"test_zlib": "0c04ab530bb9cfa4", "hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "BINASCII": "8f88a3374d5335cc", "vipermath": "3f7c5e78d8652535", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "base64": "4bf3e0150b9e02e9", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdio": "73edbcf76e32d00b", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "binascii": "8f88a3374d5335cc", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f"} \ No newline at end of file diff --git a/Test/TestProject/output/0d4517fd5afeb330.deps.json b/Test/TestProject/output/0d4517fd5afeb330.deps.json index 6a762c7..d8eb6a9 100644 --- a/Test/TestProject/output/0d4517fd5afeb330.deps.json +++ b/Test/TestProject/output/0d4517fd5afeb330.deps.json @@ -1 +1 @@ -{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3ee89b588a1da94f", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330"} \ No newline at end of file +{"test_zlib": "0c04ab530bb9cfa4", "hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "BINASCII": "8f88a3374d5335cc", "vipermath": "3f7c5e78d8652535", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "base64": "4bf3e0150b9e02e9", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdio": "73edbcf76e32d00b", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "binascii": "8f88a3374d5335cc", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330"} \ No newline at end of file diff --git a/Test/TestProject/output/29813d57621099a9.deps.json b/Test/TestProject/output/29813d57621099a9.deps.json index 94efaa6..3d535c3 100644 --- a/Test/TestProject/output/29813d57621099a9.deps.json +++ b/Test/TestProject/output/29813d57621099a9.deps.json @@ -1 +1 @@ -{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3d1656b26b38b359", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "zlib.__init__": "d63d2c2a2bd9bd2a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file +{"test_zlib": "0c04ab530bb9cfa4", "hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "BINASCII": "8f88a3374d5335cc", "vipermath": "3f7c5e78d8652535", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "base64": "4bf3e0150b9e02e9", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdio": "73edbcf76e32d00b", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "binascii": "8f88a3374d5335cc", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "c3eb91093118e1e1", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file diff --git a/Test/TestProject/output/2d7f623c6e3004ce.deps.json b/Test/TestProject/output/2d7f623c6e3004ce.deps.json index 94efaa6..ef1d5e7 100644 --- a/Test/TestProject/output/2d7f623c6e3004ce.deps.json +++ b/Test/TestProject/output/2d7f623c6e3004ce.deps.json @@ -1 +1 @@ -{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3d1656b26b38b359", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "zlib.__init__": "d63d2c2a2bd9bd2a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file +{"test_zlib": "0c04ab530bb9cfa4", "hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "BINASCII": "8f88a3374d5335cc", "vipermath": "3f7c5e78d8652535", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "base64": "4bf3e0150b9e02e9", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdio": "73edbcf76e32d00b", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "binascii": "8f88a3374d5335cc", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "d63d2c2a2bd9bd2a", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9", "zlib.__init__": "d63d2c2a2bd9bd2a"} \ No newline at end of file diff --git a/Test/TestProject/output/2e756dd336749fc2.deps.json b/Test/TestProject/output/2e756dd336749fc2.deps.json index 4690763..a9ee6fb 100644 --- a/Test/TestProject/output/2e756dd336749fc2.deps.json +++ b/Test/TestProject/output/2e756dd336749fc2.deps.json @@ -1 +1 @@ -{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "binascii": "3d1656b26b38b359", "BINASCII": "3ee89b588a1da94f", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "c3eb91093118e1e1", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2"} \ No newline at end of file +{"test_zlib": "0c04ab530bb9cfa4", "hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "BINASCII": "3ee89b588a1da94f", "vipermath": "3f7c5e78d8652535", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "base64": "4bf3e0150b9e02e9", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdio": "73edbcf76e32d00b", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "binascii": "8f88a3374d5335cc", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "c3eb91093118e1e1", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2"} \ No newline at end of file diff --git a/Test/TestProject/output/3d1656b26b38b359.deps.json b/Test/TestProject/output/3d1656b26b38b359.deps.json deleted file mode 100644 index 12b6ecc..0000000 --- a/Test/TestProject/output/3d1656b26b38b359.deps.json +++ /dev/null @@ -1 +0,0 @@ -{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3d1656b26b38b359", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "zlib.__init__": "d63d2c2a2bd9bd2a"} \ No newline at end of file diff --git a/Test/TestProject/output/3ee89b588a1da94f.deps.json b/Test/TestProject/output/3ee89b588a1da94f.deps.json index 942ae4b..93da396 100644 --- a/Test/TestProject/output/3ee89b588a1da94f.deps.json +++ b/Test/TestProject/output/3ee89b588a1da94f.deps.json @@ -1 +1 @@ -{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "c3eb91093118e1e1", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2"} \ No newline at end of file +{"test_zlib": "0c04ab530bb9cfa4", "hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "vipermath": "3f7c5e78d8652535", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "base64": "4bf3e0150b9e02e9", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdio": "73edbcf76e32d00b", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "binascii": "8f88a3374d5335cc", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "c3eb91093118e1e1", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2"} \ No newline at end of file diff --git a/Test/TestProject/output/3f7c5e78d8652535.deps.json b/Test/TestProject/output/3f7c5e78d8652535.deps.json index 81827d5..83b79bc 100644 --- a/Test/TestProject/output/3f7c5e78d8652535.deps.json +++ b/Test/TestProject/output/3f7c5e78d8652535.deps.json @@ -1 +1 @@ -{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3ee89b588a1da94f", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653"} \ No newline at end of file +{"test_zlib": "0c04ab530bb9cfa4", "hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "BINASCII": "8f88a3374d5335cc", "vipermath": "3f7c5e78d8652535", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "base64": "4bf3e0150b9e02e9", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdio": "73edbcf76e32d00b", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "binascii": "8f88a3374d5335cc", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653"} \ No newline at end of file diff --git a/Test/TestProject/output/4638d411fd53fef0.deps.json b/Test/TestProject/output/4638d411fd53fef0.deps.json index 94efaa6..ef1d5e7 100644 --- a/Test/TestProject/output/4638d411fd53fef0.deps.json +++ b/Test/TestProject/output/4638d411fd53fef0.deps.json @@ -1 +1 @@ -{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3d1656b26b38b359", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "zlib.__init__": "d63d2c2a2bd9bd2a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file +{"test_zlib": "0c04ab530bb9cfa4", "hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "BINASCII": "8f88a3374d5335cc", "vipermath": "3f7c5e78d8652535", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "base64": "4bf3e0150b9e02e9", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdio": "73edbcf76e32d00b", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "binascii": "8f88a3374d5335cc", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "d63d2c2a2bd9bd2a", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9", "zlib.__init__": "d63d2c2a2bd9bd2a"} \ No newline at end of file diff --git a/Test/TestProject/output/4bf3e0150b9e02e9.deps.json b/Test/TestProject/output/4bf3e0150b9e02e9.deps.json new file mode 100644 index 0000000..83b79bc --- /dev/null +++ b/Test/TestProject/output/4bf3e0150b9e02e9.deps.json @@ -0,0 +1 @@ +{"test_zlib": "0c04ab530bb9cfa4", "hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "BINASCII": "8f88a3374d5335cc", "vipermath": "3f7c5e78d8652535", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "base64": "4bf3e0150b9e02e9", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdio": "73edbcf76e32d00b", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "binascii": "8f88a3374d5335cc", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653"} \ No newline at end of file diff --git a/Test/TestProject/output/58121a0fb0ca7466.deps.json b/Test/TestProject/output/58121a0fb0ca7466.deps.json index c84d4ea..a7b9b5c 100644 --- a/Test/TestProject/output/58121a0fb0ca7466.deps.json +++ b/Test/TestProject/output/58121a0fb0ca7466.deps.json @@ -1 +1 @@ -{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3ee89b588a1da94f", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "c3eb91093118e1e1", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653"} \ No newline at end of file +{"test_zlib": "0c04ab530bb9cfa4", "hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "BINASCII": "3ee89b588a1da94f", "vipermath": "3f7c5e78d8652535", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "base64": "4bf3e0150b9e02e9", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdio": "73edbcf76e32d00b", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "binascii": "8f88a3374d5335cc", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "c3eb91093118e1e1", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653"} \ No newline at end of file diff --git a/Test/TestProject/output/5a6a2137958c28c5.deps.json b/Test/TestProject/output/5a6a2137958c28c5.deps.json index 5d7d4f0..0e72337 100644 --- a/Test/TestProject/output/5a6a2137958c28c5.deps.json +++ b/Test/TestProject/output/5a6a2137958c28c5.deps.json @@ -1 +1 @@ -{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3d1656b26b38b359", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "zlib.__init__": "d63d2c2a2bd9bd2a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file +{"test_zlib": "0c04ab530bb9cfa4", "hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "BINASCII": "8f88a3374d5335cc", "vipermath": "3f7c5e78d8652535", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "base64": "4bf3e0150b9e02e9", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdio": "73edbcf76e32d00b", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "binascii": "8f88a3374d5335cc", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "c3eb91093118e1e1", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/TestProject/output/68c4fe4b12c908e3.deps.json b/Test/TestProject/output/68c4fe4b12c908e3.deps.json index 94efaa6..83b79bc 100644 --- a/Test/TestProject/output/68c4fe4b12c908e3.deps.json +++ b/Test/TestProject/output/68c4fe4b12c908e3.deps.json @@ -1 +1 @@ -{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3d1656b26b38b359", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "zlib.__init__": "d63d2c2a2bd9bd2a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file +{"test_zlib": "0c04ab530bb9cfa4", "hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "BINASCII": "8f88a3374d5335cc", "vipermath": "3f7c5e78d8652535", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "base64": "4bf3e0150b9e02e9", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdio": "73edbcf76e32d00b", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "binascii": "8f88a3374d5335cc", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653"} \ No newline at end of file diff --git a/Test/TestProject/output/6aee24fdefa3cbc0.deps.json b/Test/TestProject/output/6aee24fdefa3cbc0.deps.json index 12b6ecc..83b79bc 100644 --- a/Test/TestProject/output/6aee24fdefa3cbc0.deps.json +++ b/Test/TestProject/output/6aee24fdefa3cbc0.deps.json @@ -1 +1 @@ -{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3d1656b26b38b359", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "zlib.__init__": "d63d2c2a2bd9bd2a"} \ No newline at end of file +{"test_zlib": "0c04ab530bb9cfa4", "hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "BINASCII": "8f88a3374d5335cc", "vipermath": "3f7c5e78d8652535", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "base64": "4bf3e0150b9e02e9", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdio": "73edbcf76e32d00b", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "binascii": "8f88a3374d5335cc", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653"} \ No newline at end of file diff --git a/Test/TestProject/output/72e2d5ccb7cedcf1.deps.json b/Test/TestProject/output/72e2d5ccb7cedcf1.deps.json index f57fb55..da2931b 100644 --- a/Test/TestProject/output/72e2d5ccb7cedcf1.deps.json +++ b/Test/TestProject/output/72e2d5ccb7cedcf1.deps.json @@ -1 +1 @@ -{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3d1656b26b38b359", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "zlib.__init__": "d63d2c2a2bd9bd2a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1"} \ No newline at end of file +{"test_zlib": "0c04ab530bb9cfa4", "hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "BINASCII": "8f88a3374d5335cc", "vipermath": "3f7c5e78d8652535", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "base64": "4bf3e0150b9e02e9", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdio": "73edbcf76e32d00b", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "binascii": "8f88a3374d5335cc", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "c3eb91093118e1e1", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1"} \ No newline at end of file diff --git a/Test/TestProject/output/7e4cef8dd61984f0.deps.json b/Test/TestProject/output/7e4cef8dd61984f0.deps.json deleted file mode 100644 index 94efaa6..0000000 --- a/Test/TestProject/output/7e4cef8dd61984f0.deps.json +++ /dev/null @@ -1 +0,0 @@ -{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3d1656b26b38b359", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "zlib.__init__": "d63d2c2a2bd9bd2a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file diff --git a/Test/TestProject/output/88e3e48eab9e1653.deps.json b/Test/TestProject/output/88e3e48eab9e1653.deps.json index 81827d5..83b79bc 100644 --- a/Test/TestProject/output/88e3e48eab9e1653.deps.json +++ b/Test/TestProject/output/88e3e48eab9e1653.deps.json @@ -1 +1 @@ -{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3ee89b588a1da94f", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653"} \ No newline at end of file +{"test_zlib": "0c04ab530bb9cfa4", "hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "BINASCII": "8f88a3374d5335cc", "vipermath": "3f7c5e78d8652535", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "base64": "4bf3e0150b9e02e9", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdio": "73edbcf76e32d00b", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "binascii": "8f88a3374d5335cc", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653"} \ No newline at end of file diff --git a/Test/TestProject/output/8e0d8fdba991b3b4.deps.json b/Test/TestProject/output/8e0d8fdba991b3b4.deps.json index ad7c768..d8f67bb 100644 --- a/Test/TestProject/output/8e0d8fdba991b3b4.deps.json +++ b/Test/TestProject/output/8e0d8fdba991b3b4.deps.json @@ -1 +1 @@ -{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3ee89b588a1da94f", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "c3eb91093118e1e1", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2"} \ No newline at end of file +{"test_zlib": "0c04ab530bb9cfa4", "hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "BINASCII": "3ee89b588a1da94f", "vipermath": "3f7c5e78d8652535", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "base64": "4bf3e0150b9e02e9", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdio": "73edbcf76e32d00b", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "binascii": "8f88a3374d5335cc", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "c3eb91093118e1e1", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2"} \ No newline at end of file diff --git a/Test/TestProject/output/8f88a3374d5335cc.deps.json b/Test/TestProject/output/8f88a3374d5335cc.deps.json new file mode 100644 index 0000000..5d3e5fd --- /dev/null +++ b/Test/TestProject/output/8f88a3374d5335cc.deps.json @@ -0,0 +1 @@ +{"test_zlib": "0c04ab530bb9cfa4", "hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "BINASCII": "8f88a3374d5335cc", "vipermath": "3f7c5e78d8652535", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "base64": "4bf3e0150b9e02e9", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdio": "73edbcf76e32d00b", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "binascii": "8f88a3374d5335cc", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "c3eb91093118e1e1", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2"} \ No newline at end of file diff --git a/Test/TestProject/output/94496ec50b0d13fc.deps.json b/Test/TestProject/output/94496ec50b0d13fc.deps.json index e296236..d676e78 100644 --- a/Test/TestProject/output/94496ec50b0d13fc.deps.json +++ b/Test/TestProject/output/94496ec50b0d13fc.deps.json @@ -1 +1 @@ -{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3ee89b588a1da94f", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc"} \ No newline at end of file +{"test_zlib": "0c04ab530bb9cfa4", "hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "BINASCII": "8f88a3374d5335cc", "vipermath": "3f7c5e78d8652535", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "base64": "4bf3e0150b9e02e9", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdio": "73edbcf76e32d00b", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "binascii": "8f88a3374d5335cc", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc"} \ No newline at end of file diff --git a/Test/TestProject/output/a9fa0f6200c09e65.deps.json b/Test/TestProject/output/a9fa0f6200c09e65.deps.json index 94efaa6..ef1d5e7 100644 --- a/Test/TestProject/output/a9fa0f6200c09e65.deps.json +++ b/Test/TestProject/output/a9fa0f6200c09e65.deps.json @@ -1 +1 @@ -{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3d1656b26b38b359", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "zlib.__init__": "d63d2c2a2bd9bd2a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file +{"test_zlib": "0c04ab530bb9cfa4", "hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "BINASCII": "8f88a3374d5335cc", "vipermath": "3f7c5e78d8652535", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "base64": "4bf3e0150b9e02e9", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdio": "73edbcf76e32d00b", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "binascii": "8f88a3374d5335cc", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "d63d2c2a2bd9bd2a", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9", "zlib.__init__": "d63d2c2a2bd9bd2a"} \ No newline at end of file diff --git a/Test/TestProject/output/abf9ce3160c9279e.deps.json b/Test/TestProject/output/abf9ce3160c9279e.deps.json index 9c8f69c..a56224b 100644 --- a/Test/TestProject/output/abf9ce3160c9279e.deps.json +++ b/Test/TestProject/output/abf9ce3160c9279e.deps.json @@ -1 +1 @@ -{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3d1656b26b38b359", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "zlib.__init__": "d63d2c2a2bd9bd2a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e"} \ No newline at end of file +{"test_zlib": "0c04ab530bb9cfa4", "hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "BINASCII": "8f88a3374d5335cc", "vipermath": "3f7c5e78d8652535", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "base64": "4bf3e0150b9e02e9", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdio": "73edbcf76e32d00b", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "binascii": "8f88a3374d5335cc", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "c3eb91093118e1e1", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e"} \ No newline at end of file diff --git a/Test/TestProject/output/b0267503e816efc4.deps.json b/Test/TestProject/output/b0267503e816efc4.deps.json index 94efaa6..ef1d5e7 100644 --- a/Test/TestProject/output/b0267503e816efc4.deps.json +++ b/Test/TestProject/output/b0267503e816efc4.deps.json @@ -1 +1 @@ -{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3d1656b26b38b359", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "zlib.__init__": "d63d2c2a2bd9bd2a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file +{"test_zlib": "0c04ab530bb9cfa4", "hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "BINASCII": "8f88a3374d5335cc", "vipermath": "3f7c5e78d8652535", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "base64": "4bf3e0150b9e02e9", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdio": "73edbcf76e32d00b", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "binascii": "8f88a3374d5335cc", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "d63d2c2a2bd9bd2a", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9", "zlib.__init__": "d63d2c2a2bd9bd2a"} \ No newline at end of file diff --git a/Test/TestProject/output/ba2e1c2dfc8e2f85.deps.json b/Test/TestProject/output/ba2e1c2dfc8e2f85.deps.json index 7338a29..28ea2c2 100644 --- a/Test/TestProject/output/ba2e1c2dfc8e2f85.deps.json +++ b/Test/TestProject/output/ba2e1c2dfc8e2f85.deps.json @@ -1 +1 @@ -{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3ee89b588a1da94f", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "c3eb91093118e1e1", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2"} \ No newline at end of file +{"test_zlib": "0c04ab530bb9cfa4", "hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "BINASCII": "3ee89b588a1da94f", "vipermath": "3f7c5e78d8652535", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "base64": "4bf3e0150b9e02e9", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdio": "73edbcf76e32d00b", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "binascii": "8f88a3374d5335cc", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "c3eb91093118e1e1", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2"} \ No newline at end of file diff --git a/Test/TestProject/output/bbdf3bbd4c3bc28c.deps.json b/Test/TestProject/output/bbdf3bbd4c3bc28c.deps.json index 5d7d4f0..0e72337 100644 --- a/Test/TestProject/output/bbdf3bbd4c3bc28c.deps.json +++ b/Test/TestProject/output/bbdf3bbd4c3bc28c.deps.json @@ -1 +1 @@ -{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3d1656b26b38b359", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "zlib.__init__": "d63d2c2a2bd9bd2a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file +{"test_zlib": "0c04ab530bb9cfa4", "hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "BINASCII": "8f88a3374d5335cc", "vipermath": "3f7c5e78d8652535", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "base64": "4bf3e0150b9e02e9", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdio": "73edbcf76e32d00b", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "binascii": "8f88a3374d5335cc", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "c3eb91093118e1e1", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/TestProject/output/c3eb91093118e1e1.deps.json b/Test/TestProject/output/c3eb91093118e1e1.deps.json index 827d74a..0a3191e 100644 --- a/Test/TestProject/output/c3eb91093118e1e1.deps.json +++ b/Test/TestProject/output/c3eb91093118e1e1.deps.json @@ -1 +1 @@ -{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3d1656b26b38b359", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "c3eb91093118e1e1", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "zlib.__init__": "d63d2c2a2bd9bd2a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file +{"test_zlib": "0c04ab530bb9cfa4", "hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "BINASCII": "8f88a3374d5335cc", "vipermath": "3f7c5e78d8652535", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "base64": "4bf3e0150b9e02e9", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdio": "73edbcf76e32d00b", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "binascii": "8f88a3374d5335cc", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "c3eb91093118e1e1", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653"} \ No newline at end of file diff --git a/Test/TestProject/output/c9f4be41ca1cc2b4.deps.json b/Test/TestProject/output/c9f4be41ca1cc2b4.deps.json index 12b6ecc..83b79bc 100644 --- a/Test/TestProject/output/c9f4be41ca1cc2b4.deps.json +++ b/Test/TestProject/output/c9f4be41ca1cc2b4.deps.json @@ -1 +1 @@ -{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3d1656b26b38b359", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "zlib.__init__": "d63d2c2a2bd9bd2a"} \ No newline at end of file +{"test_zlib": "0c04ab530bb9cfa4", "hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "BINASCII": "8f88a3374d5335cc", "vipermath": "3f7c5e78d8652535", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "base64": "4bf3e0150b9e02e9", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdio": "73edbcf76e32d00b", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "binascii": "8f88a3374d5335cc", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653"} \ No newline at end of file diff --git a/Test/TestProject/output/d282a7cb3385ecf0.deps.json b/Test/TestProject/output/d282a7cb3385ecf0.deps.json index 94efaa6..ef1d5e7 100644 --- a/Test/TestProject/output/d282a7cb3385ecf0.deps.json +++ b/Test/TestProject/output/d282a7cb3385ecf0.deps.json @@ -1 +1 @@ -{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3d1656b26b38b359", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "zlib.__init__": "d63d2c2a2bd9bd2a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file +{"test_zlib": "0c04ab530bb9cfa4", "hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "BINASCII": "8f88a3374d5335cc", "vipermath": "3f7c5e78d8652535", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "base64": "4bf3e0150b9e02e9", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdio": "73edbcf76e32d00b", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "binascii": "8f88a3374d5335cc", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "d63d2c2a2bd9bd2a", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9", "zlib.__init__": "d63d2c2a2bd9bd2a"} \ No newline at end of file diff --git a/Test/TestProject/output/f9629b8eb4ebdcc2.deps.json b/Test/TestProject/output/f9629b8eb4ebdcc2.deps.json index 94efaa6..ef1d5e7 100644 --- a/Test/TestProject/output/f9629b8eb4ebdcc2.deps.json +++ b/Test/TestProject/output/f9629b8eb4ebdcc2.deps.json @@ -1 +1 @@ -{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3d1656b26b38b359", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "zlib.__init__": "d63d2c2a2bd9bd2a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file +{"test_zlib": "0c04ab530bb9cfa4", "hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "BINASCII": "8f88a3374d5335cc", "vipermath": "3f7c5e78d8652535", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "base64": "4bf3e0150b9e02e9", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdio": "73edbcf76e32d00b", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "binascii": "8f88a3374d5335cc", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "d63d2c2a2bd9bd2a", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9", "zlib.__init__": "d63d2c2a2bd9bd2a"} \ No newline at end of file diff --git a/Test/TestProject/output/fa3691e66b426950.deps.json b/Test/TestProject/output/fa3691e66b426950.deps.json index 5d7d4f0..0e72337 100644 --- a/Test/TestProject/output/fa3691e66b426950.deps.json +++ b/Test/TestProject/output/fa3691e66b426950.deps.json @@ -1 +1 @@ -{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3d1656b26b38b359", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "zlib.__init__": "d63d2c2a2bd9bd2a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file +{"test_zlib": "0c04ab530bb9cfa4", "hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "BINASCII": "8f88a3374d5335cc", "vipermath": "3f7c5e78d8652535", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "base64": "4bf3e0150b9e02e9", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdio": "73edbcf76e32d00b", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "binascii": "8f88a3374d5335cc", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "c3eb91093118e1e1", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/TestProject/temp/439f5b503003443f.pyi b/Test/TestProject/temp/0c04ab530bb9cfa4.pyi similarity index 92% rename from Test/TestProject/temp/439f5b503003443f.pyi rename to Test/TestProject/temp/0c04ab530bb9cfa4.pyi index 259fce6..e520473 100644 --- a/Test/TestProject/temp/439f5b503003443f.pyi +++ b/Test/TestProject/temp/0c04ab530bb9cfa4.pyi @@ -8,7 +8,9 @@ from stdint import * import zlib.pyzlib as pyzlib import zlib.zhuff as zhuff import zlib.zdef as zdef -from stdio import printf, strlen +from stdio import printf +from string import strlen, memcmp, memcpy, memset +from stdlib import malloc, free, realloc import stdlib import string import mpool diff --git a/Test/TestProject/temp/7e4cef8dd61984f0.pyi b/Test/TestProject/temp/4bf3e0150b9e02e9.pyi similarity index 94% rename from Test/TestProject/temp/7e4cef8dd61984f0.pyi rename to Test/TestProject/temp/4bf3e0150b9e02e9.pyi index d5c249f..bd213f3 100644 --- a/Test/TestProject/temp/7e4cef8dd61984f0.pyi +++ b/Test/TestProject/temp/4bf3e0150b9e02e9.pyi @@ -4,7 +4,6 @@ Module: base64 """ -import binascii import t, c b64_tab: t.CExtern | list[t.CChar, None] diff --git a/Test/TestProject/temp/6c2029b306556c00.pyi b/Test/TestProject/temp/6c2029b306556c00.pyi new file mode 100644 index 0000000..98da680 --- /dev/null +++ b/Test/TestProject/temp/6c2029b306556c00.pyi @@ -0,0 +1,18 @@ +""" +Auto-generated Python stub file from stdlib.py +Module: stdlib +""" + +import c + + +from stdint import * +import t + +def malloc(size: t.CSizeT) -> t.CVoid | t.CPtr | t.State | t.CExtern | t.CExport: pass + +def calloc(nmemb: t.CSizeT, size: t.CSizeT) -> t.CVoid | t.CPtr | t.State | t.CExtern | t.CExport: pass + +def realloc(p: t.CVoid | t.CPtr, size: t.CSizeT) -> t.CVoid | t.CPtr | t.State | t.CExtern | t.CExport: pass + +def free(p: t.CVoid | t.CPtr) -> None | t.State | t.CExtern | t.CExport: pass diff --git a/Test/TestProject/temp/7538e542cab4c1d5.pyi b/Test/TestProject/temp/7538e542cab4c1d5.pyi deleted file mode 100644 index b5313af..0000000 --- a/Test/TestProject/temp/7538e542cab4c1d5.pyi +++ /dev/null @@ -1,18 +0,0 @@ -""" -Auto-generated Python stub file from stdlib.py -Module: stdlib -""" - -import c - - -from stdint import * -import t - -def malloc(size: UINT) -> t.CVoid | t.CPtr | t.State | t.CExtern | t.CExport: pass - -def calloc(nmemb: UINT, size: UINT) -> t.CVoid | t.CPtr | t.State | t.CExtern | t.CExport: pass - -def realloc(p: str, p2: t.CLong | t.CLong) -> t.CVoid | t.CPtr | t.State | t.CExtern | t.CExport: pass - -def free(p: t.CVoid | t.CPtr) -> None | t.State | t.CExtern | t.CExport: pass diff --git a/Test/TestProject/temp/3d1656b26b38b359.pyi b/Test/TestProject/temp/8f88a3374d5335cc.pyi similarity index 98% rename from Test/TestProject/temp/3d1656b26b38b359.pyi rename to Test/TestProject/temp/8f88a3374d5335cc.pyi index 6b4a08a..374b741 100644 --- a/Test/TestProject/temp/3d1656b26b38b359.pyi +++ b/Test/TestProject/temp/8f88a3374d5335cc.pyi @@ -5,7 +5,6 @@ Module: binascii import t, c -import stdint HEX_CHARS: t.CExtern | list[t.CChar, None] HEX_VALS: t.CExtern | list[t.CInt, 256] diff --git a/Test/TestProject/temp/_sha1_map.txt b/Test/TestProject/temp/_sha1_map.txt index 634b5ca..eefe6e8 100644 --- a/Test/TestProject/temp/_sha1_map.txt +++ b/Test/TestProject/temp/_sha1_map.txt @@ -1,22 +1,22 @@ +0c04ab530bb9cfa4:test_zlib.py 0d13cde396f4a15f:includes/hashlib\__sha1.py 0d4517fd5afeb330:includes/hashlib\__sha256.py 2d7f623c6e3004ce:includes/zlib\zdeflate.py 2e756dd336749fc2:test_numpy.py -3d1656b26b38b359:includes/binascii.py 3ee89b588a1da94f:BINASCII.py 3f7c5e78d8652535:includes/vipermath.py -439f5b503003443f:test_zlib.py 4638d411fd53fef0:includes/zlib\zchecksum.py +4bf3e0150b9e02e9:includes/base64.py 56cdd754a8a09347:includes/stdint.py 58121a0fb0ca7466:main.py 5a6a2137958c28c5:includes/w32\win32base.py 68c4fe4b12c908e3:includes/mpool.py 6aee24fdefa3cbc0:includes/string.py +6c2029b306556c00:includes/stdlib.py 73edbcf76e32d00b:includes/stdio.py -7538e542cab4c1d5:includes/stdlib.py -7e4cef8dd61984f0:includes/base64.py 88e3e48eab9e1653:includes/hashlib\__sha512.py 8e0d8fdba991b3b4:config.py +8f88a3374d5335cc:includes/binascii.py 94496ec50b0d13fc:includes/hashlib\__md5.py 96837bcc64032444:includes/hashlib\__init__.py a9fa0f6200c09e65:includes/zlib\zdef.py diff --git a/Test/TestProject/temp/_shared_sym.pkl b/Test/TestProject/temp/_shared_sym.pkl index e38d1e8541b46f5f6dc4388a51f1a3dc9d36892f..fa9d5e7ec3c202609f6aa520a8ccdbf2cd218a78 100644 GIT binary patch literal 730114 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�Am@{9A6RgLN*ufbISA6pZk1yW!>O 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 diff --git a/Test/TestProject2/project.json b/Test/TestProject2/project.json index aa634e2..d16b2c0 100644 --- a/Test/TestProject2/project.json +++ b/Test/TestProject2/project.json @@ -17,6 +17,10 @@ "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", diff --git a/Test/TestProject2/temp/09ba6d4617920d26.pyi b/Test/TestProject2/temp/09ba6d4617920d26.pyi index 65f16df..bb148a9 100644 --- a/Test/TestProject2/temp/09ba6d4617920d26.pyi +++ b/Test/TestProject2/temp/09ba6d4617920d26.pyi @@ -14,4 +14,4 @@ import zc.test as test import zc.logic_test as logic import zc.class_test as class_test -def main() -> stdint.INT | t.State: pass +def main() -> stdint.INT: pass diff --git a/Test/TestProject2/temp/73edbcf76e32d00b.pyi b/Test/TestProject2/temp/73edbcf76e32d00b.pyi index 0b25044..ef712e3 100644 --- a/Test/TestProject2/temp/73edbcf76e32d00b.pyi +++ b/Test/TestProject2/temp/73edbcf76e32d00b.pyi @@ -6,21 +6,21 @@ Module: stdio import t, c -def printf(fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport | t.State: pass +def printf(fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass -def fprintf(stream: t.CVoid | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport | t.State: pass +def fprintf(stream: t.CVoid | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass -def sprintf(buf: t.CChar | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport | t.State: pass +def sprintf(buf: t.CChar | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass -def snprintf(buf: t.CChar | t.CPtr, size: t.CSizeT, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport | t.State: pass +def snprintf(buf: t.CChar | t.CPtr, size: t.CSizeT, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass -def puts(s: t.CChar | t.CConst | t.CPtr) -> t.CInt | t.CExtern | t.CExport | t.State: pass +def puts(s: t.CChar | t.CConst | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass -def fputs(s: t.CChar | t.CConst | t.CPtr, stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport | t.State: pass +def fputs(s: t.CChar | t.CConst | t.CPtr, stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass -def fgets(buf: t.CChar | t.CPtr, size: t.CInt, stream: t.CVoid | t.CPtr) -> t.CChar | t.CPtr | t.CExtern | t.CExport | t.State: pass +def fgets(buf: t.CChar | t.CPtr, size: t.CInt, stream: t.CVoid | t.CPtr) -> t.CChar | t.CPtr | t.CExtern | t.CExport: pass -def fflush(stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport | t.State: pass +def fflush(stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass stdin: t.CExtern | t.CVoid | t.CPtr diff --git a/Test/TestProject2/temp/75583f20a922ab2e.pyi b/Test/TestProject2/temp/75583f20a922ab2e.pyi index 8a40bd2..10da71f 100644 --- a/Test/TestProject2/temp/75583f20a922ab2e.pyi +++ b/Test/TestProject2/temp/75583f20a922ab2e.pyi @@ -7,32 +7,32 @@ Module: zc.test import config import t, c -def AboutSizeTWhileTest(length: t.CSizeT) -> t.CVoid | t.State: pass +def AboutSizeTWhileTest(length: t.CSizeT) -> t.CInt: pass -def MathBasicTest(x: t.CInt, y: t.CInt) -> t.CInt | t.State: pass +def MathBasicTest(x: t.CInt, y: t.CInt) -> t.CInt: pass -def MathAdvancedTest(value: t.CInt) -> t.CInt | t.State: pass +def MathAdvancedTest(value: t.CInt) -> t.CInt: pass -def WhileWithElifElseTest(start: t.CInt, end: t.CInt) -> t.CVoid | t.State: pass +def WhileWithElifElseTest(start: t.CInt, end: t.CInt) -> t.CInt: pass -def NestedWhileWithMacrosTest(outer_limit: t.CInt, inner_limit: t.CInt) -> t.CVoid | t.State: pass +def NestedWhileWithMacrosTest(outer_limit: t.CInt, inner_limit: t.CInt) -> t.CInt: pass -def ComplexConditionTest(a: t.CInt, b: t.CInt, c_val: t.CInt) -> t.CVoid | t.State: pass +def ComplexConditionTest(a: t.CInt, b: t.CInt, c_val: t.CInt) -> t.CInt: pass -def RetryLoopTest(retry_count: t.CInt) -> t.CInt | t.State: pass +def RetryLoopTest(retry_count: t.CInt) -> t.CInt: pass -def BitwiseOperationsTest(value: t.CInt) -> t.CInt | t.State: pass +def BitwiseOperationsTest(value: t.CInt) -> t.CInt: pass -def CompoundAssignmentMathTest(a: t.CInt, b: t.CInt) -> t.CInt | t.State: pass +def CompoundAssignmentMathTest(a: t.CInt, b: t.CInt) -> t.CInt: pass -def PowerAndModuloTest(base: t.CInt, exponent: t.CInt) -> t.CInt | t.State: pass +def PowerAndModuloTest(base: t.CInt, exponent: t.CInt) -> t.CInt: pass -def MixedArithmeticTest(x: t.CInt, y: t.CInt, z: t.CInt) -> t.CInt | t.State: pass +def MixedArithmeticTest(x: t.CInt, y: t.CInt, z: t.CInt) -> t.CInt: pass -def MathWithWhileLoopTest(start: t.CInt, count: t.CInt) -> t.CInt | t.State: pass +def MathWithWhileLoopTest(start: t.CInt, count: t.CInt) -> t.CInt: pass -def ComplexNestedMathTest(a: t.CInt, b: t.CInt) -> t.CInt | t.State: pass +def ComplexNestedMathTest(a: t.CInt, b: t.CInt) -> t.CInt: pass -def ConditionalMathChainTest(value: t.CInt) -> t.CInt | t.State: pass +def ConditionalMathChainTest(value: t.CInt) -> t.CInt: pass -def BitManipulationMathTest(value: t.CInt) -> t.CInt | t.State: pass +def BitManipulationMathTest(value: t.CInt) -> t.CInt: pass diff --git a/Test/TestProject2/temp/_shared_sym.pkl b/Test/TestProject2/temp/_shared_sym.pkl index 94768a3544ed090451d94af1722084485b67fb4d..28eaf6a22fffdff879b1caaa1d31993e4eb65183 100644 GIT binary patch delta 11643 zcmb7Kdt6mj+IB5akS!=T6-41&xT)O53tj-tOiRVY(Nqvr5RWK=ViYP;=1AdnqpLpB zBrVG#(KBDGo0eaWCXRlQzpt_^v8HUwsj;Td#%Xfiwf5R)U(Pw`@W=V>%lkg>^S91#{wpqwuS}?Jys-kM<{z8P%VtE0c&woeDH*l)BTI7>1t~y*-*}hw&0w&h1 ztf*RDys*5asWG&C>B8hi6;&n4{HgPrZ}*ch}B z<$h?m4LvI7g}38Jkz83ECy(zN9@%~Jiq$cLn;iF|ZrvJtty*1Gy=Zj|f9C9%mxC0~ z>k9{vA1LyZ|I}}>@+7Ih1wA8A@86D}LGqQs(azpy^EG4n`N(C8UC;mvqH^khc1)R_ z-5C?*(CkRw9OOqjzeK%uR?JZx0tVU92Xe}wcKiVcMmyx~>SeFX^WkwxybLo z+e3aju0$dCTbu=1xkpAkg)8nMIr}Ee*E~o{I0|*8^JAhFjpZH*gDG5r$I&56G;6tT zsGxpzs1?oOmIIS0Tq)Q`lXcK?(Kmi_ZHl0ODaDFbafgsp3Ri;u52-r(WY0oKY-zf1 zX-|(uTe*u*28And2@c2Ix+T^(t!ql)eZbM5R92!9v~U3GrK341Q_wt|X+h5eL_7T6 zu{+sb0yI)a3L4u-TG4S%84N8~Uk(y|Sv)oN7!uQ8*GRSFZ0IMBesmm#E5T=5_6m&;`P)qFCr9N9 zLhEwlP>|d*DO9Gp6bJdRF)+@|sQ0WDtClWVQL@;`tgm2ZdTV4Tzw^JM;thAjq68jl z!TWylnY-F>0t;uCpP6{Kv+c8R9mk+2pv)1I1jmOb#i0q{*p4SC4m<9d?Hu=*&Or{J zB7&@&VnKyG$k8bj7xH{UhWofG%%%s&C?BWg?07BS?zz~HY>(27-omL?v_`I<+K$&K z5Hm~=`999z$8-?#$I}IaoIES^NLJA`c{F4z_&IVR=(;Ay1Qt6<&YtmzG768+h(*oZ z^2Q8`n|Yu+?8c+>MYR3-cI4z3pXO8S&rvs*NP~L zbgnGk=;{ial$Ke&$c8ex$xDkU&h!PiIOpSwi(GaCWLzrX9Hn-Y$8Dc2r8tk-+MRVv z7VB*PSte{3Ew!U%+_rfs#ml&@T(`u}S?ADG{rfUuKfm0LHi3OR-lW;qEZ5oYPKGj& zv7!vKDq>L!$KP5(af`xb*~(HKm%mgB>={)S^cJ_>R7LSyitVCRg_xV?{r5Ge-@DD`qzNA=M04VEOHb1%>!pD+-j; z>OHeXCzmmF;g>fE(t-6h zm^;$y+u01VB_=r4v`S>iY463$Imv#`f&~49viVUF^ly*a&^#VAej|k|26C?nWSR@a zFe{OQTA<=;oC}+5u(~n&0l#PK978HKAuVM{&Ya{Ztrg^H4T8$64R-Vd2l&2$!W96x zFCMVv8JX`I>+0emo*D-`IqVPorZe5!dS@du!^;TnE#ZKK5> z8w1D_w+ZU4+hWn%9Q*5S6t28sXQX??=8sL-<97<|Lp#};%If;%PPV3c!yZ1&BQ}3* z!p`0$un+Evg>{r+ckW^Zu#+s`&Q6KBDEl-L;a^T50=OK0YjvTPT3e6nOAE0;*;}Yj=eNI0` z#~u`|xaFV?w%FiUf!{hr@yk3(_i?}$Pu)0E+gyFD zYZx};^=}nSHnhf}Qylz_R*Fw~sUSn~)b6h5MtE{-DpV%AO^o9WZE>hmiP1)JXBRO% zbpRH_+yQtBPBjIm4c&AeaAK^im6d18diHemV>{P8CL%}6(_gJoUY&e3C8UOJdiui8 zz1_HxBV4XL*FbV2Q5>womh*Ob`&faT`?dIZWo9xD}?fRL~J?Qxi&O-y=w z1ekWhBCXW{965;|!oGgQG8tQSQWH`Ef#!$8a4Cm`_ieblzub0Lgz}!RH58t0!nriipcFQiJ*{#qY{JZj`q7vhYKK~@f8 zn~48YHxVC3qbxb;!~1$=yIjZm%ayP7MWf}XKTMYy{4!(yD^@1dbh z*yQ41slb!_19DF1SdA7rQiUqytV@DY^Q9!I*3HcseC-og`;{rD64%~9iVrEChQs9N zFAtJ-yEy_~Q#={^B!P1VF*f&pFOioLP~Tq_fiNh zn#-<>jLuw7ktW@#E9;~r`hAt=hWAmbRN~FqR1PLg<;QP`u;1NCmo|Cx)O8h}=(d|8 z(S096T@HA18|SynryC5LZgTO@W8?*$gS6hpAea^;lP{{o4_!o=(*L;O80*XQoro(T zG)(%e3wzS>6sjOE_^1J{A4SjMY&NpD@+pvv?vCPnp#Zf-)e%P?>y8ppcXGHpiba@o z3_&F%Ck*AF?zFZC5~~CK!4Iuc`W0Ew6K%1&rie!W$*b~;7cDDU+|x~j4 zv}8lPB}@L$2U)vXGiZDWs#a=Fp9)o5f|cLO4ilGoiT~YKQ1(U-WsmU2gf{d=HKK8U z>xZ^@0j|D^Vx$8aFxht%rezVKw!<05Yb{WS^=Lt-J|(bjkv zSas2AzweAjBf2u@XC}liS+zfH^=_|>sj0E5?JKce*j|4c#-E0}D*7v*Lr0wP4ph}*DX zik-YUN-bYh7RvBOiCB(8`Sy-cZEuZ1nci&qV!Ae4&Gc6Z4<njs))108EL|NLxaFUdENBE$Xgj3zUXk?fCL6rzoKC`0$ZDxOJI!eOo zd`>SE!axGn}x(-7@1??0WR-qYl{t{LfIJfODEbG;f^fYu4rrw0RpV}-6)eTrPKwk6?2>MT}Y5h(@7 z)1*b}J>9U_#qGB=Jeb-_)mNl80}r7sOI-K=7zPBQma6x(!hysYBw@88yUNjaWd^q{ zM`^A~k@DrdO*@)U8#A%k^UWTE)1|F}TGs*J?b@D;?J6%Qk?L3R zF%9ouF-}*?0+P5!?dXrMQ4PJ4VBe=m;6#gT`(qTgvY$uIFr2egz8~x6j+0VUD;eboV>YJwe!m5)_m1tNdX>3j_*J{ zy_ZSs|I`pgI9vMMn6rtGvPfkUwH5Xel|Dsxy z%P*q4Jm<2YMs1waH8@lH8c;sh?$VnaS3F=EWGveY@)G=NE`bLL%jP;} zjQY{y&(sBrgKL_2G^PHuI|E> zZ4a4m%nE~VrFIAPSnY=7u3~M$TJPXwwrLP>%D2-ELe|S!RwM4!YVc}v^Kw_PY=g#^~jYkkgU+l_zJaoaRr5zsPl@@d42FTYWCs<@@p`#2GOOk zCI#Q1=e^j1WEw18()Eh8UU;iE!HDI^j~G-_5{bITTglzngJw#SdWArt#M!dZ#e-~0 zBHv#308ZRRQ>rw^9e5fF-F5COI9q|gX^sjwH(=tM4@rZJN+HK?cnHH2){CeNa_FWP zJEMfkls3AvQU9fh%_C+NH5!J5u^ODEK{REMhkYYL* zxl6LdpqaR+b|+xaNy9y7V~|Cu($G+EJ%Q(LP)1yvyGJz$p=4=(*NB=Hs*A)nN%v7i z8A~|>a4X-2({Bghhm`r7f*2BFhk_1LB@#%WXu3KE3*AFO2Z>h{B#?Ui1?opVApzlI zq4{xGXetWoXT4bWLHNYe$%(F4png<&1;Qtujv4BD1?oo)1Hwm@OQ3n;=u4?CD-b># z1bfgt;$WA8+)*Qf(ut?d!&Ua==Mk9ApAjRmI)4_8!c14PnU{oQVY_h_;HT$CeWNZ1 zBxo$o(X5TqCWY+H=6#Ya9K@D`(=|)p=6ok&5IHH*M`2nw;d~M&xbbn9I_eTm?036a zyNjE2(tHmm#sfr8HoLg1n_*IHxQSQPeR?;e#&OZBnN!qZp8crniezP(A z$1$wt2%UmZKSMT<3`w^Rn!d?+3=7V+Ne%k zhU?er4K+PN-d)e9f~)IYQvp8WB7+t#&Z|;vvFiG8uBS`cf+@RjjclW@*JK``*TK2&?&dq%oj)vjxN(h3j_%7)tOd98VmlaILtBc=a?sh8f0=vp9l& QdCPN>dR$n6gm>A)hEd$}CiLVaw69 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 t.CVoid | t.State: pass - def get_age(self: Student) -> t.CInt | t.State: pass - def get_score(self: Student) -> t.CInt | t.State: pass + def __init__(self: Student, n: t.CChar | t.CPtr, a: t.CInt, s: t.CInt) -> t.CInt: pass + def get_age(self: Student) -> t.CInt: pass + def get_score(self: Student) -> t.CInt: pass class Counter(t.Object): value: t.CInt - def __init__(self: Counter, initial: t.CInt) -> t.CVoid | t.State: pass - def increment(self: Counter) -> t.CVoid | t.State: pass - def get_value(self: Counter) -> t.CInt | t.State: pass + def __init__(self: Counter, initial: t.CInt) -> t.CInt: pass + def increment(self: Counter) -> t.CInt: pass + def get_value(self: Counter) -> t.CInt: pass class StackObj(t.Object): data: t.CInt next_ptr: t.CVoid | t.CPtr -def TestBasicDataClass() -> t.CVoid | t.State: pass +def TestBasicDataClass() -> t.CInt: pass -def TestPoint3DClass() -> t.CVoid | t.State: pass +def TestPoint3DClass() -> t.CInt: pass -def TestStudentClass() -> t.CVoid | t.State: pass +def TestStudentClass() -> t.CInt: pass -def TestCounterClass() -> t.CVoid | t.State: pass +def TestCounterClass() -> t.CInt: pass -def TestStackAllocation() -> t.CVoid | t.State: pass +def TestStackAllocation() -> t.CInt: pass -def TestHeapAllocation() -> t.CVoid | t.State: pass +def TestHeapAllocation() -> t.CInt: pass -def TestHeapObjectWithInit() -> t.CVoid | t.State: pass +def TestHeapObjectWithInit() -> t.CInt: pass -def TestMultipleStackObjects() -> t.CVoid | t.State: pass +def TestMultipleStackObjects() -> t.CInt: pass -def TestImplicitInitCall() -> t.CVoid | t.State: pass +def TestImplicitInitCall() -> t.CInt: pass -def TestClassWithBitFields() -> t.CVoid | t.State: pass +def TestClassWithBitFields() -> t.CInt: pass -def TestIntArray() -> t.CVoid | t.State: pass +def TestIntArray() -> t.CInt: pass -def TestFloatArray() -> t.CVoid | t.State: pass +def TestFloatArray() -> t.CInt: pass -def TestCharArray() -> t.CVoid | t.State: pass +def TestCharArray() -> t.CInt: pass -def TestNestedArray() -> t.CVoid | t.State: pass +def TestNestedArray() -> t.CInt: pass -def TestArrayWithStruct() -> t.CVoid | t.State: pass +def TestArrayWithStruct() -> t.CInt: pass -def TestArrayPointer() -> t.CVoid | t.State: pass +def TestArrayPointer() -> t.CInt: pass -def TestDynamicString() -> t.CVoid | t.State: pass +def TestDynamicString() -> t.CInt: pass diff --git a/Test/TestProject2/temp/faec3233d98371da.pyi b/Test/TestProject2/temp/faec3233d98371da.pyi index 82fcbb8..308f5cb 100644 --- a/Test/TestProject2/temp/faec3233d98371da.pyi +++ b/Test/TestProject2/temp/faec3233d98371da.pyi @@ -7,48 +7,48 @@ Module: zc.logic_test import config import t, c -def ForRangeBasicTest(stop: t.CInt) -> t.CVoid | t.State: pass +def ForRangeBasicTest(stop: t.CInt) -> t.CInt: pass -def ForRangeWithStartStop(start: t.CInt, stop: t.CInt, step: t.CInt) -> t.CVoid | t.State: pass +def ForRangeWithStartStop(start: t.CInt, stop: t.CInt, step: t.CInt) -> t.CInt: pass -def NestedForRangeTest(rows: t.CInt, cols: t.CInt) -> t.CVoid | t.State: pass +def NestedForRangeTest(rows: t.CInt, cols: t.CInt) -> t.CInt: pass -def ForWithIfBreakTest(data_size: t.CInt) -> t.CVoid | t.State: pass +def ForWithIfBreakTest(data_size: t.CInt) -> t.CInt: pass -def ForWithIfContinueTest(n: t.CInt) -> t.CVoid | t.State: pass +def ForWithIfContinueTest(n: t.CInt) -> t.CInt: pass -def ForWithElifBranchTest(value: t.CInt) -> t.CVoid | t.State: pass +def ForWithElifBranchTest(value: t.CInt) -> t.CInt: pass -def WhileWithIfElifElseTest(iterations: t.CInt) -> t.CVoid | t.State: pass +def WhileWithIfElifElseTest(iterations: t.CInt) -> t.CInt: pass -def WhileWithNestedIfTest(limit: t.CInt) -> t.CVoid | t.State: pass +def WhileWithNestedIfTest(limit: t.CInt) -> t.CInt: pass -def WhileWithMatchCaseTest(value: t.CInt) -> t.CVoid | t.State: pass +def WhileWithMatchCaseTest(value: t.CInt) -> t.CInt: pass -def WhileWithMatchCaseNoBreakTest(value: t.CInt) -> t.CVoid | t.State: pass +def WhileWithMatchCaseNoBreakTest(value: t.CInt) -> t.CInt: pass -def ComplexForWhileMatchTest(outer_limit: t.CInt, inner_limit: t.CInt) -> t.CVoid | t.State: pass +def ComplexForWhileMatchTest(outer_limit: t.CInt, inner_limit: t.CInt) -> t.CInt: pass -def ForWithCaseAndNoBreakTest(n: t.CInt) -> t.CVoid | t.State: pass +def ForWithCaseAndNoBreakTest(n: t.CInt) -> t.CInt: pass -def WhileWithBreakConditionTest(limit: t.CInt) -> t.CVoid | t.State: pass +def WhileWithBreakConditionTest(limit: t.CInt) -> t.CInt: pass -def NestedWhileWithMultipleBreakPoints(depth: t.CInt, width: t.CInt) -> t.CVoid | t.State: pass +def NestedWhileWithMultipleBreakPoints(depth: t.CInt, width: t.CInt) -> t.CInt: pass -def ForWithMatchCaseInLoopTest(iterations: t.CInt) -> t.CVoid | t.State: pass +def ForWithMatchCaseInLoopTest(iterations: t.CInt) -> t.CInt: pass -def ComplexLogicWithElifChains(a: t.CInt, b: t.CInt, c_val: t.CInt) -> t.CVoid | t.State: pass +def ComplexLogicWithElifChains(a: t.CInt, b: t.CInt, c_val: t.CInt) -> t.CInt: pass -def ForRangeWithStepAndCondition(n: t.CInt, step: t.CInt) -> t.CVoid | t.State: pass +def ForRangeWithStepAndCondition(n: t.CInt, step: t.CInt) -> t.CInt: pass -def MatchCaseWithGuardConditions(value: t.CInt) -> t.CVoid | t.State: pass +def MatchCaseWithGuardConditions(value: t.CInt) -> t.CInt: pass -def WhileWithMultipleMatchCases(iterations: t.CInt) -> t.CVoid | t.State: pass +def WhileWithMultipleMatchCases(iterations: t.CInt) -> t.CInt: pass -def ForWhileMixWithBreakAndContinue(n: t.CInt) -> t.CVoid | t.State: pass +def ForWhileMixWithBreakAndContinue(n: t.CInt) -> t.CInt: pass -def ComplexCaseMatchingWithRanges(start: t.CInt, end: t.CInt) -> t.CVoid | t.State: pass +def ComplexCaseMatchingWithRanges(start: t.CInt, end: t.CInt) -> t.CInt: pass -def WhileWithElifInElifChain(limit: t.CInt) -> t.CVoid | t.State: pass +def WhileWithElifInElifChain(limit: t.CInt) -> t.CInt: pass -def ForWithCaseNoBreakNested(inner_limit: t.CInt) -> t.CVoid | t.State: pass +def ForWithCaseNoBreakNested(inner_limit: t.CInt) -> t.CInt: pass diff --git a/Test/TestProject3/output/067c78e9f121dce3.deps.json b/Test/TestProject3/output/067c78e9f121dce3.deps.json index 9ea60d1..f7c4d17 100644 --- a/Test/TestProject3/output/067c78e9f121dce3.deps.json +++ b/Test/TestProject3/output/067c78e9f121dce3.deps.json @@ -1 +1 @@ -{"fileiotest": "087c910044fab2d2", "main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "mpool": "21ffad37f6fc3fcf", "vector": "3fdd11bdd589aa8c", "viperlib": "4d342c40331fc964", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "string": "a326a52b7c4bd6f0", "stdlib": "a96738831f025829", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file +{"main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "viperlib": "2953a7db4185005b", "vector": "3fdd11bdd589aa8c", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "fileiotest": "c01b27dbcd683245", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3"} \ No newline at end of file diff --git a/Test/TestProject3/output/087c910044fab2d2.deps.json b/Test/TestProject3/output/087c910044fab2d2.deps.json deleted file mode 100644 index 52493aa..0000000 --- a/Test/TestProject3/output/087c910044fab2d2.deps.json +++ /dev/null @@ -1 +0,0 @@ -{"main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "mpool": "21ffad37f6fc3fcf", "vector": "3fdd11bdd589aa8c", "viperlib": "4d342c40331fc964", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "string": "a326a52b7c4bd6f0", "stdlib": "a96738831f025829", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file diff --git a/Test/TestProject3/output/0f4d14c17bf75b10.deps.json b/Test/TestProject3/output/0f4d14c17bf75b10.deps.json index 92bc69f..f95c08f 100644 --- a/Test/TestProject3/output/0f4d14c17bf75b10.deps.json +++ b/Test/TestProject3/output/0f4d14c17bf75b10.deps.json @@ -1 +1 @@ -{"fileiotest": "087c910044fab2d2", "enumtest": "1b58766d38d05de3", "mpool": "21ffad37f6fc3fcf", "vector": "3fdd11bdd589aa8c", "viperlib": "4d342c40331fc964", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "string": "a326a52b7c4bd6f0", "stdlib": "a96738831f025829", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file +{"enumtest": "1b58766d38d05de3", "viperlib": "2953a7db4185005b", "vector": "3fdd11bdd589aa8c", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "fileiotest": "c01b27dbcd683245", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file diff --git a/Test/TestProject3/output/1b58766d38d05de3.deps.json b/Test/TestProject3/output/1b58766d38d05de3.deps.json index 575d1e0..385a702 100644 --- a/Test/TestProject3/output/1b58766d38d05de3.deps.json +++ b/Test/TestProject3/output/1b58766d38d05de3.deps.json @@ -1 +1 @@ -{"fileiotest": "087c910044fab2d2", "main": "0f4d14c17bf75b10", "mpool": "21ffad37f6fc3fcf", "vector": "3fdd11bdd589aa8c", "viperlib": "4d342c40331fc964", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "string": "a326a52b7c4bd6f0", "stdlib": "a96738831f025829", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file +{"main": "0f4d14c17bf75b10", "viperlib": "2953a7db4185005b", "vector": "3fdd11bdd589aa8c", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "fileiotest": "c01b27dbcd683245", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file diff --git a/Test/TestProject3/output/21ffad37f6fc3fcf.deps.json b/Test/TestProject3/output/21ffad37f6fc3fcf.deps.json deleted file mode 100644 index 16e2398..0000000 --- a/Test/TestProject3/output/21ffad37f6fc3fcf.deps.json +++ /dev/null @@ -1 +0,0 @@ -{"fileiotest": "087c910044fab2d2", "main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "vector": "3fdd11bdd589aa8c", "viperlib": "4d342c40331fc964", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "string": "a326a52b7c4bd6f0", "stdlib": "a96738831f025829", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file diff --git a/Test/TestProject3/output/2953a7db4185005b.deps.json b/Test/TestProject3/output/2953a7db4185005b.deps.json new file mode 100644 index 0000000..26eaaa8 --- /dev/null +++ b/Test/TestProject3/output/2953a7db4185005b.deps.json @@ -0,0 +1 @@ +{"main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "viperlib": "2953a7db4185005b", "vector": "3fdd11bdd589aa8c", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "fileiotest": "c01b27dbcd683245", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file diff --git a/Test/TestProject3/output/29813d57621099a9.deps.json b/Test/TestProject3/output/29813d57621099a9.deps.json index 9ea60d1..dd5f0cf 100644 --- a/Test/TestProject3/output/29813d57621099a9.deps.json +++ b/Test/TestProject3/output/29813d57621099a9.deps.json @@ -1 +1 @@ -{"fileiotest": "087c910044fab2d2", "main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "mpool": "21ffad37f6fc3fcf", "vector": "3fdd11bdd589aa8c", "viperlib": "4d342c40331fc964", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "string": "a326a52b7c4bd6f0", "stdlib": "a96738831f025829", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file +{"main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "viperlib": "2953a7db4185005b", "vector": "3fdd11bdd589aa8c", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "fileiotest": "c01b27dbcd683245", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file diff --git a/Test/TestProject3/output/3fdd11bdd589aa8c.deps.json b/Test/TestProject3/output/3fdd11bdd589aa8c.deps.json index 5b6a8ca..26eaaa8 100644 --- a/Test/TestProject3/output/3fdd11bdd589aa8c.deps.json +++ b/Test/TestProject3/output/3fdd11bdd589aa8c.deps.json @@ -1 +1 @@ -{"fileiotest": "087c910044fab2d2", "main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "mpool": "21ffad37f6fc3fcf", "viperlib": "4d342c40331fc964", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "string": "a326a52b7c4bd6f0", "stdlib": "a96738831f025829", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file +{"main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "viperlib": "2953a7db4185005b", "vector": "3fdd11bdd589aa8c", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "fileiotest": "c01b27dbcd683245", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file diff --git a/Test/TestProject3/output/4d342c40331fc964.deps.json b/Test/TestProject3/output/4d342c40331fc964.deps.json deleted file mode 100644 index 20b6925..0000000 --- a/Test/TestProject3/output/4d342c40331fc964.deps.json +++ /dev/null @@ -1 +0,0 @@ -{"fileiotest": "087c910044fab2d2", "main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "mpool": "21ffad37f6fc3fcf", "vector": "3fdd11bdd589aa8c", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "string": "a326a52b7c4bd6f0", "stdlib": "a96738831f025829", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file diff --git a/Test/TestProject3/output/5325ec533a59d71b.deps.json b/Test/TestProject3/output/5325ec533a59d71b.deps.json index b780a03..74a9d28 100644 --- a/Test/TestProject3/output/5325ec533a59d71b.deps.json +++ b/Test/TestProject3/output/5325ec533a59d71b.deps.json @@ -1 +1 @@ -{"fileiotest": "087c910044fab2d2", "main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "mpool": "21ffad37f6fc3fcf", "vector": "3fdd11bdd589aa8c", "viperlib": "4d342c40331fc964", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "string": "a326a52b7c4bd6f0", "stdlib": "a96738831f025829", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file +{"main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "viperlib": "2953a7db4185005b", "vector": "3fdd11bdd589aa8c", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "fileiotest": "c01b27dbcd683245", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file diff --git a/Test/TestProject3/output/5a6a2137958c28c5.deps.json b/Test/TestProject3/output/5a6a2137958c28c5.deps.json index 79af064..26eaaa8 100644 --- a/Test/TestProject3/output/5a6a2137958c28c5.deps.json +++ b/Test/TestProject3/output/5a6a2137958c28c5.deps.json @@ -1 +1 @@ -{"fileiotest": "087c910044fab2d2", "main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "mpool": "21ffad37f6fc3fcf", "vector": "3fdd11bdd589aa8c", "viperlib": "4d342c40331fc964", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "definetest": "64ac83614c9bdbc6", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "string": "a326a52b7c4bd6f0", "stdlib": "a96738831f025829", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file +{"main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "viperlib": "2953a7db4185005b", "vector": "3fdd11bdd589aa8c", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "fileiotest": "c01b27dbcd683245", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file diff --git a/Test/TestProject3/output/64ac83614c9bdbc6.deps.json b/Test/TestProject3/output/64ac83614c9bdbc6.deps.json index 7784b27..5d84cc9 100644 --- a/Test/TestProject3/output/64ac83614c9bdbc6.deps.json +++ b/Test/TestProject3/output/64ac83614c9bdbc6.deps.json @@ -1 +1 @@ -{"fileiotest": "087c910044fab2d2", "main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "mpool": "21ffad37f6fc3fcf", "vector": "3fdd11bdd589aa8c", "viperlib": "4d342c40331fc964", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "string": "a326a52b7c4bd6f0", "stdlib": "a96738831f025829", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file +{"main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "viperlib": "2953a7db4185005b", "vector": "3fdd11bdd589aa8c", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "fileiotest": "c01b27dbcd683245", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file diff --git a/Test/TestProject3/output/68c4fe4b12c908e3.deps.json b/Test/TestProject3/output/68c4fe4b12c908e3.deps.json new file mode 100644 index 0000000..26eaaa8 --- /dev/null +++ b/Test/TestProject3/output/68c4fe4b12c908e3.deps.json @@ -0,0 +1 @@ +{"main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "viperlib": "2953a7db4185005b", "vector": "3fdd11bdd589aa8c", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "fileiotest": "c01b27dbcd683245", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file diff --git a/Test/TestProject3/output/6aee24fdefa3cbc0.deps.json b/Test/TestProject3/output/6aee24fdefa3cbc0.deps.json new file mode 100644 index 0000000..26eaaa8 --- /dev/null +++ b/Test/TestProject3/output/6aee24fdefa3cbc0.deps.json @@ -0,0 +1 @@ +{"main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "viperlib": "2953a7db4185005b", "vector": "3fdd11bdd589aa8c", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "fileiotest": "c01b27dbcd683245", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file diff --git a/Test/TestProject3/output/72e2d5ccb7cedcf1.deps.json b/Test/TestProject3/output/72e2d5ccb7cedcf1.deps.json index 9ea60d1..40e3886 100644 --- a/Test/TestProject3/output/72e2d5ccb7cedcf1.deps.json +++ b/Test/TestProject3/output/72e2d5ccb7cedcf1.deps.json @@ -1 +1 @@ -{"fileiotest": "087c910044fab2d2", "main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "mpool": "21ffad37f6fc3fcf", "vector": "3fdd11bdd589aa8c", "viperlib": "4d342c40331fc964", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "string": "a326a52b7c4bd6f0", "stdlib": "a96738831f025829", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file +{"main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "viperlib": "2953a7db4185005b", "vector": "3fdd11bdd589aa8c", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "fileiotest": "c01b27dbcd683245", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1"} \ No newline at end of file diff --git a/Test/TestProject3/output/a326a52b7c4bd6f0.deps.json b/Test/TestProject3/output/a326a52b7c4bd6f0.deps.json deleted file mode 100644 index ab3e82e..0000000 --- a/Test/TestProject3/output/a326a52b7c4bd6f0.deps.json +++ /dev/null @@ -1 +0,0 @@ -{"fileiotest": "087c910044fab2d2", "main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "mpool": "21ffad37f6fc3fcf", "vector": "3fdd11bdd589aa8c", "viperlib": "4d342c40331fc964", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "stdlib": "a96738831f025829", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file diff --git a/Test/TestProject3/output/abf9ce3160c9279e.deps.json b/Test/TestProject3/output/abf9ce3160c9279e.deps.json index 7908c78..26eaaa8 100644 --- a/Test/TestProject3/output/abf9ce3160c9279e.deps.json +++ b/Test/TestProject3/output/abf9ce3160c9279e.deps.json @@ -1 +1 @@ -{"fileiotest": "087c910044fab2d2", "main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "mpool": "21ffad37f6fc3fcf", "vector": "3fdd11bdd589aa8c", "viperlib": "4d342c40331fc964", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "string": "a326a52b7c4bd6f0", "stdlib": "a96738831f025829", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file +{"main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "viperlib": "2953a7db4185005b", "vector": "3fdd11bdd589aa8c", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "fileiotest": "c01b27dbcd683245", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file diff --git a/Test/TestProject3/output/bbdf3bbd4c3bc28c.deps.json b/Test/TestProject3/output/bbdf3bbd4c3bc28c.deps.json index ed5f7b3..26eaaa8 100644 --- a/Test/TestProject3/output/bbdf3bbd4c3bc28c.deps.json +++ b/Test/TestProject3/output/bbdf3bbd4c3bc28c.deps.json @@ -1 +1 @@ -{"fileiotest": "087c910044fab2d2", "main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "mpool": "21ffad37f6fc3fcf", "vector": "3fdd11bdd589aa8c", "viperlib": "4d342c40331fc964", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "string": "a326a52b7c4bd6f0", "stdlib": "a96738831f025829", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file +{"main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "viperlib": "2953a7db4185005b", "vector": "3fdd11bdd589aa8c", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "fileiotest": "c01b27dbcd683245", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file diff --git a/Test/TestProject3/output/c01b27dbcd683245.deps.json b/Test/TestProject3/output/c01b27dbcd683245.deps.json new file mode 100644 index 0000000..1f541f6 --- /dev/null +++ b/Test/TestProject3/output/c01b27dbcd683245.deps.json @@ -0,0 +1 @@ +{"main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "viperlib": "2953a7db4185005b", "vector": "3fdd11bdd589aa8c", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file diff --git a/Test/TestProject3/output/c9f4be41ca1cc2b4.deps.json b/Test/TestProject3/output/c9f4be41ca1cc2b4.deps.json index f4b825d..26eaaa8 100644 --- a/Test/TestProject3/output/c9f4be41ca1cc2b4.deps.json +++ b/Test/TestProject3/output/c9f4be41ca1cc2b4.deps.json @@ -1 +1 @@ -{"fileiotest": "087c910044fab2d2", "main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "mpool": "21ffad37f6fc3fcf", "vector": "3fdd11bdd589aa8c", "viperlib": "4d342c40331fc964", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "string": "a326a52b7c4bd6f0", "stdlib": "a96738831f025829", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file +{"main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "viperlib": "2953a7db4185005b", "vector": "3fdd11bdd589aa8c", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "fileiotest": "c01b27dbcd683245", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file diff --git a/Test/TestProject3/output/fa3691e66b426950.deps.json b/Test/TestProject3/output/fa3691e66b426950.deps.json index def18b9..26eaaa8 100644 --- a/Test/TestProject3/output/fa3691e66b426950.deps.json +++ b/Test/TestProject3/output/fa3691e66b426950.deps.json @@ -1 +1 @@ -{"fileiotest": "087c910044fab2d2", "main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "mpool": "21ffad37f6fc3fcf", "vector": "3fdd11bdd589aa8c", "viperlib": "4d342c40331fc964", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "string": "a326a52b7c4bd6f0", "stdlib": "a96738831f025829", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file +{"main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "viperlib": "2953a7db4185005b", "vector": "3fdd11bdd589aa8c", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "fileiotest": "c01b27dbcd683245", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file diff --git a/Test/TestProject3/output/fc49f6314bad25e9.deps.json b/Test/TestProject3/output/fc49f6314bad25e9.deps.json index 250a982..da3fd87 100644 --- a/Test/TestProject3/output/fc49f6314bad25e9.deps.json +++ b/Test/TestProject3/output/fc49f6314bad25e9.deps.json @@ -1 +1 @@ -{"fileiotest": "087c910044fab2d2", "main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "mpool": "21ffad37f6fc3fcf", "vector": "3fdd11bdd589aa8c", "viperlib": "4d342c40331fc964", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "string": "a326a52b7c4bd6f0", "stdlib": "a96738831f025829", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file +{"main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "viperlib": "2953a7db4185005b", "vector": "3fdd11bdd589aa8c", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "fileiotest": "c01b27dbcd683245", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/TestProject3/temp/067c78e9f121dce3.pyi b/Test/TestProject3/temp/067c78e9f121dce3.pyi new file mode 100644 index 0000000..f4f767c --- /dev/null +++ b/Test/TestProject3/temp/067c78e9f121dce3.pyi @@ -0,0 +1,136 @@ +""" +Auto-generated Python stub file from w32.win32process.py +Module: w32.win32process +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +PROCESS_TERMINATE: t.CDefine = 0x0001 +PROCESS_CREATE_THREAD: t.CDefine = 0x0002 +PROCESS_VM_OPERATION: t.CDefine = 0x0008 +PROCESS_VM_READ: t.CDefine = 0x0010 +PROCESS_VM_WRITE: t.CDefine = 0x0020 +PROCESS_QUERY_INFORMATION: t.CDefine = 0x0400 +PROCESS_ALL_ACCESS: t.CDefine = 0x001FFFFF +THREAD_TERMINATE: t.CDefine = 0x0001 +THREAD_SUSPEND_RESUME: t.CDefine = 0x0002 +THREAD_GET_CONTEXT: t.CDefine = 0x0008 +THREAD_SET_CONTEXT: t.CDefine = 0x0010 +THREAD_QUERY_INFORMATION: t.CDefine = 0x0040 +THREAD_ALL_ACCESS: t.CDefine = 0x001FFFFF +CREATE_SUSPENDED: t.CDefine = 0x00000004 +CREATE_NEW_CONSOLE: t.CDefine = 0x00000010 +CREATE_NEW_PROCESS_GROUP: t.CDefine = 0x00000200 +CREATE_NO_WINDOW: t.CDefine = 0x08000000 +DETACHED_PROCESS: t.CDefine = 0x00000008 +STARTF_USESHOWWINDOW: t.CDefine = 0x00000001 +STARTF_USESTDHANDLES: t.CDefine = 0x00000100 +SW_HIDE: t.CDefine = 0 +SW_SHOW: t.CDefine = 5 +SW_MINIMIZE: t.CDefine = 6 +NORMAL_PRIORITY_CLASS: t.CDefine = 0x00000020 +IDLE_PRIORITY_CLASS: t.CDefine = 0x00000040 +HIGH_PRIORITY_CLASS: t.CDefine = 0x00000080 +REALTIME_PRIORITY_CLASS: t.CDefine = 0x00000100 +BELOW_NORMAL_PRIORITY_CLASS: t.CDefine = 0x00004000 +ABOVE_NORMAL_PRIORITY_CLASS: t.CDefine = 0x00008000 +STILL_ACTIVE: t.CDefine = 259 + +class STARTUPINFOA: + cb: ULONG + lpReserved: CHARPTR + lpDesktop: CHARPTR + lpTitle: CHARPTR + dwX: ULONG + dwY: ULONG + dwXSize: ULONG + dwYSize: ULONG + dwXCountChars: ULONG + dwYCountChars: ULONG + dwFillAttribute: ULONG + dwFlags: ULONG + wShowWindow: WORD + cbReserved2: WORD + lpReserved2: VOIDPTR + hStdInput: HANDLE + hStdOutput: HANDLE + hStdError: HANDLE +class STARTUPINFOW: + cb: ULONG + lpReserved: WCHARPTR + lpDesktop: WCHARPTR + lpTitle: WCHARPTR + dwX: ULONG + dwY: ULONG + dwXSize: ULONG + dwYSize: ULONG + dwXCountChars: ULONG + dwYCountChars: ULONG + dwFillAttribute: ULONG + dwFlags: ULONG + wShowWindow: WORD + cbReserved2: WORD + lpReserved2: VOIDPTR + hStdInput: HANDLE + hStdOutput: HANDLE + hStdError: HANDLE +class PROCESS_INFORMATION: + hProcess: HANDLE + hThread: HANDLE + dwProcessId: ULONG + dwThreadId: ULONG + +def CreateProcessA(lpApplicationName: LPCSTR, lpCommandLine: CHARPTR, lpProcessAttributes: SECURITY_ATTRIBUTES | t.CPtr, lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInheritHandles: BOOL, dwCreationFlags: ULONG, lpEnvironment: VOIDPTR, lpCurrentDirectory: LPCSTR, lpStartupInfo: STARTUPINFOA | t.CPtr, lpProcessInformation: PROCESS_INFORMATION | t.CPtr) -> BOOL | t.State: pass + +def CreateProcessW(lpApplicationName: LPCWSTR, lpCommandLine: WCHARPTR, lpProcessAttributes: SECURITY_ATTRIBUTES | t.CPtr, lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInheritHandles: BOOL, dwCreationFlags: ULONG, lpEnvironment: VOIDPTR, lpCurrentDirectory: LPCWSTR, lpStartupInfo: STARTUPINFOW | t.CPtr, lpProcessInformation: PROCESS_INFORMATION | t.CPtr) -> BOOL | t.State: pass + +def TerminateProcess(hProcess: HANDLE, uExitCode: UINT) -> BOOL | t.State: pass + +def GetExitCodeProcess(hProcess: HANDLE, lpExitCode: ULONG | t.CPtr) -> BOOL | t.State: pass + +def GetExitCodeThread(hThread: HANDLE, lpExitCode: ULONG | t.CPtr) -> BOOL | t.State: pass + +def OpenProcess(dwDesiredAccess: ULONG, bInheritHandle: BOOL, dwProcessId: ULONG) -> HANDLE | t.State: pass + +def GetCurrentProcess() -> HANDLE | t.State: pass + +def GetCurrentProcessId() -> ULONG | t.State: pass + +def CreateThread(lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwStackSize: t.CSizeT, lpStartAddress: VOIDPTR, lpParameter: VOIDPTR, dwCreationFlags: ULONG, lpThreadId: ULONG | t.CPtr) -> HANDLE | t.State: pass + +def OpenThread(dwDesiredAccess: ULONG, bInheritHandle: BOOL, dwThreadId: ULONG) -> HANDLE | t.State: pass + +def SuspendThread(hThread: HANDLE) -> ULONG | t.State: pass + +def ResumeThread(hThread: HANDLE) -> ULONG | t.State: pass + +def TerminateThread(hThread: HANDLE, dwExitCode: ULONG) -> BOOL | t.State: pass + +def GetCurrentThread() -> HANDLE | t.State: pass + +def GetCurrentThreadId() -> ULONG | t.State: pass + +def GetThreadId(hThread: HANDLE) -> ULONG | t.State: pass + +def GetProcessId(hProcess: HANDLE) -> ULONG | t.State: pass + +def SetThreadPriority(hThread: HANDLE, nPriority: INT) -> BOOL | t.State: pass + +def GetThreadPriority(hThread: HANDLE) -> INT | t.State: pass + +def ExitProcess(uExitCode: UINT) -> VOID | t.State: pass + +def ExitThread(dwExitCode: ULONG) -> VOID | t.State: pass + +def TlsAlloc() -> ULONG | t.State: pass + +def TlsFree(dwTlsIndex: ULONG) -> BOOL | t.State: pass + +def TlsGetValue(dwTlsIndex: ULONG) -> VOIDPTR | t.State: pass + +def TlsSetValue(dwTlsIndex: ULONG, lpTlsValue: VOIDPTR) -> BOOL | t.State: pass diff --git a/Test/TestProject3/temp/0f4d14c17bf75b10.pyi b/Test/TestProject3/temp/0f4d14c17bf75b10.pyi index 46261cb..c414a8b 100644 --- a/Test/TestProject3/temp/0f4d14c17bf75b10.pyi +++ b/Test/TestProject3/temp/0f4d14c17bf75b10.pyi @@ -30,36 +30,36 @@ def double_add[T](a: T, b: T) -> T: pass class A[T]: - def __init__(self: A, a: T) -> t.CVoid: pass + def __init__(self: A, a: T) -> t.CInt: pass def get_a(self: A) -> T: pass class Pair[T1, T2]: - def __init__(self: Pair, first: T1, second: T2) -> t.CVoid: pass + def __init__(self: Pair, first: T1, second: T2) -> t.CInt: pass def get_first(self: Pair) -> T1: pass def get_second(self: Pair) -> T2: pass class Calculator[T]: - def __init__(self: Calculator, init_val: T) -> t.CVoid: pass + def __init__(self: Calculator, init_val: T) -> t.CInt: pass def compute(self: Calculator, other: T) -> T: pass def double_compute(self: Calculator, other: T) -> T: pass class Container[T]: - def __init__(self: Container, v: T) -> t.CVoid: pass + def __init__(self: Container, v: T) -> t.CInt: pass def get_value(self: Container) -> T: pass def get_flag(self: Container) -> CInt32T: pass @t.CVTable class Shape: - def __init__(self: Shape, x: CFloat64T, y: CFloat64T) -> t.CVoid: pass + def __init__(self: Shape, x: CFloat64T, y: CFloat64T) -> t.CInt: pass def area(self: Shape) -> CFloat64T: pass def perimeter(self: Shape) -> CFloat64T: pass def describe(self: Shape) -> CFloat64T: pass @t.CVTable class Circle(Shape): - def __init__(self: Circle, x: CFloat64T, y: CFloat64T, r: CFloat64T) -> t.CVoid: pass + def __init__(self: Circle, x: CFloat64T, y: CFloat64T, r: CFloat64T) -> t.CInt: pass def area(self: Circle) -> CFloat64T: pass def perimeter(self: Circle) -> CFloat64T: pass def scale(self: Circle, factor: CFloat64T) -> 'Circle' | CPtr: pass def move(self: Circle, dx: CFloat64T, dy: CFloat64T) -> 'Circle' | CPtr: pass @t.CVTable class Rect(Shape): - def __init__(self: Rect, x: CFloat64T, y: CFloat64T, w: CFloat64T, h: CFloat64T) -> t.CVoid: pass + def __init__(self: Rect, x: CFloat64T, y: CFloat64T, w: CFloat64T, h: CFloat64T) -> t.CInt: pass def area(self: Rect) -> CFloat64T: pass def perimeter(self: Rect) -> CFloat64T: pass def scale(self: Rect, factor: CFloat64T) -> 'Rect' | CPtr: pass @@ -67,7 +67,7 @@ class Vec2: x: CFloat64T y: CFloat64T def __new__() -> 'Vec2' | CPtr: pass - def __init__(self: Vec2, x: CFloat64T, y: CFloat64T) -> t.CVoid: pass + def __init__(self: Vec2, x: CFloat64T, y: CFloat64T) -> t.CInt: pass def __add__(self: Vec2, b: 'Vec2' | CPtr) -> 'Vec2' | CPtr: pass def __sub__(self: Vec2, b: 'Vec2' | CPtr) -> 'Vec2' | CPtr: pass def __mul__(self: Vec2, s: CFloat64T) -> 'Vec2' | CPtr: pass @@ -79,7 +79,7 @@ class Vec3: y: CFloat64T z: CFloat64T def __new__() -> 'Vec3' | CPtr: pass - def __init__(self: Vec3, x: CFloat64T, y: CFloat64T, z: CFloat64T) -> t.CVoid: pass + def __init__(self: Vec3, x: CFloat64T, y: CFloat64T, z: CFloat64T) -> t.CInt: pass def __add__(self: Vec3, b: 'Vec3' | CPtr) -> 'Vec3' | CPtr: pass def __sub__(self: Vec3, b: 'Vec3' | CPtr) -> 'Vec3' | CPtr: pass def __mul__(self: Vec3, s: CFloat64T) -> 'Vec3' | CPtr: pass @@ -89,14 +89,14 @@ class Vec3: def len_sq(self: Vec3) -> CFloat64T: pass @t.CVTable class Dog: - def __init__(self: Dog, name_val: CInt, bark_power: CInt32T) -> t.CVoid: pass + def __init__(self: Dog, name_val: CInt, bark_power: CInt32T) -> t.CInt: pass def speak(self: Dog) -> CInt: pass def bite(self: Dog) -> CInt32T: pass def take_damage(self: Dog, dmg: CInt32T) -> 'Dog' | CPtr: pass def is_alive(self: Dog) -> CInt: pass @t.CVTable class Cat: - def __init__(self: Cat, name_val: CInt, lives: CInt32T) -> t.CVoid: pass + def __init__(self: Cat, name_val: CInt, lives: CInt32T) -> t.CInt: pass def speak(self: Cat) -> CInt: pass def scratch(self: Cat) -> CInt32T: pass def take_damage(self: Cat, dmg: CInt32T) -> 'Cat' | CPtr: pass @@ -109,22 +109,22 @@ class Transform: scale_y: CFloat64T scale_z: CFloat64T def __new__() -> 'Transform' | CPtr: pass - def __init__(self: Transform, px: CFloat64T, py: CFloat64T, pz: CFloat64T) -> t.CVoid: pass + def __init__(self: Transform, px: CFloat64T, py: CFloat64T, pz: CFloat64T) -> t.CInt: pass def apply_scale(self: Transform, sx: CFloat64T, sy: CFloat64T, sz: CFloat64T) -> 'Transform' | CPtr: pass def world_position(self: Transform) -> 'Vec3' | CPtr: pass @t.CVTable class Vehicle: - def __init__(self: Vehicle, speed: CInt32T) -> t.CVoid: pass + def __init__(self: Vehicle, speed: CInt32T) -> t.CInt: pass def move(self: Vehicle) -> CInt: pass def is_running(self: Vehicle) -> CInt: pass @t.CVTable class Car(Vehicle): - def __init__(self: Car, speed: CInt32T, doors: CInt32T) -> t.CVoid: pass + def __init__(self: Car, speed: CInt32T, doors: CInt32T) -> t.CInt: pass def honk(self: Car) -> CInt: pass @t.CVTable class ElectricCar(Car): - def __init__(self: ElectricCar, speed: CInt32T, doors: CInt32T, battery: CInt32T) -> t.CVoid: pass - def charge(self: ElectricCar) -> t.CVoid: pass + def __init__(self: ElectricCar, speed: CInt32T, doors: CInt32T, battery: CInt32T) -> t.CInt: pass + def charge(self: ElectricCar) -> t.CInt: pass def move(self: ElectricCar) -> CInt: pass def main() -> CInt | CExport: pass diff --git a/Test/CPythonTest/temp/4d342c40331fc964.pyi b/Test/TestProject3/temp/2953a7db4185005b.pyi similarity index 100% rename from Test/CPythonTest/temp/4d342c40331fc964.pyi rename to Test/TestProject3/temp/2953a7db4185005b.pyi diff --git a/Test/TestProject3/temp/29813d57621099a9.pyi b/Test/TestProject3/temp/29813d57621099a9.pyi new file mode 100644 index 0000000..a5e9923 --- /dev/null +++ b/Test/TestProject3/temp/29813d57621099a9.pyi @@ -0,0 +1,85 @@ +""" +Auto-generated Python stub file from w32.win32sync.py +Module: w32.win32sync +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +class CRITICAL_SECTION: + DebugInfo: VOIDPTR + LockCount: LONG + RecursionCount: LONG + OwningThread: HANDLE + LockSemaphore: HANDLE + SpinCount: QWORD + +def InitializeCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def EnterCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def LeaveCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def DeleteCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def TryEnterCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> BOOL | t.State: pass + +def SetCriticalSectionSpinCount(lpCriticalSection: CRITICAL_SECTION | t.CPtr, dwSpinCount: ULONG) -> ULONG | t.State: pass + +def InitializeCriticalSectionAndSpinCount(lpCriticalSection: CRITICAL_SECTION | t.CPtr, dwSpinCount: ULONG) -> BOOL | t.State: pass + +def CreateMutexA(lpMutexAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInitialOwner: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def CreateMutexW(lpMutexAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInitialOwner: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def OpenMutexA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def OpenMutexW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def ReleaseMutex(hMutex: HANDLE) -> BOOL | t.State: pass + +def CreateEventA(lpEventAttributes: SECURITY_ATTRIBUTES | t.CPtr, bManualReset: BOOL, bInitialState: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def CreateEventW(lpEventAttributes: SECURITY_ATTRIBUTES | t.CPtr, bManualReset: BOOL, bInitialState: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def OpenEventA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def OpenEventW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def SetEvent(hEvent: HANDLE) -> BOOL | t.State: pass + +def ResetEvent(hEvent: HANDLE) -> BOOL | t.State: pass + +def PulseEvent(hEvent: HANDLE) -> BOOL | t.State: pass + +def CreateSemaphoreA(lpSemaphoreAttributes: SECURITY_ATTRIBUTES | t.CPtr, lInitialCount: LONG, lMaximumCount: LONG, lpName: LPCSTR) -> HANDLE | t.State: pass + +def CreateSemaphoreW(lpSemaphoreAttributes: SECURITY_ATTRIBUTES | t.CPtr, lInitialCount: LONG, lMaximumCount: LONG, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def OpenSemaphoreA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def OpenSemaphoreW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def ReleaseSemaphore(hSemaphore: HANDLE, lReleaseCount: LONG, lpPreviousCount: LONG | t.CPtr) -> BOOL | t.State: pass + +def WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: ULONG) -> ULONG | t.State: pass + +def WaitForSingleObjectEx(hHandle: HANDLE, dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG | t.State: pass + +def WaitForMultipleObjects(nCount: ULONG, lpHandles: VOIDPTR, bWaitAll: BOOL, dwMilliseconds: ULONG) -> ULONG | t.State: pass + +def WaitForMultipleObjectsEx(nCount: ULONG, lpHandles: VOIDPTR, bWaitAll: BOOL, dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG | t.State: pass + +def InitializeSRWLock(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def AcquireSRWLockExclusive(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def AcquireSRWLockShared(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def ReleaseSRWLockExclusive(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def ReleaseSRWLockShared(SRWLock: VOIDPTR) -> VOID | t.State: pass diff --git a/Test/TestProject3/temp/3fdd11bdd589aa8c.pyi b/Test/TestProject3/temp/3fdd11bdd589aa8c.pyi index 4062ae4..de3fa77 100644 --- a/Test/TestProject3/temp/3fdd11bdd589aa8c.pyi +++ b/Test/TestProject3/temp/3fdd11bdd589aa8c.pyi @@ -14,11 +14,11 @@ class Vector[T]: capacity: t.CSizeT elem_size: t.CSizeT pool: mpool.MPool | t.CPtr - def __init__(self: Vector, pool: mpool.MPool | t.CPtr, capacity: t.CSizeT, _hint: T) -> t.CVoid: pass - def push(self: Vector, value: T) -> t.CVoid: pass - def _grow(self: Vector) -> t.CVoid: pass + def __init__(self: Vector, pool: mpool.MPool | t.CPtr, capacity: t.CSizeT, _hint: T) -> t.CInt: pass + def push(self: Vector, value: T) -> t.CInt: pass + def _grow(self: Vector) -> t.CInt: pass def get(self: Vector, index: t.CSizeT) -> T: pass - def set(self: Vector, index: t.CSizeT, value: T) -> t.CVoid: pass + def set(self: Vector, index: t.CSizeT, value: T) -> t.CInt: pass def len(self: Vector) -> t.CSizeT: pass - def clear(self: Vector) -> t.CVoid: pass - def free(self: Vector) -> t.CVoid: pass \ No newline at end of file + def clear(self: Vector) -> t.CInt: pass + def free(self: Vector) -> t.CInt: pass \ No newline at end of file diff --git a/Test/TestProject3/temp/4d342c40331fc964.pyi b/Test/TestProject3/temp/4d342c40331fc964.pyi deleted file mode 100644 index aa40bc7..0000000 --- a/Test/TestProject3/temp/4d342c40331fc964.pyi +++ /dev/null @@ -1,19 +0,0 @@ -""" -Auto-generated Python stub file from viperlib.py -Module: viperlib -""" - - -import t, c -import viperio -from stdarg import arg - -TEMP_BUF_SIZE: t.CDefine = 24 - -def get_digit_count(num: t.CUnsignedInt, base: t.CInt) -> t.CStatic | t.CInt | t.State: pass - -def sprintf(buf: t.CChar | t.CPtr, rule: str, *args) -> t.CVoid | t.State: pass - -def vsprintf(buf: t.CChar | t.CPtr, rule: str, *args) -> t.CInt | t.State: pass - -def snprintf(buf: t.CChar | t.CPtr, size: t.CSizeT, fmt: str, *args) -> t.CInt | t.State: pass diff --git a/Test/TestProject3/temp/68c4fe4b12c908e3.pyi b/Test/TestProject3/temp/68c4fe4b12c908e3.pyi new file mode 100644 index 0000000..fc2010b --- /dev/null +++ b/Test/TestProject3/temp/68c4fe4b12c908e3.pyi @@ -0,0 +1,50 @@ +""" +Auto-generated Python stub file from mpool.py +Module: mpool +""" + + +import t, c +from stdint import * +import viperio +import string + +MPOOL_ALIGN: t.CDefine = 8 +MPOOL_TYPE_SLAB: t.CDefine = 0 +MPOOL_TYPE_BUMP: t.CDefine = 2 + +def _align_up(val: t.CSizeT, align: t.CSizeT) -> t.CSizeT: pass + + +class MPool: + mtype: t.CInt + mem: t.CVoid | t.CPtr + mem_size: t.CSizeT + offset: t.CSizeT + high_water: t.CSizeT + block_size: t.CSizeT + block_count: t.CSizeT + used_count: t.CSizeT + free_list: t.CVoid | t.CPtr + alloc_map: t.CUInt8T | t.CPtr + alloc_map_size: t.CSizeT + def __init__(self: MPool, mem: t.CVoid | t.CPtr, mem_size: t.CSizeT, block_size: t.CSizeT) -> t.CInt: pass + def _init_bump(self: MPool, mem: t.CVoid | t.CPtr, mem_size: t.CSizeT) -> t.CInt: pass + def _init_slab(self: MPool, mem: t.CVoid | t.CPtr, mem_size: t.CSizeT, block_size: t.CSizeT) -> t.CInt: pass + def __enter__(self: MPool) -> 'MPool' | t.CPtr: pass + def __exit__(self: MPool) -> t.CInt: pass + def _slab_reset(self: MPool) -> t.CInt: pass + def alloc(self: MPool, size: t.CSizeT) -> t.CVoid | t.CPtr: pass + def alloc_buf(self: MPool, capacity: t.CSizeT) -> viperio.Buf | t.CPtr: pass + def free(self: MPool, ptr: t.CVoid | t.CPtr) -> t.CInt: pass + def realloc(self: MPool, ptr: t.CVoid | t.CPtr, old_size: t.CSizeT, new_size: t.CSizeT) -> t.CVoid | t.CPtr: pass + def reset(self: MPool) -> t.CInt: pass + def _bump_alloc(self: MPool, size: t.CSizeT) -> t.CVoid | t.CPtr: pass + def _slab_alloc(self: MPool) -> t.CVoid | t.CPtr: pass + def _slab_free(self: MPool, ptr: t.CVoid | t.CPtr) -> t.CInt: pass + +def bump_create(mem: t.CVoid | t.CPtr, mem_size: t.CSizeT) -> MPool | t.CPtr: pass + +def alloc(pool: MPool | t.CPtr, size: t.CSizeT) -> t.CVoid | t.CPtr: pass + +def reset(pool: MPool | t.CPtr) -> t.CInt: pass diff --git a/Test/TestProject3/temp/6aee24fdefa3cbc0.pyi b/Test/TestProject3/temp/6aee24fdefa3cbc0.pyi new file mode 100644 index 0000000..c17475f --- /dev/null +++ b/Test/TestProject3/temp/6aee24fdefa3cbc0.pyi @@ -0,0 +1,44 @@ +""" +Auto-generated Python stub file from string.py +Module: string +""" + + +from stdint import * +import t, c + +def strcpy(dest: str, src: str) -> str: pass + +def strncpy(dest: str, src: str, n: t.CSizeT) -> str: pass + +def strlen(src: str) -> t.CSizeT | t.CExport: pass + +def strcmp(str1: str, str2: str) -> t.CInt: pass + +def samestr(str1: str, str2: str) -> bool: pass + +def strncmp(str1: str, str2: str, n: t.CSizeT) -> t.CInt: pass + +def memcmp(ptr1: t.CVoid | t.CPtr, ptr2: t.CVoid | t.CPtr, n: t.CSizeT) -> t.CInt: pass + +def strchr(s: str, cr: t.CInt) -> str: pass + +def strrchr(s: str, cr: t.CInt) -> str: pass + +def strspn(s: str, skip: str) -> int: pass + +def memset(ptr: t.CVoid | t.CPtr, value: t.CInt, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass + +def memset32(ptr: t.CVoid | t.CPtr, value: t.CUInt32T, count: t.CSizeT) -> t.CVoid | t.CPtr: pass + +def memcpy(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass + +def memmove(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr: pass + +def atoi(src: str) -> t.CInt: pass + +def atoll(src: str) -> t.CInt64T: pass + +def atof(src: str) -> t.CDouble: pass + +def split(s: str, delim: str, result: list[str]) -> int: pass diff --git a/Test/TestProject3/temp/6c2029b306556c00.pyi b/Test/TestProject3/temp/6c2029b306556c00.pyi new file mode 100644 index 0000000..98da680 --- /dev/null +++ b/Test/TestProject3/temp/6c2029b306556c00.pyi @@ -0,0 +1,18 @@ +""" +Auto-generated Python stub file from stdlib.py +Module: stdlib +""" + +import c + + +from stdint import * +import t + +def malloc(size: t.CSizeT) -> t.CVoid | t.CPtr | t.State | t.CExtern | t.CExport: pass + +def calloc(nmemb: t.CSizeT, size: t.CSizeT) -> t.CVoid | t.CPtr | t.State | t.CExtern | t.CExport: pass + +def realloc(p: t.CVoid | t.CPtr, size: t.CSizeT) -> t.CVoid | t.CPtr | t.State | t.CExtern | t.CExport: pass + +def free(p: t.CVoid | t.CPtr) -> None | t.State | t.CExtern | t.CExport: pass diff --git a/Test/TestProject3/temp/72e2d5ccb7cedcf1.pyi b/Test/TestProject3/temp/72e2d5ccb7cedcf1.pyi new file mode 100644 index 0000000..5fceb08 --- /dev/null +++ b/Test/TestProject3/temp/72e2d5ccb7cedcf1.pyi @@ -0,0 +1,91 @@ +""" +Auto-generated Python stub file from w32.win32memory.py +Module: w32.win32memory +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +MEM_COMMIT: t.CDefine = 0x00001000 +MEM_RESERVE: t.CDefine = 0x00002000 +MEM_DECOMMIT: t.CDefine = 0x00004000 +MEM_RELEASE: t.CDefine = 0x00008000 +MEM_FREE: t.CDefine = 0x00010000 +MEM_RESET: t.CDefine = 0x00080000 +MEM_TOP_DOWN: t.CDefine = 0x00100000 +MEM_WRITE_WATCH: t.CDefine = 0x00200000 +MEM_PHYSICAL: t.CDefine = 0x00400000 +MEM_LARGE_PAGES: t.CDefine = 0x20000000 +PAGE_NOACCESS: t.CDefine = 0x01 +PAGE_READONLY: t.CDefine = 0x02 +PAGE_READWRITE: t.CDefine = 0x04 +PAGE_WRITECOPY: t.CDefine = 0x08 +PAGE_EXECUTE: t.CDefine = 0x10 +PAGE_EXECUTE_READ: t.CDefine = 0x20 +PAGE_EXECUTE_READWRITE: t.CDefine = 0x40 +PAGE_EXECUTE_WRITECOPY: t.CDefine = 0x80 +PAGE_GUARD: t.CDefine = 0x100 +PAGE_NOCACHE: t.CDefine = 0x200 +PAGE_WRITECOMBINE: t.CDefine = 0x400 +HEAP_NO_SERIALIZE: t.CDefine = 0x00000001 +HEAP_GROWABLE: t.CDefine = 0x00000002 +HEAP_GENERATE_EXCEPTIONS: t.CDefine = 0x00000004 +HEAP_ZERO_MEMORY: t.CDefine = 0x00000008 +HEAP_REALLOC_IN_PLACE_ONLY: t.CDefine = 0x00000010 + +class MEMORY_BASIC_INFORMATION: + BaseAddress: VOIDPTR + AllocationBase: VOIDPTR + AllocationProtect: ULONG + RegionSize: t.CSizeT + State: ULONG + Protect: ULONG + Type: ULONG + +def VirtualAlloc(lpAddress: VOIDPTR, dwSize: t.CSizeT, flAllocationType: ULONG, flProtect: ULONG) -> VOIDPTR | t.State: pass + +def VirtualFree(lpAddress: VOIDPTR, dwSize: t.CSizeT, dwFreeType: ULONG) -> BOOL | t.State: pass + +def VirtualProtect(lpAddress: VOIDPTR, dwSize: t.CSizeT, flNewProtect: ULONG, lpflOldProtect: ULONG | t.CPtr) -> BOOL | t.State: pass + +def VirtualQuery(lpAddress: t.CConst | VOIDPTR, lpBuffer: MEMORY_BASIC_INFORMATION | t.CPtr, dwLength: t.CSizeT) -> t.CSizeT | t.State: pass + +def VirtualLock(lpAddress: VOIDPTR, dwSize: t.CSizeT) -> BOOL | t.State: pass + +def VirtualUnlock(lpAddress: VOIDPTR, dwSize: t.CSizeT) -> BOOL | t.State: pass + +def GetProcessHeap() -> HANDLE | t.State: pass + +def HeapCreate(flOptions: ULONG, dwInitialSize: t.CSizeT, dwMaximumSize: t.CSizeT) -> HANDLE | t.State: pass + +def HeapDestroy(hHeap: HANDLE) -> BOOL | t.State: pass + +def HeapAlloc(hHeap: HANDLE, dwFlags: ULONG, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def HeapReAlloc(hHeap: HANDLE, dwFlags: ULONG, lpMem: VOIDPTR, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def HeapFree(hHeap: HANDLE, dwFlags: ULONG, lpMem: VOIDPTR) -> BOOL | t.State: pass + +def HeapSize(hHeap: HANDLE, dwFlags: ULONG, lpMem: t.CConst | VOIDPTR) -> t.CSizeT | t.State: pass + +def HeapValidate(hHeap: HANDLE, dwFlags: ULONG, lpMem: t.CConst | VOIDPTR) -> BOOL | t.State: pass + +def HeapCompact(hHeap: HANDLE, dwFlags: ULONG) -> t.CSizeT | t.State: pass + +def GlobalAlloc(uFlags: UINT, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def GlobalFree(hMem: VOIDPTR) -> VOIDPTR | t.State: pass + +def GlobalLock(hMem: VOIDPTR) -> VOIDPTR | t.State: pass + +def GlobalUnlock(hMem: VOIDPTR) -> BOOL | t.State: pass + +def GlobalSize(hMem: VOIDPTR) -> t.CSizeT | t.State: pass + +def LocalAlloc(uFlags: UINT, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def LocalFree(hMem: VOIDPTR) -> VOIDPTR | t.State: pass diff --git a/Test/TestProject3/temp/_sha1_map.txt b/Test/TestProject3/temp/_sha1_map.txt index f36c421..5672ef4 100644 --- a/Test/TestProject3/temp/_sha1_map.txt +++ b/Test/TestProject3/temp/_sha1_map.txt @@ -1,19 +1,19 @@ -087c910044fab2d2:fileiotest.py 0f4d14c17bf75b10:main.py 1b58766d38d05de3:enumtest.py -21ffad37f6fc3fcf:includes/mpool.py +2953a7db4185005b:includes/viperlib.py 3fdd11bdd589aa8c:includes/vector.py -4d342c40331fc964:includes/viperlib.py 5325ec533a59d71b:mpooltest.py 56cdd754a8a09347:includes/stdint.py 5a6a2137958c28c5:includes/w32\win32base.py 64ac83614c9bdbc6:definetest.py +68c4fe4b12c908e3:includes/mpool.py +6aee24fdefa3cbc0:includes/string.py +6c2029b306556c00:includes/stdlib.py 71e0a3ffcb3ebfad:includes/stdarg.py 93c1d18e35d188d6:includes/platmacro.py -a326a52b7c4bd6f0:includes/string.py -a96738831f025829:includes/stdlib.py abf9ce3160c9279e:includes/w32\win32file.py bbdf3bbd4c3bc28c:includes/w32\win32console.py +c01b27dbcd683245:fileiotest.py c9f4be41ca1cc2b4:includes/viperio.py fa3691e66b426950:includes/w32\fileio.py fc49f6314bad25e9:vectortest.py diff --git a/Test/TestProject3/temp/_shared_sym.pkl b/Test/TestProject3/temp/_shared_sym.pkl index 0a148800f469c0db3d15a0b994c62d8d7b90f1bb..726a0e13802ac0ca151b20e76f3238874a1fcc99 100644 GIT binary patch literal 484319 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�b$Kf1a#)p^D1OX4Wwu8^bR$K~)oc<#qh6Gx4V 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 %za={t;zR8 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 F{{!6Ud3OK+ diff --git a/Test/TestProject3/temp/a326a52b7c4bd6f0.pyi b/Test/TestProject3/temp/a326a52b7c4bd6f0.pyi deleted file mode 100644 index eae6834..0000000 --- a/Test/TestProject3/temp/a326a52b7c4bd6f0.pyi +++ /dev/null @@ -1,40 +0,0 @@ -""" -Auto-generated Python stub file from string.py -Module: string -""" - - -from stdint import * -import t, c - -def strcpy(dest: str, src: str) -> str: pass - -def strncpy(dest: str, src: str, n: t.CSizeT) -> str: pass - -def strlen(src: str) -> t.CSizeT | t.CExport: pass - -def strcmp(str1: str, str2: str) -> t.CInt: pass - -def samestr(str1: str, str2: str) -> bool: pass - -def strncmp(str1: str, str2: str, n: t.CSizeT) -> t.CInt: pass - -def memcmp(ptr1: t.CVoid | t.CPtr, ptr2: t.CVoid | t.CPtr, n: t.CSizeT) -> t.CInt: pass - -def strchr(s: str, cr: t.CInt) -> str: pass - -def strrchr(s: str, cr: t.CInt) -> str: pass - -def strspn(s: str, skip: str) -> int: pass - -def memset(ptr: t.CVoid | t.CPtr, value: t.CInt, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass - -def memset32(ptr: t.CVoid | t.CPtr, value: t.CUInt32T, count: t.CSizeT) -> t.CVoid | t.CPtr: pass - -def memcpy(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass - -def memmove(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr: pass - -def atoi(src: str) -> t.CInt: pass - -def split(s: str, delim: str, result: list[str]) -> int: pass diff --git a/Test/TestProject3/temp/a96738831f025829.pyi b/Test/TestProject3/temp/a96738831f025829.pyi deleted file mode 100644 index c499547..0000000 --- a/Test/TestProject3/temp/a96738831f025829.pyi +++ /dev/null @@ -1,16 +0,0 @@ -""" -Auto-generated Python stub file from stdlib.py -Module: stdlib -""" - -import c - - -from stdint import * -import t - -def malloc(size: UINT) -> t.CVoid | t.CPtr | t.State | t.CExtern | t.CExport: pass - -def realloc(p: str, p2: t.CLong | t.CLong) -> t.CVoid | t.CPtr | t.State | t.CExtern | t.CExport: pass - -def free(p: t.CVoid | t.CPtr) -> None | t.State | t.CExtern | t.CExport: pass diff --git a/Test/TestProject3/temp/087c910044fab2d2.pyi b/Test/TestProject3/temp/c01b27dbcd683245.pyi similarity index 62% rename from Test/TestProject3/temp/087c910044fab2d2.pyi rename to Test/TestProject3/temp/c01b27dbcd683245.pyi index b7d60d2..fdb53f8 100644 --- a/Test/TestProject3/temp/087c910044fab2d2.pyi +++ b/Test/TestProject3/temp/c01b27dbcd683245.pyi @@ -17,14 +17,14 @@ from w32.fileio import File, FileW, MODE, FRESULT, SEEK_SET, SEEK_CUR, SEEK_END BUF_SIZE: t.CDefine = 4096 -def fileio_main() -> t.CVoid: pass +def fileio_main() -> t.CInt: pass -def fileio_with_test() -> t.CVoid: pass +def fileio_with_test() -> t.CInt: pass -def fileio_handle_test() -> t.CVoid: pass +def fileio_handle_test() -> t.CInt: pass -def fileio_rw_test() -> t.CVoid: pass +def fileio_rw_test() -> t.CInt: pass -def fileio_wide_test() -> t.CVoid: pass +def fileio_wide_test() -> t.CInt: pass -def fileio_chinese_test() -> t.CVoid: pass +def fileio_chinese_test() -> t.CInt: pass diff --git a/Test/TestProject3/temp/c9f4be41ca1cc2b4.pyi b/Test/TestProject3/temp/c9f4be41ca1cc2b4.pyi index 2c2291b..fdbd7ec 100644 --- a/Test/TestProject3/temp/c9f4be41ca1cc2b4.pyi +++ b/Test/TestProject3/temp/c9f4be41ca1cc2b4.pyi @@ -12,11 +12,11 @@ class Buf: length: t.CSizeT capacity: t.CSizeT owned: bool - def __init__(self: Buf, data: t.CChar | t.CPtr, capacity: t.CSizeT, length: t.CSizeT, owned: bool) -> t.CVoid: pass - def clear(self: Buf) -> t.CVoid: pass + def __init__(self: Buf, data: t.CChar | t.CPtr, capacity: t.CSizeT, length: t.CSizeT, owned: bool) -> t.CInt: pass + def clear(self: Buf) -> t.CInt: pass def write(self: Buf, src: t.CChar | t.CPtr, count: t.CSizeT) -> t.CSizeT: pass def cstr(self: Buf) -> t.CChar | t.CPtr: pass - def reset(self: Buf) -> t.CVoid: pass + def reset(self: Buf) -> t.CInt: pass def __enter__(self: Buf) -> 'Buf' | t.CPtr: pass - def __exit__(self: Buf) -> t.CVoid: pass - def free(self: Buf) -> t.CVoid: pass \ No newline at end of file + def __exit__(self: Buf) -> t.CInt: pass + def free(self: Buf) -> t.CInt: pass \ No newline at end of file diff --git a/Test/TestProject3/temp/fa3691e66b426950.pyi b/Test/TestProject3/temp/fa3691e66b426950.pyi index 109c920..48fd36c 100644 --- a/Test/TestProject3/temp/fa3691e66b426950.pyi +++ b/Test/TestProject3/temp/fa3691e66b426950.pyi @@ -41,9 +41,9 @@ class File: can_write: bool is_append: bool _share_mode: ULONG - def __init__(self: File, filename: str, mode: ULONG, share: ULONG) -> t.CVoid: pass + def __init__(self: File, filename: str, mode: ULONG, share: ULONG) -> t.CInt: pass def __enter__(self: File) -> 'File' | t.CPtr: pass - def __exit__(self: File) -> t.CVoid: pass + def __exit__(self: File) -> t.CInt: pass def read(self: File, buf: bytes, count: ULONG) -> LONG: pass def write(self: File, buf: bytes, count: ULONG) -> LONG: pass def write_str(self: File, s: str) -> LONG: pass @@ -61,9 +61,9 @@ class FileW: can_write: bool is_append: bool _share_mode: ULONG - def __init__(self: FileW, filename: LPCWSTR, mode: ULONG, share: ULONG) -> t.CVoid: pass + def __init__(self: FileW, filename: LPCWSTR, mode: ULONG, share: ULONG) -> t.CInt: pass def __enter__(self: FileW) -> 'FileW' | t.CPtr: pass - def __exit__(self: FileW) -> t.CVoid: pass + def __exit__(self: FileW) -> t.CInt: pass def read(self: FileW, buf: bytes, count: ULONG) -> LONG: pass def write(self: FileW, buf: bytes, count: ULONG) -> LONG: pass def write_str(self: FileW, s: str) -> LONG: pass diff --git a/Test/TypeCastTest/output/067c78e9f121dce3.deps.json b/Test/TypeCastTest/output/067c78e9f121dce3.deps.json index 52b8465..cd8312a 100644 --- a/Test/TypeCastTest/output/067c78e9f121dce3.deps.json +++ b/Test/TypeCastTest/output/067c78e9f121dce3.deps.json @@ -1 +1 @@ -{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "string": "a326a52b7c4bd6f0", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "bf230611b27080fa", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3"} \ No newline at end of file +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "bf230611b27080fa", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3"} \ No newline at end of file diff --git a/Test/TypeCastTest/output/29813d57621099a9.deps.json b/Test/TypeCastTest/output/29813d57621099a9.deps.json index 4159704..0e31226 100644 --- a/Test/TypeCastTest/output/29813d57621099a9.deps.json +++ b/Test/TypeCastTest/output/29813d57621099a9.deps.json @@ -1 +1 @@ -{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "string": "a326a52b7c4bd6f0", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "bf230611b27080fa", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "bf230611b27080fa", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file diff --git a/Test/TypeCastTest/output/5a6a2137958c28c5.deps.json b/Test/TypeCastTest/output/5a6a2137958c28c5.deps.json index a9f1746..276387f 100644 --- a/Test/TypeCastTest/output/5a6a2137958c28c5.deps.json +++ b/Test/TypeCastTest/output/5a6a2137958c28c5.deps.json @@ -1 +1 @@ -{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "string": "a326a52b7c4bd6f0", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "bf230611b27080fa", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "bf230611b27080fa", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/TypeCastTest/output/6aee24fdefa3cbc0.deps.json b/Test/TypeCastTest/output/6aee24fdefa3cbc0.deps.json new file mode 100644 index 0000000..5cd9b08 --- /dev/null +++ b/Test/TypeCastTest/output/6aee24fdefa3cbc0.deps.json @@ -0,0 +1 @@ +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "bf230611b27080fa"} \ No newline at end of file diff --git a/Test/TypeCastTest/output/72e2d5ccb7cedcf1.deps.json b/Test/TypeCastTest/output/72e2d5ccb7cedcf1.deps.json index 1340dfa..00aa2be 100644 --- a/Test/TypeCastTest/output/72e2d5ccb7cedcf1.deps.json +++ b/Test/TypeCastTest/output/72e2d5ccb7cedcf1.deps.json @@ -1 +1 @@ -{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "string": "a326a52b7c4bd6f0", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "bf230611b27080fa", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e"} \ No newline at end of file +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "bf230611b27080fa", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e"} \ No newline at end of file diff --git a/Test/TypeCastTest/output/a326a52b7c4bd6f0.deps.json b/Test/TypeCastTest/output/a326a52b7c4bd6f0.deps.json deleted file mode 100644 index d9c58a4..0000000 --- a/Test/TypeCastTest/output/a326a52b7c4bd6f0.deps.json +++ /dev/null @@ -1 +0,0 @@ -{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "string": "a326a52b7c4bd6f0", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "bf230611b27080fa"} \ No newline at end of file diff --git a/Test/TypeCastTest/output/abf9ce3160c9279e.deps.json b/Test/TypeCastTest/output/abf9ce3160c9279e.deps.json index 1340dfa..00aa2be 100644 --- a/Test/TypeCastTest/output/abf9ce3160c9279e.deps.json +++ b/Test/TypeCastTest/output/abf9ce3160c9279e.deps.json @@ -1 +1 @@ -{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "string": "a326a52b7c4bd6f0", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "bf230611b27080fa", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e"} \ No newline at end of file +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "bf230611b27080fa", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e"} \ No newline at end of file diff --git a/Test/TypeCastTest/output/bbdf3bbd4c3bc28c.deps.json b/Test/TypeCastTest/output/bbdf3bbd4c3bc28c.deps.json index a9f1746..276387f 100644 --- a/Test/TypeCastTest/output/bbdf3bbd4c3bc28c.deps.json +++ b/Test/TypeCastTest/output/bbdf3bbd4c3bc28c.deps.json @@ -1 +1 @@ -{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "string": "a326a52b7c4bd6f0", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "bf230611b27080fa", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "bf230611b27080fa", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/TypeCastTest/output/bf230611b27080fa.deps.json b/Test/TypeCastTest/output/bf230611b27080fa.deps.json index 73440e6..2fc9271 100644 --- a/Test/TypeCastTest/output/bf230611b27080fa.deps.json +++ b/Test/TypeCastTest/output/bf230611b27080fa.deps.json @@ -1 +1 @@ -{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "string": "a326a52b7c4bd6f0", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c"} \ No newline at end of file +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c"} \ No newline at end of file diff --git a/Test/TypeCastTest/output/fa3691e66b426950.deps.json b/Test/TypeCastTest/output/fa3691e66b426950.deps.json index a9f1746..276387f 100644 --- a/Test/TypeCastTest/output/fa3691e66b426950.deps.json +++ b/Test/TypeCastTest/output/fa3691e66b426950.deps.json @@ -1 +1 @@ -{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "string": "a326a52b7c4bd6f0", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "bf230611b27080fa", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "bf230611b27080fa", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/TypeCastTest/temp/6aee24fdefa3cbc0.pyi b/Test/TypeCastTest/temp/6aee24fdefa3cbc0.pyi new file mode 100644 index 0000000..c17475f --- /dev/null +++ b/Test/TypeCastTest/temp/6aee24fdefa3cbc0.pyi @@ -0,0 +1,44 @@ +""" +Auto-generated Python stub file from string.py +Module: string +""" + + +from stdint import * +import t, c + +def strcpy(dest: str, src: str) -> str: pass + +def strncpy(dest: str, src: str, n: t.CSizeT) -> str: pass + +def strlen(src: str) -> t.CSizeT | t.CExport: pass + +def strcmp(str1: str, str2: str) -> t.CInt: pass + +def samestr(str1: str, str2: str) -> bool: pass + +def strncmp(str1: str, str2: str, n: t.CSizeT) -> t.CInt: pass + +def memcmp(ptr1: t.CVoid | t.CPtr, ptr2: t.CVoid | t.CPtr, n: t.CSizeT) -> t.CInt: pass + +def strchr(s: str, cr: t.CInt) -> str: pass + +def strrchr(s: str, cr: t.CInt) -> str: pass + +def strspn(s: str, skip: str) -> int: pass + +def memset(ptr: t.CVoid | t.CPtr, value: t.CInt, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass + +def memset32(ptr: t.CVoid | t.CPtr, value: t.CUInt32T, count: t.CSizeT) -> t.CVoid | t.CPtr: pass + +def memcpy(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass + +def memmove(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr: pass + +def atoi(src: str) -> t.CInt: pass + +def atoll(src: str) -> t.CInt64T: pass + +def atof(src: str) -> t.CDouble: pass + +def split(s: str, delim: str, result: list[str]) -> int: pass diff --git a/Test/TypeCastTest/temp/_sha1_map.txt b/Test/TypeCastTest/temp/_sha1_map.txt index 3de0bca..0c48640 100644 --- a/Test/TypeCastTest/temp/_sha1_map.txt +++ b/Test/TypeCastTest/temp/_sha1_map.txt @@ -1,7 +1,7 @@ 56cdd754a8a09347:includes/stdint.py 5a6a2137958c28c5:includes/w32\win32base.py +6aee24fdefa3cbc0:includes/string.py 72e2d5ccb7cedcf1:includes/w32\win32memory.py 73edbcf76e32d00b:includes/stdio.py -a326a52b7c4bd6f0:includes/string.py bbdf3bbd4c3bc28c:includes/w32\win32console.py bf230611b27080fa:main.py diff --git a/Test/TypeCastTest/temp/a326a52b7c4bd6f0.pyi b/Test/TypeCastTest/temp/a326a52b7c4bd6f0.pyi deleted file mode 100644 index eae6834..0000000 --- a/Test/TypeCastTest/temp/a326a52b7c4bd6f0.pyi +++ /dev/null @@ -1,40 +0,0 @@ -""" -Auto-generated Python stub file from string.py -Module: string -""" - - -from stdint import * -import t, c - -def strcpy(dest: str, src: str) -> str: pass - -def strncpy(dest: str, src: str, n: t.CSizeT) -> str: pass - -def strlen(src: str) -> t.CSizeT | t.CExport: pass - -def strcmp(str1: str, str2: str) -> t.CInt: pass - -def samestr(str1: str, str2: str) -> bool: pass - -def strncmp(str1: str, str2: str, n: t.CSizeT) -> t.CInt: pass - -def memcmp(ptr1: t.CVoid | t.CPtr, ptr2: t.CVoid | t.CPtr, n: t.CSizeT) -> t.CInt: pass - -def strchr(s: str, cr: t.CInt) -> str: pass - -def strrchr(s: str, cr: t.CInt) -> str: pass - -def strspn(s: str, skip: str) -> int: pass - -def memset(ptr: t.CVoid | t.CPtr, value: t.CInt, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass - -def memset32(ptr: t.CVoid | t.CPtr, value: t.CUInt32T, count: t.CSizeT) -> t.CVoid | t.CPtr: pass - -def memcpy(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass - -def memmove(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr: pass - -def atoi(src: str) -> t.CInt: pass - -def split(s: str, delim: str, result: list[str]) -> int: pass diff --git a/Test/VariadicTest/output/067c78e9f121dce3.deps.json b/Test/VariadicTest/output/067c78e9f121dce3.deps.json index 47eefe1..c11e2c3 100644 --- a/Test/VariadicTest/output/067c78e9f121dce3.deps.json +++ b/Test/VariadicTest/output/067c78e9f121dce3.deps.json @@ -1 +1 @@ -{"viperlib": "2953a7db4185005b", "main": "377ad03e9b90ac39", "string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "stdarg": "71e0a3ffcb3ebfad", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3"} \ No newline at end of file +{"viperlib": "2953a7db4185005b", "main": "377ad03e9b90ac39", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "stdarg": "71e0a3ffcb3ebfad", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3"} \ No newline at end of file diff --git a/Test/VariadicTest/output/2953a7db4185005b.deps.json b/Test/VariadicTest/output/2953a7db4185005b.deps.json index ffc1ba9..43983e1 100644 --- a/Test/VariadicTest/output/2953a7db4185005b.deps.json +++ b/Test/VariadicTest/output/2953a7db4185005b.deps.json @@ -1 +1 @@ -{"viperlib": "2953a7db4185005b", "main": "377ad03e9b90ac39", "string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "stdarg": "71e0a3ffcb3ebfad", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file +{"viperlib": "2953a7db4185005b", "main": "377ad03e9b90ac39", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "stdarg": "71e0a3ffcb3ebfad", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4"} \ No newline at end of file diff --git a/Test/VariadicTest/output/29813d57621099a9.deps.json b/Test/VariadicTest/output/29813d57621099a9.deps.json index ffc1ba9..abec65b 100644 --- a/Test/VariadicTest/output/29813d57621099a9.deps.json +++ b/Test/VariadicTest/output/29813d57621099a9.deps.json @@ -1 +1 @@ -{"viperlib": "2953a7db4185005b", "main": "377ad03e9b90ac39", "string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "stdarg": "71e0a3ffcb3ebfad", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file +{"viperlib": "2953a7db4185005b", "main": "377ad03e9b90ac39", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "stdarg": "71e0a3ffcb3ebfad", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file diff --git a/Test/VariadicTest/output/377ad03e9b90ac39.deps.json b/Test/VariadicTest/output/377ad03e9b90ac39.deps.json index affbd7f..2839e14 100644 --- a/Test/VariadicTest/output/377ad03e9b90ac39.deps.json +++ b/Test/VariadicTest/output/377ad03e9b90ac39.deps.json @@ -1 +1 @@ -{"viperlib": "2953a7db4185005b", "string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "stdarg": "71e0a3ffcb3ebfad", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4"} \ No newline at end of file +{"viperlib": "2953a7db4185005b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "stdarg": "71e0a3ffcb3ebfad", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4"} \ No newline at end of file diff --git a/Test/VariadicTest/output/5a6a2137958c28c5.deps.json b/Test/VariadicTest/output/5a6a2137958c28c5.deps.json index 592b804..791ea77 100644 --- a/Test/VariadicTest/output/5a6a2137958c28c5.deps.json +++ b/Test/VariadicTest/output/5a6a2137958c28c5.deps.json @@ -1 +1 @@ -{"viperlib": "2953a7db4185005b", "main": "377ad03e9b90ac39", "string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "stdarg": "71e0a3ffcb3ebfad", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file +{"viperlib": "2953a7db4185005b", "main": "377ad03e9b90ac39", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "stdarg": "71e0a3ffcb3ebfad", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/VariadicTest/output/4d5db7f970ef510f.deps.json b/Test/VariadicTest/output/6aee24fdefa3cbc0.deps.json similarity index 64% rename from Test/VariadicTest/output/4d5db7f970ef510f.deps.json rename to Test/VariadicTest/output/6aee24fdefa3cbc0.deps.json index 6adc4cf..43983e1 100644 --- a/Test/VariadicTest/output/4d5db7f970ef510f.deps.json +++ b/Test/VariadicTest/output/6aee24fdefa3cbc0.deps.json @@ -1 +1 @@ -{"viperlib": "2953a7db4185005b", "main": "377ad03e9b90ac39", "string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "stdarg": "71e0a3ffcb3ebfad", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4"} \ No newline at end of file +{"viperlib": "2953a7db4185005b", "main": "377ad03e9b90ac39", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "stdarg": "71e0a3ffcb3ebfad", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4"} \ No newline at end of file diff --git a/Test/VariadicTest/output/72e2d5ccb7cedcf1.deps.json b/Test/VariadicTest/output/72e2d5ccb7cedcf1.deps.json index a8ad265..e515c67 100644 --- a/Test/VariadicTest/output/72e2d5ccb7cedcf1.deps.json +++ b/Test/VariadicTest/output/72e2d5ccb7cedcf1.deps.json @@ -1 +1 @@ -{"viperlib": "2953a7db4185005b", "main": "377ad03e9b90ac39", "string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "stdarg": "71e0a3ffcb3ebfad", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1"} \ No newline at end of file +{"viperlib": "2953a7db4185005b", "main": "377ad03e9b90ac39", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "stdarg": "71e0a3ffcb3ebfad", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1"} \ No newline at end of file diff --git a/Test/VariadicTest/output/abf9ce3160c9279e.deps.json b/Test/VariadicTest/output/abf9ce3160c9279e.deps.json index 77b9eb5..dbd0c83 100644 --- a/Test/VariadicTest/output/abf9ce3160c9279e.deps.json +++ b/Test/VariadicTest/output/abf9ce3160c9279e.deps.json @@ -1 +1 @@ -{"viperlib": "2953a7db4185005b", "main": "377ad03e9b90ac39", "string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "stdarg": "71e0a3ffcb3ebfad", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e"} \ No newline at end of file +{"viperlib": "2953a7db4185005b", "main": "377ad03e9b90ac39", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "stdarg": "71e0a3ffcb3ebfad", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e"} \ No newline at end of file diff --git a/Test/VariadicTest/output/bbdf3bbd4c3bc28c.deps.json b/Test/VariadicTest/output/bbdf3bbd4c3bc28c.deps.json index 592b804..791ea77 100644 --- a/Test/VariadicTest/output/bbdf3bbd4c3bc28c.deps.json +++ b/Test/VariadicTest/output/bbdf3bbd4c3bc28c.deps.json @@ -1 +1 @@ -{"viperlib": "2953a7db4185005b", "main": "377ad03e9b90ac39", "string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "stdarg": "71e0a3ffcb3ebfad", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file +{"viperlib": "2953a7db4185005b", "main": "377ad03e9b90ac39", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "stdarg": "71e0a3ffcb3ebfad", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/VariadicTest/output/c9f4be41ca1cc2b4.deps.json b/Test/VariadicTest/output/c9f4be41ca1cc2b4.deps.json index 6adc4cf..43983e1 100644 --- a/Test/VariadicTest/output/c9f4be41ca1cc2b4.deps.json +++ b/Test/VariadicTest/output/c9f4be41ca1cc2b4.deps.json @@ -1 +1 @@ -{"viperlib": "2953a7db4185005b", "main": "377ad03e9b90ac39", "string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "stdarg": "71e0a3ffcb3ebfad", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4"} \ No newline at end of file +{"viperlib": "2953a7db4185005b", "main": "377ad03e9b90ac39", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "stdarg": "71e0a3ffcb3ebfad", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4"} \ No newline at end of file diff --git a/Test/VariadicTest/output/fa3691e66b426950.deps.json b/Test/VariadicTest/output/fa3691e66b426950.deps.json index 592b804..791ea77 100644 --- a/Test/VariadicTest/output/fa3691e66b426950.deps.json +++ b/Test/VariadicTest/output/fa3691e66b426950.deps.json @@ -1 +1 @@ -{"viperlib": "2953a7db4185005b", "main": "377ad03e9b90ac39", "string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "stdarg": "71e0a3ffcb3ebfad", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file +{"viperlib": "2953a7db4185005b", "main": "377ad03e9b90ac39", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "stdarg": "71e0a3ffcb3ebfad", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/VariadicTest/temp/4d5db7f970ef510f.pyi b/Test/VariadicTest/temp/4d5db7f970ef510f.pyi deleted file mode 100644 index eae6834..0000000 --- a/Test/VariadicTest/temp/4d5db7f970ef510f.pyi +++ /dev/null @@ -1,40 +0,0 @@ -""" -Auto-generated Python stub file from string.py -Module: string -""" - - -from stdint import * -import t, c - -def strcpy(dest: str, src: str) -> str: pass - -def strncpy(dest: str, src: str, n: t.CSizeT) -> str: pass - -def strlen(src: str) -> t.CSizeT | t.CExport: pass - -def strcmp(str1: str, str2: str) -> t.CInt: pass - -def samestr(str1: str, str2: str) -> bool: pass - -def strncmp(str1: str, str2: str, n: t.CSizeT) -> t.CInt: pass - -def memcmp(ptr1: t.CVoid | t.CPtr, ptr2: t.CVoid | t.CPtr, n: t.CSizeT) -> t.CInt: pass - -def strchr(s: str, cr: t.CInt) -> str: pass - -def strrchr(s: str, cr: t.CInt) -> str: pass - -def strspn(s: str, skip: str) -> int: pass - -def memset(ptr: t.CVoid | t.CPtr, value: t.CInt, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass - -def memset32(ptr: t.CVoid | t.CPtr, value: t.CUInt32T, count: t.CSizeT) -> t.CVoid | t.CPtr: pass - -def memcpy(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass - -def memmove(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr: pass - -def atoi(src: str) -> t.CInt: pass - -def split(s: str, delim: str, result: list[str]) -> int: pass diff --git a/Test/VariadicTest/temp/6aee24fdefa3cbc0.pyi b/Test/VariadicTest/temp/6aee24fdefa3cbc0.pyi new file mode 100644 index 0000000..c17475f --- /dev/null +++ b/Test/VariadicTest/temp/6aee24fdefa3cbc0.pyi @@ -0,0 +1,44 @@ +""" +Auto-generated Python stub file from string.py +Module: string +""" + + +from stdint import * +import t, c + +def strcpy(dest: str, src: str) -> str: pass + +def strncpy(dest: str, src: str, n: t.CSizeT) -> str: pass + +def strlen(src: str) -> t.CSizeT | t.CExport: pass + +def strcmp(str1: str, str2: str) -> t.CInt: pass + +def samestr(str1: str, str2: str) -> bool: pass + +def strncmp(str1: str, str2: str, n: t.CSizeT) -> t.CInt: pass + +def memcmp(ptr1: t.CVoid | t.CPtr, ptr2: t.CVoid | t.CPtr, n: t.CSizeT) -> t.CInt: pass + +def strchr(s: str, cr: t.CInt) -> str: pass + +def strrchr(s: str, cr: t.CInt) -> str: pass + +def strspn(s: str, skip: str) -> int: pass + +def memset(ptr: t.CVoid | t.CPtr, value: t.CInt, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass + +def memset32(ptr: t.CVoid | t.CPtr, value: t.CUInt32T, count: t.CSizeT) -> t.CVoid | t.CPtr: pass + +def memcpy(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass + +def memmove(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr: pass + +def atoi(src: str) -> t.CInt: pass + +def atoll(src: str) -> t.CInt64T: pass + +def atof(src: str) -> t.CDouble: pass + +def split(s: str, delim: str, result: list[str]) -> int: pass diff --git a/Test/VariadicTest/temp/_sha1_map.txt b/Test/VariadicTest/temp/_sha1_map.txt index d9d969b..318fb4b 100644 --- a/Test/VariadicTest/temp/_sha1_map.txt +++ b/Test/VariadicTest/temp/_sha1_map.txt @@ -1,8 +1,8 @@ 2953a7db4185005b:includes/viperlib.py 377ad03e9b90ac39:main.py -4d5db7f970ef510f:includes/string.py 56cdd754a8a09347:includes/stdint.py 5a6a2137958c28c5:includes/w32\win32base.py +6aee24fdefa3cbc0:includes/string.py 71e0a3ffcb3ebfad:includes/stdarg.py 73edbcf76e32d00b:includes/stdio.py bbdf3bbd4c3bc28c:includes/w32\win32console.py diff --git a/Test/ZlibTest/App/__zlib/test_pyzlib.py b/Test/ZlibTest/App/__zlib/test_pyzlib.py index 256df64..d3b5b89 100644 --- a/Test/ZlibTest/App/__zlib/test_pyzlib.py +++ b/Test/ZlibTest/App/__zlib/test_pyzlib.py @@ -331,7 +331,7 @@ def test_compress_copy(): c1.compress(BYTEPTR(inp), input_length, c.Addr(out_length)) printf(" Original: compressed %zu bytes so far\n", out_length) - c2: pyzlib.Compress = c1.copy() + c2: pyzlib.Compress | t.CPtr = c1.copy() check("compress copy OK", c2 != None, "copy returned None") printf(" Copied compressobj\n") @@ -524,7 +524,7 @@ def test_zdict(): printf(" Input : \"%s\" (%zu bytes)\n", inp, input_length) out_length: t.CSizeT = 0 - s: pyzlib.Compress = pyzlib.compressobj(pyzlib.Z_DEFAULT_COMPRESSION, pyzlib.DEFLATED, + s: pyzlib.Compress | t.CPtr = pyzlib.compressobj(pyzlib.Z_DEFAULT_COMPRESSION, pyzlib.DEFLATED, pyzlib.MAX_WBITS, pyzlib.DEF_MEM_LEVEL, pyzlib.Z_DEFAULT_STRATEGY, BYTEPTR(dict), strlen(dict)) diff --git a/Test/ZlibTest/output/024a3459d0f585ae.deps.json b/Test/ZlibTest/output/024a3459d0f585ae.deps.json deleted file mode 100644 index 98f9df8..0000000 --- a/Test/ZlibTest/output/024a3459d0f585ae.deps.json +++ /dev/null @@ -1 +0,0 @@ -{"string": "024a3459d0f585ae", "__zlib.zdeflate": "0af305ed4e5f787d", "zdeflate": "0af305ed4e5f787d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.pyzlib": "7e9fab9c7b47c4db", "pyzlib": "7e9fab9c7b47c4db", "__zlib.zchecksum": "95e27d852b773ae8", "zchecksum": "95e27d852b773ae8", "stdlib": "a96738831f025829", "__zlib.zhuff": "c9349bf1e8390dd5", "zhuff": "c9349bf1e8390dd5", "main": "dca7ef1d57347738", "__zlib.zinflate": "e00d9854a0d03f4f", "zinflate": "e00d9854a0d03f4f", "__zlib.zdef": "f9cd063200178785", "zdef": "f9cd063200178785", "__zlib.test_pyzlib": "ffaa1aaa1355e604", "test_pyzlib": "ffaa1aaa1355e604"} \ No newline at end of file diff --git a/Test/ZlibTest/output/067c78e9f121dce3.deps.json b/Test/ZlibTest/output/067c78e9f121dce3.deps.json index 5007e65..02e0914 100644 --- a/Test/ZlibTest/output/067c78e9f121dce3.deps.json +++ b/Test/ZlibTest/output/067c78e9f121dce3.deps.json @@ -1 +1 @@ -{"string": "024a3459d0f585ae", "__zlib.zdeflate": "0af305ed4e5f787d", "zdeflate": "0af305ed4e5f787d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.pyzlib": "7e9fab9c7b47c4db", "pyzlib": "7e9fab9c7b47c4db", "__zlib.zchecksum": "95e27d852b773ae8", "zchecksum": "95e27d852b773ae8", "stdlib": "a96738831f025829", "__zlib.zhuff": "c9349bf1e8390dd5", "zhuff": "c9349bf1e8390dd5", "main": "dca7ef1d57347738", "__zlib.zinflate": "e00d9854a0d03f4f", "zinflate": "e00d9854a0d03f4f", "__zlib.zdef": "f9cd063200178785", "zdef": "f9cd063200178785", "__zlib.test_pyzlib": "ffaa1aaa1355e604", "test_pyzlib": "ffaa1aaa1355e604", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3"} \ No newline at end of file +{"__zlib.zdeflate": "0af305ed4e5f787d", "zdeflate": "0af305ed4e5f787d", "__zlib.test_pyzlib": "53fa0c913947021f", "test_pyzlib": "53fa0c913947021f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.pyzlib": "7e9fab9c7b47c4db", "pyzlib": "7e9fab9c7b47c4db", "__zlib.zchecksum": "95e27d852b773ae8", "zchecksum": "95e27d852b773ae8", "__zlib.zhuff": "c9349bf1e8390dd5", "zhuff": "c9349bf1e8390dd5", "main": "dca7ef1d57347738", "__zlib.zinflate": "e00d9854a0d03f4f", "zinflate": "e00d9854a0d03f4f", "__zlib.zdef": "f9cd063200178785", "zdef": "f9cd063200178785", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3"} \ No newline at end of file diff --git a/Test/ZlibTest/output/0af305ed4e5f787d.deps.json b/Test/ZlibTest/output/0af305ed4e5f787d.deps.json index 536ae4c..b87171f 100644 --- a/Test/ZlibTest/output/0af305ed4e5f787d.deps.json +++ b/Test/ZlibTest/output/0af305ed4e5f787d.deps.json @@ -1 +1 @@ -{"string": "024a3459d0f585ae", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.pyzlib": "7e9fab9c7b47c4db", "pyzlib": "7e9fab9c7b47c4db", "__zlib.zchecksum": "95e27d852b773ae8", "zchecksum": "95e27d852b773ae8", "stdlib": "a96738831f025829", "__zlib.zhuff": "c9349bf1e8390dd5", "zhuff": "c9349bf1e8390dd5", "main": "dca7ef1d57347738", "__zlib.zinflate": "e00d9854a0d03f4f", "zinflate": "e00d9854a0d03f4f", "__zlib.zdef": "f9cd063200178785", "zdef": "f9cd063200178785", "__zlib.test_pyzlib": "ffaa1aaa1355e604", "test_pyzlib": "ffaa1aaa1355e604"} \ No newline at end of file +{"__zlib.test_pyzlib": "53fa0c913947021f", "test_pyzlib": "53fa0c913947021f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.pyzlib": "7e9fab9c7b47c4db", "pyzlib": "7e9fab9c7b47c4db", "__zlib.zchecksum": "95e27d852b773ae8", "zchecksum": "95e27d852b773ae8", "__zlib.zhuff": "c9349bf1e8390dd5", "zhuff": "c9349bf1e8390dd5", "main": "dca7ef1d57347738", "__zlib.zinflate": "e00d9854a0d03f4f", "zinflate": "e00d9854a0d03f4f", "__zlib.zdef": "f9cd063200178785", "zdef": "f9cd063200178785"} \ No newline at end of file diff --git a/Test/ZlibTest/output/29813d57621099a9.deps.json b/Test/ZlibTest/output/29813d57621099a9.deps.json index c0a37ee..c0ff589 100644 --- a/Test/ZlibTest/output/29813d57621099a9.deps.json +++ b/Test/ZlibTest/output/29813d57621099a9.deps.json @@ -1 +1 @@ -{"string": "024a3459d0f585ae", "__zlib.zdeflate": "0af305ed4e5f787d", "zdeflate": "0af305ed4e5f787d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.pyzlib": "7e9fab9c7b47c4db", "pyzlib": "7e9fab9c7b47c4db", "__zlib.zchecksum": "95e27d852b773ae8", "zchecksum": "95e27d852b773ae8", "stdlib": "a96738831f025829", "__zlib.zhuff": "c9349bf1e8390dd5", "zhuff": "c9349bf1e8390dd5", "main": "dca7ef1d57347738", "__zlib.zinflate": "e00d9854a0d03f4f", "zinflate": "e00d9854a0d03f4f", "__zlib.zdef": "f9cd063200178785", "zdef": "f9cd063200178785", "__zlib.test_pyzlib": "ffaa1aaa1355e604", "test_pyzlib": "ffaa1aaa1355e604", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file +{"__zlib.zdeflate": "0af305ed4e5f787d", "zdeflate": "0af305ed4e5f787d", "__zlib.test_pyzlib": "53fa0c913947021f", "test_pyzlib": "53fa0c913947021f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.pyzlib": "7e9fab9c7b47c4db", "pyzlib": "7e9fab9c7b47c4db", "__zlib.zchecksum": "95e27d852b773ae8", "zchecksum": "95e27d852b773ae8", "__zlib.zhuff": "c9349bf1e8390dd5", "zhuff": "c9349bf1e8390dd5", "main": "dca7ef1d57347738", "__zlib.zinflate": "e00d9854a0d03f4f", "zinflate": "e00d9854a0d03f4f", "__zlib.zdef": "f9cd063200178785", "zdef": "f9cd063200178785", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file diff --git a/Test/ZlibTest/output/53fa0c913947021f.deps.json b/Test/ZlibTest/output/53fa0c913947021f.deps.json new file mode 100644 index 0000000..b0c8785 --- /dev/null +++ b/Test/ZlibTest/output/53fa0c913947021f.deps.json @@ -0,0 +1 @@ +{"__zlib.zdeflate": "0af305ed4e5f787d", "zdeflate": "0af305ed4e5f787d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.pyzlib": "7e9fab9c7b47c4db", "pyzlib": "7e9fab9c7b47c4db", "__zlib.zchecksum": "95e27d852b773ae8", "zchecksum": "95e27d852b773ae8", "__zlib.zhuff": "c9349bf1e8390dd5", "zhuff": "c9349bf1e8390dd5", "main": "dca7ef1d57347738", "__zlib.zinflate": "e00d9854a0d03f4f", "zinflate": "e00d9854a0d03f4f", "__zlib.zdef": "f9cd063200178785", "zdef": "f9cd063200178785"} \ No newline at end of file diff --git a/Test/ZlibTest/output/5a6a2137958c28c5.deps.json b/Test/ZlibTest/output/5a6a2137958c28c5.deps.json index 661fe60..f29b4ab 100644 --- a/Test/ZlibTest/output/5a6a2137958c28c5.deps.json +++ b/Test/ZlibTest/output/5a6a2137958c28c5.deps.json @@ -1 +1 @@ -{"string": "024a3459d0f585ae", "__zlib.zdeflate": "0af305ed4e5f787d", "zdeflate": "0af305ed4e5f787d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.pyzlib": "7e9fab9c7b47c4db", "pyzlib": "7e9fab9c7b47c4db", "__zlib.zchecksum": "95e27d852b773ae8", "zchecksum": "95e27d852b773ae8", "stdlib": "a96738831f025829", "__zlib.zhuff": "c9349bf1e8390dd5", "zhuff": "c9349bf1e8390dd5", "main": "dca7ef1d57347738", "__zlib.zinflate": "e00d9854a0d03f4f", "zinflate": "e00d9854a0d03f4f", "__zlib.zdef": "f9cd063200178785", "zdef": "f9cd063200178785", "__zlib.test_pyzlib": "ffaa1aaa1355e604", "test_pyzlib": "ffaa1aaa1355e604", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file +{"__zlib.zdeflate": "0af305ed4e5f787d", "zdeflate": "0af305ed4e5f787d", "__zlib.test_pyzlib": "53fa0c913947021f", "test_pyzlib": "53fa0c913947021f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.pyzlib": "7e9fab9c7b47c4db", "pyzlib": "7e9fab9c7b47c4db", "__zlib.zchecksum": "95e27d852b773ae8", "zchecksum": "95e27d852b773ae8", "__zlib.zhuff": "c9349bf1e8390dd5", "zhuff": "c9349bf1e8390dd5", "main": "dca7ef1d57347738", "__zlib.zinflate": "e00d9854a0d03f4f", "zinflate": "e00d9854a0d03f4f", "__zlib.zdef": "f9cd063200178785", "zdef": "f9cd063200178785", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/ZlibTest/output/6aee24fdefa3cbc0.deps.json b/Test/ZlibTest/output/6aee24fdefa3cbc0.deps.json new file mode 100644 index 0000000..6276ce6 --- /dev/null +++ b/Test/ZlibTest/output/6aee24fdefa3cbc0.deps.json @@ -0,0 +1 @@ +{"__zlib.zdeflate": "0af305ed4e5f787d", "zdeflate": "0af305ed4e5f787d", "__zlib.test_pyzlib": "53fa0c913947021f", "test_pyzlib": "53fa0c913947021f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.pyzlib": "7e9fab9c7b47c4db", "pyzlib": "7e9fab9c7b47c4db", "__zlib.zchecksum": "95e27d852b773ae8", "zchecksum": "95e27d852b773ae8", "__zlib.zhuff": "c9349bf1e8390dd5", "zhuff": "c9349bf1e8390dd5", "main": "dca7ef1d57347738", "__zlib.zinflate": "e00d9854a0d03f4f", "zinflate": "e00d9854a0d03f4f", "__zlib.zdef": "f9cd063200178785", "zdef": "f9cd063200178785"} \ No newline at end of file diff --git a/Test/ZlibTest/output/72e2d5ccb7cedcf1.deps.json b/Test/ZlibTest/output/72e2d5ccb7cedcf1.deps.json index 25dc5a3..7138317 100644 --- a/Test/ZlibTest/output/72e2d5ccb7cedcf1.deps.json +++ b/Test/ZlibTest/output/72e2d5ccb7cedcf1.deps.json @@ -1 +1 @@ -{"string": "024a3459d0f585ae", "__zlib.zdeflate": "0af305ed4e5f787d", "zdeflate": "0af305ed4e5f787d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.pyzlib": "7e9fab9c7b47c4db", "pyzlib": "7e9fab9c7b47c4db", "__zlib.zchecksum": "95e27d852b773ae8", "zchecksum": "95e27d852b773ae8", "stdlib": "a96738831f025829", "__zlib.zhuff": "c9349bf1e8390dd5", "zhuff": "c9349bf1e8390dd5", "main": "dca7ef1d57347738", "__zlib.zinflate": "e00d9854a0d03f4f", "zinflate": "e00d9854a0d03f4f", "__zlib.zdef": "f9cd063200178785", "zdef": "f9cd063200178785", "__zlib.test_pyzlib": "ffaa1aaa1355e604", "test_pyzlib": "ffaa1aaa1355e604", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e"} \ No newline at end of file +{"__zlib.zdeflate": "0af305ed4e5f787d", "zdeflate": "0af305ed4e5f787d", "__zlib.test_pyzlib": "53fa0c913947021f", "test_pyzlib": "53fa0c913947021f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.pyzlib": "7e9fab9c7b47c4db", "pyzlib": "7e9fab9c7b47c4db", "__zlib.zchecksum": "95e27d852b773ae8", "zchecksum": "95e27d852b773ae8", "__zlib.zhuff": "c9349bf1e8390dd5", "zhuff": "c9349bf1e8390dd5", "main": "dca7ef1d57347738", "__zlib.zinflate": "e00d9854a0d03f4f", "zinflate": "e00d9854a0d03f4f", "__zlib.zdef": "f9cd063200178785", "zdef": "f9cd063200178785", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e"} \ No newline at end of file diff --git a/Test/ZlibTest/output/7e9fab9c7b47c4db.deps.json b/Test/ZlibTest/output/7e9fab9c7b47c4db.deps.json index 7d3127d..e18b0d6 100644 --- a/Test/ZlibTest/output/7e9fab9c7b47c4db.deps.json +++ b/Test/ZlibTest/output/7e9fab9c7b47c4db.deps.json @@ -1 +1 @@ -{"string": "024a3459d0f585ae", "__zlib.zdeflate": "0af305ed4e5f787d", "zdeflate": "0af305ed4e5f787d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.zchecksum": "95e27d852b773ae8", "zchecksum": "95e27d852b773ae8", "stdlib": "a96738831f025829", "__zlib.zhuff": "c9349bf1e8390dd5", "zhuff": "c9349bf1e8390dd5", "main": "dca7ef1d57347738", "__zlib.zinflate": "e00d9854a0d03f4f", "zinflate": "e00d9854a0d03f4f", "__zlib.zdef": "f9cd063200178785", "zdef": "f9cd063200178785", "__zlib.test_pyzlib": "ffaa1aaa1355e604", "test_pyzlib": "ffaa1aaa1355e604"} \ No newline at end of file +{"__zlib.zdeflate": "0af305ed4e5f787d", "zdeflate": "0af305ed4e5f787d", "__zlib.test_pyzlib": "53fa0c913947021f", "test_pyzlib": "53fa0c913947021f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.zchecksum": "95e27d852b773ae8", "zchecksum": "95e27d852b773ae8", "__zlib.zhuff": "c9349bf1e8390dd5", "zhuff": "c9349bf1e8390dd5", "main": "dca7ef1d57347738", "__zlib.zinflate": "e00d9854a0d03f4f", "zinflate": "e00d9854a0d03f4f", "__zlib.zdef": "f9cd063200178785", "zdef": "f9cd063200178785"} \ No newline at end of file diff --git a/Test/ZlibTest/output/95e27d852b773ae8.deps.json b/Test/ZlibTest/output/95e27d852b773ae8.deps.json index 365282c..b228098 100644 --- a/Test/ZlibTest/output/95e27d852b773ae8.deps.json +++ b/Test/ZlibTest/output/95e27d852b773ae8.deps.json @@ -1 +1 @@ -{"string": "024a3459d0f585ae", "__zlib.zdeflate": "0af305ed4e5f787d", "zdeflate": "0af305ed4e5f787d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.pyzlib": "7e9fab9c7b47c4db", "pyzlib": "7e9fab9c7b47c4db", "stdlib": "a96738831f025829", "__zlib.zhuff": "c9349bf1e8390dd5", "zhuff": "c9349bf1e8390dd5", "main": "dca7ef1d57347738", "__zlib.zinflate": "e00d9854a0d03f4f", "zinflate": "e00d9854a0d03f4f", "__zlib.zdef": "f9cd063200178785", "zdef": "f9cd063200178785", "__zlib.test_pyzlib": "ffaa1aaa1355e604", "test_pyzlib": "ffaa1aaa1355e604"} \ No newline at end of file +{"__zlib.zdeflate": "0af305ed4e5f787d", "zdeflate": "0af305ed4e5f787d", "__zlib.test_pyzlib": "53fa0c913947021f", "test_pyzlib": "53fa0c913947021f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.pyzlib": "7e9fab9c7b47c4db", "pyzlib": "7e9fab9c7b47c4db", "__zlib.zhuff": "c9349bf1e8390dd5", "zhuff": "c9349bf1e8390dd5", "main": "dca7ef1d57347738", "__zlib.zinflate": "e00d9854a0d03f4f", "zinflate": "e00d9854a0d03f4f", "__zlib.zdef": "f9cd063200178785", "zdef": "f9cd063200178785"} \ No newline at end of file diff --git a/Test/ZlibTest/output/abf9ce3160c9279e.deps.json b/Test/ZlibTest/output/abf9ce3160c9279e.deps.json index 25dc5a3..7138317 100644 --- a/Test/ZlibTest/output/abf9ce3160c9279e.deps.json +++ b/Test/ZlibTest/output/abf9ce3160c9279e.deps.json @@ -1 +1 @@ -{"string": "024a3459d0f585ae", "__zlib.zdeflate": "0af305ed4e5f787d", "zdeflate": "0af305ed4e5f787d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.pyzlib": "7e9fab9c7b47c4db", "pyzlib": "7e9fab9c7b47c4db", "__zlib.zchecksum": "95e27d852b773ae8", "zchecksum": "95e27d852b773ae8", "stdlib": "a96738831f025829", "__zlib.zhuff": "c9349bf1e8390dd5", "zhuff": "c9349bf1e8390dd5", "main": "dca7ef1d57347738", "__zlib.zinflate": "e00d9854a0d03f4f", "zinflate": "e00d9854a0d03f4f", "__zlib.zdef": "f9cd063200178785", "zdef": "f9cd063200178785", "__zlib.test_pyzlib": "ffaa1aaa1355e604", "test_pyzlib": "ffaa1aaa1355e604", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e"} \ No newline at end of file +{"__zlib.zdeflate": "0af305ed4e5f787d", "zdeflate": "0af305ed4e5f787d", "__zlib.test_pyzlib": "53fa0c913947021f", "test_pyzlib": "53fa0c913947021f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.pyzlib": "7e9fab9c7b47c4db", "pyzlib": "7e9fab9c7b47c4db", "__zlib.zchecksum": "95e27d852b773ae8", "zchecksum": "95e27d852b773ae8", "__zlib.zhuff": "c9349bf1e8390dd5", "zhuff": "c9349bf1e8390dd5", "main": "dca7ef1d57347738", "__zlib.zinflate": "e00d9854a0d03f4f", "zinflate": "e00d9854a0d03f4f", "__zlib.zdef": "f9cd063200178785", "zdef": "f9cd063200178785", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e"} \ No newline at end of file diff --git a/Test/ZlibTest/output/bbdf3bbd4c3bc28c.deps.json b/Test/ZlibTest/output/bbdf3bbd4c3bc28c.deps.json index ac30ccb..39ce516 100644 --- a/Test/ZlibTest/output/bbdf3bbd4c3bc28c.deps.json +++ b/Test/ZlibTest/output/bbdf3bbd4c3bc28c.deps.json @@ -1 +1 @@ -{"string": "024a3459d0f585ae", "__zlib.zdeflate": "0af305ed4e5f787d", "zdeflate": "0af305ed4e5f787d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.pyzlib": "7e9fab9c7b47c4db", "pyzlib": "7e9fab9c7b47c4db", "__zlib.zchecksum": "95e27d852b773ae8", "zchecksum": "95e27d852b773ae8", "stdlib": "a96738831f025829", "__zlib.zhuff": "c9349bf1e8390dd5", "zhuff": "c9349bf1e8390dd5", "main": "dca7ef1d57347738", "__zlib.zinflate": "e00d9854a0d03f4f", "zinflate": "e00d9854a0d03f4f", "__zlib.zdef": "f9cd063200178785", "zdef": "f9cd063200178785", "__zlib.test_pyzlib": "ffaa1aaa1355e604", "test_pyzlib": "ffaa1aaa1355e604", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c"} \ No newline at end of file +{"__zlib.zdeflate": "0af305ed4e5f787d", "zdeflate": "0af305ed4e5f787d", "__zlib.test_pyzlib": "53fa0c913947021f", "test_pyzlib": "53fa0c913947021f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.pyzlib": "7e9fab9c7b47c4db", "pyzlib": "7e9fab9c7b47c4db", "__zlib.zchecksum": "95e27d852b773ae8", "zchecksum": "95e27d852b773ae8", "__zlib.zhuff": "c9349bf1e8390dd5", "zhuff": "c9349bf1e8390dd5", "main": "dca7ef1d57347738", "__zlib.zinflate": "e00d9854a0d03f4f", "zinflate": "e00d9854a0d03f4f", "__zlib.zdef": "f9cd063200178785", "zdef": "f9cd063200178785", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c"} \ No newline at end of file diff --git a/Test/ZlibTest/output/c9349bf1e8390dd5.deps.json b/Test/ZlibTest/output/c9349bf1e8390dd5.deps.json index 88b64c9..273dcc1 100644 --- a/Test/ZlibTest/output/c9349bf1e8390dd5.deps.json +++ b/Test/ZlibTest/output/c9349bf1e8390dd5.deps.json @@ -1 +1 @@ -{"string": "024a3459d0f585ae", "__zlib.zdeflate": "0af305ed4e5f787d", "zdeflate": "0af305ed4e5f787d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.pyzlib": "7e9fab9c7b47c4db", "pyzlib": "7e9fab9c7b47c4db", "__zlib.zchecksum": "95e27d852b773ae8", "zchecksum": "95e27d852b773ae8", "stdlib": "a96738831f025829", "main": "dca7ef1d57347738", "__zlib.zinflate": "e00d9854a0d03f4f", "zinflate": "e00d9854a0d03f4f", "__zlib.zdef": "f9cd063200178785", "zdef": "f9cd063200178785", "__zlib.test_pyzlib": "ffaa1aaa1355e604", "test_pyzlib": "ffaa1aaa1355e604"} \ No newline at end of file +{"__zlib.zdeflate": "0af305ed4e5f787d", "zdeflate": "0af305ed4e5f787d", "__zlib.test_pyzlib": "53fa0c913947021f", "test_pyzlib": "53fa0c913947021f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.pyzlib": "7e9fab9c7b47c4db", "pyzlib": "7e9fab9c7b47c4db", "__zlib.zchecksum": "95e27d852b773ae8", "zchecksum": "95e27d852b773ae8", "main": "dca7ef1d57347738", "__zlib.zinflate": "e00d9854a0d03f4f", "zinflate": "e00d9854a0d03f4f", "__zlib.zdef": "f9cd063200178785", "zdef": "f9cd063200178785"} \ No newline at end of file diff --git a/Test/ZlibTest/output/dca7ef1d57347738.deps.json b/Test/ZlibTest/output/dca7ef1d57347738.deps.json index bf53f56..6c2e844 100644 --- a/Test/ZlibTest/output/dca7ef1d57347738.deps.json +++ b/Test/ZlibTest/output/dca7ef1d57347738.deps.json @@ -1 +1 @@ -{"string": "024a3459d0f585ae", "__zlib.zdeflate": "0af305ed4e5f787d", "zdeflate": "0af305ed4e5f787d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.pyzlib": "7e9fab9c7b47c4db", "pyzlib": "7e9fab9c7b47c4db", "__zlib.zchecksum": "95e27d852b773ae8", "zchecksum": "95e27d852b773ae8", "stdlib": "a96738831f025829", "__zlib.zhuff": "c9349bf1e8390dd5", "zhuff": "c9349bf1e8390dd5", "__zlib.zinflate": "e00d9854a0d03f4f", "zinflate": "e00d9854a0d03f4f", "__zlib.zdef": "f9cd063200178785", "zdef": "f9cd063200178785", "__zlib.test_pyzlib": "ffaa1aaa1355e604", "test_pyzlib": "ffaa1aaa1355e604"} \ No newline at end of file +{"__zlib.zdeflate": "0af305ed4e5f787d", "zdeflate": "0af305ed4e5f787d", "__zlib.test_pyzlib": "53fa0c913947021f", "test_pyzlib": "53fa0c913947021f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.pyzlib": "7e9fab9c7b47c4db", "pyzlib": "7e9fab9c7b47c4db", "__zlib.zchecksum": "95e27d852b773ae8", "zchecksum": "95e27d852b773ae8", "__zlib.zhuff": "c9349bf1e8390dd5", "zhuff": "c9349bf1e8390dd5", "__zlib.zinflate": "e00d9854a0d03f4f", "zinflate": "e00d9854a0d03f4f", "__zlib.zdef": "f9cd063200178785", "zdef": "f9cd063200178785"} \ No newline at end of file diff --git a/Test/ZlibTest/output/e00d9854a0d03f4f.deps.json b/Test/ZlibTest/output/e00d9854a0d03f4f.deps.json index 5c0cc0d..8c2e8d1 100644 --- a/Test/ZlibTest/output/e00d9854a0d03f4f.deps.json +++ b/Test/ZlibTest/output/e00d9854a0d03f4f.deps.json @@ -1 +1 @@ -{"string": "024a3459d0f585ae", "__zlib.zdeflate": "0af305ed4e5f787d", "zdeflate": "0af305ed4e5f787d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.pyzlib": "7e9fab9c7b47c4db", "pyzlib": "7e9fab9c7b47c4db", "__zlib.zchecksum": "95e27d852b773ae8", "zchecksum": "95e27d852b773ae8", "stdlib": "a96738831f025829", "__zlib.zhuff": "c9349bf1e8390dd5", "zhuff": "c9349bf1e8390dd5", "main": "dca7ef1d57347738", "__zlib.zdef": "f9cd063200178785", "zdef": "f9cd063200178785", "__zlib.test_pyzlib": "ffaa1aaa1355e604", "test_pyzlib": "ffaa1aaa1355e604"} \ No newline at end of file +{"__zlib.zdeflate": "0af305ed4e5f787d", "zdeflate": "0af305ed4e5f787d", "__zlib.test_pyzlib": "53fa0c913947021f", "test_pyzlib": "53fa0c913947021f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.pyzlib": "7e9fab9c7b47c4db", "pyzlib": "7e9fab9c7b47c4db", "__zlib.zchecksum": "95e27d852b773ae8", "zchecksum": "95e27d852b773ae8", "__zlib.zhuff": "c9349bf1e8390dd5", "zhuff": "c9349bf1e8390dd5", "main": "dca7ef1d57347738", "__zlib.zdef": "f9cd063200178785", "zdef": "f9cd063200178785"} \ No newline at end of file diff --git a/Test/ZlibTest/output/f9cd063200178785.deps.json b/Test/ZlibTest/output/f9cd063200178785.deps.json index b3e8265..bc04c95 100644 --- a/Test/ZlibTest/output/f9cd063200178785.deps.json +++ b/Test/ZlibTest/output/f9cd063200178785.deps.json @@ -1 +1 @@ -{"string": "024a3459d0f585ae", "__zlib.zdeflate": "0af305ed4e5f787d", "zdeflate": "0af305ed4e5f787d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.pyzlib": "7e9fab9c7b47c4db", "pyzlib": "7e9fab9c7b47c4db", "__zlib.zchecksum": "95e27d852b773ae8", "zchecksum": "95e27d852b773ae8", "stdlib": "a96738831f025829", "__zlib.zhuff": "c9349bf1e8390dd5", "zhuff": "c9349bf1e8390dd5", "main": "dca7ef1d57347738", "__zlib.zinflate": "e00d9854a0d03f4f", "zinflate": "e00d9854a0d03f4f", "__zlib.test_pyzlib": "ffaa1aaa1355e604", "test_pyzlib": "ffaa1aaa1355e604"} \ No newline at end of file +{"__zlib.zdeflate": "0af305ed4e5f787d", "zdeflate": "0af305ed4e5f787d", "__zlib.test_pyzlib": "53fa0c913947021f", "test_pyzlib": "53fa0c913947021f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.pyzlib": "7e9fab9c7b47c4db", "pyzlib": "7e9fab9c7b47c4db", "__zlib.zchecksum": "95e27d852b773ae8", "zchecksum": "95e27d852b773ae8", "__zlib.zhuff": "c9349bf1e8390dd5", "zhuff": "c9349bf1e8390dd5", "main": "dca7ef1d57347738", "__zlib.zinflate": "e00d9854a0d03f4f", "zinflate": "e00d9854a0d03f4f"} \ No newline at end of file diff --git a/Test/ZlibTest/output/fa3691e66b426950.deps.json b/Test/ZlibTest/output/fa3691e66b426950.deps.json index 661fe60..f29b4ab 100644 --- a/Test/ZlibTest/output/fa3691e66b426950.deps.json +++ b/Test/ZlibTest/output/fa3691e66b426950.deps.json @@ -1 +1 @@ -{"string": "024a3459d0f585ae", "__zlib.zdeflate": "0af305ed4e5f787d", "zdeflate": "0af305ed4e5f787d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.pyzlib": "7e9fab9c7b47c4db", "pyzlib": "7e9fab9c7b47c4db", "__zlib.zchecksum": "95e27d852b773ae8", "zchecksum": "95e27d852b773ae8", "stdlib": "a96738831f025829", "__zlib.zhuff": "c9349bf1e8390dd5", "zhuff": "c9349bf1e8390dd5", "main": "dca7ef1d57347738", "__zlib.zinflate": "e00d9854a0d03f4f", "zinflate": "e00d9854a0d03f4f", "__zlib.zdef": "f9cd063200178785", "zdef": "f9cd063200178785", "__zlib.test_pyzlib": "ffaa1aaa1355e604", "test_pyzlib": "ffaa1aaa1355e604", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file +{"__zlib.zdeflate": "0af305ed4e5f787d", "zdeflate": "0af305ed4e5f787d", "__zlib.test_pyzlib": "53fa0c913947021f", "test_pyzlib": "53fa0c913947021f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "string": "6aee24fdefa3cbc0", "stdlib": "6c2029b306556c00", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.pyzlib": "7e9fab9c7b47c4db", "pyzlib": "7e9fab9c7b47c4db", "__zlib.zchecksum": "95e27d852b773ae8", "zchecksum": "95e27d852b773ae8", "__zlib.zhuff": "c9349bf1e8390dd5", "zhuff": "c9349bf1e8390dd5", "main": "dca7ef1d57347738", "__zlib.zinflate": "e00d9854a0d03f4f", "zinflate": "e00d9854a0d03f4f", "__zlib.zdef": "f9cd063200178785", "zdef": "f9cd063200178785", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/ZlibTest/output/ffaa1aaa1355e604.deps.json b/Test/ZlibTest/output/ffaa1aaa1355e604.deps.json deleted file mode 100644 index 7b7af4a..0000000 --- a/Test/ZlibTest/output/ffaa1aaa1355e604.deps.json +++ /dev/null @@ -1 +0,0 @@ -{"string": "024a3459d0f585ae", "__zlib.zdeflate": "0af305ed4e5f787d", "zdeflate": "0af305ed4e5f787d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.pyzlib": "7e9fab9c7b47c4db", "pyzlib": "7e9fab9c7b47c4db", "__zlib.zchecksum": "95e27d852b773ae8", "zchecksum": "95e27d852b773ae8", "stdlib": "a96738831f025829", "__zlib.zhuff": "c9349bf1e8390dd5", "zhuff": "c9349bf1e8390dd5", "main": "dca7ef1d57347738", "__zlib.zinflate": "e00d9854a0d03f4f", "zinflate": "e00d9854a0d03f4f", "__zlib.zdef": "f9cd063200178785", "zdef": "f9cd063200178785"} \ No newline at end of file diff --git a/Test/ZlibTest/temp/024a3459d0f585ae.pyi b/Test/ZlibTest/temp/024a3459d0f585ae.pyi deleted file mode 100644 index eae6834..0000000 --- a/Test/ZlibTest/temp/024a3459d0f585ae.pyi +++ /dev/null @@ -1,40 +0,0 @@ -""" -Auto-generated Python stub file from string.py -Module: string -""" - - -from stdint import * -import t, c - -def strcpy(dest: str, src: str) -> str: pass - -def strncpy(dest: str, src: str, n: t.CSizeT) -> str: pass - -def strlen(src: str) -> t.CSizeT | t.CExport: pass - -def strcmp(str1: str, str2: str) -> t.CInt: pass - -def samestr(str1: str, str2: str) -> bool: pass - -def strncmp(str1: str, str2: str, n: t.CSizeT) -> t.CInt: pass - -def memcmp(ptr1: t.CVoid | t.CPtr, ptr2: t.CVoid | t.CPtr, n: t.CSizeT) -> t.CInt: pass - -def strchr(s: str, cr: t.CInt) -> str: pass - -def strrchr(s: str, cr: t.CInt) -> str: pass - -def strspn(s: str, skip: str) -> int: pass - -def memset(ptr: t.CVoid | t.CPtr, value: t.CInt, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass - -def memset32(ptr: t.CVoid | t.CPtr, value: t.CUInt32T, count: t.CSizeT) -> t.CVoid | t.CPtr: pass - -def memcpy(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass - -def memmove(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr: pass - -def atoi(src: str) -> t.CInt: pass - -def split(s: str, delim: str, result: list[str]) -> int: pass diff --git a/Test/ZlibTest/temp/ffaa1aaa1355e604.pyi b/Test/ZlibTest/temp/53fa0c913947021f.pyi similarity index 100% rename from Test/ZlibTest/temp/ffaa1aaa1355e604.pyi rename to Test/ZlibTest/temp/53fa0c913947021f.pyi diff --git a/Test/ZlibTest/temp/6aee24fdefa3cbc0.pyi b/Test/ZlibTest/temp/6aee24fdefa3cbc0.pyi new file mode 100644 index 0000000..c17475f --- /dev/null +++ b/Test/ZlibTest/temp/6aee24fdefa3cbc0.pyi @@ -0,0 +1,44 @@ +""" +Auto-generated Python stub file from string.py +Module: string +""" + + +from stdint import * +import t, c + +def strcpy(dest: str, src: str) -> str: pass + +def strncpy(dest: str, src: str, n: t.CSizeT) -> str: pass + +def strlen(src: str) -> t.CSizeT | t.CExport: pass + +def strcmp(str1: str, str2: str) -> t.CInt: pass + +def samestr(str1: str, str2: str) -> bool: pass + +def strncmp(str1: str, str2: str, n: t.CSizeT) -> t.CInt: pass + +def memcmp(ptr1: t.CVoid | t.CPtr, ptr2: t.CVoid | t.CPtr, n: t.CSizeT) -> t.CInt: pass + +def strchr(s: str, cr: t.CInt) -> str: pass + +def strrchr(s: str, cr: t.CInt) -> str: pass + +def strspn(s: str, skip: str) -> int: pass + +def memset(ptr: t.CVoid | t.CPtr, value: t.CInt, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass + +def memset32(ptr: t.CVoid | t.CPtr, value: t.CUInt32T, count: t.CSizeT) -> t.CVoid | t.CPtr: pass + +def memcpy(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass + +def memmove(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr: pass + +def atoi(src: str) -> t.CInt: pass + +def atoll(src: str) -> t.CInt64T: pass + +def atof(src: str) -> t.CDouble: pass + +def split(s: str, delim: str, result: list[str]) -> int: pass diff --git a/Test/ZlibTest/temp/6c2029b306556c00.pyi b/Test/ZlibTest/temp/6c2029b306556c00.pyi new file mode 100644 index 0000000..98da680 --- /dev/null +++ b/Test/ZlibTest/temp/6c2029b306556c00.pyi @@ -0,0 +1,18 @@ +""" +Auto-generated Python stub file from stdlib.py +Module: stdlib +""" + +import c + + +from stdint import * +import t + +def malloc(size: t.CSizeT) -> t.CVoid | t.CPtr | t.State | t.CExtern | t.CExport: pass + +def calloc(nmemb: t.CSizeT, size: t.CSizeT) -> t.CVoid | t.CPtr | t.State | t.CExtern | t.CExport: pass + +def realloc(p: t.CVoid | t.CPtr, size: t.CSizeT) -> t.CVoid | t.CPtr | t.State | t.CExtern | t.CExport: pass + +def free(p: t.CVoid | t.CPtr) -> None | t.State | t.CExtern | t.CExport: pass diff --git a/Test/ZlibTest/temp/_sha1_map.txt b/Test/ZlibTest/temp/_sha1_map.txt index 3c10a9e..ec470f2 100644 --- a/Test/ZlibTest/temp/_sha1_map.txt +++ b/Test/ZlibTest/temp/_sha1_map.txt @@ -1,14 +1,14 @@ -024a3459d0f585ae:includes/string.py 0af305ed4e5f787d:__zlib\zdeflate.py +53fa0c913947021f:__zlib\test_pyzlib.py 56cdd754a8a09347:includes/stdint.py 5a6a2137958c28c5:includes/w32\win32base.py +6aee24fdefa3cbc0:includes/string.py +6c2029b306556c00:includes/stdlib.py 72e2d5ccb7cedcf1:includes/w32\win32memory.py 73edbcf76e32d00b:includes/stdio.py 7e9fab9c7b47c4db:__zlib\pyzlib.py 95e27d852b773ae8:__zlib\zchecksum.py -a96738831f025829:includes/stdlib.py c9349bf1e8390dd5:__zlib\zhuff.py dca7ef1d57347738:main.py e00d9854a0d03f4f:__zlib\zinflate.py f9cd063200178785:__zlib\zdef.py -ffaa1aaa1355e604:__zlib\test_pyzlib.py diff --git a/Test/ZlibTest/temp/_shared_sym.pkl b/Test/ZlibTest/temp/_shared_sym.pkl index 87361f3751e48c87ddaeb3459cf3f411af5a5a12..30cf99fbfde8a1ee55bffa8bce644278fdefefd1 100644 GIT binary patch literal 384819 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 K7(dQm=a)azJr~0O literal 383282 zcmeFa33OY@c_vCp+&586Yweb(Ue)TwBB{0A-4Y0bBAOt`CPAqss{@0;rGP6CU}KR) z9rts4GO@)D?DV|A@jPcdNoJg}$CKx0PvR^u;~dAyB$;HKjNhEeBuZ&mfz8yz3s(YCD(|Gi#3Ug*!Rtt_RJ z;ap@XsT2!)lZmBgqv?$D>;m~cM1Srx|Mi2#C*N1ZXM1y*NGh9*Ehmhv|y6EFQ|xd^szCLPNs;rSmZ7P_xQGO0xB z2KJ%QA67D%bS9k5MWQ$HhfW{q*kEKWN>!l9WiCu^78}UcqEZBe)MEAku~zF z_FP86zV!zZOPNS!Z7!0FlMCCP1sZhuQ*;E^3q#?>tdha%wf@2g9tdaC`Ak#^uaGea zLtDbjFj&}@9N%AG9tgK!?8Cf1Xd0L5`Qcf?QJ$E+t?CM$qhFh;W{#;>zy=`?3UwR+! zI;)&tjx3#zo?SY1HhLW#kuL&5q5d=$Nz&9B_Y%g&!xM$g91ogQ5}dv+|M zoTD%6xvN(lzX*)P-WSg=FW<+zqUXm>onKlWQO=E>KN*Xirtj*wOR9}~3+*ewB==E& zEE+khERV!apB*~|yd^G`m}Q9gSA!tz&QU3af8>|qJK`OM9{=)GBo#}7a4j6tUrB$; zKFdD+K+Aw<(j_EZ$ zRIVm+Td~k*x}8(o5GV{Pfb|-Wm8(&|wOH7xf2WV}Y9>Ni$=op7TDE5W)?#6ZR+u$@ z(gxHR0%QeaEFUb_Uc9SV=rwNUw6X`UF6I(R(5hvdXWSG2e%2anOm?X-fR|=hvuqR! zM=P}j?kmRMvUg_?EAixVtV_khaHU%C#$x=#_G)%vHRJh2GM7kc?Rlh9P3+!c{G;~D zNXIEA zs=x^|C|p)c!cCwh^;@kkhc2n^G{qw$;g!fLm}+oGM>vyCg9B=~&eY8glDc|Lf9Nl4r^Z)1 zeXt#ktD^c4xbub1BzU%|G`g7WXr&e7uNFF~4T%116bzgg7=*-I+u;v}it0gljC%6w zgYZ>-6pJHRR~Occ_OE&r{+#Yphw;}d%S4NpcicrqbH2l@OSL+TrQ*g+}#jx0Mcc1K&d|X zemM<3Dvr@Qc>R%FM7!3Hf0!>4=XoMQjohvU2y{elVC_BrEQ)G)2UIb@zRpE55qc+) zfQaxe>=TmX z9>ygWh;a?ibo#SCFu>tkmp{9h0#|^3okz1AzJfT0FVNjY1pNRo#@n$uMMCI8*Ng&j z1qe~V$oFf}5i)q{Ge8f<7$@OtVG!kbA{9;MV@mc}jF@=+5X{h-vcpU2E$m3ZuZ50V zkz^hRsUru?&K93k{ZI*Xqz`%=$tI%YB{1^->|7e2ATbu~7X&u|Irj?f3yHhnoebxf z)Dd`cx=kI0k9Bp7l&45}nv`dte6^^agO8wkp8WJ2{por7@gli$fn2!=CDi4CkNB(V zIQh*>$_Y~XNI6N$OHe|^wBhPY@Ym}_H2@zFJ(*CVNpP)5fClN)@6DK^Rxrw)7-J$x zB)FkH_oULPwUu-}3xwI}&w9;~EBL9O(vs2y{s!(Kgo`DjroS*mN3Lmh0{qoIqvRq1 zZ~%+yQ_#RdH(tZvfIic0-&dRmVEMCzktw@&>)(UOI13Qj!dig>VAw#*;d>wbc9{_p zF8Na^UdYSIH)0OJV9?(g=L1vIfDvH_=yxZ$oViSdNINwGt%HGIf)5zl7<@3n0zWG7 z*Sfk)${VDNlQKa{m6SK3RMS|jlD}VrGN@+A_be%MIwYS0-RtY@UQv?w#>}JJW9~MiJ%0i zqPft#jS^}Bn~hXZpTL4BqW(ssz&+K01fg9qQNYS4>MZmS0@6&fYjTxn#275HOay-Lb! zAkjWPI~%YA;*&r}DqTF^p#m4$oJ|Z77n=mo{HSwpr!+l$;8NAUP~w| ziD36dt~c@pB)LWY4>l*elde=^cOw7$y^ATF;8S8C-F4%d$^AULG)$}(2S`|#NC4GX z)fVI-fpVDuBy=GXxW>@$alr6cbAo|%r4krE3Vk(&B?<#3Sm=h(US7F z$in^IdGHTL&V(Vd>A)0X@_$G}fRz7^Z6V5C0uazK!H2*k2LgMV69S|w4k0i$%7wt# z=*A$>m~%~yZ30p55&?mi`4EV3Ah5SNAwas~5CUgTaUpQ#)W#riQEGt=d&HExL_i?q zo$_!d&ECU-zyr+*0n(MK5a{r7T;X=d9x$6PkRI^Hqd}Cd1n_=0vVOq7z*)ic5f1zB zYfknjU8%(WN1(6fDY9eOcLzqlbbB%Axv7Z(%1Q!QzWws7pX2uaUmSMd-<<4Dx+2+~ ztWX<dTNZixSD8~_|_P5_XuR04o?8n}xZ~94H)WPAHJBRDuH01%vwJFHa{7>a)Mjm4gibZ`u=}oF)Jd zJroaI?XZ7`eFFG!b3%f2r4l5p+F_@*5J=YtWWDr0%Q7MTs?-+1D`{LnbDx_jc#Z>Q zIsxeD4$KBG;s5q2;t>uw9&Aonf`141sS-n6wu`Ah&H+WETR1_ujAniC78 zE0wTt0s3m5CK$)QJFtG_PMS@#J7pyS?A}4-zuoqEFNfccHYdN6u2kapYZiWg)gix2 z@xEz(r>rD`->>jjL41V6@59Z>@1!ecem{e8FV0qa+CKqA=q5zq1|&Ytp~JD}qyy=S znGTk%{;HggUsqks*}!9Y%1Q!Qz6-?;m*f8vhvOe^PL3yCsl@Tt5L_p&#M0+y23X`x z`_X~PDR<^=c3}!-F%d|ZT<~A>;X+euGO6F@AmNebL;~rG83`|!(ZRHT0?5!2829jq z@JAdXJldQ@AYE}n1lm6VMCigrT3oI04GtL|Z%#6hu9(Rn?V!5muHxB2l$8WxXwkTK5wrqU1g))`^?(dwK zT^tW^@)A74VgKXJ$^N7(RoTDGJCV*~ZbChC8JT?VjL}~=006lOY2yH(tR(^fMEsw# z+x{6Mfz04{awK)g9)GQj^pnLF!%+s;qJROw71R$Xu61s9w z@Siy-c(yrFK)O;D1)X?chz$XqkgUup_sdKjn>L3iX9?i`4&Z*CYy1Zs_J2onvOnoc zRrc>f_P0C6T^mW(C%1BM8UU2H1Ob5O6n~2YfRoJ$0MZp_0I<8n2mr?pv0Rb9X#h~( z5(EIAJG`&MK0`dxoB$wQaRvapGmHRm>LTX7zW+2i5INO|HAYIuA7`lP&A>OZ} zVJF)SY5XkV04|VQ3CJj$34+7eC>IXD#(~4R=7a<3%0}S;(SIHs*v}FUF2aGbnIJfv zImLy;*En!E-<)tDUD+rcU@m|M2llgsgNtyWY$gH@WHNvYhi`M>@LY4kfpldy3MNy1{h8LR?4WuiT&_I%|bdjS!?JJ7#@K3p- z$aR%Kc}oBQIuQW86-DpmAmBoCB7k(IDgwF*0_^(=x)B17_uI=wMw?z_M7c{826&5% zKFYzs#pc8S>54-PfDd3vK149!cyEEs{=I1oQ0@|d0dfvBe;vl>I4JNmCkjYcDxtu- z4x<}0?w+$xE*L+{*pZ8#GG#LXaOk0C5jUFpTO2%$HzyuQS2lu&9%Ov;S`5uoHvKLU z;UXd^qlrR9nP}=?a1h~bPDGHdY#0%|XeuH?MpNC79Z^OTfQZi3Od^$Awx=iB(FFnk zr`rnM%lT9^mq@3I>QVT6x{ZJW+IkHBQV(JAFchyB)f4#LlKwfUj=-<*&?tPYt7D`* zMat8pJOkycMfDtf1l9B8r{~B|h4x71#>rw~N8;Rx;`@sc^?7>di|}E6i~2JBXx>k= zh&MS9;&KbIGc*4JjOV&~5lSGX2R?xQL8#Bv}A zKRc$xmZHmN&nRP~v6Cm4o?Tr_6jgpA?t5y2v`~feUhQT{@=Jw|Y%Z2a+rXs%PNuKl z2d_0FNj-v4a~Vu#@C4QSqNe%?wznEVbt%E8!MceCHJqse8gwm}6KT(CB2DeYZ*>)B z$C)%!2jJE3FOt7TitI1NOdToO%D~nombpJLI1p`p)QBV~=YzpLfz*{P2Zom<7&d5+ zm_d4@SJgJD1*7`n5ma%fm?I5dFS3p*&8rhqKERBuR45d-VVa6$O;v{^O9 zPJ!TPU(M&THp^B0K7qg}HJPOUx0P9cS5?+GgSy6E+cKZ`e?%bfOMjty%wUU}NPC1r z;fBIf13%wzPyqV~Ry%CWK6=xVlHr36Q!=n1p`K-G+s1>L(s_XJ;r#{)9}tL)&gJD~ zJ{z}NNM8{M4QU}oz#RZ@dI>%t*u0f3r2PV!pTxCc{>OTx@89dZ|AZdYK4fZVLj<+& zsSc(nRMM4dL2cSM;J3Q^oe2ss!E6q`x$Edc^4pb#Db#8+Z(J|x#f0p_b zqO2hl`nn^9ejeLfO_+%ZA>b@^MkyoBCIm_|E$XDLxna}Pny+1X_Cbob<`!>*)Mz0% zuWsMgRw%VEXB5RIlGG)ESkN>(op_V84_n!{9umm@)(`w;|P6Ir?c z3ftSbRxS*7iYwec(Wt_WsQpn~bxxMwNLja)WgYeCRRa2Yo4hE9k_soN{wo5Zp&7kY z(N{KlFYGAYaxo5n%PkkROS*Jli}WErTTLr4e@__mM^{#D>RJ5*fy{p&Mz7p{)ZDQT z<^T%8LRU7j0vnn*Q%m1&PB7Fe5V(mwgL0Wo4VKyLrqK{VU_g(7rx_0PfO$cjw))TV zRn!a{@))F|Xl_NZS0FYzSCkblG|n~xGRJ)VBn)6E73sKA8jBDiS#IH;8CzO!9qL=jI(A}IdRsv8V(F> zwzcw{gWDd&hj+9AM&RGNS~fM01Vs%%!4?UN0R^}cS%tHn{3jX#6eX^NW-o2Xm#9?; zO78T!4ZayV`+6H-?xMu1lGrG!0V2X% zX9w}40E)W`>Q=Z^Nz-QMBQ5_pbVu}0RetSA{CNerQcJ}<~bJ5Xr(bIHe zLPMhh*j*_?jh{UA(Q<)gV_ z{Z|J^83fgLp+f`F*%A1hb~$u?@4mBn30eljk(ZRo1jx%SfWs9o9*ip%K(JN&%?5~n zCjnuW%-l0D8V3-R$pipmuRnO%6Yx)jsbLs~KNjugVWG@z2$e!-Oj%B(_y&e(HSQ>L z2@JbQhjTfFC5k3Op!&YG>N$4qsW}o0%R^alY6CKtvPHKxOx9dE-wXT<2c;_-*VlOBJ-H(}QbrB_>mBy5L>K#~j) zlFW|3< zWwwie^ra!DacTUw%G8sILYXXhf(n@X&>o?n9Lo!;5YzWIP> zZjNWclw2h0@B=8T$W#wodEacp_NUCkw%eb|DVbCxY3J>C=@LS)v<)<{gy`4CZz^$v zqp{=|R=0u*owLi!WNWTfx=MZTVDx(F=<)eaj-Z1P?2P+vDJd|at^9Yya(d=5ho@)K zb!pRWt}je;W?@-Z(Q+49h_O~H*alR)*4H*rKLfgvS_R!0dcye&do<8=$zl<(mF3N5 z5&WasA{dC>4y12SL~=?fvBEKV7ZC)F;Dk+LLmJcMEeytPqd=CU2#c#;1J@*|W}sYG zv!ryo^s2n$K!GMqIP@-DT?qMR_~N1DqD4SFWs0dcQGDh=zYewIg^t@-l?W%I@LZz^ zhNl`>Fm&FYNvC+REjfA)EVW+HOKY>sR}|%@-CC0)=wJlfaRlYqZAKk|;G0V4rQq9? zE-!T5o=K$gIgUXoaq9rLUAG~qpH9UjbTCr@W$leZAO3=2T5e~p`Pl5p^W~*jka2*U61%jc^n@ndFZF#R%6O>*R z3xz`Gt#l#=`LZM&it1KAqJ3N-90tKMn#-i4o>(lSWFb&)MTG4JL7>pmxtdTxRK`fL zFjSgJjv%ITLf3|0=O?WxIE1CVmpma5F++funRG0lWJ<(i#|-BdL8xI?6&E6vZ7d0q z=03%DvVkCSr8-3576}ouR`L`nPm}Ttl&==mbMO&V&y$~?qdz@QKVBqPE|4o1p@hx$ z9{7Mj%Q*SXOUemS`barR%1cl}#eVpJdmD32t?O>clt75|2hx#PAhDE*WY#zu#By0e zgK({c1`I=84ySvmL7>6W9A;=pt+B4kgMRCKZeu_oH2Nkpio&#p-KHwNDp+U8;1w8F zEpQrLP#_!zz!hIu%jT37x^vAMyRu#v3kh}}U1hghPHi-|+dU@`4rCfT9gQUUXs}$C zV1Vt3(!pL=-HRK{3k1X7$wZQDXbz<-sfaSS2?B>U$zeXa6jpuHV@)ehX-LJ<+=?S4 z5-SEmLTL>*cK>28|2Byg>4MkS1-~p1EBjy0E19)9C9|B)tVB{##hcD!MlCyB%HJsn zG1?Llko$3=xz7D( zVAH(SRj}P45g^wD)_SSqk~jq9)e~S~SY>L^<IDt7Nj*LrP{P5mfHvv)AFck(;^n>h(}2lFH7ldEr_%cl}y2 zu|&SWx{TH9XGfLM*y(6=>1? zORu&BIfh)qhtrcn0Uwj|K8~#FM(EH>EkTG~t`Op-wzh3;j*!u#X%3D(V7}H8#Mtc? zF}j@*gD8g3>|A(a_DaxhpII)q1WER|MUo+BB-x4hxB^ES`odQ{Aus1_WBVN~L72U6 z5oXvKVF(!Jrmimdy`DfBtQePDf+P>PMUsooNJ5Z6Q>@K-F7ZzOwBOMZgxTj7VcLcr zDfs~;2OK<2&o{P%#d^IZh_c@mqD(tHqMcA=-shQ^4F;~3qlj_6B`9*h9f~+R0(?-X z2+{U-lGtu&37Q;qhbHZgV)t2K_^Pru=aM!f__mli$q9MM*Cu_b76)D^tUv^jHJsD2O5dOhB$ zvg%*I+!6#Cc8MU){1&R)ndF)o_Xjyt;oZ{`q&emiX`Hz)yQX}eIS9LiVP4+v3HYz^ zNW;0OB}hXL#ICtYaVEtE$f#eMpS|K44{)erz1|WOdBhd4Ogj@}2Pj2+LEpRw=30EO zcztsr|7>u<9*C)MYfI4SQFrL%Or{MHI$iV4&xT=UY<8X#l;Pac5_EaY9lAIR%N!zf z0rx);nDxTxP2stK$LkC8qstX3nh&s|OtlyNpqU^8<29lyeqbL1#zT zjvczEI!JM>zPEwdv3Fj%0j#)?xXWS1S-^6k(~B2F#UCu14!tRKX5q&$jJkt^Z`dhN z7aQXgDD^{zL@S@;U(7*Jg^q<>gm-AU@0_52c^zIHj0$>k$SqA%^{tK~8=S<9V0=$^f*?Re*$ zuCpTnn=#*CB%9#j5N*?zcsLcB{#7|MojggTxwpiRY{(I;?a_sO3_O_k+K!#lt4#u( z%3zUc9Ge>~V*~Y$C}$5J1-C(1I*f5Ou=*m2O!q#5+Y#T$n&i3z$ielY7IW>a@5;91wuqSTpCWE zo>C&5T&T7i1c9Vt);k&CYHlU*f88!!g;mq~YsIc~D zWnV+$q`7f&K_E{05GRmtESE{!Q@j;QuL?p6J6^#wg(8nw*viSXJp$p-gK#J_qiDV+ z2nw3gFkwMUqHUT#bQ+_QdZW4ZhF2g^h-R2q%0Q*`YNLb2I8v8Qh)A=m6;9ao34~8K z>KXpzyXjK%0H?BpBBQ;{t!OTZMhacTYjxuZQs||vf)qJz*xX3*3q(pk>XgfoWFp25 zdRZ=S6~sv0(%gud7Kj+)rg+mUs}bB~V^uGuR~r>Cl`Su+PnsJYGa}J(DVbg>yS~1! zqFs9%OzUAC6qm_(@z4H^A%6&fGLJn;C>^~1Gh1!AO^qJZzoms}Ktkd02BNL09r z3fIB#vUo7?mn||d(2Eib>S>UU>*^UOVd42X_z22F=W2cE+=4(b^i$1HZjqwpa+3f; zI@`^y9To)wf++xgD7WNdlYl|`*3AuuD=DWOcnB{EJek{B$~w{&6YE;f zg;zfc-C#SnAH*L0OYC3>z7+;xm3%&$8}_DC+1&66M;YRR>bv04pq3!cwe*qnxcMq6 zFC839E+#u1Poq%&s&9HJl31z>P;i9{gYW0SfF1YUY%m~Q*$51NQo`T{AlY4)mt$B_ z{t^I#z5d{3I5}Va1bkumW6@_<4IkGr@kQhik`P!IA`PJzsAycToDJB4Xk_Qe z6QtK7<=s6shpM4^vI|Id*B)F9*pHf3Kie{c&rXf6@!(IlIUD`ZJdgE%p=Cy&9Ti{e z(RX%YM#rQlu)vW#ztJ+o&kl#L_3%4m{%*(;?+?N$bYMrf z*O(3t6~kUihDorL-~>dlnPwM*9Fu9RWvIapZLc*ooSm+>hf>2sFcF^c1^qlFaj|8H z!A@+iH8DCI1u_m&V)%m#i<6UnuiqC8g~#Emk2B{p(=sGsN43|QBzGN=WY2=nyEyL; zT@8Cep?UxKV#vo)9oKYX7{{)$ld(y&8z|6PWe!RuU7<4%$JMv+5V?PW#YeIDVJtq5 z#g9W#;p`FG_xeV~O=pkv&R+J-2Rw6gJXv;wLo0UVY_rjdbVZ}p=aDYIfW@z3@oQLo z8H@i1i{HcI_p$gBEdCUV3iPAnA&h?AXdIyHXg8K~9O|(H4x5d7q$?Wr-bSjl^+VBv zMK2T;=p*=SpWcP53nAYOpF;2BQ0OVTPN&%@M7p9;=or%FVJx1);%O{SV{rzH3s_vl z!jHvESS(->!s1mdz6XmNSj3^IKwUao!qC@#Y0=Ly$UnrP>#63XE9r_x*Y_et-oRoV zi#M_OK`e?`d<=_!4Mhcd(NPdauYrJP{*n()iw*fM@hrt3<`9l02yZq(lCDs~sh>m2 z{4^BV@+*L8H-%AVaIp$$KFJ{sOHAEtq#<1~ljcj6Nkh9Sj5Ph1lw2T^&G|B!bjEIG zd`>4!xkKsdvz*Sh{Oy|M;1bL$>Ez%Nb`|0RJu&lc{pY}+z{ z@K#>5e^DR=`n<_>R+);VVoAj=_5Z8^5U_6mQ>91*Y-I$D3q*i+w1_7b%fR^~b`WfP z04$1%`?uUPee`XOqXY#+D~uG?)8sFiFK8=cVnQG$hQJw^NyqX@rWrhTR6HaQ6`FDM zvIEs169l=t1;B0pV6uT=aK#RTvkd@)6$yhae;n?VKp6A~(vesov6P8q);OBr0s)Q|xY+;@_;Cq=Ef0Z!KnV0~_%iH2?yB(E$QvM!4p72Z90- zFaTch!df<`tb`IPoM`EfGynz$x@5EzGn8)S$k3cX43KGJ%mv4Xz|Tnt$V|C)m^Gdk z2!XwmiKK$;A4*r!2LD|k6!d8Wst&Yi1Nv9xX#;5>HMfBj5{V20523V%61%VPHxe0` zm}iWvqB%uMnO)uel}48ZB4hu{c_p(pr(~AXnUzQ?s(91+R8HY6wCmd^ZnjyQSCdWz zfO3mF5w8eD!$B(=Ahh&aUP(pQ?8@RXi3jOX)WM^;CJ+xD3rR&;we$Xk2H<^MPc4_< zZS8>4b%DI!MR?zL$Iks%1#-XcKvVYD9Oy-`3*KL>>_E#63C-<5e~&;gV01NoR zf35TUnNxPI|Dfc0!Z_y%%RC1qxTYpF23=>5ExPq=Ng&q`+#VZ!_I4sQHo6qa+UJrB z*6U>d!TW&r=8V-1beMsoU5@G}5z5te1d8D{NLt-HCNNzfd0%Vcxgko4?G-cJhUmp#nRnq2^Q=c0`4Kq{4)+92maT zGGt&$^lMIri;l>^z!30xcnQV7(lS(F+4O5pg*O~gp&P+4Iq&1hqd#jI60nr|H73DJ zZEf3}m(fOk$K|nz>OwD;N@$!-$Zy8#!Ec>;mMcc3=qiFys0QszGB4xX(INdUoU}^SiOo?fS zIo=5w=6xPG?I3W~PKNQ8Ap^^`Uu!Zr%PKyolY!`LI~`_Qh7K&(ey!=y?no+8IuIIo zXXiM0xZW~!U|IHSO^0qrbm%8|@Vx@L#CZpGC0d3GEWLiMso*Tuy30%j2)cSWS#EE& z3@KPz{aTa4nYpyjMv5|u;(J?$9uLv!xmwfXq9XxSN{=n;= zfJ25aw+tB`aRn07&ZN@;N(NuhH}8Sj3EwMT-(1K)8|0i4_0^W4$fNF1#F>m5A{4pi zo1YECtkLW|C+zW;EklXN+@XZCu*V@n32?LnfmtscP!gUCc)Y$aKQ#NzmZ8bx?$E?p z5aa;GM0nf-^LId#$=UfC4+<=MkhbH1Hoa|}YRAsnA}X(mPPHRlp(`qhB)q8ZELjAjq{b?XSvvkYv*1=H7!evLS(3+e1!|BzDUXsJ6cv70WD7$_yB!k%9#ded750StWPdj&Y&B2 zcm~})^!?9w*u+tO*=e3)ClmH zDuKte13*XvtGNv36N*Q>ZY6N(Ervf~-@7Cup zV9L9L{8c#yD{ZOfwxxUm!P1SIgg@UMY6PSlGtgjDB#%45h789xH#RPb#>PV8F2@JY zGy*opD`4Z218m5-yXMA*Um!O6QEyz1Boi@ijOwjMz(=$KKH?7WA$3P{<6~MNK8O?I zO|Ps*cnhUI-3ajb=Nx!cb~L2IXl_8vhy=u?WO}LWLiAs61VDTl7Tp*N(Le4$LrBlN zxdAaN5D>i-5PaYJPX*#ZpTr;ls62@w0npq4cv(CE_^bcg4vCw^&;aoJ5&&C%qGCZH z0Q#v0D7V`0Py;~Vn+_l#-Q?!h0gD15z>FY%ko8mp0ATMP^a&~(LDDU5ZU9^n2>>vE z%6i2?fdJ4~`jvXcqXZ9?!$i_4Xl^`Q6^Mr(f(O1+tO|sK<`V=R=mW|B&CUPs63G8M z^~3R2l$CVGzP`0!zk`23UZbUDSyv|@zPhgZNI6N$OHjgzj(+%1KY-|N*aPx*-i;~C zNto*l!?I%~vSQz__`mDY$;gmHkI;%gr#4Y~9MTV#9;eWGJCn#MnWA-fOHdsFnoYN< zqlAuQq&!8+)1*8DB~bPpd<4~2JH8W!Es=_)Z`+1VZQl+|PKIuq96G`qmJQE^UOIH) z)pXWAd|M;bpyFBT4JzsieQf-*WZly<(9$R0SA4yATs?`6mIQ!NaMijg^u#0CcsQ;^ zV(#(36h7Q+3vBFHGs-PF_OI6D1l)Di;X&_(j-+x+NxC=gVr`X%migUa(}HPx1H26> z@FDw3EslQP0OQ|YO5~)m1B$ioL*JLkhL;nmL^iItsBNX>DVN@;&=H9xIqszz0zZk_ zoguV4ub|&_8NLP8D^Na3LI%JtufQMc>Qz!+BV{9{m7>jV(3plAfbj~d5h!6Gm*4~Z zb+TcXMJ>#7@Sb{ujBcEi2~w)0ya}b6#$uKH{Th@(HAB8Z4L;kLHH`soe01;S)uDIcvEqupir$ z^baxwR|P^!oA9IPsJsAVs{r7`ZEe6%@UK;oaDrMB^+&=! z9SKP#70#u@*|n9WG(erhILKd%G9%TWJix$7sV}f;^$8lW?jfw)15&n#pNlE+lMu3i4$Bba; zig+oS$}#^rreCeBcHXqiLVVESECf5;q8rX{7y-VVmdh=;%Pm|-%qdZb*`=$UbP86C z#?zd`l7=1>A1^jXdkJJnw6`*3$kkI?*jNH+E8A^n1OX^7aEh$jI(0I4*qAc~IC;9d z#-BWWQ5QGmCQnPIJcq8~$?o3SnYnr2!UFe5*m1qaFP52(y?}SnNz}$AsDlZTT@(f{ zIG7+=SF25k-yu&gm}mWLO8QW!6BIR2SUDio=5hVEkl4KE)c+(DLQy9JheDE zIpYb2XM+I_3clGgL^$dK5u6#L9oNG10iRt0bv&fawr%xb^{@+L@5~AXGicKP3Qzp( zZkf?P=ECSZGeX<1g=aYy=+TxL`iET@dS|K^gAibXdS=4DAZM25>6RhEBQB7@ney#} za41ZXg(v*pkX`zpZy5?a>H-CvXbuhJSKOh@KhG zE8#2S{tzcrU2GW=JXL!vOz(6Qs_utCbr|K*g8v#PMD$}VLjtz9x0WcFX}jo%1_MX~ zRLlY2WnaKRfsQ+5PKd$KnI|+WiWk|sG_0|#xg^rPD$DW0(I!;#i z4$;NhVI`AEXTmGl8+Ky+7o8YSz;a=l^XeTM=a8INq8C};QypZXQAt0lt(s>Yd$lI( ztQ{v{gk{zbln?^GLHbdR8mwdWr$#rPo19UyoFrR+ zq!Yl%vo_XHa9AgBsFr7q^n()Mc%f4}Qox#g^*cKN^6u^+bcWt}(jnG&>odvcXXW0lkrk_v6F1W=i*npy3s+tFz0kR$l-s4{Ah6AYrGDW`_D~D#$m0VwUuJ5=TOGF`igLUYSVk(eEFwKXsAq{Gp z_mII0LrP2g0Dk|Fo<5mmc>fUmy@3qx7q#3ff|Ki$W;f{YcPAr|K#_ZpmK=Su`QEj3 z_7GF*Nu*Zux$shc+0Oh@dQ^{(76$YIloCXY)nO(vV<|>l7bAms5}c9=WB$S% zPm#(ni`z7)a5M#rJ)7eX^*k!2cS4Dljg^1&2v}6)Knf#P?r*|aIq3(Bm8*Y^6986Y zT*k?(t5fxxypfZ_!)@VF*rB937N8t>w+CJZ3dIJ;i7tB95!j{^}s&l@>uW4kRW z3jN`HDxXzi;aDUWv3og^cdPSmVaPm&(qR`Pdo5IuK09@H%pNP=^!wUj9iWXfLaI7+!9NUqo^A!UmY*`lgE8&OJ=>e58b@kUNs*KS+a>Kk(0 zMJ&p!5VdAeV6$0N&!}}zR>{#l5BB{I{-avZy0Z(uanAU5Z-u>nj+yzam=WzrjvxEU#(IwG6Hw74vRwVx;;)(%PPZ+!sya88J(1Ifb*|VYva|z&|9WG92W|N$aYM zi%VRG!;&aC^hZ`#l~k-89=^8`@X!fM?%rP{=OBT0phxeqGn34JjcJ;LotOkCl9A(; zDkDcKlIBKEOcZhkvhhqJbrTOvUQTe%8~b;S0G*j`6Lg#bLaLJH2E?)`KsGax;JxeJQblq5pw8`K%-LWU@c&<%dc;LL?E+kQw99kC<_La96@iKInTmDEL2oE8YCTo=Elvc zDBSeMD(noIYChx`2h+===U-KqsPnRwkDkwnLQbEianehw-J@7(0O*wHm62k}pQELJ z+O$r|&8JIdD9+%c4rVB%PHJwQloN%l0YfKovGsp69=6Q(9f6j_2Z>s5WzBO-6h8Xz zCKF5HNGz#j#vp^Nb++Q?8UP+k4)y2}Xf3Ia!7JpnGEbsjlLGn5HVk@X@Td)k=GN-<5--Dq5i-h{ncc8$CJ zm=;dY^};vKV&vh&@cY9s^sg6>7k24Yl~>}OdX?qYH}AkZXq7c4s-vK#dWEcRlRA7W zo4CDHOkH%4Hn-NRol$+mp2(#nXS((=9UR7C2LoDD$zccXfx|p~RemLavvldCAJrrt z>zH{HMjiI1g2dZth^aEh)TmB}1{G3T6iZ5}tt_Q>YS6Fqo{UB|rie*WO|*zvX9S|9 z<8C~^4B3vXp^JCv0>zObwe#B4;v^gs1;?d%XD57|An-a+)$8g_s8da2u?oey`Wlo$HAB8&&|Q0yd;EMR1{gDUpM1gx0a!8Zp;KK8mHnZfgd} zx*GcGXZk??=a)byGXavzC>)RLUvUJ;?j{rxKF;X2%#GFLHMeT z3>7z+gubu~PU6Z(bHiqtdl@bS)hqa{rn6sxKi1W&q`XEhzY9w(__|FUC6~rXd5V;$ zNqGiJQ2poNWAp3Ks|ZsEHia1bumE&{9XV1u)&I~OIJ_ltCoFY?7{;%l8xOz} z;@Cw69j?oOBQI0jJruunOf&Kg8}n!rstD2#rXq-AD9lPKY#S{`?o$cezhfx|3vk%w z+R9RzlMzqasKi8YF>6ExIm7^MmP4)wqfItysT|^)s(;UsLyt6}93uVDO;wb+4oub3 z0iuGMSgZ$1EY=c1E)7>uTor<0jt__~^x}X+2u5136mNAE6W~=n1d>shwsu!hH)%|R z30^ZJ)X{Ej z@WKvQb8VM4a^T%&_(EqopMwM0?PD+9(CThzp_h)HJb+1%xuT7~Ja$RQ6hxsnkpkhd zi31|9{bS0hEoWIp;R?JOYjw*<@30Gp2jfXpVM_Ynw4iUQ3d2 z%t#6&ll8Skvc3^*TDN-aw6^=ncj^F&!o)0ZTKidn@F9pesb}Pin0F4^V(l`mUUTO~ z8WV(pMqUg<)|516APyG8wBL;>oXyJfy2Nm_5N7YS3EyPE6Y_4T%aDR?J**`uX4>AU9xeoM z*=RB2S(vudVzp&x!LnJ@looHl*AXpt>mq8#AB40DA@7u(60f%mC79D!OG-@d*eD?& zw?!F3yxB5@*hNjIS`uPryR+OD1|+6D3sYru_D5QV5^Nu0Eh*tpXIlut*VrF#8A9xF z0TK>1wuKUWef`;%p~PMnD6w&UT|NcUFSHCL9&mvY4pSiQH!LTh#Dsq#R4yacZ?p_K z_SK#o)5DI;r(Gq~;QQIX(=v3}?*bimI-+U9-KW~dwR@la|VqEbb|PT6XDs(@OWU>%Lxe{Y#Cxa=mIg? zoDpL`&VArUU|g3HR_^375tbhcxAA^>M;nyz&y+4reO#xDk)8V?tp{X3ujm;JXZagR zKdMbiv5uJ+hPa*(g{14-RYI7hNS3ozdyGSgBTYyN(vNDCU>&PJB@XD6h$XT)8%E5~ zxX2+0OQ|zWx4Jh6G)Ofe=|?qEu#VLq8~b!pVCFbf zA?Zv^$=IEaYaDVMYeI66epDj|>sbBC(RUYeJBDv(5;-0XZs;^H5^+4*P&A;)(yJxn zApM{;I9}MXl!vt&)(y+;uz`&xiFP>&>-{g25VVnGhulFzS-;LGEp#uffwe7{;ENgk zE)JMHWb0YwjW$OtNluQT&*(T=@^o9Bj`?U-4^zEB0CEvZP#7NgfSg+6 ziUim_i|GfZDjff=OLwY$m0l3jBid<;NJc6dA5aK{*(aO$^c=z zI_eLQofIHh1ycV;a%s+@g7Sw%&f-S*trmW}%J{9smz<`U@?sD%i3oz8~@ zvOJ64F|$ahL5IKRx?UA8^+U6=~p}R|BhsS z$^352PO{w*^=JOQrOcmHZYfDf_iT+#e?v09WPCRm{}`Q>tUu!ql`wvKNwqV5_v6|O zTm7d5q-_s)+o}N_b`Em=nSM86dc(ruvi-1RdnxPPkoAv=lJ&!OwhtSJE0FUQtOn0H z2?7ZMH$d=&C=eXsfFPgB!*U>YK9Lmya}oj)0&YOyNl_4>=8qQM2}jebYj&$YF4wqiSpR}Gm_mUySu^e>>RiHhcovOc2`zbb8BGJl$*5uHOcpq@7>^gc6M9+`JT>Q z-ME`r4KJrND-q6e{XdXQFPYvArf10nL@|9PavN6YkQ}sjgZ`V6=_S*!px)L&(2V6xTC1Hj_zb z!tqEdmQ18>*o~WulJ6zoyTSJ_h~oP}8m&yHvbjhq$60m!ie!1o@@}v^O9obdC$@Jb zl1Pn=j-5Jv#xCJkCA&*@cZ1zo>aV)9dn2d*BI&cLWhoMs`m2!#?&x8NIyCCQ7518r z7|BCI8_2u(8ppEuXmwEwqR5?mXL`1$7hoh=dZ&@1deQg`)+!8i>DR`z)K4Vi!KtEp ziQFmk+-&8H2gj*V{#@M?K@I2tibt|>yOHvr1R_UE`9Z-UQ+{k^0Gtp70OODzid7@bvh(&wlZ!;Md4N zAApu`8h-&=zGeIc5v%W#zbd2UP0NuwA9Q%6&OP;AphBm+<&iq;>Mb&3a+{QQpoFAq zYw+=U5eCQYytJo8p~X1uKAlp+*?5|>I4<4@c%do#N!SYTa`-_#rVDsEV*CYoIcEF? z5nd;{Mxtk3jRUK%s|ix7q`V2Gn#N+4{QVk~K{Z3ZZ|Lks*U@uE5PIV0ts5cX7jllw z`*7HfLZRhddX63ag1-wq`h}kJT`h6u`No};8oCw^&W63SGjsF4g$4g?&>l?uAzfU3 zvDZR{SDT3nuU4f3JNe}W2QwS%YBf0DQ*)GG^YBqo8^U=?{nx_dzJ*YDVb159u#@25 zwhRe&Q_)jX5^PhQkYG0>K}9Tlrez4hj(e#oA$lAU;(=@73E!k=F%YUOmp?T&x|B$!+b zltsaJTZRPe$d{U;V22|TbOQJf8f$pJ0V6}h7jyX zn3}@CnLP>)!K6PB^3C%+vI{LkfFmv-!I>#Kcr84&I5|1v35I8b0S*cREkgu$HcU-X z;LI59xE7ud`0NtsYRioMunPciW`%+oH0ghZCw`V&X7t(NFg4|TXGUoIweT#*0?oF} z&_C<~<2zHm7=!>5)H4(I1v#@cZ?p^v*eNkJ<$h<%w-3UhFhv%g@Owjc>Hoo&p}?aq zfWVpN1?lgbpAXL3NB^TOGy3efm|F6`^9dQSKQ$>dKR-Kfr^6>&h7OO{9tAIb*XhI< zXoCq)$b)F$QQ@arh6?Q5n3|&DJ5H$p3Sq_v3YkxYUu+p7uwA(|CBnBiK!owd$#O*a z&6XhoJ3gkSMEI6dBEUrDW#2rm;VMUn-)k8{ur0bZCB#2DB}C7R=aul4aes&ts{Zqq zAptv6rj{g_-svb*-4B84Fv_C^|20mC=pR~!1Z;b5ElDubcF_?H29O4*m;=7czJT3E z-F~7~rYqSIGqohbw6mo{{nrBiaZM-KNwBkJNWk{y){+G3uRa6}>}37W(CXUVWMV0- zkR+NbSx)}U2X#t3f$Q1HI(K$Z%L|RM!up=-C99YxNa-WxBq=XJ`D#)1!-q=xQ7!)x z>)5L`S!BIV7Fh=!5#oUoLg3EN@T~|ZdB&3*YOr0aO+^jTk80Fl9jiYzy1ivjMLDAr z-~)Xc9N2*t4MG6A?c<(W84jc$lmN%ozeaiSH&}cVi~og12kb;t+mAr;hlilpiQf)k zaTtsLg}*(H-$t+)#p18;z2AP!h*2Mar{PDWdy$wR(T%2RbUV{;G!6$C#&SB zPPJP$b2@)?Law@!ePgcgSkhDI&BO2+DfH-e%gURMUk0Xq@_ohEi^tUv^6w%Rm!Sx% zSMU;1vH;Up;E#3nDk-l)$u=DiYnzTiR*-9Bq&!8+)1*8DB`E82@DWtclb@cWKRr)B zUL;rC-krNeQ^34i6F~|Y*=17lMdrP#+s8Iy+4Mz|xZ8MX4YF3-(U5EeG?Z>PevM$G zG8*J2Viz@S9k$>vi9$nvWOY?Z#md3qUL(Mv6Y@zI%E6RT)t1}E1RU6XUvvN*sYaR` zI5APc8OX*niPTL@EV-QEJ2Q|^FR=n)A|;be zq*Hd&>Q@9JLN%G}>N8+#GS}fGd{rgSH#g76Me%&kjq+~wS0%Rtwxr`sVuj$G7n?vWaSo}P*@cO zn%-E2+1IJYgUx~g4S>yM<1c{CRpT!So0fo0MigxNG+mQkQtiPawGnW0%RmE!PuGmU z05|V3{sP>**Z2!?^UsXGPL~||28V@yfLxQad0RRCd`=Xm1`JiiMb%r4fU19EpaW24 zGU)(SpOEO-@`wN25`~U_va~o7ODdT$;I)IsG{A#64e;qk0EY<<0FGZapaKp4RR`dZ zu77j8{&z%yqnCgqnu+qD@n0Jc8h=~@jX#sn*z$Vgt{`Z{pSP+C_=SJaLPM>%uXfPF z^Hrys#6*ftY&@B?>zFwpd4()ntL*7Xb=}ofWz<%VM(xyqU+0|`@e4M)=|UO1>0)DS+;w(9)rH2j zn|5BqWUFCJso|ZS;AMZF)+N$b&wSoT+1~3wH9I|@YG&A3-n~JC4E)3iPji7`O$(Ome;ze2t@j!5eT=wt6xEi{3#ZHR+%iUyJoVu?rxay zvy0*fC;A{K2Omana$v-=&^8s7NIx_xy^XYKL#7$sU-b%arT z+=?Oig&#a@DAH659*#Gz5!}8KN!Yg^#eHRleX@}hOSNJ5HSVzQyqicZC*jQda2BLe zWW_$g`WcQ`8luM6R3j0gnsz7s(8SVfGlkzii{DyzMNqbI45SA>V4G4cw={{FXL9{y_z_LE)j9B1Fhp?_Byo=8 zX#KweK~!juWNw@+s%Hr@A{BSC$gR1}JwL`0qfI#o!qs$sEPlymc3&!E|2359QO*9l z)VTKF-fQga>+ltSaANjKm>>G=cm}Kx;s9;+05qGIoOZzbP6N=+LZ1a2Dfqdacee~F zSj@AQq?l=Y!%-qt8!cu$3!D?FjoVMliCt`chS{p=643?25nKnG`MCmkxG1FpCW_=4qtQEVB4 z9B_dkdmI77P~8DPN~pzP$UY7EV=Y67gS98b%n@gP#U33ROj&SA@#&T!#i81hV)}?9 zOdQlHfx>Cw>dg3TU?Dv2S@7AR@$)T1kHfX6$ILco(0D*62po(ao`uu*0<&IDNbuKM zh8PdJK#VqL#Mpl~rqER@NhK9l?&LC&@KPd|wPWLd=;Sc=R6V3MydjnjJKIx5`axH( zlt0jjb#hLHbdR6s%+Q$HqRL6u1f- zHAgxVQ!;j?(etb}+ifU~V@*g7(vNE7U>&PJIr{E`$`0SoByv0&?9*vrY$|!Qp=jW2 z&kyMbrNMDE^C&P@7K`^_@j4dwuvo{Uh{cDYsIb(N4S|_jbzB!;pfrQ!X8M@QozzKI|8=?A zlEOcN;d_6v@{+0#QgD>Z0l)XDzl!pK|DTZxg1_< z-1W45a6V}+yc)@7m6%=IuId8Ea4gt*u3$5{+@v4X91G5_r20goC=He)i6oB(uXAX? zmU1-}4M;z#(SUW#YZ4zOd$UY#rSZqi`@m=_SD9OBE9X{X%hZAn z*7(g-0kp6Y=uC#yfp_me15*)!LN-T{*vWVdzwon*=I zTbSY50_^ z_>%G6NYuqvc-5crhe{Zqd$!>#lIbPWyTSAEDwekRWga1W$+p!4VD!@~J$m1q#O^xriMCKPn+0 zA>alCo)iTEYX0bvo@jb?&Cd2eE7@MMy&G)*lqj~RF&@L}5AzxSze&cIjPC~HKO>6q z=~PzP^M3zaGQ4DXHyHjMq8PrH1~u^@U%O$`c2dsV%E>Di4%=X-Qq(`Lvxl&|va*_6 z1Dj@LHKSxXb5{o>-%By?hL~qZQPiLB>D<+gyNT8CayqjT;VjlaDVbg}y&Fu=5(bE3 z`b^|Dtk5C(wd@wolw^9z^lmWyS+NHF-B=>Zk@4@A>@L~e4R${-irse+gC39bUWug2 z97TLba=qkwH@N zcnNYpDOp~!yc;afGJe(HiS5Oc@L~e4R&WazUt2I@fll=ubDDA zz8WOGk+U3MGYy;LE3cja2&vCN@#Oo8uNRN2CkdoRpoEjwN8w{#9V6u_Ql2K|87N;Z zs^{Rtwas1XLr{Ce4qTxx9F0I;s2DB^F3#-Vo?j~L&!+R4s1jaD$MQ)foK4&aFGJq0 zERJjZeEhliJK_K5<1fTtg#RzZFUCFa|9IRRpMd{;@yYn5_*C2v|GyNUjtAiXnRqZh z8xQ6SosjV~9E%bHeRdBa%`f1`HuX2?U%vw%Z+5&5|Ju|)F@66#diibm!1EaU_rgPO zs0ZO=rhS|GIR4qDj^W34^&)SyqyNBwpD=vMzHz4piS+TY^GcJ;gXu|w^95L`A+sTc5Ln;O86?dnzh*r6`tN4uKEk2duU{Me>`5I?r7e~uqJ)qjAGnYN4S z_7m`Dx4IKP3LPWQjy(&L@Y7Gjwc%~*EAR=o;#t-3fhWR3-FO};k`YhCgkSO8IlLDS zJcF^q^S0nuJmqP6kBVmu;ZZqwzzv+!g6FE>@gR7l2Ml4put&MGn$D1{`bs7hUe2eY z+2Rj?09ft<*!?^f6Wvhkz;8?V?JM~0B`m()1I3Tvx5IehSFrdA{Owu%?fam3tFR}L z0>4xt6^FBHD@$qEC-{1?@BqGvBng4Ad?cUDg(I08*<$?V!u}gdO35Um;b;<44nk6? zmDOYfOn!W-^D<->fh0PBq(XZNGM*O;J0g&Ds?hDln4qBx^43*r`9*nFg z#>MT4Sh3Jf7C{$wM00o8T^$S1LjATS^(eGsx~tF|O((f3?H{D+7RZ<``U}RG1 zB3vEBKh1Y^gCOaRq*Ccz1V>4$dpwbvT{W7}o>Z2#*7bODxlCdypVQxcoMaPL2S-4v z(=pivUklsdi9PUzbt;gK#Izc<)~W~K`gE^)5I?%qL-^4LEozUzJBsQ)&J3!d4YUNu^uo6YF&Ds*HLH{#HkhoKVIz{^N9OM}%X@Fo1$?Ja5I1CaIiX}G!2 z?w!MSI(g<0JX5{{coo|eEOcfQz=%o_U~Im=B*opcCTjYE}&fcwOL?htUBi?>!Ag7(#PI%(^DUrF!# zXzxJ^(%wG=+{Z-3umeaGI#x_CF@zL*2@`DWB^pl@I%ejKmQ{HOMa?tVl9O1BI%pGD zjIjnCpcG;aItXayh?;v35eOPOy;mxXXVc3dsjP73KKU3tNhOrp4i&(l5pZzteWH}a+m?)3B=cQSM?dM+3(s6uGa% zdur4FT_yeBW$8cBa2C3Ap8z+k4Bd??47#%_m}|vedZ4u5+}Geewdwcnl78>D^m{h| z$!a`vpD_CUaRY{*z^AK$kT)*u6>MBsqp;6J+H|nfh%9yk_aU^hn4q!RCQg9K>O4vr zlQjf|4Y4e!jGY0^p|SUpGy9Y$c-X5>l)UO$)@Rkw00#GPpEw6k5LwD?I$VvENL+ST z=}4c4I!wr8_b}bW1_AC-3WK<1ktAD&01E_%AnwzZQF8fADhtpiRTTP&X^Ao_ zzY%yVwB!6d3;A?;VSh!$2!|b4ow#pws4Pf&fDTk2ZS4bepful2HDrRpirgn4Oi|d8 zUL{l~P}%N#O$SP((1#mBXsT{<%NL-(rr13C~V9B^1}WYV{71}^s@ z9CD6<%e@yB8)4(JSKZ*P1GKL!Vs(J_70fqEIv#IvpFkgg@z!zRqx<3}_5y}N)+F8Y z=W!GFiKldK;dYB@`d>7*t<1VG-F2>JHTo`v% z4c&FJ2@I?Cb&!&cRd|q+Z4kP&>Ch#safo)8)re}5U^vB@fZ#r%#qU+CowZS5^5!7e z8(B<98INwK)PM7ou%|AkWo)BPdEq&sm*4D3K!$|Ayqcz@=)?CtB!!vN>R}x%bWJE3W!VG!&7C~9 z3m&7Y!A`L?4#n8Jchf;;@5adyiy)w^$!`I}1$!9$mD2I%c2CDb*{j6F@A2esSYp&F zkyF(eif0x-STfEJ(s9NaV~dv9hkzzPRCbpk$a1CJxP} zEpt{Q3yZTFG2~5f$D5$zK7n>JL7UYw-;69^Z#YKf9%~a$=a4q>d^GM8sN0Av_!=@9 zu^27f0;~5-vVc`GQu10fkqM-^ufVHj&BShEWM?hMo2ntpD$#$FqYjRhAn6z-K9b4- zE@0K7si&-_!?dTYCIcAU7ny)zpA{(Id_!KdS{ZQIOHUwhxMI4U(_rQqbY z#H}ChDFr6Gi&4l_Q#E6|JDrU2SNc3$0?LOeT`;1vX;88nnc`

TweuD7jCRb(c2- zO7;fk%CI)+Rx1yb+$VtGR#4tYYZybY*68+UkfT*tYf7JZC$xs3o7+~rYDPD^iSZ75 zDc)3-cTlKvSBX7R!aI-DfOlApjCWX#6?upIL|NV`4|O9#%xYx3!rJg;Z79#`ewxZI zR`*G$n?Q_U#&LMlMvbw3oOV7|VvIdT z;fvsMV2qVGDXb#qfwGDYquD~(ockWQTzPtdJ;ekttMn18EyV6(17zG)qh%kDmq@tB z=@98Iy}@>dOyoWRQIj&uU3he1Rj|bd?4@YCnk+@`Yw#YsVY?Z)JyFu{CoKIoEG47g z+$YK}@8UTJtP1AqvX|nVv8mtO*T6kh!x=2Nz`_}($}QoH!Va>%reZwfxWj z+}D$ae$0SzXIdFt=zv9D3T)Tew6)FN#MT|MH=+GQ#3Rqz=01V8uxYT_Jxu$uTH&4z zEyt)PsW!u&CrTvO2|BQPK*oTjVa{=%*i1l%Rm7N-z1r|Qx$iOgotA)%Exc=0PP~;g z>>W&rvnD(aq(i2Kh@Le z@8;MxtZp{{%G!+HjwPD58R^67exYPMJR0Zl+&AtM)9?g=6Su9_tED`ESIu@JtAb&T zbr)~4n*)~7EA-&P!&rD#-=1iI?&%WHJxxJp*fLfQx74iiWEZQF**2_7oDZV1%RZ^Z zn+9Z+uz)YC1chuhYVur6Rv8m!tg@p}8Ic2LIe6ecL2QtADu4-9xjn@Qut~wPdl=c+ zyYZfCYNA?4Kg#iGo}tuaE18}#tP$*Jp@U2V+9m z(t!IWG)Ty3va4*QSRKR^`3pMcIE`gjGD(OdYMs!5|Yy8>n0MiTba#hywtY* zb_edEt~>|k)Mk7Kr4q9l-(gV6Vl%2l>TO#4vDYwzk-es(!N`3A>0{z&b`LWcS*>`F zwedt_lEzyZh(|J3EnD-=s(p(4>PIM9jeBZpt6Ce&(>y0B0oi2XNrQm3TK>mgz(go} zfxcRVw-|~01c*51pL1J`5|Az?wF)D)7MMN7X1G{007s=pAiIm<*0`%`0Hd0O;~6R= zB||?#hrXg)z=sp z*(e>t`?9lHjm*wwHCD84ReW^JyKoz3cIb~dZq19FL2WVej1E@!(Ph-0edaZ zx!ea2utkfkGLRAF{TufB(kE=o9Jym-UFOJcVt8RMufZ}$mFM7`D#6n!il-i}r$5Yb ziMUUoZYt-E8Zb6Oi>wl6^s?8YOKY_jiP3A3SnOej3HC4;2Bk|Jx$V?(Q0{8gm^ibm znSaAxj@8;?;+RXWvVUVU@ri+kl1y7%Nc^}nlt#?GIYVg#3r#k##?NYxRz(HRR6I-D z!JOfp1yGS7(SK7m#V=@+}o7@gGzS0m5>EJQr;(0oFAUrn!<>RinfiKX8F%SF&+OUdlAomHA8%WlQcLdWp^Uhpt zL#SoCrDSHDRm|K%))d1n7wPaY(f1-99$oZZL4aG76!!@<+*nBC`%gJs z&CDud3uxG@NhFX6QSN)-vKENg=-!CUh=dDtbeOw(fsPKc0ui^o(cwOUD~`w$BtxZT zJh@MxyGhNCs%nBK%2=H&1p{k0ESI3I;7y5gpRmmYa@(rU1eUv68U$i=WlEp54eO|l z6u(GG#;U(aNv3T_HtoYVq&W8pW3fUdM6*X3qS?z3vL+$Ut)3Wl=AE$&{LEx9)l{2N z@z7CW)qCiuRMc(UCmiZF_AJwF>}?j^#;qUksZEE+OFBGm=`e523ipY!Y*4!XoIT6< zfV~Y-Z{h=P{culJ!EW!5< t.CVoid | t.CPtr | t.State | t.CExtern | t.CExport: pass - -def realloc(p: str, p2: t.CLong | t.CLong) -> t.CVoid | t.CPtr | t.State | t.CExtern | t.CExport: pass - -def free(p: t.CVoid | t.CPtr) -> None | t.State | t.CExtern | t.CExport: pass diff --git a/Test/fbnq_out b/Test/fbnq_out deleted file mode 100644 index 888f849..0000000 --- a/Test/fbnq_out +++ /dev/null @@ -1,676 +0,0 @@ -[GetCTypeInfo] Node type: Name, dump: Name(id='UINT', ctx=Load())... -[GetCTypeInfo] Node type: Name, dump: Name(id='UINT', ctx=Load())... -[GetCTypeInfo] Node type: Subscript, dump: Subscript(value=Name(id='list', ctx=Load()), slice=Tuple(elt... -[GetCTypeInfo] Node type: Name, dump: Name(id='Struct1', ctx=Load())... -[GetCTypeInfo] Node type: Name, dump: Name(id='Struct1', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t -[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... -[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='UINT', ctx=Load())... -[GetCTypeInfo] Node type: Name, dump: Name(id='UINT', ctx=Load())... -[GetCTypeInfo] Node type: Name, dump: Name(id='UINT', ctx=Load())... -[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Name(id='OOPTest2', ctx=Load()), op=BitOr(), righ... -[GetCTypeInfo] Node type: Name, dump: Name(id='OOPTest2', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... -[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CSizeT', ctx... -[GetCTypeInfo-Attribute] 查询: 'CSizeT' ModulePath: t -[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Name(id='Item', ctx=Load()), op=BitOr(), right=At... -[GetCTypeInfo] Node type: Name, dump: Name(id='Item', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CSizeT', ctx... -[GetCTypeInfo-Attribute] 查询: 'CSizeT' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CSizeT', ctx... -[GetCTypeInfo-Attribute] 查询: 'CSizeT' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CDefine', ct... -[GetCTypeInfo-Attribute] 查询: 'CDefine' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUInt32T', c... -[GetCTypeInfo-Attribute] 查询: 'CUInt32T' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUInt32T', c... -[GetCTypeInfo-Attribute] 查询: 'CUInt32T' ModulePath: t -[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t -[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t -[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t -[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t -[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='BigEndian', ... -[GetCTypeInfo-Attribute] 查询: 'BigEndian' ModulePath: t -[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='LittleEndian... -[GetCTypeInfo-Attribute] 查询: 'LittleEndian' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='UINT', ctx=Load())... -[GetCTypeInfo] Node type: Name, dump: Name(id='UINT', ctx=Load())... -[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... -[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='UINT', ctx=Load())... -[GetCTypeInfo] Node type: Name, dump: Name(id='UINT', ctx=Load())... -[GetCTypeInfo] Node type: Name, dump: Name(id='UINT', ctx=Load())... -[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Name(id='OOPTest2', ctx=Load()), op=BitOr(), righ... -[GetCTypeInfo] Node type: Name, dump: Name(id='OOPTest2', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='str', ctx=Load())... -[GetCTypeInfo] Node type: Name, dump: Name(id='str', ctx=Load())... -[GetCTypeInfo] Node type: Subscript, dump: Subscript(value=Name(id='list', ctx=Load()), slice=Tuple(elt... -[GetCTypeInfo] Node type: Name, dump: Name(id='str', ctx=Load())... -[GetCTypeInfo] Node type: Subscript, dump: Subscript(value=Name(id='list', ctx=Load()), slice=Tuple(elt... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=... -[GetCTypeInfo-Attribute] 查询: 'CChar' ModulePath: t -[GetCTypeInfo] Node type: Subscript, dump: Subscript(value=Name(id='list', ctx=Load()), slice=Tuple(elt... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=... -[GetCTypeInfo-Attribute] 查询: 'CChar' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUnsignedInt... -[GetCTypeInfo-Attribute] 查询: 'CUnsignedInt' ModulePath: t -[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=... -[GetCTypeInfo-Attribute] 查询: 'CChar' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... -[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CSizeT', ctx... -[GetCTypeInfo-Attribute] 查询: 'CSizeT' ModulePath: t -[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Name(id='Item', ctx=Load()), op=BitOr(), right=At... -[GetCTypeInfo] Node type: Name, dump: Name(id='Item', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CSizeT', ctx... -[GetCTypeInfo-Attribute] 查询: 'CSizeT' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CSizeT', ctx... -[GetCTypeInfo-Attribute] 查询: 'CSizeT' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... -[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... -[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... -[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... -[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='EnumTest', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUInt32T', c... -[GetCTypeInfo-Attribute] 查询: 'CUInt32T' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUInt32T', c... -[GetCTypeInfo-Attribute] 查询: 'CUInt32T' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt32T', ct... -[GetCTypeInfo-Attribute] 查询: 'CInt32T' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt32T', ct... -[GetCTypeInfo-Attribute] 查询: 'CInt32T' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt16T', ct... -[GetCTypeInfo-Attribute] 查询: 'CInt16T' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt64T', ct... -[GetCTypeInfo-Attribute] 查询: 'CInt64T' ModulePath: t -[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t -[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t -[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t -[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t -[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='BigEndian', ... -[GetCTypeInfo-Attribute] 查询: 'BigEndian' ModulePath: t -[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='LittleEndian... -[GetCTypeInfo-Attribute] 查询: 'LittleEndian' ModulePath: t -[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... -[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... -[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=... -[GetCTypeInfo-Attribute] 查询: 'CChar' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUnsignedCha... -[GetCTypeInfo-Attribute] 查询: 'CUnsignedChar' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=... -[GetCTypeInfo-Attribute] 查询: 'CChar' ModulePath: t -[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Name(id='Item', ctx=Load()), op=BitOr(), right=At... -[GetCTypeInfo] Node type: Name, dump: Name(id='Item', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CSizeT', ctx... -[GetCTypeInfo-Attribute] 查询: 'CSizeT' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt32T', ct... -[GetCTypeInfo-Attribute] 查询: 'CInt32T' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt32T', ct... -[GetCTypeInfo-Attribute] 查询: 'CInt32T' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt16T', ct... -[GetCTypeInfo-Attribute] 查询: 'CInt16T' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt64T', ct... -[GetCTypeInfo-Attribute] 查询: 'CInt64T' ModulePath: t -=== AST Tree (Compact) === -Module(body=[ImportFrom(module='stdlib', names=[alias(name='malloc'), alias(name='free')], level=0), Import(names=[alias(name='ctypes')]), ImportFrom(module='stdint', names=[alias(name='*')], level=0), Import(names=[alias(name='string')]), Import(names=[alias(name='w32.win32console')]), ImportFrom(module='stdarg', names=[alias(name='va_start'), alias(name='va_end'), alias(name='va_arg'), alias(name='va_list')], level=0), Import(names=[alias(name='t')]), Import(names=[alias(name='c')]), ClassDef(name='Struct1', bases=[], keywords=[], body=[AnnAssign(target=Name(id='a', ctx=Store()), annotation=Name(id='UINT', ctx=Load()), simple=1), AnnAssign(target=Name(id='b', ctx=Store()), annotation=Name(id='UINT', ctx=Load()), value=Constant(value=123), simple=1)], decorator_list=[], type_params=[]), AnnAssign(target=Name(id='S1', ctx=Store()), annotation=Subscript(value=Name(id='list', ctx=Load()), slice=Tuple(elts=[Name(id='Struct1', ctx=Load()), Constant(value=5)], ctx=Load()), ctx=Load()), value=List(elts=[Call(func=Name(id='Struct1', ctx=Load()), args=[Constant(value=1), Constant(value=2)], keywords=[]), Call(func=Name(id='Struct1', ctx=Load()), args=[], keywords=[keyword(arg='b', value=Constant(value=3)), keyword(arg='a', value=Constant(value=4))]), Call(func=Name(id='Struct1', ctx=Load()), args=[], keywords=[keyword(arg='a', value=Constant(value=5)), keyword(arg='b', value=Constant(value=6))]), Call(func=Name(id='Struct1', ctx=Load()), args=[Constant(value=7)], keywords=[keyword(arg='b', value=Constant(value=8))]), Call(func=Name(id='Struct1', ctx=Load()), args=[Constant(value=9)], keywords=[])], ctx=Load()), simple=1), AnnAssign(target=Name(id='S1_', ctx=Store()), annotation=Name(id='Struct1', ctx=Load()), value=Call(func=Name(id='Struct1', ctx=Load()), args=[Constant(value=10)], keywords=[]), simple=1), Assign(targets=[Name(id='S1_2', ctx=Store())], value=Call(func=Name(id='Struct1', ctx=Load()), args=[Constant(value=112)], keywords=[])), FunctionDef(name='reptr', args=arguments(posonlyargs=[], args=[arg(arg='p', annotation=BinOp(left=Name(id='UINT', ctx=Load()), op=BitOr(), right=Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load()))), arg(arg='v', annotation=Name(id='UINT', ctx=Load()))], kwonlyargs=[], kw_defaults=[], defaults=[]), body=[Expr(value=Call(func=Attribute(value=Name(id='c', ctx=Load()), attr='DerefAs', ctx=Load()), args=[Name(id='p', ctx=Load()), Name(id='v', ctx=Load())], keywords=[]))], decorator_list=[], type_params=[]), AnnAssign(target=Name(id='GLOBAL_VAR', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), value=Constant(value=0), simple=1), ClassDef(name='OOPTest2', bases=[], keywords=[], body=[AnnAssign(target=Name(id='fb', ctx=Store()), annotation=BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=Load()), op=BitOr(), right=Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load())), simple=1), FunctionDef(name='__init__', args=arguments(posonlyargs=[], args=[arg(arg='self')], kwonlyargs=[], kw_defaults=[], defaults=[]), body=[Assign(targets=[Attribute(value=Name(id='self', ctx=Load()), attr='fb', ctx=Store())], value=Call(func=Name(id='malloc', ctx=Load()), args=[Constant(value=1024)], keywords=[])), For(target=Name(id='i', ctx=Store()), iter=Call(func=Name(id='range', ctx=Load()), args=[Constant(value=0), Constant(value=1024)], keywords=[]), body=[Assign(targets=[Subscript(value=Attribute(value=Name(id='self', ctx=Load()), attr='fb', ctx=Load()), slice=Name(id='i', ctx=Load()), ctx=Store())], value=Constant(value='1'))], orelse=[]), Expr(value=Call(func=Attribute(value=Name(id='c', ctx=Load()), attr='Set', ctx=Load()), args=[Call(func=Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=Load()), args=[Subscript(value=Attribute(value=Name(id='self', ctx=Load()), attr='fb', ctx=Load()), slice=Constant(value=1023), ctx=Load()), Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load())], keywords=[]), Constant(value='\x00')], keywords=[]))], decorator_list=[], type_params=[]), FunctionDef(name='GetFB', args=arguments(posonlyargs=[], args=[arg(arg='self')], kwonlyargs=[], kw_defaults=[], defaults=[]), body=[Return(value=Call(func=Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=Load()), args=[Attribute(value=Name(id='self', ctx=Load()), attr='fb', ctx=Load()), Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load())], keywords=[]))], decorator_list=[], returns=BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=Load()), op=BitOr(), right=Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load())), type_params=[]), FunctionDef(name='__del__', args=arguments(posonlyargs=[], args=[arg(arg='self')], kwonlyargs=[], kw_defaults=[], defaults=[]), body=[Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Constant(value='OOPTest2 __del__')], keywords=[])), Expr(value=Call(func=Name(id='free', ctx=Load()), args=[Attribute(value=Name(id='self', ctx=Load()), attr='fb', ctx=Load())], keywords=[]))], decorator_list=[], type_params=[])], decorator_list=[Attribute(value=Name(id='t', ctx=Load()), attr='Object', ctx=Load())], type_params=[]), ClassDef(name='OOPTest', bases=[], keywords=[], body=[AnnAssign(target=Name(id='a', ctx=Store()), annotation=Name(id='UINT', ctx=Load()), simple=1), AnnAssign(target=Name(id='b', ctx=Store()), annotation=Name(id='UINT', ctx=Load()), value=Constant(value=12345), simple=1), AnnAssign(target=Name(id='c', ctx=Store()), annotation=Name(id='UINT', ctx=Load()), simple=1), AnnAssign(target=Name(id='oop2', ctx=Store()), annotation=BinOp(left=Name(id='OOPTest2', ctx=Load()), op=BitOr(), right=Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load())), simple=1), FunctionDef(name='__init__', args=arguments(posonlyargs=[], args=[arg(arg='self')], kwonlyargs=[], kw_defaults=[], defaults=[]), body=[Assign(targets=[Attribute(value=Name(id='self', ctx=Load()), attr='a', ctx=Store())], value=Constant(value=451)), Assign(targets=[Attribute(value=Name(id='self', ctx=Load()), attr='oop2', ctx=Store())], value=Call(func=Attribute(value=Name(id='c', ctx=Load()), attr='Addr', ctx=Load()), args=[Call(func=Name(id='OOPTest2', ctx=Load()), args=[], keywords=[])], keywords=[])), Assign(targets=[Subscript(value=Call(func=Attribute(value=Attribute(value=Name(id='self', ctx=Load()), attr='oop2', ctx=Load()), attr='GetFB', ctx=Load()), args=[], keywords=[]), slice=Constant(value=0), ctx=Store())], value=Constant(value='1')), Assign(targets=[Name(id='cp', ctx=Store())], value=Attribute(value=Attribute(value=Name(id='self', ctx=Load()), attr='oop2', ctx=Load()), attr='fb', ctx=Load())), Assign(targets=[Subscript(value=Name(id='cp', ctx=Load()), slice=Constant(value=1), ctx=Store())], value=Constant(value='4')), Assign(targets=[Subscript(value=Name(id='cp', ctx=Load()), slice=Constant(value=2), ctx=Store())], value=Constant(value='5')), Assign(targets=[Subscript(value=Name(id='cp', ctx=Load()), slice=Constant(value=3), ctx=Store())], value=Constant(value='6')), Assign(targets=[Subscript(value=Name(id='cp', ctx=Load()), slice=Constant(value=4), ctx=Store())], value=Constant(value='7')), Assign(targets=[Subscript(value=Name(id='cp', ctx=Load()), slice=Constant(value=5), ctx=Store())], value=Constant(value='8')), Assign(targets=[Subscript(value=Name(id='cp', ctx=Load()), slice=Constant(value=6), ctx=Store())], value=Constant(value='9')), Assign(targets=[Subscript(value=Name(id='cp', ctx=Load()), slice=Constant(value=7), ctx=Store())], value=Constant(value='0')), Assign(targets=[Subscript(value=Name(id='cp', ctx=Load()), slice=Constant(value=8), ctx=Store())], value=Constant(value='9')), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Call(func=Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=Load()), args=[Subscript(value=Name(id='cp', ctx=Load()), slice=Constant(value=0), ctx=Load()), Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load())], keywords=[])], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Constant(value='长度:'), Call(func=Attribute(value=Call(func=Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=Load()), args=[Name(id='cp', ctx=Load()), Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load())], keywords=[]), attr='__sizeof__', ctx=Load()), args=[], keywords=[])], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Constant(value='cp[0]:'), Subscript(value=Name(id='cp', ctx=Load()), slice=Constant(value=0), ctx=Load())], keywords=[])), AugAssign(target=Name(id='cp', ctx=Store()), op=Add(), value=Constant(value=1)), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Constant(value='cp[0]:'), Subscript(value=Name(id='cp', ctx=Load()), slice=Constant(value=0), ctx=Load())], keywords=[])), AugAssign(target=Name(id='cp', ctx=Store()), op=Add(), value=Constant(value=1)), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Constant(value='self.oop2.GetFB()[0]:'), Call(func=Name(id='int', ctx=Load()), args=[Subscript(value=Name(id='cp', ctx=Load()), slice=Constant(value=0), ctx=Load())], keywords=[])], keywords=[])), AugAssign(target=Name(id='cp', ctx=Store()), op=Sub(), value=Constant(value=2)), Assign(targets=[Name(id='lambda_a', ctx=Store())], value=Lambda(args=arguments(posonlyargs=[], args=[], kwonlyargs=[], kw_defaults=[], defaults=[]), body=Constant(value=1))), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Subscript(value=Name(id='cp', ctx=Load()), slice=Constant(value=0), ctx=Load()), Call(func=Name(id='lambda_a', ctx=Load()), args=[], keywords=[])], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Call(func=Name(id='type', ctx=Load()), args=[Name(id='cp', ctx=Load())], keywords=[])], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Call(func=Name(id='dir', ctx=Load()), args=[Name(id='OOPTest2', ctx=Load())], keywords=[])], keywords=[])), AnnAssign(target=Name(id='vkt', ctx=Store()), annotation=BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=Load()), op=BitOr(), right=Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load())), value=Call(func=Name(id='malloc', ctx=Load()), args=[Constant(value=1024)], keywords=[]), simple=1), Expr(value=Call(func=Attribute(value=Name(id='c', ctx=Load()), attr='Set', ctx=Load()), args=[Call(func=Attribute(value=Name(id='c', ctx=Load()), attr='Cast', ctx=Load()), args=[Subscript(value=Name(id='vkt', ctx=Load()), slice=Constant(value=0), ctx=Load())], keywords=[]), Constant(value=8080)], keywords=[])), Assign(targets=[Subscript(value=Name(id='vkt', ctx=Load()), slice=Constant(value=0), ctx=Store())], value=Constant(value='2')), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Subscript(value=Call(func=Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=Load()), args=[Subscript(value=Name(id='vkt', ctx=Load()), slice=Constant(value=0), ctx=Load()), Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load())], keywords=[]), slice=Constant(value=0), ctx=Load())], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Call(func=Name(id='type', ctx=Load()), args=[Subscript(value=Name(id='vkt', ctx=Load()), slice=Constant(value=0), ctx=Load())], keywords=[])], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Call(func=Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=Load()), args=[Call(func=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), args=[Constant(value='Hello')], keywords=[]), Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load())], keywords=[])], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Call(func=Name(id='str', ctx=Load()), args=[Call(func=Attribute(value=Name(id='c', ctx=Load()), attr='Addr', ctx=Load()), args=[Constant(value='你好')], keywords=[])], keywords=[])], keywords=[])), Expr(value=Call(func=Name(id='free', ctx=Load()), args=[Name(id='vkt', ctx=Load())], keywords=[])), AnnAssign(target=Name(id='vkt', ctx=Store()), annotation=BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=Load()), op=BitOr(), right=Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load())), value=Call(func=Name(id='malloc', ctx=Load()), args=[Constant(value=1024)], keywords=[]), simple=1), AnnAssign(target=Name(id='vkt2', ctx=Store()), annotation=BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=Load()), op=BitOr(), right=Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load())), value=Call(func=Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=Load()), args=[Name(id='vkt', ctx=Load()), Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load())], keywords=[]), simple=1), Assign(targets=[Subscript(value=Name(id='vkt2', ctx=Load()), slice=Constant(value=0), ctx=Store())], value=Constant(value='1')), Assign(targets=[Subscript(value=Name(id='vkt2', ctx=Load()), slice=Constant(value=100), ctx=Store())], value=Constant(value='1')), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Constant(value='首个参数:'), Subscript(value=Name(id='vkt2', ctx=Load()), slice=Constant(value=0), ctx=Load())], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Constant(value='第100参数:'), Subscript(value=Name(id='vkt2', ctx=Load()), slice=Constant(value=100), ctx=Load())], keywords=[])), Expr(value=Call(func=Name(id='free', ctx=Load()), args=[Name(id='vkt', ctx=Load())], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Constant(value='HEX'), Call(func=Name(id='str_to_hex', ctx=Load()), args=[Constant(value='ABCDEFHIJKLMN')], keywords=[])], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Constant(value='HEX'), Call(func=Name(id='str_to_hex', ctx=Load()), args=[Constant(value='1')], keywords=[])], keywords=[])), Delete(targets=[Attribute(value=Name(id='self', ctx=Load()), attr='oop2', ctx=Del())])], decorator_list=[], type_params=[])], decorator_list=[Attribute(value=Name(id='t', ctx=Load()), attr='Object', ctx=Load())], type_params=[]), FunctionDef(name='str_to_hex', args=arguments(posonlyargs=[], args=[arg(arg='s', annotation=Name(id='str', ctx=Load()))], kwonlyargs=[], kw_defaults=[], defaults=[]), body=[AnnAssign(target=Name(id='buf', ctx=Store()), annotation=Name(id='str', ctx=Load()), value=Call(func=Name(id='malloc', ctx=Load()), args=[Constant(value=1024)], keywords=[]), simple=1), AnnAssign(target=Name(id='out', ctx=Store()), annotation=Name(id='str', ctx=Load()), value=Name(id='buf', ctx=Load()), simple=1), AnnAssign(target=Name(id='hex', ctx=Store()), annotation=Subscript(value=Name(id='list', ctx=Load()), slice=Tuple(elts=[Name(id='str', ctx=Load()), Constant(value=None)], ctx=Load()), ctx=Load()), value=Constant(value='0123456789ABCDEF'), simple=1), While(test=Compare(left=Call(func=Attribute(value=Name(id='c', ctx=Load()), attr='Cast', ctx=Load()), args=[Name(id='s', ctx=Load())], keywords=[]), ops=[NotEq()], comparators=[Constant(value=0)]), body=[AnnAssign(target=Name(id='cr', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CUnsignedChar', ctx=Load()), value=Call(func=Attribute(value=Name(id='c', ctx=Load()), attr='Cast', ctx=Load()), args=[Name(id='s', ctx=Load())], keywords=[]), simple=1), Expr(value=Call(func=Attribute(value=Name(id='c', ctx=Load()), attr='Set', ctx=Load()), args=[Call(func=Attribute(value=Name(id='c', ctx=Load()), attr='Cast', ctx=Load()), args=[Name(id='out', ctx=Load())], keywords=[]), Subscript(value=Name(id='hex', ctx=Load()), slice=BinOp(left=BinOp(left=Name(id='cr', ctx=Load()), op=RShift(), right=Constant(value=4)), op=BitAnd(), right=Constant(value=15)), ctx=Load())], keywords=[])), AugAssign(target=Name(id='out', ctx=Store()), op=Add(), value=Constant(value=1)), Expr(value=Call(func=Attribute(value=Name(id='c', ctx=Load()), attr='Set', ctx=Load()), args=[Call(func=Attribute(value=Name(id='c', ctx=Load()), attr='Cast', ctx=Load()), args=[Name(id='out', ctx=Load())], keywords=[]), Subscript(value=Name(id='hex', ctx=Load()), slice=BinOp(left=Name(id='cr', ctx=Load()), op=BitAnd(), right=Constant(value=15)), ctx=Load())], keywords=[])), AugAssign(target=Name(id='out', ctx=Store()), op=Add(), value=Constant(value=1)), AugAssign(target=Name(id='s', ctx=Store()), op=Add(), value=Constant(value=1))], orelse=[]), Expr(value=Call(func=Attribute(value=Name(id='c', ctx=Load()), attr='Set', ctx=Load()), args=[Call(func=Attribute(value=Name(id='c', ctx=Load()), attr='Cast', ctx=Load()), args=[Name(id='out', ctx=Load())], keywords=[]), Constant(value=0)], keywords=[])), Return(value=Name(id='buf', ctx=Load()))], decorator_list=[], returns=Name(id='str', ctx=Load()), type_params=[]), FunctionDef(name='int_to_hex', args=arguments(posonlyargs=[], args=[arg(arg='num', annotation=Name(id='int', ctx=Load()))], kwonlyargs=[], kw_defaults=[], defaults=[]), body=[Assign(targets=[Name(id='buf', ctx=Store())], value=Call(func=Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=Load()), args=[Call(func=Name(id='malloc', ctx=Load()), args=[Constant(value=128)], keywords=[]), Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load())], keywords=[])), If(test=UnaryOp(op=Not(), operand=Name(id='buf', ctx=Load())), body=[Return(value=Constant(value=None))], orelse=[]), AnnAssign(target=Name(id='hex_chars', ctx=Store()), annotation=Subscript(value=Name(id='list', ctx=Load()), slice=Tuple(elts=[Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=Load()), Constant(value=None)], ctx=Load()), ctx=Load()), value=Constant(value='0123456789ABCDEF'), simple=1), Assign(targets=[Name(id='i', ctx=Store())], value=Constant(value=0)), Assign(targets=[Subscript(value=Name(id='buf', ctx=Load()), slice=Name(id='i', ctx=Load()), ctx=Store())], value=Constant(value='0')), Assign(targets=[Subscript(value=Name(id='buf', ctx=Load()), slice=BinOp(left=Name(id='i', ctx=Load()), op=Add(), right=Constant(value=1)), ctx=Store())], value=Constant(value='x')), AugAssign(target=Name(id='i', ctx=Store()), op=Add(), value=Constant(value=2)), If(test=Compare(left=Name(id='num', ctx=Load()), ops=[Eq()], comparators=[Constant(value=0)]), body=[Assign(targets=[Subscript(value=Name(id='buf', ctx=Load()), slice=Name(id='i', ctx=Load()), ctx=Store())], value=Constant(value='0')), AugAssign(target=Name(id='i', ctx=Store()), op=Add(), value=Constant(value=1)), Assign(targets=[Subscript(value=Name(id='buf', ctx=Load()), slice=Name(id='i', ctx=Load()), ctx=Store())], value=Constant(value='0')), AugAssign(target=Name(id='i', ctx=Store()), op=Add(), value=Constant(value=1)), Assign(targets=[Subscript(value=Name(id='buf', ctx=Load()), slice=Name(id='i', ctx=Load()), ctx=Store())], value=Constant(value='\x00')), Return(value=Name(id='buf', ctx=Load()))], orelse=[]), AnnAssign(target=Name(id='temp', ctx=Store()), annotation=Subscript(value=Name(id='list', ctx=Load()), slice=Tuple(elts=[Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=Load()), Constant(value=32)], ctx=Load()), ctx=Load()), simple=1), Assign(targets=[Name(id='temp_idx', ctx=Store())], value=Constant(value=0)), AnnAssign(target=Name(id='n', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CUnsignedInt', ctx=Load()), value=Call(func=Attribute(value=Name(id='t', ctx=Load()), attr='CUnsignedInt', ctx=Load()), args=[Name(id='num', ctx=Load())], keywords=[]), simple=1), While(test=Compare(left=Name(id='n', ctx=Load()), ops=[Gt()], comparators=[Constant(value=0)]), body=[AnnAssign(target=Name(id='rem', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), value=BinOp(left=Name(id='n', ctx=Load()), op=BitAnd(), right=Constant(value=15)), simple=1), Assign(targets=[Subscript(value=Name(id='temp', ctx=Load()), slice=Name(id='temp_idx', ctx=Load()), ctx=Store())], value=Subscript(value=Name(id='hex_chars', ctx=Load()), slice=Name(id='rem', ctx=Load()), ctx=Load())), AugAssign(target=Name(id='temp_idx', ctx=Store()), op=Add(), value=Constant(value=1)), Assign(targets=[Name(id='n', ctx=Store())], value=BinOp(left=Name(id='n', ctx=Load()), op=RShift(), right=Constant(value=4)))], orelse=[]), While(test=Compare(left=Name(id='temp_idx', ctx=Load()), ops=[Gt()], comparators=[Constant(value=0)]), body=[AugAssign(target=Name(id='temp_idx', ctx=Store()), op=Sub(), value=Constant(value=1)), Assign(targets=[Subscript(value=Name(id='buf', ctx=Load()), slice=Name(id='i', ctx=Load()), ctx=Store())], value=Subscript(value=Name(id='temp', ctx=Load()), slice=Name(id='temp_idx', ctx=Load()), ctx=Load())), AugAssign(target=Name(id='i', ctx=Store()), op=Add(), value=Constant(value=1))], orelse=[]), Assign(targets=[Subscript(value=Name(id='buf', ctx=Load()), slice=Name(id='i', ctx=Load()), ctx=Store())], value=Constant(value='\x00')), Return(value=Name(id='buf', ctx=Load()))], decorator_list=[], returns=Name(id='str', ctx=Load()), type_params=[]), FunctionDef(name='int_to_str', args=arguments(posonlyargs=[], args=[arg(arg='num', annotation=Name(id='int', ctx=Load()))], kwonlyargs=[], kw_defaults=[], defaults=[]), body=[AnnAssign(target=Name(id='buf', ctx=Store()), annotation=BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=Load()), op=BitOr(), right=Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load())), value=Call(func=Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=Load()), args=[Call(func=Name(id='malloc', ctx=Load()), args=[Constant(value=128)], keywords=[]), Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load())], keywords=[]), simple=1), If(test=UnaryOp(op=Not(), operand=Name(id='buf', ctx=Load())), body=[Return(value=Constant(value=None))], orelse=[]), Assign(targets=[Name(id='is_negative', ctx=Store())], value=Constant(value=0)), Assign(targets=[Name(id='i', ctx=Store())], value=Constant(value=0)), If(test=Compare(left=Name(id='num', ctx=Load()), ops=[Eq()], comparators=[Constant(value=0)]), body=[Assign(targets=[Subscript(value=Name(id='buf', ctx=Load()), slice=Name(id='i', ctx=Load()), ctx=Store())], value=Constant(value='0')), AugAssign(target=Name(id='i', ctx=Store()), op=Add(), value=Constant(value=1)), Assign(targets=[Subscript(value=Name(id='buf', ctx=Load()), slice=Name(id='i', ctx=Load()), ctx=Store())], value=Constant(value='\x00')), Return(value=Name(id='buf', ctx=Load()))], orelse=[]), If(test=Compare(left=Name(id='num', ctx=Load()), ops=[Lt()], comparators=[Constant(value=0)]), body=[Assign(targets=[Name(id='is_negative', ctx=Store())], value=Constant(value=1)), Assign(targets=[Name(id='num', ctx=Store())], value=UnaryOp(op=USub(), operand=Name(id='num', ctx=Load())))], orelse=[]), While(test=Compare(left=Name(id='num', ctx=Load()), ops=[Gt()], comparators=[Constant(value=0)]), body=[Assign(targets=[Name(id='rem', ctx=Store())], value=BinOp(left=Name(id='num', ctx=Load()), op=Mod(), right=Constant(value=10))), Assign(targets=[Subscript(value=Name(id='buf', ctx=Load()), slice=Name(id='i', ctx=Load()), ctx=Store())], value=BinOp(left=Constant(value='0'), op=Add(), right=Name(id='rem', ctx=Load()))), AugAssign(target=Name(id='i', ctx=Store()), op=Add(), value=Constant(value=1)), Assign(targets=[Name(id='num', ctx=Store())], value=BinOp(left=Name(id='num', ctx=Load()), op=Div(), right=Constant(value=10)))], orelse=[]), If(test=Name(id='is_negative', ctx=Load()), body=[Assign(targets=[Subscript(value=Name(id='buf', ctx=Load()), slice=Name(id='i', ctx=Load()), ctx=Store())], value=Constant(value='-')), AugAssign(target=Name(id='i', ctx=Store()), op=Add(), value=Constant(value=1))], orelse=[]), Assign(targets=[Subscript(value=Name(id='buf', ctx=Load()), slice=Name(id='i', ctx=Load()), ctx=Store())], value=Constant(value='\x00')), Assign(targets=[Name(id='start', ctx=Store())], value=Constant(value=0)), Assign(targets=[Name(id='end', ctx=Store())], value=BinOp(left=Name(id='i', ctx=Load()), op=Sub(), right=Constant(value=1))), While(test=Compare(left=Name(id='start', ctx=Load()), ops=[Lt()], comparators=[Name(id='end', ctx=Load())]), body=[AnnAssign(target=Name(id='tr', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=Load()), value=Subscript(value=Name(id='buf', ctx=Load()), slice=Name(id='start', ctx=Load()), ctx=Load()), simple=1), Assign(targets=[Subscript(value=Name(id='buf', ctx=Load()), slice=Name(id='start', ctx=Load()), ctx=Store())], value=Subscript(value=Name(id='buf', ctx=Load()), slice=Name(id='end', ctx=Load()), ctx=Load())), Assign(targets=[Subscript(value=Name(id='buf', ctx=Load()), slice=Name(id='end', ctx=Load()), ctx=Store())], value=Name(id='tr', ctx=Load())), AugAssign(target=Name(id='start', ctx=Store()), op=Add(), value=Constant(value=1)), AugAssign(target=Name(id='end', ctx=Store()), op=Sub(), value=Constant(value=1))], orelse=[]), Return(value=Name(id='buf', ctx=Load()))], decorator_list=[], returns=Name(id='str', ctx=Load()), type_params=[]), ClassDef(name='Item', bases=[], keywords=[], body=[AnnAssign(target=Name(id='data', ctx=Store()), annotation=BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=Load()), op=BitOr(), right=Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load())), simple=1), AnnAssign(target=Name(id='size', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CSizeT', ctx=Load()), simple=1)], decorator_list=[], type_params=[]), ClassDef(name='List', bases=[], keywords=[], body=[AnnAssign(target=Name(id='items', ctx=Store()), annotation=BinOp(left=Name(id='Item', ctx=Load()), op=BitOr(), right=Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load())), simple=1), AnnAssign(target=Name(id='count', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CSizeT', ctx=Load()), value=Constant(value=0), simple=1), AnnAssign(target=Name(id='capacity', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CSizeT', ctx=Load()), value=Constant(value=4), simple=1), FunctionDef(name='__init__', args=arguments(posonlyargs=[], args=[arg(arg='self')], kwonlyargs=[], kw_defaults=[], defaults=[]), body=[Assign(targets=[Attribute(value=Name(id='self', ctx=Load()), attr='count', ctx=Store())], value=Constant(value=0)), Assign(targets=[Attribute(value=Name(id='self', ctx=Load()), attr='capacity', ctx=Store())], value=Constant(value=4)), Assign(targets=[Attribute(value=Name(id='self', ctx=Load()), attr='items', ctx=Store())], value=Call(func=Name(id='malloc', ctx=Load()), args=[BinOp(left=Attribute(value=Name(id='self', ctx=Load()), attr='capacity', ctx=Load()), op=Mult(), right=Call(func=Attribute(value=Name(id='Item', ctx=Load()), attr='__sizeof__', ctx=Load()), args=[], keywords=[]))], keywords=[]))], decorator_list=[], type_params=[]), FunctionDef(name='__grow', args=arguments(posonlyargs=[], args=[arg(arg='self')], kwonlyargs=[], kw_defaults=[], defaults=[]), body=[If(test=Compare(left=Attribute(value=Name(id='self', ctx=Load()), attr='count', ctx=Load()), ops=[GtE()], comparators=[Attribute(value=Name(id='self', ctx=Load()), attr='capacity', ctx=Load())]), body=[AugAssign(target=Attribute(value=Name(id='self', ctx=Load()), attr='capacity', ctx=Store()), op=Mult(), value=Constant(value=2)), Assign(targets=[Attribute(value=Name(id='self', ctx=Load()), attr='items', ctx=Store())], value=Call(func=Name(id='realloc', ctx=Load()), args=[Attribute(value=Name(id='self', ctx=Load()), attr='items', ctx=Load()), BinOp(left=Attribute(value=Name(id='self', ctx=Load()), attr='capacity', ctx=Load()), op=Mult(), right=Call(func=Attribute(value=Name(id='Item', ctx=Load()), attr='__sizeof__', ctx=Load()), args=[], keywords=[]))], keywords=[]))], orelse=[])], decorator_list=[], type_params=[]), FunctionDef(name='append', args=arguments(posonlyargs=[], args=[arg(arg='self'), arg(arg='data', annotation=BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=Load()), op=BitOr(), right=Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load()))), arg(arg='size', annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CSizeT', ctx=Load()))], kwonlyargs=[], kw_defaults=[], defaults=[]), body=[Expr(value=Call(func=Attribute(value=Name(id='self', ctx=Load()), attr='__grow', ctx=Load()), args=[], keywords=[])), AnnAssign(target=Name(id='item', ctx=Store()), annotation=BinOp(left=Name(id='Item', ctx=Load()), op=BitOr(), right=Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load())), value=Subscript(value=Attribute(value=Name(id='self', ctx=Load()), attr='items', ctx=Load()), slice=Attribute(value=Name(id='self', ctx=Load()), attr='count', ctx=Load()), ctx=Load()), simple=1), Assign(targets=[Attribute(value=Name(id='item', ctx=Load()), attr='size', ctx=Store())], value=Name(id='size', ctx=Load())), Assign(targets=[Attribute(value=Name(id='item', ctx=Load()), attr='data', ctx=Store())], value=Call(func=Name(id='malloc', ctx=Load()), args=[BinOp(left=Name(id='size', ctx=Load()), op=Add(), right=Constant(value=1))], keywords=[])), Expr(value=Call(func=Name(id='memcpy', ctx=Load()), args=[Attribute(value=Name(id='item', ctx=Load()), attr='data', ctx=Load()), Name(id='data', ctx=Load()), Name(id='size', ctx=Load())], keywords=[])), Expr(value=Call(func=Attribute(value=Name(id='c', ctx=Load()), attr='Set', ctx=Load()), args=[Call(func=Attribute(value=Name(id='t', ctx=Load()), attr='CUnsignedChar', ctx=Load()), args=[BinOp(left=Attribute(value=Name(id='item', ctx=Load()), attr='data', ctx=Load()), op=Add(), right=Name(id='size', ctx=Load())), Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load())], keywords=[]), Constant(value='\x00')], keywords=[])), AugAssign(target=Attribute(value=Name(id='self', ctx=Load()), attr='count', ctx=Store()), op=Add(), value=Constant(value=1))], decorator_list=[], type_params=[]), FunctionDef(name='get', args=arguments(posonlyargs=[], args=[arg(arg='self'), arg(arg='index', annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CSizeT', ctx=Load()))], kwonlyargs=[], kw_defaults=[], defaults=[]), body=[If(test=Compare(left=Name(id='index', ctx=Load()), ops=[GtE()], comparators=[Attribute(value=Name(id='self', ctx=Load()), attr='count', ctx=Load())]), body=[Return(value=Constant(value=None))], orelse=[]), Return(value=Attribute(value=Subscript(value=Attribute(value=Name(id='self', ctx=Load()), attr='items', ctx=Load()), slice=Name(id='index', ctx=Load()), ctx=Load()), attr='data', ctx=Load()))], decorator_list=[], returns=BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='CInt8T', ctx=Load()), op=BitOr(), right=Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load())), type_params=[]), FunctionDef(name='__getitem__', args=arguments(posonlyargs=[], args=[arg(arg='self'), arg(arg='index', annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CSizeT', ctx=Load()))], kwonlyargs=[], kw_defaults=[], defaults=[]), body=[Return(value=Call(func=Attribute(value=Name(id='self', ctx=Load()), attr='get', ctx=Load()), args=[Name(id='index', ctx=Load())], keywords=[]))], decorator_list=[], returns=BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='CInt8T', ctx=Load()), op=BitOr(), right=Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load())), type_params=[]), FunctionDef(name='free', args=arguments(posonlyargs=[], args=[arg(arg='self')], kwonlyargs=[], kw_defaults=[], defaults=[]), body=[AnnAssign(target=Name(id='i', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CSizeT', ctx=Load()), value=Constant(value=0), simple=1), For(target=Name(id='i', ctx=Store()), iter=Call(func=Name(id='range', ctx=Load()), args=[Attribute(value=Name(id='self', ctx=Load()), attr='count', ctx=Load())], keywords=[]), body=[If(test=Compare(left=Attribute(value=Subscript(value=Attribute(value=Name(id='self', ctx=Load()), attr='items', ctx=Load()), slice=Name(id='i', ctx=Load()), ctx=Load()), attr='data', ctx=Load()), ops=[NotEq()], comparators=[Constant(value=0)]), body=[Expr(value=Call(func=Name(id='free', ctx=Load()), args=[Attribute(value=Subscript(value=Attribute(value=Name(id='self', ctx=Load()), attr='items', ctx=Load()), slice=Name(id='i', ctx=Load()), ctx=Load()), attr='data', ctx=Load())], keywords=[]))], orelse=[])], orelse=[]), Expr(value=Call(func=Name(id='free', ctx=Load()), args=[Attribute(value=Name(id='self', ctx=Load()), attr='items', ctx=Load())], keywords=[]))], decorator_list=[], type_params=[])], decorator_list=[], type_params=[]), AnnAssign(target=Name(id='DEFINE_T', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CDefine', ctx=Load()), value=Constant(value=2423432423), simple=1), ClassDef(name='EnumTest', bases=[Attribute(value=Name(id='t', ctx=Load()), attr='CEnum', ctx=Load())], keywords=[], body=[AnnAssign(target=Name(id='A', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=Load()), simple=1), AnnAssign(target=Name(id='B', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=Load()), simple=1), AnnAssign(target=Name(id='C', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=Load()), simple=1), AnnAssign(target=Name(id='Len', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=Load()), simple=1)], decorator_list=[], type_params=[]), FunctionDef(name='main', args=arguments(posonlyargs=[], args=[], kwonlyargs=[], kw_defaults=[], defaults=[]), body=[Expr(value=Call(func=Attribute(value=Attribute(value=Name(id='w32', ctx=Load()), attr='win32console', ctx=Load()), attr='SetConsoleOutputCP', ctx=Load()), args=[Constant(value=65001)], keywords=[])), Expr(value=Call(func=Attribute(value=Attribute(value=Name(id='w32', ctx=Load()), attr='win32console', ctx=Load()), attr='SetConsoleCP', ctx=Load()), args=[Constant(value=65001)], keywords=[])), Assign(targets=[Name(id='d', ctx=Store())], value=Call(func=Name(id='OOPTest', ctx=Load()), args=[], keywords=[])), Assign(targets=[Name(id='l', ctx=Store())], value=Call(func=Name(id='List', ctx=Load()), args=[], keywords=[])), Assign(targets=[Name(id='nihao', ctx=Store())], value=Constant(value='你好!世界,这是一个可变列表')), Expr(value=Call(func=Attribute(value=Name(id='l', ctx=Load()), attr='append', ctx=Load()), args=[Call(func=Attribute(value=Name(id='c', ctx=Load()), attr='Addr', ctx=Load()), args=[Constant(value=114514)], keywords=[]), Call(func=Attribute(value=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), attr='__sizeof__', ctx=Load()), args=[], keywords=[])], keywords=[])), Expr(value=Call(func=Attribute(value=Name(id='l', ctx=Load()), attr='append', ctx=Load()), args=[Name(id='nihao', ctx=Load()), Call(func=Name(id='len', ctx=Load()), args=[Name(id='nihao', ctx=Load())], keywords=[])], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Constant(value='列表取值0:'), Call(func=Attribute(value=Name(id='c', ctx=Load()), attr='Cast', ctx=Load()), args=[Call(func=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), args=[Subscript(value=Name(id='l', ctx=Load()), slice=Constant(value=0), ctx=Load()), Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load())], keywords=[])], keywords=[])], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Constant(value='列表取值1:'), Call(func=Attribute(value=Name(id='l', ctx=Load()), attr='get', ctx=Load()), args=[Constant(value=1)], keywords=[])], keywords=[])), Expr(value=Call(func=Attribute(value=Name(id='l', ctx=Load()), attr='free', ctx=Load()), args=[], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Constant(value='结束')], keywords=[])), AnnAssign(target=Name(id='E', ctx=Store()), annotation=Name(id='EnumTest', ctx=Load()), value=Attribute(value=Name(id='EnumTest', ctx=Load()), attr='B', ctx=Load()), simple=1), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Name(id='E', ctx=Load())], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Attribute(value=Name(id='EnumTest', ctx=Load()), attr='Len', ctx=Load())], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Call(func=Name(id='EnumTest', ctx=Load()), args=[Constant(value=1)], keywords=[])], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Call(func=Name(id='type', ctx=Load()), args=[Attribute(value=Name(id='EnumTest', ctx=Load()), attr='B', ctx=Load())], keywords=[])], keywords=[])), Assign(targets=[Name(id='u', ctx=Store())], value=Call(func=Name(id='Union', ctx=Load()), args=[], keywords=[])), Assign(targets=[Attribute(value=Attribute(value=Name(id='u', ctx=Load()), attr='A', ctx=Load()), attr='a', ctx=Store())], value=Constant(value=114514)), Assign(targets=[Attribute(value=Attribute(value=Name(id='u', ctx=Load()), attr='A', ctx=Load()), attr='b', ctx=Store())], value=Constant(value=222222)), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Constant(value='u.A.a'), Attribute(value=Attribute(value=Name(id='u', ctx=Load()), attr='A', ctx=Load()), attr='a', ctx=Load())], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Constant(value='u.A.b'), Attribute(value=Attribute(value=Name(id='u', ctx=Load()), attr='A', ctx=Load()), attr='b', ctx=Load())], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Constant(value='u.A.c'), Attribute(value=Attribute(value=Name(id='u', ctx=Load()), attr='B', ctx=Load()), attr='c', ctx=Load())], keywords=[])), Assign(targets=[Name(id='wb', ctx=Store())], value=Call(func=Name(id='WBIT', ctx=Load()), args=[], keywords=[])), Assign(targets=[Attribute(value=Name(id='wb', ctx=Load()), attr='a', ctx=Store())], value=Constant(value=1)), Assign(targets=[Attribute(value=Name(id='wb', ctx=Load()), attr='b', ctx=Store())], value=Constant(value=1)), Assign(targets=[Attribute(value=Name(id='wb', ctx=Load()), attr='c', ctx=Store())], value=Constant(value=1)), Assign(targets=[Attribute(value=Name(id='wb', ctx=Load()), attr='d', ctx=Store())], value=Constant(value=12)), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Attribute(value=Name(id='wb', ctx=Load()), attr='a', ctx=Load())], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Attribute(value=Name(id='wb', ctx=Load()), attr='b', ctx=Load())], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Attribute(value=Name(id='wb', ctx=Load()), attr='c', ctx=Load())], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Attribute(value=Name(id='wb', ctx=Load()), attr='d', ctx=Load())], keywords=[])), Assign(targets=[Attribute(value=Name(id='wb', ctx=Load()), attr='a', ctx=Store())], value=Constant(value=2)), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Attribute(value=Name(id='wb', ctx=Load()), attr='a', ctx=Load())], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Call(func=Attribute(value=Name(id='wb', ctx=Load()), attr='__sizeof__', ctx=Load()), args=[], keywords=[])], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Call(func=Name(id='type', ctx=Load()), args=[Name(id='wb', ctx=Load())], keywords=[])], keywords=[])), Assign(targets=[Name(id='ble', ctx=Store())], value=Call(func=Name(id='BLE', ctx=Load()), args=[], keywords=[])), Assign(targets=[Attribute(value=Name(id='ble', ctx=Load()), attr='a', ctx=Store())], value=Constant(value=1131796)), Assign(targets=[Attribute(value=Name(id='ble', ctx=Load()), attr='b', ctx=Store())], value=Constant(value=1131796)), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Attribute(value=Name(id='ble', ctx=Load()), attr='a', ctx=Load())], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Attribute(value=Name(id='ble', ctx=Load()), attr='b', ctx=Load())], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Constant(value='a:'), Call(func=Name(id='int_to_str', ctx=Load()), args=[Attribute(value=Name(id='ble', ctx=Load()), attr='a', ctx=Load())], keywords=[])], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Constant(value='a_hex:'), Call(func=Name(id='str_to_hex', ctx=Load()), args=[Call(func=Name(id='int_to_str', ctx=Load()), args=[Attribute(value=Name(id='ble', ctx=Load()), attr='a', ctx=Load())], keywords=[])], keywords=[])], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Call(func=Name(id='int_to_hex', ctx=Load()), args=[Subscript(value=Attribute(value=Name(id='ble', ctx=Load()), attr='a', ctx=Load()), slice=Constant(value=0), ctx=Load())], keywords=[])], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Call(func=Name(id='int_to_hex', ctx=Load()), args=[Subscript(value=Attribute(value=Name(id='ble', ctx=Load()), attr='a', ctx=Load()), slice=Constant(value=1), ctx=Load())], keywords=[])], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Call(func=Name(id='int_to_hex', ctx=Load()), args=[Subscript(value=Attribute(value=Name(id='ble', ctx=Load()), attr='a', ctx=Load()), slice=Constant(value=2), ctx=Load())], keywords=[])], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Call(func=Name(id='int_to_hex', ctx=Load()), args=[Subscript(value=Attribute(value=Name(id='ble', ctx=Load()), attr='a', ctx=Load()), slice=Constant(value=3), ctx=Load())], keywords=[])], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Call(func=Name(id='int_to_hex', ctx=Load()), args=[Subscript(value=Attribute(value=Name(id='ble', ctx=Load()), attr='b', ctx=Load()), slice=Constant(value=0), ctx=Load())], keywords=[])], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Call(func=Name(id='int_to_hex', ctx=Load()), args=[Subscript(value=Attribute(value=Name(id='ble', ctx=Load()), attr='b', ctx=Load()), slice=Constant(value=1), ctx=Load())], keywords=[])], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Call(func=Name(id='int_to_hex', ctx=Load()), args=[Subscript(value=Attribute(value=Name(id='ble', ctx=Load()), attr='b', ctx=Load()), slice=Constant(value=2), ctx=Load())], keywords=[])], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Call(func=Name(id='int_to_hex', ctx=Load()), args=[Subscript(value=Attribute(value=Name(id='ble', ctx=Load()), attr='b', ctx=Load()), slice=Constant(value=3), ctx=Load())], keywords=[])], keywords=[])), Assign(targets=[Name(id='li', ctx=Store())], value=Constant(value=4294967297)), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Name(id='DEFINE_T', ctx=Load())], keywords=[])), If(test=Call(func=Attribute(value=Name(id='c', ctx=Load()), attr='CIf', ctx=Load()), args=[Compare(left=Name(id='DEFINE_T', ctx=Load()), ops=[Eq()], comparators=[Constant(value=2423432423)])], keywords=[]), body=[Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Constant(value='DEFINE_T == 2423432423')], keywords=[]))], orelse=[If(test=Call(func=Attribute(value=Name(id='c', ctx=Load()), attr='CIf', ctx=Load()), args=[Compare(left=Name(id='DEFINE_T', ctx=Load()), ops=[Eq()], comparators=[Constant(value=123)])], keywords=[]), body=[Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Constant(value='DEFINE_T == 123')], keywords=[]))], orelse=[Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Constant(value='DEFINE_T != 2423432423 and DEFINE_T != 123')], keywords=[]))])])], decorator_list=[], returns=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), type_params=[]), ClassDef(name='LIWORK', bases=[], keywords=[], body=[AnnAssign(target=Name(id='a', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CUInt32T', ctx=Load()), simple=1), AnnAssign(target=Name(id='b', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CUInt32T', ctx=Load()), simple=1)], decorator_list=[], type_params=[]), ClassDef(name='Union', bases=[Attribute(value=Name(id='t', ctx=Load()), attr='CUnion', ctx=Load())], keywords=[], body=[ClassDef(name='A', bases=[], keywords=[], body=[AnnAssign(target=Name(id='a', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CInt32T', ctx=Load()), simple=1), AnnAssign(target=Name(id='b', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CInt32T', ctx=Load()), simple=1)], decorator_list=[], type_params=[]), ClassDef(name='B', bases=[], keywords=[], body=[AnnAssign(target=Name(id='c', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CInt16T', ctx=Load()), simple=1), AnnAssign(target=Name(id='d', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CInt64T', ctx=Load()), simple=1)], decorator_list=[], type_params=[])], decorator_list=[], type_params=[]), ClassDef(name='WBIT', bases=[], keywords=[], body=[AnnAssign(target=Name(id='a', ctx=Store()), annotation=BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), op=BitOr(), right=Call(func=Attribute(value=Name(id='t', ctx=Load()), attr='Bit', ctx=Load()), args=[Constant(value=1)], keywords=[])), simple=1), AnnAssign(target=Name(id='b', ctx=Store()), annotation=BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), op=BitOr(), right=Call(func=Attribute(value=Name(id='t', ctx=Load()), attr='Bit', ctx=Load()), args=[Constant(value=1)], keywords=[])), simple=1), AnnAssign(target=Name(id='c', ctx=Store()), annotation=BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), op=BitOr(), right=Call(func=Attribute(value=Name(id='t', ctx=Load()), attr='Bit', ctx=Load()), args=[Constant(value=1)], keywords=[])), simple=1), AnnAssign(target=Name(id='d', ctx=Store()), annotation=BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), op=BitOr(), right=Call(func=Attribute(value=Name(id='t', ctx=Load()), attr='Bit', ctx=Load()), args=[Constant(value=5)], keywords=[])), simple=1)], decorator_list=[], type_params=[]), ClassDef(name='BLE', bases=[], keywords=[], body=[AnnAssign(target=Name(id='a', ctx=Store()), annotation=BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), op=BitOr(), right=Attribute(value=Name(id='t', ctx=Load()), attr='BigEndian', ctx=Load())), simple=1), AnnAssign(target=Name(id='b', ctx=Store()), annotation=BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), op=BitOr(), right=Attribute(value=Name(id='t', ctx=Load()), attr='LittleEndian', ctx=Load())), simple=1)], decorator_list=[], type_params=[])], type_ignores=[]) - -[GetCTypeInfo] Node type: Name, dump: Name(id='UINT', ctx=Load())... -[GetCTypeInfo] Node type: Name, dump: Name(id='UINT', ctx=Load())... -[GetCTypeInfo] Node type: Subscript, dump: Subscript(value=Name(id='list', ctx=Load()), slice=Tuple(elt... -[GetCTypeInfo] Node type: Name, dump: Name(id='Struct1', ctx=Load())... -[GetCTypeInfo] Node type: Name, dump: Name(id='Struct1', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t -[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... -[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='UINT', ctx=Load())... -[GetCTypeInfo] Node type: Name, dump: Name(id='UINT', ctx=Load())... -[GetCTypeInfo] Node type: Name, dump: Name(id='UINT', ctx=Load())... -[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Name(id='OOPTest2', ctx=Load()), op=BitOr(), righ... -[GetCTypeInfo] Node type: Name, dump: Name(id='OOPTest2', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... -[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CSizeT', ctx... -[GetCTypeInfo-Attribute] 查询: 'CSizeT' ModulePath: t -[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Name(id='Item', ctx=Load()), op=BitOr(), right=At... -[GetCTypeInfo] Node type: Name, dump: Name(id='Item', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CSizeT', ctx... -[GetCTypeInfo-Attribute] 查询: 'CSizeT' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CSizeT', ctx... -[GetCTypeInfo-Attribute] 查询: 'CSizeT' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CDefine', ct... -[GetCTypeInfo-Attribute] 查询: 'CDefine' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUInt32T', c... -[GetCTypeInfo-Attribute] 查询: 'CUInt32T' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUInt32T', c... -[GetCTypeInfo-Attribute] 查询: 'CUInt32T' ModulePath: t -[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t -[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t -[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t -[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t -[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='BigEndian', ... -[GetCTypeInfo-Attribute] 查询: 'BigEndian' ModulePath: t -[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='LittleEndian... -[GetCTypeInfo-Attribute] 查询: 'LittleEndian' ModulePath: t -[GetCTypeInfo] Node type: Subscript, dump: Subscript(value=Name(id='list', ctx=Load()), slice=Tuple(elt... -[GetCTypeInfo] Node type: Name, dump: Name(id='Struct1', ctx=Load())... -[GetCTypeInfo] Node type: Name, dump: Name(id='Struct1', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CDefine', ct... -[GetCTypeInfo-Attribute] 查询: 'CDefine' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... -[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... -[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CExtern', ct... -[GetCTypeInfo-Attribute] 查询: 'CExtern' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CExport', ct... -[GetCTypeInfo-Attribute] 查询: 'CExport' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... -[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... -[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CExtern', ct... -[GetCTypeInfo-Attribute] 查询: 'CExtern' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CExport', ct... -[GetCTypeInfo-Attribute] 查询: 'CExport' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CLong', ctx=... -[GetCTypeInfo-Attribute] 查询: 'CLong' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CLong', ctx=... -[GetCTypeInfo-Attribute] 查询: 'CLong' ModulePath: t -[GetCTypeInfo] Node type: Constant, dump: Constant(value=None)... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... -[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUnsignedInt... -[GetCTypeInfo-Attribute] 查询: 'CUnsignedInt' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='UINT', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUnsignedCha... -[GetCTypeInfo-Attribute] 查询: 'CUnsignedChar' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='BYTE', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUInt16T', c... -[GetCTypeInfo-Attribute] 查询: 'CUInt16T' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUInt32T', c... -[GetCTypeInfo-Attribute] 查询: 'CUInt32T' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUInt64T', c... -[GetCTypeInfo-Attribute] 查询: 'CUInt64T' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=... -[GetCTypeInfo-Attribute] 查询: 'CChar' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='str', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... -[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CShort', ctx... -[GetCTypeInfo-Attribute] 查询: 'CShort' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CShort', ctx... -[GetCTypeInfo-Attribute] 查询: 'CShort' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUnsignedSho... -[GetCTypeInfo-Attribute] 查询: 'CUnsignedShort' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUnsignedSho... -[GetCTypeInfo-Attribute] 查询: 'CUnsignedShort' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CLong', ctx=... -[GetCTypeInfo-Attribute] 查询: 'CLong' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CLong', ctx=... -[GetCTypeInfo-Attribute] 查询: 'CLong' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUnsignedLon... -[GetCTypeInfo-Attribute] 查询: 'CUnsignedLong' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CLong', ctx=... -[GetCTypeInfo-Attribute] 查询: 'CLong' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CLong', ctx=... -[GetCTypeInfo-Attribute] 查询: 'CLong' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUnsignedLon... -[GetCTypeInfo-Attribute] 查询: 'CUnsignedLong' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='WORD', ctx=Load())... -[GetCTypeInfo] Node type: Name, dump: Name(id='WORD', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=... -[GetCTypeInfo-Attribute] 查询: 'CChar' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='DWORD', ctx=Load())... -[GetCTypeInfo] Node type: Name, dump: Name(id='DWORD', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUnsignedInt... -[GetCTypeInfo-Attribute] 查询: 'CUnsignedInt' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... -[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CFloat', ctx... -[GetCTypeInfo-Attribute] 查询: 'CFloat' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CDouble', ct... -[GetCTypeInfo-Attribute] 查询: 'CDouble' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CFloat8T', c... -[GetCTypeInfo-Attribute] 查询: 'CFloat8T' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CFloat16T', ... -[GetCTypeInfo-Attribute] 查询: 'CFloat16T' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CFloat32T', ... -[GetCTypeInfo-Attribute] 查询: 'CFloat32T' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CFloat64T', ... -[GetCTypeInfo-Attribute] 查询: 'CFloat64T' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CFloat128T',... -[GetCTypeInfo-Attribute] 查询: 'CFloat128T' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt8T', ctx... -[GetCTypeInfo-Attribute] 查询: 'CInt8T' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt16T', ct... -[GetCTypeInfo-Attribute] 查询: 'CInt16T' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt32T', ct... -[GetCTypeInfo-Attribute] 查询: 'CInt32T' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt64T', ct... -[GetCTypeInfo-Attribute] 查询: 'CInt64T' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUInt8T', ct... -[GetCTypeInfo-Attribute] 查询: 'CUInt8T' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUInt16T', c... -[GetCTypeInfo-Attribute] 查询: 'CUInt16T' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUInt32T', c... -[GetCTypeInfo-Attribute] 查询: 'CUInt32T' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUInt64T', c... -[GetCTypeInfo-Attribute] 查询: 'CUInt64T' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt8T', ctx... -[GetCTypeInfo-Attribute] 查询: 'CInt8T' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt16T', ct... -[GetCTypeInfo-Attribute] 查询: 'CInt16T' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt32T', ct... -[GetCTypeInfo-Attribute] 查询: 'CInt32T' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt64T', ct... -[GetCTypeInfo-Attribute] 查询: 'CInt64T' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUInt8T', ct... -[GetCTypeInfo-Attribute] 查询: 'CUInt8T' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUInt16T', c... -[GetCTypeInfo-Attribute] 查询: 'CUInt16T' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUInt32T', c... -[GetCTypeInfo-Attribute] 查询: 'CUInt32T' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUInt64T', c... -[GetCTypeInfo-Attribute] 查询: 'CUInt64T' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CChar8T', ct... -[GetCTypeInfo-Attribute] 查询: 'CChar8T' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CChar16T', c... -[GetCTypeInfo-Attribute] 查询: 'CChar16T' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CChar32T', c... -[GetCTypeInfo-Attribute] 查询: 'CChar32T' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CChar8T', ct... -[GetCTypeInfo-Attribute] 查询: 'CChar8T' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CChar16T', c... -[GetCTypeInfo-Attribute] 查询: 'CChar16T' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CChar32T', c... -[GetCTypeInfo-Attribute] 查询: 'CChar32T' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CSizeT', ctx... -[GetCTypeInfo-Attribute] 查询: 'CSizeT' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CExport', ct... -[GetCTypeInfo-Attribute] 查询: 'CExport' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... -[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... -[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... -[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CExport', ct... -[GetCTypeInfo-Attribute] 查询: 'CExport' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... -[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... -[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... -[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... -[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CExport', ct... -[GetCTypeInfo-Attribute] 查询: 'CExport' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... -[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... -[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... -[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... -[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... -[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... -[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... -[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='UINT', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... -[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='UINT', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... -[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... -[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='CONSOLE_SCREEN_BUFFER_INFO', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... -[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... -[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... -[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='CONSOLE_CURSOR_INFO', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... -[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='CONSOLE_CURSOR_INFO', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... -[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... -[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='ULONG', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... -[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='ULONG', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... -[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='ULONG', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... -[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CConst', ctx... -[GetCTypeInfo-Attribute] 查询: 'CConst' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='VOIDPTR', ctx=Load())... -[GetCTypeInfo] Node type: Name, dump: Name(id='ULONG', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... -[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CConst', ctx... -[GetCTypeInfo-Attribute] 查询: 'CConst' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='VOIDPTR', ctx=Load())... -[GetCTypeInfo] Node type: Name, dump: Name(id='ULONG', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... -[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='ULONG', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... -[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='ULONG', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... -[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='ULONG', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... -[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... -[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='INPUT_RECORD', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='ULONG', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... -[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='INPUT_RECORD', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='ULONG', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... -[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='ULONG', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... -[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... -[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... -[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='ULONG', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... -[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='ULONG', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... -[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... -[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... -[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... -[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='SMALL_RECT', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... -[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='SMALL_RECT', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='SMALL_RECT', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='CHAR_INFO', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUnsignedCha... -[GetCTypeInfo-Attribute] 查询: 'CUnsignedChar' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... -[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CExtern', ct... -[GetCTypeInfo-Attribute] 查询: 'CExtern' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CExport', ct... -[GetCTypeInfo-Attribute] 查询: 'CExport' ModulePath: t -[GetCTypeInfo] Node type: Name, dump: Name(id='UINT', ctx=Load())... -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=... -[GetCTypeInfo-Attribute] 查询: 'CChar' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=... -[GetCTypeInfo-Attribute] 查询: 'CChar' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t diff --git a/Test/regression_test.py b/Test/regression_test.py new file mode 100644 index 0000000..2f8007e --- /dev/null +++ b/Test/regression_test.py @@ -0,0 +1,334 @@ +#!/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 + +# 测试目录 +TEST_DIR = os.path.dirname(os.path.abspath(__file__)) +# 项目根目录(Projectrans.py 所在位置) +PROJECT_ROOT = os.path.dirname(TEST_DIR) +# Projectrans.py 路径 +PROJECTRANS = os.path.join(PROJECT_ROOT, "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'python -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_NEW_CONSOLE 创建独立控制台窗口运行程序, + 避免某些程序调用 SetConsoleOutputCP(65001) 后在非控制台模式下崩溃。 + 由于新控制台窗口中 stdout 是真正的控制台句柄,无法通过管道捕获输出。 + """ + try: + CREATE_NEW_CONSOLE = 0x00000010 + proc = subprocess.Popen( + [exe_path], + cwd=os.path.dirname(exe_path), + creationflags=CREATE_NEW_CONSOLE, + ) + try: + proc.wait(timeout=RUN_TIMEOUT) + except subprocess.TimeoutExpired: + proc.kill() + proc.wait() + return (-1, "", "超时(强制终止)", True) + + return (proc.returncode, "", "", False) + 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 + + if run_tasks: + # 串行运行,避免并发导致的资源竞争(控制台输出、堆分配器等) + for proj_name, exe_path in run_tasks: + exe_name = os.path.basename(exe_path) + try: + returncode, stdout, stderr, timed_out = run_executable(exe_path) + except Exception as e: + returncode, stdout, stderr, timed_out = -1, "", str(e), False + + 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 + if extract_error_context(stdout, stderr): + project_run_ok = False + break + + 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 or extract_error_context(stdout, stderr): + 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()) diff --git a/TransPyC.py b/TransPyC.py index 4e17cc3..6d17236 100644 --- a/TransPyC.py +++ b/TransPyC.py @@ -1,715 +1,15 @@ -# TransPyC 入口程序 - -import sys -import os -import ast -import json -import struct -# 添加lib目录到Python路径 -sys.path.append(os.path.join(os.path.dirname(__file__), 'lib', 'includes')) -from lib.includes import c -from lib.includes import t -from lib.constants.config import ( - DEFAULT_INPUT_FILE, DEFAULT_OUTPUT_FILE, - DEFAULT_COMPILE_COMMAND, - DEFAULT_COMPILE_FLAGS, ERROR_MESSAGES, - HELP_MESSAGE, DEFAULT_METADATA -) -from lib.utils.helpers import ( - DetectFileType, ExecuteCommand, - AppendFileContent -) -from lib.core.translator import Translator - - -def SerializeSymbolTable(SymbolTable: dict) -> bytes: - """将符号表序列化为二进制格式 - - 格式: - - 4字节: JSON数据长度(小端序) - - N字节: JSON数据(UTF-8编码) - - Args: - SymbolTable: 符号表字典 - - Returns: - 二进制字节数据 - """ - JsonData = json.dumps(SymbolTable, ensure_ascii=False).encode('utf-8') - length = len(JsonData) - # 使用4字节小端序整数表示长度 - header = struct.pack(' dict: - """从二进制数据反序列化符号表 - - Args: - data: 二进制字节数据 - - Returns: - 符号表字典 - """ - if len(data) < 4: - raise ValueError("Invalid symbin file: data too short") - # 解析4字节长度头(小端序) - length = struct.unpack(' -o [-debug ] - if I + 1 < len(sys.argv): - InputFile = sys.argv[I + 1] - I += 2 - - # 解析可选参数 - OutputFile = None - DebugFile = None - while I < len(sys.argv) and sys.argv[I].startswith('-'): - if sys.argv[I] == '-o': - if I + 1 < len(sys.argv): - OutputFile = sys.argv[I + 1] - I += 2 - else: - print(f'Error: -o requires an argument') - sys.exit(1) - elif sys.argv[I] == '-debug': - if I + 1 < len(sys.argv): - DebugFile = sys.argv[I + 1] - I += 2 - else: - print(f'Error: -debug requires an argument') - sys.exit(1) - else: - break - - # 如果没有指定输出文件,使用默认名称 - if not OutputFile: - OutputFile = InputFile.replace('.py', '.symbin').replace('.c', '.symbin') - - # 执行预处理 - self.Args['PreSym'] = { - 'input': InputFile, - 'output': OutputFile, - 'debug': DebugFile - } - else: - print(f'Error: -presym requires an argument') - sys.exit(1) - elif sys.argv[I] == '-e' or sys.argv[I] == '--encoding': - if I + 1 < len(sys.argv): - self.Args['Encoding'] = sys.argv[I + 1] - I += 2 - else: - print(f'Error: -e/--encoding requires an argument') - sys.exit(1) - elif sys.argv[I] == '--triple': - if I + 1 < len(sys.argv): - self.triple = sys.argv[I + 1] - I += 2 - else: - print(f'Error: --triple requires an argument') - sys.exit(1) - elif sys.argv[I] == '--datalayout': - if I + 1 < len(sys.argv): - self.datalayout = sys.argv[I + 1] - I += 2 - else: - print(f'Error: --datalayout requires an argument') - sys.exit(1) - else: - print(f'Error: Unknown argument {sys.argv[I]}') - sys.exit(1) - - # 检查是否有预处理符号文件的请求,如果有则跳过输入输出检查 - if 'PreSym' not in self.Args and ('Input' not in self.Args or 'Output' not in self.Args): - print(ERROR_MESSAGES['MISSING_ARGS']) - print(HELP_MESSAGE) - sys.exit(1) - - def CompileAndRun(self, OutputFile): - """编译并运行生成的C代码""" - # 获取编译命令 - CompileCmd = self.Args.get('CompileCommand', DEFAULT_COMPILE_COMMAND) - CompileFlags = self.Args.get('CompileFlags', DEFAULT_COMPILE_FLAGS) - - # 构建编译命令 - FullCompileCmd = f'{CompileCmd} {CompileFlags} {OutputFile} -o {OutputFile}.exe' - print(f'Compiling: {FullCompileCmd}') - - # 执行编译命令 - try: - CompileResult = ExecuteCommand(FullCompileCmd) - if CompileResult: - print('Compilation successful!') - - # 检查是否需要运行 - if self.Args.get('Run', False): - RunArgs = self.Args.get('RunArgs', '') - RunCmd = f'{OutputFile}.exe {RunArgs}'.strip() - print(f'Running: {RunCmd}') - - # 执行运行命令 - RunResult = ExecuteCommand(RunCmd) - if RunResult: - print('Execution output:') - print(RunResult.stdout) - if RunResult.stderr: - print('Execution errors:') - print(RunResult.stderr) - except Exception as e: - print(f'{ERROR_MESSAGES["COMPILE_FAILED"]}: {e}') - - def WriteDebugInfo(self, content): - """写入调试信息到指定文件""" - # 获取调试文件路径 - if 'Debug' in self.Args: - DebugFile = self.Args['Debug'] - else: - DebugFile = self.Args.get('Output', '').replace('.c', '.p2c') - - if DebugFile: - AppendFileContent(DebugFile, content) - - def PythonToC(self, InputFile, OutputFile): - """Python到C的转换""" - # 获取编码参数 - encoding = self.Args.get('Encoding', 'utf-8') - - # 设置调试文件路径(使用 .p2c 扩展名) - if 'Debug' in self.Args: - DebugFile = self.Args['Debug'] - else: - # 默认使用 .p2c 文件 - DebugFile = OutputFile.replace('.c', '.p2c') - - # 设置翻译器的调试文件 - self.translator.SetDebugFile(DebugFile) - - # 先清空调试文件 - with open(DebugFile, 'w', encoding=encoding) as f: - f.write('') - - # 解析辅助文件,提取符号信息 - if self.HelperFiles: - self.translator.ParseHelperFiles(self.HelperFiles, encoding) - - # 加载注解文件,提取类型定义 - if self.AnnotationFiles: - self.translator.LoadAnnotationFiles(self.AnnotationFiles) - - # 获取编码参数 - encoding = self.Args.get('Encoding', 'utf-8') - with open(InputFile, 'r', encoding=encoding) as F: - Content = F.read() - - # 保存原始代码行 - self.translator.OriginalLines = Content.split('\n') - self.translator.Content = Content - - # 解析Python代码为AST - Tree = ast.parse(Content) - - # 解析文件以提取类型信息(用于 EmbeddedAssignments) - self.translator.ParsePythonFile(InputFile, encoding) - - # 写入AST树信息(压缩格式) - with open(DebugFile, 'a', encoding=encoding) as f: - f.write('=== AST Tree (Compact) ===\n') - f.write(ast.dump(Tree)) - f.write('\n\n') - - Target = 'llvm' - CCode = self.translator.GenerateCCode(Tree, target=Target) - - import datetime - timestamp = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') - filename = os.path.basename(OutputFile) - - encoding = self.Args.get('Encoding', 'utf-8') - with open(OutputFile, 'w', encoding=encoding) as F: - F.write(CCode) - F.write('\n') - - def CToPython(self, InputFile, OutputFile, HeaderFiles): - """C到Python的转换(暂时禁用)""" - print("C到Python的转换功能暂时禁用,请使用Python到C的转换功能。") - - def AddSymbol(self, SymbolFiles): - """添加符号文件 - - Args: - SymbolFiles: 符号文件或符号文件列表 - """ - if isinstance(SymbolFiles, list): - self.SymbolFiles.extend(SymbolFiles) - else: - self.SymbolFiles.append(SymbolFiles) - - # 收集文件路径和编码 - HelperFiles = [] - encodings = [] - for SymbolFile in self.SymbolFiles: - FilePath = SymbolFile.FilePath - encoding = SymbolFile.encoding - if FilePath: - HelperFiles.append(FilePath) - encodings.append(encoding) - - # 解析辅助文件 - if HelperFiles: - # 暂时使用第一个文件的编码 - encoding = encodings[0] if encodings else 'utf-8' - self.translator.ParseHelperFiles(HelperFiles, encoding) - - def Convert(self, OutputFilename=None, SourceFilename=None, target='llvm'): - """转换代码 - - Args: - OutputFilename: 输出文件名(用于模板渲染) - SourceFilename: 源文件路径(用于设置CurrentFile,影响导入模块的查找) - target: 目标代码类型,仅支持 'llvm' - - Returns: - 如果debug是字符串,则返回生成的代码 - 如果debug是True,则返回生成的代码和调试信息 - """ - if not self.code: - print('Error: No code provided') - return None - - from lib.core.Handles.HandlesImports import ImportHandle - ImportHandle._struct_load_cache.clear() - - # 如果提供了 SourceFilename,先设置 CurrentFile - # 这样导入模块时会相对于源文件所在目录查找 - if SourceFilename: - self.translator.CurrentFile = SourceFilename - - # 加载注解文件,提取类型定义 - if self.AnnotationFiles: - self.translator.LoadAnnotationFiles(self.AnnotationFiles) - - # 保存原始代码行 - self.translator.OriginalLines = self.code.split('\n') - - # 解析Python代码为AST - Tree = ast.parse(self.code) - - # 从源代码直接预扫描 import 语句,注册别名 - # 注意:不能依赖 Tree 中的 import 节点,因为 ParsePythonFile 可能修改了 AST - if not getattr(self.translator, '_import_aliases', None): - self.translator._import_aliases = {} - if not getattr(self.translator, '_imported_modules', None): - self.translator._imported_modules = set() - _prescan_tree = ast.parse(self.code) - for _node in ast.iter_child_nodes(_prescan_tree): - if isinstance(_node, ast.Import): - for _alias in _node.names: - _name = _alias.name - if _name in ('c', 't'): - continue - self.translator._imported_modules.add(_name) - if _alias.asname: - self.translator._import_aliases[_alias.asname] = _name - elif isinstance(_node, ast.ImportFrom): - _module_name = _node.module - if _module_name and _module_name not in ('c', 't'): - self.translator._imported_modules.add(_module_name) - for _alias in _node.names: - if _alias.asname: - self.translator._import_aliases[_alias.asname] = f"{_module_name}.{_alias.name}" - - # 解析代码以提取类型信息(用于 EmbeddedAssignments 和 TypedefAssignments) - # 创建临时文件路径用于解析 - import tempfile - import os - with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False, encoding='utf-8') as f: - f.write(self.code) - TempFile = f.name - try: - # UpdateCurrentFile=False 表示不修改 CurrentFile - if SourceFilename: - self.translator.ParsePythonFile(TempFile, UpdateCurrentFile=False) - else: - self.translator.ParsePythonFile(TempFile) - finally: - os.unlink(TempFile) - - import datetime - timestamp = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') - - if self.triple: - self.translator.triple = self.triple - if self.datalayout: - self.translator.datalayout = self.datalayout - - # 生成代码 - code = self.translator.GenerateCCode(Tree, target='llvm') - filename = os.path.basename(OutputFilename) if OutputFilename else 'generated.ll' - - # 处理调试信息 - if isinstance(self.config.debug, str): - # 如果debug是字符串,写入调试信息到文件 - with open(self.config.debug, 'w', encoding='utf-8') as f: - f.write('=== Symbol Table ===\n') - f.write(str(self.translator.SymbolTable) + '\n\n') - f.write('=== AST Tree ===\n') - f.write(ast.dump(Tree, indent=2) + '\n\n') - f.write('=== Export Table ===\n') - f.write(self.translator.ExportTable.to_json() + '\n\n') - f.write('=== Generated Code ===\n') - f.write(code + '\n') - return code - elif self.config.debug: - # 如果debug是True,返回生成的代码和调试信息 - DebugInfo = { - 'SymbolTable': self.translator.SymbolTable, - 'ast_tree': ast.dump(Tree, indent=2), - 'export_table': self.translator.ExportTable.to_dict(), - 'generated_code': code - } - return code, DebugInfo - else: - # 如果debug是False,只返回生成的代码 - return code - - def Run(self): - """主运行函数""" - # 检查是否有命令行参数 - if len(sys.argv) > 1: - # 有命令行参数,使用 ParseArgs 方法解析 - self.ParseArgs() - - # 检查是否有预处理符号文件的请求 - if 'PreSym' in self.Args: - PresymConfig = self.Args['PreSym'] - InputFile = PresymConfig['input'] - OutputFile = PresymConfig['output'] - DebugFile = PresymConfig['debug'] - - # 获取编码参数 - encoding = self.Args.get('Encoding', 'utf-8') - - # 推断文件类型 - FileType = 'py' if InputFile.endswith('.py') else 'c' if InputFile.endswith('.c') else None - - # 创建 SymbolFile 对象,传入编码参数 - SymbolFile = SymbolFile(file=InputFile, type=FileType, encoding=encoding) - - # 调用 PreProcessSymbol - if DebugFile: - BinaryData, DebugInfo = TransPyC.PreProcessSymbol(SymbolFile, debug=True) - # 写入调试文件 - with open(DebugFile, 'w', encoding=encoding) as f: - f.write(DebugInfo) - print(f"Debug info written to: {DebugFile}") - else: - BinaryData = TransPyC.PreProcessSymbol(SymbolFile, debug=False) - - # 写入二进制符号文件 - with open(OutputFile, 'wb') as f: - f.write(BinaryData) - - print(f"Symbol file generated: {OutputFile}") - return - - InputFile = self.Args['Input'] - OutputFile = self.Args['Output'] - else: - # 没有命令行参数,使用默认的测试文件名称 - InputFile = DEFAULT_INPUT_FILE - OutputFile = DEFAULT_OUTPUT_FILE - print('Using default test files: test.py -> test.c') - - FileType = DetectFileType(InputFile) - - if FileType == '.py': - self.PythonToC(InputFile, OutputFile) - # 检查是否需要编译和运行 - if 'CompileCommand' in self.Args or self.Args.get('Run', False): - self.CompileAndRun(OutputFile) - elif FileType == '.c': - self.CToPython(InputFile, OutputFile, self.HeaderFiles) - else: - print(f'Error: Unsupported file type {FileType}') - sys.exit(1) - - -if __name__ == '__main__': - trans = TransPyC() - if 'SliceLevel' in trans.Args: - trans.SliceLevel = trans.Args['SliceLevel'] - trans.Run() +# TransPyC 入口程序 +# 拆分后的模块位于 lib/Shell/ 目录下 +import sys +import os +sys.path.append(os.path.join(os.path.dirname(__file__), 'lib', 'includes')) + +from lib.Shell import ( + SerializeSymbolTable, deSerializeSymbolTable, + SymbolFile, Config, TransPyC +) + +__all__ = ['SerializeSymbolTable', 'deSerializeSymbolTable', 'SymbolFile', 'Config', 'TransPyC'] + +if __name__ == '__main__': + TransPyC().Run() diff --git a/blackhole.py b/blackhole.py deleted file mode 100644 index 8f93490..0000000 --- a/blackhole.py +++ /dev/null @@ -1,278 +0,0 @@ -#include -#include -#include -#include -from stdint import * -import vipermath -import t, c - - -W: t.CDefine = 900 -H: t.CDefine = 540 -MAX_STEPS: t.CDefine = 400 -ESCAPE: t.CDefine = 60.0 -DISK_IN: t.CDefine = 2.6 # 吸积盘内缘 (单位: 史瓦西半径 Rs=1) -DISK_OUT: t.CDefine = 11.0 # 吸积盘外缘 -CAM_DIST: t.CDefine = 22.0 -CAM_ELEV: t.CDefine = 9.0 # 相机仰角(度): 小角度=侧视/透镜效果最强(星际穿越). 想更俯视可调到35 -FOVF: t.CDefine = 0.55 # tan(半视场) - -# ---------------- 向量 ---------------- -class V3: - x: t.CDouble - y: t.CDouble - z: t.CDouble - - def __init__(self, x: t.CDefine, y: t.CDefine, z: t.CDefine): - self.x = x - self.y = y - self.z = z - - def __add__(self, other: 'V3') -> 'V3': - return V3(self.x + other.x, self.y + other.y, self.z + other.z) - - def __sub__(self, other: 'V3') -> 'V3': - return V3(self.x - other.x, self.y - other.y, self.z - other.z) - - def __mul__(self, other: t.CDouble) -> 'V3': - return V3(self.x * other, self.y * other, self.z * other) - - def __xor__(self, other: 'V3') -> t.CDouble: # dot - return self.x * other.x + self.y * other.y + self.z * other.z - - def cross(self, other: 'V3') -> 'V3': - return V3(self.y * other.z - self.z * other.y, self.z * other.x - self.x * other.z, self.x * other.y - self.y * other.x) - - def __len__(self) -> t.CDouble: - return vipermath.sqrt(c.Deref(self) ^ c.Deref(self)) - - def nrm(self) -> 'V3': - l = len(c.Deref(self)) # self.__len__() - return self / l if l > (1e-12) else self - - def lerp(self, other: 'V3', t: t.CDouble) -> 'V3': - return self + (other - self) * t - -def clmp(x: t.CDouble, a: t.CDouble, b: t.CDouble) -> t.CDouble: - return x if x >= a and x <= b else a if x < a else b - -def smoothstep(a: t.CDouble, b: t.CDouble, x: t.CDouble) -> t.CDouble: - t = clmp((x - a) / (b - a), 0, 1) - return t * t * (3 - 2 * t) - - - -# static inline V3 v(double x,double y,double z){V3 r={x,y,z};return r;} -# static inline V3 add(V3 a,V3 b){return v(a.x+b.x,a.y+b.y,a.z+b.z);} -# static inline V3 sub(V3 a,V3 b){return v(a.x-b.x,a.y-b.y,a.z-b.z);} -# static inline V3 scl(V3 a,double s){return v(a.x*s,a.y*s,a.z*s);} -# static inline double dot(V3 a,V3 b){return a.x*b.x+a.y*b.y+a.z*b.z;} -# static inline V3 cross(V3 a,V3 b){return v(a.y*b.z-a.z*b.y, a.z*b.x-a.x*b.z, a.x*b.y-a.y*b.x);} -# static inline double len(V3 a){return sqrt(dot(a,a));} -# static inline V3 nrm(V3 a){double l=len(a); return l>1e-12?scl(a,1.0/l):a;} -# static inline V3 lerp(V3 a,V3 b,double t){return add(scl(a,1-t),scl(b,t));} -# static inline double clmp(double x,double a,double b){return xb?b:x);} -# static inline double smoothstep(double a,double b,double x){double t=clmp((x-a)/(b-a),0,1);return t*t*(3-2*t);} - -# ---------------- 帧缓冲 / 相机 ---------------- -fb: UINT32PTR -CAM: V3 -FWD: V3 -RIGHT: V3 -UP: V3 -# static V3 CAM, FWD, RIGHT, UP; -gT: t.CDouble = 0.0 -# static volatile double gT = 0.0; - -def setupCamera(): - e: t.CDouble = CAM_ELEV * vipermath.U_M_PI / 180.0 - CAM = V3(CAM_DIST * vipermath.cos(e), CAM_DIST * vipermath.sin(e), 0) - FWD = (V3(0, 0, 0) - CAM).nrm() - RIGHT = (FWD.cross(V3(0,1,0))).nrm() - UP = RIGHT.cross(FWD) - -# ---------------- 哈希 / 星空 ---------------- -def hash3(x: t.CDouble, y: t.CDouble, z: t.CDouble) -> t.CDouble: - n: t.CDouble = vipermath.sin(x*127.1 + y * 311.7 + z * 74.7) * 43758.5453 - return n - vipermath.floor(n) - -def stars(d: V3) -> V3: - _c: V3 = V3(0, 0, 0) - for i in range(3): - s: t.CDouble = 80.0 + i * 90.0 - px: t.CDouble = d.x * s - py: t.CDouble = d.y * s - pz: t.CDouble = d.z * s - ix: t.CDouble = vipermath.floor(px) - iy: t.CDouble = vipermath.floor(py) - iz: t.CDouble = vipermath.floor(pz) - h: t.CDouble = hash3(ix, iy, iz) - if h > 0.991: - fx: t.CDouble = px - ix - 0.5 - fy: t.CDouble = py - iy - 0.5 - d2: t.CDouble = fx * fx + fy * fy + fz * fz - br: t.CDouble = (h-0.991) / 0.009 * vipermath.exp(-d2 * 9.0) * 1.4 - _t: t.CDouble = hash3(iy, iz, ix) - tint: V3 = V3(0.7,0.8,1.0) if (_t < 0.3) else (V3(1.0,0.8,0.6) if (_t > 0.8) else V3(1,1,1)); - _c = add(_c, scl(tint, br)) - return _c - - -# ---------------- 吸积盘着色 ---------------- -static void diskShade(V3 cp,double rr,double t,V3*emit,double*alpha){ - double tt=(rr-DISK_IN)/(DISK_OUT-DISK_IN); - double edge = smoothstep(0,0.07,tt)*smoothstep(0,0.18,1.0-tt); - double ang=atan2(cp.z,cp.x); - double w = 1.0/pow(rr,1.5); # 开普勒角速度 - double ph = ang - t*0.0011*w*9.0; # 随时间旋转 - double n = 0.5+0.5*sin(ph*5.0 - rr*1.6); - double n2 = 0.5+0.5*sin(ph*13.0 + rr*0.8 + 1.7); - double dens = (0.35+0.65*n)*(0.55+0.45*n2); - double bright = (0.45+1.7*pow(1.0-tt,1.8))*edge; - - # 相对论多普勒增亮 (一侧更亮 + 微蓝移) - V3 vdir = nrm(v(-cp.z,0,cp.x)); - double beta = 0.46/sqrt(rr); - V3 toCam = nrm(sub(CAM,cp)); - double mu = dot(vdir,toCam); - double dop = 1.0/(1.0-beta*mu); - double beam = pow(dop,3.0); - - V3 c1=v(1.0,0.92,0.68), c2=v(1.0,0.42,0.13); - V3 base=lerp(c1,c2,tt); - base.z += (dop-1.0)*0.35; base.x -= (dop-1.0)*0.05; # 蓝移微调 - - double inten = bright*dens*beam*1.25; - *emit = scl(base,inten); - *alpha = clmp(edge*dens*0.92,0,1); -} - -# ---------------- 光子测地线积分 ---------------- -static V3 trace(V3 dir){ - V3 pos=CAM, vel=dir; - V3 hvec=cross(pos,vel); - double h2=dot(hvec,hvec); # 角动量守恒 - double T=1.0; V3 col=v(0,0,0); - double t=gT; - - for(int i=0;i 黑 - if(r>ESCAPE){ col=add(col,scl(stars(nrm(vel)),T)); break; } - - double dt=clmp(r*0.08,0.03,2.2); - # RK4 (a = -1.5 h2 pos / r^5) - ACC(P) scl(P, -1.5*h2/pow(dot(P,P),2.5)) - V3 k1p=vel, k1v=ACC(pos); - V3 k2p=add(vel,scl(k1v,dt*0.5)), k2v=ACC(add(pos,scl(k1p,dt*0.5))); - V3 k3p=add(vel,scl(k2v,dt*0.5)), k3v=ACC(add(pos,scl(k2p,dt*0.5))); - V3 k4p=add(vel,scl(k3v,dt)), k4v=ACC(add(pos,scl(k3p,dt))); - V3 npos=add(pos,scl(add(add(k1p,scl(k2p,2)),add(scl(k3p,2),k4p)),dt/6.0)); - V3 nvel=add(vel,scl(add(add(k1v,scl(k2v,2)),add(scl(k3v,2),k4v)),dt/6.0)); - - # 吸积盘平面 y=0 穿越检测 - if(pos.y*npos.y<0){ - double f=pos.y/(pos.y-npos.y); - V3 cp=lerp(pos,npos,f); - double rr=sqrt(cp.x*cp.x+cp.z*cp.z); - if(rr>DISK_IN && rry0;yy1;y++) - for(int x=0;x64)NT=64; - - fb=(uint32_t*)malloc((size_t)W*H*4); - bmi.bmiHeader.biSize=sizeof(BITMAPINFOHEADER); - bmi.bmiHeader.biWidth=W; bmi.bmiHeader.biHeight=-H; # 顶向下 - bmi.bmiHeader.biPlanes=1; bmi.bmiHeader.biBitCount=32; bmi.bmiHeader.biCompression=BI_RGB; - setupCamera(); - - WNDCLASS wc={0}; wc.lpfnWndProc=WndProc; wc.hInstance=hI; - wc.lpszClassName="bh"; wc.hCursor=LoadCursor(0,IDC_ARROW); - RegisterClass(&wc); - RECT rc={0,0,W,H}; AdjustWindowRect(&rc,WS_OVERLAPPEDWINDOW,FALSE); - HWND hwnd=CreateWindow("bh","Gargantua (ESC quit)",WS_OVERLAPPEDWINDOW, - CW_USEDEFAULT,CW_USEDEFAULT,rc.right-rc.left,rc.bottom-rc.top,0,0,hI,0); - ShowWindow(hwnd,show); - - LARGE_INTEGER fq,t0,t1; QueryPerformanceFrequency(&fq); - DWORD start=GetTickCount(); - MSG msg; int run=1; double fps=0; DWORD ftc=0; int fcnt=0; - while(run){ - while(PeekMessage(&msg,0,0,0,PM_REMOVE)){ - if(msg.message==WM_QUIT){run=0;break;} - TranslateMessage(&msg); DispatchMessage(&msg); - } - if(!run)break; - gT=(double)(GetTickCount()-start); # <<< 传入的时间 t (毫秒) - QueryPerformanceCounter(&t0); - renderFrame(); - QueryPerformanceCounter(&t1); - HDC dc=GetDC(hwnd); - SetDIBitsToDevice(dc,0,0,W,H,0,0,0,H,fb,&bmi,DIB_RGB_COLORS); - ReleaseDC(hwnd,dc); - - fcnt++; DWORD now=GetTickCount(); - if(now-ftc>500){ fps=fcnt*1000.0/(now-ftc); fcnt=0; ftc=now; - char buf[128]; sprintf(buf,"Gargantua FPS:%.1f threads:%d",fps,NT); - SetWindowText(hwnd,buf); - } - } - free(fb); - return 0; -} \ No newline at end of file diff --git a/debug_out.txt b/debug_out.txt deleted file mode 100644 index ab6fd60..0000000 --- a/debug_out.txt +++ /dev/null @@ -1 +0,0 @@ -[ERROR] 类型 'window.InputEvent' 未在符号表中找到,严格模式下需要定义此类型 diff --git a/debug_output.txt b/debug_output.txt deleted file mode 100644 index cdcc976..0000000 --- a/debug_output.txt +++ /dev/null @@ -1 +0,0 @@ -[编译终止] 1 个文件翻译失败 diff --git a/find.py b/find.py new file mode 100644 index 0000000..1af572b --- /dev/null +++ b/find.py @@ -0,0 +1,163 @@ +""" +REPL 模式文件内容搜索工具 +支持正则或纯文本搜索,默认搜索当前目录 +""" +import os +import re +import sys + +# 硬编码排除目录 +EXCLUDE_DIRS = { + '.git', '.vs', 'node_modules', '__pycache__', '.idea', + 'miniprogram_npm', '_backup_pre_redesign', +} + +# 排除的文件扩展名 +EXCLUDE_EXTS = { + '.png', '.jpg', '.jpeg', '.gif', '.svg', '.ico', '.bmp', + '.mp3', '.mp4', '.wav', '.avi', + '.zip', '.rar', '.7z', '.tar', '.gz', + '.exe', '.dll', '.so', '.dylib', + '.pyc', '.pyo', '.class', '.o', '.obj', + '.db', '.sqlite', '.vsidx', +} + +# 默认搜索根目录 +DEFAULT_ROOT = os.path.dirname(os.path.abspath(__file__)) + + +def should_skip(dirpath): + """判断目录是否应跳过""" + parts = dirpath.replace('\\', '/').split('/') + return any(p in EXCLUDE_DIRS for p in parts) + + +def search(pattern, root=DEFAULT_ROOT, use_regex=True, max_results=50): + """搜索文件内容""" + if use_regex: + try: + compiled = re.compile(pattern, re.IGNORECASE) + except re.error as e: + print(f' 正则语法错误: {e}') + return + + count = 0 + for dirpath, dirnames, filenames in os.walk(root): + # 就地修改 dirnames 以跳过排除目录 + dirnames[:] = [d for d in dirnames if d not in EXCLUDE_DIRS] + + for fname in filenames: + ext = os.path.splitext(fname)[1].lower() + if ext in EXCLUDE_EXTS: + continue + + fpath = os.path.join(dirpath, fname) + relpath = os.path.relpath(fpath, root) + try: + with open(fpath, 'r', encoding='utf-8', errors='ignore') as f: + for lineno, line in enumerate(f, 1): + line_stripped = line.rstrip('\n\r') + if use_regex: + match = compiled.search(line_stripped) + if match: + highlight = line_stripped[:match.start()] + \ + f'>>> {match.group()} <<<' + \ + line_stripped[match.end():] + print(f' {relpath}:{lineno} {highlight}') + count += 1 + else: + if pattern.lower() in line_stripped.lower(): + print(f' {relpath}:{lineno} {line_stripped}') + count += 1 + + if count >= max_results: + print(f'\n ... 已达上限 {max_results} 条,停止') + return + except (PermissionError, OSError): + continue + + if count == 0: + print(' 未找到匹配内容') + else: + print(f'\n 共 {count} 条匹配') + + +def main(): + print('=== 文件内容搜索工具 ===') + print(f'搜索根目录: {DEFAULT_ROOT}') + print(f'排除目录: {EXCLUDE_DIRS}') + print() + print('命令:') + print(' /regex 正则搜索') + print(' /text 纯文本搜索') + print(' /max 设置结果上限(默认50)') + print(' /dir 切换搜索目录') + print(' /help 显示帮助') + print(' /quit 退出') + print() + print('直接输入内容默认使用【纯文本】搜索,需要正则请加 /regex 前缀') + print() + + root = DEFAULT_ROOT + use_regex = False # 修改1:默认纯文本 + max_results = 50 + + while True: + try: + raw = input('find> ').strip() + except (EOFError, KeyboardInterrupt): + print('\n再见') + break + + if not raw: + continue + + if raw == '/quit': + print('再见') + break + + if raw == '/help': + print(' /regex 正则搜索') + print(' /text 纯文本搜索') + print(' /max 设置结果上限') + print(' /dir 切换搜索目录') + print(' /help 显示帮助') + print(' /quit 退出') + print(' 直接输入内容默认纯文本搜索') + continue + + if raw.startswith('/regex '): + pattern = raw[7:].strip() + if pattern: + search(pattern, root, use_regex=True, max_results=max_results) + continue + + if raw.startswith('/text '): + pattern = raw[6:].strip() + if pattern: + search(pattern, root, use_regex=False, max_results=max_results) + continue + + if raw.startswith('/max '): + try: + max_results = int(raw[5:].strip()) + print(f' 结果上限设为 {max_results}') + except ValueError: + print(' 请输入数字') + continue + + if raw.startswith('/dir '): + new_dir = raw[5:].strip() + if os.path.isdir(new_dir): + root = os.path.abspath(new_dir) + print(f' 搜索目录切换为: {root}') + else: + print(f' 目录不存在: {new_dir}') + continue + + # 修改2:直接输入走纯文本搜索 + search(raw, root, use_regex=False, max_results=max_results) + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/includes/asm.py b/includes/asm.py index b00b1f0..ef64063 100644 --- a/includes/asm.py +++ b/includes/asm.py @@ -13,6 +13,9 @@ def hlt(): def nop(): c.Asm("nop", [t.ASM_DESCR.CLOBBER_MEMORY]) +def pause(): + c.Asm("pause", op=[t.ASM_DESCR.CLOBBER_MEMORY]) + def inb(port: t.CUInt16T) -> t.CUInt8T: value: t.CUInt32T c.Asm(f"""mov edx, {c.AsmInp(t.CUInt32T(port), t.ASM_DESCR.REG_ANY)} diff --git a/includes/base64.py b/includes/base64.py index 87e708b..899e2a8 100644 --- a/includes/base64.py +++ b/includes/base64.py @@ -1,4 +1,3 @@ -import binascii import t, c diff --git a/includes/binascii.py b/includes/binascii.py index 68f1b02..07b8b62 100644 --- a/includes/binascii.py +++ b/includes/binascii.py @@ -1,5 +1,4 @@ import t, c -import stdint HEX_CHARS: list[t.CChar, None] = "0123456789abcdef" diff --git a/includes/stdlib.py b/includes/stdlib.py index 9b603d5..38e319f 100644 --- a/includes/stdlib.py +++ b/includes/stdlib.py @@ -3,7 +3,7 @@ import t -def malloc(size: UINT) -> t.CVoid | t.CPtr | t.State | t.CExtern | t.CExport: pass -def calloc(nmemb: UINT, size: UINT) -> t.CVoid | t.CPtr | t.State | t.CExtern | t.CExport: pass -def realloc(p: str, p2: t.CLong | t.CLong) -> t.CVoid | t.CPtr | t.State | t.CExtern | t.CExport: pass +def malloc(size: t.CSizeT) -> t.CVoid | t.CPtr | t.State | t.CExtern | t.CExport: pass +def calloc(nmemb: t.CSizeT, size: t.CSizeT) -> t.CVoid | t.CPtr | t.State | t.CExtern | t.CExport: pass +def realloc(p: t.CVoid | t.CPtr, size: t.CSizeT) -> t.CVoid | t.CPtr | t.State | t.CExtern | t.CExport: pass def free(p: t.CVoid | t.CPtr) -> None | t.State | t.CExtern | t.CExport: pass \ No newline at end of file diff --git a/lib/Projectrans/Config.py b/lib/Projectrans/Config.py new file mode 100644 index 0000000..2441065 --- /dev/null +++ b/lib/Projectrans/Config.py @@ -0,0 +1,214 @@ +import os +import sys +import shutil +from lib.Projectrans.Phase1Generator import Phase1Generator +from lib.Projectrans.Phase2Translator import Phase2Translator + + +def save_sha1_map(temp_dir: str, sha1_map: dict[str, str]): + """将 SHA1 映射表保存到文件""" + map_path = os.path.join(temp_dir, '_sha1_map.txt') + with open(map_path, 'w', encoding='utf-8') as f: + for sha1, rel in sorted(sha1_map.items()): + f.write(f"{sha1}:{rel}\n") + + +def Load_sha1_map(temp_dir: str) -> dict[str, str]: + """从文件加载 SHA1 映射表""" + map_path = os.path.join(temp_dir, '_sha1_map.txt') + result = {} + if os.path.exists(map_path): + with open(map_path, 'r', encoding='utf-8') as f: + for line in f: + line = line.strip() + if ':' in line: + sha1, rel = line.split(':', 1) + result[sha1] = rel + return result + + +def Load_project_config(project_file: str) -> dict: + """从 project.json 加载配置""" + import json + with open(project_file, 'r', encoding='utf-8') as f: + return json.load(f) + + +def resolve_paths(config: dict, project_file: str) -> dict: + """将配置中的相对路径转换为绝对路径""" + project_dir = os.path.dirname(os.path.abspath(project_file)) + result = dict(config) + + def resolve(p): + if p is None: + return None + if os.path.isabs(p): + return p + return os.path.normpath(os.path.join(project_dir, p)) + + if 'source_dir' in result: + result['source_dir'] = resolve(result.get('source_dir')) + elif 'sources' in result: + resolved_sources = [] + for src in result['sources']: + if '*' in src or '?' in src: + import glob as glob_module + for matched in glob_module.glob(os.path.join(project_dir, src), recursive=True): + if os.path.isfile(matched): + resolved_sources.append(matched) + else: + resolved_sources.append(resolve(src)) + result['sources'] = [s for s in resolved_sources if os.path.isfile(s)] + + result['temp_dir'] = resolve(config.get('temp_dir')) + result['output_dir'] = resolve(config.get('output_dir')) + + if 'includes' in result: + result['includes'] = [resolve(inc) for inc in result['includes']] + + result['_project_dir'] = project_dir + return result + + +def main(): + import argparse + parser = argparse.ArgumentParser( + description='TransPyC 工程翻译器 - 基于 project.json 的两阶段翻译', + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=''' +示例: + # 从 project.json 读取配置并执行(默认查找当前目录) + python ProjectTrans.py + + # 指定 project.json 文件 + python ProjectTrans.py --project ./TestProject/project.json + + # 使用命令行参数覆盖 project.json 配置 + python ProjectTrans.py --src ./src --temp ./decl --output ./out --phase all + + # 仅运行阶段一 + python ProjectTrans.py --phase 1 + + # 仅运行阶段二 + python ProjectTrans.py --phase 2 + + # 清理临时目录 + python ProjectTrans.py --clean +''' + ) + parser.add_argument('--project', help='project.json 路径(默认查找当前目录)') + parser.add_argument('--src', help='源文件目录(覆盖 project.json)') + parser.add_argument('--temp', help='声明接口临时目录(覆盖 project.json)') + parser.add_argument('--output', help='输出目录(覆盖 project.json)') + parser.add_argument('--phase', choices=['1', '2', 'all'], help='阶段: 1=生成声明, 2=翻译+编译, all=全部') + parser.add_argument('--cc', help='LLVM 编译器命令(覆盖 project.json)') + parser.add_argument('--clean', action='store_true', help='清理 output 和 temp 目录') + + args = parser.parse_args() + + project_file = args.project + if not project_file: + candidates = ['project.json', './project.json'] + for c in candidates: + if os.path.exists(c): + project_file = c + break + + if project_file and os.path.exists(project_file): + print(f"[配置] 读取: {project_file}") + config = Load_project_config(project_file) + project_dir = os.path.dirname(os.path.abspath(project_file)) + print(f"[配置] 项目目录: {project_dir}") + else: + print("[错误] 未找到 project.json,请使用 --project 指定") + sys.exit(1) + + resolved = resolve_paths(config, project_file) + src = args.src or resolved.get('source_dir') or resolved.get('sources') + temp_dir = args.temp or resolved.get('temp_dir') + output_dir = args.output or resolved.get('output_dir') + phase = args.phase or 'all' + cc_cmd = args.cc or resolved.get('compiler', {}).get('cmd', 'llc') + cc_flags = resolved.get('compiler', {}).get('flags', ['-filetype=obj']) + slice_level = resolved.get('options', {}).get('slice_level', 3) + project_include_dirs = resolved.get('includes', []) + target_triple = resolved.get('target', {}).get('triple') + target_datalayout = resolved.get('target', {}).get('datalayout') + + if isinstance(src, list): + if len(src) == 1 and os.path.isdir(src[0]): + src = src[0] + else: + src = src[0] if len(src) == 1 else os.path.dirname(os.path.commonpath(src)) if all(os.path.exists(p) for p in src) else src[0] + + print(f"[配置] 源目录: {src}") + print(f"[配置] 临时目录: {temp_dir}") + print(f"[配置] 输出目录: {output_dir}") + print(f"[配置] 阶段: {phase}") + print(f"[配置] 编译器: {cc_cmd} {' '.join(cc_flags)}") + if target_triple: + print(f"[配置] 目标三元组: {target_triple}") + if target_datalayout: + print(f"[配置] 数据布局: {target_datalayout}") + + if args.clean: + if output_dir and os.path.exists(output_dir): + for f in os.listdir(output_dir): + fpath = os.path.join(output_dir, f) + try: + if os.path.isfile(fpath) or os.path.islink(fpath): + os.remove(fpath) + elif os.path.isdir(fpath): + shutil.rmtree(fpath, ignore_errors=True) + except: + pass + print(f"[清理] output: 已清空 {output_dir}") + if temp_dir and os.path.exists(temp_dir): + for f in os.listdir(temp_dir): + fpath = os.path.join(temp_dir, f) + try: + if os.path.isfile(fpath) or os.path.islink(fpath): + os.remove(fpath) + elif os.path.isdir(fpath): + shutil.rmtree(fpath, ignore_errors=True) + except: + pass + print(f"[清理] temp: 已清空 {temp_dir}") + print("[清理] 完成") + if (not phase or phase == 'all') and not args.project: + return + + if phase in ('1', 'all'): + if isinstance(src, list): + print("[错误] 阶段一需要指定源目录,不支持文件列表") + sys.exit(1) + all_include_dirs = list(project_include_dirs) if project_include_dirs else [] + for d in Phase2Translator.INCLUDE_DIRS: + if os.path.isdir(d): + d = os.path.abspath(d) + if d not in [os.path.abspath(x) for x in all_include_dirs]: + all_include_dirs.append(d) + gen = Phase1Generator(src, temp_dir, include_dirs=all_include_dirs, target_triple=target_triple, target_datalayout=target_datalayout) + gen.run() + save_sha1_map(temp_dir, gen.sha1_map) + + if phase in ('2', 'all'): + if not output_dir: + print("[错误] 阶段二需要指定 --output 目录") + sys.exit(1) + if not os.path.exists(temp_dir): + print(f"[错误] 声明目录不存在,请先运行阶段一: {temp_dir}") + sys.exit(1) + if isinstance(src, list): + print("[错误] 阶段二需要指定源目录,不支持文件列表") + sys.exit(1) + linker_cmd = resolved.get('linker', {}).get('cmd') + linker_flags = resolved.get('linker', {}).get('flags', []) + linker_output = resolved.get('linker', {}).get('output') + target_triple = resolved.get('target', {}).get('triple') + target_datalayout = resolved.get('target', {}).get('datalayout') + startup = resolved.get('options', {}).get('startup') + trans = Phase2Translator(src, temp_dir, output_dir, compile_cmd=cc_cmd, compile_flags=cc_flags, linker_cmd=linker_cmd, linker_flags=linker_flags, linker_output=linker_output, include_dirs=project_include_dirs, target_triple=target_triple, target_datalayout=target_datalayout, startup=startup) + trans.sha1_map = Load_sha1_map(temp_dir) + trans.slice_level = slice_level + trans.run() diff --git a/lib/Projectrans/DeclarationGenerator.py b/lib/Projectrans/DeclarationGenerator.py new file mode 100644 index 0000000..49ad2f9 --- /dev/null +++ b/lib/Projectrans/DeclarationGenerator.py @@ -0,0 +1,747 @@ +import ast +from typing import List +from lib.includes import t + + +class DeclarationGenerator: + """从 .pyi AST 生成纯 LLVM IR 声明(不使用字符串操作)""" + + def __init__(self, struct_names=None, enum_names=None, module_sha1=None, target_triple=None, target_datalayout=None, struct_sha1_map=None, exception_names=None, typedef_map=None): + import llvmlite.ir as ir + self.ir = ir + self.module = None + self.builder = None + self._DefineConstants = {} + self.struct_names = struct_names or set() + self.enum_names = enum_names or set() + self.module_sha1 = module_sha1 + self.struct_sha1_map = struct_sha1_map or {} + self.exception_names = exception_names or set() + self.target_triple = target_triple or "x86_64-none-elf" + self.target_datalayout = target_datalayout or "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + self.typedef_map = typedef_map or {} + t.configure_platform(self.target_triple) + + def generate(self, pyi_content: str, src_path: str) -> str: + import ast + tree = ast.parse(pyi_content) + + self._DefineConstants = {} + self._pyi_tree = tree + global_typedef_map = self.typedef_map + self.typedef_map = {} + if global_typedef_map: + self.typedef_map.update(global_typedef_map) + for node in ast.iter_child_nodes(tree): + if isinstance(node, ast.AnnAssign) and isinstance(node.target, ast.Name): + var_name = node.target.id + if node.value and isinstance(node.value, ast.Constant): + self._DefineConstants[var_name] = node.value.value + elif node.value and isinstance(node.value, ast.Name): + self._DefineConstants[var_name] = node.value.id + is_typedef = False + if isinstance(node.annotation, ast.Attribute) and hasattr(node.annotation, 'attr') and node.annotation.attr == 'CTypedef': + is_typedef = True + elif isinstance(node.annotation, ast.Name) and node.annotation.id == 'CTypedef': + is_typedef = True + elif isinstance(node.annotation, ast.BinOp) and isinstance(node.annotation.left, ast.Attribute) and hasattr(node.annotation.left, 'attr') and node.annotation.left.attr == 'CTypedef': + is_typedef = True + if is_typedef: + if node.value: + self.typedef_map[var_name] = node.value + elif isinstance(node.annotation, ast.BinOp) and node.annotation.right: + self.typedef_map[var_name] = node.annotation.right + + lines = [] + lines.append('; ModuleID = "transpyc_decl"') + lines.append(f'target triple = "{self.target_triple}"') + lines.append(f'target datalayout = "{self.target_datalayout}"') + lines.append('') + + for node in ast.iter_child_nodes(tree): + if isinstance(node, ast.FunctionDef): + if hasattr(node, 'type_params') and node.type_params: + continue + decl = self._generate_func_decl(node) + if decl: + lines.append(decl) + elif isinstance(node, ast.AnnAssign): + decl = self._generate_global_decl(node) + if decl: + lines.append(decl) + elif isinstance(node, ast.Assign): + decl = self._generate_global_assign_decl(node) + if decl: + lines.append(decl) + elif isinstance(node, ast.ClassDef): + if hasattr(node, 'type_params') and node.type_params: + continue + decls = self._generate_class_decl(node) + lines.extend(decls) + + return '\n'.join(lines) + + def _generate_func_decl(self, node: ast.FunctionDef) -> str: + """生成函数声明""" + func_name = node.name + is_export = self._is_export_func(node) + if self.module_sha1 and not is_export: + func_name = f"{self.module_sha1}.{func_name}" + CReturnTypes = [] + if node.decorator_list: + for decorator in node.decorator_list: + if isinstance(decorator, ast.Call) and isinstance(decorator.func, ast.Attribute): + if decorator.func.attr == 'CReturn': + for arg in decorator.args: + CReturnTypes.append(arg) + if node.returns: + if isinstance(node.returns, ast.Subscript) and isinstance(node.returns.value, ast.Name) and node.returns.value.id == 'tuple': + slice_node = node.returns.slice + if isinstance(slice_node, ast.Tuple): + for elt in slice_node.elts: + CReturnTypes.append(elt) + else: + CReturnTypes.append(slice_node) + if CReturnTypes: + elem_types = [self._get_type_str(rt, embedded=True) for rt in CReturnTypes] + ret_type = '{ ' + ', '.join(elem_types) + ' }' + else: + ret_type = self._get_type_str(node.returns) + if not ret_type or ret_type == 'void': + ret_type = 'void' + elif ret_type == 'i8*': + if node.returns is None: + ret_type = 'void' + + params = [] + for arg in node.args.args: + if arg.annotation: + arg_type = self._get_type_str(arg.annotation) + else: + arg_type = 'i8*' + if arg_type and arg_type != 'void': + params.append(arg_type) + + param_str = ', '.join(params) if params else '' + if node.args.vararg: + param_str = param_str + ', ...' if param_str else '...' + if func_name[0].isdigit(): + return f'declare {ret_type} @"{func_name}"({param_str})' + return f'declare {ret_type} @{func_name}({param_str})' + + def _is_export_func(self, node: ast.FunctionDef) -> bool: + """检查函数是否标记为 CExport""" + if not node.returns: + return False + return self._check_annotation_for_export(node.returns) + + def _check_annotation_for_export(self, annotation) -> bool: + """递归检查类型注解中是否包含 CExport 或 t.State""" + if isinstance(annotation, ast.Attribute): + if hasattr(annotation, 'attr') and annotation.attr in ('CExport', 'State'): + return True + elif isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr): + return self._check_annotation_for_export(annotation.left) or self._check_annotation_for_export(annotation.right) + elif isinstance(annotation, ast.Name): + return annotation.id in ('CExport', 'State') + return False + + def _generate_global_decl(self, node: ast.AnnAssign) -> str: + """生成全局变量声明""" + if not isinstance(node.target, ast.Name): + return None + var_name = node.target.id + if isinstance(node.annotation, ast.Attribute) and hasattr(node.annotation, 'attr') and node.annotation.attr == 'CDefine': + return None + if isinstance(node.annotation, ast.Attribute) and hasattr(node.annotation, 'attr') and node.annotation.attr == 'CTypedef': + return None + if isinstance(node.annotation, ast.Name) and node.annotation.id == 'CTypedef': + return None + if isinstance(node.annotation, ast.BinOp) and isinstance(node.annotation.left, ast.Attribute) and hasattr(node.annotation.left, 'attr') and node.annotation.left.attr == 'CTypedef': + return None + if isinstance(node.annotation, ast.List): + for elt in node.annotation.elts: + if isinstance(elt, ast.Attribute) and hasattr(elt, 'attr') and elt.attr in ('CTypedef', 'Callable'): + return None + if isinstance(elt, ast.Subscript) and isinstance(elt.value, ast.Attribute) and isinstance(elt.value.value, ast.Name) and elt.value.value.id == 't' and elt.value.attr == 'Callable': + return None + VarType = self._get_type_str(node.annotation) + if VarType.startswith('[0 x ') and node.value and isinstance(node.value, ast.List): + elem_type = VarType[5:-1] + actual_count = len(node.value.elts) + if actual_count > 0: + VarType = f'[{actual_count} x {elem_type}]' + return f'@{var_name} = external global {VarType}' + + def _generate_global_assign_decl(self, node: ast.Assign) -> str: + """从无类型标注赋值推断并生成全局变量声明""" + if not node.targets or not isinstance(node.targets[0], ast.Name): + return None + var_name = node.targets[0].id + VarType = self._infer_type(node.value) + if VarType: + return f'@{var_name} = external global {VarType}' + return None + + def _generate_class_decl(self, node: ast.ClassDef) -> List[str]: + """生成结构体/类声明""" + decls = [] + class_name = node.name + is_enum = False + is_exception = False + if node.bases: + for base in node.bases: + if isinstance(base, ast.Attribute) and hasattr(base, 'attr'): + if base.attr == 'CEnum' or base.attr == 'Enum': + is_enum = True + break + elif base.attr == 'Exception' or base.attr in self.exception_names: + is_exception = True + break + elif isinstance(base, ast.Name) and hasattr(base, 'id'): + if base.id == 'CEnum' or base.id == 'Enum': + is_enum = True + break + elif base.id == 'Exception' or base.id in self.exception_names: + is_exception = True + break + if is_exception: + return decls + if is_enum: + enum_values = {} + next_value = 0 + for item in node.body: + if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name): + var_name = item.target.id + if item.value and isinstance(item.value, ast.Constant) and isinstance(item.value.value, int): + enum_values[var_name] = item.value.value + else: + enum_values[var_name] = next_value + next_value += 1 + elif isinstance(item, ast.Assign) and len(item.targets) == 1 and isinstance(item.targets[0], ast.Name): + var_name = item.targets[0].id + if item.value and isinstance(item.value, ast.Constant) and isinstance(item.value.value, int): + enum_values[var_name] = item.value.value + next_value = item.value.value + 1 + else: + enum_values[var_name] = next_value + next_value += 1 + for var_name, value in enum_values.items(): + decls.append(f'@__config_{class_name}_{var_name} = external global i32') + return decls + member_types = [] + has_bitfield = False + total_bits = 0 + has_methods = any(isinstance(item, ast.FunctionDef) for item in node.body) + is_cvtable = False + is_cpython_object = False + if hasattr(node, 'decorator_list') and node.decorator_list: + for decorator in node.decorator_list: + if isinstance(decorator, ast.Attribute): + if getattr(decorator.value, 'id', None) == 't': + if decorator.attr == 'CVTable': + is_cvtable = True + elif decorator.attr == 'Object': + is_cpython_object = True + elif isinstance(decorator, ast.Name): + if decorator.id == 'CVTable': + is_cvtable = True + elif decorator.id == 'Object': + is_cpython_object = True + if has_methods and not is_cpython_object: + is_cpython_object = True + has_parent_class = False + for base in node.bases: + base_name = None + if isinstance(base, ast.Attribute): + base_name = base.attr + elif isinstance(base, ast.Name): + base_name = base.id + elif isinstance(base, ast.Subscript): + if isinstance(base.value, ast.Attribute): + base_name = base.value.attr + elif isinstance(base.value, ast.Name): + base_name = base.value.id + if base_name and base_name not in ('Object', 'CVTable', 'CEnum', 'Enum', 'CStruct', 'CUnion'): + has_parent_class = True + break + if has_parent_class and not is_cvtable: + is_cvtable = True + base_has_vtable = False + for base in node.bases: + base_name = None + if isinstance(base, ast.Attribute): + base_name = base.attr + elif isinstance(base, ast.Name): + base_name = base.id + elif isinstance(base, ast.Subscript): + if isinstance(base.value, ast.Attribute): + base_name = base.value.attr + elif isinstance(base.value, ast.Name): + base_name = base.value.id + if base_name and base_name not in ('Object', 'CVTable', 'CEnum', 'Enum', 'CStruct', 'CUnion'): + for n in ast.iter_child_nodes(self._pyi_tree): + if isinstance(n, ast.ClassDef) and n.name == base_name: + if hasattr(n, 'decorator_list') and n.decorator_list: + for dec in n.decorator_list: + if isinstance(dec, ast.Attribute) and getattr(dec.value, 'id', None) == 't' and dec.attr == 'CVTable': + base_has_vtable = True + elif isinstance(dec, ast.Name) and dec.id == 'CVTable': + base_has_vtable = True + break + if base_has_vtable: + break + if has_methods and is_cvtable and not base_has_vtable: + member_types.append('i8*') + seen_member_names = set() + for base in node.bases: + base_name = None + if isinstance(base, ast.Attribute): + base_name = base.attr + elif isinstance(base, ast.Name): + base_name = base.id + elif isinstance(base, ast.Subscript): + if isinstance(base.value, ast.Attribute): + base_name = base.value.attr + elif isinstance(base.value, ast.Name): + base_name = base.value.id + if base_name and base_name not in ('Object', 'CVTable', 'CEnum', 'Enum', 'CStruct', 'CUnion'): + base_member_types, base_seen = self._get_inherited_members(base_name) + for mt in base_member_types: + member_types.append(mt) + seen_member_names.update(base_seen) + for item in node.body: + if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name): + seen_member_names.add(item.target.id) + init_members = [] + for item in node.body: + if isinstance(item, ast.FunctionDef) and item.name == '__init__': + for stmt in item.body: + if (isinstance(stmt, ast.AnnAssign) + and isinstance(stmt.target, ast.Attribute) + and isinstance(stmt.target.value, ast.Name) + and stmt.target.value.id == 'self'): + init_members.append(stmt) + untyped_self_members = [] + for m_name in [m.attr for m in init_members if isinstance(m.target, ast.Attribute)]: + seen_member_names.add(m_name) + for item in node.body: + if isinstance(item, ast.FunctionDef): + if hasattr(item, 'type_params') and item.type_params: + continue + for stmt in item.body: + if (isinstance(stmt, ast.Assign) + and len(stmt.targets) == 1 + and isinstance(stmt.targets[0], ast.Attribute) + and isinstance(stmt.targets[0].value, ast.Name) + and stmt.targets[0].value.id == 'self'): + attr_name = stmt.targets[0].attr + if attr_name not in seen_member_names: + seen_member_names.add(attr_name) + untyped_self_members.append(stmt) + for item in list(node.body) + init_members + untyped_self_members: + if isinstance(item, ast.AnnAssign): + bit_width = self._get_bitfield_width(item.annotation) + if bit_width is not None: + has_bitfield = True + total_bits += bit_width + else: + VarType = self._get_type_str(item.annotation, embedded=True) + if (isinstance(item.annotation, ast.Subscript) + and isinstance(item.annotation.value, ast.Name) + and item.annotation.value.id == 'list'): + slice_node = item.annotation.slice + is_dynamic = False + if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2: + count_node = slice_node.elts[1] + if isinstance(count_node, ast.Constant) and count_node.value is None: + is_dynamic = True + elif not (isinstance(count_node, ast.Constant) and isinstance(count_node.value, int) and count_node.value > 0): + if not isinstance(count_node, (ast.Name, ast.BinOp)): + is_dynamic = True + elif not isinstance(slice_node, ast.Tuple): + is_dynamic = True + if is_dynamic: + elem_type = self._get_type_str(slice_node if not isinstance(slice_node, ast.Tuple) else slice_node.elts[0], embedded=True) + init_len = 0 + if isinstance(item.value, ast.List): + init_len = len(item.value.elts) + elif isinstance(item.value, ast.Constant) and isinstance(item.value.value, str): + init_len = len(item.value.value) + 1 + VarType = f'[{init_len} x {elem_type}]' + member_types.append(VarType) + elif isinstance(item, ast.Assign): + if (len(item.targets) == 1 + and isinstance(item.targets[0], ast.Attribute) + and isinstance(item.targets[0].value, ast.Name) + and item.targets[0].value.id == 'self'): + attr_name = item.targets[0].attr + if attr_name in seen_member_names: + continue + InferredType = 'i32' + if item.value and isinstance(item.value, ast.Constant): + if isinstance(item.value.value, float): + InferredType = 'float' + elif isinstance(item.value.value, bool): + InferredType = 'i8' + elif isinstance(item.value.value, str): + InferredType = 'i8*' + member_types.append(InferredType) + else: + member_types.append('i32') + if has_bitfield: + if total_bits <= 8: + member_types.insert(0, 'i8') + elif total_bits <= 16: + member_types.insert(0, 'i16') + elif total_bits <= 32: + member_types.insert(0, 'i32') + else: + member_types.insert(0, 'i64') + struct_type_name = f'%"{self.module_sha1}.{class_name}"' if self.module_sha1 else f'%struct.{class_name}' + struct_decl = f'{struct_type_name} = type {{ {", ".join(member_types)} }}' + decls.append(struct_decl) + if is_cpython_object or is_cvtable: + new_func_name = f'{class_name}.__before_init__' + if self.module_sha1: + new_func_name = f"{self.module_sha1}.{new_func_name}" + if new_func_name[0].isdigit(): + new_func_decl = f'declare void @"{new_func_name}"({struct_type_name}*)' + else: + new_func_decl = f'declare void @{new_func_name}({struct_type_name}*)' + decls.append(new_func_decl) + for item in node.body: + if isinstance(item, ast.FunctionDef): + if hasattr(item, 'type_params') and item.type_params: + continue + method_name = f'{class_name}.{item.name}' + if self.module_sha1: + method_name = f"{self.module_sha1}.{method_name}" + ret_type = self._get_type_str(item.returns) if item.returns else 'void' + if not ret_type: + ret_type = 'void' + params = [] + for arg_idx, arg in enumerate(item.args.args): + if arg.annotation: + arg_type = self._get_type_str(arg.annotation) + elif arg_idx == 0 and arg.arg == 'self': + arg_type = f'{struct_type_name}*' + else: + arg_type = 'i8*' + params.append(arg_type) + param_str = ', '.join(params) if params else '' + if method_name[0].isdigit(): + decls.append(f'declare {ret_type} @"{method_name}"({param_str})') + else: + decls.append(f'declare {ret_type} @{method_name}({param_str})') + return decls + + def _get_inherited_members(self, base_name: str): + import ast + member_types = [] + seen_names = set() + if not hasattr(self, '_pyi_tree') or self._pyi_tree is None: + return member_types, seen_names + base_node = None + for node in ast.iter_child_nodes(self._pyi_tree): + if isinstance(node, ast.ClassDef) and node.name == base_name: + base_node = node + break + if base_node is None: + return member_types, seen_names + base_decls = self._generate_class_decl(base_node) + for decl in base_decls: + if '= type {' in decl: + type_body = decl.split('= type {')[1].rstrip('}').strip() + if type_body: + for t in type_body.split(','): + t = t.strip() + if t: + member_types.append(t) + break + for item in base_node.body: + if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name): + seen_names.add(item.target.id) + elif isinstance(item, ast.Assign) and len(item.targets) == 1: + if isinstance(item.targets[0], ast.Attribute) and isinstance(item.targets[0].value, ast.Name) and item.targets[0].value.id == 'self': + seen_names.add(item.targets[0].attr) + for item in base_node.body: + if isinstance(item, ast.FunctionDef) and item.name == '__init__': + for stmt in item.body: + if isinstance(stmt, ast.AnnAssign) and isinstance(stmt.target, ast.Attribute) and isinstance(stmt.target.value, ast.Name) and stmt.target.value.id == 'self': + seen_names.add(stmt.target.attr) + elif isinstance(stmt, ast.Assign) and len(stmt.targets) == 1 and isinstance(stmt.targets[0], ast.Attribute) and isinstance(stmt.targets[0].value, ast.Name) and stmt.targets[0].value.id == 'self': + seen_names.add(stmt.targets[0].attr) + return member_types, seen_names + + @staticmethod + def _ctype_name_to_llvm(name: str) -> str: + """根据 CType 元属性自动推导 LLVM IR 类型 + + 通过 CTypeRegistry.NameToLLVM 查询,利用 CType 的 + position/IsSigned/Size 元属性自动推导,无需手动映射表。 + """ + from lib.includes.t import CTypeRegistry + result = CTypeRegistry.NameToLLVM(name) + return result + + def _get_type_str(self, annotation: ast.AST, embedded: bool = False) -> str: + import ast + from lib.includes.t import CTypeRegistry + if annotation is None: + return 'i8*' + + non_struct_types = {'list', 'dict', 'tuple', 'set', 'array'} + + if isinstance(annotation, ast.Name): + if annotation.id == 'None': + return 'void' + if annotation.id in ('str', 'bytes'): + return 'i8*' + llvm_type = CTypeRegistry.NameToLLVM(annotation.id) + if llvm_type is not None: + return llvm_type + resolved = CTypeRegistry.ResolveName(annotation.id) + if resolved is not None: + ctype_cls, ptr_level = resolved + base = CTypeRegistry.CTypeToLLVM(ctype_cls) + if ptr_level > 0: + if base == 'void': + return 'i8*' + if '*' in base: + return base + return f'{base}*' + return base + if annotation.id in non_struct_types: + return 'i32' + if annotation.id in self.enum_names: + return 'i32' + if annotation.id in self.struct_names: + sha1 = self.struct_sha1_map.get(annotation.id, self.module_sha1) + sname = f'%"{sha1}.{annotation.id}"' if sha1 else f'%struct.{annotation.id}' + if embedded: + return sname + else: + return f'{sname}*' + if annotation.id in self.typedef_map: + resolved = self._get_type_str(self.typedef_map[annotation.id], embedded=embedded) + return resolved + sha1 = self.struct_sha1_map.get(annotation.id, self.module_sha1) + sname = f'%"{sha1}.{annotation.id}"' if sha1 else f'%struct.{annotation.id}' + return f'{sname}*' + elif isinstance(annotation, ast.Attribute): + attr_name = annotation.attr if hasattr(annotation, 'attr') else '' + module_name = '' + if hasattr(annotation, 'value'): + if isinstance(annotation.value, ast.Name): + module_name = annotation.value.id + elif isinstance(annotation.value, ast.Attribute) and hasattr(annotation.value, 'attr'): + module_name = annotation.value.attr + if (module_name == 't' and attr_name == 'State') or attr_name == 'State': + return '' + if (module_name == 't' and attr_name == 'Callable') or attr_name == 'Callable': + return 'i8*' + llvm_type = CTypeRegistry.NameToLLVM(attr_name) + if llvm_type is not None: + return llvm_type + resolved = CTypeRegistry.ResolveName(attr_name) + if resolved is not None: + ctype_cls, ptr_level = resolved + base = CTypeRegistry.CTypeToLLVM(ctype_cls) + if ptr_level > 0: + if base == 'void': + return 'i8*' + if '*' in base: + return base + return f'{base}*' + return base + if attr_name in self.typedef_map: + return self._get_type_str(self.typedef_map[attr_name], embedded=embedded) + if attr_name in self.enum_names: + return 'i32' + if attr_name in self.struct_names: + sha1 = self.struct_sha1_map.get(attr_name, self.module_sha1) + sname = f'%"{sha1}.{attr_name}"' if sha1 else f'%struct.{attr_name}' + if embedded: + return sname + else: + return f'{sname}*' + if attr_name and attr_name[0].isupper() and attr_name not in non_struct_types: + sha1 = self.struct_sha1_map.get(attr_name, self.module_sha1) + sname = f'%"{sha1}.{attr_name}"' if sha1 else f'%struct.{attr_name}' + return f'{sname}*' + if attr_name and attr_name not in non_struct_types: + sha1 = self.struct_sha1_map.get(attr_name, self.module_sha1) + sname = f'%"{sha1}.{attr_name}"' if sha1 else f'%struct.{attr_name}' + return f'{sname}*' + return 'i32' + elif isinstance(annotation, ast.BinOp): + left_type = self._get_type_str(annotation.left, embedded=embedded) + right_type = self._get_type_str(annotation.right, embedded=embedded) + if left_type in ('', 'void'): + return right_type if right_type not in ('', 'void') else (left_type or right_type) + if right_type in ('', 'void'): + return left_type + if '*' in left_type: + return left_type + if '*' in right_type: + if right_type == 'i8*': + return self._type_to_llvm_ptr(left_type) + return right_type + return left_type + elif isinstance(annotation, ast.Subscript): + base = self._get_type_str(annotation.value) + if base == 'i8*' and isinstance(annotation.slice, ast.Constant): + return f'[{self._get_const_int(annotation.slice)} x i8]' + if isinstance(annotation.slice, ast.Constant) and isinstance(annotation.slice.value, int): + return f'[{annotation.slice.value} x {base}]' + if isinstance(annotation.value, ast.Name) and annotation.value.id == 'list': + slice_node = annotation.slice + if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2: + elem_type = self._get_type_str(slice_node.elts[0], embedded=True) + count_node = slice_node.elts[1] + array_count = self._get_const_int(count_node) + if array_count > 0: + return f'[{array_count} x {elem_type}]' + else: + return f'[0 x {elem_type}]' + elem_type = self._get_type_str(slice_node, embedded=True) + return f'[0 x {elem_type}]' + if isinstance(annotation.value, ast.Name) and annotation.value.id == 'tuple': + slice_node = annotation.slice + if isinstance(slice_node, ast.Tuple): + elem_types = [self._get_type_str(e, embedded=True) for e in slice_node.elts] + else: + elem_types = [self._get_type_str(slice_node, embedded=True)] + return '{ ' + ', '.join(elem_types) + ' }' + return f'{base}' + elif isinstance(annotation, ast.Constant): + if annotation.value is None: + return 'void' + if isinstance(annotation.value, int): + return 'i32' + if isinstance(annotation.value, str): + type_name = annotation.value + if type_name in self.enum_names: + return 'i32' + if type_name in self.struct_names: + sha1 = self.struct_sha1_map.get(type_name, self.module_sha1) + sname = f'%"{sha1}.{type_name}"' if sha1 else f'%struct.{type_name}' + if embedded: + return sname + else: + return f'{sname}*' + llvm_type = CTypeRegistry.NameToLLVM(type_name) + if llvm_type is not None: + return llvm_type + resolved = CTypeRegistry.ResolveName(type_name) + if resolved is not None: + ctype_cls, ptr_level = resolved + base = CTypeRegistry.CTypeToLLVM(ctype_cls) + if ptr_level > 0: + if base == 'void': + return 'i8*' + if '*' in base: + return base + return f'{base}*' + return base + sha1 = self.struct_sha1_map.get(type_name, self.module_sha1) + sname = f'%"{sha1}.{type_name}"' if sha1 else f'%struct.{type_name}' + return f'{sname}*' + return 'i8*' + elif isinstance(annotation, ast.Call): + if isinstance(annotation.func, ast.Name) and annotation.func.id == 'callable': + return 'i8*' + if isinstance(annotation.func, ast.Attribute) and annotation.func.attr == 'Callable': + return 'i8*' + return 'i32' + + def _type_to_llvm_ptr(self, type_str: str) -> str: + if type_str.startswith('%struct.') and not type_str.endswith('*'): + return type_str + '*' + if type_str.startswith('%') and not type_str.endswith('*'): + return type_str + '*' + if type_str.endswith('*'): + return type_str + from lib.includes.t import CTypeRegistry + resolved = CTypeRegistry.ResolveName(type_str) + if resolved is not None: + ctype_cls, ptr_level = resolved + llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls) + if llvm_str: + return f'{llvm_str}{"*" * (ptr_level + 1)}' + cnameres = CTypeRegistry.CNameToClass(type_str) + if cnameres is not None: + llvm_str = CTypeRegistry.CTypeToLLVM(cnameres) + if llvm_str: + return f'{llvm_str}*' + return f'{type_str}*' + + def _infer_type(self, value: ast.AST) -> str: + """从值推断类型""" + import ast + if isinstance(value, ast.Constant): + if isinstance(value.value, int): + return 'i32' + elif isinstance(value.value, float): + return 'double' + elif isinstance(value.value, str): + return 'i8*' + elif isinstance(value.value, bool): + return 'i8' + elif isinstance(value, ast.List): + return 'i8*' + elif isinstance(value, ast.Dict): + return 'i8*' + elif isinstance(value, ast.Name): + return 'i32' + elif isinstance(value, ast.BinOp): + return self._infer_type(value.left) + elif isinstance(value, ast.Call): + return 'i8*' + return 'i32' + + def _get_bitfield_width(self, annotation: ast.AST): + import ast + if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr): + right_width = self._get_bitfield_width(annotation.right) + if right_width is not None: + return right_width + return self._get_bitfield_width(annotation.left) + if isinstance(annotation, ast.Call): + if isinstance(annotation.func, ast.Attribute) and annotation.func.attr == 'Bit': + if annotation.args: + arg = annotation.args[0] + if isinstance(arg, ast.Constant) and isinstance(arg.value, int): + return arg.value + if isinstance(annotation, ast.Subscript): + if isinstance(annotation.value, ast.Attribute) and annotation.value.attr == 'Bit': + if isinstance(annotation.slice, ast.Constant) and isinstance(annotation.slice.value, int): + return annotation.slice.value + return None + + def _get_const_int(self, node: ast.AST) -> int: + """获取常量整数值,支持符号常量和简单表达式""" + import ast + if isinstance(node, ast.Constant) and isinstance(node.value, int): + return node.value + if isinstance(node, ast.Name): + if node.id in self._DefineConstants: + val = self._DefineConstants[node.id] + if isinstance(val, int): + return val + if isinstance(node, ast.BinOp): + left_val = self._get_const_int(node.left) + right_val = self._get_const_int(node.right) + if left_val and right_val: + if isinstance(node.op, ast.Add): + return left_val + right_val + if isinstance(node.op, ast.Sub): + return left_val - right_val + if isinstance(node.op, ast.Mult): + return left_val * right_val + if isinstance(node.op, ast.Div): + return left_val // right_val + if isinstance(node.op, ast.FloorDiv): + return left_val // right_val + return 0 diff --git a/lib/Projectrans/Phase1Generator.py b/lib/Projectrans/Phase1Generator.py new file mode 100644 index 0000000..bc3319e --- /dev/null +++ b/lib/Projectrans/Phase1Generator.py @@ -0,0 +1,338 @@ +import os +import ast +import traceback +from lib.Projectrans.Utils import compute_sha1, get_file_dependencies, find_reachable_files_from_entries +from lib.Projectrans.DeclarationGenerator import DeclarationGenerator +from StubGen import PythonToStubConverter + + +class Phase1Generator: + """阶段一:从源文件生成声明接口""" + + def __init__(self, src_root: str, temp_dir: str, include_dirs: list = None, entry_files: list = None, target_triple: str = None, target_datalayout: str = None): + self.src_root = os.path.abspath(src_root) + self.temp_dir = os.path.abspath(temp_dir) + self.include_dirs = include_dirs or [] + self.sha1_map: dict[str, str] = {} + self.include_py_map: dict[str, str] = {} + self.entry_files = entry_files + self.target_triple = target_triple + self.target_datalayout = target_datalayout + os.makedirs(self.temp_dir, exist_ok=True) + + def _get_needed_include_files(self, reachable_source_files: set) -> list: + """从可达源文件收集所有被引用(含传递依赖)的 include 文件""" + include_file_map = {} + for includes_dir in self.include_dirs: + if not os.path.isdir(includes_dir): + continue + for root, dirs, files in os.walk(includes_dir): + dirs[:] = [d for d in dirs if not d.startswith('.') and d != '__pycache__'] + for fname in files: + if fname.endswith('.py') or fname.endswith('.pyi'): + src_path = os.path.join(root, fname) + rel_from_inc = os.path.relpath(src_path, includes_dir) + ModulePath = rel_from_inc.replace(os.sep, '.').replace('/', '.') + module_name = os.path.splitext(ModulePath)[0] + info = (src_path, rel_from_inc, includes_dir) + include_file_map[module_name] = info + top_pkg = module_name.split('.')[0] + if top_pkg not in include_file_map: + include_file_map[top_pkg] = info + + imported_from_src = set() + for src_path in reachable_source_files: + deps = get_file_dependencies(src_path, self.src_root) + imported_from_src.update(deps) + + needed = set() + queue = list(imported_from_src) + while queue: + mod_name = queue.pop(0) + if mod_name in needed: + continue + if mod_name in include_file_map: + needed.add(mod_name) + src_path = include_file_map[mod_name][0] + includes_dir = include_file_map[mod_name][2] + deps = get_file_dependencies(src_path, includes_dir) + for dep in deps: + if dep in include_file_map and dep not in needed: + queue.append(dep) + + needed_infos = [] + for mod_name in sorted(needed): + if mod_name in include_file_map: + info = include_file_map[mod_name] + if info not in needed_infos: + needed_infos.append(info) + + return needed_infos + + def run(self): + """扫描源目录,只处理入口文件可达的 .py 文件(导入遍历)""" + if self.entry_files: + py_files = list(self.entry_files) + else: + main_py = os.path.join(self.src_root, 'main.py') + if os.path.exists(main_py): + py_files = [main_py] + else: + py_files = [] + for root, dirs, files in os.walk(self.src_root): + dirs[:] = [d for d in dirs if d not in ('__pycache__',)] + for file in files: + if file.endswith('.py'): + py_files.append(os.path.join(root, file)) + + if not py_files: + print("[阶段一] 未找到入口文件或源文件") + return + + if self.entry_files: + reachable = find_reachable_files_from_entries(self.src_root, py_files) + else: + reachable = find_reachable_files_from_entries(self.src_root, py_files) + + print(f"[阶段一] 找到 {len(reachable)} 个可达源文件(从入口遍历)") + + for i, src_path in enumerate(sorted(reachable), 1): + rel = os.path.relpath(src_path, self.src_root) + print(f"[{i}/{len(reachable)}] 生成签名: {rel}") + try: + self._process_file_pyi(src_path, rel) + except Exception as e: + print(f" [错误] {e}") + traceback.print_exc() + + needed_includes = self._get_needed_include_files(reachable) + self._process_include_py_files_pyi(needed_includes) + + struct_names, enum_names, struct_sha1_map, exception_names = self._build_struct_registry() + print(f"\n[阶段一] 结构体注册表: {len(struct_names)} 个类型, {len(enum_names)} 个枚举") + for name in sorted(struct_names): + print(f" {name}") + + for i, src_path in enumerate(sorted(reachable), 1): + rel = os.path.relpath(src_path, self.src_root) + try: + self._process_file_stub(src_path, rel, struct_names, enum_names=enum_names, struct_sha1_map=struct_sha1_map, exception_names=exception_names) + except Exception as e: + print(f" [错误] {e}") + traceback.print_exc() + + self._process_include_py_files_stub(struct_names, needed_includes, enum_names=enum_names, struct_sha1_map=struct_sha1_map, exception_names=exception_names) + + print(f"\n[阶段一完成] 声明接口生成到: {self.temp_dir}") + print(f"SHA1 映射表 ({len(self.sha1_map)} 个文件):") + for sha1, rel in sorted(self.sha1_map.items()): + print(f" {sha1} -> {rel}") + + def _collect_include_py_files(self): + include_py_files = [] + for includes_dir in self.include_dirs: + if not os.path.isdir(includes_dir): + continue + for root, dirs, files in os.walk(includes_dir): + dirs[:] = [d for d in dirs if not d.startswith('.') and d != '__pycache__'] + for fname in files: + if fname.endswith('.py') or fname.endswith('.pyi'): + src_path = os.path.join(root, fname) + rel_from_inc = os.path.relpath(src_path, includes_dir) + include_py_files.append((src_path, rel_from_inc, includes_dir)) + return include_py_files + + def _process_include_py_files_pyi(self, needed_includes: list = None): + if needed_includes is not None: + include_py_files = needed_includes + else: + include_py_files = self._collect_include_py_files() + if not include_py_files: + return + print(f"\n[阶段一-includes] 处理 {len(include_py_files)} 个被引用的 Python 库文件") + for src_path, rel_from_inc, includes_dir in include_py_files: + ModulePath = rel_from_inc.replace(os.sep, '.').replace('/', '.') + module_name = os.path.splitext(ModulePath)[0] + try: + with open(src_path, 'r', encoding='utf-8') as f: + content = f.read() + sha1 = compute_sha1(content) + self.sha1_map[sha1] = f"includes/{rel_from_inc}" + top_module = rel_from_inc.split(os.sep)[0].split('/')[0] + if top_module not in self.include_py_map: + self.include_py_map[top_module] = sha1 + self.include_py_map[module_name] = sha1 + + sig_path = os.path.join(self.temp_dir, f"{sha1}.pyi") + if os.path.isfile(sig_path): + print(f" 缓存命中: {rel_from_inc} -> {sha1}.pyi") + continue + + sig_content = PythonToStubConverter.convert(content, module_name) + with open(sig_path, 'w', encoding='utf-8', newline='\n') as f: + f.write(sig_content) + print(f" 生成签名: {rel_from_inc} -> {sha1}.pyi") + except Exception as e: + print(f" [错误] {rel_from_inc}: {e}") + + def _collect_typedef_map(self): + import ast as _ast + typedef_map = {} + if not os.path.isdir(self.temp_dir): + return typedef_map + for fname in os.listdir(self.temp_dir): + if not fname.endswith('.pyi'): + continue + pyi_path = os.path.join(self.temp_dir, fname) + try: + with open(pyi_path, 'r', encoding='utf-8') as f: + content = f.read() + tree = _ast.parse(content) + for node in _ast.iter_child_nodes(tree): + if isinstance(node, _ast.AnnAssign) and isinstance(node.target, _ast.Name): + var_name = node.target.id + is_typedef = False + if isinstance(node.annotation, _ast.Attribute) and hasattr(node.annotation, 'attr') and node.annotation.attr == 'CTypedef': + is_typedef = True + elif isinstance(node.annotation, _ast.Name) and node.annotation.id == 'CTypedef': + is_typedef = True + elif isinstance(node.annotation, _ast.BinOp) and isinstance(node.annotation.left, _ast.Attribute) and hasattr(node.annotation.left, 'attr') and node.annotation.left.attr == 'CTypedef': + is_typedef = True + if is_typedef and node.value and var_name not in typedef_map: + typedef_map[var_name] = node.value + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _ConfigMode + if _ConfigMode == "strict": + raise + _vlog().warning(f"收集 typedef 映射失败: {_e}", "Exception") + return typedef_map + + def _process_include_py_files_stub(self, struct_names: set, needed_includes: list = None, enum_names: set = None, struct_sha1_map: dict = None, exception_names: set = None): + if needed_includes is not None: + include_py_files = needed_includes + else: + include_py_files = self._collect_include_py_files() + if not include_py_files: + return + typedef_map = self._collect_typedef_map() + for src_path, rel_from_inc, includes_dir in include_py_files: + ModulePath = rel_from_inc.replace(os.sep, '.').replace('/', '.') + module_name = os.path.splitext(ModulePath)[0] + try: + with open(src_path, 'r', encoding='utf-8') as f: + content = f.read() + sha1 = compute_sha1(content) + + stub_path = os.path.join(self.temp_dir, f"{sha1}.stub.ll") + if os.path.isfile(stub_path): + print(f" 缓存命中: {rel_from_inc} -> {sha1}.stub.ll") + continue + + sig_path = os.path.join(self.temp_dir, f"{sha1}.pyi") + with open(sig_path, 'r', encoding='utf-8') as f: + sig_content = f.read() + + self._generate_decl_ll(sig_content, stub_path, src_path, struct_names, enum_names=enum_names, module_sha1=sha1, struct_sha1_map=struct_sha1_map, exception_names=exception_names, typedef_map=typedef_map) + print(f" 生成声明: {rel_from_inc} -> {sha1}.stub.ll") + except Exception as e: + print(f" [错误] {rel_from_inc}: {e}") + + def _process_file_pyi(self, src_path: str, rel_path: str): + with open(src_path, 'r', encoding='utf-8') as f: + content = f.read() + + sha1 = compute_sha1(content) + self.sha1_map[sha1] = rel_path + + sig_path = os.path.join(self.temp_dir, f"{sha1}.pyi") + if os.path.isfile(sig_path): + print(f" -> {sha1}.pyi (缓存)") + return + + module_name = os.path.splitext(rel_path)[0].replace(os.sep, '.').replace('/', '.') + sig_content = PythonToStubConverter.convert(content, module_name) + with open(sig_path, 'w', encoding='utf-8', newline='\n') as f: + f.write(sig_content) + print(f" -> {sha1}.pyi (签名)") + + def _process_file_stub(self, src_path: str, rel_path: str, struct_names: set, enum_names: set = None, struct_sha1_map: dict = None, exception_names: set = None): + with open(src_path, 'r', encoding='utf-8') as f: + content = f.read() + + sha1 = compute_sha1(content) + stub_path = os.path.join(self.temp_dir, f"{sha1}.stub.ll") + if os.path.isfile(stub_path): + print(f" -> {sha1}.stub.ll (缓存)") + return + + sig_path = os.path.join(self.temp_dir, f"{sha1}.pyi") + with open(sig_path, 'r', encoding='utf-8') as f: + sig_content = f.read() + + typedef_map = self._collect_typedef_map() + self._generate_decl_ll(sig_content, stub_path, src_path, struct_names, enum_names=enum_names, module_sha1=sha1, struct_sha1_map=struct_sha1_map, exception_names=exception_names, typedef_map=typedef_map) + print(f" -> {sha1}.stub.ll (声明)") + + def _build_struct_registry(self): + struct_names = set() + enum_names = set() + exception_names = set() + struct_sha1_map = {} + valid_sha1_keys = set(self.sha1_map.keys()) + for fname in os.listdir(self.temp_dir): + if not fname.endswith('.pyi'): + continue + sha1_key = fname.replace('.pyi', '') + if sha1_key not in valid_sha1_keys: + continue + pyi_path = os.path.join(self.temp_dir, fname) + try: + with open(pyi_path, 'r', encoding='utf-8') as f: + content = f.read() + tree = ast.parse(content) + for node in ast.iter_child_nodes(tree): + if isinstance(node, ast.ClassDef): + is_enum = False + is_exception = False + if node.bases: + for base in node.bases: + if isinstance(base, ast.Attribute) and hasattr(base, 'attr'): + if base.attr in ('CEnum', 'Enum'): + is_enum = True + break + elif base.attr == 'Exception' or base.attr in exception_names: + is_exception = True + break + elif isinstance(base, ast.Name) and hasattr(base, 'id'): + if base.id in ('CEnum', 'Enum'): + is_enum = True + break + elif base.id == 'Exception' or base.id in exception_names: + is_exception = True + break + if is_enum: + enum_names.add(node.name) + elif is_exception: + exception_names.add(node.name) + else: + struct_names.add(node.name) + struct_sha1_map[node.name] = sha1_key + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _ConfigMode + if _ConfigMode == "strict": + raise + _vlog().warning(f"构建结构体/枚举注册表失败: {_e}", "Exception") + return struct_names, enum_names, struct_sha1_map, exception_names + + def _generate_decl_ll(self, pyi_content: str, ll_path: str, src_path: str, struct_names: set = None, enum_names: set = None, module_sha1: str = None, struct_sha1_map: dict = None, exception_names: set = None, typedef_map: dict = None): + try: + decl_gen = DeclarationGenerator(struct_names=struct_names, enum_names=enum_names, module_sha1=module_sha1, target_triple=self.target_triple, target_datalayout=self.target_datalayout, struct_sha1_map=struct_sha1_map, exception_names=exception_names, typedef_map=typedef_map) + decl_ll = decl_gen.generate(pyi_content, src_path) + with open(ll_path, 'w', encoding='utf-8', newline='\n') as f: + f.write(decl_ll) + except Exception as e: + print(f" [警告] .ll 声明生成失败: {e}") + with open(ll_path, 'w', encoding='utf-8') as f: + f.write(f"; declaration for {os.path.basename(src_path)}\n; error: {e}\n") diff --git a/lib/Projectrans/Phase2Translator.py b/lib/Projectrans/Phase2Translator.py new file mode 100644 index 0000000..61d7eab --- /dev/null +++ b/lib/Projectrans/Phase2Translator.py @@ -0,0 +1,2423 @@ +import sys +import os +import re +import shutil +import subprocess +import ast +import traceback +import json +from lib.core.Handles.HandlesBase import CTypeInfo +from lib.includes import t +from lib.Projectrans.Utils import compute_sha1, _check_annotation_for_export, find_reachable_files_from_entries, topological_sort_files +import TransPyC +from StubGen import PythonToStubConverter + + +def _parallel_translate_worker(src_path, out_path, src_root, temp_dir, output_dir, + include_dirs, triple, datalayout, sha1_map, sig_files, + stub_files, include_py_map, slice_level, + shared_sym_pickle_path, struct_sha1_map): + try: + import pickle + from lib.Projectrans import Phase2Translator + from lib.Projectrans.Utils import compute_sha1 + trans = Phase2Translator(src_root, temp_dir, output_dir, + compile_cmd='llc', include_dirs=include_dirs, + target_triple=triple, target_datalayout=datalayout) + trans.sha1_map = sha1_map + trans.sig_files = sig_files + trans.stub_files = stub_files + trans.include_py_map = include_py_map + trans.slice_level = slice_level + trans.struct_sha1_map = struct_sha1_map + + if shared_sym_pickle_path and os.path.exists(shared_sym_pickle_path): + with open(shared_sym_pickle_path, 'rb') as f: + shared_data = pickle.load(f) + trans._shared_symbol_table = shared_data['symbol_table'] + trans._shared_source_module_sig_files = shared_data['source_module_sig_files'] + trans._shared_all_dc = shared_data['all_dc'] + trans._shared_export_extern_funcs = shared_data['export_extern_funcs'] + trans.inline_func_symbols = shared_data['inline_func_symbols'] + trans.function_default_args = shared_data['function_default_args'] + trans._shared_generic_class_templates = shared_data.get('generic_class_templates', {}) + else: + trans._precollect_inline_symbols() + trans._build_shared_symbol_data() + + trans._translate_file(src_path, out_path) + return ('ok', src_path, '') + except Exception as e: + import traceback + return ('error', src_path, f'{e}\n{traceback.format_exc()}') # limit + + +class Phase2Translator: + """阶段二:使用声明接口翻译源文件""" + + INCLUDE_LIB_EXTENSIONS = ('.dll', '.ll', '.so', '.o', '.a', '.lib') + INCLUDE_SRC_EXTENSIONS = ('.c', '.cpp', '.cc', '.cxx', '.m', '.mm') + INCLUDE_DIRS = [ + os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), 'includes'), + r"d:\Users\TermiNexus\Desktop\TransPyC\includes", + ] + + def __init__(self, src_root: str, temp_dir: str, output_dir: str, compile_cmd: str = 'llc', compile_flags: list = None, linker_cmd: str = None, linker_flags: list = None, linker_output: str = None, include_dirs: list = None, entry_files: list = None, target_triple: str = None, target_datalayout: str = None, startup=None): + self.src_root = os.path.abspath(src_root) + self.temp_dir = os.path.abspath(temp_dir) + self.output_dir = os.path.abspath(output_dir) + self.compile_cmd = compile_cmd + self.compile_flags = compile_flags or ['-filetype=obj'] + self.triple = target_triple + self.datalayout = target_datalayout + if not self.triple: + for i, flag in enumerate(self.compile_flags): + if flag.startswith('-mtriple='): + self.triple = flag[len('-mtriple='):] + elif flag == '-mtriple' and i + 1 < len(self.compile_flags): + self.triple = self.compile_flags[i + 1] + self.linker_cmd = linker_cmd + self.linker_flags = linker_flags or [] + self.linker_output = linker_output + self.slice_level = 3 + self.sha1_map: dict[str, str] = {} + self.sig_files: dict[str, str] = {} + self.stub_files: dict[str, str] = {} + self.include_py_map: dict[str, str] = {} + self.used_includes: set = set() + self._last_ErrorStack = None + self.function_default_args: dict = {} + self.inline_func_symbols: dict = {} + self.extra_link_files: list = [] + self.extra_compile_files: list = [] + self.extra_py_files: list = [] + self._include_sha1s: set = set() + self.entry_files = entry_files + self.startup = startup # None | True | dict (如 {"__main": "main"}) + self._shared_symbol_table = None + self._shared_source_module_sig_files = {} + self._shared_all_dc = {} + self._shared_export_extern_funcs = set() + self._stub_decls_cache = {} + default_dirs = [d for d in self.INCLUDE_DIRS if os.path.isdir(d)] + if include_dirs: + seen = set() + self.include_dirs = [] + for d in list(include_dirs) + default_dirs: + d = os.path.abspath(d) + if d not in seen and os.path.isdir(d): + self.include_dirs.append(d) + seen.add(d) + else: + self.include_dirs = default_dirs + self._LoadSha1Map() + + def _LoadSha1Map(self): + """从 temp_dir 加载 SHA1 映射、签名文件和 stub 声明文件列表""" + if not os.path.exists(self.temp_dir): + print(f"[错误] 声明目录不存在: {self.temp_dir}") + return + + for fname in os.listdir(self.temp_dir): + fpath = os.path.join(self.temp_dir, fname) + if fname.startswith('_'): + continue + if fname.endswith('.pyi'): + sha1 = fname[:-4] + self.sig_files[sha1] = fpath + elif fname.endswith('.stub.ll'): + sha1 = fname[:-8] + self.stub_files[sha1] = fpath + + sha1_file_path = os.path.join(self.temp_dir, '_sha1_map.txt') + if os.path.exists(sha1_file_path): + with open(sha1_file_path, 'r', encoding='utf-8') as f: + for line in f: + line = line.strip() + if ':' in line: + sha1, rel = line.split(':', 1) + self.sha1_map[sha1] = rel + if rel.startswith('includes/'): + module_name = os.path.splitext(os.path.basename(rel))[0] + self.include_py_map[module_name] = sha1 + else: + for sha1, stub_path in self.stub_files.items(): + self.sha1_map[sha1] = sha1 + + def _build_struct_sha1_map(self): + struct_sha1_map = {} + valid_sha1_keys = set(self.sha1_map.keys()) + for fname in os.listdir(self.temp_dir): + if not fname.endswith('.pyi'): + continue + sha1_key = fname.replace('.pyi', '') + if sha1_key not in valid_sha1_keys: + continue + pyi_path = os.path.join(self.temp_dir, fname) + try: + with open(pyi_path, 'r', encoding='utf-8') as f: + tree = ast.parse(f.read()) + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _config_mode + if _config_mode == "strict": + raise + _vlog().warning(f"解析 .pyi 签名文件失败: {_e}", "Exception") + continue + for node in ast.walk(tree): + if isinstance(node, ast.ClassDef): + struct_sha1_map[node.name] = sha1_key + return struct_sha1_map + + def run(self): + """扫描源目录,翻译并生成 .ll 含代码文件(导入遍历)""" + if self.entry_files: + py_files = list(self.entry_files) + else: + main_py = os.path.join(self.src_root, 'main.py') + if os.path.exists(main_py): + py_files = [main_py] + else: + py_files = [] + for root, dirs, files in os.walk(self.src_root): + dirs[:] = [d for d in dirs if d not in ('__pycache__',)] + for file in files: + if file.endswith('.py'): + py_files.append(os.path.join(root, file)) + + if not py_files: + print("[阶段二] 未找到入口文件或源文件") + return + + reachable = find_reachable_files_from_entries(self.src_root, py_files) + py_files = list(reachable) + + py_files = topological_sort_files(py_files, self.src_root) + + print(f"[阶段二] 找到 {len(py_files)} 个可达源文件(已按依赖排序)") + print("[阶段二] 处理顺序:") + for i, f in enumerate(py_files[:10], 1): + rel = os.path.relpath(f, self.src_root) + print(f" {i}. {rel}") + os.makedirs(self.output_dir, exist_ok=True) + + valid_sha1s = set(self.sha1_map.keys()) + old_stub_count = len(self.stub_files) + old_sig_count = len(self.sig_files) + self.stub_files = {k: v for k, v in self.stub_files.items() if k in valid_sha1s} + self.sig_files = {k: v for k, v in self.sig_files.items() if k in valid_sha1s} + if old_stub_count != len(self.stub_files) or old_sig_count != len(self.sig_files): + print(f"[阶段二] 过滤旧文件: stub {old_stub_count}->{len(self.stub_files)}, sig {old_sig_count}->{len(self.sig_files)}") + + active_sha1s = set() + self._precollect_inline_symbols() + self._build_shared_symbol_data() + self.struct_sha1_map = self._build_struct_sha1_map() + + need_translate = [] + for i, src_path in enumerate(py_files, 1): + rel = os.path.relpath(src_path, self.src_root) + with open(src_path, 'r', encoding='utf-8') as f: + content = f.read() + sha1 = compute_sha1(content) + active_sha1s.add(sha1) + out_path = os.path.join(self.output_dir, f"{sha1}.ll") + + current_ModuleSha1Map = self._build_current_ModuleSha1Map(sha1) + + try: + tree = ast.parse(content) + for node in ast.walk(tree): + if isinstance(node, ast.Import): + for alias in node.names: + self.used_includes.add(alias.name.split('.')[0]) + elif isinstance(node, ast.ImportFrom): + if node.module: + self.used_includes.add(node.module.split('.')[0]) + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _config_mode + if _config_mode == "strict": + raise + _vlog().warning(f"收集源文件导入的 include 模块失败: {_e}", "Exception") + + if os.path.isfile(out_path): + deps_changed = self._check_deps_changed(sha1, current_ModuleSha1Map) + if not deps_changed: + print(f"[{i}/{len(py_files)}] 跳过(缓存): {rel} -> {sha1}.ll") + continue + else: + if self._recombine_ll(sha1, current_ModuleSha1Map): + print(f"[{i}/{len(py_files)}] 重组(依赖变化): {rel} -> {sha1}.ll") + continue + print(f"[{i}/{len(py_files)}] 重译(依赖变化): {rel} -> {sha1}.ll") + + else: + stub_cache = os.path.join(self.output_dir, f"{sha1}.stub.ll") + text_cache = os.path.join(self.output_dir, f"{sha1}.text.ll") + if os.path.isfile(stub_cache) and os.path.isfile(text_cache): + if self._recombine_ll(sha1, current_ModuleSha1Map): + print(f"[{i}/{len(py_files)}] 重组(缓存恢复): {rel} -> {sha1}.ll") + continue + + need_translate.append((i, src_path, out_path, sha1, current_ModuleSha1Map)) + + if need_translate: + print(f"\n[阶段二] 需要翻译 {len(need_translate)} 个文件") + import time + t_start = time.time() + + n_workers = min(os.cpu_count() or 4, len(need_translate), 8) + + if n_workers > 1 and len(need_translate) > 1: + from concurrent.futures import ProcessPoolExecutor, as_completed + import pickle + print(f" 并行翻译 (workers={n_workers})") + + shared_pickle_path = os.path.join(self.temp_dir, '_shared_sym.pkl') + try: + shared_data = { + 'symbol_table': self._shared_symbol_table, + 'source_module_sig_files': self._shared_source_module_sig_files, + 'all_dc': self._shared_all_dc, + 'export_extern_funcs': self._shared_export_extern_funcs, + 'inline_func_symbols': self.inline_func_symbols, + 'function_default_args': self.function_default_args, + 'generic_class_templates': self._shared_generic_class_templates, + } + with open(shared_pickle_path, 'wb') as f: + pickle.dump(shared_data, f, protocol=pickle.HIGHEST_PROTOCOL) + print(f" 共享符号表已序列化 ({os.path.getsize(shared_pickle_path)//1024}KB)") + except Exception as e: + print(f" [警告] 符号表序列化失败({e}),worker将自行构建") + shared_pickle_path = '' + + errors = [] + with ProcessPoolExecutor(max_workers=n_workers) as executor: + futures = {} + for i, src_path, out_path, sha1, msm in need_translate: + rel = os.path.relpath(src_path, self.src_root) + future = executor.submit( + _parallel_translate_worker, + src_path, out_path, + self.src_root, self.temp_dir, self.output_dir, + self.include_dirs, self.triple, self.datalayout, + self.sha1_map, self.sig_files, self.stub_files, + self.include_py_map, self.slice_level, + shared_pickle_path, self.struct_sha1_map + ) + futures[future] = (i, rel) + + done_count = 0 + for future in as_completed(futures): + i, rel = futures[future] + done_count += 1 + try: + status, _, err = future.result() + if status == 'ok': + print(f" [{done_count}/{len(need_translate)}] 完成: {rel}") + else: + print(f" [错误] {rel}: {err}") + errors.append((rel, err)) + except Exception as e: + print(f" [错误] {rel}: {e}") + errors.append((rel, str(e))) + + if errors: + print(f"\n[编译终止] {len(errors)} 个文件翻译失败") + sys.exit(1) + else: + for idx, (i, src_path, out_path, sha1, msm) in enumerate(need_translate): + rel = os.path.relpath(src_path, self.src_root) + t0 = time.time() + try: + self._translate_file(src_path, out_path, prebuilt_ModuleSha1Map=msm) + t1 = time.time() + print(f" [{idx+1}/{len(need_translate)}] {rel} ({t1-t0:.1f}s)") + except Exception as e: + print(f" [错误] {rel}: {e}") + traceback.print_exc() + print(f"\n[编译终止] 翻译失败") + sys.exit(1) + t_end = time.time() + print(f" 翻译总耗时: {t_end-t_start:.1f}s") + + print(f"\n[阶段二完成] .ll 文件生成到: {self.output_dir}") + self._scan_include_libraries() + self._compile_include_py_files(active_sha1s) + self._compile_ll_files(active_sha1s) + self._compile_include_sources() + if self.linker_cmd: + self._link_obj_files(active_sha1s) + + def _build_current_ModuleSha1Map(self, self_sha1: str) -> dict: + """构建当前模块的依赖 SHA1 映射(与 _translate_file 中逻辑一致)""" + ModuleSha1Map = {} + for sha1_key, sig_path in self.sig_files.items(): + if sha1_key == self_sha1: + continue + rel_path = self.sha1_map.get(sha1_key, sha1_key) + if rel_path.startswith('includes/'): + inc_mod_name = os.path.splitext(rel_path)[0].replace(os.sep, '.').replace('/', '.') + inc_mod_name = inc_mod_name[len('includes/'):] + inc_short_name = inc_mod_name.split('.')[-1] if '.' in inc_mod_name else inc_mod_name + actual_sha1 = sha1_key + for inc_dir in self.include_dirs: + if os.path.isdir(inc_dir): + py_path = os.path.join(inc_dir, rel_path[len('includes/'):].replace(os.sep, '/')) + py_path = os.path.splitext(py_path)[0] + '.py' + if os.path.isfile(py_path): + with open(py_path, 'r', encoding='utf-8') as f: + py_sha1 = compute_sha1(f.read()) + actual_sha1 = py_sha1 + break + ModuleSha1Map[inc_mod_name] = actual_sha1 + ModuleSha1Map[inc_short_name] = actual_sha1 + # Also add parent package name (e.g., 'hashlib' for 'hashlib.__init__') + if inc_short_name == '__init__' and '.' in inc_mod_name: + parent_pkg = inc_mod_name.rsplit('.', 1)[0] + ModuleSha1Map[parent_pkg] = actual_sha1 + continue + module_name = os.path.splitext(rel_path)[0].replace(os.sep, '.').replace('/', '.') + ModuleSha1Map[module_name] = sha1_key + short_name = module_name.split('.')[-1] if '.' in module_name else module_name + ModuleSha1Map[short_name] = sha1_key + return ModuleSha1Map + + @staticmethod + def _split_ll(ll_content: str): + """将 .ll 内容拆分为 stub(声明)和 text(代码)两部分 + + stub: target, 注释, %type = type, declare, @xxx = external global + text: define ... { ... }, @xxx = global/constant (带初始化器) + """ + import re + stub_lines = [] + text_lines = [] + in_define = False + brace_depth = 0 + module_sha1 = None + defined_names = set() + + for line in ll_content.splitlines(True): + stripped = line.strip() + + if stripped.startswith('define '): + dm = re.match(r'define\s+[^@]*@"?([a-f0-9]+)\.', stripped) + if dm and module_sha1 is None: + module_sha1 = dm.group(1) + dm2 = re.match(r'define\s+[^@]*@"?([^"\s(]+)"?', stripped) + if dm2: + defined_names.add(dm2.group(1)) + + in_global_def = False + global_var_name = None + global_type_parts = [] + global_brace_depth = 0 + + for line in ll_content.splitlines(True): + stripped = line.strip() + + if in_global_def: + text_lines.append(line) + global_type_parts.append(stripped) + global_brace_depth += stripped.count('{') - stripped.count('}') + if global_brace_depth <= 0: + full_type = ' '.join(global_type_parts).strip() + depth = 0 + type_end = len(full_type) + for ci, cc in enumerate(full_type): + if cc in ('{', '['): + depth += 1 + elif cc in ('}', ']'): + depth -= 1 + elif depth == 0 and cc == ' ': + type_end = ci + break + var_type = full_type[:type_end].strip() + if var_type: + stub_lines.append(f'{global_var_name} = external global {var_type}\n') + in_global_def = False + global_var_name = None + global_type_parts = [] + global_brace_depth = 0 + continue + + if in_define: + text_lines.append(line) + brace_depth += stripped.count('{') - stripped.count('}') + if brace_depth <= 0: + in_define = False + continue + + if stripped.startswith('define '): + text_lines.append(line) + in_define = True + brace_depth = stripped.count('{') - stripped.count('}') + decl_line = re.sub(r'^define\s+', 'declare ', stripped) + decl_line = re.sub(r'\b(linkonce_odr|weak_odr|linkonce|weak|common|appending|internal|private)\s+', '', decl_line) + decl_line = re.sub(r'\balwaysinline\s+', '', decl_line) + paren_pos = decl_line.rfind(')') + if paren_pos >= 0: + decl_line = decl_line[:paren_pos + 1] + stub_lines.append(decl_line + '\n') + continue + + if stripped == '{' and text_lines and not in_define: + prev_stripped = text_lines[-1].strip() if text_lines else '' + if prev_stripped.startswith('define ') or prev_stripped.endswith('noredzone') or prev_stripped.endswith(')'): + text_lines.append(line) + brace_depth = 1 + in_define = True + if prev_stripped.startswith('define '): + decl_line = re.sub(r'^define\s+', 'declare ', prev_stripped) + decl_line = re.sub(r'\b(linkonce_odr|weak_odr|linkonce|weak|common|appending|internal|private)\s+', '', decl_line) + decl_line = re.sub(r'\balwaysinline\s+', '', decl_line) + paren_pos = decl_line.rfind(')') + if paren_pos >= 0: + decl_line = decl_line[:paren_pos + 1] + stub_lines.append(decl_line + '\n') + continue + + if stripped.startswith('@') and ' global ' in stripped and 'external global' not in stripped: + text_lines.append(line) + if ' internal ' not in stripped and ' private ' not in stripped: + name_match = re.match(r'(@\S+)', stripped) + if name_match: + var_name = name_match.group(1) + global_pos = stripped.find(' global ') + after_global = stripped[global_pos + 8:] + depth = 0 + type_end = len(after_global) + for ci, cc in enumerate(after_global): + if cc in ('{', '['): + depth += 1 + elif cc in ('}', ']'): + depth -= 1 + elif depth == 0 and cc == ' ': + type_end = ci + break + var_type = after_global[:type_end].strip() + brace_depth_gv = 0 + for cc in var_type: + if cc == '{': + brace_depth_gv += 1 + elif cc == '}': + brace_depth_gv -= 1 + if brace_depth_gv > 0: + in_global_def = True + global_var_name = var_name + global_type_parts = [var_type] + global_brace_depth = brace_depth_gv + elif var_type: + stub_lines.append(f'{var_name} = external global {var_type}\n') + continue + if stripped.startswith('@') and ' constant ' in stripped: + text_lines.append(line) + continue + + if stripped.startswith('declare'): + dm = re.match(r'declare\s+[^@]*@"?([^"\s(]+)"?', stripped) + if dm: + fname = dm.group(1) + if fname in defined_names: + stub_lines.append(line) + continue + dot_pos = fname.find('.') + if dot_pos > 0: + fname_sha1 = fname[:dot_pos] + if module_sha1 and fname_sha1 != module_sha1 and len(fname_sha1) >= 16: + continue + if re.match(r'^[a-f0-9]{16}\.', fname): + continue + stub_lines.append(line) + continue + + stub_lines.append(line) + + return ''.join(stub_lines), ''.join(text_lines) + + def _save_deps(self, sha1: str, ModuleSha1Map: dict): + """保存依赖指纹到 .deps.json""" + deps_path = os.path.join(self.output_dir, f"{sha1}.deps.json") + deps = {} + for mod_name, dep_sha1 in ModuleSha1Map.items(): + deps[mod_name] = dep_sha1 + with open(deps_path, 'w', encoding='utf-8') as f: + json.dump(deps, f) + + def _LoadDeps(self, sha1: str) -> dict: + """加载依赖指纹""" + deps_path = os.path.join(self.output_dir, f"{sha1}.deps.json") + if os.path.isfile(deps_path): + try: + with open(deps_path, 'r', encoding='utf-8') as f: + return json.load(f) + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _config_mode + if _config_mode == "strict": + raise + _vlog().warning(f"加载依赖指纹 JSON 失败: {_e}", "Exception") + return None + + def _check_deps_changed(self, sha1: str, current_ModuleSha1Map: dict) -> bool: + """检查依赖指纹是否变化""" + saved_deps = self._LoadDeps(sha1) + if saved_deps is None: + return True + for mod_name, dep_sha1 in current_ModuleSha1Map.items(): + if saved_deps.get(mod_name) != dep_sha1: + return True + for mod_name, dep_sha1 in saved_deps.items(): + if current_ModuleSha1Map.get(mod_name) != dep_sha1: + return True + return False + + def _recombine_ll(self, sha1: str, current_ModuleSha1Map: dict) -> bool: + """依赖变化时重新组合 .ll:更新 .stub.ll 中的 SHA1 前缀,拼接 .stub.ll + .text.ll""" + saved_deps = self._LoadDeps(sha1) + if saved_deps is None: + return False + + stub_path = os.path.join(self.output_dir, f"{sha1}.stub.ll") + text_path = os.path.join(self.output_dir, f"{sha1}.text.ll") + ll_path = os.path.join(self.output_dir, f"{sha1}.ll") + + if not os.path.isfile(stub_path) or not os.path.isfile(text_path): + return False + + with open(stub_path, 'r', encoding='utf-8') as f: + stub_content = f.read() + with open(text_path, 'r', encoding='utf-8') as f: + text_content = f.read() + + sha1_replacements = {} + for mod_name, old_sha1 in saved_deps.items(): + new_sha1 = current_ModuleSha1Map.get(mod_name) + if new_sha1 and old_sha1 != new_sha1: + sha1_replacements[old_sha1] = new_sha1 + + if sha1_replacements: + for old_sha1, new_sha1 in sha1_replacements.items(): + stub_content = stub_content.replace(old_sha1, new_sha1) + text_content = text_content.replace(old_sha1, new_sha1) + + combined = stub_content + if not combined.endswith('\n'): + combined += '\n' + combined += text_content + + with open(ll_path, 'w', encoding='utf-8', newline='\n') as f: + f.write(combined) + with open(stub_path, 'w', encoding='utf-8', newline='\n') as f: + f.write(stub_content) + with open(text_path, 'w', encoding='utf-8', newline='\n') as f: + f.write(text_content) + + self._save_deps(sha1, current_ModuleSha1Map) + + obj_path = os.path.join(self.output_dir, f"{sha1}.obj") + if os.path.isfile(obj_path): + os.remove(obj_path) + + return True + + def _translate_file(self, src_path: str, out_path: str, prebuilt_ModuleSha1Map: dict = None): + """翻译单个源文件,嵌入相关 .stub.ll 声明""" + with open(src_path, 'r', encoding='utf-8') as f: + code = f.read() + + sha1 = compute_sha1(code) + + if prebuilt_ModuleSha1Map is not None: + ModuleSha1Map = prebuilt_ModuleSha1Map + else: + ModuleSha1Map = self._build_current_ModuleSha1Map(sha1) + + trans = TransPyC.TransPyC(code=code, triple=self.triple, datalayout=self.datalayout) + trans.translator.CurrentFile = src_path + trans.SliceLevel = self.slice_level + trans.translator.SliceLevel = self.slice_level + trans.translator.SliceCount = 0 + trans.translator.SliceInfos = [] + trans.translator.LlvmGen = None + trans.translator._module_sha1 = sha1 + trans.translator._ModuleSha1Map = ModuleSha1Map + trans.translator._struct_sha1_map = self.struct_sha1_map + trans.translator._global_function_default_args = self.function_default_args + trans.translator._temp_dir = self.temp_dir + + if hasattr(self, '_shared_symbol_table') and self._shared_symbol_table is not None: + trans.translator.SymbolTable = self._shared_symbol_table + # 确保共享符号表的 translator 指向当前 translator,以便 import 别名解析正确 + if hasattr(self._shared_symbol_table, 'translator'): + self._shared_symbol_table.translator = trans.translator + trans.translator._source_module_sig_files = self._shared_source_module_sig_files + trans.translator._all_define_constants = self._shared_all_dc + trans.translator._export_extern_funcs = self._shared_export_extern_funcs + if hasattr(self, '_shared_generic_class_templates') and self._shared_generic_class_templates: + if not hasattr(trans.translator.ClassHandler, '_generic_class_templates'): + trans.translator.ClassHandler._generic_class_templates = {} + trans.translator.ClassHandler._generic_class_templates.update(self._shared_generic_class_templates) + else: + export_extern_funcs = set() + for sha1_key, sig_path in self.sig_files.items(): + if sha1_key == sha1: + continue + try: + with open(sig_path, 'r', encoding='utf-8') as f: + sig_content = f.read() + sig_tree = ast.parse(sig_content) + for node in ast.iter_child_nodes(sig_tree): + if isinstance(node, ast.FunctionDef): + if _check_annotation_for_export(node.returns): + export_extern_funcs.add(node.name) + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _config_mode + if _config_mode == "strict": + raise + _vlog().warning(f"收集导出外部函数声明失败: {_e}", "Exception") + if export_extern_funcs: + trans.translator._export_extern_funcs = export_extern_funcs + + for includes_dir in self.include_dirs: + if os.path.isdir(includes_dir): + for pyi_file in os.listdir(includes_dir): + if pyi_file.endswith('.pyi'): + pyi_path = os.path.join(includes_dir, pyi_file) + module_name = os.path.splitext(pyi_file)[0] + trans.translator.SymbolTable.LoadModuleSymbols(pyi_path, module_name, lineno=0) + for py_file in os.listdir(includes_dir): + if py_file.endswith('.py') and not py_file.startswith('_'): + module_name = os.path.splitext(py_file)[0] + sha1_key = self.include_py_map.get(module_name) + if sha1_key and sha1_key in self.sig_files: + sig_path = self.sig_files[sha1_key] + trans.translator.SymbolTable.LoadModuleSymbols(sig_path, module_name, lineno=0) + # 收集需要重导出的包,等所有模块符号加载完后再处理 + _pending_reexports = [] + for sha1_key, sig_path in self.sig_files.items(): + rel_path = self.sha1_map.get(sha1_key, sha1_key) + if rel_path.startswith('includes/'): + mod_name = os.path.splitext(rel_path)[0].replace(os.sep, '.').replace('/', '.') + mod_name = mod_name[len('includes/'):] + trans.translator.SymbolTable.LoadModuleSymbols(sig_path, mod_name, lineno=0) + if mod_name.endswith('.__init__'): + package_name = mod_name[:-len('.__init__')] + _pending_reexports.append((sig_path, package_name)) + + # 所有 includes 模块符号已加载,现在处理包重导出 + for sig_path, package_name in _pending_reexports: + self._register_package_reexports(trans, sig_path, package_name) + + for sha1_key, sig_path in self.sig_files.items(): + if sha1_key == sha1: + continue + rel_path = self.sha1_map.get(sha1_key, sha1_key) + if rel_path.startswith('includes/'): + continue + module_name = os.path.splitext(rel_path)[0].replace(os.sep, '.').replace('/', '.') + trans.translator.SymbolTable.LoadModuleSymbols(sig_path, module_name, lineno=0) + trans.translator._source_module_sig_files[module_name] = sig_path + short_name = module_name.split('.')[-1] if '.' in module_name else module_name + if short_name != module_name: + trans.translator._source_module_sig_files[short_name] = sig_path + + all_dc = {} + for sha1_key, stub_path in self.stub_files.items(): + if sha1_key == sha1: + continue + if os.path.exists(stub_path): + try: + with open(stub_path, 'r', encoding='utf-8') as f: + stub_content = f.read() + for line in stub_content.splitlines(): + line = line.strip() + if line.startswith('@') and '= global' in line and 'i32' in line and not line.startswith('@llvm'): + var_name = line.split('=')[0].strip().lstrip('@') + val_part = line.split('i32')[-1].strip().rstrip(']').lstrip('[').lstrip('i32') + try: + val = int(val_part) + all_dc[var_name] = val + except: + pass + except: + pass + for sha1_key, pyi_path in self.sig_files.items(): + if sha1_key == sha1: + continue + if os.path.exists(pyi_path): + try: + import ast as _ast + with open(pyi_path, 'r', encoding='utf-8') as f: + pyi_content = f.read() + tree = _ast.parse(pyi_content) + for node in _ast.iter_child_nodes(tree): + if isinstance(node, _ast.AnnAssign) and isinstance(node.target, _ast.Name): + ann_str = _ast.dump(node.annotation) + if 'CDefine' in ann_str and node.value: + val = None + if isinstance(node.value, _ast.Constant): + val = node.value.value + elif isinstance(node.value, _ast.Call) and isinstance(node.value.func, _ast.Name) and node.value.func.id == 'float' and node.value.args and isinstance(node.value.args[0], _ast.Constant): + val = node.value.args[0].value + if val is not None: + all_dc[f"{node.target.id}"] = val + except: + pass + if all_dc: + trans.translator._all_define_constants = all_dc + + for sym_name, sym_info in self.inline_func_symbols.items(): + if sym_name not in trans.translator.SymbolTable: + trans.translator.SymbolTable[sym_name] = sym_info + else: + existing = trans.translator.SymbolTable[sym_name] + if not getattr(existing, 'InlineBody', None) and getattr(sym_info, 'InlineBody', None): + existing.IsInline = sym_info.IsInline + existing.InlineBody = sym_info.InlineBody + existing.InlineParams = sym_info.InlineParams + + try: + result = trans.Convert( + OutputFilename=out_path, + SourceFilename=src_path, + target='llvm' + ) + except Exception as e: + error_stack = getattr(trans.translator, '_ErrorStack', []) + if error_stack: + self._last_ErrorStack = error_stack + chain_lines = [] + for entry in reversed(error_stack): + if len(entry) >= 3: + exc_msg, line_info = entry[1], entry[2] + chain_lines.append(" %s\n %s" % (line_info, exc_msg)) + if chain_lines: + enriched = str(e) + "\n" + "\n".join(chain_lines) + raise type(e)(enriched) from e + node_info = "" + if hasattr(trans.translator, 'LlvmGen') and trans.translator.LlvmGen: + node_info = trans.translator.LlvmGen._get_node_info() + if node_info: + enriched = "%s\n %s" % (str(e), node_info.strip()) + raise type(e)(enriched) from e + raise + + if result and isinstance(result, str): + for func_name, func_def in trans.translator.FunctionDefCache.items(): + if hasattr(func_def, 'args') and hasattr(func_def.args, 'defaults') and func_def.args.defaults: + mangled = trans.translator.LlvmGen._mangle_func_name(func_name) if trans.translator.LlvmGen else func_name + defaults = [] + for d in func_def.args.defaults: + if isinstance(d, ast.Constant): + defaults.append(d.value) + else: + defaults.append(None) + self.function_default_args[mangled] = defaults + self.function_default_args[func_name] = defaults + for sym_name, sym_info in trans.translator.SymbolTable.items(): + if isinstance(sym_info, CTypeInfo) and getattr(sym_info, 'IsInline', False) and getattr(sym_info, 'InlineBody', None): + self.inline_func_symbols[sym_name] = sym_info + # stub声明现在通过_dso.ll编译时拼接依赖模块stub.ll提供 + # stub_decls = self._collect_stub_decls_for_module(sha1) + # if stub_decls: + # result = self._inject_stub_decls(result, stub_decls) + + out_dir = os.path.dirname(out_path) + if out_dir: + os.makedirs(out_dir, exist_ok=True) + with open(out_path, 'w', encoding='utf-8', newline='\n') as f: + f.write(result) + + stub_content, text_content = self._split_ll(result) + base = os.path.splitext(out_path)[0] + with open(base + '.stub.ll', 'w', encoding='utf-8', newline='\n') as f: + f.write(stub_content) + with open(base + '.text.ll', 'w', encoding='utf-8', newline='\n') as f: + f.write(text_content) + self._save_deps(sha1, ModuleSha1Map) + + print(f" -> {os.path.basename(out_path)}") + else: + stub_path = self.stub_files.get(sha1) + if stub_path and os.path.exists(stub_path): + out_dir = os.path.dirname(out_path) + if out_dir: + os.makedirs(out_dir, exist_ok=True) + with open(stub_path, 'r', encoding='utf-8') as f: + stub_content = f.read() + with open(out_path, 'w', encoding='utf-8', newline='\n') as f: + f.write(stub_content) + print(f" -> {os.path.basename(out_path)} (仅声明)") + + def _register_package_reexports(self, trans, init_pyi_path, package_name): + """解析 __init__.pyi 中的 from .xxx import yyy 或 from __xxx import yyy,在包级别注册导出符号""" + try: + with open(init_pyi_path, 'r', encoding='utf-8') as f: + content = f.read() + tree = ast.parse(content) + for node in ast.walk(tree): + if isinstance(node, ast.ImportFrom) and node.module: + sub_module = node.module.lstrip('.') + for alias in node.names: + symbol_name = alias.name + exported_name = alias.asname if alias.asname else symbol_name + source_keys = [ + f"{package_name}.{sub_module}.{symbol_name}", + f"{package_name}.__{sub_module}.{symbol_name}" if not sub_module.startswith('__') else None, + symbol_name, + ] + target_key = f"{package_name}.{exported_name}" + if target_key not in trans.translator.SymbolTable: + for source_key in source_keys: + if source_key and source_key in trans.translator.SymbolTable: + trans.translator.SymbolTable[target_key] = trans.translator.SymbolTable[source_key] + break + if exported_name not in trans.translator.SymbolTable: + for source_key in source_keys: + if source_key and source_key in trans.translator.SymbolTable: + trans.translator.SymbolTable[exported_name] = trans.translator.SymbolTable[source_key] + break + except Exception as e: + print(f" [警告] 解析包重导出失败 {init_pyi_path}: {e}") + + def _collect_stub_decls(self, self_sha1: str) -> str: + """收集 includes 目录中模块的 .stub.ll 声明内容,去重""" + seen_symbols = set() + decl_lines = [] + for sha1_key, stub_path in self.stub_files.items(): + if sha1_key == self_sha1: + continue + rel_path = self.sha1_map.get(sha1_key, sha1_key) + if not rel_path.startswith('includes/'): + continue + if os.path.exists(stub_path): + with open(stub_path, 'r', encoding='utf-8') as f: + content = f.read() + for line in content.splitlines(): + stripped = line.strip() + if not stripped: + continue + if stripped.startswith(';'): + continue + if stripped.startswith('target '): + continue + if stripped.startswith('source_filename'): + continue + if stripped.startswith('@') and '=' in stripped: + name = stripped.split('=', 1)[0].strip() + if name in seen_symbols: + continue + seen_symbols.add(name) + elif stripped.startswith('%') and '= type' in stripped: + name = stripped.split('=', 1)[0].strip() + if name in seen_symbols: + continue + seen_symbols.add(name) + elif stripped.startswith('declare'): + parts = stripped.split('@', 1) + if len(parts) > 1: + name = '@' + parts[1].split('(', 1)[0].strip() + if name in seen_symbols: + continue + seen_symbols.add(name) + decl_lines.append(line) + if decl_lines: + result = '\n'.join(decl_lines) + self._stub_decls_cache[self_sha1] = result + return result + self._stub_decls_cache[self_sha1] = '' + return '' + + def _collect_stub_decls_for_module(self, self_sha1: str) -> str: + """收集特定模块需要的 .stub.ll 声明(包括结构体类型定义、函数声明和 typedef)""" + if self_sha1 in self._stub_decls_cache: + return self._stub_decls_cache[self_sha1] + import re + seen_symbols = set() + seen_func_symbols = set() + decl_lines = [] + + non_struct_types = {'UINT', 'INT', 'BYTE', 'BYTEPTR', 'WORD', 'DWORD', 'QWORD', + 'INT8', 'INT16', 'INT32', 'INT64', 'UINT8', 'UINT16', 'UINT32', 'UINT64', + 'INTPTR', 'UINTPTR', 'SIZE_T', 'SSIZE_T', 'PTRDIFF_T', + 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', + 'atomic_int', 'atomic_uint', 'atomic_long', 'atomic_ulong', + 'atomic_int8', 'atomic_uint8', 'atomic_int16', 'atomic_uint16', + 'atomic_int32', 'atomic_uint32', 'atomic_int64', 'atomic_uint64', + 'atomic_ptr', 'atomic_flag', 'typedef', + 'list', 'dict', 'tuple', 'set', 'str', 'bytes', 'array'} + + struct_names = set() + struct_source_sha1 = {} + + def _extract_struct_name(type_def_str): + m = re.match(r'%"?((?:[a-f0-9]+\.)?[\w.]+)"?\s*=\s*type', type_def_str) + if m: + raw = m.group(1) + if '.' in raw: + return raw.split('.', 1)[1], raw.split('.', 1)[0] + return raw, None + return None, None + + def _replace_struct_refs(type_str): + def replace_struct_name(name): + if name in struct_names: + name_sha1 = struct_source_sha1.get(name, '') + return f'%"{name_sha1}.{name}"' if name_sha1 else None + return None + def replace_struct_match(match): + name = match.group(1) + replaced = replace_struct_name(name) + return replaced if replaced else match.group(0) + def replace_sha1_struct_match(match): + name = match.group(2) + replaced = replace_struct_name(name) + return replaced if replaced else match.group(0) + result = re.sub(r'%struct\.(\w+)', replace_struct_match, type_str) + result = re.sub(r'%"?([a-f0-9]+)\.(\w+)"?', replace_sha1_struct_match, result) + return result + + for sha1_key, stub_path in self.stub_files.items(): + if os.path.exists(stub_path): + with open(stub_path, 'r', encoding='utf-8') as f: + content = f.read() + for line in content.splitlines(): + stripped = line.strip() + if stripped.startswith('%') and '= type' in stripped: + clean_name, sha1_part = _extract_struct_name(stripped) + if clean_name and clean_name not in non_struct_types: + struct_names.add(clean_name) + if clean_name not in struct_source_sha1: + struct_source_sha1[clean_name] = sha1_part or sha1_key + + for sha1_key, stub_path in self.stub_files.items(): + if sha1_key == self_sha1: + continue + if os.path.exists(stub_path): + with open(stub_path, 'r', encoding='utf-8') as f: + content = f.read() + for line in content.splitlines(): + stripped = line.strip() + if stripped.startswith('%') and '= type' in stripped: + clean_name, sha1_part = _extract_struct_name(stripped) + if not clean_name or clean_name in non_struct_types: + continue + if clean_name in seen_symbols: + continue + parts = stripped.split('= type', 1) + struct_type_body = parts[1].strip() if len(parts) > 1 else '' + if 'opaque' in struct_type_body: + seen_symbols.add(clean_name) + name_sha1 = struct_source_sha1.get(clean_name, sha1_key) + decl_lines.append(f'%"{name_sha1}.{clean_name}" = type opaque') + continue + if clean_name in struct_names: + struct_type_body = _replace_struct_refs(struct_type_body) + name_sha1 = struct_source_sha1.get(clean_name, sha1_key) + new_def = f'%"{name_sha1}.{clean_name}" = type {struct_type_body}' + seen_symbols.add(clean_name) + decl_lines.append(new_def) + if decl_lines: + return '\n'.join(decl_lines) + return '' + + def _inject_stub_decls(self, ll_content: str, stub_decls: str) -> str: + """将 stub 声明注入到 LLVM IR 模块头之后,替换 opaque 类型为具体定义""" + def normalize_type_name(name): + name = name.strip() + if name.startswith('%'): + return '%' + name[1:].strip().strip('"') + return name + + existing_symbols = {} # normalized_name -> (line_index, full_line) + for i, line in enumerate(ll_content.splitlines()): + stripped = line.strip() + if stripped.startswith('@') and '=' in stripped: + name = stripped.split('=', 1)[0].strip() + existing_symbols[name] = (i, line) + elif stripped.startswith('%') and '= type' in stripped: + name = normalize_type_name(stripped.split('=', 1)[0].strip()) + existing_symbols[name] = (i, line) + elif stripped.startswith('declare') or stripped.startswith('define'): + parts = stripped.split('@', 1) + if len(parts) > 1: + name = '@' + parts[1].split('(', 1)[0].strip() + existing_symbols[name] = (i, line) + + lines = ll_content.splitlines() + replacements = {} # line_index -> new_line + new_decls = [] # 新类型定义(不在现有输出中的) + + def normalize_type_name(name): + name = name.strip() + if name.startswith('%'): + return '%' + name[1:].strip().strip('"') + return name + + for line in stub_decls.splitlines(): + stripped = line.strip() + if stripped.startswith('%') and '= type' in stripped: + name = normalize_type_name(stripped.split('=', 1)[0].strip()) + if name in existing_symbols: + idx, existing_line = existing_symbols[name] + existing_type_body = existing_line.strip().split('= type', 1)[1].strip() if '= type' in existing_line else '' + stub_type_body = stripped.split('= type', 1)[1].strip() if '= type' in stripped else '' + if 'opaque' in existing_line and 'opaque' not in stripped: + replacements[idx] = line + else: + new_decls.append(line) + + # 应用替换 + for idx, new_line in replacements.items(): + lines[idx] = new_line + + # 追加新类型定义到末尾(去重处理) + if new_decls: + # 过滤掉已经在 Translator 输出中存在的类型定义 + existing_types = set() + for line in lines: + stripped = line.strip() + if stripped.startswith('%') and '= type' in stripped: + type_name = normalize_type_name(stripped.split('=', 1)[0].strip()) + existing_types.add(type_name) + filtered_decls = [] + for line in new_decls: + stripped = line.strip() + if '= type' in stripped: + type_name = normalize_type_name(stripped.split('=', 1)[0].strip()) + if type_name not in existing_types: + filtered_decls.append(line) + existing_types.add(type_name) + if filtered_decls: + lines.append('') + lines.extend(filtered_decls) + + # 确保所有类型定义在全局变量之前,LLVM 要求在常量初始化器中使用类型之前必须先定义 + type_def_indices = [] + first_global_idx = None + for i, line in enumerate(lines): + stripped = line.strip() + if stripped.startswith('%') and '= type' in stripped: + if first_global_idx is not None: + type_def_indices.append(i) + elif stripped.startswith('@') and ' global' in stripped: + if first_global_idx is None: + first_global_idx = i + + if type_def_indices and first_global_idx is not None: + type_defs = [lines[i] for i in reversed(type_def_indices)] + for i in reversed(type_def_indices): + del lines[i] + insert_pos = first_global_idx + if type_def_indices[0] < first_global_idx: + insert_pos = first_global_idx - len(type_def_indices) + for j, td in enumerate(type_defs): + lines.insert(insert_pos, td) + + result = '\n'.join(lines) + + return result + + def _compile_ll_files(self, active_sha1s: set): + """将 output_dir 中属于 active_sha1s 的 .ll 文件编译为 .obj(跳过已编译过的 include 文件)""" + stale_files = [] + for root, dirs, files in os.walk(self.output_dir): + for file in files: + fpath = os.path.join(root, file) + for ext in ('.ll', '.obj', '.stub.ll', '.text.ll', '.deps.json', '_dso.ll'): + if file.endswith(ext): + sha1 = file[:-(len(ext))] + if sha1 not in active_sha1s: + stale_files.append(fpath) + break + if stale_files: + for fpath in stale_files: + try: + os.remove(fpath) + except: + pass + print(f"[清理] 删除 {len(stale_files)} 个过时文件") + ll_files = [] + for root, dirs, files in os.walk(self.output_dir): + for file in files: + if file.endswith('.ll') and not file.endswith('.stub.ll') and not file.endswith('.text.ll'): + sha1 = file[:-3] + if sha1 in active_sha1s: + obj_path = os.path.join(root, file[:-3] + '.obj') + if not os.path.isfile(obj_path): + ll_files.append(os.path.join(root, file)) + + if not ll_files: + print("[编译] 无 .ll 文件需要重新编译") + else: + print(f"\n[编译] 找到 {len(ll_files)} 个 .ll 文件需要编译") + + has_inline = False + all_ll_files = [] + for root, dirs, files in os.walk(self.output_dir): + for file in files: + if file.endswith('.ll') and not file.endswith('.stub.ll') and not file.endswith('.text.ll'): + sha1 = file[:-3] + if sha1 in active_sha1s and sha1 not in self._include_sha1s: + all_ll_files.append(os.path.join(root, file)) + for ll_path in all_ll_files: + try: + with open(ll_path, 'r', encoding='utf-8') as f: + content = f.read() + if 'alwaysinline' in content: + has_inline = True + break + except: + pass + + if has_inline: + llvm_link = shutil.which('llvm-link') or shutil.which('llvm-link.exe') + opt_cmd = shutil.which('opt') or shutil.which('opt.exe') + if llvm_link and opt_cmd: + print(" [内联] 检测到 alwaysinline 函数,执行跨模块内联优化...") + for ll_path in all_ll_files: + try: + with open(ll_path, 'r', encoding='utf-8') as f: + content = f.read() + type_defs = [] + type_def_indices = set() + for i, line in enumerate(content.splitlines()): + stripped = line.strip() + if stripped.startswith('%') and '= type' in stripped: + type_defs.append(line) + type_def_indices.add(i) + if type_def_indices: + lines = content.splitlines(True) + content_no_types = ''.join(line for i, line in enumerate(lines) if i not in type_def_indices) + header_end = 0 + for i, line in enumerate(content_no_types.splitlines()): + stripped = line.strip() + if stripped.startswith(';') or stripped.startswith('target ') or stripped.startswith('source_filename') or not stripped: + header_end = i + 1 + continue + break + lines2 = content_no_types.splitlines(True) + fixed = ''.join(lines2[:header_end]) + '\n'.join(type_defs) + '\n' + ''.join(lines2[header_end:]) + with open(ll_path, 'w', encoding='utf-8') as f: + f.write(fixed) + except: + pass + merged_ll = os.path.join(self.output_dir, '_merged.ll') + optimized_ll = os.path.join(self.output_dir, '_merged_opt.ll') + try: + link_cmd = [llvm_link] + all_ll_files + ['-o', merged_ll] + result = subprocess.run(link_cmd, capture_output=True, text=True) + if result.returncode != 0: + print(f" [警告] llvm-link 失败: {result.stderr.strip()},回退到单独编译") + has_inline = False + else: + opt_result_cmd = [opt_cmd, '-passes=always-inline', merged_ll, '-S', '-o', optimized_ll] + result = subprocess.run(opt_result_cmd, capture_output=True, text=True) + if result.returncode != 0: + print(f" [警告] opt 失败: {result.stderr.strip()},回退到单独编译") + has_inline = False + else: + print(" [内联] 跨模块内联优化完成") + with open(optimized_ll, 'r', encoding='utf-8') as f: + opt_content = f.read() + import re + opt_content = re.sub(r'\b(define|declare)\s+(private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external)\s+', r'\1 \2 dso_local ', opt_content) + opt_content = re.sub(r'\b(define|declare)\s+(?!private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external|dso_local|@)', r'\1 dso_local ', opt_content) + opt_content = re.sub(r'(@[\w.]+)\s*=\s*(private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external)\s+(global|constant)', r'\1 = \2 dso_local \3', opt_content) + opt_content = re.sub(r'(@[\w.]+)\s*=\s+(?!private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external|dso_local)(global|constant)', r'\1 = linkonce_odr \2', opt_content) + with open(optimized_ll, 'w', encoding='utf-8') as f: + f.write(opt_content) + merged_obj = os.path.join(self.output_dir, '_merged.obj') + try: + cmd = [self.compile_cmd] + self.compile_flags + ['-o', merged_obj, optimized_ll] + result = subprocess.run(cmd, capture_output=True, text=True, + cwd=self.output_dir) + if result.returncode == 0: + print(f" [成功] 合并模块编译完成") + for ll_path in ll_files: + obj_path = ll_path[:-3] + '.obj' + sha1_obj = os.path.join(self.output_dir, os.path.basename(ll_path)[:-3] + '.obj') + if os.path.isfile(sha1_obj): + os.remove(sha1_obj) + return + else: + print(f" [警告] 合并模块编译失败: {result.stderr.strip()},回退到单独编译") + has_inline = False + except Exception as e: + print(f" [警告] 合并模块编译异常: {e},回退到单独编译") + has_inline = False + except FileNotFoundError: + print(f" [警告] 找不到 llvm-link 或 opt,回退到单独编译") + has_inline = False + else: + print(" [警告] 未找到 llvm-link/opt 工具,回退到单独编译(alwaysinline 可能不生效)") + + from concurrent.futures import ThreadPoolExecutor, as_completed + import re + + def _compile_one(ll_path): + rel = os.path.relpath(ll_path, self.output_dir) + obj_path = ll_path[:-3] + '.obj' + if os.path.isfile(obj_path): + return (rel, 'cached', '') + try: + with open(ll_path, 'r', encoding='utf-8') as f: + ll_content = f.read() + sha1 = os.path.basename(ll_path)[:-3] + deps = self._LoadDeps(sha1) + stub_prefix = '' + if deps: + existing_symbols = {} + opaque_line_indices = {} + existing_declares = set() + existing_declare_lines = {} + for i, line in enumerate(ll_content.splitlines()): + stripped = line.strip() + if stripped.startswith('%') and '= type' in stripped: + m = re.match(r'%"?((?:[a-f0-9]+\.)?[\w.]+)"?\s*=', stripped) + if m: + name = m.group(1) + if '= type opaque' in stripped: + existing_symbols[name] = 'opaque' + opaque_line_indices[name] = i + else: + existing_symbols[name] = 'full' + elif stripped.startswith('declare'): + dm = re.match(r'declare\s+[^@]*@"?([^"\s(]+)"?', stripped) + if dm: + fname = dm.group(1) + existing_declares.add(fname) + existing_declare_lines[fname] = i + seen_stub_sha1 = set() + replaced_opaque_names = set() + replaced_declare_names = set() + all_stub_lines = [] + stub_type_map = {} + stub_declare_names = set() + stub_declare_lines = {} + existing_defines = set() + existing_global_defs = set() + stub_global_defs = set() + for line in ll_content.splitlines(): + stripped = line.strip() + if stripped.startswith('define'): + dm = re.match(r'define\s+[^@]*@"?([^"\s(]+)"?', stripped) + if dm: + existing_defines.add(dm.group(1)) + elif stripped.startswith('@') and (' global ' in stripped or ' constant ' in stripped): + gm = re.match(r'(@\S+)', stripped) + if gm: + existing_global_defs.add(gm.group(1)) + for dep_name, dep_sha1 in deps.items(): + if dep_sha1 in seen_stub_sha1: + continue + seen_stub_sha1.add(dep_sha1) + stub_path = os.path.join(self.output_dir, f"{dep_sha1}.stub.ll") + if not os.path.isfile(stub_path): + stub_path = os.path.join(self.temp_dir, f"{dep_sha1}.stub.ll") + if os.path.isfile(stub_path): + with open(stub_path, 'r', encoding='utf-8') as sf: + stub_content = sf.read() + for line in stub_content.splitlines(): + stripped = line.strip() + if stripped.startswith(';') or stripped.startswith('target ') or stripped.startswith('source_filename') or not stripped: + continue + if stripped.startswith('declare'): + dm = re.match(r'declare\s+[^@]*@"?([^"\s(]+)"?', stripped) + if dm: + fname = dm.group(1) + if re.search(r'%("[^"]+"|[a-f0-9]+\.[A-Za-z_]\w*)\s+%', stripped): + continue + if fname in existing_defines: + continue + if fname in existing_declares or fname in stub_declare_names: + existing_decl_line = stub_declare_lines.get(fname) + if existing_decl_line is not None: + has_struct = '%' in stripped + existing_has_struct = '%' in existing_decl_line if existing_decl_line else False + if has_struct and not existing_has_struct: + for i, l in enumerate(all_stub_lines): + if l is not None and l.strip().startswith('declare'): + em = re.match(r'declare\s+[^@]*@"?([^"\s(]+)"?', l.strip()) + if em and em.group(1) == fname: + all_stub_lines[i] = line + break + continue + elif fname in existing_declares: + has_struct = '%' in stripped + if has_struct: + replaced_declare_names.add(fname) + stub_declare_names.add(fname) + stub_declare_lines[fname] = line + all_stub_lines.append(line) + continue + continue + stub_declare_names.add(fname) + stub_declare_lines[fname] = line + all_stub_lines.append(line) + continue + if stripped.startswith('%') and '= type' in stripped: + m = re.match(r'%"?((?:[a-f0-9]+\.)?[\w.]+)"?\s*=', stripped) + if m: + name = m.group(1) + is_opaque = '= type opaque' in stripped + if name in existing_symbols: + if existing_symbols[name] == 'opaque' and not is_opaque: + replaced_opaque_names.add(name) + existing_symbols[name] = 'full' + idx = len(all_stub_lines) + all_stub_lines.append(line) + stub_type_map[name] = (is_opaque, idx) + continue + if name in stub_type_map: + prev_opaque, prev_idx = stub_type_map[name] + if prev_opaque and not is_opaque: + all_stub_lines[prev_idx] = None + idx = len(all_stub_lines) + all_stub_lines.append(line) + stub_type_map[name] = (is_opaque, idx) + continue + idx = len(all_stub_lines) + all_stub_lines.append(line) + stub_type_map[name] = (is_opaque, idx) + else: + all_stub_lines.append(line) + elif stripped.startswith('@') and (' global ' in stripped or ' constant ' in stripped): + gm = re.match(r'(@\S+)', stripped) + if gm and (gm.group(1) in existing_global_defs or gm.group(1) in stub_global_defs): + continue + if gm: + stub_global_defs.add(gm.group(1)) + all_stub_lines.append(line) + else: + all_stub_lines.append(line) + filtered = [l for l in all_stub_lines if l is not None] + if filtered: + stub_prefix = '\n'.join(filtered) + '\n' + lines_to_remove = set() + if replaced_opaque_names: + for name in replaced_opaque_names: + if name in opaque_line_indices: + lines_to_remove.add(opaque_line_indices[name]) + if replaced_declare_names: + for fname in replaced_declare_names: + if fname in existing_declare_lines: + lines_to_remove.add(existing_declare_lines[fname]) + if lines_to_remove: + ll_lines = ll_content.splitlines(True) + ll_content = ''.join(line for i, line in enumerate(ll_lines) if i not in lines_to_remove) + type_defs_in_ll = [] + type_def_line_indices = set() + for i, line in enumerate(ll_content.splitlines()): + stripped = line.strip() + if stripped.startswith('%') and '= type' in stripped: + type_defs_in_ll.append(line) + type_def_line_indices.add(i) + if type_def_line_indices: + ll_lines = ll_content.splitlines(True) + ll_content = ''.join(line for i, line in enumerate(ll_lines) if i not in type_def_line_indices) + if type_defs_in_ll: + stub_prefix += '\n'.join(type_defs_in_ll) + '\n' + if stub_prefix: + header_end = 0 + for i, line in enumerate(ll_content.splitlines()): + stripped = line.strip() + if stripped.startswith(';') or stripped.startswith('target ') or stripped.startswith('source_filename') or not stripped: + header_end = i + 1 + continue + break + ll_lines = ll_content.splitlines(True) + ll_content = ''.join(ll_lines[:header_end]) + stub_prefix + ''.join(ll_lines[header_end:]) + ll_content = re.sub(r'\b(define|declare)\s+(private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external)\s+', r'\1 \2 dso_local ', ll_content) + ll_content = re.sub(r'\b(define|declare)\s+(?!private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external|dso_local|@)', r'\1 dso_local ', ll_content) + ll_content = re.sub(r'(@[\w.]+)\s*=\s*(private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external)\s+(global|constant)', r'\1 = \2 dso_local \3', ll_content) + ll_content = re.sub(r'(@[\w.]+)\s*=\s+(?!private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external|dso_local)(global|constant)', r'\1 = dso_local \2', ll_content) + final_type_defs = [] + final_type_def_indices = set() + for i, line in enumerate(ll_content.splitlines()): + stripped = line.strip() + if stripped.startswith('%') and '= type' in stripped: + final_type_defs.append(line) + final_type_def_indices.add(i) + if final_type_def_indices: + final_lines = ll_content.splitlines(True) + ll_content_no_types = ''.join(line for i, line in enumerate(final_lines) if i not in final_type_def_indices) + header_end = 0 + for i, line in enumerate(ll_content_no_types.splitlines()): + stripped = line.strip() + if stripped.startswith(';') or stripped.startswith('target ') or stripped.startswith('source_filename') or not stripped: + header_end = i + 1 + continue + break + final_lines2 = ll_content_no_types.splitlines(True) + ll_content = ''.join(final_lines2[:header_end]) + '\n'.join(final_type_defs) + '\n' + ''.join(final_lines2[header_end:]) + dso_ll_path = ll_path[:-3] + '_dso.ll' + with open(dso_ll_path, 'w', encoding='utf-8') as f: + f.write(ll_content) + cmd = [self.compile_cmd] + self.compile_flags + ['-o', obj_path, dso_ll_path] + result = subprocess.run(cmd, capture_output=True, text=True, + cwd=os.path.dirname(ll_path) or '.') + if result.returncode == 0: + return (rel, 'ok', '') + else: + return (rel, 'error', result.stderr.strip()) + except FileNotFoundError: + return (rel, 'error', f'找不到编译器: {self.compile_cmd}') + except Exception as e: + return (rel, 'error', str(e)) + + need_compile = [] + for ll_path in ll_files: + obj_path = ll_path[:-3] + '.obj' + if not os.path.isfile(obj_path): + need_compile.append(ll_path) + + if need_compile: + n_workers = min(os.cpu_count() or 4, len(need_compile), 8) + print(f" 并行编译 {len(need_compile)} 个文件 (workers={n_workers})") + errors = [] + with ThreadPoolExecutor(max_workers=n_workers) as executor: + futures = {executor.submit(_compile_one, ll_path): ll_path for ll_path in need_compile} + for future in as_completed(futures): + rel, status, err = future.result() + if status == 'ok': + print(f" [成功] {rel}") + elif status == 'error': + print(f" [错误] {rel}: {err}") + errors.append((rel, err)) + elif status == 'cached': + pass + if errors: + print(f"\n[编译终止] {len(errors)} 个文件编译失败") + sys.exit(1) + + def _scan_include_libraries(self): + """扫描 includes 目录,检测被使用的模块对应的库文件和源文件""" + if not self.used_includes: + return + + for includes_dir in self.include_dirs: + if not os.path.isdir(includes_dir): + continue + + for module_name in self.used_includes: + module_dir = os.path.join(includes_dir, module_name) + if os.path.isdir(module_dir): + self._scan_dir_for_libs(module_dir, module_name) + for root, dirs, files in os.walk(module_dir): + dirs[:] = [d for d in dirs if not d.startswith('.') and d != '__pycache__'] + for fname in files: + if fname.endswith('.py'): + py_path = os.path.join(root, fname) + if py_path not in self.extra_py_files: + self.extra_py_files.append(py_path) + print(f" [includes] 发现 Python 包文件: {os.path.relpath(py_path, includes_dir)}") + + for ext in self.INCLUDE_LIB_EXTENSIONS: + lib_path = os.path.join(includes_dir, module_name + ext) + if os.path.isfile(lib_path): + self.extra_link_files.append(lib_path) + print(f" [includes] 发现库文件: {os.path.relpath(lib_path, includes_dir)}") + + for ext in self.INCLUDE_SRC_EXTENSIONS: + src_path = os.path.join(includes_dir, module_name + ext) + if os.path.isfile(src_path): + self.extra_compile_files.append(src_path) + print(f" [includes] 发现源文件: {os.path.relpath(src_path, includes_dir)}") + + py_path = os.path.join(includes_dir, module_name + '.py') + if os.path.isfile(py_path): + self.extra_py_files.append(py_path) + print(f" [includes] 发现 Python 源文件: {os.path.relpath(py_path, includes_dir)}") + + discovered = set() + for ef in list(self.extra_py_files): + self._discover_transitive_deps(ef, includes_dir, discovered) + + if self.extra_link_files: + print(f"\n[includes] 需要链接的库文件: {len(self.extra_link_files)} 个") + if self.extra_compile_files: + print(f"[includes] 需要编译的源文件: {len(self.extra_compile_files)} 个") + + def _scan_dir_for_libs(self, directory: str, module_name: str): + """递归扫描目录中的库文件和源文件""" + for root, dirs, files in os.walk(directory): + for fname in files: + fpath = os.path.join(root, fname) + _, ext = os.path.splitext(fname) + ext = ext.lower() + if ext in self.INCLUDE_LIB_EXTENSIONS: + self.extra_link_files.append(fpath) + print(f" [includes] 发现库文件: {os.path.relpath(fpath, directory)}") + elif ext in self.INCLUDE_SRC_EXTENSIONS: + self.extra_compile_files.append(fpath) + print(f" [includes] 发现源文件: {os.path.relpath(fpath, directory)}") + + def _discover_transitive_deps(self, py_path: str, includes_dir: str, discovered: set): + """递归发现 Python 文件的间接依赖""" + if py_path in discovered: + return + discovered.add(py_path) + try: + with open(py_path, 'r', encoding='utf-8') as f: + content = f.read() + import ast as _ast + tree = _ast.parse(content) + for node in _ast.walk(tree): + if isinstance(node, _ast.Import): + for alias in node.names: + mod = alias.name.split('.')[0] + self._try_add_include_dep(mod, includes_dir, discovered) + elif isinstance(node, _ast.ImportFrom): + if node.module and node.level == 0: + mod = node.module.split('.')[0] + self._try_add_include_dep(mod, includes_dir, discovered) + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _config_mode + if _config_mode == "strict": + raise + _vlog().warning(f"发现 include 传递依赖失败: {_e}", "Exception") + + def _try_add_include_dep(self, module_name: str, includes_dir: str, discovered: set): + """尝试将模块添加为 include 依赖""" + py_path = os.path.join(includes_dir, module_name + '.py') + if os.path.isfile(py_path) and py_path not in self.extra_py_files: + self.extra_py_files.append(py_path) + print(f" [includes] 发现间接依赖: {os.path.relpath(py_path, includes_dir)}") + self._discover_transitive_deps(py_path, includes_dir, discovered) + + def _is_decl_only_file(self, src_path: str) -> bool: + try: + with open(src_path, 'r', encoding='utf-8') as f: + content = f.read() + import ast as _ast + tree = _ast.parse(content) + for node in _ast.walk(tree): + if isinstance(node, _ast.ClassDef): + return False + if isinstance(node, _ast.FunctionDef): + body = node.body + if len(body) == 1: + stmt = body[0] + if isinstance(stmt, _ast.Expr) and isinstance(stmt.value, _ast.Constant) and stmt.value.value is ...: + continue + if isinstance(stmt, _ast.Pass): + continue + return False + return True + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _config_mode + if _config_mode == "strict": + raise + _vlog().warning(f"判断是否为声明文件失败: {_e}", "Exception") + return False + + def _sort_include_files_by_deps(self, file_list: list) -> list: + """按依赖关系对 include 文件进行拓扑排序,确保被依赖的文件先编译""" + import ast as _ast + + # 构建文件名到路径的映射 + name_to_path = {} + for fpath in file_list: + basename = os.path.splitext(os.path.basename(fpath))[0] + name_to_path[basename] = fpath + + # 也支持包内模块: vpsdk/window -> path + for fpath in file_list: + # 尝试从 includes 目录推断模块全名 + for includes_dir in self.include_dirs: + try: + rel = os.path.relpath(fpath, includes_dir) + mod_name = os.path.splitext(rel)[0].replace(os.sep, '.').replace('/', '.') + name_to_path[mod_name] = fpath + except ValueError: + pass + + # 分析每个文件的 import 依赖 + deps = {} # path -> set of paths it depends on + for fpath in file_list: + deps[fpath] = set() + try: + with open(fpath, 'r', encoding='utf-8') as f: + content = f.read() + tree = _ast.parse(content) + for node in _ast.iter_child_nodes(tree): + if isinstance(node, _ast.Import): + for alias in node.names: + mod = alias.name.split('.')[0] + if mod in name_to_path and name_to_path[mod] != fpath: + deps[fpath].add(name_to_path[mod]) + elif isinstance(node, _ast.ImportFrom): + if node.module and node.level == 0: + mod = node.module.split('.')[0] + if mod in name_to_path and name_to_path[mod] != fpath: + deps[fpath].add(name_to_path[mod]) + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _config_mode + if _config_mode == "strict": + raise + _vlog().warning(f"分析 include 文件导入依赖失败: {_e}", "Exception") + + # 拓扑排序 (Kahn's algorithm) + in_degree = {fpath: len(deps[fpath]) for fpath in file_list} + # 反向邻接表:如果 A 依赖 B,则 B -> A + reverse_adj = {fpath: [] for fpath in file_list} + for fpath in file_list: + for dep in deps[fpath]: + if dep in reverse_adj: + reverse_adj[dep].append(fpath) + + result = [] + queue = [fpath for fpath in file_list if in_degree[fpath] == 0] + # 对队列排序以保持确定性 + queue.sort(key=lambda x: x) + + while queue: + current = queue.pop(0) + result.append(current) + for neighbor in reverse_adj[current]: + in_degree[neighbor] -= 1 + if in_degree[neighbor] == 0: + queue.append(neighbor) + queue.sort(key=lambda x: x) + + # 如果有循环依赖,把剩余文件也加入 + for fpath in file_list: + if fpath not in result: + result.append(fpath) + + return result + + def _compile_include_py_files(self, active_sha1s: set): + """通过 TransPyC 翻译器编译 includes 目录中发现的 .py 文件""" + if not self.extra_py_files: + return + + # 按依赖关系排序 include 文件,确保被依赖的文件先编译 + sorted_files = self._sort_include_files_by_deps(self.extra_py_files) + + print(f"\n[includes 编译] 找到 {len(sorted_files)} 个 Python 源文件") + + # 构建 include 文件的模块 SHA1 映射 + # 必须在编译前预构建完整的映射,否则后续文件引用前面文件时会用错误的 SHA1 + include_ModuleSha1Map = self._build_current_ModuleSha1Map(None) + # 预先为所有 include 文件计算 SHA1 并添加到映射中 + for src_path in sorted_files: + module_name = os.path.splitext(os.path.basename(src_path))[0] + with open(src_path, 'r', encoding='utf-8') as f: + py_content = f.read() + sha1 = compute_sha1(py_content) + self.include_py_map[module_name] = sha1 + active_sha1s.add(sha1) + self._include_sha1s.add(sha1) + + # 将 include 文件的模块名映射到其 SHA1 + for includes_dir in self.include_dirs: + try: + rel = os.path.relpath(src_path, includes_dir) + mod_full = os.path.splitext(rel)[0].replace(os.sep, '.').replace('/', '.') + include_ModuleSha1Map[mod_full] = sha1 + include_ModuleSha1Map[module_name] = sha1 + except ValueError: + pass + include_ModuleSha1Map[module_name] = sha1 + ll_path = os.path.join(self.output_dir, f"{sha1}.ll") + obj_path = os.path.join(self.output_dir, f"{sha1}.obj") + + if self._is_decl_only_file(src_path): + print(f" 跳过(声明文件): {module_name}.py") + self._collect_inline_symbols(src_path) + continue + + if os.path.isfile(obj_path): + print(f" 跳过(缓存): {module_name}.py -> {sha1}.obj") + self._collect_inline_symbols(src_path) + self.extra_link_files.append(obj_path) + continue + + print(f" 翻译: {os.path.basename(src_path)} -> {sha1}.ll") + + try: + self._translate_file(src_path, ll_path, prebuilt_ModuleSha1Map=include_ModuleSha1Map) + if os.path.isfile(ll_path): + print(f" 编译: {sha1}.ll -> {sha1}.obj") + with open(ll_path, 'r', encoding='utf-8') as f: + ll_content = f.read() + import re + ll_content = re.sub(r'\b(define|declare)\s+(private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external)\s+', r'\1 \2 dso_local ', ll_content) + ll_content = re.sub(r'\b(define|declare)\s+(?!private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external|dso_local)', r'\1 dso_local ', ll_content) + ll_content = re.sub(r'(@[\w.]+)\s*=\s*(private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external)\s+(global|constant)', r'\1 = \2 dso_local \3', ll_content) + ll_content = re.sub(r'(@[\w.]+)\s*=\s+(?!private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external|dso_local)(global|constant)', r'\1 = dso_local \2', ll_content) + stub_decls = [] + for other_sha1, other_stub in self.stub_files.items(): + if other_sha1 == sha1: + continue + if os.path.exists(other_stub): + try: + with open(other_stub, 'r', encoding='utf-8') as sf: + for sline in sf: + sl = sline.strip() + if sl.startswith('%') and '= type' in sl and 'opaque' not in sl: + struct_name_match = re.match(r'%"?([\w.]+)"?\s*=', sl) + if struct_name_match: + stub_decls.append(sl) + except: + pass + if stub_decls: + for sdecl in stub_decls: + sname_match = re.match(r'%"?([\w.]+)"?\s*=\s*type', sdecl) + if sname_match: + sname = sname_match.group(1) + short = sname.split('.')[-1] if '.' in sname else sname + ll_content = re.sub( + r'%"?' + re.escape(sname) + r'"?\s*=\s*type\s*opaque', + sdecl, ll_content) + if short != sname: + ll_content = re.sub( + r'%"?' + re.escape(short) + r'"?\s*=\s*type\s*opaque', + sdecl, ll_content) + dso_ll_path = ll_path[:-3] + '_dso.ll' + with open(dso_ll_path, 'w', encoding='utf-8') as f: + f.write(ll_content) + cmd = [self.compile_cmd] + self.compile_flags + ['-o', obj_path, dso_ll_path] + result = subprocess.run( + cmd, + capture_output=True, + text=True, + cwd=self.output_dir + ) + if result.returncode == 0: + print(f" [成功]") + self.extra_link_files.append(obj_path) + + # 编译成功后,生成 .pyi 签名文件和 .stub.ll 文件 + # 并注册到符号表和签名映射中,以便后续 include 文件可以引用 + self._register_compiled_include(src_path, sha1, ll_content, include_ModuleSha1Map) + else: + print(f" [警告] 编译失败: {result.stderr.strip()}") + for ext in ['.ll', '_dso.ll']: + p = ll_path[:-3] + ext + if os.path.isfile(p): + os.remove(p) + else: + print(f" [错误] 翻译未生成 .ll 文件") + except Exception as e: + import traceback + for ext in ['.ll', '_dso.ll']: + p = ll_path[:-3] + ext + if os.path.isfile(p): + os.remove(p) + print(f" [错误] 翻译异常: {e}") + traceback.print_exc() + print(f"\n[编译终止] includes 文件翻译失败") + sys.exit(1) + + def _register_compiled_include(self, src_path, sha1, ll_content, include_ModuleSha1Map): + """编译 include 文件成功后,生成签名和 stub 文件并注册到符号表中""" + module_name = os.path.splitext(os.path.basename(src_path))[0] + + # 确定完整模块名(如 vpsdk.window) + mod_full = module_name + for includes_dir in self.include_dirs: + try: + rel = os.path.relpath(src_path, includes_dir) + mod_full = os.path.splitext(rel)[0].replace(os.sep, '.').replace('/', '.') + break + except ValueError: + pass + + # 1. 生成 .pyi 签名文件(如果还没有的话) + sig_path = os.path.join(self.temp_dir, f"{sha1}.pyi") + if not os.path.isfile(sig_path): + try: + with open(src_path, 'r', encoding='utf-8') as f: + py_content = f.read() + sig_content = PythonToStubConverter.convert(py_content, mod_full) + os.makedirs(self.temp_dir, exist_ok=True) + with open(sig_path, 'w', encoding='utf-8', newline='\n') as f: + f.write(sig_content) + except Exception as e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _config_mode + if _config_mode == "strict": + raise + _vlog().warning(f"签名生成失败不阻塞编译: {e}", "Exception") + + # 注册到 sig_files 和 _source_module_sig_files + if os.path.isfile(sig_path): + self.sig_files[sha1] = sig_path + self.sha1_map[sha1] = f"includes/{mod_full.replace('.', os.sep)}.py" + if hasattr(self, '_shared_source_module_sig_files') and self._shared_source_module_sig_files is not None: + self._shared_source_module_sig_files[mod_full] = sig_path + self._shared_source_module_sig_files[module_name] = sig_path + + # 将签名信息加载到共享符号表中 + if hasattr(self, '_shared_symbol_table') and self._shared_symbol_table is not None: + try: + self._shared_symbol_table.LoadModuleSymbols(sig_path, mod_full, lineno=0) + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _config_mode + if _config_mode == "strict": + raise + _vlog().warning(f"加载模块签名到共享符号表失败: {_e}", "Exception") + + # 2. 生成 .stub.ll 文件 + stub_path = os.path.join(self.output_dir, f"{sha1}.stub.ll") + if not os.path.isfile(stub_path) and ll_content: + try: + stub_content, _ = self._split_ll(ll_content) + with open(stub_path, 'w', encoding='utf-8', newline='\n') as f: + f.write(stub_content) + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _config_mode + if _config_mode == "strict": + raise + _vlog().warning(f"生成 .stub.ll 文件失败: {_e}", "Exception") + + # 注册到 stub_files + if os.path.isfile(stub_path): + self.stub_files[sha1] = stub_path + elif os.path.isfile(sig_path): + # 如果 stub 文件不存在,也尝试从 temp 目录查找 + temp_stub = os.path.join(self.temp_dir, f"{sha1}.stub.ll") + if os.path.isfile(temp_stub): + self.stub_files[sha1] = temp_stub + + def _precollect_inline_symbols(self): + """在主翻译循环之前,扫描includes目录中used_includes相关的模块收集内联函数AST""" + if not self.used_includes: + return + for includes_dir in self.include_dirs: + if not os.path.isdir(includes_dir): + continue + for module_name in self.used_includes: + module_dir = os.path.join(includes_dir, module_name) + if os.path.isdir(module_dir): + for root, dirs, files in os.walk(module_dir): + dirs[:] = [d for d in dirs if not d.startswith('.') and d != '__pycache__'] + for fname in files: + if fname.endswith('.py'): + src_path = os.path.join(root, fname) + self._collect_inline_symbols(src_path) + py_path = os.path.join(includes_dir, module_name + '.py') + if os.path.isfile(py_path): + self._collect_inline_symbols(py_path) + for ef in self.extra_py_files: + self._collect_inline_symbols(ef) + + def _collect_inline_symbols(self, src_path: str): + """解析源文件,收集内联函数的AST信息到inline_func_symbols""" + try: + with open(src_path, 'r', encoding='utf-8') as f: + code = f.read() + tree = ast.parse(code) + module_name = os.path.splitext(os.path.basename(src_path))[0] + for node in ast.iter_child_nodes(tree): + if isinstance(node, ast.FunctionDef) and node.returns: + is_inline = False + if isinstance(node.returns, ast.BinOp) and isinstance(node.returns.op, ast.BitOr): + for part in [node.returns.left, node.returns.right]: + if isinstance(part, ast.Attribute) and part.attr == 'CInline': + is_inline = True + break + if isinstance(part, ast.Name) and part.id == 'CInline': + is_inline = True + break + elif isinstance(node.returns, ast.Attribute) and node.returns.attr == 'CInline': + is_inline = True + elif isinstance(node.returns, ast.Name) and node.returns.id == 'CInline': + is_inline = True + if is_inline: + func_name = node.name + sym_key = f"{module_name}.{func_name}" + info = CTypeInfo() + info.Name = func_name + info.IsFunction = True + info.IsInline = True + info.InlineBody = node.body + info.InlineParams = [arg.arg for arg in node.args.args] + info.Storage = t.CInline() + self.inline_func_symbols[func_name] = info + self.inline_func_symbols[sym_key] = info + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _config_mode + if _config_mode == "strict": + raise + _vlog().warning(f"预收集内联函数符号失败: {_e}", "Exception") + + def _build_shared_symbol_data(self): + """一次性构建所有文件共享的符号表数据,避免每个文件重复加载""" + import copy + import time + t0 = time.time() + + print("[缓存] 构建共享符号表数据...") + + base_trans = TransPyC.TransPyC(code="pass", triple=self.triple, datalayout=self.datalayout) + base_trans.translator.LlvmGen = None + base_trans.translator._ModuleSha1Map = {} + base_trans.translator._global_function_default_args = self.function_default_args + + for includes_dir in self.include_dirs: + if os.path.isdir(includes_dir): + for pyi_file in os.listdir(includes_dir): + if pyi_file.endswith('.pyi'): + pyi_path = os.path.join(includes_dir, pyi_file) + module_name = os.path.splitext(pyi_file)[0] + base_trans.translator.SymbolTable.LoadModuleSymbols(pyi_path, module_name, lineno=0) + for py_file in os.listdir(includes_dir): + if py_file.endswith('.py') and not py_file.startswith('_'): + module_name = os.path.splitext(py_file)[0] + sha1_key = self.include_py_map.get(module_name) + if sha1_key and sha1_key in self.sig_files: + sig_path = self.sig_files[sha1_key] + base_trans.translator.SymbolTable.LoadModuleSymbols(sig_path, module_name, lineno=0) + # 收集需要重导出的包,等所有模块符号加载完后再处理 + _pending_reexports = [] + for sha1_key, sig_path in self.sig_files.items(): + rel_path = self.sha1_map.get(sha1_key, sha1_key) + if rel_path.startswith('includes/'): + mod_name = os.path.splitext(rel_path)[0].replace(os.sep, '.').replace('/', '.') + mod_name = mod_name[len('includes/'):] + base_trans.translator.SymbolTable.LoadModuleSymbols(sig_path, mod_name, lineno=0) + if mod_name.endswith('.__init__'): + package_name = mod_name[:-len('.__init__')] + _pending_reexports.append((sig_path, package_name)) + + # 所有 includes 模块符号已加载,现在处理包重导出 + for sig_path, package_name in _pending_reexports: + self._register_package_reexports(base_trans, sig_path, package_name) + + for sha1_key, sig_path in self.sig_files.items(): + rel_path = self.sha1_map.get(sha1_key, sha1_key) + if rel_path.startswith('includes/'): + continue + module_name = os.path.splitext(rel_path)[0].replace(os.sep, '.').replace('/', '.') + base_trans.translator.SymbolTable.LoadModuleSymbols(sig_path, module_name, lineno=0) + base_trans.translator._source_module_sig_files[module_name] = sig_path + short_name = module_name.split('.')[-1] if '.' in module_name else module_name + if short_name != module_name: + base_trans.translator._source_module_sig_files[short_name] = sig_path + + all_dc = {} + for sha1_key, stub_path in self.stub_files.items(): + if os.path.exists(stub_path): + try: + with open(stub_path, 'r', encoding='utf-8') as f: + stub_content = f.read() + for line in stub_content.splitlines(): + line = line.strip() + if line.startswith('@') and '= global' in line and 'i32' in line and not line.startswith('@llvm'): + var_name = line.split('=')[0].strip().lstrip('@') + val_part = line.split('i32')[-1].strip().rstrip(']').lstrip('[').lstrip('i32') + try: + val = int(val_part) + all_dc[var_name] = val + except: + pass + except: + pass + + for sha1_key, pyi_path in self.sig_files.items(): + if os.path.exists(pyi_path): + try: + with open(pyi_path, 'r', encoding='utf-8') as f: + pyi_content = f.read() + tree = ast.parse(pyi_content) + for node in ast.iter_child_nodes(tree): + if isinstance(node, ast.AnnAssign) and isinstance(node.target, ast.Name): + ann_str = ast.dump(node.annotation) + if 'CDefine' in ann_str and node.value: + val = None + if isinstance(node.value, ast.Constant): + val = node.value.value + elif isinstance(node.value, ast.Call) and isinstance(node.value.func, ast.Name) and node.value.func.id == 'float' and node.value.args and isinstance(node.value.args[0], ast.Constant): + val = node.value.args[0].value + if val is not None: + all_dc[f"{node.target.id}"] = val + except: + pass + + export_extern_funcs = set() + for sha1_key, sig_path in self.sig_files.items(): + try: + with open(sig_path, 'r', encoding='utf-8') as f: + sig_content = f.read() + sig_tree = ast.parse(sig_content) + for node in ast.iter_child_nodes(sig_tree): + if isinstance(node, ast.FunctionDef): + if _check_annotation_for_export(node.returns): + export_extern_funcs.add(node.name) + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _config_mode + if _config_mode == "strict": + raise + _vlog().warning(f"收集共享导出外部函数失败: {_e}", "Exception") + + for sym_name, sym_info in self.inline_func_symbols.items(): + if sym_name not in base_trans.translator.SymbolTable: + base_trans.translator.SymbolTable[sym_name] = sym_info + else: + existing = base_trans.translator.SymbolTable[sym_name] + if not getattr(existing, 'InlineBody', None) and getattr(sym_info, 'InlineBody', None): + existing.IsInline = sym_info.IsInline + existing.InlineBody = sym_info.InlineBody + existing.InlineParams = sym_info.InlineParams + + self._shared_symbol_table = base_trans.translator.SymbolTable + self._shared_source_module_sig_files = dict(base_trans.translator._source_module_sig_files) + self._shared_all_dc = all_dc + self._shared_export_extern_funcs = export_extern_funcs + + generic_class_templates = {} + for includes_dir in self.include_dirs: + if os.path.isdir(includes_dir): + abs_includes = os.path.join(self.src_root, includes_dir) if not os.path.isabs(includes_dir) else includes_dir + if not os.path.isdir(abs_includes): + abs_includes = includes_dir + for py_file in os.listdir(abs_includes): + if py_file.endswith('.py') and not py_file.startswith('_'): + py_path = os.path.join(abs_includes, py_file) + try: + with open(py_path, 'r', encoding='utf-8') as f: + py_code = f.read() + py_tree = ast.parse(py_code) + for node in py_tree.body: + if isinstance(node, ast.ClassDef) and hasattr(node, 'type_params') and node.type_params: + type_params = [tp.name for tp in node.type_params] + generic_class_templates[node.name] = { + 'node': node, + 'type_params': type_params, + } + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _config_mode + if _config_mode == "strict": + raise + _vlog().warning(f"收集泛型类模板失败: {_e}", "Exception") + self._shared_generic_class_templates = generic_class_templates + + t1 = time.time() + print(f"[缓存] 共享符号表构建完成 ({t1-t0:.2f}s, {len(self._shared_symbol_table)} 符号, {len(generic_class_templates)} 泛型模板)") + + def _compile_include_sources(self): + """扫描项目目录中的汇编存根,编译 includes 目录中发现的 C/C++ 源文件""" + extra_sources = list(self.extra_compile_files) + scan_dirs = [] + if self.src_root and os.path.isdir(self.src_root): + scan_dirs.append(self.src_root) + project_dir = os.path.dirname(self.output_dir) + if project_dir and os.path.isdir(project_dir) and project_dir not in scan_dirs: + scan_dirs.append(project_dir) + for scan_dir in scan_dirs: + for root, dirs, files in os.walk(scan_dir): + dirs[:] = [d for d in dirs if not d.startswith('.') and d != '__pycache__'] + for fname in files: + if fname.endswith(('.S', '.s', '.c', '.cpp')): + if fname.startswith('test_'): + continue + fpath = os.path.join(root, fname) + if fpath not in extra_sources: + extra_sources.append(fpath) + if not extra_sources: + return + + cc_map = { + '.c': 'gcc', + '.cpp': 'g++', '.cc': 'g++', '.cxx': 'g++', + '.m': 'clang', '.mm': 'clang++', + '.s': 'gcc', '.S': 'gcc', + } + + print(f"\n[includes 编译] 找到 {len(extra_sources)} 个源文件") + + for src_path in extra_sources: + _, ext = os.path.splitext(src_path) + ext = ext.lower() + obj_path = os.path.join(self.output_dir, os.path.splitext(os.path.basename(src_path))[0] + '.obj') + if ext in ('.s', '.S') and any('oformat' in f for f in self.linker_flags): + cc = 'clang' + compile_src = src_path + extra_flags = ['-c', '-target', 'x86_64-none-elf', '-o', obj_path, compile_src] + else: + cc = cc_map.get(ext, 'gcc') + extra_flags = ['-c', '-o', obj_path, src_path] + + print(f" 编译: {os.path.basename(src_path)} -> {os.path.basename(obj_path)}") + + try: + cmd = [cc] + extra_flags + result = subprocess.run(cmd, capture_output=True, text=True) + if result.returncode == 0: + print(f" [成功]") + self.extra_link_files.append(obj_path) + else: + print(f" [错误] 编译失败: {result.stderr.strip()}") + print(f"\n[编译终止] C/C++ 源文件编译失败,立即终止编译。") + sys.exit(1) + except FileNotFoundError: + print(f" [错误] 找不到编译器: {cc}") + print(f"\n[编译终止] 找不到编译器,立即终止编译。") + sys.exit(1) + except Exception as e: + print(f" [错误] {e}") + print(f"\n[编译终止] 编译异常,立即终止编译。") + sys.exit(1) + + def _strip_debug_sections(self, exe_path: str): + """剥离 .exe 中的调试段(跳过裸机二进制)""" + if not os.path.exists(exe_path): + return + ext = os.path.splitext(exe_path)[1].lower() + if ext not in ('.exe', '.dll', '.obj', '.o', '.elf'): + print(f" [剥离] 跳过({ext} 格式无需剥离)") + return + import shutil + for tool in ['llvm-strip', 'strip']: + strip_cmd = shutil.which(tool) + if strip_cmd: + try: + result = subprocess.run( + [strip_cmd, '--strip-debug', exe_path], + capture_output=True, text=True + ) + if result.returncode == 0: + print(f" [剥离] 调试段已移除 ({tool})") + else: + print(f" [剥离] 警告: {result.stderr.strip()}") + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _config_mode + if _config_mode == "strict": + raise + _vlog().warning(f"剥离可执行文件调试段失败: {_e}", "Exception") + break + + def _generate_startup_obj(self): + """当 project.json 中配置了 startup 时,生成符号别名 shim。 + + startup 配置格式: + true -> 等价于 {"__main": "main"} + {"__main": "main", "_start": "main"} -> 为每个别名生成调用目标函数的包装 + + 生成的 .ll 会被编译为 _startup.obj 并加入链接列表。 + """ + if not self.startup: + return None + + # 归一化配置 + if self.startup is True: + aliases = {"__main": "main"} + elif isinstance(self.startup, dict): + aliases = self.startup + else: + return None + + # 构建 LLVM IR + decls = [] + defs = [] + for alias_name, target_name in aliases.items(): + # 声明目标函数 + decls.append(f"declare i32 @{target_name}()") + # 定义别名函数:调用目标函数并返回其返回值 + defs.append( + f"define dso_local i32 @{alias_name}() {{\n" + f"entry:\n" + f" %r = call i32 @{target_name}()\n" + f" ret i32 %r\n" + f"}}\n" + ) + + ll_content = "; startup shim (auto-generated)\n" + "\n".join(decls) + "\n\n" + "\n".join(defs) + "\n" + + ll_path = os.path.join(self.output_dir, '_startup.ll') + obj_path = os.path.join(self.output_dir, '_startup.obj') + + with open(ll_path, 'w', encoding='utf-8', newline='\n') as f: + f.write(ll_content) + + # 编译为 .obj + cmd = [self.compile_cmd] + self.compile_flags + ['-o', obj_path, ll_path] + result = subprocess.run(cmd, capture_output=True, text=True, cwd=self.output_dir or '.') + if result.returncode != 0: + print(f" [startup] 编译失败: {result.stderr.strip()}") + return None + + print(f" [startup] 生成符号别名: {aliases}") + return obj_path + + def _link_obj_files(self, active_sha1s: set): + """将 active_sha1s 对应的 .obj 文件和 includes 库文件链接为可执行文件""" + obj_files = [] + merged_obj = os.path.join(self.output_dir, '_merged.obj') + if os.path.isfile(merged_obj): + obj_files.append(merged_obj) + else: + for root, dirs, files in os.walk(self.output_dir): + for file in files: + if file.endswith('.obj'): + sha1 = file[:-4] + if sha1 in active_sha1s and sha1 not in self._include_sha1s: + obj_files.append(os.path.join(root, file)) + + if not obj_files and not self.extra_link_files: + print("[链接] 无文件可链接") + return + + # 生成 startup 符号别名 shim + startup_obj = self._generate_startup_obj() + if startup_obj: + obj_files.append(startup_obj) + + print(f"\n[链接] 找到 {len(obj_files)} 个 .obj 文件") + + all_link_files = obj_files + self.extra_link_files + seen = set() + all_link_files = [f for f in all_link_files if not (f in seen or seen.add(f))] + if self.extra_link_files: + print(f"[链接] 额外库文件: {len(self.extra_link_files)} 个") + for lib in self.extra_link_files: + print(f" - {os.path.basename(lib)}") + + if not self.linker_cmd: + print("[链接] 未配置链接器") + return + + exe_path = os.path.join(self.output_dir, self.linker_output) if self.linker_output else os.path.join(self.output_dir, 'a.exe') + is_binary = self.linker_output and self.linker_output.endswith('.bin') + + # 检查是否直接输出二进制(使用 --oformat binary / -oformat binary 标志) + is_direct_binary = is_binary and any('oformat' in f for f in self.linker_flags) + + if is_binary and not is_direct_binary: + link_output = exe_path[:-4] + '_pe.exe' + else: + link_output = exe_path + + # 自动复制或生成 linker.ld 到输出目录 + linker_ld_src = os.path.join(os.path.dirname(self.output_dir), 'linker.ld') + linker_ld_dst = os.path.join(self.output_dir, 'linker.ld') + if os.path.isfile(linker_ld_src) and not os.path.isfile(linker_ld_dst): + import shutil + shutil.copy2(linker_ld_src, linker_ld_dst) + print(f" [链接] 使用链接脚本: linker.ld") + elif not os.path.isfile(linker_ld_dst) and any('-T' in f or '-T' in f.replace(',', ' ') for f in self.linker_flags): + default_ld = """ENTRY(_start) + +SECTIONS { + . = 0x100000; + + .text : { + *(.text.startup) + *(.text) + *(.text.*) + } + + .rodata : { + *(.rodata) + *(.rodata.*) + } + + .data : { + *(.data) + *(.data.*) + } + + .bss : { + *(.bss) + *(.bss.*) + } + + /DISCARD/ : { + *(.comment) + *(.note) + *(.eh_frame) + *(.eh_frame_hdr) + *(.reloc) + *(.rela) + *(.debug*) + } +} +""" + with open(linker_ld_dst, 'w', encoding='utf-8', newline='\n') as f: + f.write(default_ld) + print(f" [链接] 自动创建默认链接脚本: linker.ld") + + try: + # 将 linker_flags 拆分为非库标志和库标志(-l/-L),库标志放在目标文件之后 + # 这样 Unix 风格链接器才能正确解析库中的符号 + # -Wl, 选项是链接器全局选项,放在目标文件之前 + non_lib_flags = [] + lib_flags = [] + i = 0 + while i < len(self.linker_flags): + flag = self.linker_flags[i] + if flag in ('-l', '-L') and i + 1 < len(self.linker_flags): + # -l xxx / -L xxx 分开的形式 + lib_flags.extend([flag, self.linker_flags[i + 1]]) + i += 2 + elif flag.startswith('-l') or flag.startswith('-L'): + # -lxxx / -Lxxx 合并的形式 + lib_flags.append(flag) + i += 1 + else: + # 其他所有标志(包括 -Wl, 选项)放在目标文件之前 + non_lib_flags.append(flag) + i += 1 + cmd = [self.linker_cmd] + non_lib_flags + ['-o', link_output] + all_link_files + lib_flags + print(f" 执行: {' '.join(cmd)}") + result = subprocess.run( + cmd, + capture_output=True, + text=True, + cwd=self.output_dir or '.' + ) + if result.returncode == 0: + if is_binary and not is_direct_binary: + import shutil + objcopy = shutil.which('llvm-objcopy') or shutil.which('objcopy') + if objcopy: + conv = subprocess.run( + [objcopy, '-O', 'binary', link_output, exe_path], + capture_output=True, text=True + ) + if conv.returncode == 0: + os.remove(link_output) + print(f" [成功] 生成裸机二进制: {exe_path}") + file_size = os.path.getsize(exe_path) + print(f" [大小] {file_size} 字节") + else: + print(f" [错误] 二进制转换失败: {conv.stderr.strip()}") + sys.exit(1) + else: + print(" [错误] 找不到 llvm-objcopy,无法生成裸机二进制") + sys.exit(1) + else: + print(f" [成功] 生成: {exe_path}") + file_size = os.path.getsize(exe_path) + print(f" [大小] {file_size} 字节") + if not is_binary: + self._strip_debug_sections(exe_path) + else: + print(f" [错误] 链接失败: {result.stderr.strip()}") + print(f"\n[编译终止] 链接失败,立即终止编译。") + sys.exit(1) + except FileNotFoundError: + print(f" [错误] 找不到链接器: {self.linker_cmd}") + print(f"\n[编译终止] 找不到链接器,立即终止编译。") + sys.exit(1) + except Exception as e: + print(f" [错误] {e}") + print(f"\n[编译终止] 链接异常,立即终止编译。") + sys.exit(1) diff --git a/lib/Projectrans/Utils.py b/lib/Projectrans/Utils.py new file mode 100644 index 0000000..834fec7 --- /dev/null +++ b/lib/Projectrans/Utils.py @@ -0,0 +1,170 @@ +import hashlib +import os +import ast + + +def compute_sha1(content: str) -> str: + return hashlib.sha1(content.encode('utf-8')).hexdigest()[:16] + + +def _check_annotation_for_export(annotation) -> bool: + """递归检查类型注解中是否包含 CExport""" + if annotation is None: + return False + if isinstance(annotation, ast.Attribute): + if hasattr(annotation, 'attr') and annotation.attr == 'CExport': + return True + elif isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr): + return _check_annotation_for_export(annotation.left) or _check_annotation_for_export(annotation.right) + elif isinstance(annotation, ast.Name): + return annotation.id == 'CExport' + return False + + +def sha1_file(filepath: str) -> str: + with open(filepath, 'r', encoding='utf-8') as f: + content = f.read() + return compute_sha1(content) + + +def get_file_dependencies(filepath: str, src_root: str) -> set: + """解析 Python 文件的导入依赖""" + dependencies = set() + try: + with open(filepath, 'r', encoding='utf-8') as f: + content = f.read() + tree = ast.parse(content) + for node in ast.walk(tree): + if isinstance(node, ast.Import): + for alias in node.names: + module = alias.name + dependencies.add(module) + elif isinstance(node, ast.ImportFrom): + if node.module: + module = node.module + if node.level > 0: + # from .module import name → 依赖 pkg.module(模块本身) + pkg_dir = os.path.dirname(filepath) + pkg_rel = os.path.relpath(pkg_dir, src_root).replace(os.sep, '.').replace('/', '.') + if pkg_rel == '.': + pkg_rel = '' + if pkg_rel: + dep_module = f'{pkg_rel}.{module}' + else: + dep_module = module + dependencies.add(dep_module) + else: + if not module.startswith('_'): + dependencies.add(module) + elif node.level > 0 and node.names: + # from . import name → 依赖 pkg.name(子模块) + for alias in node.names: + pkg_dir = os.path.dirname(filepath) + pkg_rel = os.path.relpath(pkg_dir, src_root).replace(os.sep, '.').replace('/', '.') + if pkg_rel == '.': + pkg_rel = '' + dep_module = f'{pkg_rel}.{alias.name}' if pkg_rel else alias.name + dependencies.add(dep_module) + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _ConfigMode + if _ConfigMode == "strict": + raise + _vlog().warning(f"解析文件导入依赖失败: {_e}", "Exception") + return dependencies + + +def find_reachable_files_from_entries(src_root: str, entry_files: list) -> set: + """从入口文件出发,找出所有可达的 .py 文件(通过导入关系)""" + all_files = {} # module_name -> filepath + for root, dirs, files in os.walk(src_root): + dirs[:] = [d for d in dirs if d not in ('__pycache__',)] + for file in files: + if file.endswith('.py'): + filepath = os.path.join(root, file) + rel = os.path.relpath(filepath, src_root) + module = os.path.splitext(rel)[0].replace(os.sep, '.').replace('/', '.') + if filepath.endswith('__init__.py'): + all_files[module] = filepath + parent_module = module.rsplit('.', 1)[0] if '.' in module else module + if parent_module not in all_files or not all_files[parent_module].endswith('__init__.py'): + all_files[parent_module] = filepath + elif module not in all_files: + all_files[module] = filepath + top_module = module.split('.')[0] + if top_module not in all_files: + all_files[top_module] = filepath + + reachable = set() + queue = list(entry_files) + + while queue: + current = queue.pop(0) + if current in reachable: + continue + reachable.add(current) + deps = get_file_dependencies(current, src_root) + for dep in deps: + if dep in all_files and all_files[dep] not in reachable: + queue.append(all_files[dep]) + else: + for key, val in all_files.items(): + if key.endswith('.' + dep) or key == dep: + if val not in reachable: + queue.append(val) + break + + return reachable + + +def topological_sort_files(py_files: list, src_root: str) -> list: + """对 Python 文件进行拓扑排序,确保依赖模块先被处理""" + # 构建模块名到文件路径的映射 + module_to_file = {} + for filepath in py_files: + rel = os.path.relpath(filepath, src_root) + module = os.path.splitext(rel)[0].replace(os.sep, '.').replace('/', '.') + module_to_file[module] = filepath + # 也添加顶层模块名 + top_module = module.split('.')[0] + if top_module not in module_to_file: + module_to_file[top_module] = filepath + + # 构建依赖图 + graph = {f: set() for f in py_files} + for filepath in py_files: + deps = get_file_dependencies(filepath, src_root) + for dep in deps: + if dep in module_to_file: + dep_file = module_to_file[dep] + if dep_file != filepath: # 避免自依赖 + graph[filepath].add(dep_file) + + # 拓扑排序 (Kahn's algorithm) + in_degree = {f: 0 for f in py_files} + for f, deps in graph.items(): + for dep in deps: + if dep in in_degree: + in_degree[f] += 1 + + queue = [f for f, degree in in_degree.items() if degree == 0] + sorted_files = [] + + while queue: + # 按字母顺序处理同级别的文件,确保确定性 + queue.sort() + current = queue.pop(0) + sorted_files.append(current) + + for f, deps in graph.items(): + if current in deps: + in_degree[f] -= 1 + if in_degree[f] == 0: + queue.append(f) + + # 如果有环,添加剩余文件 + if len(sorted_files) < len(py_files): + remaining = [f for f in py_files if f not in sorted_files] + sorted_files.extend(remaining) + + return sorted_files diff --git a/lib/Projectrans/__init__.py b/lib/Projectrans/__init__.py new file mode 100644 index 0000000..2506ee1 --- /dev/null +++ b/lib/Projectrans/__init__.py @@ -0,0 +1,37 @@ +"""Projectrans 包 - 工程级 TransPyC 翻译器""" +import os +import sys + +# 确保项目根目录在 sys.path 中,以便 import TransPyC 和 from StubGen import ... 正常工作 +_PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +if _PROJECT_ROOT not in sys.path: + sys.path.insert(0, _PROJECT_ROOT) + +from lib.core.VLogger import Logger, LogLevel, set_logger + +# 创建全局日志实例 +logger = Logger( + name="TransPyC", + log_file="build.log", + level=LogLevel.INFO, + use_colors=True +) +set_logger(logger) + +from lib.Projectrans.Utils import ( + compute_sha1, _check_annotation_for_export, sha1_file, + get_file_dependencies, find_reachable_files_from_entries, + topological_sort_files +) +from lib.Projectrans.Phase1Generator import Phase1Generator +from lib.Projectrans.DeclarationGenerator import DeclarationGenerator +from lib.Projectrans.Phase2Translator import Phase2Translator, _parallel_translate_worker +from lib.Projectrans.Config import save_sha1_map, Load_sha1_map, Load_project_config, resolve_paths, main + +__all__ = [ + 'compute_sha1', '_check_annotation_for_export', 'sha1_file', + 'get_file_dependencies', 'find_reachable_files_from_entries', + 'topological_sort_files', 'Phase1Generator', 'DeclarationGenerator', + 'Phase2Translator', '_parallel_translate_worker', + 'save_sha1_map', 'Load_sha1_map', 'Load_project_config', 'resolve_paths', 'main' +] diff --git a/lib/Shell/Config.py b/lib/Shell/Config.py new file mode 100644 index 0000000..77bcaae --- /dev/null +++ b/lib/Shell/Config.py @@ -0,0 +1,5 @@ +class Config: + """配置类""" + def __init__(self): + self.debug = False + self.mode = 'relaxed' # 'relaxed' 或 'strict' diff --git a/lib/Shell/Serializer.py b/lib/Shell/Serializer.py new file mode 100644 index 0000000..8df3965 --- /dev/null +++ b/lib/Shell/Serializer.py @@ -0,0 +1,58 @@ +import json +import struct + + +def SerializeSymbolTable(SymbolTable: dict) -> bytes: + """将符号表序列化为二进制格式 + + 格式: + - 4字节: JSON数据长度(小端序) + - N字节: JSON数据(UTF-8编码) + + Args: + SymbolTable: 符号表字典 + + Returns: + 二进制字节数据 + """ + JsonData = json.dumps(SymbolTable, ensure_ascii=False).encode('utf-8') + length = len(JsonData) + # 使用4字节小端序整数表示长度 + header = struct.pack(' dict: + """从二进制数据反序列化符号表 + + Args: + data: 二进制字节数据 + + Returns: + 符号表字典 + """ + if len(data) < 4: + raise ValueError("Invalid symbin file: data too short") + # 解析4字节长度头(小端序) + length = struct.unpack(' -o [-debug ] + if I + 1 < len(sys.argv): + InputFile = sys.argv[I + 1] + I += 2 + + # 解析可选参数 + OutputFile = None + DebugFile = None + while I < len(sys.argv) and sys.argv[I].startswith('-'): + if sys.argv[I] == '-o': + if I + 1 < len(sys.argv): + OutputFile = sys.argv[I + 1] + I += 2 + else: + print(f'Error: -o requires an argument') + sys.exit(1) + elif sys.argv[I] == '-debug': + if I + 1 < len(sys.argv): + DebugFile = sys.argv[I + 1] + I += 2 + else: + print(f'Error: -debug requires an argument') + sys.exit(1) + else: + break + + # 如果没有指定输出文件,使用默认名称 + if not OutputFile: + OutputFile = InputFile.replace('.py', '.symbin').replace('.c', '.symbin') + + # 执行预处理 + self.Args['PreSym'] = { + 'input': InputFile, + 'output': OutputFile, + 'debug': DebugFile + } + else: + print(f'Error: -presym requires an argument') + sys.exit(1) + elif sys.argv[I] == '-e' or sys.argv[I] == '--encoding': + if I + 1 < len(sys.argv): + self.Args['Encoding'] = sys.argv[I + 1] + I += 2 + else: + print(f'Error: -e/--encoding requires an argument') + sys.exit(1) + elif sys.argv[I] == '--triple': + if I + 1 < len(sys.argv): + self.triple = sys.argv[I + 1] + I += 2 + else: + print(f'Error: --triple requires an argument') + sys.exit(1) + elif sys.argv[I] == '--datalayout': + if I + 1 < len(sys.argv): + self.datalayout = sys.argv[I + 1] + I += 2 + else: + print(f'Error: --datalayout requires an argument') + sys.exit(1) + else: + print(f'Error: Unknown argument {sys.argv[I]}') + sys.exit(1) + + # 检查是否有预处理符号文件的请求,如果有则跳过输入输出检查 + if 'PreSym' not in self.Args and ('Input' not in self.Args or 'Output' not in self.Args): + print(ERROR_MESSAGES['MISSING_ARGS']) + print(HELP_MESSAGE) + sys.exit(1) + + def CompileAndRun(self, OutputFile): + """编译并运行生成的C代码""" + # 获取编译命令 + CompileCmd = self.Args.get('CompileCommand', DEFAULT_COMPILE_COMMAND) + CompileFlags = self.Args.get('CompileFlags', DEFAULT_COMPILE_FLAGS) + + # 构建编译命令 + FullCompileCmd = f'{CompileCmd} {CompileFlags} {OutputFile} -o {OutputFile}.exe' + print(f'Compiling: {FullCompileCmd}') + + # 执行编译命令 + try: + CompileResult = ExecuteCommand(FullCompileCmd) + if CompileResult: + print('Compilation successful!') + + # 检查是否需要运行 + if self.Args.get('Run', False): + RunArgs = self.Args.get('RunArgs', '') + RunCmd = f'{OutputFile}.exe {RunArgs}'.strip() + print(f'Running: {RunCmd}') + + # 执行运行命令 + RunResult = ExecuteCommand(RunCmd) + if RunResult: + print('Execution output:') + print(RunResult.stdout) + if RunResult.stderr: + print('Execution errors:') + print(RunResult.stderr) + except Exception as e: + print(f'{ERROR_MESSAGES["COMPILE_FAILED"]}: {e}') + + def WriteDebugInfo(self, content): + """写入调试信息到指定文件""" + # 获取调试文件路径 + if 'Debug' in self.Args: + DebugFile = self.Args['Debug'] + else: + DebugFile = self.Args.get('Output', '').replace('.c', '.p2c') + + if DebugFile: + AppendFileContent(DebugFile, content) + + def PythonToC(self, InputFile, OutputFile): + """Python到C的转换""" + # 获取编码参数 + encoding = self.Args.get('Encoding', 'utf-8') + + # 设置调试文件路径(使用 .p2c 扩展名) + if 'Debug' in self.Args: + DebugFile = self.Args['Debug'] + else: + # 默认使用 .p2c 文件 + DebugFile = OutputFile.replace('.c', '.p2c') + + # 设置翻译器的调试文件 + self.translator.SetDebugFile(DebugFile) + + # 先清空调试文件 + with open(DebugFile, 'w', encoding=encoding) as f: + f.write('') + + # 解析辅助文件,提取符号信息 + if self.HelperFiles: + self.translator.ParseHelperFiles(self.HelperFiles, encoding) + + # 加载注解文件,提取类型定义 + if self.AnnotationFiles: + self.translator.LoadAnnotationFiles(self.AnnotationFiles) + + # 获取编码参数 + encoding = self.Args.get('Encoding', 'utf-8') + with open(InputFile, 'r', encoding=encoding) as F: + Content = F.read() + + # 保存原始代码行 + self.translator.OriginalLines = Content.split('\n') + self.translator.Content = Content + + # 解析Python代码为AST + Tree = ast.parse(Content) + + # 解析文件以提取类型信息(用于 EmbeddedAssignments) + self.translator.ParsePythonFile(InputFile, encoding) + + # 写入AST树信息(压缩格式) + with open(DebugFile, 'a', encoding=encoding) as f: + f.write('=== AST Tree (Compact) ===\n') + f.write(ast.dump(Tree)) + f.write('\n\n') + + Target = 'llvm' + CCode = self.translator.GenerateCCode(Tree, target=Target) + + import datetime + timestamp = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') + filename = os.path.basename(OutputFile) + + encoding = self.Args.get('Encoding', 'utf-8') + with open(OutputFile, 'w', encoding=encoding) as F: + F.write(CCode) + F.write('\n') + + def CToPython(self, InputFile, OutputFile, HeaderFiles): + """C到Python的转换(暂时禁用)""" + print("C到Python的转换功能暂时禁用,请使用Python到C的转换功能。") + + def AddSymbol(self, SymbolFiles): + """添加符号文件 + + Args: + SymbolFiles: 符号文件或符号文件列表 + """ + if isinstance(SymbolFiles, list): + self.SymbolFiles.extend(SymbolFiles) + else: + self.SymbolFiles.append(SymbolFiles) + + # 收集文件路径和编码 + HelperFiles = [] + encodings = [] + for SymbolFile in self.SymbolFiles: + FilePath = SymbolFile.FilePath + encoding = SymbolFile.encoding + if FilePath: + HelperFiles.append(FilePath) + encodings.append(encoding) + + # 解析辅助文件 + if HelperFiles: + # 暂时使用第一个文件的编码 + encoding = encodings[0] if encodings else 'utf-8' + self.translator.ParseHelperFiles(HelperFiles, encoding) + + def Convert(self, OutputFilename=None, SourceFilename=None, target='llvm'): + """转换代码 + + Args: + OutputFilename: 输出文件名(用于模板渲染) + SourceFilename: 源文件路径(用于设置CurrentFile,影响导入模块的查找) + target: 目标代码类型,仅支持 'llvm' + + Returns: + 如果debug是字符串,则返回生成的代码 + 如果debug是True,则返回生成的代码和调试信息 + """ + if not self.code: + print('Error: No code provided') + return None + + from lib.core.Handles.HandlesImports import ImportHandle + ImportHandle._struct_Load_cache.clear() + + # 如果提供了 SourceFilename,先设置 CurrentFile + # 这样导入模块时会相对于源文件所在目录查找 + if SourceFilename: + self.translator.CurrentFile = SourceFilename + + # 加载注解文件,提取类型定义 + if self.AnnotationFiles: + self.translator.LoadAnnotationFiles(self.AnnotationFiles) + + # 保存原始代码行 + self.translator.OriginalLines = self.code.split('\n') + + # 解析Python代码为AST + Tree = ast.parse(self.code) + + # 从源代码直接预扫描 import 语句,注册别名 + # 注意:不能依赖 Tree 中的 import 节点,因为 ParsePythonFile 可能修改了 AST + if not getattr(self.translator, '_ImportAliases', None): + self.translator._ImportAliases = {} + if not getattr(self.translator, '_ImportedModules', None): + self.translator._ImportedModules = set() + _prescan_tree = ast.parse(self.code) + for _node in ast.iter_child_nodes(_prescan_tree): + if isinstance(_node, ast.Import): + for _alias in _node.names: + _name = _alias.name + if _name in ('c', 't'): + continue + self.translator._ImportedModules.add(_name) + if _alias.asname: + self.translator._ImportAliases[_alias.asname] = _name + elif isinstance(_node, ast.ImportFrom): + _module_name = _node.module + if _module_name and _module_name not in ('c', 't'): + self.translator._ImportedModules.add(_module_name) + for _alias in _node.names: + if _alias.asname: + self.translator._ImportAliases[_alias.asname] = f"{_module_name}.{_alias.name}" + + # 解析代码以提取类型信息(用于 EmbeddedAssignments 和 TypedefAssignments) + # 创建临时文件路径用于解析 + import tempfile + import os + with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False, encoding='utf-8') as f: + f.write(self.code) + TempFile = f.name + try: + # UpdateCurrentFile=False 表示不修改 CurrentFile + if SourceFilename: + self.translator.ParsePythonFile(TempFile, UpdateCurrentFile=False) + else: + self.translator.ParsePythonFile(TempFile) + finally: + os.unlink(TempFile) + + import datetime + timestamp = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') + + if self.triple: + self.translator.triple = self.triple + if self.datalayout: + self.translator.datalayout = self.datalayout + + # 生成代码 + code = self.translator.GenerateCCode(Tree, target='llvm') + filename = os.path.basename(OutputFilename) if OutputFilename else 'generated.ll' + + # 处理调试信息 + if isinstance(self.config.debug, str): + # 如果debug是字符串,写入调试信息到文件 + with open(self.config.debug, 'w', encoding='utf-8') as f: + f.write('=== Symbol Table ===\n') + f.write(str(self.translator.SymbolTable) + '\n\n') + f.write('=== AST Tree ===\n') + f.write(ast.dump(Tree, indent=2) + '\n\n') + f.write('=== Export Table ===\n') + f.write(self.translator.Exportable.to_json() + '\n\n') + f.write('=== Generated Code ===\n') + f.write(code + '\n') + return code + elif self.config.debug: + # 如果debug是True,返回生成的代码和调试信息 + DebugInfo = { + 'SymbolTable': self.translator.SymbolTable, + 'ast_tree': ast.dump(Tree, indent=2), + 'Exportable': self.translator.Exportable.to_dict(), + 'generated_code': code + } + return code, DebugInfo + else: + # 如果debug是False,只返回生成的代码 + return code + + def Run(self): + """主运行函数""" + # 检查是否有命令行参数 + if len(sys.argv) > 1: + # 有命令行参数,使用 ParseArgs 方法解析 + self.ParseArgs() + + # 检查是否有预处理符号文件的请求 + if 'PreSym' in self.Args: + PresymConfig = self.Args['PreSym'] + InputFile = PresymConfig['input'] + OutputFile = PresymConfig['output'] + DebugFile = PresymConfig['debug'] + + # 获取编码参数 + encoding = self.Args.get('Encoding', 'utf-8') + + # 推断文件类型 + FileType = 'py' if InputFile.endswith('.py') else 'c' if InputFile.endswith('.c') else None + + # 创建 SymbolFile 对象,传入编码参数 + SymbolFile = SymbolFile(file=InputFile, type=FileType, encoding=encoding) + + # 调用 PreProcessSymbol + if DebugFile: + BinaryData, DebugInfo = TransPyC.PreProcessSymbol(SymbolFile, debug=True) + # 写入调试文件 + with open(DebugFile, 'w', encoding=encoding) as f: + f.write(DebugInfo) + print(f"Debug info written to: {DebugFile}") + else: + BinaryData = TransPyC.PreProcessSymbol(SymbolFile, debug=False) + + # 写入二进制符号文件 + with open(OutputFile, 'wb') as f: + f.write(BinaryData) + + print(f"Symbol file generated: {OutputFile}") + return + + InputFile = self.Args['Input'] + OutputFile = self.Args['Output'] + else: + # 没有命令行参数,使用默认的测试文件名称 + InputFile = DEFAULT_INPUT_FILE + OutputFile = DEFAULT_OUTPUT_FILE + print('Using default test files: test.py -> test.c') + + FileType = DetectFileType(InputFile) + + if FileType == '.py': + self.PythonToC(InputFile, OutputFile) + # 检查是否需要编译和运行 + if 'CompileCommand' in self.Args or self.Args.get('Run', False): + self.CompileAndRun(OutputFile) + elif FileType == '.c': + self.CToPython(InputFile, OutputFile, self.HeaderFiles) + else: + print(f'Error: Unsupported file type {FileType}') + sys.exit(1) diff --git a/lib/Shell/__init__.py b/lib/Shell/__init__.py new file mode 100644 index 0000000..ffec9e5 --- /dev/null +++ b/lib/Shell/__init__.py @@ -0,0 +1,6 @@ +"""Shell 包 - TransPyC 命令行入口""" +from lib.Shell.Serializer import SerializeSymbolTable, deSerializeSymbolTable, SymbolFile +from lib.Shell.Config import Config +from lib.Shell.TransPyC import TransPyC + +__all__ = ['SerializeSymbolTable', 'deSerializeSymbolTable', 'SymbolFile', 'Config', 'TransPyC'] diff --git a/lib/StubGen/Config.py b/lib/StubGen/Config.py new file mode 100644 index 0000000..fae30bc --- /dev/null +++ b/lib/StubGen/Config.py @@ -0,0 +1,42 @@ +"""StubGen 配置模块""" +import json +from dataclasses import dataclass, field +from typing import List, Dict, Optional + + +@dataclass +class StubGenConfig: + """存根生成器配置""" + InputDir: Optional[str] = None + OutputDir: str = "./stubs" + InputFiles: List[str] = field(default_factory=list) + IncludePatterns: List[str] = field(default_factory=lambda: ["*.h", "*.c", "*.py"]) + ExcludePatterns: List[str] = field(default_factory=list) + TypeMappings: Dict[str, str] = field(default_factory=dict) + PreserveStructure: bool = True # 保持目录结构 + GenerateGuards: bool = True # 生成宏守卫 + verbose: bool = False + DryRun: bool = False + + @classmethod + def from_dict(cls, data: Dict) -> 'StubGenConfig': + """从字典创建配置""" + return cls( + InputDir=data.get('InputDir'), + OutputDir=data.get('OutputDir', './stubs'), + InputFiles=data.get('InputFiles', []), + IncludePatterns=data.get('IncludePatterns', ['*.h', '*.c', '*.py']), + ExcludePatterns=data.get('ExcludePatterns', []), + TypeMappings=data.get('TypeMappings', {}), + PreserveStructure=data.get('PreserveStructure', True), + GenerateGuards=data.get('GenerateGuards', True), + verbose=data.get('verbose', False), + DryRun=data.get('DryRun', False), + ) + + @classmethod + def from_file(cls, FilePath: str) -> 'StubGenConfig': + """从 JSON 文件加载配置""" + with open(FilePath, 'r', encoding='utf-8') as f: + data = json.load(f) + return cls.from_dict(data) diff --git a/lib/StubGen/Converter.py b/lib/StubGen/Converter.py new file mode 100644 index 0000000..a808713 --- /dev/null +++ b/lib/StubGen/Converter.py @@ -0,0 +1,967 @@ +"""StubGen 转换器模块 - 将 Python 文件转换为存根格式""" +import ast +import re +from typing import List, Dict, Optional, Tuple + + +class PythonToStubConverter: + """将 Python 文件转换为存根格式""" + + # __include 别名映射表 {alias: ModuleName} + IncludeAliasMap: Dict[str, str] = {} + + # 变量排除列表 - 匹配这些模式的变量不会被添加到存根文件 + VarExcludeList: List[str] = [] + + # 宏排除列表 - 匹配这些模式的宏不会被添加到存根文件 + MacroExcludeList: List[str] = [] + + @classmethod + def SetIncludeAliasMap(cls, alias_map: Dict[str, str]): + """设置 __include 别名映射表""" + cls.IncludeAliasMap = alias_map + + @classmethod + def SetVarExcludeList(cls, exclude_list: List[str]): + """设置变量排除列表""" + cls.VarExcludeList = exclude_list + + @classmethod + def SetMacroExcludeList(cls, exclude_list: List[str]): + """设置宏排除列表""" + cls.MacroExcludeList = exclude_list + + @classmethod + def _ShouldExcludeVar(cls, VarName: str) -> bool: + """检查变量是否应该被排除""" + import fnmatch + for pattern in cls.VarExcludeList: + if fnmatch.fnmatch(VarName, pattern): + return True + return False + + @classmethod + def _ShouldExcludeMacro(cls, MacroName: str) -> bool: + """检查宏是否应该被排除""" + import fnmatch + for pattern in cls.MacroExcludeList: + if fnmatch.fnmatch(MacroName, pattern): + return True + return False + + @staticmethod + def convert(PyContent: str, ModuleName: str) -> str: + """将 Python 代码转换为存根格式""" + lines = PyContent.split('\n') + StubLines = [] + + # 添加文件头 + StubLines.append('"""') + StubLines.append(f'Auto-generated Python stub file from {ModuleName}.py') + StubLines.append(f'Module: {ModuleName}') + StubLines.append('"""') + StubLines.append('') + + # 解析 Python 代码,检查是否已经导入了 t 和 c + import ast + HasImportT = False + HasImportC = False + try: + tree = ast.parse(PyContent) + for node in tree.body: + if isinstance(node, ast.Import): + for alias in node.names: + if alias.name == 't': + HasImportT = True + elif alias.name == 'c': + HasImportC = True + except: + pass + + # 添加默认导入(如果源代码中没有) + if not HasImportT: + StubLines.append('import t') + if not HasImportC: + StubLines.append('import c') + if not HasImportT or not HasImportC: + StubLines.append('') + + # 添加 c.CPragma("once") + # StubLines.append('c.CPragma("once")') + StubLines.append('') + + # 生成文件级别宏守卫名称 + #FileGuardName = f'__{ModuleName.upper()}_DEFINE__' + + # 添加文件开头宏守卫 + #StubLines.append(f'c.CIfndef({FileGuardName})') + #StubLines.append(f'{FileGuardName}: t.CDefine') + #StubLines.append('') + + # 解析 Python 代码,提取类型定义 + try: + tree = ast.parse(PyContent) + + # 第一遍扫描:收集 Postdefinition 变量 + PostdefVars = {} # {ClassName: [(VarName, TypeStr, node), ...]} + for node in tree.body: + if isinstance(node, ast.AnnAssign) and isinstance(node.target, ast.Name): + TypeStr = PythonToStubConverter._GetTypeString(node.annotation) + # 检查是否是 Postdefinition 类型 + if 't.Postdefinition' in TypeStr: + # 提取引用的类名 + ClassName = PythonToStubConverter._ExtractPostdefClass(node.annotation) + if ClassName: + if ClassName not in PostdefVars: + PostdefVars[ClassName] = [] + PostdefVars[ClassName].append((node.target.id, TypeStr, node)) + + # 按原始顺序处理节点,保持代码的原始顺序 + PrevType = None # 记录前一个节点的类型 + + for node in tree.body: + CurrentType = None + + if isinstance(node, ast.ClassDef): + CurrentType = 'class' + # 如果前一个不是类,添加空行分隔 + if PrevType is not None and PrevType != 'class': + StubLines.append('') + # 检查是否有对应的 Postdefinition 变量 + ClassPostdefs = PostdefVars.get(node.name, []) + ClassLines = PythonToStubConverter._ConvertClass( + node, SourceLines=lines, PostdefVars=ClassPostdefs + ) + StubLines.extend(ClassLines) + elif isinstance(node, ast.FunctionDef): + CurrentType = 'function' + # 如果前一个是类或者是第一个函数,添加空行分隔 + if PrevType == 'class' or (PrevType is not None and PrevType != 'function'): + StubLines.append('') + FuncLines = PythonToStubConverter._ConvertFunction(node, SourceLines=lines) + StubLines.extend(FuncLines) + StubLines.append('') # 函数后空行 + elif isinstance(node, ast.AnnAssign): + CurrentType = 'variable' + # 跳过 Postdefinition 变量(已经在类中处理) + TypeStr = PythonToStubConverter._GetTypeString(node.annotation) + if 't.Postdefinition' in TypeStr: + continue + # 检查是否带有 t.CStatic 标志,如果有则不排除 + HasStatic = 't.CStatic' in TypeStr + # 检查变量是否应该被排除 + ShouldExclude = False + if isinstance(node.target, ast.Name) and not HasStatic: + VarName = node.target.id + if PythonToStubConverter._ShouldExcludeVar(VarName): + ShouldExclude = True + if ShouldExclude: + continue + # 如果前一个不是变量,添加空行分隔 + if PrevType is not None and PrevType != 'variable': + StubLines.append('') + VarLines = PythonToStubConverter._ConvertVariable(node, SourceLines=lines) + # 移除多余的空行 + VarLines = [line for line in VarLines if line.strip()] + StubLines.extend(VarLines) + elif isinstance(node, ast.Import): + # 处理导入语句 + CurrentType = 'import' + ImportStr = PythonToStubConverter._GetImportString(node, SourceLines=lines) + if ImportStr: + if PrevType is not None and PrevType != 'import': + StubLines.append('') + StubLines.append(ImportStr) + elif isinstance(node, ast.Assign): + CurrentType = 'variable' + # 处理模块级别的全局变量(无类型标注) + if PrevType is not None and PrevType != 'variable': + StubLines.append('') + AssignLines = PythonToStubConverter._ConvertGlobalAssign(node) + StubLines.extend(AssignLines) + elif isinstance(node, ast.ImportFrom): + # 处理 from ... import ... 语句 + CurrentType = 'import' + ImportStr = PythonToStubConverter._GetImportFromString(node, SourceLines=lines) + if ImportStr: + if PrevType is not None and PrevType != 'import': + StubLines.append('') + StubLines.append(ImportStr) + elif isinstance(node, ast.Expr): + # 处理模块级别的宏调用,如 c.CIf(...), c.CEndif() + ExprStr = PythonToStubConverter._GetExprString(node.value) + if ExprStr: + CurrentType = 'macro' + StubLines.append(ExprStr) + StubLines.append('') # 宏后空行 + elif isinstance(node, ast.If): + # 处理模块级别的 if 宏条件,如 if c.CIf(FF_MULTI_PARTITION): + IfStr = PythonToStubConverter._GetModuleIfMacroString(node) + if IfStr: + CurrentType = 'macro' + StubLines.append(IfStr) + StubLines.append('') # 宏后空行 + + if CurrentType: + PrevType = CurrentType + + # 添加文件结尾宏守卫 + #StubLines.append('') + #StubLines.append('c.CEndif()') + + except SyntaxError as e: + # 如果解析失败,添加注释说明 + StubLines.append(f'# Warning: Failed to parse Python code: {e}') + StubLines.append('# Original content:') + StubLines.append('"""') + StubLines.append(PyContent[:1000]) # 只显示前1000字符 + StubLines.append('"""') + + return '\n'.join(StubLines) + + @staticmethod + def _ConvertClass(node: ast.ClassDef, SourceLines: List[str] = None, PostdefVars: List[Tuple[str, str, ast.AnnAssign]] = None, indent: int = 0) -> List[str]: + """转换类定义 + + Args: + node: 类定义节点 + SourceLines: 源代码行列表 + PostdefVars: Postdefinition 变量列表 [(VarName, TypeStr, node), ...] + indent: 缩进级别(用于嵌套类) + """ + lines = [] + PostdefVars = PostdefVars or [] + IndentStr = ' ' * indent + + # 处理类装饰器 + for decorator in node.decorator_list: + DecoratorStr = PythonToStubConverter._GetDecoratorString(decorator) + if DecoratorStr: + lines.append(f'{IndentStr}@{DecoratorStr}') + + # 检查是否是结构体、联合体或枚举 + BaseNames = [base.attr if isinstance(base, ast.Attribute) else base.id + for base in node.bases + if isinstance(base, (ast.Name, ast.Attribute))] + + # 保留原始基类 + if node.bases: + BaseStrs = [] + for base in node.bases: + if isinstance(base, ast.Name): + BaseStrs.append(base.id) + elif isinstance(base, ast.Attribute): + BaseStrs.append(f'{base.value.id}.{base.attr}') + elif isinstance(base, ast.Subscript): + # 处理泛型类型,如 memory_block_t[MAX_ORDER + 1] + BaseStrs.append(PythonToStubConverter._GetTypeString(base)) + ClassTypeParamStr = '' + if hasattr(node, 'type_params') and node.type_params: + param_names = [tp.name for tp in node.type_params] + ClassTypeParamStr = f'[{", ".join(param_names)}]' + if BaseStrs: + lines.append(f'{IndentStr}class {node.name}{ClassTypeParamStr}({", ".join(BaseStrs)}):') + else: + lines.append(f'{IndentStr}class {node.name}{ClassTypeParamStr}:') + else: + ClassTypeParamStr = '' + if hasattr(node, 'type_params') and node.type_params: + param_names = [tp.name for tp in node.type_params] + ClassTypeParamStr = f'[{", ".join(param_names)}]' + lines.append(f'{IndentStr}class {node.name}{ClassTypeParamStr}:') + + # 处理类成员 + HasMembers = False + seen_member_names = set() + for item in node.body: + if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name): + seen_member_names.add(item.target.id) + init_members = [] + for item in node.body: + if isinstance(item, ast.FunctionDef) and item.name == '__init__': + for stmt in item.body: + if (isinstance(stmt, ast.AnnAssign) + and isinstance(stmt.target, ast.Attribute) + and isinstance(stmt.target.value, ast.Name) + and stmt.target.value.id == 'self'): + init_members.append(stmt) + untyped_self_members = [] + for m_name in [m.target.attr for m in init_members if isinstance(m.target, ast.Attribute)]: + seen_member_names.add(m_name) + for item in node.body: + if isinstance(item, ast.FunctionDef): + for stmt in item.body: + if (isinstance(stmt, ast.Assign) + and len(stmt.targets) == 1 + and isinstance(stmt.targets[0], ast.Attribute) + and isinstance(stmt.targets[0].value, ast.Name) + and stmt.targets[0].value.id == 'self'): + attr_name = stmt.targets[0].attr + if attr_name not in seen_member_names: + seen_member_names.add(attr_name) + untyped_self_members.append(stmt) + for item in list(node.body) + init_members + untyped_self_members: + if isinstance(item, ast.Assign): + if (len(item.targets) == 1 + and isinstance(item.targets[0], ast.Attribute) + and isinstance(item.targets[0].value, ast.Name) + and item.targets[0].value.id == 'self'): + HasMembers = True + MemberIndent = IndentStr + ' ' + attr_name = item.targets[0].attr + if attr_name in seen_member_names: + continue + InferredType = 'int' + if item.value and isinstance(item.value, ast.Constant): + if isinstance(item.value.value, float): + InferredType = 'float' + elif isinstance(item.value.value, bool): + InferredType = 'bool' + elif isinstance(item.value.value, str): + InferredType = 'str' + lines.append(f'{MemberIndent}{attr_name}: {InferredType}') + else: + HasMembers = True + MemberIndent = IndentStr + ' ' + if SourceLines and hasattr(item, 'lineno'): + StartLine = item.lineno - 1 + EndLine = item.EndLineno if hasattr(item, 'EndLineno') and item.EndLineno else StartLine + 1 + for i in range(StartLine, min(EndLine, len(SourceLines))): + lines.append(MemberIndent + SourceLines[i].lstrip()) + elif isinstance(item, ast.AnnAssign): + HasMembers = True + TypeStr = PythonToStubConverter._GetTypeString(item.annotation) + MemberIndent = IndentStr + ' ' + # 检查是否是宏变量(类型包含 t.CDefine) + if 't.CDefine' in TypeStr: + # 检查宏变量是否应该被排除 + if isinstance(item.target, ast.Name): + MacroName = item.target.id + if PythonToStubConverter._ShouldExcludeMacro(MacroName): + continue # 跳过该宏 + # 宏变量保持原样(包括赋值) + if SourceLines and hasattr(item, 'lineno'): + StartLine = item.lineno - 1 + EndLine = item.EndLineno if hasattr(item, 'EndLineno') and item.EndLineno else StartLine + 1 + for i in range(StartLine, min(EndLine, len(SourceLines))): + lines.append(MemberIndent + SourceLines[i].lstrip()) + else: + lines.append(f'{MemberIndent}{item.target.id}: {TypeStr}') + else: + if isinstance(item.target, ast.Attribute): + MemberName = item.target.attr + else: + MemberName = item.target.id + FinalTypeStr = TypeStr + if (isinstance(item.annotation, ast.Subscript) + and isinstance(item.annotation.value, ast.Name) + and item.annotation.value.id == 'list'): + slice_node = item.annotation.slice + has_size = False + if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2: + count_node = slice_node.elts[1] + if isinstance(count_node, ast.Constant) and isinstance(count_node.value, int) and count_node.value > 0: + has_size = True + else: + try: + count_expr = ast.unparse(count_node) + except Exception: + count_expr = '' + if count_expr and count_expr != 'None': + has_size = True + elem_type_str = PythonToStubConverter._GetTypeString(slice_node.elts[0]) + FinalTypeStr = f'list[{elem_type_str}, {count_expr}]' + if not has_size: + elem_type_str = PythonToStubConverter._GetTypeString(slice_node if not isinstance(slice_node, ast.Tuple) else slice_node.elts[0]) + init_len = 0 + if item.value is not None: + if isinstance(item.value, ast.List): + init_len = len(item.value.elts) + elif isinstance(item.value, ast.Constant) and isinstance(item.value.value, str): + init_len = len(item.value.value) + 1 + if init_len > 0: + FinalTypeStr = f'list[{elem_type_str}, {init_len}]' + else: + FinalTypeStr = f'list[{elem_type_str}, None]' + lines.append(f'{MemberIndent}{MemberName}: {FinalTypeStr}') + elif isinstance(item, ast.FunctionDef): + HasMembers = True + FuncStub = PythonToStubConverter._ConvertFunction(item, indent=indent+1, SourceLines=SourceLines, class_name=node.name) + lines.extend(FuncStub) + elif isinstance(item, ast.Expr): + # 处理宏调用,如 c.CIf(...), c.CEndif(), c.CElif(), c.CElse() + ExprStr = PythonToStubConverter._GetExprString(item.value) + if ExprStr: + lines.append(f'{IndentStr} {ExprStr}') + elif isinstance(item, ast.If): + # 处理 if c.CIf(...): 形式的宏条件 + IfStr = PythonToStubConverter._get_if_macro_string(item, indent=indent+1) + if IfStr: + lines.append(IfStr) + elif isinstance(item, ast.ClassDef): + # 处理嵌套类 + HasMembers = True + NestedClassLines = PythonToStubConverter._ConvertClass(item, SourceLines=SourceLines, PostdefVars=[], indent=indent+1) + # 移除嵌套类的宏守卫(因为已经在父类的宏守卫内) + FilteredLines = [] + for line in NestedClassLines: + # 跳过宏守卫相关行 + if line.strip().startswith('c.CIfndef(') or line.strip().startswith('c.CEndif()'): + continue + if ': t.CDefine' in line and '__' in line: + continue + FilteredLines.append(line) + lines.extend(FilteredLines) + + if not HasMembers: + lines.append(f'{IndentStr} pass') + + # 添加 Postdefinition 变量 + if PostdefVars: + lines.append('') + for VarName, TypeStr, _ in PostdefVars: + lines.append(f'{VarName}: {TypeStr}') + + return lines + + @staticmethod + def _ConvertFunction(node: ast.FunctionDef, indent: int = 0, SourceLines: List[str] = None, class_name: str = None) -> List[str]: + """转换函数定义""" + lines = [] + IndentStr = ' ' * indent + + # 检查是否是宏函数(返回类型包含 t.CDefine) + is_macro_func = False + if node.returns: + ReturnType = PythonToStubConverter._GetTypeString(node.returns) + if 't.CDefine' in ReturnType: + is_macro_func = True + + # 如果是宏函数,检查是否应该被排除 + if is_macro_func: + if PythonToStubConverter._ShouldExcludeMacro(node.name): + return lines # 返回空列表,排除该宏 + + # 保持原样(包括代码块) + if SourceLines: + StartLine = node.lineno - 1 + EndLine = node.EndLineno if hasattr(node, 'EndLineno') and node.EndLineno else StartLine + 1 + for i in range(StartLine, min(EndLine, len(SourceLines))): + lines.append(SourceLines[i]) + if lines and lines[-1].strip() and not lines[-1].rstrip().endswith(':'): + pass + else: + lines.append(f'{IndentStr} pass') + return lines + + # 处理函数装饰器 + for decorator in node.decorator_list: + DecoratorStr = PythonToStubConverter._GetDecoratorString(decorator) + if DecoratorStr: + lines.append(f'{IndentStr}@{DecoratorStr}') + + # 构建参数列表 + params = [] + for arg_idx, arg in enumerate(node.args.args): + ArgName = arg.arg + if arg.annotation: + TypeStr = PythonToStubConverter._GetTypeString(arg.annotation) + params.append(f'{ArgName}: {TypeStr}') + elif class_name and arg_idx == 0 and ArgName == 'self': + params.append(f'self: {class_name}') + else: + params.append(ArgName) + + # 处理 *args + if node.args.vararg: + ArgName = node.args.vararg.arg + if node.args.vararg.annotation: + TypeStr = PythonToStubConverter._GetTypeString(node.args.vararg.annotation) + params.append(f'*{ArgName}: {TypeStr}') + else: + params.append(f'*{ArgName}') + + # 处理 **kwargs + if node.args.kwarg: + ArgName = node.args.kwarg.arg + if node.args.kwarg.annotation: + TypeStr = PythonToStubConverter._GetTypeString(node.args.kwarg.annotation) + params.append(f'**{ArgName}: {TypeStr}') + else: + params.append(f'**{ArgName}') + + ParamStr = ', '.join(params) + + # 返回类型 - 保持原始类型(不添加t.State) + if node.returns: + ReturnType = PythonToStubConverter._GetTypeString(node.returns) + else: + ReturnType = 't.CInt' + + TypeParamStr = '' + if hasattr(node, 'type_params') and node.type_params: + param_names = [tp.name for tp in node.type_params] + TypeParamStr = f'[{", ".join(param_names)}]' + + lines.append(f'{IndentStr}def {node.name}{TypeParamStr}({ParamStr}) -> {ReturnType}: pass') + return lines + + @staticmethod + def _ConvertVariable(node: ast.AnnAssign, SourceLines: List[str] = None) -> List[str]: + """转换变量定义""" + lines = [] + if isinstance(node.target, ast.Name): + VarName = node.target.id + TypeStr = PythonToStubConverter._GetTypeString(node.annotation) + # 检查是否是宏变量(类型包含 t.CDefine) + if 't.CDefine' in TypeStr: + # 检查宏变量是否应该被排除 + if PythonToStubConverter._ShouldExcludeMacro(VarName): + return lines # 返回空列表,排除该宏 + # 宏变量保持原样(包括赋值) + if SourceLines and hasattr(node, 'lineno'): + StartLine = node.lineno - 1 + EndLine = node.EndLineno if hasattr(node, 'EndLineno') and node.EndLineno else StartLine + 1 + for i in range(StartLine, min(EndLine, len(SourceLines))): + lines.append(SourceLines[i]) + else: + lines.append(f'{VarName}: {TypeStr}') + return lines + # 非宏变量:不加 t.State + # 含有 typedef 的变量不加 extern,普通变量需要加 extern + has_typedef = 't.CTypedef' in TypeStr or 'CTypedef' in TypeStr + if has_typedef and node.value is not None: + ValueTypeStr = PythonToStubConverter._GetTypeString(node.value) + lines.append(f'{VarName}: {TypeStr} = {ValueTypeStr}') + else: + if not has_typedef and 't.CExtern' not in TypeStr and 't.CStatic' not in TypeStr: + TypeStr = f't.CExtern | {TypeStr}' + lines.append(f'{VarName}: {TypeStr}') + return lines + + @staticmethod + def _ConvertGlobalAssign(node: ast.Assign) -> List[str]: + """转换模块级别的全局变量(无类型标注)""" + lines = [] + if not node.targets or not isinstance(node.targets[0], ast.Name): + return lines + + VarName = node.targets[0].id + + # 跳过私有变量(以下划线开头) + if VarName.startswith('_'): + return lines + + # 从值推断类型 + inferred_type = PythonToStubConverter._InferTypeFromValue(node.value) + if inferred_type: + lines.append(f'{VarName}: {inferred_type}') + else: + lines.append(f'{VarName}: t.CInt') + + return lines + + @staticmethod + def _InferTypeFromValue(value: ast.AST) -> str: + """从值推断 C 类型""" + if isinstance(value, ast.Constant): + if isinstance(value.value, int): + return 't.CInt' + elif isinstance(value.value, float): + return 't.CDouble' + elif isinstance(value.value, str): + return 't.CCharPtr' + elif isinstance(value.value, bool): + return 't.CInt' + elif isinstance(value, ast.List): + return 't.CVoidPtr' + elif isinstance(value, ast.Dict): + return 't.CVoidPtr' + elif isinstance(value, ast.Name): + return 't.CInt' + elif isinstance(value, ast.BinOp): + left_type = PythonToStubConverter._InferTypeFromValue(value.left) + if left_type: + return left_type + return 't.CInt' + elif isinstance(value, ast.Call): + # 函数调用返回值,假设为指针类型 + if isinstance(value.func, ast.Name): + func_name = value.func.id + if func_name == 'malloc': + return 't.CVoidPtr' + elif func_name in ('ctypes.cast', 'cast'): + return 't.CVoidPtr' + return 't.CVoidPtr' + return None + + @staticmethod + def _GetTypeString(annotation: ast.AST) -> str: + """获取类型字符串""" + if isinstance(annotation, ast.Name): + return annotation.id + elif isinstance(annotation, ast.Attribute): + if isinstance(annotation.value, ast.Name): + return f'{annotation.value.id}.{annotation.attr}' + else: + # 处理嵌套属性访问,如 t.attr.packed + ParentStr = PythonToStubConverter._GetTypeString(annotation.value) + return f'{ParentStr}.{annotation.attr}' + elif isinstance(annotation, ast.Subscript): + base = PythonToStubConverter._GetTypeString(annotation.value) + if isinstance(annotation.slice, ast.Tuple): + slice_strs = [PythonToStubConverter._GetTypeString(e) for e in annotation.slice.elts] + SliceStr = ', '.join(slice_strs) + else: + SliceStr = PythonToStubConverter._GetTypeString(annotation.slice) + return f'{base}[{SliceStr}]' + elif isinstance(annotation, ast.BinOp): + # 处理 BinOp,如 t.CExtern | fd_table.__set_default__(...) + left = annotation.left + right = annotation.right + + # 检查右侧是否是 __set_default__ 调用 + if isinstance(right, ast.Call) and isinstance(right.func, ast.Attribute) and right.func.attr in ('__set_default__', '__set_default'): + # 去除 __set_default__,保留左侧,右侧替换为函数名部分 + LeftStr = PythonToStubConverter._GetTypeString(left) + RightStr = PythonToStubConverter._GetTypeString(right.func.value) + if isinstance(annotation.op, ast.BitOr): + return f'{LeftStr} | {RightStr}' + + LeftStr = PythonToStubConverter._GetTypeString(left) + RightStr = PythonToStubConverter._GetTypeString(right) + if isinstance(annotation.op, ast.BitOr): + return f'{LeftStr} | {RightStr}' + elif isinstance(annotation.op, ast.Add): + return f'{LeftStr} + {RightStr}' + elif isinstance(annotation.op, ast.Sub): + return f'{LeftStr} - {RightStr}' + elif isinstance(annotation.op, ast.Mult): + return f'{LeftStr} * {RightStr}' + elif isinstance(annotation.op, ast.Div): + return f'{LeftStr} / {RightStr}' + elif isinstance(annotation.op, ast.Mod): + return f'{LeftStr} % {RightStr}' + elif isinstance(annotation, ast.UnaryOp): + if isinstance(annotation.op, ast.Not): + operand = PythonToStubConverter._GetTypeString(annotation.operand) + return f'not {operand}' + elif isinstance(annotation.op, ast.Invert): + operand = PythonToStubConverter._GetTypeString(annotation.operand) + return f'~{operand}' + elif isinstance(annotation.op, ast.USub): + operand = PythonToStubConverter._GetTypeString(annotation.operand) + return f'-{operand}' + elif isinstance(annotation, ast.Compare): + # 处理比较操作,如 FF_MAX_SS != FF_MIN_SS + left = PythonToStubConverter._GetTypeString(annotation.left) + comparators = [PythonToStubConverter._GetTypeString(c) for c in annotation.comparators] + ops = [] + for op in annotation.ops: + if isinstance(op, ast.Eq): + ops.append('==') + elif isinstance(op, ast.NotEq): + ops.append('!=') + elif isinstance(op, ast.Lt): + ops.append('<') + elif isinstance(op, ast.LtE): + ops.append('<=') + elif isinstance(op, ast.Gt): + ops.append('>') + elif isinstance(op, ast.GtE): + ops.append('>=') + else: + ops.append('?') + result = left + for i, op in enumerate(ops): + result += f' {op} {comparators[i]}' + return result + elif isinstance(annotation, ast.Constant): + return repr(annotation.value) + elif isinstance(annotation, ast.Index): + return PythonToStubConverter._GetTypeString(annotation.value) + elif isinstance(annotation, ast.List): + # 处理列表,如 [MAX_FILE_DESCRIPTORS] + elements = [PythonToStubConverter._GetTypeString(elem) for elem in annotation.elts] + return f'[{", ".join(elements)}]' + elif isinstance(annotation, ast.Call): + # 处理函数调用形式的类型注解,如 t.Postdefinition(xxa) 或 callable(t.CVoid, app_id = t.CInt) + # 如果是 __set_default__ 调用,只返回函数名部分 + if isinstance(annotation.func, ast.Attribute) and annotation.func.attr in ('__set_default__', '__set_default'): + return PythonToStubConverter._GetTypeString(annotation.func.value) + + FuncStr = PythonToStubConverter._GetTypeString(annotation.func) + ArgsStr = ', '.join([PythonToStubConverter._GetTypeString(arg) for arg in annotation.args]) + # 处理关键字参数 + keywords_str = ', '.join([f'{kw.arg} = {PythonToStubConverter._GetTypeString(kw.value)}' for kw in annotation.keywords]) + # 合并位置参数和关键字参数 + if ArgsStr and keywords_str: + return f'{FuncStr}({ArgsStr}, {keywords_str})' + elif keywords_str: + return f'{FuncStr}({keywords_str})' + else: + return f'{FuncStr}({ArgsStr})' + return 't.CVoid' + + @staticmethod + def _ExtractPostdefClass(annotation: ast.AST) -> Optional[str]: + """从 Postdefinition 类型注解中提取类名 + + 例如:t.Postdefinition(__buddy_system) -> '__buddy_system' + t.Postdefinition(xxx) | t.CTypedef -> 'xxx' + """ + # 处理 BinOp (如: t.Postdefinition(xxx) | t.CTypedef) + if isinstance(annotation, ast.BinOp): + # 递归检查左操作数 + left_result = PythonToStubConverter._ExtractPostdefClass(annotation.left) + if left_result: + return left_result + # 递归检查右操作数 + right_result = PythonToStubConverter._ExtractPostdefClass(annotation.right) + if right_result: + return right_result + return None + + # 处理函数调用 (如: t.Postdefinition(__buddy_system)) + if isinstance(annotation, ast.Call): + FuncStr = PythonToStubConverter._GetTypeString(annotation.func) + if FuncStr == 't.Postdefinition' and annotation.args: + # 提取第一个参数 + first_arg = annotation.args[0] + if isinstance(first_arg, ast.Name): + return first_arg.id + elif isinstance(first_arg, ast.Attribute): + return f'{first_arg.value.id}.{first_arg.attr}' + + return None + + @staticmethod + def _GetImportString(node: ast.Import, SourceLines: List[str] = None) -> str: + """获取导入语句字符串""" + parts = [] + IncludeAliasMap = PythonToStubConverter.IncludeAliasMap + + for alias in node.names: + ModuleName = alias.name + # 检查是否是 __include.xxx 格式的导入 + if ModuleName.startswith('__include.'): + # 提取别名(xxx 部分) + SubModule = ModuleName[len('__include.'):] + if SubModule in IncludeAliasMap: + # 替换为实际模块路径 + RealModule = IncludeAliasMap[SubModule] + if alias.asname: + parts.append(f'{RealModule} as {alias.asname}') + else: + parts.append(f'{RealModule} as {SubModule}') + else: + # 不在映射表中,保持原样 + if alias.asname: + parts.append(f'{ModuleName} as {alias.asname}') + else: + parts.append(ModuleName) + else: + if alias.asname: + parts.append(f'{alias.name} as {alias.asname}') + else: + parts.append(alias.name) + + result = f'import {", ".join(parts)}' + + # 提取并保留注释 + if SourceLines and hasattr(node, 'lineno'): + LineIdx = node.lineno - 1 + if 0 <= LineIdx < len(SourceLines): + line = SourceLines[LineIdx] + CommentMatch = re.search(r'#.*$', line) + if CommentMatch: + result += ' ' + CommentMatch.group(0) + + return result + + @staticmethod + def _GetImportFromString(node: ast.ImportFrom, SourceLines: List[str] = None) -> str: + """获取 from ... import ... 语句字符串""" + module = node.module or '' + parts = [] + IncludeAliasMap = PythonToStubConverter.IncludeAliasMap + + # 处理相对导入 (from . import xxx 或 from ..package import xxx) + if node.level > 0: + if module: + if node.level == 1: + full_module = f'.{module}' + else: + full_module = '.' * node.level + module + else: + full_module = '.' * node.level + for alias in node.names: + if alias.asname: + parts.append(f'{alias.name} as {alias.asname}') + else: + parts.append(alias.name) + return f'from {full_module} import {", ".join(parts)}' + + # 提取注释(在生成结果前获取) + comment = '' + if SourceLines and hasattr(node, 'lineno'): + LineIdx = node.lineno - 1 + if 0 <= LineIdx < len(SourceLines): + line = SourceLines[LineIdx] + CommentMatch = re.search(r'#.*$', line) + if CommentMatch: + comment = ' ' + CommentMatch.group(0) + + # 检查是否是 from __include import xxx 格式 + if module == '__include': + for alias in node.names: + name = alias.name + if name in IncludeAliasMap: + # 替换为实际模块路径 + RealModule = IncludeAliasMap[name] + if alias.asname: + parts.append(f'import {RealModule} as {alias.asname}{comment}') + else: + parts.append(f'import {RealModule} as {name}{comment}') + else: + # 不在映射表中,保持原样 + if alias.asname: + parts.append(f'from {module} import {name} as {alias.asname}{comment}') + else: + parts.append(f'from {module} import {name}{comment}') + return '\n'.join(parts) + + # 普通 from ... import ... 语句 + for alias in node.names: + if alias.asname: + parts.append(f'{alias.name} as {alias.asname}') + else: + parts.append(alias.name) + return f'from {module} import {", ".join(parts)}{comment}' + + @staticmethod + def _GetDecoratorString(decorator: ast.AST) -> str: + """获取装饰器字符串""" + if isinstance(decorator, ast.Name): + return decorator.id + elif isinstance(decorator, ast.Attribute): + if isinstance(decorator.value, ast.Name): + return f'{decorator.value.id}.{decorator.attr}' + return decorator.attr + elif isinstance(decorator, ast.Call): + # 处理带参数的装饰器,如 @c.Attribute(t.attr.packed) + FuncStr = PythonToStubConverter._GetDecoratorString(decorator.func) + ArgsStr = ', '.join([PythonToStubConverter._GetTypeString(arg) for arg in decorator.args]) + return f'{FuncStr}({ArgsStr})' + return '' + + @staticmethod + def _GetExprString(expr: ast.AST) -> str: + """获取表达式字符串(用于宏调用)""" + if isinstance(expr, ast.Call): + # 处理函数调用,如 c.CIf(...), c.CEndif(), c.CUndef(...), c.CPragma(...) + FuncStr = PythonToStubConverter._GetDecoratorString(expr.func) + if FuncStr and ('CIf' in FuncStr or 'CEndif' in FuncStr or 'CElif' in FuncStr or 'CElse' in FuncStr or 'CUndef' in FuncStr or 'CPragma' in FuncStr): + ArgsStr = ', '.join([PythonToStubConverter._GetTypeString(arg) for arg in expr.args]) + return f'{FuncStr}({ArgsStr})' if ArgsStr else f'{FuncStr}()' + return '' + + @staticmethod + def _get_if_macro_string(node: ast.If, indent: int = 1) -> str: + """获取类内部的 if 宏字符串(如 if c.CIf(...):)""" + IndentStr = ' ' * indent + InnerIndent = ' ' * (indent + 1) + # 检查条件是否是宏调用 + if isinstance(node.test, ast.Call): + FuncStr = PythonToStubConverter._GetDecoratorString(node.test.func) + if FuncStr and 'CIf' in FuncStr: + ArgsStr = ', '.join([PythonToStubConverter._GetTypeString(arg) for arg in node.test.args]) + result = [f'{IndentStr}if {FuncStr}({ArgsStr}):' if ArgsStr else f'{IndentStr}if {FuncStr}():'] + # 处理 if 体内的语句 + for item in node.body: + if isinstance(item, ast.AnnAssign): + TypeStr = PythonToStubConverter._GetTypeString(item.annotation) + result.append(f'{InnerIndent}{item.target.id}: {TypeStr}') + elif isinstance(item, ast.Expr): + ExprStr = PythonToStubConverter._GetExprString(item.value) + if ExprStr: + result.append(f'{InnerIndent}{ExprStr}') + return '\n'.join(result) + return '' + + @staticmethod + def _GetModuleIfMacroString(node: ast.If) -> str: + """获取模块级别的 if 宏字符串(如 if c.CIf(FF_MULTI_PARTITION):)""" + return PythonToStubConverter._ProcessIfMacro(node, indent=0) + + @staticmethod + def _ProcessIfMacro(node: ast.If, indent: int = 0) -> str: + """处理 if 宏节点,支持 elif 和 else""" + IndentStr = ' ' * indent + + # 检查条件是否是宏调用 + if isinstance(node.test, ast.Call): + FuncStr = PythonToStubConverter._GetDecoratorString(node.test.func) + if FuncStr and 'CIf' in FuncStr: + ArgsStr = ', '.join([PythonToStubConverter._GetTypeString(arg) for arg in node.test.args]) + result = [f'{IndentStr}if {FuncStr}({ArgsStr}):' if ArgsStr else f'{IndentStr}if {FuncStr}():'] + # 处理 if 体内的语句 + for item in node.body: + result.extend(PythonToStubConverter._ProcessMacroBodyItem(item, indent + 1)) + + # 处理 elif 和 else + current = node + while current.orelse: + if len(current.orelse) == 1 and isinstance(current.orelse[0], ast.If): + # elif 情况 + elif_node = current.orelse[0] + if isinstance(elif_node.test, ast.Call): + ElifFuncStr = PythonToStubConverter._GetDecoratorString(elif_node.test.func) + if ElifFuncStr and 'CIf' in ElifFuncStr: + ElifArgsStr = ', '.join([PythonToStubConverter._GetTypeString(arg) for arg in elif_node.test.args]) + result.append(f'{IndentStr}elif {ElifFuncStr}({ElifArgsStr}):' if ElifArgsStr else f'{IndentStr}elif {ElifFuncStr}():') + for item in elif_node.body: + result.extend(PythonToStubConverter._ProcessMacroBodyItem(item, indent + 1)) + current = elif_node + continue + break + else: + # else 情况 + result.append(f'{IndentStr}else:') + for item in current.orelse: + result.extend(PythonToStubConverter._ProcessMacroBodyItem(item, indent + 1)) + break + + return '\n'.join(result) + return '' + + @staticmethod + def _ProcessMacroBodyItem(item: ast.AST, indent: int = 0) -> list: + """处理宏体内的单个语句""" + IndentStr = ' ' * indent + result = [] + + if isinstance(item, ast.ClassDef): + class_stub = PythonToStubConverter._ConvertClass(item) + for line in class_stub: + if line.strip(): + result.append(f'{IndentStr}{line}') + else: + result.append(line) + elif isinstance(item, ast.FunctionDef): + FuncStub = PythonToStubConverter._ConvertFunction(item, indent=indent) + result.extend(FuncStub) + elif isinstance(item, ast.AnnAssign): + TypeStr = PythonToStubConverter._GetTypeString(item.annotation) + result.append(f'{IndentStr}{item.target.id}: {TypeStr}') + elif isinstance(item, ast.Expr): + ExprStr = PythonToStubConverter._GetExprString(item.value) + if ExprStr: + result.append(f'{IndentStr}{ExprStr}') + elif isinstance(item, ast.If): + # 处理嵌套的 if 宏 + NestedIf = PythonToStubConverter._ProcessIfMacro(item, indent=indent) + if NestedIf: + result.append(NestedIf) + + return result diff --git a/lib/StubGen/Generator.py b/lib/StubGen/Generator.py new file mode 100644 index 0000000..111b87d --- /dev/null +++ b/lib/StubGen/Generator.py @@ -0,0 +1,311 @@ +"""StubGen 生成器模块 - 存根生成器主类和命令行入口""" +import sys +import os +import re +import argparse +import logging +from pathlib import Path +from typing import List, Tuple + +from lib.core.stub_generator import CHeaderParser, PythonStubGenerator, CTypeMapper +from lib.StubGen.Config import StubGenConfig +from lib.StubGen.Converter import PythonToStubConverter + + +class StubGen: + """存根生成器主类""" + + def __init__(self, config: StubGenConfig): + self.config = config + self.logger = self._SetupLogger() + self.GeneratedFiles: List[str] = [] + self.FailedFiles: List[str] = [] + + # 应用自定义类型映射 + if config.TypeMappings: + CTypeMapper.BASIC_TYPE_MAP.update(config.TypeMappings) + + def _SetupLogger(self) -> logging.Logger: + """设置日志""" + logger = logging.getLogger('StubGen') + logger.setLevel(logging.DEBUG if self.config.verbose else logging.INFO) + + if not logger.handlers: + handler = logging.StreamHandler(sys.stdout) + formatter = logging.Formatter( + '%(asctime)s - %(name)s - %(levelname)s - %(message)s', + datefmt='%H:%M:%S' + ) + handler.setFormatter(formatter) + logger.addHandler(handler) + + return logger + + def FindInputFiles(self) -> List[Tuple[str, str]]: + """查找输入文件,返回 (文件路径, 相对路径) 列表""" + files = [] + + # 添加显式指定的文件 + for FilePath in self.config.InputFiles: + if os.path.exists(FilePath): + RelPath = os.path.relpath(FilePath, self.config.InputDir or '.') + files.append((FilePath, RelPath)) + else: + self.logger.warning(f"Input file not found: {FilePath}") + + # 从输入目录查找 + if self.config.InputDir and os.path.exists(self.config.InputDir): + InputPath = Path(self.config.InputDir) + for pattern in self.config.IncludePatterns: + for FilePath in InputPath.rglob(pattern): + # 检查是否在排除列表中 + excluded = False + RelPath = os.path.relpath(str(FilePath), self.config.InputDir) + + for exclude_pattern in self.config.ExcludePatterns: + if FilePath.match(exclude_pattern) or RelPath == exclude_pattern: + excluded = True + break + + if not excluded: + files.append((str(FilePath), RelPath)) + + # 去重并保持顺序 + seen = set() + UniqueFiles = [] + for FilePath, RelPath in files: + key = FilePath + if key not in seen: + seen.add(key) + UniqueFiles.append((FilePath, RelPath)) + + return UniqueFiles + + def _GenerateGuardName(self, FilePath: str) -> str: + """生成宏守卫名称""" + # 获取文件名(不含扩展名) + BaseName = os.path.splitext(os.path.basename(FilePath))[0] + + # 转换为大写,替换特殊字符为下划线 + guard = re.sub(r'[^a-zA-Z0-9_]', '_', BaseName).upper() + guard = re.sub(r'_+', '_', guard) # 合并多个下划线 + guard = guard.strip('_') + + return f'{guard}_DEFINE_H' + + def _GetOutputPath(self, RelPath: str) -> str: + """获取输出文件路径""" + # 更改扩展名为 .pyi (Python stub file) + BaseName = os.path.splitext(RelPath)[0] + OutputRelPath = BaseName + '.pyi' + + # 构建完整输出路径 + if self.config.OutputDir: + OutputPath = os.path.join(self.config.OutputDir, OutputRelPath) + else: + OutputPath = OutputRelPath + + return OutputPath + + def GenerateStub(self, InputFile: str, RelPath: str) -> bool: + """生成单个存根文件""" + try: + self.logger.info(f"Processing: {InputFile}") + + # 确定输出文件路径 + OutputFile = self._GetOutputPath(RelPath) + + # 确保输出目录存在 + OutputDir = os.path.dirname(OutputFile) + if OutputDir and not os.path.exists(OutputDir): + if not self.config.DryRun: + os.makedirs(OutputDir, exist_ok=True) + self.logger.debug(f"Created directory: {OutputDir}") + + if self.config.DryRun: + self.logger.info(f"[DRY RUN] Would generate: {OutputFile}") + return True + + # 根据文件类型选择处理方式 + ext = os.path.splitext(InputFile)[1].lower() + + if ext in ['.h', '.c']: + # C 文件:使用 CHeaderParser + content = self._GenerateFromC(InputFile, RelPath) + elif ext == '.py': + # Python 文件:使用 PythonToStubConverter + content = self._GenerateFromPy(InputFile, RelPath) + else: + self.logger.warning(f"Unsupported file type: {ext}") + return False + + # 写入文件 + with open(OutputFile, 'w', encoding='utf-8') as f: + f.write(content) + + self.GeneratedFiles.append(OutputFile) + self.logger.info(f"Generated: {OutputFile}") + return True + + except Exception as e: + self.logger.error(f"Failed to process {InputFile}: {e}") + import traceback + traceback.print_exc() + self.FailedFiles.append(InputFile) + return False + + def _GenerateFromC(self, InputFile: str, RelPath: str) -> str: + """从 C 文件生成存根""" + parser = CHeaderParser() + parser.parse_file(InputFile) + + generator = PythonStubGenerator(parser) + ModuleName = os.path.splitext(os.path.basename(InputFile))[0] + content = generator.generate(ModuleName) + + # 添加宏守卫(如果需要) + if self.config.GenerateGuards: + guard_name = self._GenerateGuardName(InputFile) + guard_comment = f"\n# Guard: {guard_name}\n" + content = content + guard_comment + + return content + + def _GenerateFromPy(self, InputFile: str, RelPath: str) -> str: + """从 Python 文件生成存根""" + with open(InputFile, 'r', encoding='utf-8') as f: + PyContent = f.read() + + ModuleName = os.path.splitext(os.path.basename(InputFile))[0] + content = PythonToStubConverter.convert(PyContent, ModuleName) + + # 添加宏守卫(如果需要) + if self.config.GenerateGuards: + guard_name = self._GenerateGuardName(InputFile) + guard_comment = f"\n# Guard: {guard_name}\n" + content = content + guard_comment + + return content + + def run(self) -> bool: + """运行生成器""" + self.logger.info("=" * 60) + self.logger.info("StubGen - C/H/Py to Python Stub Generator") + self.logger.info("=" * 60) + + # 查找输入文件 + InputFiles = self.FindInputFiles() + + if not InputFiles: + self.logger.warning("No input files found!") + return False + + self.logger.info(f"Found {len(InputFiles)} input file(s)") + for FilePath, RelPath in InputFiles: + self.logger.debug(f" - {RelPath}") + + # 处理每个文件 + SuccessCount = 0 + for FilePath, RelPath in InputFiles: + if self.GenerateStub(FilePath, RelPath): + SuccessCount += 1 + + # 输出统计信息 + self.logger.info("=" * 60) + self.logger.info(f"Summary: {SuccessCount}/{len(InputFiles)} files generated successfully") + + if self.FailedFiles: + self.logger.warning(f"Failed files ({len(self.FailedFiles)}):") + for f in self.FailedFiles: + self.logger.warning(f" - {f}") + + return SuccessCount == len(InputFiles) + + +def main(): + parser = argparse.ArgumentParser( + description='StubGen - Generate Python stub files from C/H/Py sources', + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=''' +Examples: + # 使用配置文件 + %(prog)s -c config.json + + # 处理单个文件 + %(prog)s -i input.h -o output.py + + # 批量处理目录(保持目录结构) + %(prog)s -d ./kernel -o ./kernel/include + + # 干运行(不实际生成文件) + %(prog)s -d ./kernel --dry-run + + # 不生成宏守卫 + %(prog)s -d ./kernel --no-guards + ''' + ) + + # 输入选项 + InputGroup = parser.add_mutually_exclusive_group(required=True) + InputGroup.add_argument('-c', '--config', help='Configuration file (JSON)') + InputGroup.add_argument('-i', '--input', help='Input file') + InputGroup.add_argument('-d', '--directory', help='Input directory') + + # 输出选项 + parser.add_argument('-o', '--output', help='Output directory') + + # 其他选项 + parser.add_argument('--include', action='append', + help='Include patterns (default: *.h, *.c, *.py)') + parser.add_argument('--exclude', action='append', + help='Exclude patterns') + parser.add_argument('--no-guards', action='store_true', + help='Do not generate guard macros') + parser.add_argument('--no-structure', action='store_true', + help='Do not preserve directory structure') + parser.add_argument('-v', '--verbose', action='store_true', + help='Verbose output') + parser.add_argument('--dry-run', action='store_true', + help='Dry run (do not create files)') + + args = parser.parse_args() + + # 加载配置 + if args.config: + if not os.path.exists(args.config): + print(f"Error: Config file not found: {args.config}") + sys.exit(1) + config = StubGenConfig.from_file(args.config) + else: + config = StubGenConfig() + config.IncludePatterns = args.include or ['*.h', '*.c', '*.py'] + config.ExcludePatterns = args.exclude or [] + config.GenerateGuards = not args.no_guards + config.PreserveStructure = not args.no_structure + config.verbose = args.verbose + config.DryRun = args.dry_run + + if args.input: + config.InputFiles = [args.input] + if args.output: + config.OutputDir = os.path.dirname(args.output) or '.' + elif args.directory: + config.InputDir = args.directory + if args.output: + config.OutputDir = args.output + + # 创建生成器并运行 + generator = StubGen(config) + + # 如果指定了单个输出文件,直接处理 + if args.input and args.output and not os.path.isdir(args.output): + RelPath = os.path.relpath(args.input, config.InputDir or '.') + success = generator.GenerateStub(args.input, RelPath) + else: + success = generator.run() + + sys.exit(0 if success else 1) + + +if __name__ == '__main__': + main() diff --git a/lib/StubGen/__init__.py b/lib/StubGen/__init__.py new file mode 100644 index 0000000..00a45bd --- /dev/null +++ b/lib/StubGen/__init__.py @@ -0,0 +1,6 @@ +"""StubGen 包 - 存根文件生成器""" +from lib.StubGen.Config import StubGenConfig +from lib.StubGen.Converter import PythonToStubConverter +from lib.StubGen.Generator import StubGen, main + +__all__ = ['StubGenConfig', 'PythonToStubConverter', 'StubGen', 'main'] diff --git a/lib/core/AsmIntelToAtt.py b/lib/core/AsmIntelToAtt.py deleted file mode 100644 index 7a15058..0000000 --- a/lib/core/AsmIntelToAtt.py +++ /dev/null @@ -1,534 +0,0 @@ -from __future__ import annotations -import re - - -_X86_REGS = { - 'al', 'ah', 'ax', 'eax', 'rax', - 'bl', 'bh', 'bx', 'ebx', 'rbx', - 'cl', 'ch', 'cx', 'ecx', 'rcx', - 'dl', 'dh', 'dx', 'edx', 'rdx', - 'sil', 'si', 'esi', 'rsi', - 'dil', 'di', 'edi', 'rdi', - 'bpl', 'bp', 'ebp', 'rbp', - 'spl', 'sp', 'esp', 'rsp', - 'rip', 'eip', 'ip', - 'r8', 'r9', 'r10', 'r11', 'r12', 'r13', 'r14', 'r15', - 'r8b', 'r9b', 'r10b', 'r11b', 'r12b', 'r13b', 'r14b', 'r15b', - 'r8w', 'r9w', 'r10w', 'r11w', 'r12w', 'r13w', 'r14w', 'r15w', - 'r8d', 'r9d', 'r10d', 'r11d', 'r12d', 'r13d', 'r14d', 'r15d', -} - -_CR_REGS = {'cr0', 'cr2', 'cr3', 'cr4', 'cr8'} -_SEG_REGS = {'ds', 'es', 'fs', 'gs', 'ss', 'cs'} - -_SIZE_MAP = { - 'al': 'b', 'ah': 'b', 'ax': 'w', 'eax': 'l', 'rax': 'q', - 'bl': 'b', 'bh': 'b', 'bx': 'w', 'ebx': 'l', 'rbx': 'q', - 'cl': 'b', 'ch': 'b', 'cx': 'w', 'ecx': 'l', 'rcx': 'q', - 'dl': 'b', 'dh': 'b', 'dx': 'w', 'edx': 'l', 'rdx': 'q', - 'si': 'w', 'esi': 'l', 'rsi': 'q', - 'di': 'w', 'edi': 'l', 'rdi': 'q', - 'bp': 'w', 'ebp': 'l', 'rbp': 'q', - 'sp': 'w', 'esp': 'l', 'rsp': 'q', - 'ip': 'w', 'eip': 'l', 'rip': 'q', - 'r8b': 'b', 'r8w': 'w', 'r8d': 'l', 'r8': 'q', - 'r9b': 'b', 'r9w': 'w', 'r9d': 'l', 'r9': 'q', - 'r10b': 'b', 'r10w': 'w', 'r10d': 'l', 'r10': 'q', - 'r11b': 'b', 'r11w': 'w', 'r11d': 'l', 'r11': 'q', - 'r12b': 'b', 'r12w': 'w', 'r12d': 'l', 'r12': 'q', - 'r13b': 'b', 'r13w': 'w', 'r13d': 'l', 'r13': 'q', - 'r14b': 'b', 'r14w': 'w', 'r14d': 'l', 'r14': 'q', - 'r15b': 'b', 'r15w': 'w', 'r15d': 'l', 'r15': 'q', -} - -_SIZE_PREFIX = { - 'byte': 'b', - 'word': 'w', - 'dword': 'l', - 'qword': 'q', -} - -_TWO_OPS_SWAP = frozenset({ - 'mov', 'lea', 'add', 'sub', 'adc', 'sbb', - 'and', 'or', 'xor', 'cmp', 'test', - 'shl', 'shr', 'sal', 'sar', 'rol', 'ror', 'rcl', 'rcr', - 'bt', 'btc', 'btr', 'bts', - 'xadd', 'xchg', 'cmpxchg', -}) - -_NO_SUFFIX_OPS = frozenset({ - 'call', 'jmp', 'ret', 'push', 'pop', - 'cli', 'sti', 'hlt', 'nop', 'cld', 'std', 'cpuid', 'rdmsr', 'wrmsr', - 'sfence', 'mfence', 'lfence', 'fninit', 'pause', 'ud2', - 'invlpg', 'swapgs', 'syscall', 'sysret', 'iretq', 'int', - 'fxsave', 'fxrstor', 'stmxcsr', 'ldmxcsr', - 'bswap', 'cbw', 'cwde', 'cdqe', 'cwd', 'cdq', 'cqo', - 'sete', 'setne', 'seta', 'setae', 'setb', 'setbe', - 'setg', 'setge', 'setl', 'setle', 'sets', 'setns', 'setc', 'setnc', - 'seto', 'setno', 'setp', 'setnp', - 'cmovo', 'cmovno', 'cmovb', 'cmovae', 'cmove', 'cmovne', - 'cmova', 'cmovbe', 'cmovg', 'cmovge', 'cmovl', 'cmovle', - 'cmovs', 'cmovns', 'cmovc', 'cmovnc', 'cmovp', 'cmovnp', -}) - -_BRANCH_OPS = frozenset({ - 'jz', 'jnz', 'je', 'jne', 'jg', 'jl', 'jge', 'jle', - 'ja', 'jb', 'jae', 'jbe', 'jo', 'jno', 'js', 'jns', - 'jc', 'jnc', 'jp', 'jnp', 'loop', 'jcxz', 'jecxz', 'jrcxz', -}) - -_STRING_OPS = frozenset({ - 'lodsb', 'lodsw', 'lodsd', 'lodsq', - 'stosb', 'stosw', 'stosd', 'stosq', - 'movsb', 'movsw', 'movsd', 'movsq', - 'cmpsb', 'cmpsw', 'cmpsd', 'cmpsq', - 'scasb', 'scasw', 'scasd', 'scasq', - 'insb', 'insw', 'insd', 'outsb', 'outsw', 'outsd', -}) - -_STRING_OPS_ATT_MAP = { - 'lodsd': 'lodsl', 'stosd': 'stosl', 'movsd': 'movsl', - 'cmpsd': 'cmpsl', 'scasd': 'scasl', 'insd': 'insl', - 'outsd': 'outsl', -} - -_PREFIX_OPS = frozenset({ - 'rep', 'repe', 'repz', 'repne', 'repnz', 'lock', -}) - - -def _is_operand_ref(token: str) -> bool: - return bool(re.match(r'^\$\d+$', token)) - - -def _parse_operands(operands_str: str): - result = [] - current = '' - depth = 0 - i = 0 - while i < len(operands_str): - ch = operands_str[i] - if ch == '[' or ch == '(': - depth += 1 - current += ch - elif ch == ']' or ch == ')': - depth -= 1 - current += ch - elif ch == ',' and depth == 0: - result.append(current.strip()) - current = '' - else: - current += ch - i += 1 - if current.strip(): - result.append(current.strip()) - return result - - -def _tokenize_mem(mem: str) -> list: - result = [] - current = '' - i = 0 - while i < len(mem): - ch = mem[i] - if ch == '(': - if current.strip(): - result.append(current.strip()) - current = '' - result.append('(') - i += 1 - elif ch == ')': - if current.strip(): - result.append(current.strip()) - current = '' - result.append(')') - i += 1 - elif ch in '+-': - if current.strip(): - result.append(current.strip()) - current = '' - result.append(ch) - i += 1 - elif ch in ' \t': - if current.strip(): - result.append(current.strip()) - current = '' - i += 1 - else: - current += ch - i += 1 - if current.strip(): - result.append(current.strip()) - return result - - -def _convert_mem_token(token: str) -> str: - if token in ('(', ')', '+', '-'): - return token - if _is_operand_ref(token): - return token - if token.lower() in _X86_REGS: - return '%' + token - try: - int(token, 0) - return token - except ValueError: - pass - return token - - -def _convert_mem_operand(op: str) -> str: - op = op.strip().replace('[', '(').replace(']', ')') - - m = re.match(r'^\(([^)]+)\)$', op) - if m: - inner = m.group(1).strip() - return _convert_mem_inner(inner) - - return _convert_mem_inner(op.strip('()')) - - -def _convert_mem_inner(inner: str) -> str: - tokens = [] - current = '' - i = 0 - while i < len(inner): - ch = inner[i] - if ch in ' \t': - if current.strip(): - tokens.append(current.strip()) - current = '' - i += 1 - elif ch in '+-': - if current.strip(): - tokens.append(current.strip()) - current = '' - tokens.append(ch) - i += 1 - else: - current += ch - i += 1 - if current.strip(): - tokens.append(current.strip()) - - base = '' - index = '' - scale = '' - disp = '' - op = '+' - - for tok in tokens: - if tok == '+': - op = '+' - continue - elif tok == '-': - op = '-' - continue - - is_reg = tok.lower() in _X86_REGS or tok.lower() in _CR_REGS - is_operand = _is_operand_ref(tok) - - if is_reg or is_operand: - if not base: - base = _convert_mem_token(tok) - elif not index: - index = _convert_mem_token(tok) - else: - disp += ('+' if op == '+' else '-') + tok - else: - try: - int(tok, 0) - if op == '-': - disp += '-' + tok - else: - disp += tok - except ValueError: - if op == '-': - disp += '-' + tok - else: - if not base: - base = tok - else: - disp += tok - - result = '' - if disp: - result = disp - result += '(' - if base: - result += base - if index: - result += ',' + index - if scale: - result += ',' + scale - result += ')' - return result - - -def _att_convert_operand(op: str) -> str: - op = op.strip() - if not op: - return op - - m = re.match(r'^(byte|word|dword|qword)\s+ptr\s+(.+)$', op, re.IGNORECASE) - if m: - op = m.group(2).strip() - - if '[' in op or ']' in op: - return _convert_mem_operand(op) - - if _is_operand_ref(op): - return op - - if op.lower() in _CR_REGS: - return '%' + op - if op.lower() in _SEG_REGS: - return '%' + op - if op.lower() in _X86_REGS: - return '%' + op - - try: - int(op, 0) - return '$$' + op - except ValueError: - pass - - if op.startswith('~'): - inner = op[1:] - try: - int(inner, 0) - return '$$' + op - except ValueError: - pass - - return op - - -def _extract_size(op: str) -> str: - m = re.match(r'^(byte|word|dword|qword)\s+ptr\s+', op, re.IGNORECASE) - if m: - return _SIZE_PREFIX.get(m.group(1).lower(), '') - - cleaned = op.lower().replace('[', '(').replace(']', ')').replace('$', '') - for reg in _CR_REGS: - if re.search(r'(? str: - for o in operands: - s = _extract_size(o) - if s: - return s - if op in ('imul',): - return 'l' - if op in ('shl', 'shr', 'sal', 'sar', 'rol', 'ror', 'rcl', 'rcr'): - return 'q' - return 'q' - - -def _convert_instruction(op: str, operands: list) -> str: - op_lower = op.lower() - - if op_lower in _PREFIX_OPS and len(operands) == 0: - return op_lower - - if op_lower in _PREFIX_OPS and len(operands) >= 1: - att_ops = [] - for o in operands: - o_lower = o.strip().lower() - if o_lower in _STRING_OPS_ATT_MAP: - att_ops.append(_STRING_OPS_ATT_MAP[o_lower]) - elif o_lower in _NO_SUFFIX_OPS or o_lower in _STRING_OPS: - att_ops.append(o) - else: - att_ops.append(_att_convert_operand(o)) - return f"{op_lower} {' '.join(att_ops)}" - - if op_lower in ('push', 'pop') and len(operands) >= 1: - p = _att_convert_operand(operands[0]) - return f"{op_lower} {p}" - - if op_lower == 'in' and len(operands) >= 2: - dst, port = operands[0], operands[1] - suffix = _size_suffix_for_all([dst], op_lower) or 'b' - return f"in{suffix} {_att_convert_operand(port)}, {_att_convert_operand(dst)}" - - if op_lower == 'out' and len(operands) >= 2: - port, src = operands[0], operands[1] - suffix = _size_suffix_for_all([src], op_lower) or 'b' - return f"out{suffix} {_att_convert_operand(src)}, {_att_convert_operand(port)}" - - if op_lower in ('lidt', 'lgdt', 'sidt', 'sgdt') and len(operands) >= 1: - return f"{op_lower}q {_att_convert_operand(operands[0])}" - - if op_lower == 'call' and len(operands) >= 1: - target = operands[0].strip() - att_target = _att_convert_operand(target) - if _is_operand_ref(target): - return f"call *{att_target}" - if target.startswith('[') or target.startswith('('): - return f"call *{att_target}" - if target.lower() in _X86_REGS or target.lower() in _CR_REGS: - return f"call *{att_target}" - return f"call {att_target}" - - if op_lower == 'jmp' and len(operands) >= 1: - target = operands[0].strip() - att_target = _att_convert_operand(target) - if _is_operand_ref(target): - return f"jmp *{att_target}" - if target.startswith('[') or target.startswith('('): - return f"jmp *{att_target}" - if target.lower() in _X86_REGS or target.lower() in _CR_REGS: - return f"jmp *{att_target}" - return f"jmp {att_target}" - - if op_lower in _BRANCH_OPS and len(operands) >= 1: - target = operands[0].strip() - att_target = _att_convert_operand(target) - return f"{op_lower} {att_target}" - - if op_lower == 'imul' and len(operands) >= 3: - src1, src2, imm = operands[0], operands[1], operands[2] - suffix = _size_suffix_for_all([src1, src2], op_lower) - return f"imul{suffix} {_att_convert_operand(imm)}, {_att_convert_operand(src1)}, {_att_convert_operand(src2)}" - - if op_lower == 'movzx' and len(operands) >= 2: - dst, src = operands[0], operands[1] - src_size = _extract_size(src) or 'b' - dst_size = _extract_size(dst) or 'l' - return f"movz{src_size}{dst_size} {_att_convert_operand(src)}, {_att_convert_operand(dst)}" - - if op_lower == 'movsxd' and len(operands) >= 2: - dst, src = operands[0], operands[1] - src_size = _extract_size(src) or 'l' - dst_size = _extract_size(dst) or 'q' - return f"movs{src_size}{dst_size} {_att_convert_operand(src)}, {_att_convert_operand(dst)}" - - if op_lower in _TWO_OPS_SWAP and len(operands) >= 2: - src, dst = operands[0], operands[1] - suffix = _size_suffix_for_all([src, dst], op_lower) - return f"{op_lower}{suffix} {_att_convert_operand(dst)}, {_att_convert_operand(src)}" - - if op_lower in _NO_SUFFIX_OPS or op_lower in _STRING_OPS or len(operands) == 0: - att_op = _STRING_OPS_ATT_MAP.get(op_lower, op_lower) - parts = [att_op] + [_att_convert_operand(o) for o in operands] - return ' '.join(parts) - - if len(operands) >= 3: - suffix = _size_suffix_for_all(operands, op_lower) - converted_ops = [_att_convert_operand(o) for o in operands] - return f"{op_lower}{suffix} {', '.join(converted_ops[1:])}, {converted_ops[0]}" - - if len(operands) >= 2: - src, dst = operands[0], operands[1] - suffix = _size_suffix_for_all([src, dst], op_lower) - return f"{op_lower}{suffix} {_att_convert_operand(dst)}, {_att_convert_operand(src)}" - - if len(operands) == 1: - suffix = _size_suffix_for_all(operands, op_lower) - return f"{op_lower}{suffix} {_att_convert_operand(operands[0])}" - - return op_lower - - -def _find_comment(s: str) -> int: - in_string = False - i = 0 - while i < len(s): - ch = s[i] - if ch == '"': - in_string = not in_string - elif ch == ';' and not in_string: - return i - i += 1 - return -1 - - -def _convert_single(stmt: str) -> str: - stmt = re.sub(r'%(\d+)', r'$\1', stmt) - - if stmt.strip().startswith('.'): - return stmt - - space_idx = -1 - for i, ch in enumerate(stmt): - if ch in ' \t': - space_idx = i - break - - if space_idx < 0: - op = stmt - operands_str = '' - else: - op = stmt[:space_idx] - operands_str = stmt[space_idx:] - - op = op.strip() - operands_str = operands_str.strip() - - if not operands_str: - if op.lower() in _X86_REGS: - return '%' + op - return op - - operands = _parse_operands(operands_str) - return _convert_instruction(op, operands) - - -def convert(template: str) -> str: - lines = template.split('\n') - result = [] - for line in lines: - stripped = line.strip() - if not stripped: - result.append('') - continue - - stripped = stripped.replace('\t', ' ') - - statements = stripped.split(';') - converted_stmts = [] - for stmt in statements: - stmt = stmt.strip() - if not stmt: - continue - - comment_pos = _find_comment(stmt) - if comment_pos >= 0: - code_part = stmt[:comment_pos].strip() - comment_part = stmt[comment_pos:].strip() - else: - code_part = stmt - comment_part = '' - - if code_part.startswith('.'): - converted_stmts.append(code_part + (f' ; {comment_part}' if comment_part else '')) - continue - - m = re.match(r'^(\d+):(.*)$', code_part) - if m: - label_num = m.group(1) - rest = m.group(2).strip() - if rest: - converted_rest = _convert_single(rest) - converted_stmts.append(f"{label_num}: {converted_rest}" + (f' ; {comment_part}' if comment_part else '')) - else: - converted_stmts.append(f"{label_num}:" + (f' ; {comment_part}' if comment_part else '')) - continue - - converted = _convert_single(code_part) - if comment_part: - converted += f' ; {comment_part}' - converted_stmts.append(converted) - - result.append('; '.join(converted_stmts)) - return '\n'.join(result) diff --git a/lib/core/DecoratorPass.py b/lib/core/DecoratorPass.py index c3e5f07..88b93ff 100644 --- a/lib/core/DecoratorPass.py +++ b/lib/core/DecoratorPass.py @@ -1,522 +1,522 @@ -""" -DecoratorPass - Viper 语言自定义装饰器的 IR 层包装转换 (v4) - -v4 增强版特性: -1. 栈帧局部上下文 (ctx):替代全局变量,解决并发/递归状态错乱 -2. 流程劫持:handler 返回 i32 控制原函数调用次数 - - 返回 0:跳过原函数调用(@cache, @mock) - - 返回 1:正常调用一次(默认) - - 返回 N > 1:循环调用 N 次(@repeat) -3. alwaysinline 属性:消除 wrapper 调用开销 -4. 参数打包与修改:pre-phase 后从 args_struct 读回参数,装饰器可修改入参 -5. 返回值修改:ret_ptr 可写,装饰器可在后置阶段修改返回值 -6. 递归装饰保护:最外层 wrapper 检查全局标志位,递归调用时跳过所有装饰逻辑 - -装饰器调用约定 (v4): - i32 decor_name(i8* ctx, i8* func_name, i32 phase, - i8* args_ptr, i8* ret_ptr, i8* decor_args_ptr) - - 参数说明: - ctx : i8* - 栈帧局部上下文缓冲区(32字节),每次调用独立分配 - 前置阶段可写入状态,后置阶段可读取,生命周期绑定本次调用 - 多线程/递归完全隔离,替代全局变量 - func_name : i8* - 原始函数名字符串 - phase : i32 - 执行阶段(0=前置, 1=后置) - args_ptr : i8* - 指向函数参数打包结构体(可读写,无参数时为 null) - 前置阶段可写入修改参数值,wrapper 会从结构体读回修改后的参数 - ret_ptr : i8* - 指向返回值(前置阶段为 null,void 函数始终为 null) - 后置阶段可读写,装饰器可修改返回值 - decor_args_ptr : i8* - 指向装饰器参数打包结构体(无参数装饰器为 null) - - 返回值(仅前置阶段有效,后置阶段忽略): - 0 : 跳过原函数调用(@cache, @mock, @skip) - 1 : 调用原函数一次(默认行为,@log, @timing, @trace) - N>1: 循环调用原函数 N 次(@repeat, @benchmark) - - 编译器生成的 wrapper(以 add(i32, i32) -> i32, @log 为例): - define i32 @__decor_wrap_add(i32 %a, i32 %b) alwaysinline { - entry: - ; 递归保护:检查标志位 - %rec_val = load i8, i8* @__decor_rec___decor_wrap_add - %is_rec = icmp ne i8 %rec_val, 0 - br i1 %is_rec, label %recursive_call, label %decorated_entry - - recursive_call: - ; 递归调用:跳过所有装饰逻辑,直接调用原函数 - %rec_result = call i32 @add(i32 %a, i32 %b) - ret i32 %rec_result - - decorated_entry: - ; 设置递归保护标志 - store i8 1, i8* @__decor_rec___decor_wrap_add - - ; 分配栈帧局部上下文 - %ctx = alloca [32 x i8] - %ctx_ptr = bitcast [32 x i8]* %ctx to i8* - - ; 打包函数参数到结构体(装饰器可通过 args_ptr 修改) - %args = alloca {i32, i32} - store i32 %a, i32* getelementptr({i32, i32}* %args, i32 0, i32 0) - store i32 %b, i32* getelementptr({i32, i32}* %args, i32 0, i32 1) - %args_ptr = bitcast {i32, i32}* %args to i8* - - ; 分配返回值存储(零初始化) - %ret = alloca i32 - store i32 0, i32* %ret - - ; 前置阶段:handler 返回调用次数 - %n = call i32 @log(i8* %ctx_ptr, i8* "add", i32 0, - i8* %args_ptr, i8* null, i8* null) - br label %loop.header - - loop.header: - %i = phi i32 [0, %decorated_entry], [%i.next, %loop.body] - %cond = icmp slt i32 %i, %n - br i1 %cond, label %loop.body, label %post - - loop.body: - ; 从结构体读回参数(装饰器可能已修改) - %a.loaded = load i32, i32* getelementptr({i32, i32}* %args, i32 0, i32 0) - %b.loaded = load i32, i32* getelementptr({i32, i32}* %args, i32 0, i32 1) - %result = call i32 @add(i32 %a.loaded, i32 %b.loaded) - store i32 %result, i32* %ret - %i.next = add i32 %i, 1 - br label %loop.header - - post: - %ret_ptr = bitcast i32* %ret to i8* - call i32 @log(i8* %ctx_ptr, i8* "add", i32 1, - i8* %args_ptr, i8* %ret_ptr, i8* null) - - ; 清除递归保护标志 - store i8 0, i8* @__decor_rec___decor_wrap_add - - %final = load i32, i32* %ret - ret i32 %final - } - -链式装饰器(从下到上嵌套): - @log - @timing - def f(x) -> int: - 等价于 log(timing(f)) - 执行顺序:log_pre → timing_pre → f → timing_post → log_post - 生成:__decor_wrap_f (log) → __decor_wrap_f_timing (timing) → f - 递归保护仅在最外层 wrapper 生效,递归调用直接跳到原始 f -""" -from __future__ import annotations -import llvmlite.ir as ir - - -# 栈帧局部上下文缓冲区大小(字节) -_CTX_SIZE = 32 - -# 装饰器处理函数的 LLVM 签名:i32 (i8*, i8*, i32, i8*, i8*, i8*) -_DECOR_HANDLER_PARAM_TYPES = None # 延迟初始化 - - -def _get_decor_handler_func_type(): - """获取装饰器处理函数的 LLVM FunctionType: i32 (i8*, i8*, i32, i8*, i8*, i8*)""" - global _DECOR_HANDLER_PARAM_TYPES - if _DECOR_HANDLER_PARAM_TYPES is None: - i8_ptr = ir.IntType(8).as_pointer() - _DECOR_HANDLER_PARAM_TYPES = ir.FunctionType( - ir.IntType(32), - [i8_ptr, i8_ptr, ir.IntType(32), i8_ptr, i8_ptr, i8_ptr] - ) - return _DECOR_HANDLER_PARAM_TYPES - - -def _find_or_declare_handler(module, handler_name): - """在 module 中查找或声明装饰器处理函数""" - for f in module.functions: - if f.name == handler_name: - return f - func_type = _get_decor_handler_func_type() - handler = ir.Function(module, func_type, name=handler_name) - return handler - - -def _make_string_constant(module, text, name_prefix="decor.str"): - """在 module 中创建一个全局字符串常量,返回 i8* 指针""" - counter = getattr(_make_string_constant, '_counter', 0) + 1 - _make_string_constant._counter = counter - const_name = f"{name_prefix}.{counter}" - - encoded = text.encode('utf-8') + b'\x00' - const_type = ir.ArrayType(ir.IntType(8), len(encoded)) - const_val = ir.Constant(const_type, bytearray(encoded)) - - global_var = ir.GlobalVariable(module, const_type, name=const_name) - global_var.global_constant = True - global_var.linkage = 'private' - global_var.initializer = const_val - - return global_var.bitcast(ir.IntType(8).as_pointer()) - - -def _make_decor_args_constant(module, decorator_info): - """ - 为带参数的装饰器生成全局常量结构体,返回 i8* 指针。 - 无参数装饰器返回 null。 - - 支持的参数类型: - - int → i32 / i64 - - float → f64 - - bool → i1 - - str → i8*(全局字符串常量) - """ - deco_args = decorator_info.get('args', []) - deco_kwargs = decorator_info.get('kwargs', {}) - - if not deco_args and not deco_kwargs: - return ir.Constant(ir.IntType(8).as_pointer(), None) - - field_types = [] - field_values = [] - - for arg in deco_args: - llvm_type, llvm_val = _python_value_to_llvm(module, arg) - if llvm_type is None: - return ir.Constant(ir.IntType(8).as_pointer(), None) - field_types.append(llvm_type) - field_values.append(llvm_val) - - for kw in sorted(deco_kwargs.keys()): - llvm_type, llvm_val = _python_value_to_llvm(module, deco_kwargs[kw]) - if llvm_type is None: - return ir.Constant(ir.IntType(8).as_pointer(), None) - field_types.append(llvm_type) - field_values.append(llvm_val) - - struct_type = ir.LiteralStructType(field_types) - struct_const = ir.Constant(struct_type, field_values) - - counter = getattr(_make_decor_args_constant, '_counter', 0) + 1 - _make_decor_args_constant._counter = counter - global_name = f"__decor_args.{counter}" - - global_var = ir.GlobalVariable(module, struct_type, name=global_name) - global_var.global_constant = True - global_var.linkage = 'private' - global_var.initializer = struct_const - - return global_var.bitcast(ir.IntType(8).as_pointer()) - - -def _python_value_to_llvm(module, value): - """将 Python 值转换为 (LLVM类型, LLVM常量) 元组。""" - if isinstance(value, bool): - return ir.IntType(1), ir.Constant(ir.IntType(1), int(value)) - elif isinstance(value, int): - if -2**31 <= value < 2**31: - return ir.IntType(32), ir.Constant(ir.IntType(32), value) - else: - return ir.IntType(64), ir.Constant(ir.IntType(64), value) - elif isinstance(value, float): - return ir.DoubleType(), ir.Constant(ir.DoubleType(), value) - elif isinstance(value, str): - str_const = _make_string_constant(module, value, name_prefix="decor.arg") - return ir.IntType(8).as_pointer(), str_const - else: - return None, None - - -def _zero_constant(llvm_type): - """为给定 LLVM 类型创建零值常量""" - if isinstance(llvm_type, ir.IntType): - return ir.Constant(llvm_type, 0) - elif isinstance(llvm_type, (ir.FloatType, ir.DoubleType)): - return ir.Constant(llvm_type, 0.0) - elif isinstance(llvm_type, ir.PointerType): - return ir.Constant(llvm_type, None) - elif isinstance(llvm_type, ir.ArrayType): - elem_zero = _zero_constant(llvm_type.element) - if elem_zero is None: - return None - return ir.Constant(llvm_type, [elem_zero] * llvm_type.count) - else: - return None - - -def _generate_single_wrapper(module, original_func, wrapper_name, func_name_str, - decorator_info, is_export=False, - is_outermost=False, true_original_func=None): - """ - 为单个装饰器生成一层 wrapper 函数。 - - v4 Wrapper 结构(最外层含递归保护): - entry → 递归保护检查(仅最外层) - recursive_call → 递归时直接调用原函数,跳过所有装饰(仅最外层) - decorated_entry → 设置递归标志,分配 ctx/args/ret,调用 handler 前置 - loop.header → phi 计数器,比较 i < n_calls - loop.body → 从 args_struct 读回参数(支持修改),调用原函数 - post → 调用 handler 后置,清除递归标志,返回结果 - """ - decor_name = decorator_info['name'] - handler = _find_or_declare_handler(module, decor_name) - func_name_const = _make_string_constant(module, func_name_str, name_prefix="decor.fn") - - func_type = original_func.ftype - return_type = func_type.return_type - param_types = [p.type for p in original_func.args] - is_void = isinstance(return_type, ir.VoidType) - - wrapper_type = ir.FunctionType(return_type, param_types) - wrapper = ir.Function(module, wrapper_type, name=wrapper_name) - - # 添加 alwaysinline 属性,优化器完全内联消除调用开销 - wrapper.attributes.add('alwaysinline') - - i32 = ir.IntType(32) - i8 = ir.IntType(8) - i8_ptr = ir.IntType(8).as_pointer() - phase_pre = ir.Constant(i32, 0) - phase_post = ir.Constant(i32, 1) - null_ptr = ir.Constant(i8_ptr, None) - zero_i32 = ir.Constant(i32, 0) - one_i32 = ir.Constant(i32, 1) - one_i8 = ir.Constant(i8, 1) - zero_i8 = ir.Constant(i8, 0) - - # 递归保护:仅最外层 wrapper 生成 - rec_flag = None - if is_outermost and true_original_func is not None: - rec_flag_name = f"__decor_rec_{wrapper_name}" - # 检查是否已存在 - rec_flag = None - for g in module.global_values: - if g.name == rec_flag_name: - rec_flag = g - break - if rec_flag is None: - rec_flag = ir.GlobalVariable(module, i8, name=rec_flag_name) - rec_flag.global_constant = False - rec_flag.linkage = 'internal' - rec_flag.initializer = zero_i8 - - # 创建基本块 - entry_block = wrapper.append_basic_block("entry") - - if rec_flag is not None: - recursive_call_block = wrapper.append_basic_block("recursive_call") - decorated_entry_block = wrapper.append_basic_block("decorated_entry") - else: - recursive_call_block = None - decorated_entry_block = None - - loop_header_block = wrapper.append_basic_block("loop.header") - loop_body_block = wrapper.append_basic_block("loop.body") - post_block = wrapper.append_basic_block("post") - - # ==== Entry block ==== - builder = ir.IRBuilder(entry_block) - - if rec_flag is not None: - # 递归保护:检查标志位 - rec_val = builder.load(rec_flag, name="rec_val") - is_recursive = builder.icmp_signed('!=', rec_val, zero_i8) - builder.cbranch(is_recursive, recursive_call_block, decorated_entry_block) - - # ==== Recursive call block ==== - builder = ir.IRBuilder(recursive_call_block) - # 递归调用:直接调用真正的原函数,跳过所有装饰逻辑 - rec_call_args = [arg for arg in wrapper.args] - rec_ret_val = builder.call(true_original_func, rec_call_args) - if is_void: - builder.ret_void() - else: - builder.ret(rec_ret_val) - - # ==== Decorated entry block ==== - builder = ir.IRBuilder(decorated_entry_block) - # 设置递归保护标志 - builder.store(one_i8, rec_flag) - - # 记录 loop.header 的前置块为 decorated_entry_block - loop_predecessor = decorated_entry_block - else: - loop_predecessor = entry_block - - # 1. 分配栈帧局部上下文(每次调用独立,线程安全,递归安全) - ctx_type = ir.ArrayType(ir.IntType(8), _CTX_SIZE) - ctx_alloca = builder.alloca(ctx_type, name="ctx") - ctx_ptr = builder.bitcast(ctx_alloca, i8_ptr) - - # 2. 打包函数参数到结构体(装饰器可通过 args_ptr 读写修改) - args_alloca = None - args_struct_type = None - if param_types: - args_struct_type = ir.LiteralStructType(param_types) - args_alloca = builder.alloca(args_struct_type, name="args") - zero = ir.Constant(i32, 0) - for i, arg in enumerate(wrapper.args): - field_idx = ir.Constant(i32, i) - gep = builder.gep(args_alloca, [zero, field_idx], inbounds=True) - builder.store(arg, gep) - args_ptr = builder.bitcast(args_alloca, i8_ptr) - else: - args_ptr = null_ptr - - # 3. 分配返回值存储(零初始化,确保跳过原函数时返回安全默认值) - if not is_void: - ret_alloca = builder.alloca(return_type, name="ret") - zero_val = _zero_constant(return_type) - if zero_val is not None: - builder.store(zero_val, ret_alloca) - else: - ret_alloca = None - - # 4. 获取装饰器参数指针 - decor_args_ptr = _make_decor_args_constant(module, decorator_info) - - # 5. 前置阶段:handler 返回调用次数 - n_calls = builder.call(handler, [ctx_ptr, func_name_const, phase_pre, - args_ptr, null_ptr, decor_args_ptr]) - - # 6. 跳转到循环头 - builder.branch(loop_header_block) - - # ==== Loop header block ==== - builder = ir.IRBuilder(loop_header_block) - i_phi = builder.phi(i32, "i") - i_phi.add_incoming(zero_i32, loop_predecessor) - cond = builder.icmp_signed('<', i_phi, n_calls) - builder.cbranch(cond, loop_body_block, post_block) - - # ==== Loop body block ==== - builder = ir.IRBuilder(loop_body_block) - - # v4: 从 args_struct 读回参数(装饰器可能在 pre-phase 中修改了参数) - if args_alloca is not None and args_struct_type is not None: - zero = ir.Constant(i32, 0) - call_args = [] - for i in range(len(param_types)): - field_idx = ir.Constant(i32, i) - gep = builder.gep(args_alloca, [zero, field_idx], inbounds=True) - loaded_arg = builder.load(gep, name=f"arg.{i}") - call_args.append(loaded_arg) - else: - call_args = [] - - ret_val = builder.call(original_func, call_args) - if ret_alloca is not None: - builder.store(ret_val, ret_alloca) - i_next = builder.add(i_phi, one_i32) - i_phi.add_incoming(i_next, loop_body_block) - builder.branch(loop_header_block) - - # ==== Post block ==== - builder = ir.IRBuilder(post_block) - - # 后置阶段 - if ret_alloca is not None: - ret_ptr = builder.bitcast(ret_alloca, i8_ptr) - else: - ret_ptr = null_ptr - builder.call(handler, [ctx_ptr, func_name_const, phase_post, - args_ptr, ret_ptr, decor_args_ptr]) - - # 递归保护:清除标志(必须在 post-phase 之后、return 之前) - if rec_flag is not None: - builder.store(zero_i8, rec_flag) - - # 返回 - if is_void: - builder.ret_void() - else: - final_ret = builder.load(ret_alloca, name="final_ret") - builder.ret(final_ret) - - return wrapper - - -def _redirect_calls(module, old_func, new_func, skip_func_names=None): - """ - 替换 module 中所有对 old_func 的调用指令为对 new_func 的调用。 - 跳过 skip_func_names 中的函数(wrapper 函数内部不应被重定向)。 - """ - if skip_func_names is None: - skip_func_names = set() - - for func in module.functions: - if func.name in skip_func_names: - continue - if func.name == new_func.name: - continue - for block in func.blocks: - for instr in list(block.instructions): - if not isinstance(instr, ir.CallInstr): - continue - callee = instr.callee - if isinstance(callee, ir.Function) and callee is old_func: - instr.callee = new_func - - -def run(Gen): - """ - 执行 DecoratorPass。 - - 处理流程: - 1. 遍历 _decorated_funcs 中所有带装饰标记的函数 - 2. 对每个函数,按装饰器列表从底到顶生成嵌套 wrapper - 3. 将原函数改为 internal 链接 - 4. 替换所有调用点 - """ - if not hasattr(Gen, '_decorated_funcs') or not Gen._decorated_funcs: - return - - module = Gen.module - decorated = Gen._decorated_funcs.copy() - - for mangled_name, info in decorated.items(): - decorators = info['decorators'] - func_name = info['func_name'] - is_export = info['is_export'] - - # 查找原始函数 - original_func = None - for f in module.functions: - if f.name == mangled_name: - original_func = f - break - if original_func is None: - continue - - # 原函数改为 internal 链接(仅 wrapper 调用) - original_func.linkage = 'internal' - - # 按装饰器列表从底到顶生成嵌套 wrapper - # Python 装饰器顺序:@a @b def f() => a(b(f)) - # 执行顺序:先应用最靠近函数的 @b,再应用 @a - - current_func = original_func - all_wrapper_names = set() - - for i in range(len(decorators) - 1, -1, -1): - deco = decorators[i] - is_outermost = (i == 0) - deco_name = deco['name'] - - if is_outermost: - wrapper_name = f"__decor_wrap_{mangled_name}" - else: - wrapper_name = f"__decor_wrap_{mangled_name}_{deco_name}" - - all_wrapper_names.add(wrapper_name) - - wrapper = _generate_single_wrapper( - module, current_func, wrapper_name, - func_name, deco, is_export=is_export, - is_outermost=is_outermost, - true_original_func=original_func if is_outermost else None - ) - current_func = wrapper - - # 更新 functions 映射,使原函数名指向最外层 wrapper - Gen.functions[mangled_name] = current_func - if func_name in Gen.functions: - Gen.functions[func_name] = current_func - - # 替换所有非 wrapper 函数中对原函数的调用 - _redirect_calls(module, original_func, current_func, all_wrapper_names) +""" +DecoratorPass - Viper 语言自定义装饰器的 IR 层包装转换 (v4) + +v4 增强版特性: +1. 栈帧局部上下文 (ctx):替代全局变量,解决并发/递归状态错乱 +2. 流程劫持:handler 返回 i32 控制原函数调用次数 + - 返回 0:跳过原函数调用(@cache, @mock) + - 返回 1:正常调用一次(默认) + - 返回 N > 1:循环调用 N 次(@repeat) +3. alwaysinline 属性:消除 wrapper 调用开销 +4. 参数打包与修改:pre-phase 后从 args_struct 读回参数,装饰器可修改入参 +5. 返回值修改:ret_ptr 可写,装饰器可在后置阶段修改返回值 +6. 递归装饰保护:最外层 wrapper 检查全局标志位,递归调用时跳过所有装饰逻辑 + +装饰器调用约定 (v4): + i32 decor_name(i8* ctx, i8* func_name, i32 phase, + i8* args_ptr, i8* ret_ptr, i8* decor_args_ptr) + + 参数说明: + ctx : i8* - 栈帧局部上下文缓冲区(32字节),每次调用独立分配 + 前置阶段可写入状态,后置阶段可读取,生命周期绑定本次调用 + 多线程/递归完全隔离,替代全局变量 + func_name : i8* - 原始函数名字符串 + phase : i32 - 执行阶段(0=前置, 1=后置) + args_ptr : i8* - 指向函数参数打包结构体(可读写,无参数时为 null) + 前置阶段可写入修改参数值,wrapper 会从结构体读回修改后的参数 + ret_ptr : i8* - 指向返回值(前置阶段为 null,void 函数始终为 null) + 后置阶段可读写,装饰器可修改返回值 + decor_args_ptr : i8* - 指向装饰器参数打包结构体(无参数装饰器为 null) + + 返回值(仅前置阶段有效,后置阶段忽略): + 0 : 跳过原函数调用(@cache, @mock, @skip) + 1 : 调用原函数一次(默认行为,@log, @timing, @trace) + N>1: 循环调用原函数 N 次(@repeat, @benchmark) + + 编译器生成的 wrapper(以 add(i32, i32) -> i32, @log 为例): + define i32 @__decor_wrap_add(i32 %a, i32 %b) alwaysinline { + entry: + ; 递归保护:检查标志位 + %rec_val = Load i8, i8* @__decor_rec___decor_wrap_add + %is_rec = icmp ne i8 %rec_val, 0 + br i1 %is_rec, label %recursive_call, label %decorated_entry + + recursive_call: + ; 递归调用:跳过所有装饰逻辑,直接调用原函数 + %rec_result = call i32 @add(i32 %a, i32 %b) + ret i32 %rec_result + + decorated_entry: + ; 设置递归保护标志 + store i8 1, i8* @__decor_rec___decor_wrap_add + + ; 分配栈帧局部上下文 + %ctx = alloca [32 x i8] + %ctx_ptr = bitcast [32 x i8]* %ctx to i8* + + ; 打包函数参数到结构体(装饰器可通过 args_ptr 修改) + %args = alloca {i32, i32} + store i32 %a, i32* getelementptr({i32, i32}* %args, i32 0, i32 0) + store i32 %b, i32* getelementptr({i32, i32}* %args, i32 0, i32 1) + %args_ptr = bitcast {i32, i32}* %args to i8* + + ; 分配返回值存储(零初始化) + %ret = alloca i32 + store i32 0, i32* %ret + + ; 前置阶段:handler 返回调用次数 + %n = call i32 @log(i8* %ctx_ptr, i8* "add", i32 0, + i8* %args_ptr, i8* null, i8* null) + br label %loop.header + + loop.header: + %i = phi i32 [0, %decorated_entry], [%i.next, %loop.body] + %cond = icmp slt i32 %i, %n + br i1 %cond, label %loop.body, label %post + + loop.body: + ; 从结构体读回参数(装饰器可能已修改) + %a.Loaded = Load i32, i32* getelementptr({i32, i32}* %args, i32 0, i32 0) + %b.Loaded = Load i32, i32* getelementptr({i32, i32}* %args, i32 0, i32 1) + %result = call i32 @add(i32 %a.Loaded, i32 %b.Loaded) + store i32 %result, i32* %ret + %i.next = add i32 %i, 1 + br label %loop.header + + post: + %ret_ptr = bitcast i32* %ret to i8* + call i32 @log(i8* %ctx_ptr, i8* "add", i32 1, + i8* %args_ptr, i8* %ret_ptr, i8* null) + + ; 清除递归保护标志 + store i8 0, i8* @__decor_rec___decor_wrap_add + + %final = Load i32, i32* %ret + ret i32 %final + } + +链式装饰器(从下到上嵌套): + @log + @timing + def f(x) -> int: + 等价于 log(timing(f)) + 执行顺序:log_pre → timing_pre → f → timing_post → log_post + 生成:__decor_wrap_f (log) → __decor_wrap_f_timing (timing) → f + 递归保护仅在最外层 wrapper 生效,递归调用直接跳到原始 f +""" +from __future__ import annotations +import llvmlite.ir as ir + + +# 栈帧局部上下文缓冲区大小(字节) +_CTX_SIZE = 32 + +# 装饰器处理函数的 LLVM 签名:i32 (i8*, i8*, i32, i8*, i8*, i8*) +_DECOR_HANDLER_PARAM_TYPES = None # 延迟初始化 + + +def _get_decor_handler_func_type(): + """获取装饰器处理函数的 LLVM FunctionType: i32 (i8*, i8*, i32, i8*, i8*, i8*)""" + global _DECOR_HANDLER_PARAM_TYPES + if _DECOR_HANDLER_PARAM_TYPES is None: + i8_ptr = ir.IntType(8).as_pointer() + _DECOR_HANDLER_PARAM_TYPES = ir.FunctionType( + ir.IntType(32), + [i8_ptr, i8_ptr, ir.IntType(32), i8_ptr, i8_ptr, i8_ptr] + ) + return _DECOR_HANDLER_PARAM_TYPES + + +def _find_or_declare_handler(module, handler_name): + """在 module 中查找或声明装饰器处理函数""" + for f in module.functions: + if f.name == handler_name: + return f + func_type = _get_decor_handler_func_type() + handler = ir.Function(module, func_type, name=handler_name) + return handler + + +def _make_string_constant(module, text, name_prefix="decor.str"): + """在 module 中创建一个全局字符串常量,返回 i8* 指针""" + counter = getattr(_make_string_constant, '_counter', 0) + 1 + _make_string_constant._counter = counter + const_name = f"{name_prefix}.{counter}" + + encoded = text.encode('utf-8') + b'\x00' + const_type = ir.ArrayType(ir.IntType(8), len(encoded)) + const_val = ir.Constant(const_type, bytearray(encoded)) + + global_var = ir.GlobalVariable(module, const_type, name=const_name) + global_var.global_constant = True + global_var.linkage = 'private' + global_var.initializer = const_val + + return global_var.bitcast(ir.IntType(8).as_pointer()) + + +def _make_decor_args_constant(module, decorator_info): + """ + 为带参数的装饰器生成全局常量结构体,返回 i8* 指针。 + 无参数装饰器返回 null。 + + 支持的参数类型: + - int → i32 / i64 + - float → f64 + - bool → i1 + - str → i8*(全局字符串常量) + """ + deco_args = decorator_info.get('args', []) + deco_kwargs = decorator_info.get('kwargs', {}) + + if not deco_args and not deco_kwargs: + return ir.Constant(ir.IntType(8).as_pointer(), None) + + field_types = [] + field_values = [] + + for arg in deco_args: + llvm_type, llvm_val = _python_value_to_llvm(module, arg) + if llvm_type is None: + return ir.Constant(ir.IntType(8).as_pointer(), None) + field_types.append(llvm_type) + field_values.append(llvm_val) + + for kw in sorted(deco_kwargs.keys()): + llvm_type, llvm_val = _python_value_to_llvm(module, deco_kwargs[kw]) + if llvm_type is None: + return ir.Constant(ir.IntType(8).as_pointer(), None) + field_types.append(llvm_type) + field_values.append(llvm_val) + + struct_type = ir.LiteralStructType(field_types) + struct_const = ir.Constant(struct_type, field_values) + + counter = getattr(_make_decor_args_constant, '_counter', 0) + 1 + _make_decor_args_constant._counter = counter + global_name = f"__decor_args.{counter}" + + global_var = ir.GlobalVariable(module, struct_type, name=global_name) + global_var.global_constant = True + global_var.linkage = 'private' + global_var.initializer = struct_const + + return global_var.bitcast(ir.IntType(8).as_pointer()) + + +def _python_value_to_llvm(module, value): + """将 Python 值转换为 (LLVM类型, LLVM常量) 元组。""" + if isinstance(value, bool): + return ir.IntType(1), ir.Constant(ir.IntType(1), int(value)) + elif isinstance(value, int): + if -2**31 <= value < 2**31: + return ir.IntType(32), ir.Constant(ir.IntType(32), value) + else: + return ir.IntType(64), ir.Constant(ir.IntType(64), value) + elif isinstance(value, float): + return ir.DoubleType(), ir.Constant(ir.DoubleType(), value) + elif isinstance(value, str): + str_const = _make_string_constant(module, value, name_prefix="decor.arg") + return ir.IntType(8).as_pointer(), str_const + else: + return None, None + + +def _ZeroConstant(llvm_type): + """为给定 LLVM 类型创建零值常量""" + if isinstance(llvm_type, ir.IntType): + return ir.Constant(llvm_type, 0) + elif isinstance(llvm_type, (ir.FloatType, ir.DoubleType)): + return ir.Constant(llvm_type, 0.0) + elif isinstance(llvm_type, ir.PointerType): + return ir.Constant(llvm_type, None) + elif isinstance(llvm_type, ir.ArrayType): + elem_zero = _ZeroConstant(llvm_type.element) + if elem_zero is None: + return None + return ir.Constant(llvm_type, [elem_zero] * llvm_type.count) + else: + return None + + +def _generate_single_wrapper(module, original_func, wrapper_name, func_name_str, + decorator_info, is_export=False, + is_outermost=False, true_original_func=None): + """ + 为单个装饰器生成一层 wrapper 函数。 + + v4 Wrapper 结构(最外层含递归保护): + entry → 递归保护检查(仅最外层) + recursive_call → 递归时直接调用原函数,跳过所有装饰(仅最外层) + decorated_entry → 设置递归标志,分配 ctx/args/ret,调用 handler 前置 + loop.header → phi 计数器,比较 i < n_calls + loop.body → 从 args_struct 读回参数(支持修改),调用原函数 + post → 调用 handler 后置,清除递归标志,返回结果 + """ + decor_name = decorator_info['name'] + handler = _find_or_declare_handler(module, decor_name) + func_name_const = _make_string_constant(module, func_name_str, name_prefix="decor.fn") + + func_type = original_func.ftype + return_type = func_type.return_type + param_types = [p.type for p in original_func.args] + is_void = isinstance(return_type, ir.VoidType) + + wrapper_type = ir.FunctionType(return_type, param_types) + wrapper = ir.Function(module, wrapper_type, name=wrapper_name) + + # 添加 alwaysinline 属性,优化器完全内联消除调用开销 + wrapper.attributes.add('alwaysinline') + + i32 = ir.IntType(32) + i8 = ir.IntType(8) + i8_ptr = ir.IntType(8).as_pointer() + phase_pre = ir.Constant(i32, 0) + phase_post = ir.Constant(i32, 1) + null_ptr = ir.Constant(i8_ptr, None) + zero_i32 = ir.Constant(i32, 0) + one_i32 = ir.Constant(i32, 1) + one_i8 = ir.Constant(i8, 1) + zero_i8 = ir.Constant(i8, 0) + + # 递归保护:仅最外层 wrapper 生成 + rec_flag = None + if is_outermost and true_original_func is not None: + rec_flag_name = f"__decor_rec_{wrapper_name}" + # 检查是否已存在 + rec_flag = None + for g in module.global_values: + if g.name == rec_flag_name: + rec_flag = g + break + if rec_flag is None: + rec_flag = ir.GlobalVariable(module, i8, name=rec_flag_name) + rec_flag.global_constant = False + rec_flag.linkage = 'internal' + rec_flag.initializer = zero_i8 + + # 创建基本块 + entry_block = wrapper.append_basic_block("entry") + + if rec_flag is not None: + recursive_call_block = wrapper.append_basic_block("recursive_call") + decorated_entry_block = wrapper.append_basic_block("decorated_entry") + else: + recursive_call_block = None + decorated_entry_block = None + + loop_header_block = wrapper.append_basic_block("loop.header") + loop_body_block = wrapper.append_basic_block("loop.body") + post_block = wrapper.append_basic_block("post") + + # ==== Entry block ==== + builder = ir.IRBuilder(entry_block) + + if rec_flag is not None: + # 递归保护:检查标志位 + rec_val = builder.load(rec_flag, name="rec_val") + is_recursive = builder.icmp_signed('!=', rec_val, zero_i8) + builder.cbranch(is_recursive, recursive_call_block, decorated_entry_block) + + # ==== Recursive call block ==== + builder = ir.IRBuilder(recursive_call_block) + # 递归调用:直接调用真正的原函数,跳过所有装饰逻辑 + rec_call_args = [arg for arg in wrapper.args] + rec_ret_val = builder.call(true_original_func, rec_call_args) + if is_void: + builder.ret_void() + else: + builder.ret(rec_ret_val) + + # ==== Decorated entry block ==== + builder = ir.IRBuilder(decorated_entry_block) + # 设置递归保护标志 + builder.store(one_i8, rec_flag) + + # 记录 loop.header 的前置块为 decorated_entry_block + loop_predecessor = decorated_entry_block + else: + loop_predecessor = entry_block + + # 1. 分配栈帧局部上下文(每次调用独立,线程安全,递归安全) + ctx_type = ir.ArrayType(ir.IntType(8), _CTX_SIZE) + ctx_alloca = builder.alloca(ctx_type, name="ctx") + ctx_ptr = builder.bitcast(ctx_alloca, i8_ptr) + + # 2. 打包函数参数到结构体(装饰器可通过 args_ptr 读写修改) + args_alloca = None + args_struct_type = None + if param_types: + args_struct_type = ir.LiteralStructType(param_types) + args_alloca = builder.alloca(args_struct_type, name="args") + zero = ir.Constant(i32, 0) + for i, arg in enumerate(wrapper.args): + field_idx = ir.Constant(i32, i) + gep = builder.gep(args_alloca, [zero, field_idx], inbounds=True) + builder.store(arg, gep) + args_ptr = builder.bitcast(args_alloca, i8_ptr) + else: + args_ptr = null_ptr + + # 3. 分配返回值存储(零初始化,确保跳过原函数时返回安全默认值) + if not is_void: + ret_alloca = builder.alloca(return_type, name="ret") + zero_val = _ZeroConstant(return_type) + if zero_val is not None: + builder.store(zero_val, ret_alloca) + else: + ret_alloca = None + + # 4. 获取装饰器参数指针 + decor_args_ptr = _make_decor_args_constant(module, decorator_info) + + # 5. 前置阶段:handler 返回调用次数 + n_calls = builder.call(handler, [ctx_ptr, func_name_const, phase_pre, + args_ptr, null_ptr, decor_args_ptr]) + + # 6. 跳转到循环头 + builder.branch(loop_header_block) + + # ==== Loop header block ==== + builder = ir.IRBuilder(loop_header_block) + i_phi = builder.phi(i32, "i") + i_phi.add_incoming(zero_i32, loop_predecessor) + cond = builder.icmp_signed('<', i_phi, n_calls) + builder.cbranch(cond, loop_body_block, post_block) + + # ==== Loop body block ==== + builder = ir.IRBuilder(loop_body_block) + + # v4: 从 args_struct 读回参数(装饰器可能在 pre-phase 中修改了参数) + if args_alloca is not None and args_struct_type is not None: + zero = ir.Constant(i32, 0) + call_args = [] + for i in range(len(param_types)): + field_idx = ir.Constant(i32, i) + gep = builder.gep(args_alloca, [zero, field_idx], inbounds=True) + Loaded_arg = builder.load(gep, name=f"arg.{i}") + call_args.append(Loaded_arg) + else: + call_args = [] + + ret_val = builder.call(original_func, call_args) + if ret_alloca is not None: + builder.store(ret_val, ret_alloca) + i_next = builder.add(i_phi, one_i32) + i_phi.add_incoming(i_next, loop_body_block) + builder.branch(loop_header_block) + + # ==== Post block ==== + builder = ir.IRBuilder(post_block) + + # 后置阶段 + if ret_alloca is not None: + ret_ptr = builder.bitcast(ret_alloca, i8_ptr) + else: + ret_ptr = null_ptr + builder.call(handler, [ctx_ptr, func_name_const, phase_post, + args_ptr, ret_ptr, decor_args_ptr]) + + # 递归保护:清除标志(必须在 post-phase 之后、return 之前) + if rec_flag is not None: + builder.store(zero_i8, rec_flag) + + # 返回 + if is_void: + builder.ret_void() + else: + final_ret = builder.load(ret_alloca, name="final_ret") + builder.ret(final_ret) + + return wrapper + + +def _redirect_calls(module, old_func, new_func, skip_func_names=None): + """ + 替换 module 中所有对 old_func 的调用指令为对 new_func 的调用。 + 跳过 skip_func_names 中的函数(wrapper 函数内部不应被重定向)。 + """ + if skip_func_names is None: + skip_func_names = set() + + for func in module.functions: + if func.name in skip_func_names: + continue + if func.name == new_func.name: + continue + for block in func.blocks: + for instr in list(block.instructions): + if not isinstance(instr, ir.CallInstr): + continue + callee = instr.callee + if isinstance(callee, ir.Function) and callee is old_func: + instr.callee = new_func + + +def run(Gen): + """ + 执行 DecoratorPass。 + + 处理流程: + 1. 遍历 _decorated_funcs 中所有带装饰标记的函数 + 2. 对每个函数,按装饰器列表从底到顶生成嵌套 wrapper + 3. 将原函数改为 internal 链接 + 4. 替换所有调用点 + """ + if not hasattr(Gen, '_decorated_funcs') or not Gen._decorated_funcs: + return + + module = Gen.module + decorated = Gen._decorated_funcs.copy() + + for mangled_name, info in decorated.items(): + decorators = info['decorators'] + func_name = info['func_name'] + is_export = info['is_export'] + + # 查找原始函数 + original_func = None + for f in module.functions: + if f.name == mangled_name: + original_func = f + break + if original_func is None: + continue + + # 原函数改为 internal 链接(仅 wrapper 调用) + original_func.linkage = 'internal' + + # 按装饰器列表从底到顶生成嵌套 wrapper + # Python 装饰器顺序:@a @b def f() => a(b(f)) + # 执行顺序:先应用最靠近函数的 @b,再应用 @a + + current_func = original_func + all_wrapper_names = set() + + for i in range(len(decorators) - 1, -1, -1): + deco = decorators[i] + is_outermost = (i == 0) + deco_name = deco['name'] + + if is_outermost: + wrapper_name = f"__decor_wrap_{mangled_name}" + else: + wrapper_name = f"__decor_wrap_{mangled_name}_{deco_name}" + + all_wrapper_names.add(wrapper_name) + + wrapper = _generate_single_wrapper( + module, current_func, wrapper_name, + func_name, deco, is_export=is_export, + is_outermost=is_outermost, + true_original_func=original_func if is_outermost else None + ) + current_func = wrapper + + # 更新 functions 映射,使原函数名指向最外层 wrapper + Gen.functions[mangled_name] = current_func + if func_name in Gen.functions: + Gen.functions[func_name] = current_func + + # 替换所有非 wrapper 函数中对原函数的调用 + _redirect_calls(module, original_func, current_func, all_wrapper_names) diff --git a/lib/core/export_table.py b/lib/core/Exportable.py similarity index 93% rename from lib/core/export_table.py rename to lib/core/Exportable.py index e206be1..00d6c01 100644 --- a/lib/core/export_table.py +++ b/lib/core/Exportable.py @@ -1,177 +1,177 @@ -#!/usr/bin/env python3 -""" -导出表模块 - 用于收集和存储文件的公开符号信息 -""" -from dataclasses import dataclass, field -from typing import Dict, List, Optional, Any - - -@dataclass -class EnumMember: - """枚举成员信息""" - name: str - value: int - lineno: int - - -@dataclass -class EnumInfo: - """枚举类型信息""" - name: str - members: List[EnumMember] = field(default_factory=list) - lineno: int = 0 - is_public: bool = True - - -@dataclass -class FunctionParam: - """函数参数信息""" - name: str - type_name: str - is_pointer: bool = False - - -@dataclass -class FunctionInfo: - """函数信息""" - name: str - return_type: str - params: List[FunctionParam] = field(default_factory=list) - lineno: int = 0 - is_public: bool = True - - -@dataclass -class StructMember: - """结构体成员信息""" - name: str - type_name: str - is_pointer: bool = False - array_size: Optional[int] = None - - -@dataclass -class StructInfo: - """结构体类型信息""" - name: str - members: List[StructMember] = field(default_factory=list) - lineno: int = 0 - is_public: bool = True - - -@dataclass -class TypedefInfo: - """类型别名信息""" - name: str - original_type: str - lineno: int = 0 - is_public: bool = True - - -@dataclass -class ExportTable: - """导出表 - 存储文件的所有公开符号""" - filename: str - enums: List[EnumInfo] = field(default_factory=list) - functions: List[FunctionInfo] = field(default_factory=list) - structs: List[StructInfo] = field(default_factory=list) - typedefs: List[TypedefInfo] = field(default_factory=list) - - def add_enum(self, name: str, lineno: int, is_public: bool = True) -> EnumInfo: - """添加枚举类型""" - enum_info = EnumInfo(name=name, lineno=lineno, is_public=is_public) - self.enums.append(enum_info) - return enum_info - - def add_function(self, name: str, return_type: str, lineno: int, is_public: bool = True) -> FunctionInfo: - """添加函数""" - func_info = FunctionInfo(name=name, return_type=return_type, lineno=lineno, is_public=is_public) - self.functions.append(func_info) - return func_info - - def add_struct(self, name: str, lineno: int, is_public: bool = True) -> StructInfo: - """添加结构体""" - struct_info = StructInfo(name=name, lineno=lineno, is_public=is_public) - self.structs.append(struct_info) - return struct_info - - def add_typedef(self, name: str, original_type: str, lineno: int, is_public: bool = True) -> TypedefInfo: - """添加类型别名""" - typedef_info = TypedefInfo(name=name, original_type=original_type, lineno=lineno, is_public=is_public) - self.typedefs.append(typedef_info) - return typedef_info - - def to_dict(self) -> Dict[str, Any]: - """转换为字典格式""" - return { - 'filename': self.filename, - 'enums': [ - { - 'name': enum.name, - 'lineno': enum.lineno, - 'is_public': enum.is_public, - 'members': [ - {'name': m.name, 'value': m.value, 'lineno': m.lineno} - for m in enum.members - ] - } - for enum in self.enums - ], - 'functions': [ - { - 'name': func.name, - 'return_type': func.return_type, - 'lineno': func.lineno, - 'is_public': func.is_public, - 'params': [ - {'name': p.name, 'type_name': p.type_name, 'is_pointer': p.is_pointer} - for p in func.params - ] - } - for func in self.functions - ], - 'structs': [ - { - 'name': struct.name, - 'lineno': struct.lineno, - 'is_public': struct.is_public, - 'members': [ - { - 'name': m.name, - 'type_name': m.type_name, - 'is_pointer': m.is_pointer, - 'array_size': m.array_size - } - for m in struct.members - ] - } - for struct in self.structs - ], - 'typedefs': [ - { - 'name': typedef.name, - 'original_type': typedef.original_type, - 'lineno': typedef.lineno, - 'is_public': typedef.is_public - } - for typedef in self.typedefs - ] - } - - def merge(self, other: 'ExportTable') -> None: - """合并另一个导出表""" - self.enums.extend(other.enums) - self.functions.extend(other.functions) - self.structs.extend(other.structs) - self.typedefs.extend(other.typedefs) - - def get_public_symbols(self) -> 'ExportTable': - """获取仅包含公开符号的导出表""" - result = ExportTable(filename=self.filename) - - result.enums = [e for e in self.enums if e.is_public] - result.functions = [f for f in self.functions if f.is_public] - result.structs = [s for s in self.structs if s.is_public] - result.typedefs = [t for t in self.typedefs if t.is_public] - - return result +#!/usr/bin/env python3 +""" +导出表模块 - 用于收集和存储文件的公开符号信息 +""" +from dataclasses import dataclass, field +from typing import Dict, List, Optional, Any + + +@dataclass +class EnumMember: + """枚举成员信息""" + name: str + value: int + lineno: int + + +@dataclass +class EnumInfo: + """枚举类型信息""" + name: str + members: List[EnumMember] = field(default_factory=list) + lineno: int = 0 + is_public: bool = True + + +@dataclass +class FunctionParam: + """函数参数信息""" + name: str + type_name: str + is_pointer: bool = False + + +@dataclass +class FunctionInfo: + """函数信息""" + name: str + return_type: str + params: List[FunctionParam] = field(default_factory=list) + lineno: int = 0 + is_public: bool = True + + +@dataclass +class StructMember: + """结构体成员信息""" + name: str + type_name: str + is_pointer: bool = False + array_size: Optional[int] = None + + +@dataclass +class StructInfo: + """结构体类型信息""" + name: str + members: List[StructMember] = field(default_factory=list) + lineno: int = 0 + is_public: bool = True + + +@dataclass +class TypedefInfo: + """类型别名信息""" + name: str + original_type: str + lineno: int = 0 + is_public: bool = True + + +@dataclass +class Exportable: + """导出表 - 存储文件的所有公开符号""" + filename: str + enums: List[EnumInfo] = field(default_factory=list) + functions: List[FunctionInfo] = field(default_factory=list) + structs: List[StructInfo] = field(default_factory=list) + typedefs: List[TypedefInfo] = field(default_factory=list) + + def add_enum(self, name: str, lineno: int, is_public: bool = True) -> EnumInfo: + """添加枚举类型""" + enum_info = EnumInfo(name=name, lineno=lineno, is_public=is_public) + self.enums.append(enum_info) + return enum_info + + def add_function(self, name: str, return_type: str, lineno: int, is_public: bool = True) -> FunctionInfo: + """添加函数""" + func_info = FunctionInfo(name=name, return_type=return_type, lineno=lineno, is_public=is_public) + self.functions.append(func_info) + return func_info + + def add_struct(self, name: str, lineno: int, is_public: bool = True) -> StructInfo: + """添加结构体""" + struct_info = StructInfo(name=name, lineno=lineno, is_public=is_public) + self.structs.append(struct_info) + return struct_info + + def add_typedef(self, name: str, original_type: str, lineno: int, is_public: bool = True) -> TypedefInfo: + """添加类型别名""" + typedef_info = TypedefInfo(name=name, original_type=original_type, lineno=lineno, is_public=is_public) + self.typedefs.append(typedef_info) + return typedef_info + + def to_dict(self) -> Dict[str, Any]: + """转换为字典格式""" + return { + 'filename': self.filename, + 'enums': [ + { + 'name': enum.name, + 'lineno': enum.lineno, + 'is_public': enum.is_public, + 'members': [ + {'name': m.name, 'value': m.value, 'lineno': m.lineno} + for m in enum.members + ] + } + for enum in self.enums + ], + 'functions': [ + { + 'name': func.name, + 'return_type': func.return_type, + 'lineno': func.lineno, + 'is_public': func.is_public, + 'params': [ + {'name': p.name, 'type_name': p.type_name, 'is_pointer': p.is_pointer} + for p in func.params + ] + } + for func in self.functions + ], + 'structs': [ + { + 'name': struct.name, + 'lineno': struct.lineno, + 'is_public': struct.is_public, + 'members': [ + { + 'name': m.name, + 'type_name': m.type_name, + 'is_pointer': m.is_pointer, + 'array_size': m.array_size + } + for m in struct.members + ] + } + for struct in self.structs + ], + 'typedefs': [ + { + 'name': typedef.name, + 'original_type': typedef.original_type, + 'lineno': typedef.lineno, + 'is_public': typedef.is_public + } + for typedef in self.typedefs + ] + } + + def merge(self, other: 'Exportable') -> None: + """合并另一个导出表""" + self.enums.extend(other.enums) + self.functions.extend(other.functions) + self.structs.extend(other.structs) + self.typedefs.extend(other.typedefs) + + def get_public_symbols(self) -> 'Exportable': + """获取仅包含公开符号的导出表""" + result = Exportable(filename=self.filename) + + result.enums = [e for e in self.enums if e.is_public] + result.functions = [f for f in self.functions if f.is_public] + result.structs = [s for s in self.structs if s.is_public] + result.typedefs = [t for t in self.typedefs if t.is_public] + + return result diff --git a/lib/core/Handles/HandlesAnnAssign.py b/lib/core/Handles/HandlesAnnAssign.py index 7809086..6afab8d 100644 --- a/lib/core/Handles/HandlesAnnAssign.py +++ b/lib/core/Handles/HandlesAnnAssign.py @@ -2,7 +2,7 @@ from __future__ import annotations from typing import TYPE_CHECKING if TYPE_CHECKING: from lib.core.translator import Translator -from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo +from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo from lib.includes import t import ast import llvmlite.ir as ir @@ -33,7 +33,7 @@ class AnnAssignHandle(BaseHandle): CastedVal = Gen.builder.bitcast(Value, VarPtr.type.pointee, name=f"cast_{VarName}") Gen._store(CastedVal, VarPtr) except Exception: # 回退:bitcast 失败时 alloca 新变量 - NewVar = Gen._alloca_entry(Value.type, name=VarName) + NewVar = Gen._allocaEntry(Value.type, name=VarName) Gen._store(Value, NewVar) Gen.variables[VarName] = NewVar @@ -90,7 +90,7 @@ class AnnAssignHandle(BaseHandle): if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.IntType) and ObjVal.type.pointee.width == 8: ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType): - ObjVal = Gen._load(ObjVal, name=f"load_{ClassName}") + ObjVal = Gen._load(ObjVal, name=f"Load_{ClassName}") if isinstance(ObjVal.type, ir.PointerType) and ObjVal.type.pointee == Gen.structs[ClassName]: if IsUnion: NestedStructName = f"{ClassName}_{AttrName}" @@ -195,7 +195,7 @@ class AnnAssignHandle(BaseHandle): if Node.value and isinstance(Node.value, ast.Constant) and isinstance(Node.value.value, str): ArrayCount = len(Node.value.value) + 1 VarType = ir.ArrayType(ElemType, ArrayCount) - var = Gen._alloca_entry(VarType, name=VarName) + var = Gen._allocaEntry(VarType, name=VarName) Gen.variables[VarName] = var Gen._record_var_signedness(VarName, False) if Node.value and isinstance(Node.value, ast.List): @@ -267,7 +267,7 @@ class AnnAssignHandle(BaseHandle): if VarName in Gen._reg_values: OldVal = Gen._reg_values[VarName] if isinstance(OldVal.type, ir.PointerType): - var = Gen._alloca_entry(OldVal.type, name=VarName) + var = Gen._allocaEntry(OldVal.type, name=VarName) Gen._store(OldVal, var) Gen.variables[VarName] = var del Gen._reg_values[VarName] @@ -294,7 +294,7 @@ class AnnAssignHandle(BaseHandle): is_vtable_class = True break if is_vtable_class: - var = Gen._alloca_entry(InitValue.type, name=VarName) + var = Gen._allocaEntry(InitValue.type, name=VarName) Gen._store(InitValue, var) Gen.variables[VarName] = var if isinstance(Node.annotation, ast.Name) and Node.annotation.id in Gen.structs: @@ -329,7 +329,7 @@ class AnnAssignHandle(BaseHandle): Gen.variables[VarName] = GVar Gen._record_var_signedness(VarName, IsUnsigned) return - var = Gen._alloca_entry(VarType, name=VarName) + var = Gen._allocaEntry(VarType, name=VarName) if InitValue and isinstance(InitValue.type, ir.PointerType): pointee = InitValue.type.pointee if isinstance(pointee, ir.IdentifiedStructType): @@ -340,7 +340,7 @@ class AnnAssignHandle(BaseHandle): is_vtable_class = True break if is_vtable_class and not isinstance(VarType, ir.PointerType): - var = Gen._alloca_entry(InitValue.type, name=VarName) + var = Gen._allocaEntry(InitValue.type, name=VarName) VarType = InitValue.type IsPtr = True Gen._store(InitValue, var) @@ -356,7 +356,7 @@ class AnnAssignHandle(BaseHandle): Gen.var_struct_class[VarName] = CN Gen.global_struct_class[VarName] = CN if isinstance(VarType, ir.PointerType) and VarType.pointee is not ST and VarType.pointee != ST: - var = Gen._alloca_entry(ir.PointerType(pointee), name=VarName) + var = Gen._allocaEntry(ir.PointerType(pointee), name=VarName) VarType = ir.PointerType(pointee) break if InitValue: @@ -435,8 +435,12 @@ class AnnAssignHandle(BaseHandle): AttrTypeInfo = CTypeInfo.FromNode(Node.annotation, self.Trans.SymbolTable) if AttrTypeInfo: AttrVarType = Gen._ctype_to_llvm(AttrTypeInfo) - except Exception as e: - pass + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _config_mode + if _config_mode == "strict": + raise + _vlog().warning(f"解析类型失败: {_e}", "Exception") Value = self.HandleExprLlvm(Node.value, VarType=AttrVarType) if Value: self._HandleAttributeStoreLlvm(Node.target, Value) diff --git a/lib/core/Handles/HandlesAssign.py b/lib/core/Handles/HandlesAssign.py index e7ceb93..17161eb 100644 --- a/lib/core/Handles/HandlesAssign.py +++ b/lib/core/Handles/HandlesAssign.py @@ -2,7 +2,7 @@ from __future__ import annotations from typing import TYPE_CHECKING if TYPE_CHECKING: from lib.core.translator import Translator -from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo, FuncMeta +from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo, FuncMeta from lib.includes import t import ast import llvmlite.ir as ir @@ -89,12 +89,12 @@ class AssignHandle: fmt_ptr = Gen.builder.bitcast(fmt_gvar, ir.PointerType(ir.IntType(8)), name=f"{VarName}_fmt") fmt_var_name = f"__{VarName}_fmt" if fmt_var_name not in Gen.variables: - fmt_alloca = Gen._alloca_entry(ir.PointerType(ir.IntType(8)), name=fmt_var_name) + fmt_alloca = Gen._allocaEntry(ir.PointerType(ir.IntType(8)), name=fmt_var_name) Gen.variables[fmt_var_name] = fmt_alloca Gen.builder.store(fmt_ptr, Gen.variables[fmt_var_name]) kind_var_name = f"__{VarName}_kind" if kind_var_name not in Gen.variables: - kind_alloca = Gen._alloca_entry(ir.IntType(32), name=kind_var_name) + kind_alloca = Gen._allocaEntry(ir.IntType(32), name=kind_var_name) Gen.variables[kind_var_name] = kind_alloca Gen.builder.store(ir.Constant(ir.IntType(32), 0), Gen.variables[kind_var_name]) if VarName not in Gen.variables: @@ -116,12 +116,12 @@ class AssignHandle: fmt_ptr = Gen.builder.bitcast(fmt_gvar, ir.PointerType(ir.IntType(8)), name=f"{VarName}_fmt") fmt_var_name = f"__{VarName}_fmt" if fmt_var_name not in Gen.variables: - fmt_alloca = Gen._alloca_entry(ir.PointerType(ir.IntType(8)), name=fmt_var_name) + fmt_alloca = Gen._allocaEntry(ir.PointerType(ir.IntType(8)), name=fmt_var_name) Gen.variables[fmt_var_name] = fmt_alloca Gen.builder.store(fmt_ptr, Gen.variables[fmt_var_name]) kind_var_name = f"__{VarName}_kind" if kind_var_name not in Gen.variables: - kind_alloca = Gen._alloca_entry(ir.IntType(32), name=kind_var_name) + kind_alloca = Gen._allocaEntry(ir.IntType(32), name=kind_var_name) Gen.variables[kind_var_name] = kind_alloca Gen.builder.store(ir.Constant(ir.IntType(32), 1), Gen.variables[kind_var_name]) if VarName not in Gen.variables: @@ -129,7 +129,7 @@ class AssignHandle: Gen.variables[VarName] = dummy_var return if isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Name) and Node.value.func.id == 'va_list': - va_list_ptr = Gen._alloca_entry(ir.IntType(8).as_pointer(), name="va_list") + va_list_ptr = Gen._allocaEntry(ir.IntType(8).as_pointer(), name="va_list") Gen.variables[VarName] = va_list_ptr return IsStructCtor = (isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Name) @@ -147,7 +147,7 @@ class AssignHandle: if IsUnion: Value = self.HandleExprLlvm(Node.value) if Value: - var = Gen._alloca_entry(Value.type, name=VarName) + var = Gen._allocaEntry(Value.type, name=VarName) Gen._store(Value, var) Gen.variables[VarName] = var return @@ -160,7 +160,7 @@ class AssignHandle: elif VarName in Gen._reg_values: OldVal = Gen._reg_values[VarName] if isinstance(OldVal.type, ir.PointerType): - var = Gen._alloca_entry(OldVal.type, name=VarName) + var = Gen._allocaEntry(OldVal.type, name=VarName) Gen._store(OldVal, var) Gen.variables[VarName] = var del Gen._reg_values[VarName] @@ -168,7 +168,7 @@ class AssignHandle: elif VarName in Gen._direct_values: OldVal = Gen._direct_values.pop(VarName) if isinstance(OldVal.type, ir.PointerType): - var = Gen._alloca_entry(OldVal.type, name=VarName) + var = Gen._allocaEntry(OldVal.type, name=VarName) Gen._store(OldVal, var) Gen.variables[VarName] = var ExistingPtr = var @@ -195,7 +195,7 @@ class AssignHandle: return if isinstance(Value.type, ir.VoidType): return - Gen._unregister_temp_ptr(Value) + Gen._UnregisterTempPtr(Value) if isinstance(Value.type, ir.PointerType) and isinstance(Value.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): found_class = None found = Gen.find_struct_by_pointee(Value.type.pointee) @@ -219,7 +219,7 @@ class AssignHandle: if VarName in Gen.variables and Gen.variables[VarName] is not None: Gen._store(Value, Gen.variables[VarName]) else: - var = Gen._alloca_entry(Value.type, name=VarName) + var = Gen._allocaEntry(Value.type, name=VarName) Gen._store(Value, var) Gen.variables[VarName] = var if isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Name): @@ -231,17 +231,17 @@ class AssignHandle: dst_fmt_var = f"__{VarName}_fmt" if src_fmt_var in Gen.variables: if dst_fmt_var not in Gen.variables: - dst_alloca = Gen._alloca_entry(ir.PointerType(ir.IntType(8)), name=dst_fmt_var) + dst_alloca = Gen._allocaEntry(ir.PointerType(ir.IntType(8)), name=dst_fmt_var) Gen.variables[dst_fmt_var] = dst_alloca - src_fmt_ptr = Gen._load(Gen.variables[src_fmt_var], name=f"load_{call_func_name}_fmt_for_{VarName}") + src_fmt_ptr = Gen._load(Gen.variables[src_fmt_var], name=f"Load_{call_func_name}_fmt_for_{VarName}") Gen.builder.store(src_fmt_ptr, Gen.variables[dst_fmt_var]) src_kind_var = f"__{call_func_name}_kind" dst_kind_var = f"__{VarName}_kind" if src_kind_var in Gen.variables: if dst_kind_var not in Gen.variables: - dst_kind_alloca = Gen._alloca_entry(ir.IntType(32), name=dst_kind_var) + dst_kind_alloca = Gen._allocaEntry(ir.IntType(32), name=dst_kind_var) Gen.variables[dst_kind_var] = dst_kind_alloca - src_kind_val = Gen._load(Gen.variables[src_kind_var], name=f"load_{call_func_name}_kind_for_{VarName}") + src_kind_val = Gen._load(Gen.variables[src_kind_var], name=f"Load_{call_func_name}_kind_for_{VarName}") Gen.builder.store(src_kind_val, Gen.variables[dst_kind_var]) Gen.var_type_info[VarName] = {'type': 't_type_runtime', 'source': call_func_name} return @@ -260,13 +260,13 @@ class AssignHandle: return if VarName in Gen._reg_values: OldVal = Gen._reg_values[VarName] - var = Gen._alloca_entry(OldVal.type, name=VarName) + var = Gen._allocaEntry(OldVal.type, name=VarName) Gen._store(OldVal, var) Gen.variables[VarName] = var del Gen._reg_values[VarName] if VarName in Gen._direct_values: OldVal = Gen._direct_values.pop(VarName) - var = Gen._alloca_entry(OldVal.type, name=VarName) + var = Gen._allocaEntry(OldVal.type, name=VarName) Gen._store(OldVal, var) Gen.variables[VarName] = var if VarName in Gen.variables and Gen.variables[VarName] is not None: @@ -277,12 +277,12 @@ class AssignHandle: except AssertionError: types_differ = False if isinstance(Value.type, ir.PointerType) and isinstance(Value.type.pointee, ir.PointerType): - LoadedValue = Gen._load(Value, name=f"load_{VarName}") + LoadedValue = Gen._load(Value, name=f"Load_{VarName}") try: - loaded_differ = TargetType and LoadedValue.type != TargetType + Loaded_differ = TargetType and LoadedValue.type != TargetType except AssertionError: - loaded_differ = False - if loaded_differ: + Loaded_differ = False + if Loaded_differ: try: Coerced = Gen._coerce_value(LoadedValue, TargetType) if Coerced is not None: @@ -308,12 +308,12 @@ class AssignHandle: Gen._store(Value, GVar) Gen.variables[VarName] = GVar elif isinstance(Value.type, ir.PointerType) and isinstance(Value.type.pointee, ir.PointerType): - LoadedValue = Gen._load(Value, name=f"load_{VarName}") - var = Gen._alloca_entry(LoadedValue.type, name=VarName) + LoadedValue = Gen._load(Value, name=f"Load_{VarName}") + var = Gen._allocaEntry(LoadedValue.type, name=VarName) Gen._store(LoadedValue, var) Gen.variables[VarName] = var else: - var = Gen._alloca_entry(Value.type, name=VarName) + var = Gen._allocaEntry(Value.type, name=VarName) Gen._store(Value, var) Gen.variables[VarName] = var is_u = Gen._check_node_unsigned(Node.value) @@ -327,17 +327,17 @@ class AssignHandle: dst_fmt_var = f"__{VarName}_fmt" if src_fmt_var in Gen.variables: if dst_fmt_var not in Gen.variables: - dst_alloca = Gen._alloca_entry(ir.PointerType(ir.IntType(8)), name=dst_fmt_var) + dst_alloca = Gen._allocaEntry(ir.PointerType(ir.IntType(8)), name=dst_fmt_var) Gen.variables[dst_fmt_var] = dst_alloca - src_fmt_ptr = Gen._load(Gen.variables[src_fmt_var], name=f"load_{call_func_name}_fmt_for_{VarName}") + src_fmt_ptr = Gen._load(Gen.variables[src_fmt_var], name=f"Load_{call_func_name}_fmt_for_{VarName}") Gen.builder.store(src_fmt_ptr, Gen.variables[dst_fmt_var]) src_kind_var = f"__{call_func_name}_kind" dst_kind_var = f"__{VarName}_kind" if src_kind_var in Gen.variables: if dst_kind_var not in Gen.variables: - dst_kind_alloca = Gen._alloca_entry(ir.IntType(32), name=dst_kind_var) + dst_kind_alloca = Gen._allocaEntry(ir.IntType(32), name=dst_kind_var) Gen.variables[dst_kind_var] = dst_kind_alloca - src_kind_val = Gen._load(Gen.variables[src_kind_var], name=f"load_{call_func_name}_kind_for_{VarName}") + src_kind_val = Gen._load(Gen.variables[src_kind_var], name=f"Load_{call_func_name}_kind_for_{VarName}") Gen.builder.store(src_kind_val, Gen.variables[dst_kind_var]) Gen.var_type_info[VarName] = {'type': 't_type_runtime', 'source': call_func_name} else: @@ -403,12 +403,12 @@ class AssignHandle: elif isinstance(Target, ast.Tuple): if isinstance(Node.value, ast.Call): FuncName = None - module_path = None + ModulePath = None if isinstance(Node.value.func, ast.Name): FuncName = Node.value.func.id elif isinstance(Node.value.func, ast.Attribute): FuncName = Node.value.func.attr - module_path = self.Trans.ExprCallHandle._get_module_path(Node.value.func.value) + ModulePath = self.Trans.ExprCallHandle._get_ModulePath(Node.value.func.value) CReturnTypes = [] FuncDef = self.Trans.FunctionDefCache.get(FuncName) if FuncName else None if FuncDef: @@ -436,8 +436,8 @@ class AssignHandle: if not CReturnTypes: sym_key = FuncName if sym_key not in self.Trans.SymbolTable: - if module_path: - sym_key = f"{module_path}.{FuncName}" + if ModulePath: + sym_key = f"{ModulePath}.{FuncName}" sym_info = self.Trans.SymbolTable.get(sym_key) if sym_info and sym_info.IsFunction: ret_type_info = getattr(sym_info, 'FuncPtrReturn', None) @@ -604,7 +604,7 @@ class AssignHandle: CastedVal = Gen.builder.bitcast(Value, VarPtr.type.pointee, name=f"cast_{VarName}") Gen._store(CastedVal, VarPtr) except Exception: # 回退:bitcast 失败时 alloca 新变量 - NewVar = Gen._alloca_entry(Value.type, name=VarName) + NewVar = Gen._allocaEntry(Value.type, name=VarName) Gen._store(Value, NewVar) Gen.variables[VarName] = NewVar @@ -620,7 +620,7 @@ class AssignHandle: SelfVar = Gen._get_var_ptr('self') if SelfVar: SelfPtr = Gen._load(SelfVar, name="self") - SetterFunc = Gen._get_function(PropKey) + SetterFunc = Gen._get_function(PropKey + '$set') if SetterFunc and SelfPtr: Gen.builder.call(SetterFunc, [SelfPtr, Value], name=f"prop_set_{PropKey}") return @@ -683,7 +683,7 @@ class AssignHandle: if offset >= max_offset: VarName = f"self.{AttrName}" if VarName not in Gen.variables: - NewVar = Gen._alloca_entry(Value.type, name=AttrName) + NewVar = Gen._allocaEntry(Value.type, name=AttrName) Gen.variables[VarName] = NewVar Gen._store(Value, Gen.variables[VarName]) return @@ -736,10 +736,10 @@ class AssignHandle: PropInfo = self.Trans.SymbolTable.get(PropKey) if PropInfo and hasattr(PropInfo, 'MetaList') and FuncMeta.PROPERTY_SETTER in PropInfo.MetaList: ObjVal = self.Trans.ExprHandler.HandleExprLlvm(Target.value) - SetterFunc = Gen._get_function(PropKey) + SetterFunc = Gen._get_function(PropKey + '$set') if SetterFunc and ObjVal: if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType): - ObjVal = Gen._load(ObjVal, name=f"load_{ClassName}") + ObjVal = Gen._load(ObjVal, name=f"Load_{ClassName}") Gen.builder.call(SetterFunc, [ObjVal, Value], name=f"prop_set_{PropKey}") return ObjVal = self.Trans.ExprHandler.HandleExprLlvm(Target.value) @@ -747,7 +747,7 @@ class AssignHandle: if BaseHandle._is_char_pointer(ObjVal): ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType): - ObjVal = Gen._load(ObjVal, name=f"load_{ClassName}") + ObjVal = Gen._load(ObjVal, name=f"Load_{ClassName}") if isinstance(ObjVal.type, ir.PointerType) and ObjVal.type.pointee == Gen.structs[ClassName]: if IsUnion: NestedStructName = f"{ClassName}_{AttrName}" @@ -855,8 +855,8 @@ class AssignHandle: self._StoreWithCoerce(Value, MemberPtr) if not ClassName: - imported_modules = getattr(self.Trans, '_imported_modules', None) - import_aliases = getattr(self.Trans, '_import_aliases', {}) + imported_modules = getattr(self.Trans, '_ImportedModules', None) + import_aliases = getattr(self.Trans, '_ImportAliases', {}) resolved_mod = import_aliases.get(VarName, VarName) if imported_modules and (VarName in imported_modules or resolved_mod in imported_modules): PossibleKeys = [f"{VarName}.{AttrName}", AttrName] @@ -874,14 +874,14 @@ class AssignHandle: return self._StoreWithCoerce(Value, GVar) return - module_sha1_map = getattr(Gen, 'module_sha1_map', {}) + ModuleSha1Map = getattr(Gen, 'ModuleSha1Map', {}) sha1_candidates = [VarName, resolved_mod] for mod_name in imported_modules: if mod_name.endswith(f".{VarName}") or mod_name == VarName: if mod_name not in sha1_candidates: sha1_candidates.append(mod_name) for cand in sha1_candidates: - sha1 = module_sha1_map.get(cand) + sha1 = ModuleSha1Map.get(cand) if sha1: prefixed = f"{sha1}.{AttrName}" if prefixed in Gen.module.globals: @@ -945,7 +945,7 @@ class AssignHandle: self._StoreWithCoerce(Value, MemberPtr) return elif isinstance(Target.value, ast.Call): - # Check if this is c.Deref(...) — we need the pointer, not the loaded value + # Check if this is c.Deref(...) — we need the pointer, not the Loaded value ObjVal = None is_cderef = (isinstance(Target.value.func, ast.Attribute) and isinstance(Target.value.func.value, ast.Name) and @@ -953,7 +953,7 @@ class AssignHandle: Target.value.func.attr == 'Deref' and Target.value.args) if is_cderef: - # Get the pointer from c.Deref argument, don't load the value + # Get the pointer from c.Deref argument, don't Load the value deref_arg = Target.value.args[0] inner_val = self.HandleExprLlvm(deref_arg) if inner_val and isinstance(inner_val.type, ir.PointerType): @@ -1019,7 +1019,7 @@ class AssignHandle: MemberPtr = Gen.builder.gep(SubPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) self._StoreWithCoerce(Value, MemberPtr) elif isinstance(pointee, ir.PointerType): - LoadedPtr = Gen._load(SubPtr, name=f"load_{AttrName}_ptr") + LoadedPtr = Gen._load(SubPtr, name=f"Load_{AttrName}_ptr") if isinstance(LoadedPtr.type, ir.PointerType) and isinstance(LoadedPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): found = Gen.find_struct_by_pointee(LoadedPtr.type.pointee) if found: @@ -1049,8 +1049,8 @@ class AssignHandle: if not ValueVal or not IndexVal: return if BaseHandle._is_char_pointer(IndexVal): - loaded_byte = Gen._load(IndexVal, name="load_char_idx_store") - IndexVal = Gen.builder.zext(loaded_byte, ir.IntType(32), name="char_to_int_idx_store") + Loaded_byte = Gen._load(IndexVal, name="Load_char_idx_store") + IndexVal = Gen.builder.zext(Loaded_byte, ir.IntType(32), name="char_to_int_idx_store") if isinstance(ValueVal.type, ir.IntType): var_ptr = self._get_int_ptr(Target.value) if var_ptr: @@ -1116,7 +1116,7 @@ class AssignHandle: ElemPtr = Gen.builder.gep(AttrPtr, [zero, IndexVal], name="subscript") self._StoreWithCoerce(Value, ElemPtr) return - arr_alloc = Gen._alloca_entry(ValueVal.type, name="arr_subscript_tmp") + arr_alloc = Gen._allocaEntry(ValueVal.type, name="arr_subscript_tmp") Gen._store(ValueVal, arr_alloc) ElemPtr = Gen.builder.gep(arr_alloc, [zero, IndexVal], name="subscript") self._StoreWithCoerce(Value, ElemPtr) diff --git a/lib/core/Handles/HandlesAugAssign.py b/lib/core/Handles/HandlesAugAssign.py index 575bd6e..a8cf11d 100644 --- a/lib/core/Handles/HandlesAugAssign.py +++ b/lib/core/Handles/HandlesAugAssign.py @@ -1,212 +1,212 @@ -from __future__ import annotations -from typing import TYPE_CHECKING -if TYPE_CHECKING: - from lib.core.translator import Translator -from lib.core.Handles.HandlesBase import BaseHandle -import ast -import llvmlite.ir as ir - - -class AugAssignHandle(BaseHandle): - _AUGOP_MAP = { - ast.Add: '__iadd__', ast.Sub: '__isub__', ast.Mult: '__imul__', - ast.Div: '__itruediv__', ast.FloorDiv: '__ifloordiv__', ast.Mod: '__imod__', ast.Pow: '__ipow__', - } - _AUGOP_FALLBACK = { - ast.Add: '__add__', ast.Sub: '__sub__', ast.Mult: '__mul__', - ast.Div: '__truediv__', ast.FloorDiv: '__floordiv__', ast.Mod: '__mod__', ast.Pow: '__pow__', - } - - def _is_aug_unsigned(self, Node, OldVal, Value): - """判断增量赋值操作是否应使用无符号指令""" - Gen = self.Trans.LlvmGen - if isinstance(Node.target, ast.Name): - if Gen._check_node_unsigned(Node.target): - return True - elif isinstance(Node.target, ast.Attribute): - if Gen._check_node_unsigned(Node.target): - return True - elif isinstance(Node.target, ast.Subscript): - if Gen._check_node_unsigned(Node.target): - return True - if Node.value is not None and Gen._check_node_unsigned(Node.value): - return True - return False - - def _HandleAugAssignLlvm(self, Node): - Gen = self.Trans.LlvmGen - if isinstance(Node.target, ast.Name): - VarName = Node.target.id - if VarName in Gen.var_const_flags: - src_info = Gen._get_node_info() - print(f"[错误] 不能对 const 变量 '{VarName}' 增量赋值{src_info}") - import sys - sys.exit(1) - ClassName = Gen.var_struct_class.get(VarName) - iop_name = self._AUGOP_MAP.get(type(Node.op)) - if ClassName and iop_name: - iFuncName = f'{ClassName}.{iop_name}' - FuncName = f'{ClassName}.{self._AUGOP_FALLBACK.get(type(Node.op), "")}' - if iFuncName in Gen.functions or FuncName in Gen.functions: - OldVal = self.Trans.ExprHandler.HandleExprLlvm(ast.Name(id=VarName, ctx=ast.Load())) - Value = self.HandleExprLlvm(Node.value) - if OldVal and Value: - if iFuncName in Gen.functions: - result = self.Trans.ExprHandler._try_operator_overload(ClassName, iop_name, OldVal, Gen, Value) - else: - result = self.Trans.ExprHandler._try_operator_overload(ClassName, self._AUGOP_FALLBACK[type(Node.op)], OldVal, Gen, Value) - if result is not None: - if VarName in Gen.variables and Gen.variables[VarName] is not None: - VarPtr = Gen.variables[VarName] - if VarPtr.type.pointee == result.type: - Gen._store(result, VarPtr) - elif isinstance(VarPtr.type.pointee, ir.PointerType) and isinstance(result.type, ir.PointerType): - CastedVal = Gen.builder.bitcast(result, VarPtr.type.pointee, name=f"cast_{VarName}") - Gen._store(CastedVal, VarPtr) - else: - NewVar = Gen._alloca_entry(result.type, name=VarName) - Gen._store(result, NewVar) - Gen.variables[VarName] = NewVar - else: - Gen._reg_values[VarName] = result - Gen.variables[VarName] = None - return - Value = self.HandleExprLlvm(Node.value) - if not Value: - return - is_unsigned = self._is_aug_unsigned(Node, None, Value) - if isinstance(Node.target, ast.Name): - VarName = Node.target.id - Op = self.Trans.ExprHandler.GetOpSymbol(Node.op) - if VarName in Gen.global_vars and VarName in Gen.module.globals: - GVar = Gen.module.globals[VarName] - Gen.variables[VarName] = GVar - OldVal = Gen._load(GVar, name=VarName) - NewVal = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned) - Gen._store(NewVal, GVar) - return - if VarName in Gen._reg_values: - OldVal = Gen._reg_values[VarName] - saved_block = Gen.builder.block - entry_block = Gen.func.entry_basic_block - Gen.builder.position_at_start(entry_block) - var = Gen.builder.alloca(OldVal.type, name=VarName) - Gen._store(OldVal, var) - Gen.builder.position_at_end(saved_block) - Gen.variables[VarName] = var - del Gen._reg_values[VarName] - if VarName in Gen._direct_values: - OldVal = Gen._direct_values.pop(VarName) - saved_block = Gen.builder.block - entry_block = Gen.func.entry_basic_block - Gen.builder.position_at_start(entry_block) - var = Gen.builder.alloca(OldVal.type, name=VarName) - Gen._store(OldVal, var) - Gen.builder.position_at_end(saved_block) - Gen.variables[VarName] = var - if Gen.builder.block.is_terminated: - return - if VarName in Gen.variables and Gen.variables[VarName] is not None: - OldVal = Gen._load(Gen.variables[VarName], name=VarName) - store_ptr = Gen.variables[VarName] - if isinstance(OldVal.type, ir.PointerType) and isinstance(Value.type, ir.IntType): - if Value.type.width != 64: - Value = Gen.builder.zext(Value, ir.IntType(64), name="zext_ptr_offset") - if Op == '-' or Op == '+': - if Op == '-': - NegValue = Gen.builder.neg(Value, name="neg_ptr_offset") - NewVal = Gen.builder.gep(OldVal, [NegValue], name="ptr_sub") - else: - NewVal = Gen.builder.gep(OldVal, [Value], name="ptr_add") - else: - ptr_val = OldVal - OldVal = Gen._load(OldVal, name="deref_ptr_for_op") - orig_type = OldVal.type - if isinstance(OldVal.type, ir.IntType) and isinstance(Value.type, ir.IntType): - if OldVal.type.width < Value.type.width: - OldVal = Gen.builder.zext(OldVal, Value.type, name="zext_left") - elif OldVal.type.width > Value.type.width: - Value = Gen.builder.zext(Value, OldVal.type, name="zext_right") - NewVal = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned) - if isinstance(NewVal.type, ir.IntType) and isinstance(orig_type, ir.IntType): - if NewVal.type.width > orig_type.width: - NewVal = Gen.builder.trunc(NewVal, orig_type, name="trunc_result") - store_ptr = ptr_val - else: - if isinstance(OldVal.type, ir.IntType) and isinstance(Value.type, ir.IntType): - if OldVal.type.width < Value.type.width: - OldVal = Gen.builder.zext(OldVal, Value.type, name="zext_left") - elif OldVal.type.width > Value.type.width: - Value = Gen.builder.zext(Value, OldVal.type, name="zext_right") - elif isinstance(OldVal.type, ir.PointerType) and isinstance(Value.type, ir.IntType): - if Op in ('+', '-'): - if Value.type.width < 64: - Value = Gen.builder.zext(Value, ir.IntType(64), name="zext_ptr_offset_aug") - if Op == '-': - NegValue = Gen.builder.neg(Value, name="neg_ptr_offset_aug") - NewVal = Gen.builder.gep(OldVal, [NegValue], name="ptr_sub_aug") - else: - NewVal = Gen.builder.gep(OldVal, [Value], name="ptr_add_aug") - Gen._store(NewVal, store_ptr) - return - NewVal = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned) - if isinstance(store_ptr.type, ir.PointerType): - TargetType = store_ptr.type.pointee - if NewVal.type != TargetType: - Coerced = Gen._coerce_value(NewVal, TargetType) - if Coerced is not None: - NewVal = Coerced - Gen._store(NewVal, store_ptr) - elif VarName == 'pos': - var = Gen._alloca_entry(Value.type, name=VarName) - Gen.variables[VarName] = var - OldVal = Gen._load(var, name=VarName) - NewVal = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned) - Gen._store(NewVal, var) - elif isinstance(Node.target, ast.Attribute): - AttrName = Node.target.attr - OldVal = self.Trans.ExprHandler.HandleExprLlvm(Node.target) - if OldVal: - def _deref_if_ptr(val): - if isinstance(val.type, ir.PointerType): - pointee = val.type.pointee - if isinstance(pointee, (ir.IntType, ir.FloatType, ir.DoubleType)): - return Gen._load(val, name="deref_aug") - return val - OldVal = _deref_if_ptr(OldVal) - Op = self.Trans.ExprHandler.GetOpSymbol(Node.op) - if isinstance(OldVal.type, ir.IntType) and isinstance(Value.type, ir.IntType): - if OldVal.type.width < Value.type.width: - OldVal = Gen.builder.zext(OldVal, Value.type, name="zext_left_attr") - elif OldVal.type.width > Value.type.width: - Value = Gen.builder.zext(Value, OldVal.type, name="zext_right_attr") - NewVal = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned) - self.Trans.AssignHandler._HandleAttributeStoreLlvm(Node.target, NewVal) - elif isinstance(Node.target, ast.Subscript): - SubTarget = Node.target - ElemPtr = self.Trans.ExprAttrHandle.HandleSubscriptPtrLlvm(SubTarget) - if ElemPtr: - if isinstance(ElemPtr.type, ir.PointerType): - OldVal = Gen._load(ElemPtr, name="old_subscript_val") - Op = self.Trans.ExprHandler.GetOpSymbol(Node.op) - if isinstance(OldVal.type, ir.IntType) and isinstance(Value.type, ir.IntType): - if OldVal.type.width < Value.type.width: - OldVal = Gen.builder.zext(OldVal, Value.type, name="zext_left_sub") - elif OldVal.type.width > Value.type.width: - Value = Gen.builder.zext(Value, OldVal.type, name="zext_right_sub") - elif isinstance(OldVal.type, ir.PointerType) and isinstance(Value.type, ir.IntType): - if Op in ('+', '-'): - if Value.type.width < 64: - Value = Gen.builder.zext(Value, ir.IntType(64), name="zext_ptr_offset_sub") - if Op == '-': - NegValue = Gen.builder.neg(Value, name="neg_ptr_offset_sub") - NewVal = Gen.builder.gep(OldVal, [NegValue], name="ptr_sub_sub") - else: - NewVal = Gen.builder.gep(OldVal, [Value], name="ptr_add_sub") - Gen._store(NewVal, ElemPtr) - return - NewVal = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned) - if isinstance(NewVal.type, ir.IntType) and isinstance(ElemPtr.type.pointee, ir.IntType): - if NewVal.type.width > ElemPtr.type.pointee.width: - NewVal = Gen.builder.trunc(NewVal, ElemPtr.type.pointee, name="trunc_sub_result") - Gen._store(NewVal, ElemPtr) +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle +import ast +import llvmlite.ir as ir + + +class AugAssignHandle(BaseHandle): + _AUGOP_MAP = { + ast.Add: '__iadd__', ast.Sub: '__isub__', ast.Mult: '__imul__', + ast.Div: '__itruediv__', ast.FloorDiv: '__ifloordiv__', ast.Mod: '__imod__', ast.Pow: '__ipow__', + } + _AUGOP_FALLBACK = { + ast.Add: '__add__', ast.Sub: '__sub__', ast.Mult: '__mul__', + ast.Div: '__truediv__', ast.FloorDiv: '__floordiv__', ast.Mod: '__mod__', ast.Pow: '__pow__', + } + + def _is_aug_unsigned(self, Node, OldVal, Value): + """判断增量赋值操作是否应使用无符号指令""" + Gen = self.Trans.LlvmGen + if isinstance(Node.target, ast.Name): + if Gen._check_node_unsigned(Node.target): + return True + elif isinstance(Node.target, ast.Attribute): + if Gen._check_node_unsigned(Node.target): + return True + elif isinstance(Node.target, ast.Subscript): + if Gen._check_node_unsigned(Node.target): + return True + if Node.value is not None and Gen._check_node_unsigned(Node.value): + return True + return False + + def _HandleAugAssignLlvm(self, Node): + Gen = self.Trans.LlvmGen + if isinstance(Node.target, ast.Name): + VarName = Node.target.id + if VarName in Gen.var_const_flags: + src_info = Gen._get_node_info() + print(f"[错误] 不能对 const 变量 '{VarName}' 增量赋值{src_info}") + import sys + sys.exit(1) + ClassName = Gen.var_struct_class.get(VarName) + iop_name = self._AUGOP_MAP.get(type(Node.op)) + if ClassName and iop_name: + iFuncName = f'{ClassName}.{iop_name}' + FuncName = f'{ClassName}.{self._AUGOP_FALLBACK.get(type(Node.op), "")}' + if iFuncName in Gen.functions or FuncName in Gen.functions: + OldVal = self.Trans.ExprHandler.HandleExprLlvm(ast.Name(id=VarName, ctx=ast.Load())) + Value = self.HandleExprLlvm(Node.value) + if OldVal and Value: + if iFuncName in Gen.functions: + result = self.Trans.ExprHandler._try_operator_overLoad(ClassName, iop_name, OldVal, Gen, Value) + else: + result = self.Trans.ExprHandler._try_operator_overLoad(ClassName, self._AUGOP_FALLBACK[type(Node.op)], OldVal, Gen, Value) + if result is not None: + if VarName in Gen.variables and Gen.variables[VarName] is not None: + VarPtr = Gen.variables[VarName] + if VarPtr.type.pointee == result.type: + Gen._store(result, VarPtr) + elif isinstance(VarPtr.type.pointee, ir.PointerType) and isinstance(result.type, ir.PointerType): + CastedVal = Gen.builder.bitcast(result, VarPtr.type.pointee, name=f"cast_{VarName}") + Gen._store(CastedVal, VarPtr) + else: + NewVar = Gen._allocaEntry(result.type, name=VarName) + Gen._store(result, NewVar) + Gen.variables[VarName] = NewVar + else: + Gen._reg_values[VarName] = result + Gen.variables[VarName] = None + return + Value = self.HandleExprLlvm(Node.value) + if not Value: + return + is_unsigned = self._is_aug_unsigned(Node, None, Value) + if isinstance(Node.target, ast.Name): + VarName = Node.target.id + Op = self.Trans.ExprHandler.GetOpSymbol(Node.op) + if VarName in Gen.global_vars and VarName in Gen.module.globals: + GVar = Gen.module.globals[VarName] + Gen.variables[VarName] = GVar + OldVal = Gen._load(GVar, name=VarName) + NewVal = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned) + Gen._store(NewVal, GVar) + return + if VarName in Gen._reg_values: + OldVal = Gen._reg_values[VarName] + saved_block = Gen.builder.block + entry_block = Gen.func.entry_basic_block + Gen.builder.position_at_start(entry_block) + var = Gen.builder.alloca(OldVal.type, name=VarName) + Gen._store(OldVal, var) + Gen.builder.position_at_end(saved_block) + Gen.variables[VarName] = var + del Gen._reg_values[VarName] + if VarName in Gen._direct_values: + OldVal = Gen._direct_values.pop(VarName) + saved_block = Gen.builder.block + entry_block = Gen.func.entry_basic_block + Gen.builder.position_at_start(entry_block) + var = Gen.builder.alloca(OldVal.type, name=VarName) + Gen._store(OldVal, var) + Gen.builder.position_at_end(saved_block) + Gen.variables[VarName] = var + if Gen.builder.block.is_terminated: + return + if VarName in Gen.variables and Gen.variables[VarName] is not None: + OldVal = Gen._load(Gen.variables[VarName], name=VarName) + store_ptr = Gen.variables[VarName] + if isinstance(OldVal.type, ir.PointerType) and isinstance(Value.type, ir.IntType): + if Value.type.width != 64: + Value = Gen.builder.zext(Value, ir.IntType(64), name="zext_ptr_offset") + if Op == '-' or Op == '+': + if Op == '-': + NegValue = Gen.builder.neg(Value, name="neg_ptr_offset") + NewVal = Gen.builder.gep(OldVal, [NegValue], name="ptr_sub") + else: + NewVal = Gen.builder.gep(OldVal, [Value], name="ptr_add") + else: + ptr_val = OldVal + OldVal = Gen._load(OldVal, name="deref_ptr_for_op") + orig_type = OldVal.type + if isinstance(OldVal.type, ir.IntType) and isinstance(Value.type, ir.IntType): + if OldVal.type.width < Value.type.width: + OldVal = Gen.builder.zext(OldVal, Value.type, name="zext_left") + elif OldVal.type.width > Value.type.width: + Value = Gen.builder.zext(Value, OldVal.type, name="zext_right") + NewVal = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned) + if isinstance(NewVal.type, ir.IntType) and isinstance(orig_type, ir.IntType): + if NewVal.type.width > orig_type.width: + NewVal = Gen.builder.trunc(NewVal, orig_type, name="trunc_result") + store_ptr = ptr_val + else: + if isinstance(OldVal.type, ir.IntType) and isinstance(Value.type, ir.IntType): + if OldVal.type.width < Value.type.width: + OldVal = Gen.builder.zext(OldVal, Value.type, name="zext_left") + elif OldVal.type.width > Value.type.width: + Value = Gen.builder.zext(Value, OldVal.type, name="zext_right") + elif isinstance(OldVal.type, ir.PointerType) and isinstance(Value.type, ir.IntType): + if Op in ('+', '-'): + if Value.type.width < 64: + Value = Gen.builder.zext(Value, ir.IntType(64), name="zext_ptr_offset_aug") + if Op == '-': + NegValue = Gen.builder.neg(Value, name="neg_ptr_offset_aug") + NewVal = Gen.builder.gep(OldVal, [NegValue], name="ptr_sub_aug") + else: + NewVal = Gen.builder.gep(OldVal, [Value], name="ptr_add_aug") + Gen._store(NewVal, store_ptr) + return + NewVal = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned) + if isinstance(store_ptr.type, ir.PointerType): + TargetType = store_ptr.type.pointee + if NewVal.type != TargetType: + Coerced = Gen._coerce_value(NewVal, TargetType) + if Coerced is not None: + NewVal = Coerced + Gen._store(NewVal, store_ptr) + elif VarName == 'pos': + var = Gen._allocaEntry(Value.type, name=VarName) + Gen.variables[VarName] = var + OldVal = Gen._load(var, name=VarName) + NewVal = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned) + Gen._store(NewVal, var) + elif isinstance(Node.target, ast.Attribute): + AttrName = Node.target.attr + OldVal = self.Trans.ExprHandler.HandleExprLlvm(Node.target) + if OldVal: + def _deref_if_ptr(val): + if isinstance(val.type, ir.PointerType): + pointee = val.type.pointee + if isinstance(pointee, (ir.IntType, ir.FloatType, ir.DoubleType)): + return Gen._load(val, name="deref_aug") + return val + OldVal = _deref_if_ptr(OldVal) + Op = self.Trans.ExprHandler.GetOpSymbol(Node.op) + if isinstance(OldVal.type, ir.IntType) and isinstance(Value.type, ir.IntType): + if OldVal.type.width < Value.type.width: + OldVal = Gen.builder.zext(OldVal, Value.type, name="zext_left_attr") + elif OldVal.type.width > Value.type.width: + Value = Gen.builder.zext(Value, OldVal.type, name="zext_right_attr") + NewVal = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned) + self.Trans.AssignHandler._HandleAttributeStoreLlvm(Node.target, NewVal) + elif isinstance(Node.target, ast.Subscript): + SubTarget = Node.target + ElemPtr = self.Trans.ExprAttrHandle.HandleSubscriptPtrLlvm(SubTarget) + if ElemPtr: + if isinstance(ElemPtr.type, ir.PointerType): + OldVal = Gen._load(ElemPtr, name="old_subscript_val") + Op = self.Trans.ExprHandler.GetOpSymbol(Node.op) + if isinstance(OldVal.type, ir.IntType) and isinstance(Value.type, ir.IntType): + if OldVal.type.width < Value.type.width: + OldVal = Gen.builder.zext(OldVal, Value.type, name="zext_left_sub") + elif OldVal.type.width > Value.type.width: + Value = Gen.builder.zext(Value, OldVal.type, name="zext_right_sub") + elif isinstance(OldVal.type, ir.PointerType) and isinstance(Value.type, ir.IntType): + if Op in ('+', '-'): + if Value.type.width < 64: + Value = Gen.builder.zext(Value, ir.IntType(64), name="zext_ptr_offset_sub") + if Op == '-': + NegValue = Gen.builder.neg(Value, name="neg_ptr_offset_sub") + NewVal = Gen.builder.gep(OldVal, [NegValue], name="ptr_sub_sub") + else: + NewVal = Gen.builder.gep(OldVal, [Value], name="ptr_add_sub") + Gen._store(NewVal, ElemPtr) + return + NewVal = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned) + if isinstance(NewVal.type, ir.IntType) and isinstance(ElemPtr.type.pointee, ir.IntType): + if NewVal.type.width > ElemPtr.type.pointee.width: + NewVal = Gen.builder.trunc(NewVal, ElemPtr.type.pointee, name="trunc_sub_result") + Gen._store(NewVal, ElemPtr) diff --git a/lib/core/Handles/HandlesBase.py b/lib/core/Handles/HandlesBase.py index 60b7983..94d0b9b 100644 --- a/lib/core/Handles/HandlesBase.py +++ b/lib/core/Handles/HandlesBase.py @@ -1,5 +1,5 @@ from __future__ import annotations -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Dict, Tuple if TYPE_CHECKING: from lib.core.translator import Translator from lib.constants import config as _config @@ -950,7 +950,7 @@ class CTypeInfo: if ModulePath: resolved = False if hasattr(SymbolTable, 'translator'): - import_aliases = getattr(SymbolTable.translator, '_import_aliases', {}) + import_aliases = getattr(SymbolTable.translator, '_ImportAliases', {}) if ModulePath in import_aliases: ModulePath = import_aliases[ModulePath] resolved = True @@ -1056,10 +1056,10 @@ class CTypeInfo: if OriginalType and 'typedef' in OriginalType: parts = OriginalType.split() if len(parts) >= 2: - base_type_name = parts[1] - if not base_type_name.startswith('C'): - base_type_name = 'C' + base_type_name - CNAME = CTypeHelper.GetCName(base_type_name) + BaseType_name = parts[1] + if not BaseType_name.startswith('C'): + BaseType_name = 'C' + BaseType_name + CNAME = CTypeHelper.GetCName(BaseType_name) if CNAME: return cls.FromTypeName(CNAME) Result = cls() diff --git a/lib/core/Handles/HandlesBody.py b/lib/core/Handles/HandlesBody.py index 63a8d48..e236783 100644 --- a/lib/core/Handles/HandlesBody.py +++ b/lib/core/Handles/HandlesBody.py @@ -67,10 +67,10 @@ class BodyHandle(BaseHandle): line_info = "源代码 (%s, line %d)" % (src_path, lineno) if source_line: line_info += ":\n %d | %s" % (lineno, source_line) - self.Trans._error_stack.append((type(e).__name__, str(e), line_info)) + self.Trans._ErrorStack.append((type(e).__name__, str(e), line_info)) raise if Gen.builder and not Gen.builder.block.is_terminated: - Gen._emit_temp_frees() + Gen._EmitTempFrees() def HandleExprLlvm(self, Node, VarType=None): return self.Trans.ExprHandler.HandleExprLlvm(Node, VarType) diff --git a/lib/core/Handles/HandlesClassDef.py b/lib/core/Handles/HandlesClassDef.py index 29df85a..9c72ecb 100644 --- a/lib/core/Handles/HandlesClassDef.py +++ b/lib/core/Handles/HandlesClassDef.py @@ -2,7 +2,7 @@ from __future__ import annotations from typing import TYPE_CHECKING if TYPE_CHECKING: from lib.core.translator import Translator -from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo +from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo, FuncMeta from lib.core.SymbolNode import SymbolNode from lib.includes import t import ast @@ -345,6 +345,12 @@ class ClassHandle(BaseHandle): if isinstance(item, ast.FunctionDef): MethodName = item.name FullMethodName = f"{ClassName}.{MethodName}" + # property setter/deleter 使用不同的函数名后缀 + item_meta = self.Trans.FunctionHandler._ExtractFuncMeta(item.decorator_list) + if FuncMeta.PROPERTY_SETTER in item_meta: + FullMethodName = FullMethodName + '$set' + elif FuncMeta.PROPERTY_DELETER in item_meta: + FullMethodName = FullMethodName + '$del' if FullMethodName not in Gen.class_methods[ClassName]: Gen.class_methods[ClassName].append(FullMethodName) Gen.register_method(ClassName, FullMethodName) @@ -781,8 +787,8 @@ class ClassHandle(BaseHandle): EnumTypeInfo.BaseType = t.CEnum(ClassName) EnumTypeInfo.IsEnum = True self.Trans.SymbolTable[ClassName] = EnumTypeInfo - from lib.core.export_table import EnumMember as ExportEnumMember - enum_export = self.Trans.ExportTable.add_enum( + from lib.core.Exportable import EnumMember as ExportEnumMember + enum_export = self.Trans.Exportable.add_enum( name=ClassName, lineno=Node.lineno, is_public=True diff --git a/lib/core/Handles/HandlesDelete.py b/lib/core/Handles/HandlesDelete.py index a511244..243733b 100644 --- a/lib/core/Handles/HandlesDelete.py +++ b/lib/core/Handles/HandlesDelete.py @@ -44,7 +44,7 @@ class DeleteHandle(BaseHandle): SelfVar = Gen._get_var_ptr('self') if SelfVar: SelfPtr = Gen._load(SelfVar, name="self") - DeleterFunc = Gen._get_function(PropKey) + DeleterFunc = Gen._get_function(PropKey + '$del') if DeleterFunc and SelfPtr: Gen.builder.call(DeleterFunc, [SelfPtr], name=f"prop_del_{PropKey}") continue @@ -57,7 +57,7 @@ class DeleteHandle(BaseHandle): if PropInfo and hasattr(PropInfo, 'MetaList') and FuncMeta.PROPERTY_DELETER in PropInfo.MetaList: obj_val = self.Trans.ExprHandler.HandleExprLlvm(target.value) if obj_val: - DeleterFunc = Gen._get_function(PropKey) + DeleterFunc = Gen._get_function(PropKey + '$del') if DeleterFunc: Gen.builder.call(DeleterFunc, [obj_val], name=f"prop_del_{PropKey}") continue @@ -66,7 +66,7 @@ class DeleteHandle(BaseHandle): obj_val = self.Trans.ExprHandler.HandleExprLlvm(target) if obj_val: if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.PointerType): - obj_val = Gen._load(obj_val, name="load_del_ptr") + obj_val = Gen._load(obj_val, name="Load_del_ptr") ClassName = None if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): for CN, ST in Gen.structs.items(): diff --git a/lib/core/Handles/HandlesExpr.py b/lib/core/Handles/HandlesExpr.py index 956994b..dbf117c 100644 --- a/lib/core/Handles/HandlesExpr.py +++ b/lib/core/Handles/HandlesExpr.py @@ -1,429 +1,429 @@ -from __future__ import annotations -from typing import TYPE_CHECKING -if TYPE_CHECKING: - from lib.core.translator import Translator -from lib.core.Handles.HandlesBase import BaseHandle -import ast -import llvmlite.ir as ir - - -class ExprHandle(BaseHandle): - def __init__(self, translator: "Translator"): - super().__init__(translator) - - def GetOpSymbol(self, Op): - return self.Trans.ExprUtils.GetOpSymbol(Op) - - def GetUnaryOpSymbol(self, Op): - return self.Trans.ExprUtils.GetUnaryOpSymbol(Op) - - def GetComparatorSymbol(self, Op): - return self.Trans.ExprUtils.GetComparatorSymbol(Op) - - def _get_var_class(self, node, Gen): - return self.Trans.ExprUtils._get_var_class(node, Gen) - - def _try_operator_overload(self, ClassName, op_name, obj_val, Gen, other_val=None): - return self.Trans.ExprUtils._try_operator_overload(ClassName, op_name, obj_val, Gen, other_val) - - def _get_llvm_member_offset(self, field_name, ClassName, Gen): - return self.Trans.ExprAttrHandle._get_llvm_member_offset(field_name, ClassName, Gen) - - def HandleExprLlvm(self, Node, VarType=None): - Gen = self.Trans.LlvmGen - if not Gen or not Gen.builder: - return None - if isinstance(Node, ast.Constant): - return self._HandleConstantLlvm(Node, VarType) - elif isinstance(Node, ast.Name): - return self._HandleNameLlvm(Node, VarType) - elif isinstance(Node, ast.BinOp): - return self.Trans.ExprOpsHandle._HandleBinOpLlvm(Node, VarType) - elif isinstance(Node, ast.BoolOp): - return self.Trans.ExprOpsHandle._HandleBoolOpLlvm(Node) - elif isinstance(Node, ast.UnaryOp): - return self.Trans.ExprOpsHandle._HandleUnaryOpLlvm(Node) - elif isinstance(Node, ast.Call): - return self.Trans.ExprCallHandle._HandleCallLlvm(Node) - elif isinstance(Node, ast.Compare): - return self.Trans.ExprOpsHandle._HandleCompareLlvm(Node) - elif isinstance(Node, ast.Attribute): - return self.Trans.ExprAttrHandle._HandleAttributeLlvm(Node) - elif isinstance(Node, ast.Subscript): - return self.Trans.ExprAttrHandle._HandleSubscriptLlvm(Node) - elif isinstance(Node, ast.IfExp): - return self.Trans.ExprLambdaHandle._HandleIfExpLlvm(Node) - elif isinstance(Node, ast.NamedExpr): - return self.Trans.ExprLambdaHandle._HandleNamedExprLlvm(Node) - elif isinstance(Node, ast.JoinedStr): - in_str_method = getattr(Gen, 'func', None) and getattr(Gen.func, 'name', '').endswith('.__str__') - return self.Trans.ExprFormatHandle._HandleJoinedStrLlvm(Node, return_str=in_str_method) - elif isinstance(Node, ast.Lambda): - return self.Trans.ExprLambdaHandle._HandleLambdaLlvm(Node) - elif isinstance(Node, ast.List): - return self._HandleListLlvm(Node, VarType) - return ir.Constant(ir.IntType(32), 0) - - def _HandleListLlvm(self, Node, VarType=None): - Gen = self.Trans.LlvmGen - elements = Node.elts - if not elements: - return ir.Constant(ir.IntType(8).as_pointer(), None) - - array_len = len(elements) - elem_type = 'i8' - - if VarType and isinstance(VarType, str) and 'list[' in VarType: - import re - match = re.search(r'list\[([^,\]]+)(?:,\s*(\d+))?\]', VarType) - if match: - type_str = match.group(1).strip() - if match.group(2): - array_len = int(match.group(2)) - if 'CChar' in type_str or 'char' in type_str.lower(): - elem_type = 'i8' - elif 'CFloat' in type_str or type_str.lower() == 'float': - elem_type = 'float' - elif 'CDouble' in type_str or type_str.lower() == 'double': - elem_type = 'double' - elif 'CInt' in type_str or ('int' in type_str.lower() and 'unsigned' not in type_str.lower()): - elem_type = 'i32' - elif 'CUnsignedInt' in type_str or 'unsigned' in type_str.lower(): - elem_type = 'i32' - elif 'CUnsignedChar' in type_str or 'unsigned char' in type_str.lower(): - elem_type = 'i8' - elif 'CShort' in type_str or 'short' in type_str.lower(): - elem_type = 'i16' - elif 'CUnsignedShort' in type_str: - elem_type = 'i16' - elif elements and all(isinstance(e, (ast.Constant,)) and isinstance(getattr(e, 'value', None), float) for e in elements): - elem_type = 'float' - - alloc_size = array_len - if elem_type == 'i32': - alloc_size *= 4 - elif elem_type == 'i16': - alloc_size *= 2 - elif elem_type == 'float': - alloc_size *= 4 - elif elem_type == 'double': - alloc_size *= 8 - - malloc_fn = None - malloc_arg_type = ir.IntType(64) - for fn in Gen.module.global_values: - if fn.name == 'malloc': - malloc_fn = fn - func_ftype = getattr(fn, 'ftype', None) - if func_ftype and getattr(func_ftype, 'args', None): - if func_ftype.args: - malloc_arg_type = fn.ftype.args[0] - break - - if not malloc_fn: - try: - malloc_fn_type = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.IntType(64)]) - malloc_fn = ir.Function(Gen.module, malloc_fn_type, name='malloc') - Gen.functions['malloc'] = malloc_fn - except Exception: # 回退:malloc 函数创建失败时返回 null - return ir.Constant(ir.IntType(8).as_pointer(), None) - - alloc_ptr = Gen.builder.call(malloc_fn, [ir.Constant(malloc_arg_type, alloc_size)]) - cast_ptr = Gen.builder.bitcast(alloc_ptr, ir.PointerType(ir.IntType(8))) - - for i, elem in enumerate(elements): - if i >= array_len: - break - - elem_val = self.HandleExprLlvm(elem, VarType=elem_type) - if elem_val is None: - continue - - byte_offset = i - if elem_type == 'i32': - byte_offset = i * 4 - elif elem_type == 'i16': - byte_offset = i * 2 - elif elem_type == 'float': - byte_offset = i * 4 - elif elem_type == 'double': - byte_offset = i * 8 - - ptr_as_int = Gen.builder.ptrtoint(cast_ptr, ir.IntType(64)) - new_ptr_val = Gen.builder.add(ptr_as_int, ir.Constant(ir.IntType(64), byte_offset)) - if elem_type == 'i32': - elem_ptr = Gen.builder.inttoptr(new_ptr_val, ir.PointerType(ir.IntType(32))) - elif elem_type == 'i16': - elem_ptr = Gen.builder.inttoptr(new_ptr_val, ir.PointerType(ir.IntType(16))) - elif elem_type == 'float': - elem_ptr = Gen.builder.inttoptr(new_ptr_val, ir.PointerType(ir.FloatType())) - elif elem_type == 'double': - elem_ptr = Gen.builder.inttoptr(new_ptr_val, ir.PointerType(ir.DoubleType())) - else: - elem_ptr = Gen.builder.inttoptr(new_ptr_val, ir.PointerType(ir.IntType(8))) - - if elem_type == 'i8': - if isinstance(elem_val.type, ir.IntType) and elem_val.type.width > 8: - elem_val = Gen.builder.trunc(elem_val, ir.IntType(8), name=f"trunc_elem_{i}") - elif isinstance(elem_val.type, ir.PointerType): - elem_val = Gen.builder.ptrtoint(elem_val, ir.IntType(64), name=f"ptrtoint_elem_{i}") - elem_val = Gen.builder.trunc(elem_val, ir.IntType(8), name=f"trunc_elem_{i}") - elif elem_type == 'i32': - if isinstance(elem_val.type, ir.IntType): - if elem_val.type.width < 32: - elem_val = Gen.builder.zext(elem_val, ir.IntType(32), name=f"zext_elem_{i}") - elif elem_val.type.width > 32: - elem_val = Gen.builder.trunc(elem_val, ir.IntType(32), name=f"trunc_elem_{i}") - elif isinstance(elem_val.type, ir.PointerType): - elem_val = Gen.builder.ptrtoint(elem_val, ir.IntType(32), name=f"ptrtoint_elem_{i}") - elif elem_type == 'i16': - if isinstance(elem_val.type, ir.IntType): - if elem_val.type.width < 16: - elem_val = Gen.builder.zext(elem_val, ir.IntType(16), name=f"zext_elem_{i}") - elif elem_val.type.width > 16: - elem_val = Gen.builder.trunc(elem_val, ir.IntType(16), name=f"trunc_elem_{i}") - elif elem_type == 'float': - if isinstance(elem_val.type, ir.DoubleType): - elem_val = Gen.builder.fptrunc(elem_val, ir.FloatType(), name=f"fptrunc_elem_{i}") - elif isinstance(elem_val.type, ir.IntType): - elem_val = Gen.builder.sitofp(elem_val, ir.FloatType(), name=f"sitofp_elem_{i}") - elif elem_type == 'double': - if isinstance(elem_val.type, ir.FloatType): - elem_val = Gen.builder.fpext(elem_val, ir.DoubleType(), name=f"fpext_elem_{i}") - elif isinstance(elem_val.type, ir.IntType): - elem_val = Gen.builder.sitofp(elem_val, ir.DoubleType(), name=f"sitofp_elem_{i}") - - Gen.builder.store(elem_val, elem_ptr) - - if elem_type == 'float': - return Gen.builder.bitcast(alloc_ptr, ir.PointerType(ir.FloatType()), name="list_float_ptr") - elif elem_type == 'double': - return Gen.builder.bitcast(alloc_ptr, ir.PointerType(ir.DoubleType()), name="list_double_ptr") - return cast_ptr - - def _HandleConstantLlvm(self, Node, VarType=None): - Gen = self.Trans.LlvmGen - Value = Node.value - if Value is None: - if VarType is not None and isinstance(VarType, ir.PointerType): - return ir.Constant(VarType, None) - return ir.Constant(ir.IntType(8).as_pointer(), None) - elif isinstance(Value, bool): - return ir.Constant(ir.IntType(32), 1 if Value else 0) - elif isinstance(Value, int): - if VarType is not None: - if isinstance(VarType, ir.IntType): - return ir.Constant(VarType, Value & ((1 << VarType.width) - 1)) - if isinstance(VarType, ir.PointerType): - return ir.Constant(ir.IntType(64), Value) - if isinstance(VarType, (ir.FloatType, ir.DoubleType)): - return ir.Constant(VarType, float(Value)) - if isinstance(VarType, str) and '*' in VarType: - return ir.Constant(ir.IntType(64), Value) - if isinstance(VarType, str): - from lib.includes.t import CTypeRegistry as _CR - resolved = _CR.ResolveName(VarType) or _CR.CNameToClass(VarType) or _CR.LLVMToCType(VarType) - if resolved: - ctype_cls = resolved[0] if isinstance(resolved, tuple) else resolved - inst = ctype_cls() - size = getattr(inst, 'Size', 32) - is_unsigned = getattr(inst, 'IsSigned', True) is False - mask = (1 << size) - 1 - return ir.Constant(ir.IntType(size), Value & mask) - llvm_match = __import__('re').match(r'^i(\d+)$', VarType) - if llvm_match: - width = int(llvm_match.group(1)) - return ir.Constant(ir.IntType(width), Value & ((1 << width) - 1)) - if Value < 0 or Value > 0xFFFFFFFF: - return ir.Constant(ir.IntType(64), Value) - return ir.Constant(ir.IntType(32), Value & 0xFFFFFFFF) - elif isinstance(Value, float): - if VarType and isinstance(VarType, ir.FloatType): - return ir.Constant(VarType, Value) - elif VarType and isinstance(VarType, ir.DoubleType): - return ir.Constant(VarType, Value) - return ir.Constant(ir.DoubleType(), Value) - elif isinstance(Value, str): - is_wide = getattr(Node, 'kind', None) == 'u' - if len(Value) == 1 and not is_wide: - if VarType is not None and isinstance(VarType, ir.PointerType): - pass - elif isinstance(VarType, ir.IntType): - return ir.Constant(VarType, ord(Value[0])) - elif isinstance(VarType, str): - from lib.includes.t import CTypeRegistry as _CR - resolved = _CR.ResolveName(VarType) or _CR.CNameToClass(VarType) or _CR.LLVMToCType(VarType) - if resolved: - ctype_cls = resolved[0] if isinstance(resolved, tuple) else resolved - inst = ctype_cls() - size = getattr(inst, 'Size', 32) - return ir.Constant(ir.IntType(size), ord(Value[0])) - llvm_match = __import__('re').match(r'^i(\d+)$', VarType) - if llvm_match: - return ir.Constant(ir.IntType(int(llvm_match.group(1))), ord(Value[0])) - elif VarType is not None: - return ir.Constant(ir.IntType(8), ord(Value[0])) - if is_wide: - str_value = Value + '\x00' - wide_chars = [ord(c) for c in str_value] - target_count = len(wide_chars) - str_type = ir.ArrayType(ir.IntType(16), target_count) - gv_name = f"str_const_{Gen.string_const_counter}" - gv = ir.GlobalVariable(Gen.module, str_type, name=gv_name) - gv.initializer = ir.Constant(str_type, wide_chars) - gv.linkage = 'internal' - Gen.string_const_counter += 1 - ptr = Gen.builder.gep(gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{gv_name}_cast") - return ptr - else: - str_value = Value + '\x00' - str_bytes = str_value.encode('utf-8') - target_count = len(str_bytes) - if isinstance(VarType, ir.ArrayType) and isinstance(VarType.element, ir.IntType) and VarType.element.width == 8: - target_count = VarType.count - if len(str_bytes) < target_count: - str_bytes = str_bytes + b'\x00' * (target_count - len(str_bytes)) - else: - str_bytes = str_bytes[:target_count] - str_type = ir.ArrayType(ir.IntType(8), target_count) - gv_name = f"str_const_{Gen.string_const_counter}" - gv = ir.GlobalVariable(Gen.module, str_type, name=gv_name) - gv.initializer = ir.Constant(str_type, bytearray(str_bytes)) - gv.linkage = 'internal' - Gen.string_const_counter += 1 - ptr = Gen.builder.gep(gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{gv_name}_cast") - return ptr - return ir.Constant(ir.IntType(32), 0) - - def _HandleNameLlvm(self, Node, VarType=None): - Gen = self.Trans.LlvmGen - VarName = Node.id - define_constants = getattr(Gen, '_define_constants', {}) - if VarName in define_constants: - val = define_constants[VarName] - if isinstance(val, int): - # Use VarType hint if available to avoid unnecessary type mismatch - if VarType is not None and isinstance(VarType, ir.IntType): - return ir.Constant(VarType, val & ((1 << VarType.width) - 1)) - if VarName in Gen.var_signedness and Gen.var_signedness[VarName]: - if val < -(1 << 31) or val > 0xFFFFFFFF: - return ir.Constant(ir.IntType(64), val & 0xFFFFFFFFFFFFFFFF) - return ir.Constant(ir.IntType(32), val & 0xFFFFFFFF) - if val < -(1 << 31) or val > 0xFFFFFFFF: - return ir.Constant(ir.IntType(64), val) - return ir.Constant(ir.IntType(32), val & 0xFFFFFFFF) - elif isinstance(val, float): - return ir.Constant(ir.DoubleType(), val) - elif isinstance(val, str): - str_value = val + '\x00' - str_bytes = str_value.encode('utf-8') - str_type = ir.ArrayType(ir.IntType(8), len(str_bytes)) - gv_name = f"str_const_{Gen.string_const_counter}" - gv = ir.GlobalVariable(Gen.module, str_type, name=gv_name) - gv.initializer = ir.Constant(str_type, bytearray(str_bytes)) - gv.linkage = 'internal' - Gen.string_const_counter += 1 - ptr = Gen.builder.gep(gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{gv_name}_cast") - return ptr - # 如果 _define_constants 中没有,尝试从符号表查找 - if VarName not in getattr(Gen, '_define_constants', {}): - try: - sym_info = self.translator.SymbolTable.get(VarName) - if sym_info and getattr(sym_info, 'IsDefine', None) and getattr(sym_info, 'DefineValue', None) is not None: - val = sym_info.DefineValue - if isinstance(val, int): - # Use VarType hint if available - if VarType is not None and isinstance(VarType, ir.IntType): - return ir.Constant(VarType, val & ((1 << VarType.width) - 1)) - if val < -(1 << 31) or val > 0xFFFFFFFF: - return ir.Constant(ir.IntType(64), val) - return ir.Constant(ir.IntType(32), val & 0xFFFFFFFF) - elif isinstance(val, float): - return ir.Constant(ir.DoubleType(), val) - elif isinstance(val, str): - str_value = val + '\x00' - str_bytes = str_value.encode('utf-8') - str_type = ir.ArrayType(ir.IntType(8), len(str_bytes)) - gv_name = f"str_const_{Gen.string_const_counter}" - gv = ir.GlobalVariable(Gen.module, str_type, name=gv_name) - gv.initializer = ir.Constant(str_type, bytearray(str_bytes)) - gv.linkage = 'internal' - Gen.string_const_counter += 1 - ptr = Gen.builder.gep(gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{gv_name}_cast") - return ptr - except Exception as _e: - if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": - self.Trans.LogWarning(f"异常被忽略: {_e}") - # 优先检查 variables(alloca),因为变量可能已被 += 等操作迁移到 variables - if VarName in Gen.variables and Gen.variables[VarName] is not None: - VarPtr = Gen.variables[VarName] - if isinstance(VarPtr, ir.GlobalVariable) and isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): - if VarName in Gen.global_struct_class: - Gen.var_struct_class[VarName] = Gen.global_struct_class[VarName] - return VarPtr - if isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): - if VarName in Gen.global_struct_class: - Gen.var_struct_class[VarName] = Gen.global_struct_class[VarName] - return VarPtr - return Gen._load(VarPtr, name=VarName) - if VarName in Gen._reg_values: - return Gen._reg_values[VarName] - if VarName in Gen._direct_values: - return Gen._direct_values[VarName] - if VarName in Gen.global_vars and VarName in Gen.module.globals: - GVar = Gen.module.globals[VarName] - Gen.variables[VarName] = GVar - if isinstance(GVar, ir.Function): - return GVar - if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): - return GVar - return Gen._load(GVar, name=VarName) - if VarName in Gen.module.globals: - GVar = Gen.module.globals[VarName] - Gen.variables[VarName] = GVar - if isinstance(GVar, ir.Function): - return GVar - if VarName in Gen.global_struct_class: - Gen.var_struct_class[VarName] = Gen.global_struct_class[VarName] - if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): - return GVar - return Gen._load(GVar, name=VarName) - if VarName == 'self': - return Gen._get_var_ptr('self') - if Gen._has_function(VarName): - func = Gen._get_function(VarName) - if func: - return Gen.builder.bitcast(func, ir.IntType(8).as_pointer(), name=f"funcptr_{VarName}") - if VarName in Gen.class_methods: - return ir.Constant(ir.IntType(8).as_pointer(), None) - if VarName == 'True' or VarName == 'False': - return ir.Constant(ir.IntType(32), 1 if VarName == 'True' else 0) - if VarName in self.Trans.SymbolTable: - SymInfo = self.Trans.SymbolTable[VarName] - if getattr(SymInfo, 'IsEnumMember', None) and isinstance(getattr(SymInfo, 'value', None), int): - return ir.Constant(ir.IntType(32), SymInfo.value) - if getattr(SymInfo, 'IsFunction', False) or getattr(SymInfo, 'IsFuncPtr', False): - MangledName = Gen._mangle_func_name(VarName) - if MangledName in Gen.module.globals: - g = Gen.module.globals[MangledName] - if isinstance(g, ir.Function): - Gen.functions[VarName] = g - return Gen.builder.bitcast(g, ir.IntType(8).as_pointer(), name=f"funcptr_{VarName}") - for sha1 in Gen.module_sha1_map.values(): - prefixed = f"{sha1}.{VarName}" - if prefixed in Gen.module.globals: - g = Gen.module.globals[prefixed] - if isinstance(g, ir.Function): - Gen.functions[VarName] = g - return Gen.builder.bitcast(g, ir.IntType(8).as_pointer(), name=f"funcptr_{VarName}") - t_c_imported = getattr(self.Trans, '_t_c_imported_names', {}) - if VarName in t_c_imported: - src_module, src_name = t_c_imported[VarName] - virtual_attr = ast.Attribute( - value=ast.Name(id=src_module, ctx=ast.Load()), - attr=src_name, - ctx=ast.Load() - ) - ast.copy_location(virtual_attr, Node) - return self.Trans.ExprAttrHandle._HandleAttributeLlvm(virtual_attr) - return ir.Constant(ir.IntType(32), 0) +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle +import ast +import llvmlite.ir as ir + + +class ExprHandle(BaseHandle): + def __init__(self, translator: "Translator"): + super().__init__(translator) + + def GetOpSymbol(self, Op): + return self.Trans.ExprUtils.GetOpSymbol(Op) + + def GetUnaryOpSymbol(self, Op): + return self.Trans.ExprUtils.GetUnaryOpSymbol(Op) + + def GetComparatorSymbol(self, Op): + return self.Trans.ExprUtils.GetComparatorSymbol(Op) + + def _get_var_class(self, node, Gen): + return self.Trans.ExprUtils._get_var_class(node, Gen) + + def _try_operator_overLoad(self, ClassName, op_name, obj_val, Gen, other_val=None): + return self.Trans.ExprUtils._try_operator_overLoad(ClassName, op_name, obj_val, Gen, other_val) + + def _get_llvm_member_offset(self, field_name, ClassName, Gen): + return self.Trans.ExprAttrHandle._get_llvm_member_offset(field_name, ClassName, Gen) + + def HandleExprLlvm(self, Node, VarType=None): + Gen = self.Trans.LlvmGen + if not Gen or not Gen.builder: + return None + if isinstance(Node, ast.Constant): + return self._HandleConstantLlvm(Node, VarType) + elif isinstance(Node, ast.Name): + return self._HandleNameLlvm(Node, VarType) + elif isinstance(Node, ast.BinOp): + return self.Trans.ExprOpsHandle._HandleBinOpLlvm(Node, VarType) + elif isinstance(Node, ast.BoolOp): + return self.Trans.ExprOpsHandle._HandleBoolOpLlvm(Node) + elif isinstance(Node, ast.UnaryOp): + return self.Trans.ExprOpsHandle._HandleUnaryOpLlvm(Node) + elif isinstance(Node, ast.Call): + return self.Trans.ExprCallHandle._HandleCallLlvm(Node) + elif isinstance(Node, ast.Compare): + return self.Trans.ExprOpsHandle._HandleCompareLlvm(Node) + elif isinstance(Node, ast.Attribute): + return self.Trans.ExprAttrHandle._HandleAttributeLlvm(Node) + elif isinstance(Node, ast.Subscript): + return self.Trans.ExprAttrHandle._HandleSubscriptLlvm(Node) + elif isinstance(Node, ast.IfExp): + return self.Trans.ExprLambdaHandle._HandleIfExpLlvm(Node) + elif isinstance(Node, ast.NamedExpr): + return self.Trans.ExprLambdaHandle._HandleNamedExprLlvm(Node) + elif isinstance(Node, ast.JoinedStr): + in_str_method = getattr(Gen, 'func', None) and getattr(Gen.func, 'name', '').endswith('.__str__') + return self.Trans.ExprFormatHandle._HandleJoinedStrLlvm(Node, return_str=in_str_method) + elif isinstance(Node, ast.Lambda): + return self.Trans.ExprLambdaHandle._HandleLambdaLlvm(Node) + elif isinstance(Node, ast.List): + return self._HandleListLlvm(Node, VarType) + return ir.Constant(ir.IntType(32), 0) + + def _HandleListLlvm(self, Node, VarType=None): + Gen = self.Trans.LlvmGen + elements = Node.elts + if not elements: + return ir.Constant(ir.IntType(8).as_pointer(), None) + + array_len = len(elements) + elem_type = 'i8' + + if VarType and isinstance(VarType, str) and 'list[' in VarType: + import re + match = re.search(r'list\[([^,\]]+)(?:,\s*(\d+))?\]', VarType) + if match: + type_str = match.group(1).strip() + if match.group(2): + array_len = int(match.group(2)) + if 'CChar' in type_str or 'char' in type_str.lower(): + elem_type = 'i8' + elif 'CFloat' in type_str or type_str.lower() == 'float': + elem_type = 'float' + elif 'CDouble' in type_str or type_str.lower() == 'double': + elem_type = 'double' + elif 'CInt' in type_str or ('int' in type_str.lower() and 'unsigned' not in type_str.lower()): + elem_type = 'i32' + elif 'CUnsignedInt' in type_str or 'unsigned' in type_str.lower(): + elem_type = 'i32' + elif 'CUnsignedChar' in type_str or 'unsigned char' in type_str.lower(): + elem_type = 'i8' + elif 'CShort' in type_str or 'short' in type_str.lower(): + elem_type = 'i16' + elif 'CUnsignedShort' in type_str: + elem_type = 'i16' + elif elements and all(isinstance(e, (ast.Constant,)) and isinstance(getattr(e, 'value', None), float) for e in elements): + elem_type = 'float' + + alloc_size = array_len + if elem_type == 'i32': + alloc_size *= 4 + elif elem_type == 'i16': + alloc_size *= 2 + elif elem_type == 'float': + alloc_size *= 4 + elif elem_type == 'double': + alloc_size *= 8 + + malloc_fn = None + malloc_arg_type = ir.IntType(64) + for fn in Gen.module.global_values: + if fn.name == 'malloc': + malloc_fn = fn + func_ftype = getattr(fn, 'ftype', None) + if func_ftype and getattr(func_ftype, 'args', None): + if func_ftype.args: + malloc_arg_type = fn.ftype.args[0] + break + + if not malloc_fn: + try: + malloc_fn_type = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.IntType(64)]) + malloc_fn = ir.Function(Gen.module, malloc_fn_type, name='malloc') + Gen.functions['malloc'] = malloc_fn + except Exception: # 回退:malloc 函数创建失败时返回 null + return ir.Constant(ir.IntType(8).as_pointer(), None) + + alloc_ptr = Gen.builder.call(malloc_fn, [ir.Constant(malloc_arg_type, alloc_size)]) + cast_ptr = Gen.builder.bitcast(alloc_ptr, ir.PointerType(ir.IntType(8))) + + for i, elem in enumerate(elements): + if i >= array_len: + break + + elem_val = self.HandleExprLlvm(elem, VarType=elem_type) + if elem_val is None: + continue + + byte_offset = i + if elem_type == 'i32': + byte_offset = i * 4 + elif elem_type == 'i16': + byte_offset = i * 2 + elif elem_type == 'float': + byte_offset = i * 4 + elif elem_type == 'double': + byte_offset = i * 8 + + ptr_as_int = Gen.builder.ptrtoint(cast_ptr, ir.IntType(64)) + new_ptr_val = Gen.builder.add(ptr_as_int, ir.Constant(ir.IntType(64), byte_offset)) + if elem_type == 'i32': + elem_ptr = Gen.builder.inttoptr(new_ptr_val, ir.PointerType(ir.IntType(32))) + elif elem_type == 'i16': + elem_ptr = Gen.builder.inttoptr(new_ptr_val, ir.PointerType(ir.IntType(16))) + elif elem_type == 'float': + elem_ptr = Gen.builder.inttoptr(new_ptr_val, ir.PointerType(ir.FloatType())) + elif elem_type == 'double': + elem_ptr = Gen.builder.inttoptr(new_ptr_val, ir.PointerType(ir.DoubleType())) + else: + elem_ptr = Gen.builder.inttoptr(new_ptr_val, ir.PointerType(ir.IntType(8))) + + if elem_type == 'i8': + if isinstance(elem_val.type, ir.IntType) and elem_val.type.width > 8: + elem_val = Gen.builder.trunc(elem_val, ir.IntType(8), name=f"trunc_elem_{i}") + elif isinstance(elem_val.type, ir.PointerType): + elem_val = Gen.builder.ptrtoint(elem_val, ir.IntType(64), name=f"ptrtoint_elem_{i}") + elem_val = Gen.builder.trunc(elem_val, ir.IntType(8), name=f"trunc_elem_{i}") + elif elem_type == 'i32': + if isinstance(elem_val.type, ir.IntType): + if elem_val.type.width < 32: + elem_val = Gen.builder.zext(elem_val, ir.IntType(32), name=f"zext_elem_{i}") + elif elem_val.type.width > 32: + elem_val = Gen.builder.trunc(elem_val, ir.IntType(32), name=f"trunc_elem_{i}") + elif isinstance(elem_val.type, ir.PointerType): + elem_val = Gen.builder.ptrtoint(elem_val, ir.IntType(32), name=f"ptrtoint_elem_{i}") + elif elem_type == 'i16': + if isinstance(elem_val.type, ir.IntType): + if elem_val.type.width < 16: + elem_val = Gen.builder.zext(elem_val, ir.IntType(16), name=f"zext_elem_{i}") + elif elem_val.type.width > 16: + elem_val = Gen.builder.trunc(elem_val, ir.IntType(16), name=f"trunc_elem_{i}") + elif elem_type == 'float': + if isinstance(elem_val.type, ir.DoubleType): + elem_val = Gen.builder.fptrunc(elem_val, ir.FloatType(), name=f"fptrunc_elem_{i}") + elif isinstance(elem_val.type, ir.IntType): + elem_val = Gen.builder.sitofp(elem_val, ir.FloatType(), name=f"sitofp_elem_{i}") + elif elem_type == 'double': + if isinstance(elem_val.type, ir.FloatType): + elem_val = Gen.builder.fpext(elem_val, ir.DoubleType(), name=f"fpext_elem_{i}") + elif isinstance(elem_val.type, ir.IntType): + elem_val = Gen.builder.sitofp(elem_val, ir.DoubleType(), name=f"sitofp_elem_{i}") + + Gen.builder.store(elem_val, elem_ptr) + + if elem_type == 'float': + return Gen.builder.bitcast(alloc_ptr, ir.PointerType(ir.FloatType()), name="list_float_ptr") + elif elem_type == 'double': + return Gen.builder.bitcast(alloc_ptr, ir.PointerType(ir.DoubleType()), name="list_double_ptr") + return cast_ptr + + def _HandleConstantLlvm(self, Node, VarType=None): + Gen = self.Trans.LlvmGen + Value = Node.value + if Value is None: + if VarType is not None and isinstance(VarType, ir.PointerType): + return ir.Constant(VarType, None) + return ir.Constant(ir.IntType(8).as_pointer(), None) + elif isinstance(Value, bool): + return ir.Constant(ir.IntType(32), 1 if Value else 0) + elif isinstance(Value, int): + if VarType is not None: + if isinstance(VarType, ir.IntType): + return ir.Constant(VarType, Value & ((1 << VarType.width) - 1)) + if isinstance(VarType, ir.PointerType): + return ir.Constant(ir.IntType(64), Value) + if isinstance(VarType, (ir.FloatType, ir.DoubleType)): + return ir.Constant(VarType, float(Value)) + if isinstance(VarType, str) and '*' in VarType: + return ir.Constant(ir.IntType(64), Value) + if isinstance(VarType, str): + from lib.includes.t import CTypeRegistry as _CR + resolved = _CR.ResolveName(VarType) or _CR.CNameToClass(VarType) or _CR.LLVMToCType(VarType) + if resolved: + ctype_cls = resolved[0] if isinstance(resolved, tuple) else resolved + inst = ctype_cls() + size = getattr(inst, 'Size', 32) + is_unsigned = getattr(inst, 'IsSigned', True) is False + mask = (1 << size) - 1 + return ir.Constant(ir.IntType(size), Value & mask) + llvm_match = __import__('re').match(r'^i(\d+)$', VarType) + if llvm_match: + width = int(llvm_match.group(1)) + return ir.Constant(ir.IntType(width), Value & ((1 << width) - 1)) + if Value < 0 or Value > 0xFFFFFFFF: + return ir.Constant(ir.IntType(64), Value) + return ir.Constant(ir.IntType(32), Value & 0xFFFFFFFF) + elif isinstance(Value, float): + if VarType and isinstance(VarType, ir.FloatType): + return ir.Constant(VarType, Value) + elif VarType and isinstance(VarType, ir.DoubleType): + return ir.Constant(VarType, Value) + return ir.Constant(ir.DoubleType(), Value) + elif isinstance(Value, str): + is_wide = getattr(Node, 'kind', None) == 'u' + if len(Value) == 1 and not is_wide: + if VarType is not None and isinstance(VarType, ir.PointerType): + pass + elif isinstance(VarType, ir.IntType): + return ir.Constant(VarType, ord(Value[0])) + elif isinstance(VarType, str): + from lib.includes.t import CTypeRegistry as _CR + resolved = _CR.ResolveName(VarType) or _CR.CNameToClass(VarType) or _CR.LLVMToCType(VarType) + if resolved: + ctype_cls = resolved[0] if isinstance(resolved, tuple) else resolved + inst = ctype_cls() + size = getattr(inst, 'Size', 32) + return ir.Constant(ir.IntType(size), ord(Value[0])) + llvm_match = __import__('re').match(r'^i(\d+)$', VarType) + if llvm_match: + return ir.Constant(ir.IntType(int(llvm_match.group(1))), ord(Value[0])) + elif VarType is not None: + return ir.Constant(ir.IntType(8), ord(Value[0])) + if is_wide: + str_value = Value + '\x00' + wide_chars = [ord(c) for c in str_value] + target_count = len(wide_chars) + str_type = ir.ArrayType(ir.IntType(16), target_count) + gv_name = f"str_const_{Gen.string_const_counter}" + gv = ir.GlobalVariable(Gen.module, str_type, name=gv_name) + gv.initializer = ir.Constant(str_type, wide_chars) + gv.linkage = 'internal' + Gen.string_const_counter += 1 + ptr = Gen.builder.gep(gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{gv_name}_cast") + return ptr + else: + str_value = Value + '\x00' + str_bytes = str_value.encode('utf-8') + target_count = len(str_bytes) + if isinstance(VarType, ir.ArrayType) and isinstance(VarType.element, ir.IntType) and VarType.element.width == 8: + target_count = VarType.count + if len(str_bytes) < target_count: + str_bytes = str_bytes + b'\x00' * (target_count - len(str_bytes)) + else: + str_bytes = str_bytes[:target_count] + str_type = ir.ArrayType(ir.IntType(8), target_count) + gv_name = f"str_const_{Gen.string_const_counter}" + gv = ir.GlobalVariable(Gen.module, str_type, name=gv_name) + gv.initializer = ir.Constant(str_type, bytearray(str_bytes)) + gv.linkage = 'internal' + Gen.string_const_counter += 1 + ptr = Gen.builder.gep(gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{gv_name}_cast") + return ptr + return ir.Constant(ir.IntType(32), 0) + + def _HandleNameLlvm(self, Node, VarType=None): + Gen = self.Trans.LlvmGen + VarName = Node.id + define_constants = getattr(Gen, '_define_constants', {}) + if VarName in define_constants: + val = define_constants[VarName] + if isinstance(val, int): + # Use VarType hint if available to avoid unnecessary type mismatch + if VarType is not None and isinstance(VarType, ir.IntType): + return ir.Constant(VarType, val & ((1 << VarType.width) - 1)) + if VarName in Gen.var_signedness and Gen.var_signedness[VarName]: + if val < -(1 << 31) or val > 0xFFFFFFFF: + return ir.Constant(ir.IntType(64), val & 0xFFFFFFFFFFFFFFFF) + return ir.Constant(ir.IntType(32), val & 0xFFFFFFFF) + if val < -(1 << 31) or val > 0xFFFFFFFF: + return ir.Constant(ir.IntType(64), val) + return ir.Constant(ir.IntType(32), val & 0xFFFFFFFF) + elif isinstance(val, float): + return ir.Constant(ir.DoubleType(), val) + elif isinstance(val, str): + str_value = val + '\x00' + str_bytes = str_value.encode('utf-8') + str_type = ir.ArrayType(ir.IntType(8), len(str_bytes)) + gv_name = f"str_const_{Gen.string_const_counter}" + gv = ir.GlobalVariable(Gen.module, str_type, name=gv_name) + gv.initializer = ir.Constant(str_type, bytearray(str_bytes)) + gv.linkage = 'internal' + Gen.string_const_counter += 1 + ptr = Gen.builder.gep(gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{gv_name}_cast") + return ptr + # 如果 _define_constants 中没有,尝试从符号表查找 + if VarName not in getattr(Gen, '_define_constants', {}): + try: + sym_info = self.translator.SymbolTable.get(VarName) + if sym_info and getattr(sym_info, 'IsDefine', None) and getattr(sym_info, 'DefineValue', None) is not None: + val = sym_info.DefineValue + if isinstance(val, int): + # Use VarType hint if available + if VarType is not None and isinstance(VarType, ir.IntType): + return ir.Constant(VarType, val & ((1 << VarType.width) - 1)) + if val < -(1 << 31) or val > 0xFFFFFFFF: + return ir.Constant(ir.IntType(64), val) + return ir.Constant(ir.IntType(32), val & 0xFFFFFFFF) + elif isinstance(val, float): + return ir.Constant(ir.DoubleType(), val) + elif isinstance(val, str): + str_value = val + '\x00' + str_bytes = str_value.encode('utf-8') + str_type = ir.ArrayType(ir.IntType(8), len(str_bytes)) + gv_name = f"str_const_{Gen.string_const_counter}" + gv = ir.GlobalVariable(Gen.module, str_type, name=gv_name) + gv.initializer = ir.Constant(str_type, bytearray(str_bytes)) + gv.linkage = 'internal' + Gen.string_const_counter += 1 + ptr = Gen.builder.gep(gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{gv_name}_cast") + return ptr + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + self.Trans.LogWarning(f"异常被忽略: {_e}") + # 优先检查 variables(alloca),因为变量可能已被 += 等操作迁移到 variables + if VarName in Gen.variables and Gen.variables[VarName] is not None: + VarPtr = Gen.variables[VarName] + if isinstance(VarPtr, ir.GlobalVariable) and isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): + if VarName in Gen.global_struct_class: + Gen.var_struct_class[VarName] = Gen.global_struct_class[VarName] + return VarPtr + if isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): + if VarName in Gen.global_struct_class: + Gen.var_struct_class[VarName] = Gen.global_struct_class[VarName] + return VarPtr + return Gen._load(VarPtr, name=VarName) + if VarName in Gen._reg_values: + return Gen._reg_values[VarName] + if VarName in Gen._direct_values: + return Gen._direct_values[VarName] + if VarName in Gen.global_vars and VarName in Gen.module.globals: + GVar = Gen.module.globals[VarName] + Gen.variables[VarName] = GVar + if isinstance(GVar, ir.Function): + return GVar + if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): + return GVar + return Gen._load(GVar, name=VarName) + if VarName in Gen.module.globals: + GVar = Gen.module.globals[VarName] + Gen.variables[VarName] = GVar + if isinstance(GVar, ir.Function): + return GVar + if VarName in Gen.global_struct_class: + Gen.var_struct_class[VarName] = Gen.global_struct_class[VarName] + if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): + return GVar + return Gen._load(GVar, name=VarName) + if VarName == 'self': + return Gen.GetVarPtr('self') + if Gen._has_function(VarName): + func = Gen._get_function(VarName) + if func: + return Gen.builder.bitcast(func, ir.IntType(8).as_pointer(), name=f"funcptr_{VarName}") + if VarName in Gen.class_methods: + return ir.Constant(ir.IntType(8).as_pointer(), None) + if VarName == 'True' or VarName == 'False': + return ir.Constant(ir.IntType(32), 1 if VarName == 'True' else 0) + if VarName in self.Trans.SymbolTable: + SymInfo = self.Trans.SymbolTable[VarName] + if getattr(SymInfo, 'IsEnumMember', None) and isinstance(getattr(SymInfo, 'value', None), int): + return ir.Constant(ir.IntType(32), SymInfo.value) + if getattr(SymInfo, 'IsFunction', False) or getattr(SymInfo, 'IsFuncPtr', False): + MangledName = Gen._mangle_func_name(VarName) + if MangledName in Gen.module.globals: + g = Gen.module.globals[MangledName] + if isinstance(g, ir.Function): + Gen.functions[VarName] = g + return Gen.builder.bitcast(g, ir.IntType(8).as_pointer(), name=f"funcptr_{VarName}") + for sha1 in Gen.ModuleSha1Map.values(): + prefixed = f"{sha1}.{VarName}" + if prefixed in Gen.module.globals: + g = Gen.module.globals[prefixed] + if isinstance(g, ir.Function): + Gen.functions[VarName] = g + return Gen.builder.bitcast(g, ir.IntType(8).as_pointer(), name=f"funcptr_{VarName}") + t_c_imported = getattr(self.Trans, '_t_c_imported_names', {}) + if VarName in t_c_imported: + src_module, src_name = t_c_imported[VarName] + virtual_attr = ast.Attribute( + value=ast.Name(id=src_module, ctx=ast.Load()), + attr=src_name, + ctx=ast.Load() + ) + ast.copy_location(virtual_attr, Node) + return self.Trans.ExprAttrHandle._HandleAttributeLlvm(virtual_attr) + return ir.Constant(ir.IntType(32), 0) diff --git a/lib/core/Handles/HandlesExprAsm.py b/lib/core/Handles/HandlesExprAsm.py index 004babf..886933b 100644 --- a/lib/core/Handles/HandlesExprAsm.py +++ b/lib/core/Handles/HandlesExprAsm.py @@ -1,578 +1,578 @@ -from __future__ import annotations -from typing import TYPE_CHECKING -if TYPE_CHECKING: - from lib.core.translator import Translator -from lib.core.Handles.HandlesBase import BaseHandle -import ast -import llvmlite.ir as ir -import t - -# 猴子补丁 llvmlite.ir.InlineAsm 以支持 asm_dialect 参数 -# 添加保护避免重复补丁 -_InlineAsmPatched = getattr(ir.InlineAsm, '_transpyc_patched', False) - -if not _InlineAsmPatched: - _OrigInlineAsmInit = ir.InlineAsm.__init__ - _OrigInlineAsmDescr = ir.InlineAsm.descr - - def _patched_inline_asm_init(self, ftype, asm, constraint, side_effect=False, asm_dialect=None): - _OrigInlineAsmInit(self, ftype, asm, constraint, side_effect) - self.asm_dialect = asm_dialect - - def _patched_inline_asm_descr(self, buf): - sideeffect = 'sideeffect' if self.side_effect else '' - dialect_str = getattr(self, 'asm_dialect', None) - if dialect_str == 'intel': - dialect = 'inteldialect' - else: - dialect = '' - fmt = 'asm {sideeffect} {dialect} "{asm}", "{constraint}"' - buf.append(fmt.format(sideeffect=sideeffect, dialect=dialect, asm=self.asm, - constraint=self.constraint)) - - ir.InlineAsm.__init__ = _patched_inline_asm_init - ir.InlineAsm.descr = _patched_inline_asm_descr - ir.InlineAsm._transpyc_patched = True - - -class ExprAsmHandle(BaseHandle): - @staticmethod - def _format_to_dialect(asm_format): - """将用户指定的 format 参数转换为 LLVM asm_dialect 值""" - fmt = asm_format.lower() if asm_format else 'intel' - if fmt == 'att': - return 'att' - elif fmt == 'arm': - return None # ARM 没有专门的 dialect 标记 - else: - return 'intel' # 默认 Intel - - def _HandleAsmLlvm(self, Node): - Gen = self.Trans.LlvmGen - - op_arg = None - input_arg = None - output_arg = None - asm_format = 'Intel' # 汇编格式: Intel / AT&T / ARM - for kw in Node.keywords: - if kw.arg == 'op': - op_arg = kw.value - elif kw.arg in ('input', 'inp', 'inputs'): - input_arg = kw.value - elif kw.arg in ('output', 'out', 'outputs'): - output_arg = kw.value - elif kw.arg == 'format': - if isinstance(kw.value, ast.Constant) and isinstance(kw.value.value, str): - asm_format = kw.value.value - - if len(Node.args) >= 1: - pos_op = None - if len(Node.args) >= 2 and op_arg is None: - pos_op = Node.args[1] - return self._HandleAsmWithOpLlvm(Node.args[0], op_arg or pos_op, input_arg, output_arg, asm_format) - - if len(Node.args) < 2: - return ir.Constant(ir.IntType(32), 1) - - args = Node.args - - if len(args) == 4: - output_type_arg = args[0] - asm_template_arg = args[1] - constraint_arg = args[2] - clobber_arg = args[3] - - output_type = self._infer_expr_llvm_type(output_type_arg) - if not output_type: - output_type = ir.IntType(32) - - asm_template = '' - if isinstance(asm_template_arg, ast.Constant) and isinstance(asm_template_arg.value, str): - asm_template = self._prepare_intel_asm(self._mangle_asm_calls(asm_template_arg.value)) - - constraint = '' - if isinstance(constraint_arg, ast.Constant) and isinstance(constraint_arg.value, str): - constraint = constraint_arg.value - - clobber = '' - if isinstance(clobber_arg, ast.Constant) and isinstance(clobber_arg.value, str): - clobber = clobber_arg.value - - full_constraint = constraint - func_type = ir.FunctionType(output_type, []) - asm_dialect = self._format_to_dialect(asm_format) - inline_asm = ir.InlineAsm(func_type, asm_template, constraint, side_effect=True, asm_dialect=asm_dialect) - result = Gen.builder.call(inline_asm, [], name="asm_result") - return result - - elif len(args) >= 2: - output_type_arg = args[0] - asm_template_arg = args[1] - - output_type = self._infer_expr_llvm_type(output_type_arg) - if not output_type: - output_type = ir.IntType(32) - - asm_template = '' - if isinstance(asm_template_arg, ast.Constant) and isinstance(asm_template_arg.value, str): - asm_template = self._prepare_intel_asm(self._mangle_asm_calls(asm_template_arg.value)) - - output_constraints = [] - output_values = [] - if len(args) > 2 and isinstance(args[2], (ast.List, ast.Tuple)): - for item in args[2].elts: - if isinstance(item, (ast.List, ast.Tuple)) and len(item.elts) >= 2: - constraint_node = item.elts[0] - value_node = item.elts[1] - if isinstance(constraint_node, ast.Constant) and isinstance(constraint_node.value, str): - output_constraints.append(constraint_node.value) - value = self.HandleExprLlvm(value_node) - if value: - output_values.append(value) - - input_constraints = [] - input_values = [] - if len(args) > 3 and isinstance(args[3], (ast.List, ast.Tuple)): - for item in args[3].elts: - if isinstance(item, (ast.List, ast.Tuple)) and len(item.elts) >= 2: - constraint_node = item.elts[0] - value_node = item.elts[1] - if isinstance(constraint_node, ast.Constant) and isinstance(constraint_node.value, str): - input_constraints.append(constraint_node.value) - value = self.HandleExprLlvm(value_node) - if value: - input_values.append(value) - - clobbers = [] - if len(args) > 4 and isinstance(args[4], (ast.List, ast.Tuple)): - for item in args[4].elts: - if isinstance(item, ast.Constant) and isinstance(item.value, str): - clobbers.append(item.value) - - constraint_parts = [] - for oc in output_constraints: - constraint_parts.append(oc) - - input_start_idx = len(output_constraints) - for ic in input_constraints: - constraint_parts.append(ic) - - full_constraint = ",".join(constraint_parts) - - if clobbers: - if full_constraint: - full_constraint += "," - for c in clobbers: - full_constraint += f"~{{{c}}}" - - operands = output_values + input_values - param_types = [v.type for v in operands] - func_type = ir.FunctionType(output_type, param_types) - asm_dialect = self._format_to_dialect(asm_format) - inline_asm = ir.InlineAsm(func_type, asm_template, full_constraint, side_effect=False, asm_dialect=asm_dialect) - result = Gen.builder.call(inline_asm, operands, name="asm_result") - return result - - return None - - def _prepare_intel_asm(self, template: str) -> str: - import re - template = re.sub(r'%(\d+)', r'$\1', template) - template = re.sub(r'%([a-zA-Z][a-zA-Z0-9]*)', r'\1', template) - return template - - def _normalize_asm_template(self, template: str) -> str: - lines = template.split('\n') - if len(lines) <= 1: - return template - first_line = lines[0] - rest_lines = lines[1:] - stripped = [] - for line in rest_lines: - s = line.lstrip() - if s: - stripped.append(s) - else: - stripped.append('') - return '\n'.join([first_line] + stripped) - - def _process_joined_str_template(self, node, out_input_ops, out_input_constraints, - out_output_ops, out_output_constraints): - if not isinstance(node, ast.JoinedStr): - if isinstance(node, ast.Constant) and isinstance(node.value, str): - return node.value - return '' - - raw_parts = [] - for value in node.values: - if isinstance(value, ast.Constant) and isinstance(value.value, str): - raw_parts.append(('text', value.value)) - elif isinstance(value, ast.FormattedValue): - expr = value.value - if isinstance(expr, ast.Call) and isinstance(expr.func, ast.Attribute): - if isinstance(expr.func.value, ast.Name) and expr.func.value.id == 'c': - if expr.func.attr == 'AsmInp': - if expr.args: - v = self.HandleExprLlvm(expr.args[0]) - if v: - c = 'r' - if len(expr.args) >= 2: - c = self._parse_asm_descr(expr.args[1]) - if not c: - c = 'r' - out_input_ops.append(v) - out_input_constraints.append(c) - raw_parts.append(('input', len(out_input_ops) - 1)) - elif expr.func.attr == 'AsmOut': - if expr.args: - target_ptr = self._get_var_ptr_for_asm(expr.args[0]) - if target_ptr: - v = target_ptr - else: - v = self.HandleExprLlvm(expr.args[0]) - if v: - c = '=r' - if len(expr.args) >= 2: - c = self._parse_asm_descr(expr.args[1]) - if not c: - c = '=r' - if not c.startswith('='): - c = '=' + c - out_output_ops.append(v) - out_output_constraints.append(c) - raw_parts.append(('output', len(out_output_ops) - 1)) - else: - fallback = self.HandleExprLlvm(expr) - if fallback and isinstance(fallback.type, ir.IntType): - out_input_ops.append(fallback) - out_input_constraints.append('r') - raw_parts.append(('input', len(out_input_ops) - 1)) - else: - raw_parts.append(('text', '')) - - num_outputs = len(out_output_ops) - parts = [] - for kind, data in raw_parts: - if kind == 'text': - parts.append(data) - elif kind == 'output': - parts.append(f'%{data}') - elif kind == 'input': - parts.append(f'%{num_outputs + data}') - return ''.join(parts) - - _X86_REGISTERS = frozenset({ - 'rax', 'rbx', 'rcx', 'rdx', 'rsi', 'rdi', 'rbp', 'rsp', - 'r8', 'r9', 'r10', 'r11', 'r12', 'r13', 'r14', 'r15', - 'eax', 'ebx', 'ecx', 'edx', 'esi', 'edi', 'ebp', 'esp', - 'ax', 'bx', 'cx', 'dx', 'si', 'di', 'bp', 'sp', - 'al', 'bl', 'cl', 'dl', 'ah', 'bh', 'ch', 'dh', - 'sil', 'dil', 'bpl', 'spl', - 'r8d', 'r9d', 'r10d', 'r11d', 'r12d', 'r13d', 'r14d', 'r15d', - 'r8w', 'r9w', 'r10w', 'r11w', 'r12w', 'r13w', 'r14w', 'r15w', - 'r8b', 'r9b', 'r10b', 'r11b', 'r12b', 'r13b', 'r14b', 'r15b', - }) - - def _mangle_asm_calls(self, template: str) -> str: - import re - Gen = self.Trans.LlvmGen - sha1 = getattr(Gen, 'module_sha1', '') - if not sha1: - return template - - def replace_call(m): - prefix = m.group(1) - func_name = m.group(2) - if func_name.lower() in self._X86_REGISTERS: - return m.group(0) - mangled = Gen._mangle_func_name(func_name) - if '.' in mangled: - return f'{prefix}\\22{mangled}\\22' - return f"{prefix}{mangled}" - - return re.sub(r'(call\s+)(\w+)', replace_call, template) - - def _HandleAsmWithOpLlvm(self, asm_template_arg, op_arg, input_arg=None, output_arg=None, asm_format='Intel'): - Gen = self.Trans.LlvmGen - - input_ops = [] - input_constraints = [] - output_ops = [] - output_constraints = [] - - if output_arg and isinstance(output_arg, (ast.List, ast.Tuple)): - for item in output_arg.elts: - if isinstance(item, ast.Call) and isinstance(item.func, ast.Attribute): - if item.func.value.id == 'c' and item.func.attr == 'AsmOut': - if len(item.args) >= 1: - target_ptr = self._get_var_ptr_for_asm(item.args[0]) - if target_ptr: - output_ops.append(target_ptr) - else: - value = self.HandleExprLlvm(item.args[0]) - if value: - output_ops.append(value) - constraint = '=r' - if len(item.args) >= 2: - base_constraint = self._parse_asm_descr(item.args[1]) - if base_constraint: - if base_constraint.startswith('='): - constraint = base_constraint - else: - constraint = '=' + base_constraint - output_constraints.append(constraint) - - if isinstance(asm_template_arg, ast.JoinedStr): - raw_template = self._normalize_asm_template( - self._process_joined_str_template( - asm_template_arg, input_ops, input_constraints, output_ops, output_constraints - ) - ) - elif isinstance(asm_template_arg, ast.Constant) and isinstance(asm_template_arg.value, str): - raw_template = self._normalize_asm_template(asm_template_arg.value) - else: - raw_template = '' - - raw_template = self._mangle_asm_calls(raw_template) - asm_dialect = self._format_to_dialect(asm_format) - if asm_format == 'AT&T': - asm_template = raw_template # AT&T 不需要转换 - elif asm_format == 'ARM': - asm_template = raw_template # ARM 不需要转换 - else: - asm_template = self._prepare_intel_asm(raw_template) # Intel → LLVM IR 格式 - - if input_arg and isinstance(input_arg, (ast.List, ast.Tuple)): - for item in input_arg.elts: - if isinstance(item, ast.Call) and isinstance(item.func, ast.Attribute): - if item.func.value.id == 'c' and item.func.attr == 'AsmInp': - if len(item.args) >= 1: - value = self.HandleExprLlvm(item.args[0]) - if value: - input_ops.append(value) - constraint = 'r' - if len(item.args) >= 2: - constraint = self._parse_asm_descr(item.args[1]) - if not constraint: - constraint = 'r' - input_constraints.append(constraint) - elif isinstance(item, (ast.List, ast.Tuple)) and len(item.elts) >= 2: - value_node = item.elts[0] - descr_node = item.elts[1] - value = self.HandleExprLlvm(value_node) - if value: - input_ops.append(value) - constraint = self._parse_asm_descr(descr_node) - if not constraint: - constraint = 'r' - input_constraints.append(constraint) - - clobbers = [] - if op_arg and isinstance(op_arg, (ast.List, ast.Tuple)): - for item in op_arg.elts: - clobber = self._parse_asm_descr(item) - if clobber: - clobbers.append(clobber) - - constraint_parts = [] - for oc in output_constraints: - c = oc if oc.startswith('=') else ('=' + oc) - constraint_parts.append(c) - for ic in input_constraints: - if ic in ('d', 'edx', 'rdx'): - constraint_parts.append('{dx}') - else: - constraint_parts.append(ic) - - full_constraint = ",".join(constraint_parts) - - constraint_to_reg = { - 'a': 'rax', 'b': 'rbx', 'c': 'rcx', 'd': 'rdx', - 'S': 'rsi', 'D': 'rdi', - 'A': 'rax', 'U': 'r8', - } - used_regs = set() - for ic in input_constraints: - if ic in constraint_to_reg: - used_regs.add(constraint_to_reg[ic]) - for oc in output_constraints: - base_oc = oc.lstrip('=').lstrip('+') - if base_oc in constraint_to_reg: - used_regs.add(constraint_to_reg[base_oc]) - - if clobbers: - has_memory = 'memory' in clobbers - if has_memory and output_ops: - clobbers = [c for c in clobbers if c != 'memory'] - if asm_format == 'ARM': - # ARM 不需要 x86 的 e→r 寄存器名转换 - clobber_final = [c for c in clobbers if c not in used_regs] - else: - clobber_64bit = [] - for c in clobbers: - if c in ['eax', 'ebx', 'ecx', 'edx', 'esi', 'edi', 'ebp', 'esp']: - clobber_64bit.append(c.replace('e', 'r')) - else: - clobber_64bit.append(c) - clobber_final = [c for c in clobber_64bit if c not in used_regs] - if clobber_final: - if full_constraint: - full_constraint += "," - full_constraint += ",".join([f"~{{{c}}}" for c in clobber_final]) - - if output_ops: - single_out = len(output_ops) == 1 - if single_out: - op = output_ops[0] - if isinstance(op, ir.AllocaInstr): - ret_type = op.type.pointee - elif isinstance(op, ir.GlobalVariable): - ret_type = op.type.pointee - elif isinstance(op, (ir.GEPInstr, ir.CastInstr)): - ret_type = op.type.pointee if isinstance(op.type, ir.PointerType) else op.type - else: - ret_type = op.type - else: - def _get_ret_type(op): - if isinstance(op, (ir.AllocaInstr, ir.GlobalVariable)): - return op.type.pointee - return op.type - ret_type = ir.LiteralStructType([_get_ret_type(op) for op in output_ops]) - if isinstance(ret_type, ir.PointerType) and isinstance(ret_type.pointee, ir.IdentifiedStructType): - ret_type = ir.IntType(64) - operands = input_ops - param_types = [op.type for op in operands] - func_type = ir.FunctionType(ret_type, param_types) - inline_asm = ir.InlineAsm(func_type, asm_template, full_constraint, side_effect=len(output_ops) == 0, asm_dialect=asm_dialect) - result = Gen.builder.call(inline_asm, operands, name="asm_result") - if single_out: - target = output_ops[0] - if isinstance(target, ir.AllocaInstr): - if target.type.pointee != result.type: - i64t = ir.IntType(64) - iv = Gen.builder.ptrtoint(result, i64t) - ptr = Gen.builder.bitcast(target, ir.PointerType(i64t)) - Gen.builder.store(iv, ptr) - else: - Gen.builder.store(result, target) - elif isinstance(target, (ir.GlobalVariable, ir.GEPInstr, ir.CastInstr)): - target_pointee = target.type.pointee - if target_pointee != result.type: - if isinstance(target_pointee, ir.PointerType) and isinstance(result, ir.Instruction) and result.type == ir.IntType(64): - ptr_val = Gen.builder.inttoptr(result, target_pointee) - Gen.builder.store(ptr_val, target) - else: - i64t = ir.IntType(64) - iv = Gen.builder.ptrtoint(result, i64t) - ptr = Gen.builder.bitcast(target, ir.PointerType(i64t)) - Gen.builder.store(iv, ptr) - else: - Gen.builder.store(result, target) - else: - dst = Gen._alloca_entry(result.type) - Gen.builder.store(result, dst) - else: - for i, out_op in enumerate(output_ops): - val = Gen.builder.extract_value(result, i, name=f"asm_out_{i}") - target = out_op if isinstance(out_op, ir.AllocaInstr) else Gen._alloca_entry(val.type) - if isinstance(target, ir.AllocaInstr) and target.type.pointee != val.type: - i64t = ir.IntType(64) - iv = Gen.builder.ptrtoint(val, i64t) - ptr = Gen.builder.bitcast(target, ir.PointerType(i64t)) - Gen.builder.store(iv, ptr) - else: - Gen.builder.store(val, target) - else: - operands = input_ops - param_types = [op.type for op in operands] - func_type = ir.FunctionType(ir.VoidType(), param_types) - inline_asm = ir.InlineAsm(func_type, asm_template, full_constraint, side_effect=True, asm_dialect=asm_dialect) - Gen.builder.call(inline_asm, operands, name="asm_call") - return ir.Constant(ir.IntType(32), 1) - - def _get_var_ptr_for_asm(self, node): - Gen = self.Trans.LlvmGen - if isinstance(node, ast.Name): - var_name = node.id - if var_name in Gen.variables and Gen.variables[var_name] is not None: - ptr = Gen.variables[var_name] - if isinstance(ptr, ir.AllocaInstr): - return ptr - if isinstance(ptr, ir.GlobalVariable): - return ptr - elif isinstance(node, ast.Attribute): - obj_ptr = self._get_var_ptr_for_asm(node.value) - if obj_ptr is not None: - obj_type = obj_ptr.type.pointee - if isinstance(obj_type, ir.PointerType) and isinstance(obj_type.pointee, ir.IdentifiedStructType): - loaded = Gen.builder.load(obj_ptr, name="asm_attr_load") - struct_type = obj_type.pointee - class_name = Gen._resolve_class_for_var(node.value.id) if isinstance(node.value, ast.Name) else None - if class_name: - offset = Gen._get_member_offset(node.attr, class_name) - gep = Gen.builder.gep(loaded, [ir.Constant(ir.IntType(32), 0), - ir.Constant(ir.IntType(32), offset)], - inbounds=True) - return gep - for idx, elem_type in enumerate(struct_type.elements): - gep = Gen.builder.gep(loaded, [ir.Constant(ir.IntType(32), 0), - ir.Constant(ir.IntType(32), idx)], - inbounds=True) - return gep - elif isinstance(obj_type, ir.IdentifiedStructType): - class_name = Gen._resolve_class_for_var(node.value.id) if isinstance(node.value, ast.Name) else None - if class_name: - offset = Gen._get_member_offset(node.attr, class_name) - gep = Gen.builder.gep(obj_ptr, [ir.Constant(ir.IntType(32), 0), - ir.Constant(ir.IntType(32), offset)], - inbounds=True) - return gep - for idx, elem_type in enumerate(obj_type.elements): - gep = Gen.builder.gep(obj_ptr, [ir.Constant(ir.IntType(32), 0), - ir.Constant(ir.IntType(32), idx)], - inbounds=True) - return gep - return None - - def _parse_asm_descr(self, expr): - from lib.includes import t - - if isinstance(expr, ast.BinOp): - left_val = self._parse_asm_descr(expr.left) - right_val = self._parse_asm_descr(expr.right) - return left_val + right_val - - elif isinstance(expr, ast.Attribute): - if isinstance(expr.value, ast.Attribute): - if (isinstance(expr.value.value, ast.Name) and - expr.value.value.id == 't' and - expr.value.attr == 'ASM_DESCR'): - AttrName = expr.attr - return getattr(t.ASM_DESCR, AttrName, "") - elif isinstance(expr.value, ast.Name) and expr.value.id == 't': - AttrName = expr.attr - return getattr(t.ASM_DESCR, AttrName, "") - - elif isinstance(expr, ast.Constant): - return expr.value - - return "" - - def _infer_expr_llvm_type(self, expr): - import llvmlite.ir as ir - if isinstance(expr, ast.Name): - type_name = expr.id - if hasattr(t, type_name): - ctype = getattr(t, type_name) - if isinstance(ctype, type) and issubclass(ctype, t.CType): - size = getattr(ctype, 'Size', None) - if size is not None: - return ir.IntType(size) - if type_name == 'CFloat': - return ir.FloatType() - elif type_name == 'CDouble': - return ir.DoubleType() - elif isinstance(expr, ast.Attribute): - if isinstance(expr.value, ast.Name) and expr.value.id == 't': - return self._infer_expr_llvm_type(ast.Name(id=expr.attr, ctx=ast.Load())) - return None +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle +import ast +import llvmlite.ir as ir +import t + +# 猴子补丁 llvmlite.ir.InlineAsm 以支持 asm_dialect 参数 +# 添加保护避免重复补丁 +_InlineAsmPatched = getattr(ir.InlineAsm, '_transpyc_patched', False) + +if not _InlineAsmPatched: + _OrigInlineAsmInit = ir.InlineAsm.__init__ + _OrigInlineAsmDescr = ir.InlineAsm.descr + + def _patched_inline_asm_init(self, ftype, asm, constraint, side_effect=False, asm_dialect=None): + _OrigInlineAsmInit(self, ftype, asm, constraint, side_effect) + self.asm_dialect = asm_dialect + + def _patched_inline_asm_descr(self, buf): + sideeffect = 'sideeffect' if self.side_effect else '' + dialect_str = getattr(self, 'asm_dialect', None) + if dialect_str == 'intel': + dialect = 'inteldialect' + else: + dialect = '' + fmt = 'asm {sideeffect} {dialect} "{asm}", "{constraint}"' + buf.append(fmt.format(sideeffect=sideeffect, dialect=dialect, asm=self.asm, + constraint=self.constraint)) + + ir.InlineAsm.__init__ = _patched_inline_asm_init + ir.InlineAsm.descr = _patched_inline_asm_descr + ir.InlineAsm._transpyc_patched = True + + +class ExprAsmHandle(BaseHandle): + @staticmethod + def _format_to_dialect(asm_format): + """将用户指定的 format 参数转换为 LLVM asm_dialect 值""" + fmt = asm_format.lower() if asm_format else 'intel' + if fmt == 'att': + return 'att' + elif fmt == 'arm': + return None # ARM 没有专门的 dialect 标记 + else: + return 'intel' # 默认 Intel + + def _HandleAsmLlvm(self, Node): + Gen = self.Trans.LlvmGen + + op_arg = None + input_arg = None + output_arg = None + asm_format = 'Intel' # 汇编格式: Intel / AT&T / ARM + for kw in Node.keywords: + if kw.arg == 'op': + op_arg = kw.value + elif kw.arg in ('input', 'inp', 'inputs'): + input_arg = kw.value + elif kw.arg in ('output', 'out', 'outputs'): + output_arg = kw.value + elif kw.arg == 'format': + if isinstance(kw.value, ast.Constant) and isinstance(kw.value.value, str): + asm_format = kw.value.value + + if len(Node.args) >= 1: + pos_op = None + if len(Node.args) >= 2 and op_arg is None: + pos_op = Node.args[1] + return self._HandleAsmWithOpLlvm(Node.args[0], op_arg or pos_op, input_arg, output_arg, asm_format) + + if len(Node.args) < 2: + return ir.Constant(ir.IntType(32), 1) + + args = Node.args + + if len(args) == 4: + output_type_arg = args[0] + asm_template_arg = args[1] + constraint_arg = args[2] + clobber_arg = args[3] + + output_type = self._infer_expr_llvm_type(output_type_arg) + if not output_type: + output_type = ir.IntType(32) + + asm_template = '' + if isinstance(asm_template_arg, ast.Constant) and isinstance(asm_template_arg.value, str): + asm_template = self._prepare_intel_asm(self._mangle_asm_calls(asm_template_arg.value)) + + constraint = '' + if isinstance(constraint_arg, ast.Constant) and isinstance(constraint_arg.value, str): + constraint = constraint_arg.value + + clobber = '' + if isinstance(clobber_arg, ast.Constant) and isinstance(clobber_arg.value, str): + clobber = clobber_arg.value + + full_constraint = constraint + func_type = ir.FunctionType(output_type, []) + asm_dialect = self._format_to_dialect(asm_format) + inline_asm = ir.InlineAsm(func_type, asm_template, constraint, side_effect=True, asm_dialect=asm_dialect) + result = Gen.builder.call(inline_asm, [], name="asm_result") + return result + + elif len(args) >= 2: + output_type_arg = args[0] + asm_template_arg = args[1] + + output_type = self._infer_expr_llvm_type(output_type_arg) + if not output_type: + output_type = ir.IntType(32) + + asm_template = '' + if isinstance(asm_template_arg, ast.Constant) and isinstance(asm_template_arg.value, str): + asm_template = self._prepare_intel_asm(self._mangle_asm_calls(asm_template_arg.value)) + + output_constraints = [] + output_values = [] + if len(args) > 2 and isinstance(args[2], (ast.List, ast.Tuple)): + for item in args[2].elts: + if isinstance(item, (ast.List, ast.Tuple)) and len(item.elts) >= 2: + constraint_node = item.elts[0] + value_node = item.elts[1] + if isinstance(constraint_node, ast.Constant) and isinstance(constraint_node.value, str): + output_constraints.append(constraint_node.value) + value = self.HandleExprLlvm(value_node) + if value: + output_values.append(value) + + input_constraints = [] + input_values = [] + if len(args) > 3 and isinstance(args[3], (ast.List, ast.Tuple)): + for item in args[3].elts: + if isinstance(item, (ast.List, ast.Tuple)) and len(item.elts) >= 2: + constraint_node = item.elts[0] + value_node = item.elts[1] + if isinstance(constraint_node, ast.Constant) and isinstance(constraint_node.value, str): + input_constraints.append(constraint_node.value) + value = self.HandleExprLlvm(value_node) + if value: + input_values.append(value) + + clobbers = [] + if len(args) > 4 and isinstance(args[4], (ast.List, ast.Tuple)): + for item in args[4].elts: + if isinstance(item, ast.Constant) and isinstance(item.value, str): + clobbers.append(item.value) + + constraint_parts = [] + for oc in output_constraints: + constraint_parts.append(oc) + + input_start_idx = len(output_constraints) + for ic in input_constraints: + constraint_parts.append(ic) + + full_constraint = ",".join(constraint_parts) + + if clobbers: + if full_constraint: + full_constraint += "," + for c in clobbers: + full_constraint += f"~{{{c}}}" + + operands = output_values + input_values + param_types = [v.type for v in operands] + func_type = ir.FunctionType(output_type, param_types) + asm_dialect = self._format_to_dialect(asm_format) + inline_asm = ir.InlineAsm(func_type, asm_template, full_constraint, side_effect=False, asm_dialect=asm_dialect) + result = Gen.builder.call(inline_asm, operands, name="asm_result") + return result + + return None + + def _prepare_intel_asm(self, template: str) -> str: + import re + template = re.sub(r'%(\d+)', r'$\1', template) + template = re.sub(r'%([a-zA-Z][a-zA-Z0-9]*)', r'\1', template) + return template + + def _normalize_asm_template(self, template: str) -> str: + lines = template.split('\n') + if len(lines) <= 1: + return template + first_line = lines[0] + rest_lines = lines[1:] + stripped = [] + for line in rest_lines: + s = line.lstrip() + if s: + stripped.append(s) + else: + stripped.append('') + return '\n'.join([first_line] + stripped) + + def _process_joined_str_template(self, node, out_input_ops, out_input_constraints, + out_output_ops, out_output_constraints): + if not isinstance(node, ast.JoinedStr): + if isinstance(node, ast.Constant) and isinstance(node.value, str): + return node.value + return '' + + raw_parts = [] + for value in node.values: + if isinstance(value, ast.Constant) and isinstance(value.value, str): + raw_parts.append(('text', value.value)) + elif isinstance(value, ast.FormattedValue): + expr = value.value + if isinstance(expr, ast.Call) and isinstance(expr.func, ast.Attribute): + if isinstance(expr.func.value, ast.Name) and expr.func.value.id == 'c': + if expr.func.attr == 'AsmInp': + if expr.args: + v = self.HandleExprLlvm(expr.args[0]) + if v: + c = 'r' + if len(expr.args) >= 2: + c = self._parse_asm_descr(expr.args[1]) + if not c: + c = 'r' + out_input_ops.append(v) + out_input_constraints.append(c) + raw_parts.append(('input', len(out_input_ops) - 1)) + elif expr.func.attr == 'AsmOut': + if expr.args: + target_ptr = self._get_var_ptr_for_asm(expr.args[0]) + if target_ptr: + v = target_ptr + else: + v = self.HandleExprLlvm(expr.args[0]) + if v: + c = '=r' + if len(expr.args) >= 2: + c = self._parse_asm_descr(expr.args[1]) + if not c: + c = '=r' + if not c.startswith('='): + c = '=' + c + out_output_ops.append(v) + out_output_constraints.append(c) + raw_parts.append(('output', len(out_output_ops) - 1)) + else: + fallback = self.HandleExprLlvm(expr) + if fallback and isinstance(fallback.type, ir.IntType): + out_input_ops.append(fallback) + out_input_constraints.append('r') + raw_parts.append(('input', len(out_input_ops) - 1)) + else: + raw_parts.append(('text', '')) + + num_outputs = len(out_output_ops) + parts = [] + for kind, data in raw_parts: + if kind == 'text': + parts.append(data) + elif kind == 'output': + parts.append(f'%{data}') + elif kind == 'input': + parts.append(f'%{num_outputs + data}') + return ''.join(parts) + + _X86_REGISTERS = frozenset({ + 'rax', 'rbx', 'rcx', 'rdx', 'rsi', 'rdi', 'rbp', 'rsp', + 'r8', 'r9', 'r10', 'r11', 'r12', 'r13', 'r14', 'r15', + 'eax', 'ebx', 'ecx', 'edx', 'esi', 'edi', 'ebp', 'esp', + 'ax', 'bx', 'cx', 'dx', 'si', 'di', 'bp', 'sp', + 'al', 'bl', 'cl', 'dl', 'ah', 'bh', 'ch', 'dh', + 'sil', 'dil', 'bpl', 'spl', + 'r8d', 'r9d', 'r10d', 'r11d', 'r12d', 'r13d', 'r14d', 'r15d', + 'r8w', 'r9w', 'r10w', 'r11w', 'r12w', 'r13w', 'r14w', 'r15w', + 'r8b', 'r9b', 'r10b', 'r11b', 'r12b', 'r13b', 'r14b', 'r15b', + }) + + def _mangle_asm_calls(self, template: str) -> str: + import re + Gen = self.Trans.LlvmGen + sha1 = getattr(Gen, 'module_sha1', '') + if not sha1: + return template + + def replace_call(m): + prefix = m.group(1) + func_name = m.group(2) + if func_name.lower() in self._X86_REGISTERS: + return m.group(0) + mangled = Gen._mangle_func_name(func_name) + if '.' in mangled: + return f'{prefix}\\22{mangled}\\22' + return f"{prefix}{mangled}" + + return re.sub(r'(call\s+)(\w+)', replace_call, template) + + def _HandleAsmWithOpLlvm(self, asm_template_arg, op_arg, input_arg=None, output_arg=None, asm_format='Intel'): + Gen = self.Trans.LlvmGen + + input_ops = [] + input_constraints = [] + output_ops = [] + output_constraints = [] + + if output_arg and isinstance(output_arg, (ast.List, ast.Tuple)): + for item in output_arg.elts: + if isinstance(item, ast.Call) and isinstance(item.func, ast.Attribute): + if item.func.value.id == 'c' and item.func.attr == 'AsmOut': + if len(item.args) >= 1: + target_ptr = self._get_var_ptr_for_asm(item.args[0]) + if target_ptr: + output_ops.append(target_ptr) + else: + value = self.HandleExprLlvm(item.args[0]) + if value: + output_ops.append(value) + constraint = '=r' + if len(item.args) >= 2: + base_constraint = self._parse_asm_descr(item.args[1]) + if base_constraint: + if base_constraint.startswith('='): + constraint = base_constraint + else: + constraint = '=' + base_constraint + output_constraints.append(constraint) + + if isinstance(asm_template_arg, ast.JoinedStr): + raw_template = self._normalize_asm_template( + self._process_joined_str_template( + asm_template_arg, input_ops, input_constraints, output_ops, output_constraints + ) + ) + elif isinstance(asm_template_arg, ast.Constant) and isinstance(asm_template_arg.value, str): + raw_template = self._normalize_asm_template(asm_template_arg.value) + else: + raw_template = '' + + raw_template = self._mangle_asm_calls(raw_template) + asm_dialect = self._format_to_dialect(asm_format) + if asm_format == 'AT&T': + asm_template = raw_template # AT&T 不需要转换 + elif asm_format == 'ARM': + asm_template = raw_template # ARM 不需要转换 + else: + asm_template = self._prepare_intel_asm(raw_template) # Intel → LLVM IR 格式 + + if input_arg and isinstance(input_arg, (ast.List, ast.Tuple)): + for item in input_arg.elts: + if isinstance(item, ast.Call) and isinstance(item.func, ast.Attribute): + if item.func.value.id == 'c' and item.func.attr == 'AsmInp': + if len(item.args) >= 1: + value = self.HandleExprLlvm(item.args[0]) + if value: + input_ops.append(value) + constraint = 'r' + if len(item.args) >= 2: + constraint = self._parse_asm_descr(item.args[1]) + if not constraint: + constraint = 'r' + input_constraints.append(constraint) + elif isinstance(item, (ast.List, ast.Tuple)) and len(item.elts) >= 2: + value_node = item.elts[0] + descr_node = item.elts[1] + value = self.HandleExprLlvm(value_node) + if value: + input_ops.append(value) + constraint = self._parse_asm_descr(descr_node) + if not constraint: + constraint = 'r' + input_constraints.append(constraint) + + clobbers = [] + if op_arg and isinstance(op_arg, (ast.List, ast.Tuple)): + for item in op_arg.elts: + clobber = self._parse_asm_descr(item) + if clobber: + clobbers.append(clobber) + + constraint_parts = [] + for oc in output_constraints: + c = oc if oc.startswith('=') else ('=' + oc) + constraint_parts.append(c) + for ic in input_constraints: + if ic in ('d', 'edx', 'rdx'): + constraint_parts.append('{dx}') + else: + constraint_parts.append(ic) + + full_constraint = ",".join(constraint_parts) + + constraint_to_reg = { + 'a': 'rax', 'b': 'rbx', 'c': 'rcx', 'd': 'rdx', + 'S': 'rsi', 'D': 'rdi', + 'A': 'rax', 'U': 'r8', + } + used_regs = set() + for ic in input_constraints: + if ic in constraint_to_reg: + used_regs.add(constraint_to_reg[ic]) + for oc in output_constraints: + base_oc = oc.lstrip('=').lstrip('+') + if base_oc in constraint_to_reg: + used_regs.add(constraint_to_reg[base_oc]) + + if clobbers: + has_memory = 'memory' in clobbers + if has_memory and output_ops: + clobbers = [c for c in clobbers if c != 'memory'] + if asm_format == 'ARM': + # ARM 不需要 x86 的 e→r 寄存器名转换 + clobber_final = [c for c in clobbers if c not in used_regs] + else: + clobber_64bit = [] + for c in clobbers: + if c in ['eax', 'ebx', 'ecx', 'edx', 'esi', 'edi', 'ebp', 'esp']: + clobber_64bit.append(c.replace('e', 'r')) + else: + clobber_64bit.append(c) + clobber_final = [c for c in clobber_64bit if c not in used_regs] + if clobber_final: + if full_constraint: + full_constraint += "," + full_constraint += ",".join([f"~{{{c}}}" for c in clobber_final]) + + if output_ops: + single_out = len(output_ops) == 1 + if single_out: + op = output_ops[0] + if isinstance(op, ir.AllocaInstr): + ret_type = op.type.pointee + elif isinstance(op, ir.GlobalVariable): + ret_type = op.type.pointee + elif isinstance(op, (ir.GEPInstr, ir.CastInstr)): + ret_type = op.type.pointee if isinstance(op.type, ir.PointerType) else op.type + else: + ret_type = op.type + else: + def _get_ret_type(op): + if isinstance(op, (ir.AllocaInstr, ir.GlobalVariable)): + return op.type.pointee + return op.type + ret_type = ir.LiteralStructType([_get_ret_type(op) for op in output_ops]) + if isinstance(ret_type, ir.PointerType) and isinstance(ret_type.pointee, ir.IdentifiedStructType): + ret_type = ir.IntType(64) + operands = input_ops + param_types = [op.type for op in operands] + func_type = ir.FunctionType(ret_type, param_types) + inline_asm = ir.InlineAsm(func_type, asm_template, full_constraint, side_effect=len(output_ops) == 0, asm_dialect=asm_dialect) + result = Gen.builder.call(inline_asm, operands, name="asm_result") + if single_out: + target = output_ops[0] + if isinstance(target, ir.AllocaInstr): + if target.type.pointee != result.type: + i64t = ir.IntType(64) + iv = Gen.builder.ptrtoint(result, i64t) + ptr = Gen.builder.bitcast(target, ir.PointerType(i64t)) + Gen.builder.store(iv, ptr) + else: + Gen.builder.store(result, target) + elif isinstance(target, (ir.GlobalVariable, ir.GEPInstr, ir.CastInstr)): + target_pointee = target.type.pointee + if target_pointee != result.type: + if isinstance(target_pointee, ir.PointerType) and isinstance(result, ir.Instruction) and result.type == ir.IntType(64): + ptr_val = Gen.builder.inttoptr(result, target_pointee) + Gen.builder.store(ptr_val, target) + else: + i64t = ir.IntType(64) + iv = Gen.builder.ptrtoint(result, i64t) + ptr = Gen.builder.bitcast(target, ir.PointerType(i64t)) + Gen.builder.store(iv, ptr) + else: + Gen.builder.store(result, target) + else: + dst = Gen._allocaEntry(result.type) + Gen.builder.store(result, dst) + else: + for i, out_op in enumerate(output_ops): + val = Gen.builder.extract_value(result, i, name=f"asm_out_{i}") + target = out_op if isinstance(out_op, ir.AllocaInstr) else Gen._allocaEntry(val.type) + if isinstance(target, ir.AllocaInstr) and target.type.pointee != val.type: + i64t = ir.IntType(64) + iv = Gen.builder.ptrtoint(val, i64t) + ptr = Gen.builder.bitcast(target, ir.PointerType(i64t)) + Gen.builder.store(iv, ptr) + else: + Gen.builder.store(val, target) + else: + operands = input_ops + param_types = [op.type for op in operands] + func_type = ir.FunctionType(ir.VoidType(), param_types) + inline_asm = ir.InlineAsm(func_type, asm_template, full_constraint, side_effect=True, asm_dialect=asm_dialect) + Gen.builder.call(inline_asm, operands, name="asm_call") + return ir.Constant(ir.IntType(32), 1) + + def _get_var_ptr_for_asm(self, node): + Gen = self.Trans.LlvmGen + if isinstance(node, ast.Name): + var_name = node.id + if var_name in Gen.variables and Gen.variables[var_name] is not None: + ptr = Gen.variables[var_name] + if isinstance(ptr, ir.AllocaInstr): + return ptr + if isinstance(ptr, ir.GlobalVariable): + return ptr + elif isinstance(node, ast.Attribute): + obj_ptr = self._get_var_ptr_for_asm(node.value) + if obj_ptr is not None: + obj_type = obj_ptr.type.pointee + if isinstance(obj_type, ir.PointerType) and isinstance(obj_type.pointee, ir.IdentifiedStructType): + Loaded = Gen.builder.load(obj_ptr, name="asm_attr_Load") + struct_type = obj_type.pointee + class_name = Gen._resolve_class_for_var(node.value.id) if isinstance(node.value, ast.Name) else None + if class_name: + offset = Gen._get_member_offset(node.attr, class_name) + gep = Gen.builder.gep(Loaded, [ir.Constant(ir.IntType(32), 0), + ir.Constant(ir.IntType(32), offset)], + inbounds=True) + return gep + for idx, elem_type in enumerate(struct_type.elements): + gep = Gen.builder.gep(Loaded, [ir.Constant(ir.IntType(32), 0), + ir.Constant(ir.IntType(32), idx)], + inbounds=True) + return gep + elif isinstance(obj_type, ir.IdentifiedStructType): + class_name = Gen._resolve_class_for_var(node.value.id) if isinstance(node.value, ast.Name) else None + if class_name: + offset = Gen._get_member_offset(node.attr, class_name) + gep = Gen.builder.gep(obj_ptr, [ir.Constant(ir.IntType(32), 0), + ir.Constant(ir.IntType(32), offset)], + inbounds=True) + return gep + for idx, elem_type in enumerate(obj_type.elements): + gep = Gen.builder.gep(obj_ptr, [ir.Constant(ir.IntType(32), 0), + ir.Constant(ir.IntType(32), idx)], + inbounds=True) + return gep + return None + + def _parse_asm_descr(self, expr): + from lib.includes import t + + if isinstance(expr, ast.BinOp): + left_val = self._parse_asm_descr(expr.left) + right_val = self._parse_asm_descr(expr.right) + return left_val + right_val + + elif isinstance(expr, ast.Attribute): + if isinstance(expr.value, ast.Attribute): + if (isinstance(expr.value.value, ast.Name) and + expr.value.value.id == 't' and + expr.value.attr == 'ASM_DESCR'): + AttrName = expr.attr + return getattr(t.ASM_DESCR, AttrName, "") + elif isinstance(expr.value, ast.Name) and expr.value.id == 't': + AttrName = expr.attr + return getattr(t.ASM_DESCR, AttrName, "") + + elif isinstance(expr, ast.Constant): + return expr.value + + return "" + + def _infer_expr_llvm_type(self, expr): + import llvmlite.ir as ir + if isinstance(expr, ast.Name): + type_name = expr.id + if hasattr(t, type_name): + ctype = getattr(t, type_name) + if isinstance(ctype, type) and issubclass(ctype, t.CType): + size = getattr(ctype, 'Size', None) + if size is not None: + return ir.IntType(size) + if type_name == 'CFloat': + return ir.FloatType() + elif type_name == 'CDouble': + return ir.DoubleType() + elif isinstance(expr, ast.Attribute): + if isinstance(expr.value, ast.Name) and expr.value.id == 't': + return self._infer_expr_llvm_type(ast.Name(id=expr.attr, ctx=ast.Load())) + return None diff --git a/lib/core/Handles/HandlesExprAttr.py b/lib/core/Handles/HandlesExprAttr.py index b476008..2a29cce 100644 --- a/lib/core/Handles/HandlesExprAttr.py +++ b/lib/core/Handles/HandlesExprAttr.py @@ -1,1161 +1,1161 @@ -from __future__ import annotations -from typing import TYPE_CHECKING -if TYPE_CHECKING: - from lib.core.translator import Translator -from lib.core.Handles.HandlesBase import BaseHandle, FuncMeta -import ast -import llvmlite.ir as ir - - -class ExprAttrHandle(BaseHandle): - - # ========== 辅助方法 ========== - - def _apply_bswap_on_load(self, val, ClassName, AttrName): - Gen = self.Trans.LlvmGen - byte_order = getattr(Gen, 'class_member_byteorders', {}).get(ClassName, {}).get(AttrName, "") - if byte_order == 'big' and isinstance(val.type, ir.IntType): - if val.type.width in (16, 32, 64): - val = Gen.builder.bswap(val, name=f"bswap_load_{AttrName}") - return val - - def _gep_and_load_member(self, Gen, ObjVal, offset, AttrName, ClassName, ST=None): - """从结构体指针通过 GEP 取成员,处理 array/struct pointer/class_members 特殊情况""" - if offset is None: - return None - if isinstance(ObjVal.type, ir.PointerType): - pointee = ObjVal.type.pointee - if isinstance(pointee, ir.IdentifiedStructType) and pointee.elements is not None and offset >= len(pointee.elements): - return None - MemberPtr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) - if isinstance(MemberPtr.type, ir.PointerType) and isinstance(MemberPtr.type.pointee, ir.ArrayType): - return MemberPtr - if isinstance(MemberPtr.type, ir.PointerType) and isinstance(MemberPtr.type.pointee, ir.IdentifiedStructType): - return MemberPtr - # 检查 pointer-to-pointer 且实际元素是 ArrayType - if isinstance(MemberPtr.type, ir.PointerType) and isinstance(MemberPtr.type.pointee, ir.PointerType): - actual_elem_type = None - if ST is not None and isinstance(ST, ir.IdentifiedStructType) and ST.elements is not None and offset < len(ST.elements): - actual_elem_type = ST.elements[offset] - if isinstance(actual_elem_type, ir.ArrayType): - return Gen.builder.bitcast(MemberPtr, ir.PointerType(actual_elem_type), name=f"cast_arr_{AttrName}") - # 检查 class_members 中的 ArrayType - if ClassName in Gen.class_members: - for member_name, member_type in Gen.class_members[ClassName]: - if member_name == AttrName and isinstance(member_type, ir.ArrayType): - return Gen.builder.bitcast(MemberPtr, ir.PointerType(member_type), name=f"cast_arr_{AttrName}") - val = Gen._load(MemberPtr, name=AttrName) - return self._apply_bswap_on_load(val, ClassName, AttrName) - - def _try_load_struct_from_stub(self, Gen, ClassName): - """尝试从 stub 加载结构体定义,返回 (struct_type, ok)""" - if ClassName not in Gen.structs: - return None, False - st = Gen.structs[ClassName] - if isinstance(st, ir.IdentifiedStructType) and (st.elements is None or len(st.elements) == 0): - self.Trans.ImportHandler._TryLoadStructFromStub(ClassName, Gen) - st = Gen.structs.get(ClassName, st) - if isinstance(st, ir.IdentifiedStructType) and (st.elements is None or len(st.elements) == 0): - return st, False - return st, True - - def _make_define_constant(self, Gen, val): - """将 CDefine 值转为 LLVM 常量""" - if isinstance(val, int): - if abs(val) > 2147483647: - return ir.Constant(ir.IntType(64), val) - return ir.Constant(ir.IntType(32), val) - elif isinstance(val, float): - return ir.Constant(ir.DoubleType(), val) - elif isinstance(val, str): - str_value = val + '\x00' - str_bytes = str_value.encode('utf-8') - str_type = ir.ArrayType(ir.IntType(8), len(str_bytes)) - gv_name = f"str_const_{Gen.string_const_counter}" - gv = ir.GlobalVariable(Gen.module, str_type, name=gv_name) - gv.initializer = ir.Constant(str_type, bytearray(str_bytes)) - gv.linkage = 'internal' - Gen.string_const_counter += 1 - return Gen.builder.gep(gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{gv_name}_cast") - return None - - def _lookup_cdefine(self, Gen, VarName, AttrName): - """在符号表和模块中查找 CDefine 常量值""" - imported_modules = getattr(self.Trans, '_imported_modules', None) - if not imported_modules: - return None - PossibleKeys = [f"{VarName}.{AttrName}", AttrName] - for mod_name in imported_modules: - if mod_name.endswith(f".{VarName}") or mod_name == VarName: - key = f"{mod_name}.{AttrName}" - if key not in PossibleKeys: - PossibleKeys.append(key) - for lookup_key in PossibleKeys: - SymInfo = self.Trans.SymbolTable.get(lookup_key) - if SymInfo and getattr(SymInfo, 'IsDefine', None) and getattr(SymInfo, 'DefineValue', None) is not None: - return self._make_define_constant(Gen, SymInfo.DefineValue) - # 也检查 _define_constants - define_constants = getattr(Gen, '_define_constants', {}) - for key in (f"{VarName}.{AttrName}", AttrName): - if key in define_constants: - return self._make_define_constant(Gen, define_constants[key]) - return None - - def _lookup_module_global(self, Gen, VarName, AttrName): - """在模块全局变量中查找 import 的属性""" - imported_modules = getattr(self.Trans, '_imported_modules', None) - import_aliases = getattr(self.Trans, '_import_aliases', {}) - if not imported_modules: - return None - resolved_mod = import_aliases.get(VarName, VarName) - if VarName not in imported_modules and resolved_mod not in imported_modules: - return None - PossibleKeys = [f"{VarName}.{AttrName}", AttrName] - for mod_name in imported_modules: - if mod_name.endswith(f".{VarName}") or mod_name == VarName: - key = f"{mod_name}.{AttrName}" - if key not in PossibleKeys: - PossibleKeys.append(key) - for key in PossibleKeys: - if key in Gen.module.globals: - GVar = Gen.module.globals[key] - if isinstance(GVar, ir.Function): - return GVar - if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): - return GVar - return Gen._load(GVar, name=AttrName) - # SHA1 前缀查找 - module_sha1_map = getattr(Gen, 'module_sha1_map', {}) - sha1_candidates = [VarName, resolved_mod] - for mod_name in imported_modules: - if mod_name.endswith(f".{VarName}") or mod_name == VarName: - if mod_name not in sha1_candidates: - sha1_candidates.append(mod_name) - for cand in sha1_candidates: - sha1 = module_sha1_map.get(cand) - if sha1: - prefixed = f"{sha1}.{AttrName}" - if prefixed in Gen.module.globals: - GVar2 = Gen.module.globals[prefixed] - if isinstance(GVar2, ir.Function): - return GVar2 - if isinstance(GVar2.type, ir.PointerType) and isinstance(GVar2.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): - return GVar2 - return Gen._load(GVar2, name=AttrName) - if AttrName in Gen.module.globals: - gv = Gen.module.globals[AttrName] - if AttrName in Gen.variables and Gen.variables[AttrName] is None: - str_gv_name = AttrName + '_str' - if str_gv_name in Gen.module.globals: - str_gv = Gen.module.globals[str_gv_name] - return Gen.builder.gep(str_gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{AttrName}_str_ptr") - return Gen.builder.load(gv, name=AttrName) - return None - - def _resolve_var_classname(self, Gen, VarName): - """根据变量名解析其结构体类名""" - ClassName = Gen.var_struct_class.get(VarName) - if not ClassName and getattr(Gen, 'global_struct_class', None): - ClassName = Gen.global_struct_class.get(VarName) - if ClassName: - Gen.var_struct_class[VarName] = ClassName - if not ClassName and VarName in Gen.module.globals: - GVar = Gen.module.globals[VarName] - if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): - found = Gen.find_struct_by_pointee(GVar.type.pointee) - if found: - ClassName = found[0] - Gen.var_struct_class[VarName] = ClassName - if getattr(Gen, 'global_struct_class', None): - Gen.global_struct_class[VarName] = ClassName - if not ClassName and VarName in Gen.variables: - VarPtr = Gen.variables[VarName] - if VarPtr is not None and isinstance(VarPtr.type, ir.PointerType): - pointee = VarPtr.type.pointee - if isinstance(pointee, ir.PointerType): - pointee = pointee.pointee - found = Gen.find_struct_by_pointee(pointee) - if found: - ClassName = found[0] - return ClassName - - def _check_struct_match(self, Gen, ObjVal, ClassName): - """检查 ObjVal 是否指向 ClassName 对应的结构体""" - if ClassName not in Gen.structs: - return False - if isinstance(ObjVal.type, ir.PointerType): - ST = Gen.structs[ClassName] - if ObjVal.type.pointee == ST: - return True - if isinstance(ObjVal.type.pointee, ir.IdentifiedStructType) and isinstance(ST, ir.IdentifiedStructType) and ObjVal.type.pointee.name == ST.name: - return True - return False - - # ========== _HandleAttributeLlvm 子方法 ========== - - def _handle_attr_self(self, Node, VarName): - """处理 self.xxx 属性访问""" - Gen = self.Trans.LlvmGen - ClassName = self.Trans._CurrentCpythonObjectClass - if not ClassName: - return None - # 检查 property getter - PropKey = f'{ClassName}.{Node.attr}' - PropInfo = self.Trans.SymbolTable.get(PropKey) - if PropInfo and hasattr(PropInfo, 'MetaList') and FuncMeta.PROPERTY_GETTER in PropInfo.MetaList: - SelfVar = Gen._get_var_ptr('self') - if SelfVar: - SelfPtr = Gen._load(SelfVar, name="self") - GetterFunc = Gen._get_function(PropKey) - if GetterFunc and SelfPtr: - return Gen.builder.call(GetterFunc, [SelfPtr], name=f"prop_{PropKey}") - offset = Gen._get_member_offset(Node.attr, ClassName) - SelfVar = Gen._get_var_ptr('self') - if not SelfVar: - return None - SelfPtr = Gen._load(SelfVar, name="self") - if not isinstance(SelfPtr.type, ir.PointerType): - return None - pointee = SelfPtr.type.pointee - if isinstance(pointee, ir.IdentifiedStructType) and pointee.elements is None: - for CN2, ST2 in Gen.structs.items(): - if isinstance(ST2, ir.IdentifiedStructType) and ST2.name == pointee.name and ST2.elements is not None: - pointee = ST2 - break - if isinstance(pointee, ir.IdentifiedStructType) and pointee.elements is not None and offset is not None and offset < len(pointee.elements): - if isinstance(pointee.elements[offset], ir.VoidType): - return None - return self._gep_and_load_member(Gen, SelfPtr, offset, Node.attr, ClassName, pointee) - DynamicVarName = f"self.{Node.attr}" - if DynamicVarName in Gen.variables: - return Gen._load(Gen.variables[DynamicVarName], name=Node.attr) - return None - - def _handle_attr_enum(self, Node, VarName): - """处理枚举成员访问 (VarName 是枚举类型名)""" - SymInfo = self.Trans.SymbolTable.get(VarName) - if not SymInfo or not getattr(SymInfo, 'IsEnum', None): - return None - if Node.attr in self.Trans.SymbolTable: - MemberInfo = self.Trans.SymbolTable[Node.attr] - if getattr(MemberInfo, 'IsEnumMember', None) and getattr(MemberInfo, 'EnumName', None) == VarName: - if isinstance(getattr(MemberInfo, 'value', None), int): - return ir.Constant(ir.IntType(32), MemberInfo.value) - for key, info in self.Trans.SymbolTable.items(): - if getattr(info, 'IsEnumMember', None) and getattr(info, 'EnumName', None) == VarName and key == Node.attr: - if isinstance(getattr(info, 'value', None), int): - return ir.Constant(ir.IntType(32), info.value) - return None - - def _handle_attr_name(self, Node, VarName): - """处理 x.attr 形式 (x 是普通 Name)""" - Gen = self.Trans.LlvmGen - AttrName = Node.attr - - # 先尝试枚举成员 - result = self._handle_attr_enum(Node, VarName) - if result is not None: - return result - - # 尝试 CDefine 常量 - result = self._lookup_cdefine(Gen, VarName, AttrName) - if result is not None: - return result - - # 尝试 import 模块全局变量 - result = self._lookup_module_global(Gen, VarName, AttrName) - if result is not None: - return result - - # 尝试 attr 直接作为全局变量 - if AttrName in Gen.module.globals: - gv = Gen.module.globals[AttrName] - if AttrName in Gen.variables and Gen.variables[AttrName] is None: - str_gv_name = AttrName + '_str' - if str_gv_name in Gen.module.globals: - str_gv = Gen.module.globals[str_gv_name] - return Gen.builder.gep(str_gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{AttrName}_str_ptr") - return Gen.builder.load(gv, name=AttrName) - - # 解析结构体类名并访问成员 - ClassName = self._resolve_var_classname(Gen, VarName) - if not ClassName: - return None - - # 检查 property getter - PropKey = f'{ClassName}.{AttrName}' - PropInfo = self.Trans.SymbolTable.get(PropKey) - if PropInfo and hasattr(PropInfo, 'MetaList') and FuncMeta.PROPERTY_GETTER in PropInfo.MetaList: - ObjVal = self.HandleExprLlvm(Node.value) - GetterFunc = Gen._get_function(PropKey) - if GetterFunc and ObjVal: - if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType): - ObjVal = Gen._load(ObjVal, name=f"load_{VarName}") - return Gen.builder.call(GetterFunc, [ObjVal], name=f"prop_{PropKey}") - - # 获取类型信息 - TypeInfo = self.Trans.SymbolTable.get(ClassName) - IsUnion = TypeInfo.IsUnion if TypeInfo else False - IsCenum = TypeInfo.IsEnum if TypeInfo else False - IsRenum = getattr(TypeInfo, 'IsRenum', False) if TypeInfo else False - - # REnum 处理 - if IsRenum: - if AttrName == 'tag': - ObjVal = self.HandleExprLlvm(Node.value) - if ObjVal: - if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType): - ObjVal = Gen._load(ObjVal, name=f"load_{VarName}") - tag_ptr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="tag_ptr") - return Gen._load(tag_ptr, name="tag_val") - NestedStructName = f"{ClassName}_{AttrName}" - if NestedStructName in Gen.structs: - NestedStructType = Gen.structs[NestedStructName] - ObjVal = self.HandleExprLlvm(Node.value) - if ObjVal: - if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType): - ObjVal = Gen._load(ObjVal, name=f"load_{VarName}") - return Gen.builder.bitcast(ObjVal, ir.PointerType(NestedStructType), name=f"cast_{NestedStructName}") - - # CEnum 处理 - if IsCenum: - for qname in (f"{ClassName}.{AttrName}", f"{ClassName}_{AttrName}"): - if qname in self.Trans.SymbolTable: - info = self.Trans.SymbolTable[qname] - if getattr(info, 'IsEnumMember', None) and isinstance(getattr(info, 'value', None), int): - return ir.Constant(ir.IntType(32), info.value) - for key, info in self.Trans.SymbolTable.items(): - if key == AttrName: - if getattr(info, 'IsEnumMember', None) and getattr(info, 'EnumName', None) == ClassName: - if isinstance(getattr(info, 'value', None), int): - return ir.Constant(ir.IntType(32), info.value) - break - - # CUnion 处理 - if IsUnion: - NestedStructName = f"{ClassName}_{AttrName}" - if NestedStructName in Gen.structs: - NestedStructType = Gen.structs[NestedStructName] - ObjVal = self.HandleExprLlvm(Node.value) - if ObjVal: - if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType): - ObjVal = Gen._load(ObjVal, name=f"load_{VarName}") - return Gen.builder.bitcast(ObjVal, ir.PointerType(NestedStructType), name=f"cast_{NestedStructName}") - - # 普通结构体成员访问 - ObjVal = self.HandleExprLlvm(Node.value) - if not ObjVal: - return None - # char* → struct* cast - if self._is_char_pointer(ObjVal): - if ClassName in Gen.structs: - ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") - # 二级指针解引用 - if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType): - ObjVal = Gen._load(ObjVal, name=f"load_{VarName}") - - # 检查结构体匹配 - struct_match = self._check_struct_match(Gen, ObjVal, ClassName) - if not struct_match and ClassName and VarName: - if VarName in Gen.var_struct_class: - CN = Gen.var_struct_class[VarName] - if CN != ClassName and CN in Gen.structs: - ClassName = CN - struct_match = self._check_struct_match(Gen, ObjVal, ClassName) - if not struct_match: - return None - - st, ok = self._try_load_struct_from_stub(Gen, ClassName) - if not ok: - return None - - # bitfield 处理 - bitfield_offsets = Gen.class_member_bitoffsets.get(ClassName, {}) - bitfields = Gen.class_member_bitfields.get(ClassName, {}) - if AttrName in bitfield_offsets and bitfields.get(AttrName, 0) > 0: - return self._load_bitfield_member(ObjVal, ClassName, AttrName) - if AttrName in bitfields and bitfields[AttrName] > 0: - if ClassName not in Gen.class_member_bitoffsets: - Gen.class_member_bitoffsets[ClassName] = {} - if AttrName not in Gen.class_member_bitoffsets[ClassName]: - bo = 0 - for bf_name, bf_width in bitfields.items(): - if bf_name == AttrName: - break - bo += bf_width - Gen.class_member_bitoffsets[ClassName][AttrName] = bo - return self._load_bitfield_member(ObjVal, ClassName, AttrName) - - offset = Gen._get_member_offset(AttrName, ClassName) - # 检查 offset 是否超出实际结构体 - if isinstance(ObjVal.type, ir.PointerType): - actual_pointee = ObjVal.type.pointee - if isinstance(actual_pointee, ir.IdentifiedStructType): - actual_elems = actual_pointee.elements - if actual_elems is not None and offset is not None and offset >= len(actual_elems): - self.Trans.ImportHandler._TryLoadStructFromStub(ClassName, Gen) - actual_elems = actual_pointee.elements - if actual_elems is not None and offset >= len(actual_elems): - return None - return self._gep_and_load_member(Gen, ObjVal, offset, AttrName, ClassName, st) - - def _handle_attr_nested(self, Node): - """处理 a.b.c 嵌套属性访问""" - Gen = self.Trans.LlvmGen - if isinstance(Node.value.value, ast.Name): - ParentVarName = Node.value.value.id - ParentAttrName = Node.value.attr - enum_result = self._try_resolve_cross_module_enum(ParentVarName, ParentAttrName, Node.attr) - if enum_result is not None: - return enum_result - # 尝试跨模块子模块全局变量解析: a.b.c 其中 a.b 是已知子模块, c 是该模块的全局变量 - imported_modules = getattr(self.Trans, '_imported_modules', None) - if imported_modules: - full_module_path = f"{ParentVarName}.{ParentAttrName}" - if full_module_path in imported_modules: - result = self._lookup_module_global(Gen, full_module_path, Node.attr) - if result is not None: - return result - cdefine_result = self._try_resolve_nested_cdefine(Node) - if cdefine_result is not None: - return cdefine_result - ObjVal = self.HandleExprLlvm(Node.value) - if not ObjVal or not isinstance(ObjVal.type, ir.PointerType): - return None - pointee = ObjVal.type.pointee - - # char* → struct* cast + 成员访问 - if isinstance(pointee, ir.IntType) and pointee.width == 8: - AttrClassName = self._get_attr_class(Node.value, Gen) - if AttrClassName and AttrClassName in Gen.structs: - st, ok = self._try_load_struct_from_stub(Gen, AttrClassName) - if not isinstance(st, ir.IdentifiedStructType) or st.elements is None: - return None - CastedObj = Gen.builder.bitcast(ObjVal, ir.PointerType(st), name=f"cast_{AttrClassName}") - offset = Gen._get_member_offset(Node.attr, AttrClassName) - if offset is None: - return None - if offset < len(st.elements) and isinstance(st.elements[offset], ir.VoidType): - return None - return self._gep_and_load_member(Gen, CastedObj, offset, Node.attr, AttrClassName, st) - - # 已知结构体类型 → 直接成员访问 - if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): - for CN, ST in Gen.structs.items(): - if pointee == ST or (isinstance(pointee, ir.IdentifiedStructType) and isinstance(ST, ir.IdentifiedStructType) and pointee.name == ST.name): - st, ok = self._try_load_struct_from_stub(Gen, CN) - if not isinstance(st, ir.IdentifiedStructType) or st.elements is None: - break - bitfield_offsets = Gen.class_member_bitoffsets.get(CN, {}) - if Node.attr in bitfield_offsets: - return self._load_bitfield_member(ObjVal, CN, Node.attr) - offset = Gen._get_member_offset(Node.attr, CN) - if offset is None: - break - return self._gep_and_load_member(Gen, ObjVal, offset, Node.attr, CN, st) - return None - - def _handle_attr_call_result(self, Node): - """处理 func().attr 属性访问""" - Gen = self.Trans.LlvmGen - # Check if this is c.Deref(...) — we need the pointer, not the loaded value - ObjVal = None - is_cderef = (isinstance(Node.value, ast.Call) and - isinstance(Node.value.func, ast.Attribute) and - isinstance(Node.value.func.value, ast.Name) and - Node.value.func.value.id == 'c' and - Node.value.func.attr == 'Deref' and - Node.value.args) - if is_cderef: - deref_arg = Node.value.args[0] - inner_val = self.HandleExprLlvm(deref_arg) - if inner_val and isinstance(inner_val.type, ir.PointerType): - if isinstance(inner_val.type.pointee, ir.PointerType): - ObjVal = Gen._load(inner_val, name="deref_load_ptr") - else: - ObjVal = inner_val - if ObjVal is None: - ObjVal = self.HandleExprLlvm(Node.value) - if not ObjVal or not isinstance(ObjVal.type, ir.PointerType): - return None - pointee = ObjVal.type.pointee - if isinstance(pointee, ir.PointerType): - ObjVal = Gen._load(ObjVal, name="load_ptr_for_attr") - pointee = ObjVal.type.pointee - found = Gen.find_struct_by_pointee(pointee) - if not found: - return None - CN, ST = found - st, ok = self._try_load_struct_from_stub(Gen, CN) - if not isinstance(st, ir.IdentifiedStructType) or st.elements is None: - return None - bitfield_offsets = Gen.class_member_bitoffsets.get(CN, {}) - if Node.attr in bitfield_offsets: - return self._load_bitfield_member(ObjVal, CN, Node.attr) - offset = Gen._get_member_offset(Node.attr, CN) - if offset is None: - return None - return self._gep_and_load_member(Gen, ObjVal, offset, Node.attr, CN, st) - - def _handle_attr_subscript_result(self, Node): - """处理 arr[i].attr 属性访问""" - Gen = self.Trans.LlvmGen - ObjVal = self.HandleExprLlvm(Node.value) - if not ObjVal or not isinstance(ObjVal.type, ir.PointerType): - return None - pointee = ObjVal.type.pointee - if not isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): - return None - found = Gen.find_struct_by_pointee(pointee) - if not found: - return None - CN, ST = found - st, ok = self._try_load_struct_from_stub(Gen, CN) - if not isinstance(st, ir.IdentifiedStructType) or st.elements is None: - return None - offset = Gen._get_member_offset(Node.attr, CN) - if offset is None: - return None - return self._gep_and_load_member(Gen, ObjVal, offset, Node.attr, CN, st) - - def _handle_attr_fallback(self, Node): - """兜底:对任意值尝试指针解引用后查找结构体成员""" - Gen = self.Trans.LlvmGen - ObjVal = self.HandleExprLlvm(Node.value) - if not ObjVal or not isinstance(ObjVal.type, ir.PointerType): - return None - pointee = ObjVal.type.pointee - if isinstance(pointee, ir.PointerType): - ObjVal = Gen._load(ObjVal, name="load_ptr_for_attr_fallback") - pointee = ObjVal.type.pointee - if not isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): - return None - found = Gen.find_struct_by_pointee(pointee) - if not found: - return None - CN, ST = found - st, ok = self._try_load_struct_from_stub(Gen, CN) - if not isinstance(st, ir.IdentifiedStructType) or st.elements is None: - return None - offset = Gen._get_member_offset(Node.attr, CN) - if offset is None: - return None - return self._gep_and_load_member(Gen, ObjVal, offset, Node.attr, CN, st) - - # ========== 主入口 ========== - - def _HandleAttributeLlvm(self, Node): - Gen = self.Trans.LlvmGen - - if isinstance(Node.value, ast.Name): - VarName = Node.value.id - # 处理 t/c import 的别名重定向 - t_c_imported = getattr(self.Trans, '_t_c_imported_names', {}) - if VarName != 'self' and VarName in t_c_imported: - src_module, src_name = t_c_imported[VarName] - virtual_attr = ast.Attribute( - value=ast.Name(id=src_module, ctx=ast.Load()), - attr=src_name, ctx=ast.Load() - ) - ast.copy_location(virtual_attr, Node) - return self._HandleAttributeLlvm(ast.Attribute( - value=virtual_attr, attr=Node.attr, ctx=ast.Load() - )) - if VarName == 'self': - return self._handle_attr_self(Node, VarName) - return self._handle_attr_name(Node, VarName) - - elif isinstance(Node.value, ast.Attribute): - return self._handle_attr_nested(Node) - - elif isinstance(Node.value, ast.Call): - return self._handle_attr_call_result(Node) - - elif isinstance(Node.value, ast.Subscript): - return self._handle_attr_subscript_result(Node) - - # 兜底 - return self._handle_attr_fallback(Node) - - # ========== HandleSubscript 及其辅助 ========== - - def _HandleSubscriptLlvm(self, Node): - Gen = self.Trans.LlvmGen - ClassName = self.Trans.ExprHandler._get_var_class(Node.value, Gen) - if ClassName and Gen._has_function(f'{ClassName}.__getitem__'): - obj_val = self.HandleExprLlvm(Node.value) - idx_val = self.HandleExprLlvm(Node.slice) - if obj_val and idx_val: - if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8: - obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") - if isinstance(idx_val.type, ir.IntType) and idx_val.type.width < 64: - idx_val = Gen.builder.zext(idx_val, ir.IntType(64), name="zext_idx") - result = Gen.builder.call(Gen._get_function(f'{ClassName}.__getitem__'), [obj_val, idx_val], name=f"call_{ClassName}.__getitem__") - return result - ValueVal = self.HandleExprLlvm(Node.value) - if not ValueVal: - return None - IndexVal = self.HandleExprLlvm(Node.slice) - if not IndexVal: - return None - if isinstance(IndexVal.type, ir.PointerType) and isinstance(IndexVal.type.pointee, ir.IntType) and IndexVal.type.pointee.width == 8: - loaded_byte = Gen._load(IndexVal, name="load_char_idx") - IndexVal = Gen.builder.zext(loaded_byte, ir.IntType(32), name="char_to_int_idx") - if isinstance(ValueVal.type, ir.IntType): - var_ptr = self._get_int_ptr(Node.value) - if var_ptr: - i8_ptr = Gen.builder.bitcast(var_ptr, ir.PointerType(ir.IntType(8)), name="int_to_i8ptr") - if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64: - IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_int_index") - ptr = Gen.builder.gep(i8_ptr, [IndexVal], name="int_subscript_ptr") - return Gen._load(ptr, name="int_subscript_val") - return None - if isinstance(ValueVal.type, ir.PointerType) and isinstance(ValueVal.type.pointee, ir.PointerType): - if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64: - IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_ptr_index") - ElemPtr = Gen.builder.gep(ValueVal, [IndexVal], name="subscript") - if isinstance(ValueVal.type.pointee.pointee, ir.IntType) and ValueVal.type.pointee.pointee.width == 8: - return Gen._load(ElemPtr, name="subscript_val") - return Gen._load(ElemPtr, name="subscript_val") - if isinstance(ValueVal.type, ir.PointerType): - pointee = ValueVal.type.pointee - if isinstance(pointee, ir.ArrayType): - zero = ir.Constant(ir.IntType(32), 0) - if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: - if IndexVal.type.width < 32: - IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") - else: - IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") - ElemPtr = Gen.builder.gep(ValueVal, [zero, IndexVal], name="subscript") - elem_type = pointee.element - if isinstance(elem_type, (ir.IdentifiedStructType, ir.LiteralStructType)): - return ElemPtr - return Gen._load(ElemPtr, name="subscript_val") - else: - if isinstance(pointee, ir.IntType) and pointee.width == 8: - elem_class = self._infer_element_struct_class(Node.value, Gen) - if elem_class and elem_class in Gen.structs: - CastedPtr = Gen.builder.bitcast(ValueVal, ir.PointerType(Gen.structs[elem_class]), name=f"cast_{elem_class}_arr") - if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64: - IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_arr_index") - ElemPtr = Gen.builder.gep(CastedPtr, [IndexVal], name="subscript") - if isinstance(pointee, ir.IntType): - return Gen._load(ElemPtr, name="subscript_val") - return ElemPtr - arr_type = self._infer_array_member_type(Node.value, Gen) - if arr_type and isinstance(arr_type, ir.ArrayType): - arr_ptr = Gen.builder.bitcast(ValueVal, ir.PointerType(arr_type), name=f"cast_arr_subscript") - zero = ir.Constant(ir.IntType(32), 0) - if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: - if IndexVal.type.width < 32: - IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") - else: - IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") - ElemPtr = Gen.builder.gep(arr_ptr, [zero, IndexVal], name="subscript") - arr_elem_type = arr_type.element - if isinstance(arr_elem_type, (ir.IdentifiedStructType, ir.LiteralStructType)): - return ElemPtr - return Gen._load(ElemPtr, name="subscript_val") - ElemPtr = Gen.builder.gep(ValueVal, [IndexVal], name="subscript") - if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): - return ElemPtr - return Gen._load(ElemPtr, name="subscript_val") - elif isinstance(ValueVal.type, ir.ArrayType): - zero = ir.Constant(ir.IntType(32), 0) - if isinstance(Node.value, ast.Name): - VarName = Node.value.id - if VarName in Gen.variables and Gen.variables[VarName] is not None: - VarPtr = Gen.variables[VarName] - if isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, ir.ArrayType): - if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: - if IndexVal.type.width < 32: - IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") - else: - IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") - ElemPtr = Gen.builder.gep(VarPtr, [zero, IndexVal], name="subscript") - var_arr_elem_type = VarPtr.type.pointee.element - if isinstance(var_arr_elem_type, (ir.IdentifiedStructType, ir.LiteralStructType)): - return ElemPtr - return Gen._load(ElemPtr, name="subscript_val") - if isinstance(Node.value, ast.Attribute): - AttrPtr = self._get_attr_ptr(Node.value) - if AttrPtr and isinstance(AttrPtr.type, ir.PointerType) and isinstance(AttrPtr.type.pointee, ir.ArrayType): - if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: - if IndexVal.type.width < 32: - IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") - else: - IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") - ElemPtr = Gen.builder.gep(AttrPtr, [zero, IndexVal], name="subscript") - attr_arr_elem_type = AttrPtr.type.pointee.element - if isinstance(attr_arr_elem_type, (ir.IdentifiedStructType, ir.LiteralStructType)): - return ElemPtr - return Gen._load(ElemPtr, name="subscript_val") - if isinstance(Node.value, ast.Subscript): - InnerPtr = self.HandleSubscriptPtrLlvm(Node.value) - if InnerPtr and isinstance(InnerPtr.type, ir.PointerType): - inner_pointee = InnerPtr.type.pointee - if isinstance(inner_pointee, ir.ArrayType): - if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: - if IndexVal.type.width < 32: - IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") - else: - IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") - ElemPtr = Gen.builder.gep(InnerPtr, [zero, IndexVal], name="subscript") - inner_elem_type = inner_pointee.element - if isinstance(inner_elem_type, (ir.IdentifiedStructType, ir.LiteralStructType)): - return ElemPtr - return Gen._load(ElemPtr, name="subscript_val") - arr_alloc = Gen._alloca_entry(ValueVal.type, name="arr_subscript_tmp") - Gen._store(ValueVal, arr_alloc) - ElemPtr = Gen.builder.gep(arr_alloc, [zero, IndexVal], name="subscript") - alloc_arr_elem_type = ValueVal.type.element - if isinstance(alloc_arr_elem_type, (ir.IdentifiedStructType, ir.LiteralStructType)): - return ElemPtr - return Gen._load(ElemPtr, name="subscript_val") - return None - - def HandleSubscriptPtrLlvm(self, Node): - Gen = self.Trans.LlvmGen - ValueVal = self.HandleExprLlvm(Node.value) - if not ValueVal: - return None - IndexVal = self.HandleExprLlvm(Node.slice) - if not IndexVal: - return None - if isinstance(IndexVal.type, ir.PointerType) and isinstance(IndexVal.type.pointee, ir.IntType) and IndexVal.type.pointee.width == 8: - loaded_byte = Gen._load(IndexVal, name="load_char_idx_ptr") - IndexVal = Gen.builder.zext(loaded_byte, ir.IntType(32), name="char_to_int_idx_ptr") - if isinstance(ValueVal.type, ir.PointerType): - pointee = ValueVal.type.pointee - if isinstance(pointee, ir.ArrayType): - zero = ir.Constant(ir.IntType(32), 0) - if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: - if IndexVal.type.width < 32: - IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") - else: - IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") - ElemPtr = Gen.builder.gep(ValueVal, [zero, IndexVal], name="subscript_ptr") - return ElemPtr - elif isinstance(pointee, ir.PointerType): - if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64: - IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_ptr_index_ptr") - ElemPtr = Gen.builder.gep(ValueVal, [IndexVal], name="subscript_ptr") - return ElemPtr - else: - if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64: - IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_ptr_index") - ElemPtr = Gen.builder.gep(ValueVal, [IndexVal], name="subscript_ptr") - return ElemPtr - elif isinstance(ValueVal.type, ir.IntType): - var_ptr = self._get_int_ptr(Node.value) - if var_ptr: - i8_ptr = Gen.builder.bitcast(var_ptr, ir.PointerType(ir.IntType(8)), name="int_to_i8ptr") - if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64: - IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_int_index") - ElemPtr = Gen.builder.gep(i8_ptr, [IndexVal], name="int_subscript_ptr") - return ElemPtr - elif isinstance(ValueVal.type, ir.ArrayType): - zero = ir.Constant(ir.IntType(32), 0) - if isinstance(Node.value, ast.Name): - VarName = Node.value.id - if VarName in Gen.variables and Gen.variables[VarName] is not None: - VarPtr = Gen.variables[VarName] - if isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, ir.ArrayType): - if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: - if IndexVal.type.width < 32: - IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") - else: - IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") - ElemPtr = Gen.builder.gep(VarPtr, [zero, IndexVal], name="subscript_ptr") - return ElemPtr - if isinstance(Node.value, ast.Subscript): - InnerPtr = self.HandleSubscriptPtrLlvm(Node.value) - if InnerPtr: - if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: - if IndexVal.type.width < 32: - IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") - else: - IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") - ElemPtr = Gen.builder.gep(InnerPtr, [zero, IndexVal], name="subscript_ptr") - return ElemPtr - if isinstance(Node.value, ast.Attribute): - AttrPtr = self._get_attr_ptr(Node.value) - if AttrPtr and isinstance(AttrPtr.type, ir.PointerType) and isinstance(AttrPtr.type.pointee, ir.ArrayType): - if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: - if IndexVal.type.width < 32: - IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") - else: - IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") - ElemPtr = Gen.builder.gep(AttrPtr, [zero, IndexVal], name="subscript_ptr") - return ElemPtr - arr_alloc = Gen._alloca_entry(ValueVal.type, name="arr_subscript_tmp") - Gen._store(ValueVal, arr_alloc) - ElemPtr = Gen.builder.gep(arr_alloc, [zero, IndexVal], name="subscript_ptr") - return ElemPtr - return None - - # ========== _get_attr_ptr / _get_int_ptr / _get_attr_class ========== - - def _get_attr_ptr(self, Node): - Gen = self.Trans.LlvmGen - if not isinstance(Node, ast.Attribute): - return None - if isinstance(Node.value, ast.Name): - VarName = Node.value.id - if VarName == 'self': - ClassName = self.Trans._CurrentCpythonObjectClass - if ClassName: - offset = Gen._get_member_offset(Node.attr, ClassName) - SelfVar = Gen._get_var_ptr('self') - if SelfVar: - SelfPtr = Gen._load(SelfVar, name="self") - if isinstance(SelfPtr.type, ir.PointerType): - MemberPtr = Gen.builder.gep(SelfPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=Node.attr) - return MemberPtr - ClassName = Gen.var_struct_class.get(VarName) - if not ClassName and getattr(Gen, 'global_struct_class', None): - ClassName = Gen.global_struct_class.get(VarName) - if not ClassName: - imported_modules = getattr(self.Trans, '_imported_modules', None) - import_aliases = getattr(self.Trans, '_import_aliases', {}) - resolved_mod = import_aliases.get(VarName, VarName) - if imported_modules and (VarName in imported_modules or resolved_mod in imported_modules): - AttrName = Node.attr - module_sha1_map = getattr(Gen, 'module_sha1_map', {}) - candidates = [VarName, resolved_mod] - for mod_name in imported_modules: - if mod_name.endswith(f".{VarName}") or mod_name == VarName: - if mod_name not in candidates: - candidates.append(mod_name) - for cand in candidates: - sha1 = module_sha1_map.get(cand) - if sha1: - prefixed = f"{sha1}.{AttrName}" - if prefixed in Gen.module.globals: - return Gen.module.globals[prefixed] - if AttrName in Gen.module.globals: - gv = Gen.module.globals[AttrName] - if isinstance(gv, ir.GlobalVariable): - return gv - if ClassName and ClassName in Gen.structs: - VarPtr = Gen.variables.get(VarName) - if VarPtr: - ObjVal = VarPtr - if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType): - ObjVal = Gen._load(ObjVal, name=f"load_{VarName}") - if isinstance(ObjVal.type, ir.PointerType) and ObjVal.type.pointee == Gen.structs[ClassName]: - ST = Gen.structs[ClassName] - if isinstance(ST, ir.IdentifiedStructType) and (ST.elements is None or len(ST.elements) == 0): - self.Trans.ImportHandler._TryLoadStructFromStub(ClassName, Gen) - ST = Gen.structs.get(ClassName, ST) - if ST.elements is not None and isinstance(ObjVal.type.pointee, ir.IdentifiedStructType) and ObjVal.type.pointee.elements is None: - ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(ST), name=f"cast_{ClassName}") - offset = Gen._get_member_offset(Node.attr, ClassName) - if offset is not None and ST.elements is not None: - MemberPtr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=Node.attr) - return MemberPtr - elif isinstance(Node.value, ast.Attribute): - InnerPtr = self._get_attr_ptr(Node.value) - if InnerPtr and isinstance(InnerPtr.type, ir.PointerType): - pointee = InnerPtr.type.pointee - if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): - found = Gen.find_struct_by_pointee(pointee) - if found: - CN, ST = found - if isinstance(ST, ir.IdentifiedStructType) and (ST.elements is None or len(ST.elements) == 0): - self.Trans.ImportHandler._TryLoadStructFromStub(CN, Gen) - ST = Gen.structs.get(CN, ST) - if ST.elements is not None and isinstance(InnerPtr.type, ir.PointerType) and isinstance(InnerPtr.type.pointee, ir.IdentifiedStructType) and InnerPtr.type.pointee.elements is None: - InnerPtr = Gen.builder.bitcast(InnerPtr, ir.PointerType(ST), name=f"cast_{CN}") - offset = Gen._get_member_offset(Node.attr, CN) - if offset is not None and ST.elements is not None: - MemberPtr = Gen.builder.gep(InnerPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=Node.attr) - return MemberPtr - elif isinstance(pointee, ir.IntType) and pointee.width == 8: - AttrClassName = self._get_attr_class(Node.value, Gen) - if AttrClassName and AttrClassName in Gen.structs: - CastedObj = Gen.builder.bitcast(InnerPtr, ir.PointerType(Gen.structs[AttrClassName]), name=f"cast_{AttrClassName}") - offset = Gen._get_member_offset(Node.attr, AttrClassName) - if offset is not None: - MemberPtr = Gen.builder.gep(CastedObj, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=Node.attr) - return MemberPtr - elif isinstance(Node.value, ast.Subscript): - SubPtr = self.HandleSubscriptPtrLlvm(Node.value) - if SubPtr and isinstance(SubPtr.type, ir.PointerType): - pointee = SubPtr.type.pointee - if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): - found = Gen.find_struct_by_pointee(pointee) - if found: - CN, ST = found - offset = Gen._get_member_offset(Node.attr, CN) - if offset is not None: - MemberPtr = Gen.builder.gep(SubPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=Node.attr) - return MemberPtr - return None - - def _HandleSliceLlvm(self, base_val, slice_node, base_ast): - Gen = self.Trans.LlvmGen - lower_val = None - upper_val = None - step_val = None - if isinstance(slice_node, ast.Slice): - if slice_node.lower: - lower_val = self.HandleExprLlvm(slice_node.lower) - if slice_node.upper: - upper_val = self.HandleExprLlvm(slice_node.upper) - if slice_node.step: - step_val = self.HandleExprLlvm(slice_node.step) - if isinstance(slice_node, ast.Index): - return self.HandleExprLlvm(slice_node.value) - return None - - def _infer_element_struct_class(self, node, Gen): - if isinstance(node, ast.Attribute): - attr_name = node.attr - if isinstance(node.value, ast.Name) and node.value.id == 'self': - current_class = self.Trans._CurrentCpythonObjectClass - if current_class: - if current_class in Gen.class_member_element_class: - elem_class = Gen.class_member_element_class[current_class].get(attr_name) - if elem_class and elem_class in Gen.structs: - return elem_class - if current_class in Gen.class_members: - for member_name, member_type in Gen.class_members[current_class]: - if member_name == attr_name: - if isinstance(member_type, ir.IdentifiedStructType): - found = Gen.find_struct_by_pointee(member_type) - if found: - return found[0] - break - class_name = Gen.var_struct_class.get(attr_name) - if class_name: - return class_name - elif isinstance(node, ast.Name): - var_name = node.id - class_name = Gen.var_struct_class.get(var_name) - if class_name: - return class_name - return None - - def _get_int_ptr(self, target): - Gen = self.Trans.LlvmGen - if isinstance(target, ast.Name): - VarName = target.id - if VarName in Gen.variables and Gen.variables[VarName] is not None: - VarPtr = Gen.variables[VarName] - if isinstance(VarPtr.type, ir.PointerType): - pointee = VarPtr.type.pointee - if isinstance(pointee, ir.ArrayType): - return Gen.builder.gep(VarPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"arr_start_{VarName}") - return VarPtr - elif isinstance(target, ast.Attribute): - if isinstance(target.value, ast.Name): - obj_name = target.value.id - if obj_name in Gen.variables and Gen.variables[obj_name] is not None: - obj_ptr = Gen.variables[obj_name] - if isinstance(obj_ptr.type, ir.PointerType): - pointee = obj_ptr.type.pointee - if isinstance(pointee, ir.PointerType): - obj_ptr = Gen._load(obj_ptr, name=f"load_{obj_name}") - pointee = obj_ptr.type.pointee - if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): - StructName = None - if isinstance(pointee, ir.IdentifiedStructType): - StructName = pointee.name - if not StructName: - found = Gen.find_struct_by_pointee(pointee) - if found: - StructName = found[0] - if StructName and StructName in Gen.structs: - offset = Gen._get_member_offset(target.attr, StructName) - if offset is not None: - return Gen.builder.gep(obj_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=f"{target.attr}_ptr") - obj_val = self.HandleExprLlvm(target.value) - if obj_val and isinstance(obj_val.type, ir.PointerType): - if isinstance(obj_val.type.pointee, ir.PointerType): - obj_val = Gen._load(obj_val, name="load_attr_ptr") - pointee = obj_val.type.pointee - if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): - StructName = None - if isinstance(pointee, ir.IdentifiedStructType): - StructName = pointee.name - if not StructName: - found = Gen.find_struct_by_pointee(pointee) - if found: - StructName = found[0] - if StructName and StructName in Gen.structs: - offset = Gen._get_member_offset(target.attr, StructName) - if offset is not None: - return Gen.builder.gep(obj_val, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=f"{target.attr}_ptr") - return None - - def _resolve_struct_class_for_attr(self, Node, Gen): - if isinstance(Node, ast.Name): - VarName = Node.id - if VarName in Gen.var_struct_class: - return Gen.var_struct_class[VarName] - elif isinstance(Node, ast.Attribute): - ClassName = self._resolve_struct_class_for_attr(Node.value, Gen) - if ClassName and ClassName in Gen.class_members: - for member_name, _ in Gen.class_members[ClassName]: - if member_name == Node.attr: - return ClassName - return None - - def _infer_array_member_type(self, Node, Gen): - if isinstance(Node, ast.Attribute): - parent_class = self._get_attr_class(Node, Gen) - if parent_class and parent_class in Gen.class_members: - for m_name, m_type in Gen.class_members[parent_class]: - if m_name == Node.attr and isinstance(m_type, ir.ArrayType): - return m_type - if parent_class and parent_class in Gen.structs: - st = Gen.structs[parent_class] - if isinstance(st, ir.IdentifiedStructType) and st.elements is not None: - offset = Gen._get_member_offset(Node.attr, parent_class) - if offset is not None and offset < len(st.elements): - elem = st.elements[offset] - if isinstance(elem, ir.ArrayType): - return elem - return None - - def _build_attr_path(self, node): - parts = [] - current = node - while isinstance(current, ast.Attribute): - parts.append(current.attr) - current = current.value - if isinstance(current, ast.Name): - parts.append(current.id) - parts.reverse() - return parts - - def _try_resolve_nested_cdefine(self, Node): - Gen = self.Trans.LlvmGen - imported_modules = getattr(self.Trans, '_imported_modules', None) - if not imported_modules: - return None - import_aliases = getattr(self.Trans, '_import_aliases', {}) - parts = self._build_attr_path(Node) - if len(parts) < 2: - return None - attr_name = parts[-1] - module_parts = parts[:-1] - possible_keys = [attr_name] - full_path = '.'.join(parts) - possible_keys.append(full_path) - if module_parts: - module_path = '.'.join(module_parts) - resolved_first = import_aliases.get(module_parts[0], module_parts[0]) - if resolved_first != module_parts[0]: - resolved_parts = [resolved_first] + module_parts[1:] - resolved_path = '.'.join(resolved_parts) - possible_keys.append(f"{resolved_path}.{attr_name}") - for mod_name in imported_modules: - if mod_name.endswith('.' + module_path) or mod_name == module_path: - key = f"{mod_name}.{attr_name}" - if key not in possible_keys: - possible_keys.append(key) - if module_parts and (mod_name.endswith('.' + module_parts[-1]) or mod_name == module_parts[-1]): - key = f"{mod_name}.{attr_name}" - if key not in possible_keys: - possible_keys.append(key) - for lookup_key in possible_keys: - SymInfo = self.Trans.SymbolTable.get(lookup_key) - if SymInfo and getattr(SymInfo, 'IsDefine', None) and getattr(SymInfo, 'DefineValue', None) is not None: - val = SymInfo.DefineValue - if isinstance(val, int): - if val > 0x7FFFFFFF or val < -0x80000000: - return ir.Constant(ir.IntType(64), val & 0xFFFFFFFFFFFFFFFF) - return ir.Constant(ir.IntType(32), val) - elif isinstance(val, float): - return ir.Constant(ir.FloatType(), val) - return None - - def _try_resolve_cross_module_enum(self, module_alias, enum_class_name, member_name): - Gen = self.Trans.LlvmGen - imported_modules = getattr(self.Trans, '_imported_modules', None) - if not imported_modules: - return None - import_aliases = getattr(self.Trans, '_import_aliases', {}) - resolved_module = import_aliases.get(module_alias, module_alias) - if resolved_module not in imported_modules and module_alias not in imported_modules: - return None - enum_keys = [enum_class_name, f"{resolved_module}.{enum_class_name}"] - for enum_key in enum_keys: - if enum_key in self.Trans.SymbolTable: - SymInfo = self.Trans.SymbolTable[enum_key] - if getattr(SymInfo, 'IsEnum', None): - for qname in (f"{enum_key}.{member_name}", f"{enum_key}_{member_name}"): - if qname in self.Trans.SymbolTable: - info = self.Trans.SymbolTable[qname] - if getattr(info, 'IsEnumMember', None) and isinstance(getattr(info, 'value', None), int): - return ir.Constant(ir.IntType(32), info.value) - for key, info in self.Trans.SymbolTable.items(): - if getattr(info, 'IsEnumMember', None) and getattr(info, 'EnumName', None) == enum_key and key == member_name: - if isinstance(getattr(info, 'value', None), int): - return ir.Constant(ir.IntType(32), info.value) - for key, info in self.Trans.SymbolTable.items(): - if getattr(info, 'IsEnumMember', None) and key == member_name: - if isinstance(getattr(info, 'value', None), int): - for enum_key in enum_keys: - if getattr(info, 'EnumName', None) == enum_key: - return ir.Constant(ir.IntType(32), info.value) - return None - - def _get_attr_class(self, Node, Gen): - if isinstance(Node, ast.Attribute): - # 注: 不再硬编码 ZLIB_VERSION / C_OK,它们应从符号表查找 - if isinstance(Node.value, ast.Name) and Node.value.id == 'self': - ClassName = self.Trans._CurrentCpythonObjectClass - if ClassName and ClassName in Gen.class_member_element_class: - return Gen.class_member_element_class[ClassName].get(Node.attr) - if isinstance(Node.value, ast.Name): - VarName = Node.value.id - if VarName in Gen.var_struct_class: - ParentClass = Gen.var_struct_class[VarName] - if ParentClass in Gen.class_member_element_class: - return Gen.class_member_element_class[ParentClass].get(Node.attr) - if isinstance(Node.value, ast.Attribute): - ParentClass = self._get_attr_class(Node.value, Gen) - if ParentClass and ParentClass in Gen.class_member_element_class: - return Gen.class_member_element_class[ParentClass].get(Node.attr) - return None - - def _get_llvm_member_offset(self, field_name, ClassName, Gen): - return Gen._get_member_offset(field_name, ClassName) - - def _load_bitfield_member(self, struct_ptr, ClassName, field_name): - Gen = self.Trans.LlvmGen - bitfield_offsets = Gen.class_member_bitoffsets.get(ClassName, {}) - bitfield_widths = Gen.class_member_bitfields.get(ClassName, {}) - if field_name not in bitfield_offsets: - return None - bit_offset = bitfield_offsets[field_name] - bit_width = bitfield_widths.get(field_name, 0) - if bit_width == 0: - return None - struct_type = Gen.structs.get(ClassName) - if struct_type is None or struct_type.elements is None or len(struct_type.elements) == 0: - return None - storage_type = struct_type.elements[0] - member_ptr = Gen.builder.gep(struct_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{field_name}_storage_ptr") - storage_val = Gen._load(member_ptr, name=f"{field_name}_storage") - shift_amount = bit_offset - if shift_amount > 0: - shifted = Gen.builder.lshr(storage_val, ir.Constant(storage_type, shift_amount), name=f"{field_name}_shift") - else: - shifted = storage_val - mask = (1 << bit_width) - 1 - masked = Gen.builder.and_(shifted, ir.Constant(storage_type, mask), name=f"{field_name}_mask") - is_signed = Gen.class_member_signeds.get(ClassName, {}).get(field_name, False) - if is_signed and bit_width > 0: - sign_bit = 1 << (bit_width - 1) - sign_masked = Gen.builder.and_(shifted, ir.Constant(storage_type, sign_bit), name=f"{field_name}_sign") - sign_extend = Gen.builder.icmp_signed('!=', sign_masked, ir.Constant(storage_type, 0), name=f"{field_name}_sign_check") - extended = Gen.builder.select(sign_extend, - Gen.builder.sext(masked, ir.IntType(32), name=f"{field_name}_sext"), - Gen.builder.zext(masked, ir.IntType(32), name=f"{field_name}_zext"), - name=f"{field_name}_extend") - return extended +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle, FuncMeta +import ast +import llvmlite.ir as ir + + +class ExprAttrHandle(BaseHandle): + + # ========== 辅助方法 ========== + + def _apply_bswap_on_Load(self, val, ClassName, AttrName): + Gen = self.Trans.LlvmGen + byte_order = getattr(Gen, 'class_member_byteorders', {}).get(ClassName, {}).get(AttrName, "") + if byte_order == 'big' and isinstance(val.type, ir.IntType): + if val.type.width in (16, 32, 64): + val = Gen.builder.bswap(val, name=f"bswap_Load_{AttrName}") + return val + + def _gep_and_Load_member(self, Gen, ObjVal, offset, AttrName, ClassName, ST=None): + """从结构体指针通过 GEP 取成员,处理 array/struct pointer/class_members 特殊情况""" + if offset is None: + return None + if isinstance(ObjVal.type, ir.PointerType): + pointee = ObjVal.type.pointee + if isinstance(pointee, ir.IdentifiedStructType) and pointee.elements is not None and offset >= len(pointee.elements): + return None + MemberPtr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) + if isinstance(MemberPtr.type, ir.PointerType) and isinstance(MemberPtr.type.pointee, ir.ArrayType): + return MemberPtr + if isinstance(MemberPtr.type, ir.PointerType) and isinstance(MemberPtr.type.pointee, ir.IdentifiedStructType): + return MemberPtr + # 检查 pointer-to-pointer 且实际元素是 ArrayType + if isinstance(MemberPtr.type, ir.PointerType) and isinstance(MemberPtr.type.pointee, ir.PointerType): + actual_elem_type = None + if ST is not None and isinstance(ST, ir.IdentifiedStructType) and ST.elements is not None and offset < len(ST.elements): + actual_elem_type = ST.elements[offset] + if isinstance(actual_elem_type, ir.ArrayType): + return Gen.builder.bitcast(MemberPtr, ir.PointerType(actual_elem_type), name=f"cast_arr_{AttrName}") + # 检查 class_members 中的 ArrayType + if ClassName in Gen.class_members: + for member_name, member_type in Gen.class_members[ClassName]: + if member_name == AttrName and isinstance(member_type, ir.ArrayType): + return Gen.builder.bitcast(MemberPtr, ir.PointerType(member_type), name=f"cast_arr_{AttrName}") + val = Gen._load(MemberPtr, name=AttrName) + return self._apply_bswap_on_Load(val, ClassName, AttrName) + + def _try_Load_struct_from_stub(self, Gen, ClassName): + """尝试从 stub 加载结构体定义,返回 (struct_type, ok)""" + if ClassName not in Gen.structs: + return None, False + st = Gen.structs[ClassName] + if isinstance(st, ir.IdentifiedStructType) and (st.elements is None or len(st.elements) == 0): + self.Trans.ImportHandler._TryLoadStructFromStub(ClassName, Gen) + st = Gen.structs.get(ClassName, st) + if isinstance(st, ir.IdentifiedStructType) and (st.elements is None or len(st.elements) == 0): + return st, False + return st, True + + def _make_define_constant(self, Gen, val): + """将 CDefine 值转为 LLVM 常量""" + if isinstance(val, int): + if abs(val) > 2147483647: + return ir.Constant(ir.IntType(64), val) + return ir.Constant(ir.IntType(32), val) + elif isinstance(val, float): + return ir.Constant(ir.DoubleType(), val) + elif isinstance(val, str): + str_value = val + '\x00' + str_bytes = str_value.encode('utf-8') + str_type = ir.ArrayType(ir.IntType(8), len(str_bytes)) + gv_name = f"str_const_{Gen.string_const_counter}" + gv = ir.GlobalVariable(Gen.module, str_type, name=gv_name) + gv.initializer = ir.Constant(str_type, bytearray(str_bytes)) + gv.linkage = 'internal' + Gen.string_const_counter += 1 + return Gen.builder.gep(gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{gv_name}_cast") + return None + + def _lookup_cdefine(self, Gen, VarName, AttrName): + """在符号表和模块中查找 CDefine 常量值""" + imported_modules = getattr(self.Trans, '_ImportedModules', None) + if not imported_modules: + return None + PossibleKeys = [f"{VarName}.{AttrName}", AttrName] + for mod_name in imported_modules: + if mod_name.endswith(f".{VarName}") or mod_name == VarName: + key = f"{mod_name}.{AttrName}" + if key not in PossibleKeys: + PossibleKeys.append(key) + for lookup_key in PossibleKeys: + SymInfo = self.Trans.SymbolTable.get(lookup_key) + if SymInfo and getattr(SymInfo, 'IsDefine', None) and getattr(SymInfo, 'DefineValue', None) is not None: + return self._make_define_constant(Gen, SymInfo.DefineValue) + # 也检查 _define_constants + define_constants = getattr(Gen, '_define_constants', {}) + for key in (f"{VarName}.{AttrName}", AttrName): + if key in define_constants: + return self._make_define_constant(Gen, define_constants[key]) + return None + + def _lookup_module_global(self, Gen, VarName, AttrName): + """在模块全局变量中查找 import 的属性""" + imported_modules = getattr(self.Trans, '_ImportedModules', None) + import_aliases = getattr(self.Trans, '_ImportAliases', {}) + if not imported_modules: + return None + resolved_mod = import_aliases.get(VarName, VarName) + if VarName not in imported_modules and resolved_mod not in imported_modules: + return None + PossibleKeys = [f"{VarName}.{AttrName}", AttrName] + for mod_name in imported_modules: + if mod_name.endswith(f".{VarName}") or mod_name == VarName: + key = f"{mod_name}.{AttrName}" + if key not in PossibleKeys: + PossibleKeys.append(key) + for key in PossibleKeys: + if key in Gen.module.globals: + GVar = Gen.module.globals[key] + if isinstance(GVar, ir.Function): + return GVar + if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): + return GVar + return Gen._load(GVar, name=AttrName) + # SHA1 前缀查找 + ModuleSha1Map = getattr(Gen, 'ModuleSha1Map', {}) + sha1_candidates = [VarName, resolved_mod] + for mod_name in imported_modules: + if mod_name.endswith(f".{VarName}") or mod_name == VarName: + if mod_name not in sha1_candidates: + sha1_candidates.append(mod_name) + for cand in sha1_candidates: + sha1 = ModuleSha1Map.get(cand) + if sha1: + prefixed = f"{sha1}.{AttrName}" + if prefixed in Gen.module.globals: + GVar2 = Gen.module.globals[prefixed] + if isinstance(GVar2, ir.Function): + return GVar2 + if isinstance(GVar2.type, ir.PointerType) and isinstance(GVar2.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): + return GVar2 + return Gen._load(GVar2, name=AttrName) + if AttrName in Gen.module.globals: + gv = Gen.module.globals[AttrName] + if AttrName in Gen.variables and Gen.variables[AttrName] is None: + str_gv_name = AttrName + '_str' + if str_gv_name in Gen.module.globals: + str_gv = Gen.module.globals[str_gv_name] + return Gen.builder.gep(str_gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{AttrName}_str_ptr") + return Gen.builder.load(gv, name=AttrName) + return None + + def _resolve_var_classname(self, Gen, VarName): + """根据变量名解析其结构体类名""" + ClassName = Gen.var_struct_class.get(VarName) + if not ClassName and getattr(Gen, 'global_struct_class', None): + ClassName = Gen.global_struct_class.get(VarName) + if ClassName: + Gen.var_struct_class[VarName] = ClassName + if not ClassName and VarName in Gen.module.globals: + GVar = Gen.module.globals[VarName] + if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): + found = Gen.find_struct_by_pointee(GVar.type.pointee) + if found: + ClassName = found[0] + Gen.var_struct_class[VarName] = ClassName + if getattr(Gen, 'global_struct_class', None): + Gen.global_struct_class[VarName] = ClassName + if not ClassName and VarName in Gen.variables: + VarPtr = Gen.variables[VarName] + if VarPtr is not None and isinstance(VarPtr.type, ir.PointerType): + pointee = VarPtr.type.pointee + if isinstance(pointee, ir.PointerType): + pointee = pointee.pointee + found = Gen.find_struct_by_pointee(pointee) + if found: + ClassName = found[0] + return ClassName + + def _check_struct_match(self, Gen, ObjVal, ClassName): + """检查 ObjVal 是否指向 ClassName 对应的结构体""" + if ClassName not in Gen.structs: + return False + if isinstance(ObjVal.type, ir.PointerType): + ST = Gen.structs[ClassName] + if ObjVal.type.pointee == ST: + return True + if isinstance(ObjVal.type.pointee, ir.IdentifiedStructType) and isinstance(ST, ir.IdentifiedStructType) and ObjVal.type.pointee.name == ST.name: + return True + return False + + # ========== _HandleAttributeLlvm 子方法 ========== + + def _handle_attr_self(self, Node, VarName): + """处理 self.xxx 属性访问""" + Gen = self.Trans.LlvmGen + ClassName = self.Trans._CurrentCpythonObjectClass + if not ClassName: + return None + # 检查 property getter + PropKey = f'{ClassName}.{Node.attr}' + PropInfo = self.Trans.SymbolTable.get(PropKey) + if PropInfo and hasattr(PropInfo, 'MetaList') and FuncMeta.PROPERTY_GETTER in PropInfo.MetaList: + SelfVar = Gen._get_var_ptr('self') + if SelfVar: + SelfPtr = Gen._load(SelfVar, name="self") + GetterFunc = Gen._get_function(PropKey) + if GetterFunc and SelfPtr: + return Gen.builder.call(GetterFunc, [SelfPtr], name=f"prop_{PropKey}") + offset = Gen._get_member_offset(Node.attr, ClassName) + SelfVar = Gen._get_var_ptr('self') + if not SelfVar: + return None + SelfPtr = Gen._load(SelfVar, name="self") + if not isinstance(SelfPtr.type, ir.PointerType): + return None + pointee = SelfPtr.type.pointee + if isinstance(pointee, ir.IdentifiedStructType) and pointee.elements is None: + for CN2, ST2 in Gen.structs.items(): + if isinstance(ST2, ir.IdentifiedStructType) and ST2.name == pointee.name and ST2.elements is not None: + pointee = ST2 + break + if isinstance(pointee, ir.IdentifiedStructType) and pointee.elements is not None and offset is not None and offset < len(pointee.elements): + if isinstance(pointee.elements[offset], ir.VoidType): + return None + return self._gep_and_Load_member(Gen, SelfPtr, offset, Node.attr, ClassName, pointee) + DynamicVarName = f"self.{Node.attr}" + if DynamicVarName in Gen.variables: + return Gen._load(Gen.variables[DynamicVarName], name=Node.attr) + return None + + def _handle_attr_enum(self, Node, VarName): + """处理枚举成员访问 (VarName 是枚举类型名)""" + SymInfo = self.Trans.SymbolTable.get(VarName) + if not SymInfo or not getattr(SymInfo, 'IsEnum', None): + return None + if Node.attr in self.Trans.SymbolTable: + MemberInfo = self.Trans.SymbolTable[Node.attr] + if getattr(MemberInfo, 'IsEnumMember', None) and getattr(MemberInfo, 'EnumName', None) == VarName: + if isinstance(getattr(MemberInfo, 'value', None), int): + return ir.Constant(ir.IntType(32), MemberInfo.value) + for key, info in self.Trans.SymbolTable.items(): + if getattr(info, 'IsEnumMember', None) and getattr(info, 'EnumName', None) == VarName and key == Node.attr: + if isinstance(getattr(info, 'value', None), int): + return ir.Constant(ir.IntType(32), info.value) + return None + + def _handle_attr_name(self, Node, VarName): + """处理 x.attr 形式 (x 是普通 Name)""" + Gen = self.Trans.LlvmGen + AttrName = Node.attr + + # 先尝试枚举成员 + result = self._handle_attr_enum(Node, VarName) + if result is not None: + return result + + # 尝试 CDefine 常量 + result = self._lookup_cdefine(Gen, VarName, AttrName) + if result is not None: + return result + + # 尝试 import 模块全局变量 + result = self._lookup_module_global(Gen, VarName, AttrName) + if result is not None: + return result + + # 尝试 attr 直接作为全局变量 + if AttrName in Gen.module.globals: + gv = Gen.module.globals[AttrName] + if AttrName in Gen.variables and Gen.variables[AttrName] is None: + str_gv_name = AttrName + '_str' + if str_gv_name in Gen.module.globals: + str_gv = Gen.module.globals[str_gv_name] + return Gen.builder.gep(str_gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{AttrName}_str_ptr") + return Gen.builder.load(gv, name=AttrName) + + # 解析结构体类名并访问成员 + ClassName = self._resolve_var_classname(Gen, VarName) + if not ClassName: + return None + + # 检查 property getter + PropKey = f'{ClassName}.{AttrName}' + PropInfo = self.Trans.SymbolTable.get(PropKey) + if PropInfo and hasattr(PropInfo, 'MetaList') and FuncMeta.PROPERTY_GETTER in PropInfo.MetaList: + ObjVal = self.HandleExprLlvm(Node.value) + GetterFunc = Gen._get_function(PropKey) + if GetterFunc and ObjVal: + if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType): + ObjVal = Gen._load(ObjVal, name=f"Load_{VarName}") + return Gen.builder.call(GetterFunc, [ObjVal], name=f"prop_{PropKey}") + + # 获取类型信息 + TypeInfo = self.Trans.SymbolTable.get(ClassName) + IsUnion = TypeInfo.IsUnion if TypeInfo else False + IsCenum = TypeInfo.IsEnum if TypeInfo else False + IsRenum = getattr(TypeInfo, 'IsRenum', False) if TypeInfo else False + + # REnum 处理 + if IsRenum: + if AttrName == 'tag': + ObjVal = self.HandleExprLlvm(Node.value) + if ObjVal: + if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType): + ObjVal = Gen._load(ObjVal, name=f"Load_{VarName}") + tag_ptr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="tag_ptr") + return Gen._load(tag_ptr, name="tag_val") + NestedStructName = f"{ClassName}_{AttrName}" + if NestedStructName in Gen.structs: + NestedStructType = Gen.structs[NestedStructName] + ObjVal = self.HandleExprLlvm(Node.value) + if ObjVal: + if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType): + ObjVal = Gen._load(ObjVal, name=f"Load_{VarName}") + return Gen.builder.bitcast(ObjVal, ir.PointerType(NestedStructType), name=f"cast_{NestedStructName}") + + # CEnum 处理 + if IsCenum: + for qname in (f"{ClassName}.{AttrName}", f"{ClassName}_{AttrName}"): + if qname in self.Trans.SymbolTable: + info = self.Trans.SymbolTable[qname] + if getattr(info, 'IsEnumMember', None) and isinstance(getattr(info, 'value', None), int): + return ir.Constant(ir.IntType(32), info.value) + for key, info in self.Trans.SymbolTable.items(): + if key == AttrName: + if getattr(info, 'IsEnumMember', None) and getattr(info, 'EnumName', None) == ClassName: + if isinstance(getattr(info, 'value', None), int): + return ir.Constant(ir.IntType(32), info.value) + break + + # CUnion 处理 + if IsUnion: + NestedStructName = f"{ClassName}_{AttrName}" + if NestedStructName in Gen.structs: + NestedStructType = Gen.structs[NestedStructName] + ObjVal = self.HandleExprLlvm(Node.value) + if ObjVal: + if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType): + ObjVal = Gen._load(ObjVal, name=f"Load_{VarName}") + return Gen.builder.bitcast(ObjVal, ir.PointerType(NestedStructType), name=f"cast_{NestedStructName}") + + # 普通结构体成员访问 + ObjVal = self.HandleExprLlvm(Node.value) + if not ObjVal: + return None + # char* → struct* cast + if self._is_char_pointer(ObjVal): + if ClassName in Gen.structs: + ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") + # 二级指针解引用 + if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType): + ObjVal = Gen._load(ObjVal, name=f"Load_{VarName}") + + # 检查结构体匹配 + struct_match = self._check_struct_match(Gen, ObjVal, ClassName) + if not struct_match and ClassName and VarName: + if VarName in Gen.var_struct_class: + CN = Gen.var_struct_class[VarName] + if CN != ClassName and CN in Gen.structs: + ClassName = CN + struct_match = self._check_struct_match(Gen, ObjVal, ClassName) + if not struct_match: + return None + + st, ok = self._try_Load_struct_from_stub(Gen, ClassName) + if not ok: + return None + + # bitfield 处理 + bitfield_offsets = Gen.class_member_bitoffsets.get(ClassName, {}) + bitfields = Gen.class_member_bitfields.get(ClassName, {}) + if AttrName in bitfield_offsets and bitfields.get(AttrName, 0) > 0: + return self._load_bitfield_member(ObjVal, ClassName, AttrName) + if AttrName in bitfields and bitfields[AttrName] > 0: + if ClassName not in Gen.class_member_bitoffsets: + Gen.class_member_bitoffsets[ClassName] = {} + if AttrName not in Gen.class_member_bitoffsets[ClassName]: + bo = 0 + for bf_name, bf_width in bitfields.items(): + if bf_name == AttrName: + break + bo += bf_width + Gen.class_member_bitoffsets[ClassName][AttrName] = bo + return self._load_bitfield_member(ObjVal, ClassName, AttrName) + + offset = Gen._get_member_offset(AttrName, ClassName) + # 检查 offset 是否超出实际结构体 + if isinstance(ObjVal.type, ir.PointerType): + actual_pointee = ObjVal.type.pointee + if isinstance(actual_pointee, ir.IdentifiedStructType): + actual_elems = actual_pointee.elements + if actual_elems is not None and offset is not None and offset >= len(actual_elems): + self.Trans.ImportHandler._TryLoadStructFromStub(ClassName, Gen) + actual_elems = actual_pointee.elements + if actual_elems is not None and offset >= len(actual_elems): + return None + return self._gep_and_Load_member(Gen, ObjVal, offset, AttrName, ClassName, st) + + def _handle_attr_nested(self, Node): + """处理 a.b.c 嵌套属性访问""" + Gen = self.Trans.LlvmGen + if isinstance(Node.value.value, ast.Name): + ParentVarName = Node.value.value.id + ParentAttrName = Node.value.attr + enum_result = self._try_resolve_cross_module_enum(ParentVarName, ParentAttrName, Node.attr) + if enum_result is not None: + return enum_result + # 尝试跨模块子模块全局变量解析: a.b.c 其中 a.b 是已知子模块, c 是该模块的全局变量 + imported_modules = getattr(self.Trans, '_ImportedModules', None) + if imported_modules: + full_ModulePath = f"{ParentVarName}.{ParentAttrName}" + if full_ModulePath in imported_modules: + result = self._lookup_module_global(Gen, full_ModulePath, Node.attr) + if result is not None: + return result + cdefine_result = self._try_resolve_nested_cdefine(Node) + if cdefine_result is not None: + return cdefine_result + ObjVal = self.HandleExprLlvm(Node.value) + if not ObjVal or not isinstance(ObjVal.type, ir.PointerType): + return None + pointee = ObjVal.type.pointee + + # char* → struct* cast + 成员访问 + if isinstance(pointee, ir.IntType) and pointee.width == 8: + AttrClassName = self._get_attr_class(Node.value, Gen) + if AttrClassName and AttrClassName in Gen.structs: + st, ok = self._try_Load_struct_from_stub(Gen, AttrClassName) + if not isinstance(st, ir.IdentifiedStructType) or st.elements is None: + return None + CastedObj = Gen.builder.bitcast(ObjVal, ir.PointerType(st), name=f"cast_{AttrClassName}") + offset = Gen._get_member_offset(Node.attr, AttrClassName) + if offset is None: + return None + if offset < len(st.elements) and isinstance(st.elements[offset], ir.VoidType): + return None + return self._gep_and_Load_member(Gen, CastedObj, offset, Node.attr, AttrClassName, st) + + # 已知结构体类型 → 直接成员访问 + if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): + for CN, ST in Gen.structs.items(): + if pointee == ST or (isinstance(pointee, ir.IdentifiedStructType) and isinstance(ST, ir.IdentifiedStructType) and pointee.name == ST.name): + st, ok = self._try_Load_struct_from_stub(Gen, CN) + if not isinstance(st, ir.IdentifiedStructType) or st.elements is None: + break + bitfield_offsets = Gen.class_member_bitoffsets.get(CN, {}) + if Node.attr in bitfield_offsets: + return self._load_bitfield_member(ObjVal, CN, Node.attr) + offset = Gen._get_member_offset(Node.attr, CN) + if offset is None: + break + return self._gep_and_Load_member(Gen, ObjVal, offset, Node.attr, CN, st) + return None + + def _handle_attr_call_result(self, Node): + """处理 func().attr 属性访问""" + Gen = self.Trans.LlvmGen + # Check if this is c.Deref(...) — we need the pointer, not the Loaded value + ObjVal = None + is_cderef = (isinstance(Node.value, ast.Call) and + isinstance(Node.value.func, ast.Attribute) and + isinstance(Node.value.func.value, ast.Name) and + Node.value.func.value.id == 'c' and + Node.value.func.attr == 'Deref' and + Node.value.args) + if is_cderef: + deref_arg = Node.value.args[0] + inner_val = self.HandleExprLlvm(deref_arg) + if inner_val and isinstance(inner_val.type, ir.PointerType): + if isinstance(inner_val.type.pointee, ir.PointerType): + ObjVal = Gen._load(inner_val, name="deref_load_ptr") + else: + ObjVal = inner_val + if ObjVal is None: + ObjVal = self.HandleExprLlvm(Node.value) + if not ObjVal or not isinstance(ObjVal.type, ir.PointerType): + return None + pointee = ObjVal.type.pointee + if isinstance(pointee, ir.PointerType): + ObjVal = Gen._load(ObjVal, name="load_ptr_for_attr") + pointee = ObjVal.type.pointee + found = Gen.find_struct_by_pointee(pointee) + if not found: + return None + CN, ST = found + st, ok = self._try_Load_struct_from_stub(Gen, CN) + if not isinstance(st, ir.IdentifiedStructType) or st.elements is None: + return None + bitfield_offsets = Gen.class_member_bitoffsets.get(CN, {}) + if Node.attr in bitfield_offsets: + return self._load_bitfield_member(ObjVal, CN, Node.attr) + offset = Gen._get_member_offset(Node.attr, CN) + if offset is None: + return None + return self._gep_and_Load_member(Gen, ObjVal, offset, Node.attr, CN, st) + + def _handle_attr_subscript_result(self, Node): + """处理 arr[i].attr 属性访问""" + Gen = self.Trans.LlvmGen + ObjVal = self.HandleExprLlvm(Node.value) + if not ObjVal or not isinstance(ObjVal.type, ir.PointerType): + return None + pointee = ObjVal.type.pointee + if not isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): + return None + found = Gen.find_struct_by_pointee(pointee) + if not found: + return None + CN, ST = found + st, ok = self._try_Load_struct_from_stub(Gen, CN) + if not isinstance(st, ir.IdentifiedStructType) or st.elements is None: + return None + offset = Gen._get_member_offset(Node.attr, CN) + if offset is None: + return None + return self._gep_and_Load_member(Gen, ObjVal, offset, Node.attr, CN, st) + + def _handle_attr_fallback(self, Node): + """兜底:对任意值尝试指针解引用后查找结构体成员""" + Gen = self.Trans.LlvmGen + ObjVal = self.HandleExprLlvm(Node.value) + if not ObjVal or not isinstance(ObjVal.type, ir.PointerType): + return None + pointee = ObjVal.type.pointee + if isinstance(pointee, ir.PointerType): + ObjVal = Gen._load(ObjVal, name="load_ptr_for_attr_fallback") + pointee = ObjVal.type.pointee + if not isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): + return None + found = Gen.find_struct_by_pointee(pointee) + if not found: + return None + CN, ST = found + st, ok = self._try_Load_struct_from_stub(Gen, CN) + if not isinstance(st, ir.IdentifiedStructType) or st.elements is None: + return None + offset = Gen._get_member_offset(Node.attr, CN) + if offset is None: + return None + return self._gep_and_Load_member(Gen, ObjVal, offset, Node.attr, CN, st) + + # ========== 主入口 ========== + + def _HandleAttributeLlvm(self, Node): + Gen = self.Trans.LlvmGen + + if isinstance(Node.value, ast.Name): + VarName = Node.value.id + # 处理 t/c import 的别名重定向 + t_c_imported = getattr(self.Trans, '_t_c_imported_names', {}) + if VarName != 'self' and VarName in t_c_imported: + src_module, src_name = t_c_imported[VarName] + virtual_attr = ast.Attribute( + value=ast.Name(id=src_module, ctx=ast.Load()), + attr=src_name, ctx=ast.Load() + ) + ast.copy_location(virtual_attr, Node) + return self._HandleAttributeLlvm(ast.Attribute( + value=virtual_attr, attr=Node.attr, ctx=ast.Load() + )) + if VarName == 'self': + return self._handle_attr_self(Node, VarName) + return self._handle_attr_name(Node, VarName) + + elif isinstance(Node.value, ast.Attribute): + return self._handle_attr_nested(Node) + + elif isinstance(Node.value, ast.Call): + return self._handle_attr_call_result(Node) + + elif isinstance(Node.value, ast.Subscript): + return self._handle_attr_subscript_result(Node) + + # 兜底 + return self._handle_attr_fallback(Node) + + # ========== HandleSubscript 及其辅助 ========== + + def _HandleSubscriptLlvm(self, Node): + Gen = self.Trans.LlvmGen + ClassName = self.Trans.ExprHandler._get_var_class(Node.value, Gen) + if ClassName and Gen._has_function(f'{ClassName}.__getitem__'): + obj_val = self.HandleExprLlvm(Node.value) + idx_val = self.HandleExprLlvm(Node.slice) + if obj_val and idx_val: + if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8: + obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") + if isinstance(idx_val.type, ir.IntType) and idx_val.type.width < 64: + idx_val = Gen.builder.zext(idx_val, ir.IntType(64), name="zext_idx") + result = Gen.builder.call(Gen._get_function(f'{ClassName}.__getitem__'), [obj_val, idx_val], name=f"call_{ClassName}.__getitem__") + return result + ValueVal = self.HandleExprLlvm(Node.value) + if not ValueVal: + return None + IndexVal = self.HandleExprLlvm(Node.slice) + if not IndexVal: + return None + if isinstance(IndexVal.type, ir.PointerType) and isinstance(IndexVal.type.pointee, ir.IntType) and IndexVal.type.pointee.width == 8: + Loaded_byte = Gen._load(IndexVal, name="Load_char_idx") + IndexVal = Gen.builder.zext(Loaded_byte, ir.IntType(32), name="char_to_int_idx") + if isinstance(ValueVal.type, ir.IntType): + var_ptr = self._get_int_ptr(Node.value) + if var_ptr: + i8_ptr = Gen.builder.bitcast(var_ptr, ir.PointerType(ir.IntType(8)), name="int_to_i8ptr") + if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_int_index") + ptr = Gen.builder.gep(i8_ptr, [IndexVal], name="int_subscript_ptr") + return Gen._load(ptr, name="int_subscript_val") + return None + if isinstance(ValueVal.type, ir.PointerType) and isinstance(ValueVal.type.pointee, ir.PointerType): + if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_ptr_index") + ElemPtr = Gen.builder.gep(ValueVal, [IndexVal], name="subscript") + if isinstance(ValueVal.type.pointee.pointee, ir.IntType) and ValueVal.type.pointee.pointee.width == 8: + return Gen._load(ElemPtr, name="subscript_val") + return Gen._load(ElemPtr, name="subscript_val") + if isinstance(ValueVal.type, ir.PointerType): + pointee = ValueVal.type.pointee + if isinstance(pointee, ir.ArrayType): + zero = ir.Constant(ir.IntType(32), 0) + if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: + if IndexVal.type.width < 32: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") + else: + IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") + ElemPtr = Gen.builder.gep(ValueVal, [zero, IndexVal], name="subscript") + elem_type = pointee.element + if isinstance(elem_type, (ir.IdentifiedStructType, ir.LiteralStructType)): + return ElemPtr + return Gen._load(ElemPtr, name="subscript_val") + else: + if isinstance(pointee, ir.IntType) and pointee.width == 8: + elem_class = self._infer_element_struct_class(Node.value, Gen) + if elem_class and elem_class in Gen.structs: + CastedPtr = Gen.builder.bitcast(ValueVal, ir.PointerType(Gen.structs[elem_class]), name=f"cast_{elem_class}_arr") + if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_arr_index") + ElemPtr = Gen.builder.gep(CastedPtr, [IndexVal], name="subscript") + if isinstance(pointee, ir.IntType): + return Gen._load(ElemPtr, name="subscript_val") + return ElemPtr + arr_type = self._infer_array_member_type(Node.value, Gen) + if arr_type and isinstance(arr_type, ir.ArrayType): + arr_ptr = Gen.builder.bitcast(ValueVal, ir.PointerType(arr_type), name=f"cast_arr_subscript") + zero = ir.Constant(ir.IntType(32), 0) + if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: + if IndexVal.type.width < 32: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") + else: + IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") + ElemPtr = Gen.builder.gep(arr_ptr, [zero, IndexVal], name="subscript") + arr_elem_type = arr_type.element + if isinstance(arr_elem_type, (ir.IdentifiedStructType, ir.LiteralStructType)): + return ElemPtr + return Gen._load(ElemPtr, name="subscript_val") + ElemPtr = Gen.builder.gep(ValueVal, [IndexVal], name="subscript") + if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): + return ElemPtr + return Gen._load(ElemPtr, name="subscript_val") + elif isinstance(ValueVal.type, ir.ArrayType): + zero = ir.Constant(ir.IntType(32), 0) + if isinstance(Node.value, ast.Name): + VarName = Node.value.id + if VarName in Gen.variables and Gen.variables[VarName] is not None: + VarPtr = Gen.variables[VarName] + if isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, ir.ArrayType): + if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: + if IndexVal.type.width < 32: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") + else: + IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") + ElemPtr = Gen.builder.gep(VarPtr, [zero, IndexVal], name="subscript") + var_arr_elem_type = VarPtr.type.pointee.element + if isinstance(var_arr_elem_type, (ir.IdentifiedStructType, ir.LiteralStructType)): + return ElemPtr + return Gen._load(ElemPtr, name="subscript_val") + if isinstance(Node.value, ast.Attribute): + AttrPtr = self._get_attr_ptr(Node.value) + if AttrPtr and isinstance(AttrPtr.type, ir.PointerType) and isinstance(AttrPtr.type.pointee, ir.ArrayType): + if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: + if IndexVal.type.width < 32: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") + else: + IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") + ElemPtr = Gen.builder.gep(AttrPtr, [zero, IndexVal], name="subscript") + attr_arr_elem_type = AttrPtr.type.pointee.element + if isinstance(attr_arr_elem_type, (ir.IdentifiedStructType, ir.LiteralStructType)): + return ElemPtr + return Gen._load(ElemPtr, name="subscript_val") + if isinstance(Node.value, ast.Subscript): + InnerPtr = self.HandleSubscriptPtrLlvm(Node.value) + if InnerPtr and isinstance(InnerPtr.type, ir.PointerType): + inner_pointee = InnerPtr.type.pointee + if isinstance(inner_pointee, ir.ArrayType): + if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: + if IndexVal.type.width < 32: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") + else: + IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") + ElemPtr = Gen.builder.gep(InnerPtr, [zero, IndexVal], name="subscript") + inner_elem_type = inner_pointee.element + if isinstance(inner_elem_type, (ir.IdentifiedStructType, ir.LiteralStructType)): + return ElemPtr + return Gen._load(ElemPtr, name="subscript_val") + arr_alloc = Gen._allocaEntry(ValueVal.type, name="arr_subscript_tmp") + Gen._store(ValueVal, arr_alloc) + ElemPtr = Gen.builder.gep(arr_alloc, [zero, IndexVal], name="subscript") + alloc_arr_elem_type = ValueVal.type.element + if isinstance(alloc_arr_elem_type, (ir.IdentifiedStructType, ir.LiteralStructType)): + return ElemPtr + return Gen._load(ElemPtr, name="subscript_val") + return None + + def HandleSubscriptPtrLlvm(self, Node): + Gen = self.Trans.LlvmGen + ValueVal = self.HandleExprLlvm(Node.value) + if not ValueVal: + return None + IndexVal = self.HandleExprLlvm(Node.slice) + if not IndexVal: + return None + if isinstance(IndexVal.type, ir.PointerType) and isinstance(IndexVal.type.pointee, ir.IntType) and IndexVal.type.pointee.width == 8: + Loaded_byte = Gen._load(IndexVal, name="Load_char_idx_ptr") + IndexVal = Gen.builder.zext(Loaded_byte, ir.IntType(32), name="char_to_int_idx_ptr") + if isinstance(ValueVal.type, ir.PointerType): + pointee = ValueVal.type.pointee + if isinstance(pointee, ir.ArrayType): + zero = ir.Constant(ir.IntType(32), 0) + if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: + if IndexVal.type.width < 32: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") + else: + IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") + ElemPtr = Gen.builder.gep(ValueVal, [zero, IndexVal], name="subscript_ptr") + return ElemPtr + elif isinstance(pointee, ir.PointerType): + if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_ptr_index_ptr") + ElemPtr = Gen.builder.gep(ValueVal, [IndexVal], name="subscript_ptr") + return ElemPtr + else: + if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_ptr_index") + ElemPtr = Gen.builder.gep(ValueVal, [IndexVal], name="subscript_ptr") + return ElemPtr + elif isinstance(ValueVal.type, ir.IntType): + var_ptr = self._get_int_ptr(Node.value) + if var_ptr: + i8_ptr = Gen.builder.bitcast(var_ptr, ir.PointerType(ir.IntType(8)), name="int_to_i8ptr") + if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_int_index") + ElemPtr = Gen.builder.gep(i8_ptr, [IndexVal], name="int_subscript_ptr") + return ElemPtr + elif isinstance(ValueVal.type, ir.ArrayType): + zero = ir.Constant(ir.IntType(32), 0) + if isinstance(Node.value, ast.Name): + VarName = Node.value.id + if VarName in Gen.variables and Gen.variables[VarName] is not None: + VarPtr = Gen.variables[VarName] + if isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, ir.ArrayType): + if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: + if IndexVal.type.width < 32: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") + else: + IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") + ElemPtr = Gen.builder.gep(VarPtr, [zero, IndexVal], name="subscript_ptr") + return ElemPtr + if isinstance(Node.value, ast.Subscript): + InnerPtr = self.HandleSubscriptPtrLlvm(Node.value) + if InnerPtr: + if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: + if IndexVal.type.width < 32: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") + else: + IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") + ElemPtr = Gen.builder.gep(InnerPtr, [zero, IndexVal], name="subscript_ptr") + return ElemPtr + if isinstance(Node.value, ast.Attribute): + AttrPtr = self._get_attr_ptr(Node.value) + if AttrPtr and isinstance(AttrPtr.type, ir.PointerType) and isinstance(AttrPtr.type.pointee, ir.ArrayType): + if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: + if IndexVal.type.width < 32: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") + else: + IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") + ElemPtr = Gen.builder.gep(AttrPtr, [zero, IndexVal], name="subscript_ptr") + return ElemPtr + arr_alloc = Gen._allocaEntry(ValueVal.type, name="arr_subscript_tmp") + Gen._store(ValueVal, arr_alloc) + ElemPtr = Gen.builder.gep(arr_alloc, [zero, IndexVal], name="subscript_ptr") + return ElemPtr + return None + + # ========== _get_attr_ptr / _get_int_ptr / _get_attr_class ========== + + def _get_attr_ptr(self, Node): + Gen = self.Trans.LlvmGen + if not isinstance(Node, ast.Attribute): + return None + if isinstance(Node.value, ast.Name): + VarName = Node.value.id + if VarName == 'self': + ClassName = self.Trans._CurrentCpythonObjectClass + if ClassName: + offset = Gen._get_member_offset(Node.attr, ClassName) + SelfVar = Gen._get_var_ptr('self') + if SelfVar: + SelfPtr = Gen._load(SelfVar, name="self") + if isinstance(SelfPtr.type, ir.PointerType): + MemberPtr = Gen.builder.gep(SelfPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=Node.attr) + return MemberPtr + ClassName = Gen.var_struct_class.get(VarName) + if not ClassName and getattr(Gen, 'global_struct_class', None): + ClassName = Gen.global_struct_class.get(VarName) + if not ClassName: + imported_modules = getattr(self.Trans, '_ImportedModules', None) + import_aliases = getattr(self.Trans, '_ImportAliases', {}) + resolved_mod = import_aliases.get(VarName, VarName) + if imported_modules and (VarName in imported_modules or resolved_mod in imported_modules): + AttrName = Node.attr + ModuleSha1Map = getattr(Gen, 'ModuleSha1Map', {}) + candidates = [VarName, resolved_mod] + for mod_name in imported_modules: + if mod_name.endswith(f".{VarName}") or mod_name == VarName: + if mod_name not in candidates: + candidates.append(mod_name) + for cand in candidates: + sha1 = ModuleSha1Map.get(cand) + if sha1: + prefixed = f"{sha1}.{AttrName}" + if prefixed in Gen.module.globals: + return Gen.module.globals[prefixed] + if AttrName in Gen.module.globals: + gv = Gen.module.globals[AttrName] + if isinstance(gv, ir.GlobalVariable): + return gv + if ClassName and ClassName in Gen.structs: + VarPtr = Gen.variables.get(VarName) + if VarPtr: + ObjVal = VarPtr + if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType): + ObjVal = Gen._load(ObjVal, name=f"Load_{VarName}") + if isinstance(ObjVal.type, ir.PointerType) and ObjVal.type.pointee == Gen.structs[ClassName]: + ST = Gen.structs[ClassName] + if isinstance(ST, ir.IdentifiedStructType) and (ST.elements is None or len(ST.elements) == 0): + self.Trans.ImportHandler._TryLoadStructFromStub(ClassName, Gen) + ST = Gen.structs.get(ClassName, ST) + if ST.elements is not None and isinstance(ObjVal.type.pointee, ir.IdentifiedStructType) and ObjVal.type.pointee.elements is None: + ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(ST), name=f"cast_{ClassName}") + offset = Gen._get_member_offset(Node.attr, ClassName) + if offset is not None and ST.elements is not None: + MemberPtr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=Node.attr) + return MemberPtr + elif isinstance(Node.value, ast.Attribute): + InnerPtr = self._get_attr_ptr(Node.value) + if InnerPtr and isinstance(InnerPtr.type, ir.PointerType): + pointee = InnerPtr.type.pointee + if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): + found = Gen.find_struct_by_pointee(pointee) + if found: + CN, ST = found + if isinstance(ST, ir.IdentifiedStructType) and (ST.elements is None or len(ST.elements) == 0): + self.Trans.ImportHandler._TryLoadStructFromStub(CN, Gen) + ST = Gen.structs.get(CN, ST) + if ST.elements is not None and isinstance(InnerPtr.type, ir.PointerType) and isinstance(InnerPtr.type.pointee, ir.IdentifiedStructType) and InnerPtr.type.pointee.elements is None: + InnerPtr = Gen.builder.bitcast(InnerPtr, ir.PointerType(ST), name=f"cast_{CN}") + offset = Gen._get_member_offset(Node.attr, CN) + if offset is not None and ST.elements is not None: + MemberPtr = Gen.builder.gep(InnerPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=Node.attr) + return MemberPtr + elif isinstance(pointee, ir.IntType) and pointee.width == 8: + AttrClassName = self._get_attr_class(Node.value, Gen) + if AttrClassName and AttrClassName in Gen.structs: + CastedObj = Gen.builder.bitcast(InnerPtr, ir.PointerType(Gen.structs[AttrClassName]), name=f"cast_{AttrClassName}") + offset = Gen._get_member_offset(Node.attr, AttrClassName) + if offset is not None: + MemberPtr = Gen.builder.gep(CastedObj, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=Node.attr) + return MemberPtr + elif isinstance(Node.value, ast.Subscript): + SubPtr = self.HandleSubscriptPtrLlvm(Node.value) + if SubPtr and isinstance(SubPtr.type, ir.PointerType): + pointee = SubPtr.type.pointee + if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): + found = Gen.find_struct_by_pointee(pointee) + if found: + CN, ST = found + offset = Gen._get_member_offset(Node.attr, CN) + if offset is not None: + MemberPtr = Gen.builder.gep(SubPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=Node.attr) + return MemberPtr + return None + + def _HandleSliceLlvm(self, base_val, slice_node, base_ast): + Gen = self.Trans.LlvmGen + lower_val = None + upper_val = None + step_val = None + if isinstance(slice_node, ast.Slice): + if slice_node.lower: + lower_val = self.HandleExprLlvm(slice_node.lower) + if slice_node.upper: + upper_val = self.HandleExprLlvm(slice_node.upper) + if slice_node.step: + step_val = self.HandleExprLlvm(slice_node.step) + if isinstance(slice_node, ast.Index): + return self.HandleExprLlvm(slice_node.value) + return None + + def _infer_element_struct_class(self, node, Gen): + if isinstance(node, ast.Attribute): + attr_name = node.attr + if isinstance(node.value, ast.Name) and node.value.id == 'self': + current_class = self.Trans._CurrentCpythonObjectClass + if current_class: + if current_class in Gen.class_member_element_class: + elem_class = Gen.class_member_element_class[current_class].get(attr_name) + if elem_class and elem_class in Gen.structs: + return elem_class + if current_class in Gen.class_members: + for member_name, member_type in Gen.class_members[current_class]: + if member_name == attr_name: + if isinstance(member_type, ir.IdentifiedStructType): + found = Gen.find_struct_by_pointee(member_type) + if found: + return found[0] + break + class_name = Gen.var_struct_class.get(attr_name) + if class_name: + return class_name + elif isinstance(node, ast.Name): + var_name = node.id + class_name = Gen.var_struct_class.get(var_name) + if class_name: + return class_name + return None + + def _get_int_ptr(self, target): + Gen = self.Trans.LlvmGen + if isinstance(target, ast.Name): + VarName = target.id + if VarName in Gen.variables and Gen.variables[VarName] is not None: + VarPtr = Gen.variables[VarName] + if isinstance(VarPtr.type, ir.PointerType): + pointee = VarPtr.type.pointee + if isinstance(pointee, ir.ArrayType): + return Gen.builder.gep(VarPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"arr_start_{VarName}") + return VarPtr + elif isinstance(target, ast.Attribute): + if isinstance(target.value, ast.Name): + obj_name = target.value.id + if obj_name in Gen.variables and Gen.variables[obj_name] is not None: + obj_ptr = Gen.variables[obj_name] + if isinstance(obj_ptr.type, ir.PointerType): + pointee = obj_ptr.type.pointee + if isinstance(pointee, ir.PointerType): + obj_ptr = Gen._load(obj_ptr, name=f"Load_{obj_name}") + pointee = obj_ptr.type.pointee + if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): + StructName = None + if isinstance(pointee, ir.IdentifiedStructType): + StructName = pointee.name + if not StructName: + found = Gen.find_struct_by_pointee(pointee) + if found: + StructName = found[0] + if StructName and StructName in Gen.structs: + offset = Gen._get_member_offset(target.attr, StructName) + if offset is not None: + return Gen.builder.gep(obj_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=f"{target.attr}_ptr") + obj_val = self.HandleExprLlvm(target.value) + if obj_val and isinstance(obj_val.type, ir.PointerType): + if isinstance(obj_val.type.pointee, ir.PointerType): + obj_val = Gen._load(obj_val, name="Load_attr_ptr") + pointee = obj_val.type.pointee + if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): + StructName = None + if isinstance(pointee, ir.IdentifiedStructType): + StructName = pointee.name + if not StructName: + found = Gen.find_struct_by_pointee(pointee) + if found: + StructName = found[0] + if StructName and StructName in Gen.structs: + offset = Gen._get_member_offset(target.attr, StructName) + if offset is not None: + return Gen.builder.gep(obj_val, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=f"{target.attr}_ptr") + return None + + def _resolve_struct_class_for_attr(self, Node, Gen): + if isinstance(Node, ast.Name): + VarName = Node.id + if VarName in Gen.var_struct_class: + return Gen.var_struct_class[VarName] + elif isinstance(Node, ast.Attribute): + ClassName = self._resolve_struct_class_for_attr(Node.value, Gen) + if ClassName and ClassName in Gen.class_members: + for member_name, _ in Gen.class_members[ClassName]: + if member_name == Node.attr: + return ClassName + return None + + def _infer_array_member_type(self, Node, Gen): + if isinstance(Node, ast.Attribute): + parent_class = self._get_attr_class(Node, Gen) + if parent_class and parent_class in Gen.class_members: + for m_name, m_type in Gen.class_members[parent_class]: + if m_name == Node.attr and isinstance(m_type, ir.ArrayType): + return m_type + if parent_class and parent_class in Gen.structs: + st = Gen.structs[parent_class] + if isinstance(st, ir.IdentifiedStructType) and st.elements is not None: + offset = Gen._get_member_offset(Node.attr, parent_class) + if offset is not None and offset < len(st.elements): + elem = st.elements[offset] + if isinstance(elem, ir.ArrayType): + return elem + return None + + def _build_attr_path(self, node): + parts = [] + current = node + while isinstance(current, ast.Attribute): + parts.append(current.attr) + current = current.value + if isinstance(current, ast.Name): + parts.append(current.id) + parts.reverse() + return parts + + def _try_resolve_nested_cdefine(self, Node): + Gen = self.Trans.LlvmGen + imported_modules = getattr(self.Trans, '_ImportedModules', None) + if not imported_modules: + return None + import_aliases = getattr(self.Trans, '_ImportAliases', {}) + parts = self._build_attr_path(Node) + if len(parts) < 2: + return None + attr_name = parts[-1] + module_parts = parts[:-1] + possible_keys = [attr_name] + full_path = '.'.join(parts) + possible_keys.append(full_path) + if module_parts: + ModulePath = '.'.join(module_parts) + resolved_first = import_aliases.get(module_parts[0], module_parts[0]) + if resolved_first != module_parts[0]: + resolved_parts = [resolved_first] + module_parts[1:] + resolved_path = '.'.join(resolved_parts) + possible_keys.append(f"{resolved_path}.{attr_name}") + for mod_name in imported_modules: + if mod_name.endswith('.' + ModulePath) or mod_name == ModulePath: + key = f"{mod_name}.{attr_name}" + if key not in possible_keys: + possible_keys.append(key) + if module_parts and (mod_name.endswith('.' + module_parts[-1]) or mod_name == module_parts[-1]): + key = f"{mod_name}.{attr_name}" + if key not in possible_keys: + possible_keys.append(key) + for lookup_key in possible_keys: + SymInfo = self.Trans.SymbolTable.get(lookup_key) + if SymInfo and getattr(SymInfo, 'IsDefine', None) and getattr(SymInfo, 'DefineValue', None) is not None: + val = SymInfo.DefineValue + if isinstance(val, int): + if val > 0x7FFFFFFF or val < -0x80000000: + return ir.Constant(ir.IntType(64), val & 0xFFFFFFFFFFFFFFFF) + return ir.Constant(ir.IntType(32), val) + elif isinstance(val, float): + return ir.Constant(ir.FloatType(), val) + return None + + def _try_resolve_cross_module_enum(self, module_alias, enum_class_name, member_name): + Gen = self.Trans.LlvmGen + imported_modules = getattr(self.Trans, '_ImportedModules', None) + if not imported_modules: + return None + import_aliases = getattr(self.Trans, '_ImportAliases', {}) + resolved_module = import_aliases.get(module_alias, module_alias) + if resolved_module not in imported_modules and module_alias not in imported_modules: + return None + enum_keys = [enum_class_name, f"{resolved_module}.{enum_class_name}"] + for enum_key in enum_keys: + if enum_key in self.Trans.SymbolTable: + SymInfo = self.Trans.SymbolTable[enum_key] + if getattr(SymInfo, 'IsEnum', None): + for qname in (f"{enum_key}.{member_name}", f"{enum_key}_{member_name}"): + if qname in self.Trans.SymbolTable: + info = self.Trans.SymbolTable[qname] + if getattr(info, 'IsEnumMember', None) and isinstance(getattr(info, 'value', None), int): + return ir.Constant(ir.IntType(32), info.value) + for key, info in self.Trans.SymbolTable.items(): + if getattr(info, 'IsEnumMember', None) and getattr(info, 'EnumName', None) == enum_key and key == member_name: + if isinstance(getattr(info, 'value', None), int): + return ir.Constant(ir.IntType(32), info.value) + for key, info in self.Trans.SymbolTable.items(): + if getattr(info, 'IsEnumMember', None) and key == member_name: + if isinstance(getattr(info, 'value', None), int): + for enum_key in enum_keys: + if getattr(info, 'EnumName', None) == enum_key: + return ir.Constant(ir.IntType(32), info.value) + return None + + def _get_attr_class(self, Node, Gen): + if isinstance(Node, ast.Attribute): + # 注: 不再硬编码 ZLIB_VERSION / C_OK,它们应从符号表查找 + if isinstance(Node.value, ast.Name) and Node.value.id == 'self': + ClassName = self.Trans._CurrentCpythonObjectClass + if ClassName and ClassName in Gen.class_member_element_class: + return Gen.class_member_element_class[ClassName].get(Node.attr) + if isinstance(Node.value, ast.Name): + VarName = Node.value.id + if VarName in Gen.var_struct_class: + ParentClass = Gen.var_struct_class[VarName] + if ParentClass in Gen.class_member_element_class: + return Gen.class_member_element_class[ParentClass].get(Node.attr) + if isinstance(Node.value, ast.Attribute): + ParentClass = self._get_attr_class(Node.value, Gen) + if ParentClass and ParentClass in Gen.class_member_element_class: + return Gen.class_member_element_class[ParentClass].get(Node.attr) + return None + + def _get_llvm_member_offset(self, field_name, ClassName, Gen): + return Gen._get_member_offset(field_name, ClassName) + + def _Load_bitfield_member(self, struct_ptr, ClassName, field_name): + Gen = self.Trans.LlvmGen + bitfield_offsets = Gen.class_member_bitoffsets.get(ClassName, {}) + bitfield_widths = Gen.class_member_bitfields.get(ClassName, {}) + if field_name not in bitfield_offsets: + return None + bit_offset = bitfield_offsets[field_name] + bit_width = bitfield_widths.get(field_name, 0) + if bit_width == 0: + return None + struct_type = Gen.structs.get(ClassName) + if struct_type is None or struct_type.elements is None or len(struct_type.elements) == 0: + return None + storage_type = struct_type.elements[0] + member_ptr = Gen.builder.gep(struct_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{field_name}_storage_ptr") + storage_val = Gen._load(member_ptr, name=f"{field_name}_storage") + shift_amount = bit_offset + if shift_amount > 0: + shifted = Gen.builder.lshr(storage_val, ir.Constant(storage_type, shift_amount), name=f"{field_name}_shift") + else: + shifted = storage_val + mask = (1 << bit_width) - 1 + masked = Gen.builder.and_(shifted, ir.Constant(storage_type, mask), name=f"{field_name}_mask") + is_signed = Gen.class_member_signeds.get(ClassName, {}).get(field_name, False) + if is_signed and bit_width > 0: + sign_bit = 1 << (bit_width - 1) + sign_masked = Gen.builder.and_(shifted, ir.Constant(storage_type, sign_bit), name=f"{field_name}_sign") + sign_extend = Gen.builder.icmp_signed('!=', sign_masked, ir.Constant(storage_type, 0), name=f"{field_name}_sign_check") + extended = Gen.builder.select(sign_extend, + Gen.builder.sext(masked, ir.IntType(32), name=f"{field_name}_sext"), + Gen.builder.zext(masked, ir.IntType(32), name=f"{field_name}_zext"), + name=f"{field_name}_extend") + return extended return Gen.builder.zext(masked, ir.IntType(32), name=f"{field_name}_zext") \ No newline at end of file diff --git a/lib/core/Handles/HandlesExprBuiltin.py b/lib/core/Handles/HandlesExprBuiltin.py index 0bb130e..6b7c02c 100644 --- a/lib/core/Handles/HandlesExprBuiltin.py +++ b/lib/core/Handles/HandlesExprBuiltin.py @@ -56,9 +56,9 @@ class ExprBuiltinHandle(BaseHandle): if isinstance(Val.type, ir.IntType): if Val.type.width == 1: return Val - return Gen.builder.icmp_signed('!=', Val, Gen._zero_const(Val.type), name="bool_result") + return Gen.builder.icmp_signed('!=', Val, Gen._ZeroConst(Val.type), name="bool_result") elif isinstance(Val.type, ir.PointerType): - return Gen.builder.icmp_signed('!=', Val, Gen._zero_const(Val.type), name="bool_result") + return Gen.builder.icmp_signed('!=', Val, Gen._ZeroConst(Val.type), name="bool_result") return Val return ir.Constant(ir.IntType(1), 0) elif FuncName == 'int': @@ -254,7 +254,7 @@ class ExprBuiltinHandle(BaseHandle): val = Gen.builder.zext(val, ir.IntType(32), name="zext_bool_print") elif val.type.width == 8: if self._is_char_type(arg): - char_var = Gen._alloca_entry(ir.IntType(8), name="print_char_buf") + char_var = Gen._allocaEntry(ir.IntType(8), name="print_char_buf") Gen.builder.store(val, char_var) fmt_parts.append('%c') fmt_args.append(char_var) @@ -316,7 +316,7 @@ class ExprBuiltinHandle(BaseHandle): if ClassName in Gen.structs: obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") str_val = Gen.builder.call(Gen._get_function(f'{ClassName}.__str__'), [obj_val], name=f"call_{ClassName}.__str__") - Gen._register_temp_ptr(str_val) + Gen._RegisterTempPtr(str_val) Gen._emit_printf([str_val], unsigned_flags=[False], sep=None, end=None) else: val = self.HandleExprLlvm(arg) @@ -325,7 +325,7 @@ class ExprBuiltinHandle(BaseHandle): pointee = val.type.pointee if not (isinstance(pointee, ir.IntType) and pointee.width == 8): try: - val = Gen._load(val, name="print_load") + val = Gen._load(val, name="print_Load") except Exception as _e: if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": self.Trans.LogWarning(f"异常被忽略: {_e}") @@ -394,7 +394,7 @@ class ExprBuiltinHandle(BaseHandle): if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): for CN, ST in Gen.structs.items(): if pointee == ST: - result = self.Trans.ExprUtils._try_operator_overload(CN, '__len__', val, Gen) + result = self.Trans.ExprUtils._try_operator_overLoad(CN, '__len__', val, Gen) if result is not None: return result break @@ -442,8 +442,12 @@ class ExprBuiltinHandle(BaseHandle): size_bits = getattr(ctype_inst, 'Size', 0) or 0 size_bytes = size_bits // 8 return ir.Constant(ir.IntType(64), size_bytes) - except Exception: - pass + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _config_mode + if _config_mode == "strict": + raise + _vlog().warning(f"解析类型失败: {_e}", "Exception") resolved = CTypeRegistry.ResolveName(type_name) if resolved: ctype_cls, ptr_level = resolved @@ -454,8 +458,12 @@ class ExprBuiltinHandle(BaseHandle): if ptr_level > 0: size_bytes = 8 return ir.Constant(ir.IntType(64), size_bytes) - except Exception: - pass + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _config_mode + if _config_mode == "strict": + raise + _vlog().warning(f"解析类型失败: {_e}", "Exception") return ir.Constant(ir.IntType(64), 0) struct_type = Gen.structs[type_name] @@ -479,7 +487,7 @@ class ExprBuiltinHandle(BaseHandle): if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): for CN, ST in Gen.structs.items(): if pointee == ST: - result = self.Trans.ExprUtils._try_operator_overload(CN, '__abs__', val, Gen) + result = self.Trans.ExprUtils._try_operator_overLoad(CN, '__abs__', val, Gen) if result is not None: return result break @@ -525,12 +533,12 @@ class ExprBuiltinHandle(BaseHandle): if TypeInfo.IsEnum: enum_type_name = arg_name elif isinstance(arg, ast.Attribute): - last_part = None + LastPart = None enum_class_name = None if isinstance(arg.value, ast.Name): - last_part = arg.attr - if last_part in self.Trans.SymbolTable: - AttrInfo = self.Trans.SymbolTable[last_part] + LastPart = arg.attr + if LastPart in self.Trans.SymbolTable: + AttrInfo = self.Trans.SymbolTable[LastPart] if getattr(AttrInfo, 'IsEnumMember', None) and getattr(AttrInfo, 'EnumName', None): enum_type_name = AttrInfo.EnumName elif isinstance(arg.value, ast.Attribute): @@ -539,9 +547,9 @@ class ExprBuiltinHandle(BaseHandle): parts = attr_path.split('.') if len(parts) >= 2: enum_class_name = parts[-2] - last_part = parts[-1] - qualified_name_dot = f"{enum_class_name}.{last_part}" - qualified_name_under = f"{enum_class_name}_{last_part}" + LastPart = parts[-1] + qualified_name_dot = f"{enum_class_name}.{LastPart}" + qualified_name_under = f"{enum_class_name}_{LastPart}" enum_member_found = None for qname in (qualified_name_dot, qualified_name_under): if qname in self.Trans.SymbolTable: @@ -551,7 +559,7 @@ class ExprBuiltinHandle(BaseHandle): break if not enum_member_found: for key in self.Trans.SymbolTable: - if key == last_part: + if key == LastPart: info = self.Trans.SymbolTable[key] if getattr(info, 'IsEnumMember', None) and getattr(info, 'EnumName', None) == enum_class_name: enum_member_found = info diff --git a/lib/core/Handles/HandlesExprCall.py b/lib/core/Handles/HandlesExprCall.py index 5082730..e1f08ef 100644 --- a/lib/core/Handles/HandlesExprCall.py +++ b/lib/core/Handles/HandlesExprCall.py @@ -48,9 +48,9 @@ class ExprCallHandle(BaseHandle): elif arg.name == '__eh_code_out__' and eh_code_ptr is None: eh_code_ptr = arg if eh_msg_ptr is None: - eh_msg_ptr = Gen._alloca_entry(ir.PointerType(ir.IntType(8)), name="eh_msg_out_null") + eh_msg_ptr = Gen._allocaEntry(ir.PointerType(ir.IntType(8)), name="eh_msg_out_null") if eh_code_ptr is None: - eh_code_ptr = Gen._alloca_entry(ir.IntType(32), name="eh_code_out_null") + eh_code_ptr = Gen._allocaEntry(ir.IntType(32), name="eh_code_out_null") Gen._store(ir.Constant(ir.PointerType(ir.IntType(8)), None), eh_msg_ptr) Gen._store(ir.Constant(ir.IntType(32), 0), eh_code_ptr) CallArgs.append(eh_msg_ptr) @@ -83,7 +83,7 @@ class ExprCallHandle(BaseHandle): elif arg.name == '__eh_code_out__' and eh_code_ptr is None: eh_code_ptr = arg if eh_msg_ptr is not None: - eh_msg_val = Gen._load(eh_msg_ptr, name=f"load_eh_msg_{func_name}") + eh_msg_val = Gen._load(eh_msg_ptr, name=f"Load_eh_msg_{func_name}") null_ptr = ir.Constant(ir.PointerType(ir.IntType(8)), None) is_error = Gen.builder.icmp_signed('!=', eh_msg_val, null_ptr, name=f"check_eh_msg_{func_name}") OkBB = Gen.func.append_basic_block(name=f"ok_after_{func_name}") @@ -114,7 +114,7 @@ class ExprCallHandle(BaseHandle): ExceptBB, _, exception_code, _ = Gen.eh_except_block_stack[-1] if ExceptBB is not None: if has_eh_code_out and eh_code_ptr is not None: - eh_code_val = Gen._load(eh_code_ptr, name=f"load_eh_code_{func_name}") + eh_code_val = Gen._load(eh_code_ptr, name=f"Load_eh_code_{func_name}") Gen._store(eh_code_val, exception_code) else: Gen._store(ir.Constant(ir.IntType(32), 1), exception_code) @@ -199,8 +199,8 @@ class ExprCallHandle(BaseHandle): def _HandleCallLlvm(self, Node): Gen = self.Trans.LlvmGen - func_attr = None - module_path = None + FuncAttr = None + ModulePath = None if isinstance(Node.func, ast.Name): FuncName = Node.func.id if hasattr(self.Trans.FunctionHandler, '_generic_templates') and FuncName in self.Trans.FunctionHandler._generic_templates: @@ -231,9 +231,9 @@ class ExprCallHandle(BaseHandle): if isinstance(Val.type, ir.IntType): if Val.type.width == 1: return Val - return Gen.builder.icmp_signed('!=', Val, Gen._zero_const(Val.type), name="bool_result") + return Gen.builder.icmp_signed('!=', Val, Gen._ZeroConst(Val.type), name="bool_result") elif isinstance(Val.type, ir.PointerType): - return Gen.builder.icmp_signed('!=', Val, Gen._zero_const(Val.type), name="bool_result") + return Gen.builder.icmp_signed('!=', Val, Gen._ZeroConst(Val.type), name="bool_result") return Val return ir.Constant(ir.IntType(1), 0) elif FuncName == 'int': @@ -355,7 +355,7 @@ class ExprCallHandle(BaseHandle): return self._HandleCallLlvm(virtual_node) # 检查是否是闭包变量(lambda 赋值给变量后调用) if FuncName in Gen.variables and Gen.variables[FuncName] is not None: - closure_ptr = Gen._load(Gen.variables[FuncName], name=f"load_closure_{FuncName}") + closure_ptr = Gen._load(Gen.variables[FuncName], name=f"Load_closure_{FuncName}") if isinstance(closure_ptr.type, ir.PointerType) and isinstance(closure_ptr.type.pointee, ir.LiteralStructType): st = closure_ptr.type.pointee if len(st.elements) == 2 and isinstance(st.elements[1], ir.PointerType) and isinstance(st.elements[1].pointee, ir.FunctionType): @@ -428,30 +428,30 @@ class ExprCallHandle(BaseHandle): type_name = Node.func.value.attr SizeofNode = ast.Name(id=type_name, ctx=ast.Load()) return self._HandleSizeofLlvm(SizeofNode) - module_path = self._get_module_path(Node.func.value) - if module_path: - aliases = getattr(self.Trans, '_import_aliases', {}) - first_part = module_path.split('.')[0] + ModulePath = self._get_ModulePath(Node.func.value) + if ModulePath: + aliases = getattr(self.Trans, '_ImportAliases', {}) + first_part = ModulePath.split('.')[0] if first_part in aliases: - module_path = aliases[first_part] + module_path[len(first_part):] - is_instance_var = isinstance(Node.func.value, ast.Name) and Node.func.value.id in Gen.var_struct_class and Node.func.value.id not in Gen.module_sha1_map + ModulePath = aliases[first_part] + ModulePath[len(first_part):] + is_instance_var = isinstance(Node.func.value, ast.Name) and Node.func.value.id in Gen.var_struct_class and Node.func.value.id not in Gen.ModuleSha1Map is_class_name = isinstance(Node.func.value, ast.Name) and (Node.func.value.id in Gen.structs or (Node.func.value.id in self.Trans.SymbolTable and getattr(self.Trans.SymbolTable[Node.func.value.id], 'IsStruct', False))) if is_instance_var and not is_class_name: return self._HandleMethodCallLlvm(Node) - func_attr = Node.func.attr - if func_attr in Gen.structs: - result = self._HandleClassNewLlvm(Node, func_attr) + FuncAttr = Node.func.attr + if FuncAttr in Gen.structs: + result = self._HandleClassNewLlvm(Node, FuncAttr) if result is not None: return result - if hasattr(self.Trans.ClassHandler, '_generic_class_templates') and func_attr in self.Trans.ClassHandler._generic_class_templates: - return self._HandleGenericClassNewLlvm(Node, func_attr) - if func_attr in self.Trans.SymbolTable: - SymInfo = self.Trans.SymbolTable[func_attr] + if hasattr(self.Trans.ClassHandler, '_generic_class_templates') and FuncAttr in self.Trans.ClassHandler._generic_class_templates: + return self._HandleGenericClassNewLlvm(Node, FuncAttr) + if FuncAttr in self.Trans.SymbolTable: + SymInfo = self.Trans.SymbolTable[FuncAttr] if SymInfo.IsStruct: - if func_attr not in Gen.structs: - self._ensure_struct_declared(func_attr) - if func_attr in Gen.structs: - result = self._HandleClassNewLlvm(Node, func_attr) + if FuncAttr not in Gen.structs: + self._ensure_struct_declared(FuncAttr) + if FuncAttr in Gen.structs: + result = self._HandleClassNewLlvm(Node, FuncAttr) if result is not None: return result if getattr(SymInfo, 'IsEnumMember', False) and getattr(SymInfo, 'EnumName', None): @@ -459,58 +459,58 @@ class ExprCallHandle(BaseHandle): if EnumName in self.Trans.SymbolTable: EnumInfo = self.Trans.SymbolTable[EnumName] if getattr(EnumInfo, 'IsRenum', False): - result = self._HandleREnumConstructLlvm(Node, EnumName, func_attr, SymInfo.value) + result = self._HandleREnumConstructLlvm(Node, EnumName, FuncAttr, SymInfo.value) if result is not None: return result - FullAttrKey = f"{module_path}.{func_attr}" + FullAttrKey = f"{ModulePath}.{FuncAttr}" if FullAttrKey in self.Trans.SymbolTable: SymInfo = self.Trans.SymbolTable[FullAttrKey] if SymInfo.IsStruct: - if func_attr not in Gen.structs: - self._ensure_struct_declared(func_attr) - if func_attr in Gen.structs: - result = self._HandleClassNewLlvm(Node, func_attr) + if FuncAttr not in Gen.structs: + self._ensure_struct_declared(FuncAttr) + if FuncAttr in Gen.structs: + result = self._HandleClassNewLlvm(Node, FuncAttr) if result is not None: return result if is_class_name: ClassName = Node.func.value.id - result = self._HandleStaticMethodCallLlvm(Node, ClassName, func_attr) + result = self._HandleStaticMethodCallLlvm(Node, ClassName, FuncAttr) if result is not None: return result - FullAttrKey = f"{module_path}.{func_attr}" + FullAttrKey = f"{ModulePath}.{FuncAttr}" if FullAttrKey in self.Trans.SymbolTable: SymInfo = self.Trans.SymbolTable[FullAttrKey] if getattr(SymInfo, 'IsTypedef', False): return ir.Constant(ir.IntType(32), 0) if getattr(SymInfo, 'IsStruct', False): - if func_attr not in Gen.structs: - self._ensure_struct_declared(func_attr) - if func_attr in Gen.structs: - result = self._HandleClassNewLlvm(Node, func_attr) + if FuncAttr not in Gen.structs: + self._ensure_struct_declared(FuncAttr) + if FuncAttr in Gen.structs: + result = self._HandleClassNewLlvm(Node, FuncAttr) if result is not None: return result - if func_attr in Gen.structs: - result = self._HandleClassNewLlvm(Node, func_attr) + if FuncAttr in Gen.structs: + result = self._HandleClassNewLlvm(Node, FuncAttr) if result is not None: return result - if module_path == 'c': - if func_attr == 'Asm': + if ModulePath == 'c': + if FuncAttr == 'Asm': return self.Trans.ExprAsmHandle._HandleAsmLlvm(Node) - elif func_attr == 'Addr': + elif FuncAttr == 'Addr': return self.Trans.CSpecialCallHandle._HandleCAddrLlvm(Node) - elif func_attr == 'Set': + elif FuncAttr == 'Set': return self.Trans.CSpecialCallHandle._HandleCSetLlvm(Node) - elif func_attr == 'Load': + elif FuncAttr == 'Load': return self.Trans.CSpecialCallHandle._HandleCLoadLlvm(Node) - elif func_attr == 'Deref': + elif FuncAttr == 'Deref': return self.Trans.CSpecialCallHandle._HandleCDerefLlvm(Node) - elif func_attr == 'DerefAs': + elif FuncAttr == 'DerefAs': return self._HandleCDerefAsLlvm(Node) - elif func_attr == 'PtrToInt': + elif FuncAttr == 'PtrToInt': return self.Trans.CSpecialCallHandle._HandleCPtrToIntLlvm(Node) - elif func_attr in ('CIf', 'CElif'): + elif FuncAttr in ('CIf', 'CElif'): return self.Trans.CSpecialCallHandle._HandleCIfLlvm(Node) - elif func_attr == 'CError': + elif FuncAttr == 'CError': msg = "compile-time error" if Node.args: arg = Node.args[0] @@ -520,52 +520,119 @@ class ExprCallHandle(BaseHandle): msg = arg.s lineno = getattr(Node, 'lineno', 0) raise Exception(f"#error: {msg} (line {lineno})") - elif func_attr in ('AsmInp', 'AsmOut'): + elif FuncAttr in ('AsmInp', 'AsmOut'): return ir.Constant(ir.IntType(32), 0) - elif func_attr == 'LLVMIR': + elif FuncAttr == 'LLVMIR': return self._HandleLLVMIRLlvm(Node) - elif func_attr in ('LInp', 'LOut'): + elif FuncAttr in ('LInp', 'LOut'): return ir.Constant(ir.IntType(32), 0) - if module_path == 't': - method_result_t = self._HandleMethodCallLlvm(Node) - if method_result_t is not None: - return method_result_t - raise Exception(f"Undefined method: 't.{func_attr}'") + if ModulePath == 't': + MethodResult_t = self._HandleMethodCallLlvm(Node) + if MethodResult_t is not None: + return MethodResult_t + raise Exception(f"Undefined method: 't.{FuncAttr}'") if isinstance(Node.func.value, ast.Attribute): inner_attr = Node.func.value.attr if inner_attr in Gen.structs or (inner_attr in self.Trans.SymbolTable and getattr(self.Trans.SymbolTable[inner_attr], 'IsStruct', False)): - static_result = self._HandleStaticMethodCallLlvm(Node, inner_attr, func_attr) + static_result = self._HandleStaticMethodCallLlvm(Node, inner_attr, FuncAttr) if static_result is not None: return static_result - method_result_attr = self._HandleMethodCallLlvm(Node) - is_zero_attr = isinstance(method_result_attr, ir.Constant) and isinstance(method_result_attr.type, ir.IntType) and method_result_attr.constant == 0 - if method_result_attr is not None and not is_zero_attr: - return method_result_attr - result = self._HandleExternalCallLlvm(Node, func_attr, module_path) + MethodResult_attr = self._HandleMethodCallLlvm(Node) + is_zero_attr = isinstance(MethodResult_attr, ir.Constant) and isinstance(MethodResult_attr.type, ir.IntType) and MethodResult_attr.constant == 0 + if MethodResult_attr is not None and not is_zero_attr: + return MethodResult_attr + result = self._HandleExternalCallLlvm(Node, FuncAttr, ModulePath) if result is not None: return result - method_result = self._HandleMethodCallLlvm(Node) - is_zero_result = isinstance(method_result, ir.Constant) and isinstance(method_result.type, ir.IntType) and method_result.constant == 0 - if is_zero_result and func_attr is not None: - mangled_name = Gen._mangle_func_name(func_attr, module_path if module_path and module_path != 't' else None) + MethodResult = self._HandleMethodCallLlvm(Node) + IsZeroResult = isinstance(MethodResult, ir.Constant) and isinstance(MethodResult.type, ir.IntType) and MethodResult.constant == 0 + if IsZeroResult and FuncAttr is not None: + mangled_name = Gen._mangle_func_name(FuncAttr, ModulePath if ModulePath and ModulePath != 't' else None) if Gen._has_function(mangled_name): CallArgs = [] for arg in Node.args: ArgVal = self.HandleExprLlvm(arg) if ArgVal: CallArgs.append(ArgVal) - return Gen.builder.call(Gen._get_function(mangled_name), CallArgs, name=f"call_{func_attr}") - if method_result is None or is_zero_result: - imported = getattr(self.Trans, '_imported_modules', set()) - aliases = getattr(self.Trans, '_import_aliases', {}) - is_known = module_path in imported or module_path in aliases - if module_path and is_known: - raise Exception(f"Undefined symbol: '{module_path}.{func_attr}'") - if module_path and module_path not in {'t', 'c'} and not is_known: - raise Exception(f"Unknown module: '{module_path}' (undefined symbol: '{module_path}.{func_attr}')") - if not module_path and func_attr: - raise Exception(f"Undefined method: '{func_attr}'") - return method_result if method_result is not None else ir.Constant(ir.IntType(32), 0) + return Gen.builder.call(Gen._get_function(mangled_name), CallArgs, name=f"call_{FuncAttr}") + if MethodResult is None or IsZeroResult: + imported = getattr(self.Trans, '_ImportedModules', set()) + aliases = getattr(self.Trans, '_ImportAliases', {}) + ModuleSha1Map = getattr(Gen, 'ModuleSha1Map', {}) + IsKnown = (ModulePath in imported or ModulePath in aliases or + ModulePath in ModuleSha1Map) + if not IsKnown and ModulePath and '.' in ModulePath: + LastPart = ModulePath.split('.')[-1] + IsKnown = (LastPart in imported or LastPart in aliases or + LastPart in ModuleSha1Map) + # 最后尝试: 用 FuncAttr 直接查找 Gen.functions(_find_function 会遍历 SHA1 前缀) + if FuncAttr and ModulePath and ModulePath not in {'t', 'c'}: + # 优先检查 FuncAttr 是否为 struct/类构造器 + if FuncAttr not in Gen.structs: + self._ensure_struct_declared(FuncAttr) + if FuncAttr in Gen.structs: + result = self._HandleClassNewLlvm(Node, FuncAttr) + if result is not None: + return result + # 检查 FullAttrKey 是否为 struct(如 hashlib.md5) + if ModulePath: + FullAttrKey = f"{ModulePath}.{FuncAttr}" + if FullAttrKey in self.Trans.SymbolTable: + FullSymInfo = self.Trans.SymbolTable[FullAttrKey] + if getattr(FullSymInfo, 'IsStruct', False) or getattr(FullSymInfo, 'IsCpythonObject', False): + if FuncAttr not in Gen.structs: + self._ensure_struct_declared(FuncAttr) + if FuncAttr in Gen.structs: + result = self._HandleClassNewLlvm(Node, FuncAttr) + if result is not None: + return result + fallback_func = Gen._find_function(FuncAttr) + if fallback_func is not None: + CallArgs = [] + for arg in Node.args: + ArgVal = self.HandleExprLlvm(arg) + if ArgVal: + CallArgs.append(ArgVal) + self._append_eh_msg_out_arg(CallArgs, fallback_func, Gen) + result = Gen.builder.call(fallback_func, CallArgs, name=f"call_{FuncAttr}") + return self._check_eh_return(result, FuncAttr, Gen, called_func=fallback_func) + # 尝试从 stub 按需加载函数声明 + if ModulePath in ModuleSha1Map: + sha1 = ModuleSha1Map[ModulePath] + stub_mangled = f"{sha1}.{FuncAttr}" + try: + stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(stub_mangled, Gen) + except Exception: + stub_func_type = None + if not stub_func_type: + try: + stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(FuncAttr, Gen) + except Exception: + stub_func_type = None + if stub_func_type: + decl_name = stub_mangled if stub_mangled in getattr(self.Trans.ImportHandler, '_stub_func_cache', {}) else FuncAttr + if decl_name not in Gen.functions: + func_decl = ir.Function(Gen.module, stub_func_type, name=decl_name) + Gen.functions[decl_name] = func_decl + if decl_name != FuncAttr and FuncAttr not in Gen.functions: + Gen.functions[FuncAttr] = func_decl + else: + func_decl = Gen.functions[decl_name] + CallArgs = [] + for arg in Node.args: + ArgVal = self.HandleExprLlvm(arg) + if ArgVal: + CallArgs.append(ArgVal) + self._append_eh_msg_out_arg(CallArgs, func_decl, Gen) + result = Gen.builder.call(func_decl, CallArgs, name=f"call_{FuncAttr}") + return self._check_eh_return(result, FuncAttr, Gen, called_func=func_decl) + if ModulePath and IsKnown: + raise Exception(f"Undefined symbol: '{ModulePath}.{FuncAttr}'") + if ModulePath and ModulePath not in {'t', 'c'} and not IsKnown: + raise Exception(f"Unknown module: '{ModulePath}' (undefined symbol: '{ModulePath}.{FuncAttr}')") + if not ModulePath and FuncAttr: + raise Exception(f"Undefined method: '{FuncAttr}'") + return MethodResult if MethodResult is not None else ir.Constant(ir.IntType(32), 0) if isinstance(Node.func, ast.BinOp) and isinstance(Node.func.op, ast.BitOr): return self._HandleTypeUnionCastLlvm(Node) raise Exception(f"Unsupported call expression") @@ -771,7 +838,7 @@ class ExprCallHandle(BaseHandle): ast.copy_location(new_node, Node) return new_node - def _get_module_path(self, node): + def _get_ModulePath(self, node): parts = [] while isinstance(node, ast.Attribute): parts.append(node.attr) @@ -936,9 +1003,9 @@ class ExprCallHandle(BaseHandle): result = method(src_val, dest_type, name="llvmir_result") return self._StoreLLVMIROutputs(Gen, result, output_targets) - load_match = re.match(r'load\s+(\w+),\s*(\w+)\s+%__OP(\d+)__', template) - if load_match: - ptr_val = resolve_op(int(load_match.group(3))) + Load_match = re.match(r'Load\s+(\w+),\s*(\w+)\s+%__OP(\d+)__', template) + if Load_match: + ptr_val = resolve_op(int(Load_match.group(3))) if ptr_val: result = Gen.builder.load(ptr_val, name="llvmir_result") return self._StoreLLVMIROutputs(Gen, result, output_targets) @@ -1095,8 +1162,8 @@ class ExprCallHandle(BaseHandle): expected_type = self._ParseLLVMType(Gen, expected_type_str.rstrip('*')) if not expected_type: return val - is_ptr = expected_type_str.endswith('*') - if is_ptr: + IsPtr = expected_type_str.endswith('*') + if IsPtr: expected_ptr_type = ir.PointerType(expected_type) if isinstance(val.type, ir.PointerType) and val.type != expected_ptr_type: try: @@ -1124,31 +1191,32 @@ class ExprCallHandle(BaseHandle): return Gen.builder.inttoptr(val, expected_type) return val - def _HandleExternalCallLlvm(self, Node, func_name, module_path): + def _HandleExternalCallLlvm(self, Node, func_name, ModulePath): Gen = self.Trans.LlvmGen # 解析 import 别名: 如 window -> vpsdk.window - if module_path and module_path not in ('c', 't'): - import_aliases = getattr(self.Trans, '_import_aliases', {}) - if module_path in import_aliases: - module_path = import_aliases[module_path] + if ModulePath and ModulePath not in ('c', 't'): + import_aliases = getattr(self.Trans, '_ImportAliases', {}) + if ModulePath in import_aliases: + ModulePath = import_aliases[ModulePath] - is_user_module = (module_path and module_path not in ('c', 't') and - (module_path in Gen.module_sha1_map or - module_path in getattr(self.Trans, '_imported_modules', set()) or - module_path in getattr(self.Trans, '_import_aliases', {}))) - if module_path and module_path not in ('c', 't') and not is_user_module: - is_user_module = (module_path in Gen.module_sha1_map or - module_path.split('.')[-1] in Gen.module_sha1_map) - if is_user_module and module_path not in Gen.module_sha1_map: - module_path = module_path.split('.')[-1] + is_user_module = (ModulePath and ModulePath not in ('c', 't') and + (ModulePath in Gen.ModuleSha1Map or + ModulePath in getattr(self.Trans, '_ImportedModules', set()) or + ModulePath in getattr(self.Trans, '_ImportAliases', {}))) + if ModulePath and ModulePath not in ('c', 't') and not is_user_module: + is_user_module = (ModulePath in Gen.ModuleSha1Map or + ModulePath.split('.')[-1] in Gen.ModuleSha1Map or + ModulePath.split('.')[-1] in getattr(self.Trans, '_ImportedModules', set())) + if is_user_module and ModulePath not in Gen.ModuleSha1Map and ModulePath not in getattr(self.Trans, '_ImportedModules', set()): + ModulePath = ModulePath.split('.')[-1] - if module_path and module_path not in ('c', 't') and not is_user_module: + if ModulePath and ModulePath not in ('c', 't') and not is_user_module: return None if is_user_module: - mangled_name = Gen._mangle_func_name(func_name, module_path) - sym_key = f'{module_path}.{func_name}' + mangled_name = Gen._mangle_func_name(func_name, ModulePath) + sym_key = f'{ModulePath}.{func_name}' sym_info = self.Trans.SymbolTable.get(sym_key) or self.Trans.SymbolTable.get(func_name) is_inline = sym_info and (getattr(sym_info, 'IsInline', False) or isinstance(getattr(sym_info, 'Storage', None), t.CInline)) if is_inline and getattr(sym_info, 'InlineBody', None): @@ -1166,11 +1234,11 @@ class ExprCallHandle(BaseHandle): kw_provided.add(exact_param_names.index(kw.arg)) for i in range(len(exact_param_names)): if i >= provided and i not in kw_provided: - raise Exception(f"调用 {module_path}.{func_name}() 缺少必需参数 '{exact_param_names[i]}',该参数没有默认值") - elif module_path in Gen.module_sha1_map and len(Node.args) == 0: + raise Exception(f"调用 {ModulePath}.{func_name}() 缺少必需参数 '{exact_param_names[i]}',该参数没有默认值") + elif ModulePath in Gen.ModuleSha1Map and len(Node.args) == 0: func = Gen.functions.get(mangled_name) if func and len(func.function_type.args) > 0: - raise Exception(f"调用 {module_path}.{func_name}() 缺少必需参数,函数需要 {len(func.function_type.args)} 个参数但未传入任何参数") + raise Exception(f"调用 {ModulePath}.{func_name}() 缺少必需参数,函数需要 {len(func.function_type.args)} 个参数但未传入任何参数") if Gen._has_function(mangled_name): return self._HandleClosureCallLlvm(Node, mangled_name) try: @@ -1195,7 +1263,7 @@ class ExprCallHandle(BaseHandle): if decl_name != func_name and func_name not in Gen.functions: Gen.functions[func_name] = func_decl return self._HandleClosureCallLlvm(Node, decl_name) - sym_key = f'{module_path}.{func_name}' + sym_key = f'{ModulePath}.{func_name}' sym_info = self.Trans.SymbolTable.get(sym_key) if not sym_info: sym_info = self.Trans.SymbolTable.get(func_name) @@ -1234,9 +1302,13 @@ class ExprCallHandle(BaseHandle): if replaced and replaced != existing: Gen.functions[mangled_name] = replaced return self._HandleClosureCallLlvm(Node, mangled_name) + # 回退: 直接用 func_name 查找(_find_function 会遍历 SHA1 前缀) + fallback_func = Gen._find_function(func_name) + if fallback_func is not None: + return self._HandleClosureCallLlvm(Node, func_name) return None - if module_path == 'c': + if ModulePath == 'c': if func_name == 'Asm': return self.Trans.ExprAsmHandle._HandleAsmLlvm(Node) elif func_name == 'Addr': @@ -1276,7 +1348,7 @@ class ExprCallHandle(BaseHandle): 'GetConsoleOutputCP': (ir.IntType(32), []), 'GetConsoleCP': (ir.IntType(32), []), } - if module_path and 'win32console' in module_path and func_name in win32_apis: + if ModulePath and 'win32console' in ModulePath and func_name in win32_apis: ret_type, param_types = win32_apis[func_name] if func_name not in Gen.functions: func_type = ir.FunctionType(ret_type, param_types) @@ -1304,7 +1376,7 @@ class ExprCallHandle(BaseHandle): if func_name in self._C_LIB_FUNCS: return self._HandleClosureCallLlvm(Node, func_name) - mangled_name = Gen._mangle_func_name(func_name, module_path) + mangled_name = Gen._mangle_func_name(func_name, ModulePath) try: stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(mangled_name, Gen) except Exception: @@ -1322,7 +1394,7 @@ class ExprCallHandle(BaseHandle): Gen.functions[func_name] = func_decl return self._HandleClosureCallLlvm(Node, decl_name) - sym_key = f'{module_path}.{func_name}' if module_path else func_name + sym_key = f'{ModulePath}.{func_name}' if ModulePath else func_name sym_info = self.Trans.SymbolTable.get(sym_key) if not sym_info: sym_info = self.Trans.SymbolTable.get(func_name) @@ -1347,7 +1419,7 @@ class ExprCallHandle(BaseHandle): if isinstance(lp, ir.VoidType): lp = ir.IntType(8).as_pointer() llvm_param_types.append(lp) - mangled_name = Gen._mangle_func_name(func_name, module_path) + mangled_name = Gen._mangle_func_name(func_name, ModulePath) if mangled_name not in Gen.functions: func_type = ir.FunctionType(ret_type, llvm_param_types, var_arg=sym_is_variadic) func_decl = ir.Function(Gen.module, func_type, name=mangled_name) @@ -1372,18 +1444,22 @@ class ExprCallHandle(BaseHandle): type_info = None try: type_info = getattr(self.Trans, 'TypeMergeHandler', None) and self.Trans.TypeMergeHandler.MergeTypes(Node.func) - except Exception: - pass + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _config_mode + if _config_mode == "strict": + raise + _vlog().warning(f"解析类型失败: {_e}", "Exception") if not isinstance(type_info, CTypeInfo): return None target_type_str = type_info.ToString() - is_ptr = type_info.IsPtr - if is_ptr and target_type_str and '*' not in target_type_str: + IsPtr = type_info.IsPtr + if IsPtr and target_type_str and '*' not in target_type_str: target_type_str += ' *' if not target_type_str: return None - if type_info.IsPtr and not is_ptr: - is_ptr = True + if type_info.IsPtr and not IsPtr: + IsPtr = True if '*' not in target_type_str: target_type_str += ' *' if isinstance(type_info.Storage, t.CExport) or isinstance(type_info.Storage, t.CExtern): @@ -1408,8 +1484,8 @@ class ExprCallHandle(BaseHandle): dst_is_float = isinstance(target_type, (ir.FloatType, ir.DoubleType)) src_is_int = isinstance(val.type, ir.IntType) dst_is_int = isinstance(target_type, ir.IntType) - src_is_ptr = isinstance(val.type, ir.PointerType) - dst_is_ptr = isinstance(target_type, ir.PointerType) + src_IsPtr = isinstance(val.type, ir.PointerType) + dst_IsPtr = isinstance(target_type, ir.PointerType) if src_is_int and dst_is_float: is_unsigned = Gen._check_node_unsigned(expr_node) if is_unsigned: @@ -1442,17 +1518,17 @@ class ExprCallHandle(BaseHandle): if isinstance(val.type, ir.DoubleType) and isinstance(target_type, ir.FloatType): return Gen.builder.fptrunc(val, target_type, name="fptrunc_cast") return val - if src_is_ptr and dst_is_int: + if src_IsPtr and dst_is_int: if target_type.width < 64: ptr_to_i64 = Gen.builder.ptrtoint(val, ir.IntType(64), name="ptr2i64") return Gen.builder.trunc(ptr_to_i64, target_type, name="ptr2int_cast") return Gen.builder.ptrtoint(val, target_type, name="ptr2int_cast") - if src_is_int and dst_is_ptr: + if src_is_int and dst_IsPtr: return Gen.builder.inttoptr(val, target_type, name="int2ptr_cast") - if src_is_ptr and dst_is_ptr: + if src_IsPtr and dst_IsPtr: if isinstance(val.type.pointee, ir.PointerType) and isinstance(target_type.pointee, ir.IntType): - loaded = Gen._load(val, name="load_ptr") - return loaded + Loaded = Gen._load(val, name="load_ptr") + return Loaded return Gen.builder.bitcast(val, target_type, name="ptrcast") try: return Gen.builder.bitcast(val, target_type, name="cast") @@ -1464,7 +1540,7 @@ class ExprCallHandle(BaseHandle): if RenumName not in Gen.structs: return None RenumType = Gen.structs[RenumName] - result = Gen._alloca_entry(RenumType, name=f"{RenumName}_{VariantName}") + result = Gen._allocaEntry(RenumType, name=f"{RenumName}_{VariantName}") tag_ptr = Gen.builder.gep(result, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="renum_tag_ptr") Gen._store(ir.Constant(ir.IntType(32), TagValue), tag_ptr) NestedStructName = f"{RenumName}_{VariantName}" @@ -1473,10 +1549,10 @@ class ExprCallHandle(BaseHandle): NestedStructPtrType = ir.PointerType(NestedStructType) variant_ptr = Gen.builder.bitcast(result, NestedStructPtrType, name=f"cast_{NestedStructName}") members = Gen.class_members.get(NestedStructName, []) - payload_members = [(n, t) for n, t in members if n != '__tag'] + payLoad_members = [(n, t) for n, t in members if n != '__tag'] for i, arg in enumerate(Node.args): - if i < len(payload_members): - member_name, member_type = payload_members[i] + if i < len(payLoad_members): + member_name, member_type = payLoad_members[i] ArgVal = self.HandleExprLlvm(arg) if ArgVal: Coerced = Gen._coerce_value(ArgVal, member_type) @@ -1543,7 +1619,7 @@ class ExprCallHandle(BaseHandle): old_var_scopes = list(self.Trans.VarScopes) for param_name, val in saved_vars.items(): if val is not None: - alloca = Gen._alloca_entry(val.type, name=f"inline_arg_{param_name}") + alloca = Gen._allocaEntry(val.type, name=f"inline_arg_{param_name}") Gen._store(val, alloca) self.Trans.VarScopes.append((param_name, alloca)) self.Trans.BodyHandler.HandleBodyLlvm(inline_body) @@ -1679,7 +1755,7 @@ class ExprCallHandle(BaseHandle): CallArgs.append(Gen.variables[var_name]) elif var_name in Gen._reg_values: OldVal = Gen._reg_values[var_name] - var = Gen._alloca_entry(OldVal.type, name=var_name) + var = Gen._allocaEntry(OldVal.type, name=var_name) Gen._store(OldVal, var) Gen.variables[var_name] = var del Gen._reg_values[var_name] @@ -1762,7 +1838,7 @@ class ExprCallHandle(BaseHandle): if target_bits is None: target_bits = 0 is_float = getattr(ctype_inst, 'IsSigned', False) is None and target_bits > 0 if ctype_inst else False - is_ptr_cast = len(Node.args) >= 2 and ( + IsPtr_cast = len(Node.args) >= 2 and ( (isinstance(Node.args[1], ast.Attribute) and Node.args[1].attr == 'CPtr' and isinstance(Node.args[1].value, ast.Name) and Node.args[1].value.id == 't') or (isinstance(Node.args[1], ast.Name) and Node.args[1].id == 'CPtr') ) @@ -1771,10 +1847,10 @@ class ExprCallHandle(BaseHandle): if isinstance(ArgNode, ast.Subscript): SubscriptPtr = self._HandleSubscriptPtrLlvm(ArgNode) if SubscriptPtr: - if MethodName == 'CPtr' or is_ptr_cast: + if MethodName == 'CPtr' or IsPtr_cast: return SubscriptPtr if isinstance(SubscriptPtr.type, ir.PointerType): - val = Gen._load(SubscriptPtr, name="load_subscript_val") + val = Gen._load(SubscriptPtr, name="Load_subscript_val") else: val = SubscriptPtr if target_bits > 0 and isinstance(val.type, ir.IntType) and not is_float: @@ -1784,7 +1860,7 @@ class ExprCallHandle(BaseHandle): val = Gen.builder.trunc(val, ir.IntType(target_bits), name="trunc_cast") return val val = self.HandleExprLlvm(ArgNode) - if is_ptr_cast: + if IsPtr_cast: if target_bits > 0 and not is_float: target_ptr_type = ir.PointerType(ir.IntType(target_bits)) elif is_float and target_bits == 32: @@ -1839,9 +1915,9 @@ class ExprCallHandle(BaseHandle): if isinstance(ArgVal, ir.Constant) and isinstance(ArgVal.type, ir.IntType): return ir.Constant(ir.IntType(1), 1 if ArgVal.constant != 0 else 0) if isinstance(ArgVal.type, ir.IntType): - return Gen.builder.icmp_signed('!=', ArgVal, Gen._zero_const(ArgVal.type), name="cif_cond") + return Gen.builder.icmp_signed('!=', ArgVal, Gen._ZeroConst(ArgVal.type), name="cif_cond") if isinstance(ArgVal.type, ir.PointerType): - return Gen.builder.icmp_signed('!=', ArgVal, Gen._zero_const(ArgVal.type), name="cif_cond") + return Gen.builder.icmp_signed('!=', ArgVal, Gen._ZeroConst(ArgVal.type), name="cif_cond") return ir.Constant(ir.IntType(1), 0) elif MethodName in ('CIfdef', 'CIfndef'): return ir.Constant(ir.IntType(1), 1) @@ -1858,8 +1934,12 @@ class ExprCallHandle(BaseHandle): val = self.HandleExprLlvm(arg) if isinstance(val, str): msg = val - except Exception: - pass + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _config_mode + if _config_mode == "strict": + raise + _vlog().warning(f"处理函数调用失败: {_e}", "Exception") lineno = getattr(Node, 'lineno', 0) raise Exception(f"#error: {msg} (line {lineno})") elif MethodName in ('CElse', 'CEndif', 'CPragma', 'CUndef'): @@ -1877,21 +1957,21 @@ class ExprCallHandle(BaseHandle): if isinstance(var_ptr.type, ir.PointerType) and isinstance(var_ptr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): ObjVal = var_ptr else: - tmp = Gen._alloca_entry(ObjVal.type, name="chain_method_tmp") + tmp = Gen._allocaEntry(ObjVal.type, name="chain_method_tmp") Gen._store(ObjVal, tmp) ObjVal = tmp else: - tmp = Gen._alloca_entry(ObjVal.type, name="chain_method_tmp") + tmp = Gen._allocaEntry(ObjVal.type, name="chain_method_tmp") Gen._store(ObjVal, tmp) ObjVal = tmp else: - tmp = Gen._alloca_entry(ObjVal.type, name="chain_method_tmp") + tmp = Gen._allocaEntry(ObjVal.type, name="chain_method_tmp") Gen._store(ObjVal, tmp) ObjVal = tmp if isinstance(Node.func.value, ast.Name): ModuleName = Node.func.value.id - aliases = getattr(self.Trans, '_import_aliases', {}) - imported = getattr(self.Trans, '_imported_modules', set()) + aliases = getattr(self.Trans, '_ImportAliases', {}) + imported = getattr(self.Trans, '_ImportedModules', set()) actual_module = aliases.get(ModuleName, ModuleName) if ModuleName in imported or actual_module in imported: mangled_name = Gen._mangle_func_name(MethodName, actual_module) @@ -2001,7 +2081,7 @@ class ExprCallHandle(BaseHandle): if not stub_func_type: stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(MethodName, Gen) if not stub_func_type and mangled_name != MethodName: - for sha1 in getattr(Gen, 'module_sha1_map', {}).values(): + for sha1 in getattr(Gen, 'ModuleSha1Map', {}).values(): alt_name = f"{sha1}.{MethodName}" stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(alt_name, Gen) if stub_func_type: @@ -2250,7 +2330,7 @@ class ExprCallHandle(BaseHandle): val = Gen.builder.zext(val, ir.IntType(32), name="zext_bool_print") elif val.type.width == 8: if self._is_char_type(arg): - char_var = Gen._alloca_entry(ir.IntType(8), name="print_char_buf") + char_var = Gen._allocaEntry(ir.IntType(8), name="print_char_buf") Gen.builder.store(val, char_var) fmt_parts.append('%c') fmt_args.append(char_var) @@ -2314,7 +2394,7 @@ class ExprCallHandle(BaseHandle): if ClassName in Gen.structs: obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") str_val = Gen.builder.call(Gen._get_function(f'{ClassName}.__str__'), [obj_val], name=f"call_{ClassName}.__str__") - Gen._register_temp_ptr(str_val) + Gen._RegisterTempPtr(str_val) Gen._emit_printf([str_val], unsigned_flags=[False], sep=None, end=None) elif isinstance(arg, ast.Name) and arg.id in Gen.var_struct_class: ClassName = Gen.var_struct_class[arg.id] @@ -2325,7 +2405,7 @@ class ExprCallHandle(BaseHandle): if isinstance(obj_val.type, ir.PointerType) and not isinstance(obj_val.type.pointee, type(Gen.structs[ClassName])): obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") str_val = Gen.builder.call(str_func, [obj_val], name=f"call_{ClassName}.__str__") - Gen._register_temp_ptr(str_val) + Gen._RegisterTempPtr(str_val) Gen._emit_printf([str_val], unsigned_flags=[False], sep=None, end=None) else: val = self.HandleExprLlvm(arg) @@ -2340,7 +2420,7 @@ class ExprCallHandle(BaseHandle): pointee = val.type.pointee if not self._is_char_pointer(val): try: - val = Gen._load(val, name="print_load") + val = Gen._load(val, name="print_Load") except Exception as _e: if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": self.Trans.LogWarning(f"异常被忽略: {_e}") @@ -2431,7 +2511,7 @@ class ExprCallHandle(BaseHandle): if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): for CN, ST in Gen.structs.items(): if pointee == ST: - result = self.Trans.ExprUtils._try_operator_overload(CN, '__len__', val, Gen) + result = self.Trans.ExprUtils._try_operator_overLoad(CN, '__len__', val, Gen) if result is not None: return result break @@ -2479,8 +2559,12 @@ class ExprCallHandle(BaseHandle): size_bits = getattr(ctype_inst, 'Size', 0) or 0 size_bytes = size_bits // 8 return ir.Constant(ir.IntType(64), size_bytes) - except Exception: - pass + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _config_mode + if _config_mode == "strict": + raise + _vlog().warning(f"解析类型失败: {_e}", "Exception") resolved = CTypeRegistry.ResolveName(type_name) if resolved: ctype_cls, ptr_level = resolved @@ -2491,8 +2575,12 @@ class ExprCallHandle(BaseHandle): if ptr_level > 0: size_bytes = 8 return ir.Constant(ir.IntType(64), size_bytes) - except Exception: - pass + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _config_mode + if _config_mode == "strict": + raise + _vlog().warning(f"解析类型失败: {_e}", "Exception") return ir.Constant(ir.IntType(64), 0) struct_type = Gen.structs[type_name] @@ -2516,7 +2604,7 @@ class ExprCallHandle(BaseHandle): if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): for CN, ST in Gen.structs.items(): if pointee == ST: - result = self.Trans.ExprUtils._try_operator_overload(CN, '__abs__', val, Gen) + result = self.Trans.ExprUtils._try_operator_overLoad(CN, '__abs__', val, Gen) if result is not None: return result break @@ -2562,12 +2650,12 @@ class ExprCallHandle(BaseHandle): if TypeInfo.IsEnum: enum_type_name = arg_name elif isinstance(arg, ast.Attribute): - last_part = None + LastPart = None enum_class_name = None if isinstance(arg.value, ast.Name): - last_part = arg.attr - if last_part in self.Trans.SymbolTable: - AttrInfo = self.Trans.SymbolTable[last_part] + LastPart = arg.attr + if LastPart in self.Trans.SymbolTable: + AttrInfo = self.Trans.SymbolTable[LastPart] if AttrInfo.IsEnumMember and AttrInfo.EnumName: enum_type_name = AttrInfo.EnumName elif isinstance(arg.value, ast.Attribute): @@ -2576,9 +2664,9 @@ class ExprCallHandle(BaseHandle): parts = attr_path.split('.') if len(parts) >= 2: enum_class_name = parts[-2] - last_part = parts[-1] - qualified_name_dot = f"{enum_class_name}.{last_part}" - qualified_name_under = f"{enum_class_name}_{last_part}" + LastPart = parts[-1] + qualified_name_dot = f"{enum_class_name}.{LastPart}" + qualified_name_under = f"{enum_class_name}_{LastPart}" enum_member_found = None for qname in (qualified_name_dot, qualified_name_under): if qname in self.Trans.SymbolTable: @@ -2588,7 +2676,7 @@ class ExprCallHandle(BaseHandle): break if not enum_member_found: for key in self.Trans.SymbolTable: - if key == last_part: + if key == LastPart: info = self.Trans.SymbolTable[key] if info.IsEnumMember and info.EnumName == enum_class_name: enum_member_found = info @@ -2921,7 +3009,7 @@ class ExprCallHandle(BaseHandle): NewFunc = Gen._get_function(NewFuncName) StructType = Gen.structs.get(ClassName) if StructType: - result = Gen._alloca_entry(StructType, name=f"{ClassName}_alloca") + result = Gen._allocaEntry(StructType, name=f"{ClassName}_alloca") else: return ir.Constant(ir.IntType(32), 0) Gen.builder.call(NewFunc, [result], name=f"before_init_{ClassName}") @@ -2983,7 +3071,7 @@ class ExprCallHandle(BaseHandle): StructType = StructType.pointee is_opaque = isinstance(StructType, ir.IdentifiedStructType) and (StructType.elements is None or len(StructType.elements) == 0) if is_opaque: - result = Gen._alloca_entry(StructType, name=f"{ClassName}_alloca") + result = Gen._allocaEntry(StructType, name=f"{ClassName}_alloca") Gen.builder.store(ir.Constant(StructType, None), result) InitFunc = Gen.functions.get(InitFuncName) if not InitFunc: @@ -3006,7 +3094,7 @@ class ExprCallHandle(BaseHandle): adjusted_init = Gen._adjust_args(InitArgs, InitFunc) Gen.builder.call(InitFunc, adjusted_init, name=f"init_{ClassName}") return result - result = Gen._alloca_entry(StructType, name=f"{ClassName}_alloca") + result = Gen._allocaEntry(StructType, name=f"{ClassName}_alloca") # Call __new__ method if it exists (may replace self with heap pointer) if has_new_method: NewMethodFunc = Gen._find_function(NewMethodFuncName) @@ -3196,7 +3284,7 @@ class ExprCallHandle(BaseHandle): return ptr return None if isinstance(ValueVal.type, ir.PointerType) and isinstance(ValueVal.type.pointee, ir.PointerType): - LoadedValueVal = Gen._load(ValueVal, name="load_subscript") + LoadedValueVal = Gen._load(ValueVal, name="Load_subscript") if isinstance(LoadedValueVal.type, ir.PointerType): ElemPtr = Gen.builder.gep(LoadedValueVal, [IndexVal], name="subscript") return ElemPtr @@ -3232,7 +3320,7 @@ class ExprCallHandle(BaseHandle): IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") ElemPtr = Gen.builder.gep(VarPtr, [zero, IndexVal], name="subscript") return ElemPtr - arr_alloc = Gen._alloca_entry(ValueVal.type, name="arr_subscript_tmp") + arr_alloc = Gen._allocaEntry(ValueVal.type, name="arr_subscript_tmp") Gen._store(ValueVal, arr_alloc) ElemPtr = Gen.builder.gep(arr_alloc, [zero, IndexVal], name="subscript") return ElemPtr diff --git a/lib/core/Handles/HandlesExprFormat.py b/lib/core/Handles/HandlesExprFormat.py index 8000bcc..a0ab30b 100644 --- a/lib/core/Handles/HandlesExprFormat.py +++ b/lib/core/Handles/HandlesExprFormat.py @@ -1,110 +1,110 @@ -from __future__ import annotations -from typing import TYPE_CHECKING -if TYPE_CHECKING: - from lib.core.translator import Translator -from lib.core.Handles.HandlesBase import BaseHandle -import ast -import llvmlite.ir as ir - - -class ExprFormatHandle(BaseHandle): - def _HandleJoinedStrLlvm(self, Node, return_str=False): - Gen = self.Trans.LlvmGen - if not Gen or not Gen.builder: - return ir.Constant(ir.IntType(8).as_pointer(), None) - format_str = "" - cast_args = [] - for part in Node.values: - if isinstance(part, ast.Constant) and isinstance(part.value, str): - format_str += part.value.replace('\\', '\\\\').replace('%', '%%').replace('\n', '\\n').replace('\t', '\\t').replace('\0', '\\0') - elif isinstance(part, ast.FormattedValue): - fmt_class = self.Trans.ExprHandler._get_var_class(part.value, Gen) - if fmt_class and Gen._has_function(f'{fmt_class}.__str__'): - obj_val = self.HandleExprLlvm(part.value) - if obj_val: - if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8: - if fmt_class in Gen.structs: - obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[fmt_class]), name=f"cast_{fmt_class}") - val = Gen.builder.call(Gen._get_function(f'{fmt_class}.__str__'), [obj_val], name=f"call_{fmt_class}.__str__") - Gen._register_temp_ptr(val) - format_str += "%s" - cast_args.append(val) - else: - format_str += "%s" - cast_args.append(ir.Constant(ir.PointerType(ir.IntType(8)), None)) - continue - val = self.HandleExprLlvm(part.value) - if not val: - format_str += "%d" - cast_args.append(ir.Constant(ir.IntType(32), 0)) - continue - if isinstance(val.type, ir.PointerType): - pointee = val.type.pointee - if isinstance(pointee, ir.IntType) and pointee.width == 8: - format_str += "%s" - cast_args.append(val) - elif isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): - int_val = Gen.builder.ptrtoint(val, ir.IntType(64), name="fstr_ptr2int") - trunc_val = Gen.builder.trunc(int_val, ir.IntType(32), name="fstr_trunc") - format_str += "%d" - cast_args.append(trunc_val) - else: - loaded = Gen._load(val, name="fstr_deref") - if isinstance(loaded.type, ir.IntType): - if loaded.type.width == 8: - format_str += "%c" - ext = Gen.builder.zext(loaded, ir.IntType(32), name="fstr_char2int") - cast_args.append(ext) - else: - format_str += "%d" - cast_args.append(loaded) - elif isinstance(loaded.type, (ir.FloatType, ir.DoubleType)): - format_str += "%f" - cast_args.append(loaded) - elif isinstance(loaded.type, ir.PointerType): - format_str += "%s" - cast_args.append(loaded) - else: - format_str += "%d" - cast_args.append(loaded) - elif isinstance(val.type, ir.IntType): - if val.type.width == 8: - format_str += "%c" - ext = Gen.builder.zext(val, ir.IntType(32), name="fstr_char2int") - cast_args.append(ext) - elif val.type.width == 1: - zext = Gen.builder.zext(val, ir.IntType(32), name="fstr_bool2int") - format_str += "%d" - cast_args.append(zext) - else: - is_u = Gen._check_node_unsigned(part.value) - format_str += "%u" if is_u else "%d" - cast_args.append(val) - elif isinstance(val.type, (ir.FloatType, ir.DoubleType)): - format_str += "%f" - cast_args.append(val) - else: - format_str += "%d" - cast_args.append(val) - if not format_str and not cast_args: - return Gen.emit_constant("", 'string') - encoded = format_str.encode('utf-8') + b'\x00' - string_type = ir.ArrayType(ir.IntType(8), len(encoded)) - string_const = ir.Constant(string_type, bytearray(encoded)) - global_var = ir.GlobalVariable(Gen.module, string_type, name=f"str_const_{Gen.string_const_counter}") - Gen.string_const_counter += 1 - global_var.initializer = string_const - global_var.linkage = 'internal' - format_ptr = Gen.builder.bitcast(global_var, ir.PointerType(ir.IntType(8))) - if return_str: - buf_size = ir.Constant(ir.IntType(64), 1024) - calloc_type = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.IntType(64), ir.IntType(64)]) - calloc_func = Gen._get_or_declare_func('calloc', calloc_type) - buf_ptr = Gen.builder.call(calloc_func, [ir.Constant(ir.IntType(64), 1), buf_size], name="call_calloc_buf") - sprintf_func = Gen.get_or_declare_c_func('sprintf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8))], var_arg=True)) - sprintf_args = [buf_ptr, format_ptr] + cast_args - Gen.builder.call(sprintf_func, sprintf_args, name="call_sprintf") - return buf_ptr - printf_func = Gen.get_or_declare_c_func('printf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True)) - call_args = [format_ptr] + cast_args - return Gen.builder.call(printf_func, call_args, name="call_fstring") +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle +import ast +import llvmlite.ir as ir + + +class ExprFormatHandle(BaseHandle): + def _HandleJoinedStrLlvm(self, Node, return_str=False): + Gen = self.Trans.LlvmGen + if not Gen or not Gen.builder: + return ir.Constant(ir.IntType(8).as_pointer(), None) + format_str = "" + cast_args = [] + for part in Node.values: + if isinstance(part, ast.Constant) and isinstance(part.value, str): + format_str += part.value.replace('\\', '\\\\').replace('%', '%%').replace('\n', '\\n').replace('\t', '\\t').replace('\0', '\\0') + elif isinstance(part, ast.FormattedValue): + fmt_class = self.Trans.ExprHandler._get_var_class(part.value, Gen) + if fmt_class and Gen._has_function(f'{fmt_class}.__str__'): + obj_val = self.HandleExprLlvm(part.value) + if obj_val: + if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8: + if fmt_class in Gen.structs: + obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[fmt_class]), name=f"cast_{fmt_class}") + val = Gen.builder.call(Gen._get_function(f'{fmt_class}.__str__'), [obj_val], name=f"call_{fmt_class}.__str__") + Gen.RegisterTempPtr(val) + format_str += "%s" + cast_args.append(val) + else: + format_str += "%s" + cast_args.append(ir.Constant(ir.PointerType(ir.IntType(8)), None)) + continue + val = self.HandleExprLlvm(part.value) + if not val: + format_str += "%d" + cast_args.append(ir.Constant(ir.IntType(32), 0)) + continue + if isinstance(val.type, ir.PointerType): + pointee = val.type.pointee + if isinstance(pointee, ir.IntType) and pointee.width == 8: + format_str += "%s" + cast_args.append(val) + elif isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): + int_val = Gen.builder.ptrtoint(val, ir.IntType(64), name="fstr_ptr2int") + trunc_val = Gen.builder.trunc(int_val, ir.IntType(32), name="fstr_trunc") + format_str += "%d" + cast_args.append(trunc_val) + else: + Loaded = Gen._load(val, name="fstr_deref") + if isinstance(Loaded.type, ir.IntType): + if Loaded.type.width == 8: + format_str += "%c" + ext = Gen.builder.zext(Loaded, ir.IntType(32), name="fstr_char2int") + cast_args.append(ext) + else: + format_str += "%d" + cast_args.append(Loaded) + elif isinstance(Loaded.type, (ir.FloatType, ir.DoubleType)): + format_str += "%f" + cast_args.append(Loaded) + elif isinstance(Loaded.type, ir.PointerType): + format_str += "%s" + cast_args.append(Loaded) + else: + format_str += "%d" + cast_args.append(Loaded) + elif isinstance(val.type, ir.IntType): + if val.type.width == 8: + format_str += "%c" + ext = Gen.builder.zext(val, ir.IntType(32), name="fstr_char2int") + cast_args.append(ext) + elif val.type.width == 1: + zext = Gen.builder.zext(val, ir.IntType(32), name="fstr_bool2int") + format_str += "%d" + cast_args.append(zext) + else: + is_u = Gen._check_node_unsigned(part.value) + format_str += "%u" if is_u else "%d" + cast_args.append(val) + elif isinstance(val.type, (ir.FloatType, ir.DoubleType)): + format_str += "%f" + cast_args.append(val) + else: + format_str += "%d" + cast_args.append(val) + if not format_str and not cast_args: + return Gen.emit_constant("", 'string') + encoded = format_str.encode('utf-8') + b'\x00' + string_type = ir.ArrayType(ir.IntType(8), len(encoded)) + string_const = ir.Constant(string_type, bytearray(encoded)) + global_var = ir.GlobalVariable(Gen.module, string_type, name=f"str_const_{Gen.string_const_counter}") + Gen.string_const_counter += 1 + global_var.initializer = string_const + global_var.linkage = 'internal' + format_ptr = Gen.builder.bitcast(global_var, ir.PointerType(ir.IntType(8))) + if return_str: + buf_size = ir.Constant(ir.IntType(64), 1024) + calloc_type = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.IntType(64), ir.IntType(64)]) + calloc_func = Gen._get_or_declare_func('calloc', calloc_type) + buf_ptr = Gen.builder.call(calloc_func, [ir.Constant(ir.IntType(64), 1), buf_size], name="call_calloc_buf") + sprintf_func = Gen.get_or_declare_c_func('sprintf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8))], var_arg=True)) + sprintf_args = [buf_ptr, format_ptr] + cast_args + Gen.builder.call(sprintf_func, sprintf_args, name="call_sprintf") + return buf_ptr + printf_func = Gen.get_or_declare_c_func('printf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True)) + call_args = [format_ptr] + cast_args + return Gen.builder.call(printf_func, call_args, name="call_fstring") diff --git a/lib/core/Handles/HandlesExprLambda.py b/lib/core/Handles/HandlesExprLambda.py index 9c3309c..a8d8410 100644 --- a/lib/core/Handles/HandlesExprLambda.py +++ b/lib/core/Handles/HandlesExprLambda.py @@ -1,232 +1,232 @@ -from __future__ import annotations -from typing import TYPE_CHECKING -if TYPE_CHECKING: - from lib.core.translator import Translator -from lib.core.Handles.HandlesBase import BaseHandle -import ast -import llvmlite.ir as ir - - -class ExprLambdaHandle(BaseHandle): - def _HandleLambdaLlvm(self, Node): - Gen = self.Trans.LlvmGen - if not getattr(Gen, '_lambda_counter', None): - Gen._lambda_counter = 0 - lambda_id = Gen._lambda_counter - Gen._lambda_counter += 1 - fn_name = f"lambda_fn_{lambda_id}" - captured_vars = self._get_lambda_captured_vars(Node) - env_types = [] - env_var_names = [] - for var_name, var_val in captured_vars: - env_types.append(var_val.type) - env_var_names.append(var_name) - env_struct_type = ir.LiteralStructType(env_types) if env_types else ir.LiteralStructType([]) - ret_type = self.Trans.ExprUtils._infer_expr_llvm_type_full(Node.body) - param_types = [ir.PointerType(env_struct_type)] - if Node.args: - for arg in Node.args.args: - param_types.append(ir.IntType(32)) - fn_type = ir.FunctionType(ret_type, param_types) - fn = ir.Function(Gen.module, fn_type, name=fn_name) - Gen.functions[fn_name] = fn - entry_block = fn.append_basic_block(name=f"{fn_name}_entry") - prev_builder = Gen.builder - prev_func = Gen.func - prev_vars = dict(Gen.variables) - Gen.builder = ir.IRBuilder(entry_block) - Gen.func = fn - Gen.variables = {} - for i, arg in enumerate(fn.args): - arg.name = f"arg_{i}" if i > 0 else "env" - if env_types: - for idx, var_name in enumerate(env_var_names): - env_ptr = fn.args[0] - zero = ir.Constant(ir.IntType(32), 0) - member_ptr = Gen.builder.gep(env_ptr, [zero, ir.Constant(ir.IntType(32), idx)], name=f"env_{var_name}") - loaded = Gen._load(member_ptr, name=f"load_env_{var_name}") - temp_alloca = Gen._alloca(loaded.type, name=f"temp_{var_name}") - Gen._store(loaded, temp_alloca) - Gen.variables[var_name] = temp_alloca - if Node.args: - for i, arg in enumerate(Node.args.args): - Gen.variables[arg.arg] = Gen._alloca(ir.IntType(32), name=arg.arg) - Gen._store(fn.args[i + 1], Gen.variables[arg.arg]) - body_val = self.HandleExprLlvm(Node.body) - if body_val: - if isinstance(body_val.type, ir.PointerType) and not isinstance(ret_type, ir.PointerType): - body_val = Gen._load(body_val, name="load_lambda_ret") - if body_val.type != ret_type: - if isinstance(body_val.type, ir.IntType) and isinstance(ret_type, ir.IntType): - if body_val.type.width < ret_type.width: - body_val = Gen.builder.zext(body_val, ret_type, name="zext_lambda_ret") - elif body_val.type.width > ret_type.width: - body_val = Gen.builder.trunc(body_val, ret_type, name="trunc_lambda_ret") - elif isinstance(body_val.type, ir.PointerType) and isinstance(ret_type, ir.PointerType): - body_val = Gen.builder.bitcast(body_val, ret_type, name="bitcast_lambda_ret") - Gen.builder.ret(body_val) - else: - Gen.builder.ret(ir.Constant(ret_type, 0)) - Gen.builder = prev_builder - Gen.func = prev_func - Gen.variables = prev_vars - closure_struct_type = ir.LiteralStructType([ - ir.PointerType(ir.IntType(8)), - ir.PointerType(fn_type) - ]) - closure_ptr = Gen._alloca(closure_struct_type, name=f"closure_{lambda_id}") - env_ptr = Gen._alloca(env_struct_type, name=f"env_{lambda_id}") - if env_types: - for idx, (var_name, var_val) in enumerate(captured_vars): - zero = ir.Constant(ir.IntType(32), 0) - member_ptr = Gen.builder.gep(env_ptr, [zero, ir.Constant(ir.IntType(32), idx)], name=f"store_env_{var_name}") - Gen._store(var_val, member_ptr) - zero = ir.Constant(ir.IntType(32), 0) - env_field_ptr = Gen.builder.gep(closure_ptr, [zero, zero], name="closure_env_ptr") - env_i8_ptr = Gen.builder.bitcast(env_ptr, ir.PointerType(ir.IntType(8)), name="env_i8_ptr") - Gen._store(env_i8_ptr, env_field_ptr) - fn_field_ptr = Gen.builder.gep(closure_ptr, [zero, ir.Constant(ir.IntType(32), 1)], name="closure_fn_ptr") - Gen._store(fn, fn_field_ptr) - return closure_ptr - - def _get_lambda_captured_vars(self, Node): - Gen = self.Trans.LlvmGen - captured = [] - free_vars = self._get_lambda_free_vars(Node) - for var_name in free_vars: - if var_name in Gen.variables: - var_ptr = Gen.variables[var_name] - if isinstance(var_ptr, ir.AllocaInstr) or isinstance(var_ptr, ir.GlobalVariable): - loaded = Gen._load(var_ptr, name=f"capture_{var_name}") - captured.append((var_name, loaded)) - return captured - - def _get_lambda_free_vars(self, Node): - bound_vars = set() - free_vars = set() - # 收集 lambda body 中的 bound 和 free 变量 - self.Trans.ExprUtils._collect_names(Node.body, bound_vars, free_vars) - # lambda 参数也是 bound 的 - if Node.args: - for arg in Node.args.args: - bound_vars.add(arg.arg) - # free 变量 = 在 body 中引用(Load)但不是参数也不是 body 内赋值的变量 - result = free_vars - bound_vars - return list(result) - - def _HandleIfExpLlvm(self, Node): - Gen = self.Trans.LlvmGen - TestVal = self.HandleExprLlvm(Node.test) - if not TestVal: - return None - if not isinstance(TestVal.type, ir.IntType) or TestVal.type.width != 1: - TestVal = Gen.builder.icmp_signed('!=', TestVal, Gen._zero_const(TestVal.type), name="ifexp_cond") - ThenBB = Gen.func.append_basic_block(name="ifexp.then") - ElseBB = Gen.func.append_basic_block(name="ifexp.else") - MergeBB = Gen.func.append_basic_block(name="ifexp.end") - Gen.builder.cbranch(TestVal, ThenBB, ElseBB) - # 先在 ThenBB 中生成 BodyVal - Gen.builder.position_at_start(ThenBB) - BodyVal = self.HandleExprLlvm(Node.body) - if not BodyVal: - BodyVal = ir.Constant(ir.IntType(32), 0) - ThenEndBB = Gen.builder.block - # 在 ElseBB 中生成 OrelseVal - Gen.builder.position_at_start(ElseBB) - OrelseVal = self.HandleExprLlvm(Node.orelse) - if not OrelseVal: - OrelseVal = ir.Constant(ir.IntType(32), 0) - ElseEndBB = Gen.builder.block - # 确定 phi 节点的目标类型 - result_type = BodyVal.type - if BodyVal.type != OrelseVal.type: - if isinstance(BodyVal.type, ir.IntType) and isinstance(OrelseVal.type, ir.IntType): - result_type = BodyVal.type if BodyVal.type.width >= OrelseVal.type.width else OrelseVal.type - elif isinstance(BodyVal.type, ir.PointerType) and isinstance(OrelseVal.type, ir.PointerType): - # 指针类型,使用 BodyVal 的类型 - result_type = BodyVal.type - elif isinstance(BodyVal.type, ir.IntType) and isinstance(OrelseVal.type, ir.PointerType): - # BodyVal 是整数,OrelseVal 是指针(字符串字面量) - # 如果指针指向 i8,将指针转换为 i8(加载字符) - if isinstance(OrelseVal.type.pointee, ir.IntType) and OrelseVal.type.pointee.width == 8: - result_type = ir.IntType(8) - else: - result_type = OrelseVal.type - elif isinstance(BodyVal.type, ir.PointerType) and isinstance(OrelseVal.type, ir.IntType): - # BodyVal 是指针(字符串字面量),OrelseVal 是整数 - # 如果指针指向 i8,将指针转换为 i8(加载字符) - if isinstance(BodyVal.type.pointee, ir.IntType) and BodyVal.type.pointee.width == 8: - result_type = ir.IntType(8) - else: - result_type = BodyVal.type - else: - result_type = OrelseVal.type - # 在 ThenBB 末尾添加类型转换(如果需要)和分支 - if not ThenEndBB.is_terminated: - Gen.builder.position_at_end(ThenEndBB) - if BodyVal.type != result_type: - if isinstance(BodyVal.type, ir.IntType) and isinstance(result_type, ir.IntType): - if BodyVal.type.width < result_type.width: - BodyVal = Gen.builder.zext(BodyVal, result_type, name="ifexp_body_zext") - else: - BodyVal = Gen.builder.trunc(BodyVal, result_type, name="ifexp_body_trunc") - elif isinstance(BodyVal.type, ir.IntType) and isinstance(result_type, ir.PointerType): - # 如果 result_type 是 i8*,说明 Else 分支是字符串字面量 - # 不应该将整数转换为指针,而应该保持整数类型 - # 这里将 result_type 改为 i8 - result_type = ir.IntType(8) - # 重新处理 Else 分支的类型转换 - elif isinstance(BodyVal.type, ir.PointerType) and isinstance(result_type, ir.IntType): - # 指针转整数 - BodyVal = Gen.builder.ptrtoint(BodyVal, result_type, name="ifexp_body_ptr2int") - Gen.builder.branch(MergeBB) - # 在 ElseBB 末尾添加类型转换(如果需要)和分支 - if not ElseEndBB.is_terminated: - Gen.builder.position_at_end(ElseEndBB) - if OrelseVal.type != result_type: - if isinstance(OrelseVal.type, ir.IntType) and isinstance(result_type, ir.IntType): - if OrelseVal.type.width < result_type.width: - OrelseVal = Gen.builder.zext(OrelseVal, result_type, name="ifexp_orelse_zext") - else: - OrelseVal = Gen.builder.trunc(OrelseVal, result_type, name="ifexp_orelse_trunc") - elif isinstance(OrelseVal.type, ir.IntType) and isinstance(result_type, ir.PointerType): - # 如果 result_type 是 i8*,说明 BodyVal 分支是字符串字面量 - # 不应该将整数转换为指针,而应该保持整数类型 - # 这里将 result_type 改为 i8 - result_type = ir.IntType(8) - # 重新处理 BodyVal 分支的类型转换(已经在上面处理过了) - elif isinstance(OrelseVal.type, ir.PointerType) and isinstance(result_type, ir.IntType): - # 如果指针指向 i8,加载字符值 - if isinstance(OrelseVal.type.pointee, ir.IntType) and OrelseVal.type.pointee.width == 8: - OrelseVal = Gen._load(OrelseVal, name="ifexp_orelse_load_char") - else: - OrelseVal = Gen.builder.ptrtoint(OrelseVal, result_type, name="ifexp_orelse_ptr2int") - Gen.builder.branch(MergeBB) - Gen.builder.position_at_start(MergeBB) - result_phi = Gen.builder.phi(result_type, name="ifexp.result") - result_phi.add_incoming(BodyVal, ThenEndBB) - result_phi.add_incoming(OrelseVal, ElseEndBB) - return result_phi - - def _HandleNamedExprLlvm(self, Node): - Gen = self.Trans.LlvmGen - ValueVal = self.HandleExprLlvm(Node.value) - if not ValueVal: - return None - TargetName = Node.target.id - if TargetName in Gen._reg_values: - del Gen._reg_values[TargetName] - if TargetName in Gen.variables and Gen.variables[TargetName] is not None: - VarPtr = Gen.variables[TargetName] - if VarPtr.type.pointee == ValueVal.type: - Gen._store(ValueVal, VarPtr) - else: - NewVar = Gen._alloca(ValueVal.type, name=TargetName) - Gen._store(ValueVal, NewVar) - Gen.variables[TargetName] = NewVar - else: - NewVar = Gen._alloca(ValueVal.type, name=TargetName) - Gen._store(ValueVal, NewVar) - Gen.variables[TargetName] = NewVar - Gen._reg_values[TargetName] = ValueVal - return ValueVal +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle +import ast +import llvmlite.ir as ir + + +class ExprLambdaHandle(BaseHandle): + def _HandleLambdaLlvm(self, Node): + Gen = self.Trans.LlvmGen + if not getattr(Gen, '_lambda_counter', None): + Gen._lambda_counter = 0 + lambda_id = Gen._lambda_counter + Gen._lambda_counter += 1 + fn_name = f"lambda_fn_{lambda_id}" + captured_vars = self._get_lambda_captured_vars(Node) + env_types = [] + env_var_names = [] + for var_name, var_val in captured_vars: + env_types.append(var_val.type) + env_var_names.append(var_name) + env_struct_type = ir.LiteralStructType(env_types) if env_types else ir.LiteralStructType([]) + ret_type = self.Trans.ExprUtils._infer_expr_llvm_type_full(Node.body) + param_types = [ir.PointerType(env_struct_type)] + if Node.args: + for arg in Node.args.args: + param_types.append(ir.IntType(32)) + fn_type = ir.FunctionType(ret_type, param_types) + fn = ir.Function(Gen.module, fn_type, name=fn_name) + Gen.functions[fn_name] = fn + entry_block = fn.append_basic_block(name=f"{fn_name}_entry") + prev_builder = Gen.builder + prev_func = Gen.func + prev_vars = dict(Gen.variables) + Gen.builder = ir.IRBuilder(entry_block) + Gen.func = fn + Gen.variables = {} + for i, arg in enumerate(fn.args): + arg.name = f"arg_{i}" if i > 0 else "env" + if env_types: + for idx, var_name in enumerate(env_var_names): + env_ptr = fn.args[0] + zero = ir.Constant(ir.IntType(32), 0) + member_ptr = Gen.builder.gep(env_ptr, [zero, ir.Constant(ir.IntType(32), idx)], name=f"env_{var_name}") + Loaded = Gen._load(member_ptr, name=f"Load_env_{var_name}") + temp_alloca = Gen._alloca(Loaded.type, name=f"temp_{var_name}") + Gen._store(Loaded, temp_alloca) + Gen.variables[var_name] = temp_alloca + if Node.args: + for i, arg in enumerate(Node.args.args): + Gen.variables[arg.arg] = Gen._alloca(ir.IntType(32), name=arg.arg) + Gen._store(fn.args[i + 1], Gen.variables[arg.arg]) + body_val = self.HandleExprLlvm(Node.body) + if body_val: + if isinstance(body_val.type, ir.PointerType) and not isinstance(ret_type, ir.PointerType): + body_val = Gen._load(body_val, name="Load_lambda_ret") + if body_val.type != ret_type: + if isinstance(body_val.type, ir.IntType) and isinstance(ret_type, ir.IntType): + if body_val.type.width < ret_type.width: + body_val = Gen.builder.zext(body_val, ret_type, name="zext_lambda_ret") + elif body_val.type.width > ret_type.width: + body_val = Gen.builder.trunc(body_val, ret_type, name="trunc_lambda_ret") + elif isinstance(body_val.type, ir.PointerType) and isinstance(ret_type, ir.PointerType): + body_val = Gen.builder.bitcast(body_val, ret_type, name="bitcast_lambda_ret") + Gen.builder.ret(body_val) + else: + Gen.builder.ret(ir.Constant(ret_type, 0)) + Gen.builder = prev_builder + Gen.func = prev_func + Gen.variables = prev_vars + closure_struct_type = ir.LiteralStructType([ + ir.PointerType(ir.IntType(8)), + ir.PointerType(fn_type) + ]) + closure_ptr = Gen._alloca(closure_struct_type, name=f"closure_{lambda_id}") + env_ptr = Gen._alloca(env_struct_type, name=f"env_{lambda_id}") + if env_types: + for idx, (var_name, var_val) in enumerate(captured_vars): + zero = ir.Constant(ir.IntType(32), 0) + member_ptr = Gen.builder.gep(env_ptr, [zero, ir.Constant(ir.IntType(32), idx)], name=f"store_env_{var_name}") + Gen._store(var_val, member_ptr) + zero = ir.Constant(ir.IntType(32), 0) + env_field_ptr = Gen.builder.gep(closure_ptr, [zero, zero], name="closure_env_ptr") + env_i8_ptr = Gen.builder.bitcast(env_ptr, ir.PointerType(ir.IntType(8)), name="env_i8_ptr") + Gen._store(env_i8_ptr, env_field_ptr) + fn_field_ptr = Gen.builder.gep(closure_ptr, [zero, ir.Constant(ir.IntType(32), 1)], name="closure_fn_ptr") + Gen._store(fn, fn_field_ptr) + return closure_ptr + + def _get_lambda_captured_vars(self, Node): + Gen = self.Trans.LlvmGen + captured = [] + free_vars = self._get_lambda_free_vars(Node) + for var_name in free_vars: + if var_name in Gen.variables: + var_ptr = Gen.variables[var_name] + if isinstance(var_ptr, ir.AllocaInstr) or isinstance(var_ptr, ir.GlobalVariable): + Loaded = Gen._load(var_ptr, name=f"capture_{var_name}") + captured.append((var_name, Loaded)) + return captured + + def _get_lambda_free_vars(self, Node): + bound_vars = set() + free_vars = set() + # 收集 lambda body 中的 bound 和 free 变量 + self.Trans.ExprUtils._collect_names(Node.body, bound_vars, free_vars) + # lambda 参数也是 bound 的 + if Node.args: + for arg in Node.args.args: + bound_vars.add(arg.arg) + # free 变量 = 在 body 中引用(Load)但不是参数也不是 body 内赋值的变量 + result = free_vars - bound_vars + return list(result) + + def _HandleIfExpLlvm(self, Node): + Gen = self.Trans.LlvmGen + TestVal = self.HandleExprLlvm(Node.test) + if not TestVal: + return None + if not isinstance(TestVal.type, ir.IntType) or TestVal.type.width != 1: + TestVal = Gen.builder.icmp_signed('!=', TestVal, Gen._ZeroConst(TestVal.type), name="ifexp_cond") + ThenBB = Gen.func.append_basic_block(name="ifexp.then") + ElseBB = Gen.func.append_basic_block(name="ifexp.else") + MergeBB = Gen.func.append_basic_block(name="ifexp.end") + Gen.builder.cbranch(TestVal, ThenBB, ElseBB) + # 先在 ThenBB 中生成 BodyVal + Gen.builder.position_at_start(ThenBB) + BodyVal = self.HandleExprLlvm(Node.body) + if not BodyVal: + BodyVal = ir.Constant(ir.IntType(32), 0) + ThenEndBB = Gen.builder.block + # 在 ElseBB 中生成 OrelseVal + Gen.builder.position_at_start(ElseBB) + OrelseVal = self.HandleExprLlvm(Node.orelse) + if not OrelseVal: + OrelseVal = ir.Constant(ir.IntType(32), 0) + ElseEndBB = Gen.builder.block + # 确定 phi 节点的目标类型 + result_type = BodyVal.type + if BodyVal.type != OrelseVal.type: + if isinstance(BodyVal.type, ir.IntType) and isinstance(OrelseVal.type, ir.IntType): + result_type = BodyVal.type if BodyVal.type.width >= OrelseVal.type.width else OrelseVal.type + elif isinstance(BodyVal.type, ir.PointerType) and isinstance(OrelseVal.type, ir.PointerType): + # 指针类型,使用 BodyVal 的类型 + result_type = BodyVal.type + elif isinstance(BodyVal.type, ir.IntType) and isinstance(OrelseVal.type, ir.PointerType): + # BodyVal 是整数,OrelseVal 是指针(字符串字面量) + # 如果指针指向 i8,将指针转换为 i8(加载字符) + if isinstance(OrelseVal.type.pointee, ir.IntType) and OrelseVal.type.pointee.width == 8: + result_type = ir.IntType(8) + else: + result_type = OrelseVal.type + elif isinstance(BodyVal.type, ir.PointerType) and isinstance(OrelseVal.type, ir.IntType): + # BodyVal 是指针(字符串字面量),OrelseVal 是整数 + # 如果指针指向 i8,将指针转换为 i8(加载字符) + if isinstance(BodyVal.type.pointee, ir.IntType) and BodyVal.type.pointee.width == 8: + result_type = ir.IntType(8) + else: + result_type = BodyVal.type + else: + result_type = OrelseVal.type + # 在 ThenBB 末尾添加类型转换(如果需要)和分支 + if not ThenEndBB.is_terminated: + Gen.builder.position_at_end(ThenEndBB) + if BodyVal.type != result_type: + if isinstance(BodyVal.type, ir.IntType) and isinstance(result_type, ir.IntType): + if BodyVal.type.width < result_type.width: + BodyVal = Gen.builder.zext(BodyVal, result_type, name="ifexp_body_zext") + else: + BodyVal = Gen.builder.trunc(BodyVal, result_type, name="ifexp_body_trunc") + elif isinstance(BodyVal.type, ir.IntType) and isinstance(result_type, ir.PointerType): + # 如果 result_type 是 i8*,说明 Else 分支是字符串字面量 + # 不应该将整数转换为指针,而应该保持整数类型 + # 这里将 result_type 改为 i8 + result_type = ir.IntType(8) + # 重新处理 Else 分支的类型转换 + elif isinstance(BodyVal.type, ir.PointerType) and isinstance(result_type, ir.IntType): + # 指针转整数 + BodyVal = Gen.builder.ptrtoint(BodyVal, result_type, name="ifexp_body_ptr2int") + Gen.builder.branch(MergeBB) + # 在 ElseBB 末尾添加类型转换(如果需要)和分支 + if not ElseEndBB.is_terminated: + Gen.builder.position_at_end(ElseEndBB) + if OrelseVal.type != result_type: + if isinstance(OrelseVal.type, ir.IntType) and isinstance(result_type, ir.IntType): + if OrelseVal.type.width < result_type.width: + OrelseVal = Gen.builder.zext(OrelseVal, result_type, name="ifexp_orelse_zext") + else: + OrelseVal = Gen.builder.trunc(OrelseVal, result_type, name="ifexp_orelse_trunc") + elif isinstance(OrelseVal.type, ir.IntType) and isinstance(result_type, ir.PointerType): + # 如果 result_type 是 i8*,说明 BodyVal 分支是字符串字面量 + # 不应该将整数转换为指针,而应该保持整数类型 + # 这里将 result_type 改为 i8 + result_type = ir.IntType(8) + # 重新处理 BodyVal 分支的类型转换(已经在上面处理过了) + elif isinstance(OrelseVal.type, ir.PointerType) and isinstance(result_type, ir.IntType): + # 如果指针指向 i8,加载字符值 + if isinstance(OrelseVal.type.pointee, ir.IntType) and OrelseVal.type.pointee.width == 8: + OrelseVal = Gen._load(OrelseVal, name="ifexp_orelse_Load_char") + else: + OrelseVal = Gen.builder.ptrtoint(OrelseVal, result_type, name="ifexp_orelse_ptr2int") + Gen.builder.branch(MergeBB) + Gen.builder.position_at_start(MergeBB) + result_phi = Gen.builder.phi(result_type, name="ifexp.result") + result_phi.add_incoming(BodyVal, ThenEndBB) + result_phi.add_incoming(OrelseVal, ElseEndBB) + return result_phi + + def _HandleNamedExprLlvm(self, Node): + Gen = self.Trans.LlvmGen + ValueVal = self.HandleExprLlvm(Node.value) + if not ValueVal: + return None + TargetName = Node.target.id + if TargetName in Gen._reg_values: + del Gen._reg_values[TargetName] + if TargetName in Gen.variables and Gen.variables[TargetName] is not None: + VarPtr = Gen.variables[TargetName] + if VarPtr.type.pointee == ValueVal.type: + Gen._store(ValueVal, VarPtr) + else: + NewVar = Gen._alloca(ValueVal.type, name=TargetName) + Gen._store(ValueVal, NewVar) + Gen.variables[TargetName] = NewVar + else: + NewVar = Gen._alloca(ValueVal.type, name=TargetName) + Gen._store(ValueVal, NewVar) + Gen.variables[TargetName] = NewVar + Gen._reg_values[TargetName] = ValueVal + return ValueVal diff --git a/lib/core/Handles/HandlesExprOps.py b/lib/core/Handles/HandlesExprOps.py index 5b061ff..a44c677 100644 --- a/lib/core/Handles/HandlesExprOps.py +++ b/lib/core/Handles/HandlesExprOps.py @@ -1,402 +1,402 @@ -from __future__ import annotations -from typing import TYPE_CHECKING -if TYPE_CHECKING: - from lib.core.translator import Translator -from lib.core.Handles.HandlesBase import BaseHandle -import ast -import llvmlite.ir as ir - - -class ExprOpsHandle(BaseHandle): - def _HandleBinOpLlvm(self, Node, VarType=None): - Gen = self.Trans.LlvmGen - Gen._set_node_info(Node, "BinOp") - LeftVal = self.HandleExprLlvm(Node.left, VarType) - if not LeftVal: - return None - RightVal = self.HandleExprLlvm(Node.right, VarType) - if not RightVal: - return None - Op = self.Trans.ExprHandler.GetOpSymbol(Node.op) - if not Op: - return None - OP_OVERLOAD_MAP = { - '+': '__add__', '-': '__sub__', '*': '__mul__', - '/': '__truediv__', '//': '__floordiv__', '%': '__mod__', - '**': '__pow__', - } - if Op in OP_OVERLOAD_MAP: - LeftClassName = None - if isinstance(LeftVal.type, ir.PointerType): - pointee = LeftVal.type.pointee - if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): - for CN, ST in Gen.structs.items(): - if pointee == ST: - LeftClassName = CN - break - elif isinstance(pointee, ir.IntType) and pointee.width == 8: - LeftClassName = self.Trans.ExprUtils._get_var_class(Node.left, Gen) - if LeftClassName and LeftClassName in Gen.structs: - TargetStructPtr = ir.PointerType(Gen.structs[LeftClassName]) - LeftVal = Gen.builder.bitcast(LeftVal, TargetStructPtr, name=f"bitcast_to_{LeftClassName}") - if LeftClassName is None and isinstance(Node.left, ast.Name): - LeftClassName = Gen.var_struct_class.get(Node.left.id) - if LeftClassName and LeftClassName in Gen.structs: - if isinstance(LeftVal.type, ir.PointerType) and isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8: - TargetStructPtr = ir.PointerType(Gen.structs[LeftClassName]) - LeftVal = Gen.builder.bitcast(LeftVal, TargetStructPtr, name=f"bitcast_to_{LeftClassName}") - if LeftClassName: - op_name = OP_OVERLOAD_MAP[Op] - result = self.Trans.ExprUtils._try_operator_overload(LeftClassName, op_name, LeftVal, Gen, RightVal) - if result is not None: - return result - if Op in ('+', 'Add') and isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.IntType): - if isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8: - if isinstance(Node.left, ast.Constant) and isinstance(Node.left.value, str) and len(Node.left.value) == 1: - CharVal = Gen._load(LeftVal, name="load_char_const") - CharAsInt = Gen.builder.zext(CharVal, RightVal.type, name="char_to_int") - result = Gen.builder.add(CharAsInt, RightVal, name="char_add") - TruncResult = Gen.builder.trunc(result, ir.IntType(8), name="add_to_char") - return TruncResult - is_unsigned = Gen._check_node_unsigned(Node.left) or Gen._check_node_unsigned(Node.right) - if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType): - if LeftVal.type.width < RightVal.type.width: - need_zext = is_unsigned or Gen._check_node_unsigned(Node.left) or LeftVal.type.width == 8 - if not need_zext and isinstance(RightVal, ir.Constant): - signed_max = (1 << (LeftVal.type.width - 1)) - 1 - try: - if RightVal.constant > signed_max: - need_zext = True - except (TypeError, ValueError): - pass - if need_zext: - LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_left") - else: - LeftVal = Gen.builder.sext(LeftVal, RightVal.type, name="sext_left") - elif LeftVal.type.width > RightVal.type.width: - need_zext = is_unsigned or Gen._check_node_unsigned(Node.right) or RightVal.type.width == 8 - if not need_zext and isinstance(LeftVal, ir.Constant): - signed_max = (1 << (RightVal.type.width - 1)) - 1 - try: - if LeftVal.constant > signed_max: - need_zext = True - except (TypeError, ValueError): - pass - if need_zext: - RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_right") - else: - RightVal = Gen.builder.sext(RightVal, LeftVal.type, name="zext_right") - elif isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.IntType): - if Op not in ('+', '-', 'Add', 'Sub') and isinstance(LeftVal.type.pointee, ir.IntType): - LeftVal = Gen._load(LeftVal, name="deref_ptr_binop") - if LeftVal.type.width < RightVal.type.width: - LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_deref_left") - elif LeftVal.type.width > RightVal.type.width: - RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_right_deref") - elif isinstance(RightVal.type, ir.PointerType) and isinstance(LeftVal.type, ir.IntType): - if Op not in ('+', '-', 'Add', 'Sub') and isinstance(RightVal.type.pointee, ir.IntType): - RightVal = Gen._load(RightVal, name="deref_ptr_binop_r") - if RightVal.type.width < LeftVal.type.width: - RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_deref_right") - elif RightVal.type.width > LeftVal.type.width: - LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_left_deref") - if Op in ('>>', 'RShift') and isinstance(Node.left, ast.Name): - vname = Node.left.id - if vname in Gen.var_signedness and Gen.var_signedness[vname]: - is_unsigned = True - result = Gen.emit_binary_op(Op, LeftVal, RightVal, is_unsigned=is_unsigned) - return result - - def _HandleBoolOpLlvm(self, Node): - Gen = self.Trans.LlvmGen - - def _to_bool(val, name): - if isinstance(val.type, (ir.FloatType, ir.DoubleType)): - return Gen.builder.fcmp_ordered('!=', val, ir.Constant(val.type, 0.0), name=name) - if not isinstance(val.type, ir.IntType) or val.type.width != 1: - return Gen.builder.icmp_signed('!=', val, Gen._zero_const(val.type), name=name) - return val - - values = Node.values - if len(values) < 2: - return self.HandleExprLlvm(values[0]) if values else None - if isinstance(Node.op, ast.And): - phi_incomings = [] - end_bb = Gen.func.append_basic_block(name="and.end") - for idx in range(len(values) - 1): - val = self.HandleExprLlvm(values[idx]) - if not val: - if not end_bb.is_terminated: - saved_block = Gen.builder.block - Gen.builder.position_at_start(end_bb) - Gen.builder.unreachable() - Gen.builder.position_at_end(saved_block) - return None - if not isinstance(val.type, ir.IntType) or val.type.width != 1: - val = _to_bool(val, f"andcond{idx}") - cur_bb = Gen.builder.block - next_bb = Gen.func.append_basic_block(name=f"and.rhs{idx}") - Gen.builder.cbranch(val, next_bb, end_bb) - phi_incomings.append((ir.Constant(ir.IntType(1), 0), cur_bb)) - Gen.builder.position_at_start(next_bb) - last_val = self.HandleExprLlvm(values[-1]) - if not last_val: - last_val = ir.Constant(ir.IntType(1), 0) - if not isinstance(last_val.type, ir.IntType) or last_val.type.width != 1: - last_val = _to_bool(last_val, "andcond_last") - last_bb = Gen.builder.block - Gen.builder.branch(end_bb) - Gen.builder.position_at_start(end_bb) - result_phi = Gen.builder.phi(ir.IntType(1), name="and.result") - for const_val, bb in phi_incomings: - result_phi.add_incoming(const_val, bb) - result_phi.add_incoming(last_val, last_bb) - return result_phi - elif isinstance(Node.op, ast.Or): - phi_incomings = [] - end_bb = Gen.func.append_basic_block(name="or.end") - for idx in range(len(values) - 1): - val = self.HandleExprLlvm(values[idx]) - if not val: - if not end_bb.is_terminated: - saved_block = Gen.builder.block - Gen.builder.position_at_start(end_bb) - Gen.builder.unreachable() - Gen.builder.position_at_end(saved_block) - return None - if not isinstance(val.type, ir.IntType) or val.type.width != 1: - val = _to_bool(val, f"orcond{idx}") - cur_bb = Gen.builder.block - next_bb = Gen.func.append_basic_block(name=f"or.rhs{idx}") - Gen.builder.cbranch(val, end_bb, next_bb) - phi_incomings.append((ir.Constant(ir.IntType(1), 1), cur_bb)) - Gen.builder.position_at_start(next_bb) - last_val = self.HandleExprLlvm(values[-1]) - if not last_val: - last_val = ir.Constant(ir.IntType(1), 1) - if not isinstance(last_val.type, ir.IntType) or last_val.type.width != 1: - last_val = _to_bool(last_val, "orcond_last") - last_bb = Gen.builder.block - Gen.builder.branch(end_bb) - Gen.builder.position_at_start(end_bb) - result_phi = Gen.builder.phi(ir.IntType(1), name="or.result") - for const_val, bb in phi_incomings: - result_phi.add_incoming(const_val, bb) - result_phi.add_incoming(last_val, last_bb) - return result_phi - return None - - def _HandleUnaryOpLlvm(self, Node): - Gen = self.Trans.LlvmGen - OperandVal = self.HandleExprLlvm(Node.operand) - if not OperandVal: - return None - OpSymbol = self.Trans.ExprHandler.GetUnaryOpSymbol(Node.op) - if not OpSymbol: - return None - UNARY_OVERLOAD_MAP = { - '-': '__neg__', - '+': '__pos__', - '~': '__invert__', - } - if OpSymbol in UNARY_OVERLOAD_MAP: - ClassName = None - if isinstance(OperandVal.type, ir.PointerType): - pointee = OperandVal.type.pointee - if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): - for CN, ST in Gen.structs.items(): - if pointee == ST: - ClassName = CN - break - elif isinstance(pointee, ir.IntType) and pointee.width == 8: - ClassName = self.Trans.ExprUtils._get_var_class(Node.operand, Gen) - if ClassName and ClassName in Gen.structs: - TargetStructPtr = ir.PointerType(Gen.structs[ClassName]) - OperandVal = Gen.builder.bitcast(OperandVal, TargetStructPtr, name=f"bitcast_to_{ClassName}") - if ClassName is None and isinstance(Node.operand, ast.Name): - ClassName = Gen.var_struct_class.get(Node.operand.id) - if ClassName and ClassName in Gen.structs: - if isinstance(OperandVal.type, ir.PointerType) and isinstance(OperandVal.type.pointee, ir.IntType) and OperandVal.type.pointee.width == 8: - TargetStructPtr = ir.PointerType(Gen.structs[ClassName]) - OperandVal = Gen.builder.bitcast(OperandVal, TargetStructPtr, name=f"bitcast_to_{ClassName}") - if ClassName: - op_name = UNARY_OVERLOAD_MAP[OpSymbol] - result = self.Trans.ExprUtils._try_operator_overload(ClassName, op_name, OperandVal, Gen) - if result is not None: - return result - if OpSymbol == 'not': - if isinstance(OperandVal.type, ir.IntType) and OperandVal.type.width == 1: - return Gen.builder.not_(OperandVal, name="not_result") - if isinstance(OperandVal.type, ir.PointerType): - null_val = ir.Constant(OperandVal.type, None) - return Gen.builder.icmp_signed('==', OperandVal, null_val, name="not_result") - zero = ir.Constant(OperandVal.type, 0) - return Gen.builder.icmp_signed('==', OperandVal, zero, name="not_result") - elif OpSymbol == '~': - if isinstance(OperandVal.type, ir.IntType): - mask = (1 << OperandVal.type.width) - 1 - return Gen.builder.xor(OperandVal, ir.Constant(OperandVal.type, mask), name="bnot_result") - return Gen.builder.xor(OperandVal, ir.Constant(OperandVal.type, -1), name="bnot_result") - elif OpSymbol == '+': - return OperandVal - elif OpSymbol == '-': - if isinstance(OperandVal.type, ir.IntType): - return Gen.builder.neg(OperandVal, name="neg_result") - elif isinstance(OperandVal.type, (ir.FloatType, ir.DoubleType)): - return Gen.builder.fneg(OperandVal, name="fneg_result") - return None - - def _HandleCompareLlvm(self, Node): - Gen = self.Trans.LlvmGen - LeftVal = self.HandleExprLlvm(Node.left) - if not LeftVal: - return None - is_unsigned = Gen._check_node_unsigned(Node.left) or (Gen._check_node_unsigned(Node.comparators[0]) if Node.comparators else False) - if len(Node.ops) == 1: - Op = Node.ops[0] - ComparatorSymbol = self.Trans.ExprHandler.GetComparatorSymbol(Op) - if not ComparatorSymbol: - return None - RightVal = self.HandleExprLlvm(Node.comparators[0]) - if not RightVal: - return None - if isinstance(LeftVal, ir.Constant) and isinstance(RightVal, ir.Constant): - if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType): - lv, rv = LeftVal.constant, RightVal.constant - lw, rw = LeftVal.type.width, RightVal.type.width - if lw < rw: - lv = lv if lv >= 0 else lv + (1 << lw) - elif rw < lw: - rv = rv if rv >= 0 else rv + (1 << rw) - if is_unsigned: - mask_l = (1 << max(lw, rw)) - 1 - lv = lv & mask_l - rv = rv & mask_l - cmp_map = { - '==': lv == rv, '!=': lv != rv, - '<': lv < rv, '>': lv > rv, - '<=': lv <= rv, '>=': lv >= rv, - } - result = cmp_map.get(ComparatorSymbol, False) - return ir.Constant(ir.IntType(1), 1 if result else 0) - if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType): - if LeftVal.type.width < RightVal.type.width: - # 如果宽类型常量值超出窄类型有符号范围,则必须用zext - # i8 类型默认使用 zext(系统编程中 i8 几乎总是无符号字节) - need_zext = is_unsigned or Gen._check_node_unsigned(Node.left) or LeftVal.type.width == 8 - if not need_zext and isinstance(RightVal, ir.Constant): - signed_max = (1 << (LeftVal.type.width - 1)) - 1 - try: - if RightVal.constant > signed_max or RightVal.constant < 0: - need_zext = True - except (TypeError, ValueError): - pass - if need_zext: - LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_left_cmp") - else: - LeftVal = Gen.builder.sext(LeftVal, RightVal.type, name="sext_left_cmp") - elif LeftVal.type.width > RightVal.type.width: - need_zext = is_unsigned or Gen._check_node_unsigned(Node.comparators[0]) or RightVal.type.width == 8 - if not need_zext and isinstance(LeftVal, ir.Constant): - signed_max = (1 << (RightVal.type.width - 1)) - 1 - try: - if LeftVal.constant > signed_max or LeftVal.constant < 0: - need_zext = True - except (TypeError, ValueError): - pass - if need_zext: - RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_right_cmp") - else: - RightVal = Gen.builder.sext(RightVal, LeftVal.type, name="sext_right_cmp") - elif isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.IntType): - if isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8 and isinstance(RightVal.type, ir.IntType) and RightVal.type.width == 8: - LeftVal = Gen._load(LeftVal, name="load_char_ptr_cmp") - else: - if isinstance(RightVal, ir.Constant) and RightVal.constant == 0: - RightVal = ir.Constant(LeftVal.type, None) - else: - RightVal = Gen.builder.inttoptr(RightVal, LeftVal.type, name="int2ptr_cmp") - elif isinstance(RightVal.type, ir.PointerType) and isinstance(LeftVal.type, ir.IntType): - if isinstance(RightVal.type.pointee, ir.IntType) and RightVal.type.pointee.width == 8 and isinstance(LeftVal.type, ir.IntType) and LeftVal.type.width == 8: - RightVal = Gen._load(RightVal, name="load_char_ptr_cmp") - else: - if isinstance(LeftVal, ir.Constant) and LeftVal.constant == 0: - LeftVal = ir.Constant(RightVal.type, None) - else: - LeftVal = Gen.builder.inttoptr(LeftVal, RightVal.type, name="int2ptr_cmp") - if isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.PointerType): - result = Gen.builder.icmp_unsigned(ComparatorSymbol, LeftVal, RightVal, name="cmpresult") - elif isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) or isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)): - if isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(RightVal.type, ir.IntType): - RightVal = Gen.builder.sitofp(RightVal, LeftVal.type, name="int_to_float_cmp") - elif isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(LeftVal.type, ir.IntType): - LeftVal = Gen.builder.sitofp(LeftVal, RightVal.type, name="int_to_float_cmp") - result = Gen.builder.fcmp_unordered(ComparatorSymbol, LeftVal, RightVal, name="cmpresult") - elif is_unsigned: - result = Gen.builder.icmp_unsigned(ComparatorSymbol, LeftVal, RightVal, name="cmpresult") - else: - result = Gen.builder.icmp_signed(ComparatorSymbol, LeftVal, RightVal, name="cmpresult") - return result - EndBB = Gen.func.append_basic_block(name="cmp.end") - result_val = None - PrevBB = Gen.builder.block - for i, (Op, Comparator) in enumerate(zip(Node.ops, Node.comparators)): - ComparatorSymbol = self.Trans.ExprHandler.GetComparatorSymbol(Op) - if not ComparatorSymbol: - continue - RightVal = self.HandleExprLlvm(Comparator) - if not RightVal: - continue - NextBB = Gen.func.append_basic_block(name="cmp.next") - if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType): - if LeftVal.type.width < RightVal.type.width: - need_zext = is_unsigned or Gen._check_node_unsigned(Node.left) or LeftVal.type.width == 8 - if not need_zext and isinstance(RightVal, ir.Constant): - signed_max = (1 << (LeftVal.type.width - 1)) - 1 - try: - if RightVal.constant > signed_max or RightVal.constant < 0: - need_zext = True - except (TypeError, ValueError): - pass - if need_zext: - LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name=f"zext_left_{i}") - else: - LeftVal = Gen.builder.sext(LeftVal, RightVal.type, name=f"sext_left_{i}") - elif LeftVal.type.width > RightVal.type.width: - need_zext = is_unsigned or Gen._check_node_unsigned(Comparator) or RightVal.type.width == 8 - if not need_zext and isinstance(LeftVal, ir.Constant): - signed_max = (1 << (RightVal.type.width - 1)) - 1 - try: - if LeftVal.constant > signed_max or LeftVal.constant < 0: - need_zext = True - except (TypeError, ValueError): - pass - if need_zext: - RightVal = Gen.builder.zext(RightVal, LeftVal.type, name=f"zext_right_{i}") - else: - RightVal = Gen.builder.sext(RightVal, LeftVal.type, name=f"sext_right_{i}") - if is_unsigned: - cmp_result = Gen.builder.icmp_unsigned(ComparatorSymbol, LeftVal, RightVal, name=f"cmp_{i}") - elif isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) or isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)): - if isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(RightVal.type, ir.IntType): - RightVal = Gen.builder.sitofp(RightVal, LeftVal.type, name=f"int_to_float_cmp_{i}") - elif isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(LeftVal.type, ir.IntType): - LeftVal = Gen.builder.sitofp(LeftVal, RightVal.type, name=f"int_to_float_cmp_{i}") - cmp_result = Gen.builder.fcmp_unordered(ComparatorSymbol, LeftVal, RightVal, name=f"cmp_{i}") - else: - cmp_result = Gen.builder.icmp_signed(ComparatorSymbol, LeftVal, RightVal, name=f"cmp_{i}") - if result_val is None: - result_val = cmp_result - else: - result_val = Gen.builder.and_(result_val, cmp_result, name=f"and_cmp_{i}") - Gen.builder.cbranch(cmp_result, NextBB, EndBB) - Gen.builder.position_at_start(NextBB) - LeftVal = RightVal - Gen.builder.branch(EndBB) - Gen.builder.position_at_start(EndBB) - final_result = Gen.builder.phi(ir.IntType(1), name="final_cmp") - final_result.add_incoming(ir.Constant(ir.IntType(1), 0), PrevBB) - for i in range(len(Node.ops)): - bb = Gen.func.append_basic_block(name=f"cmp.end.{i}") - final_result.add_incoming(ir.Constant(ir.IntType(1), 1), bb) - return final_result +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle +import ast +import llvmlite.ir as ir + + +class ExprOpsHandle(BaseHandle): + def _HandleBinOpLlvm(self, Node, VarType=None): + Gen = self.Trans.LlvmGen + Gen._set_node_info(Node, "BinOp") + LeftVal = self.HandleExprLlvm(Node.left, VarType) + if not LeftVal: + return None + RightVal = self.HandleExprLlvm(Node.right, VarType) + if not RightVal: + return None + Op = self.Trans.ExprHandler.GetOpSymbol(Node.op) + if not Op: + return None + OP_OVERLOAD_MAP = { + '+': '__add__', '-': '__sub__', '*': '__mul__', + '/': '__truediv__', '//': '__floordiv__', '%': '__mod__', + '**': '__pow__', + } + if Op in OP_OVERLOAD_MAP: + LeftClassName = None + if isinstance(LeftVal.type, ir.PointerType): + pointee = LeftVal.type.pointee + if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): + for CN, ST in Gen.structs.items(): + if pointee == ST: + LeftClassName = CN + break + elif isinstance(pointee, ir.IntType) and pointee.width == 8: + LeftClassName = self.Trans.ExprUtils._get_var_class(Node.left, Gen) + if LeftClassName and LeftClassName in Gen.structs: + TargetStructPtr = ir.PointerType(Gen.structs[LeftClassName]) + LeftVal = Gen.builder.bitcast(LeftVal, TargetStructPtr, name=f"bitcast_to_{LeftClassName}") + if LeftClassName is None and isinstance(Node.left, ast.Name): + LeftClassName = Gen.var_struct_class.get(Node.left.id) + if LeftClassName and LeftClassName in Gen.structs: + if isinstance(LeftVal.type, ir.PointerType) and isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8: + TargetStructPtr = ir.PointerType(Gen.structs[LeftClassName]) + LeftVal = Gen.builder.bitcast(LeftVal, TargetStructPtr, name=f"bitcast_to_{LeftClassName}") + if LeftClassName: + op_name = OP_OVERLOAD_MAP[Op] + result = self.Trans.ExprUtils._try_operator_overLoad(LeftClassName, op_name, LeftVal, Gen, RightVal) + if result is not None: + return result + if Op in ('+', 'Add') and isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.IntType): + if isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8: + if isinstance(Node.left, ast.Constant) and isinstance(Node.left.value, str) and len(Node.left.value) == 1: + CharVal = Gen._load(LeftVal, name="Load_char_const") + CharAsInt = Gen.builder.zext(CharVal, RightVal.type, name="char_to_int") + result = Gen.builder.add(CharAsInt, RightVal, name="char_add") + TruncResult = Gen.builder.trunc(result, ir.IntType(8), name="add_to_char") + return TruncResult + is_unsigned = Gen._check_node_unsigned(Node.left) or Gen._check_node_unsigned(Node.right) + if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType): + if LeftVal.type.width < RightVal.type.width: + need_zext = is_unsigned or Gen._check_node_unsigned(Node.left) or LeftVal.type.width == 8 + if not need_zext and isinstance(RightVal, ir.Constant): + signed_max = (1 << (LeftVal.type.width - 1)) - 1 + try: + if RightVal.constant > signed_max: + need_zext = True + except (TypeError, ValueError): + pass + if need_zext: + LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_left") + else: + LeftVal = Gen.builder.sext(LeftVal, RightVal.type, name="sext_left") + elif LeftVal.type.width > RightVal.type.width: + need_zext = is_unsigned or Gen._check_node_unsigned(Node.right) or RightVal.type.width == 8 + if not need_zext and isinstance(LeftVal, ir.Constant): + signed_max = (1 << (RightVal.type.width - 1)) - 1 + try: + if LeftVal.constant > signed_max: + need_zext = True + except (TypeError, ValueError): + pass + if need_zext: + RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_right") + else: + RightVal = Gen.builder.sext(RightVal, LeftVal.type, name="zext_right") + elif isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.IntType): + if Op not in ('+', '-', 'Add', 'Sub') and isinstance(LeftVal.type.pointee, ir.IntType): + LeftVal = Gen._load(LeftVal, name="deref_ptr_binop") + if LeftVal.type.width < RightVal.type.width: + LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_deref_left") + elif LeftVal.type.width > RightVal.type.width: + RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_right_deref") + elif isinstance(RightVal.type, ir.PointerType) and isinstance(LeftVal.type, ir.IntType): + if Op not in ('+', '-', 'Add', 'Sub') and isinstance(RightVal.type.pointee, ir.IntType): + RightVal = Gen._load(RightVal, name="deref_ptr_binop_r") + if RightVal.type.width < LeftVal.type.width: + RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_deref_right") + elif RightVal.type.width > LeftVal.type.width: + LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_left_deref") + if Op in ('>>', 'RShift') and isinstance(Node.left, ast.Name): + vname = Node.left.id + if vname in Gen.var_signedness and Gen.var_signedness[vname]: + is_unsigned = True + result = Gen.emit_binary_op(Op, LeftVal, RightVal, is_unsigned=is_unsigned) + return result + + def _HandleBoolOpLlvm(self, Node): + Gen = self.Trans.LlvmGen + + def _to_bool(val, name): + if isinstance(val.type, (ir.FloatType, ir.DoubleType)): + return Gen.builder.fcmp_ordered('!=', val, ir.Constant(val.type, 0.0), name=name) + if not isinstance(val.type, ir.IntType) or val.type.width != 1: + return Gen.builder.icmp_signed('!=', val, Gen._ZeroConst(val.type), name=name) + return val + + values = Node.values + if len(values) < 2: + return self.HandleExprLlvm(values[0]) if values else None + if isinstance(Node.op, ast.And): + phi_incomings = [] + end_bb = Gen.func.append_basic_block(name="and.end") + for idx in range(len(values) - 1): + val = self.HandleExprLlvm(values[idx]) + if not val: + if not end_bb.is_terminated: + saved_block = Gen.builder.block + Gen.builder.position_at_start(end_bb) + Gen.builder.unreachable() + Gen.builder.position_at_end(saved_block) + return None + if not isinstance(val.type, ir.IntType) or val.type.width != 1: + val = _to_bool(val, f"andcond{idx}") + cur_bb = Gen.builder.block + next_bb = Gen.func.append_basic_block(name=f"and.rhs{idx}") + Gen.builder.cbranch(val, next_bb, end_bb) + phi_incomings.append((ir.Constant(ir.IntType(1), 0), cur_bb)) + Gen.builder.position_at_start(next_bb) + last_val = self.HandleExprLlvm(values[-1]) + if not last_val: + last_val = ir.Constant(ir.IntType(1), 0) + if not isinstance(last_val.type, ir.IntType) or last_val.type.width != 1: + last_val = _to_bool(last_val, "andcond_last") + last_bb = Gen.builder.block + Gen.builder.branch(end_bb) + Gen.builder.position_at_start(end_bb) + result_phi = Gen.builder.phi(ir.IntType(1), name="and.result") + for const_val, bb in phi_incomings: + result_phi.add_incoming(const_val, bb) + result_phi.add_incoming(last_val, last_bb) + return result_phi + elif isinstance(Node.op, ast.Or): + phi_incomings = [] + end_bb = Gen.func.append_basic_block(name="or.end") + for idx in range(len(values) - 1): + val = self.HandleExprLlvm(values[idx]) + if not val: + if not end_bb.is_terminated: + saved_block = Gen.builder.block + Gen.builder.position_at_start(end_bb) + Gen.builder.unreachable() + Gen.builder.position_at_end(saved_block) + return None + if not isinstance(val.type, ir.IntType) or val.type.width != 1: + val = _to_bool(val, f"orcond{idx}") + cur_bb = Gen.builder.block + next_bb = Gen.func.append_basic_block(name=f"or.rhs{idx}") + Gen.builder.cbranch(val, end_bb, next_bb) + phi_incomings.append((ir.Constant(ir.IntType(1), 1), cur_bb)) + Gen.builder.position_at_start(next_bb) + last_val = self.HandleExprLlvm(values[-1]) + if not last_val: + last_val = ir.Constant(ir.IntType(1), 1) + if not isinstance(last_val.type, ir.IntType) or last_val.type.width != 1: + last_val = _to_bool(last_val, "orcond_last") + last_bb = Gen.builder.block + Gen.builder.branch(end_bb) + Gen.builder.position_at_start(end_bb) + result_phi = Gen.builder.phi(ir.IntType(1), name="or.result") + for const_val, bb in phi_incomings: + result_phi.add_incoming(const_val, bb) + result_phi.add_incoming(last_val, last_bb) + return result_phi + return None + + def _HandleUnaryOpLlvm(self, Node): + Gen = self.Trans.LlvmGen + OperandVal = self.HandleExprLlvm(Node.operand) + if not OperandVal: + return None + OpSymbol = self.Trans.ExprHandler.GetUnaryOpSymbol(Node.op) + if not OpSymbol: + return None + UNARY_OVERLOAD_MAP = { + '-': '__neg__', + '+': '__pos__', + '~': '__invert__', + } + if OpSymbol in UNARY_OVERLOAD_MAP: + ClassName = None + if isinstance(OperandVal.type, ir.PointerType): + pointee = OperandVal.type.pointee + if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): + for CN, ST in Gen.structs.items(): + if pointee == ST: + ClassName = CN + break + elif isinstance(pointee, ir.IntType) and pointee.width == 8: + ClassName = self.Trans.ExprUtils._get_var_class(Node.operand, Gen) + if ClassName and ClassName in Gen.structs: + TargetStructPtr = ir.PointerType(Gen.structs[ClassName]) + OperandVal = Gen.builder.bitcast(OperandVal, TargetStructPtr, name=f"bitcast_to_{ClassName}") + if ClassName is None and isinstance(Node.operand, ast.Name): + ClassName = Gen.var_struct_class.get(Node.operand.id) + if ClassName and ClassName in Gen.structs: + if isinstance(OperandVal.type, ir.PointerType) and isinstance(OperandVal.type.pointee, ir.IntType) and OperandVal.type.pointee.width == 8: + TargetStructPtr = ir.PointerType(Gen.structs[ClassName]) + OperandVal = Gen.builder.bitcast(OperandVal, TargetStructPtr, name=f"bitcast_to_{ClassName}") + if ClassName: + op_name = UNARY_OVERLOAD_MAP[OpSymbol] + result = self.Trans.ExprUtils._try_operator_overLoad(ClassName, op_name, OperandVal, Gen) + if result is not None: + return result + if OpSymbol == 'not': + if isinstance(OperandVal.type, ir.IntType) and OperandVal.type.width == 1: + return Gen.builder.not_(OperandVal, name="not_result") + if isinstance(OperandVal.type, ir.PointerType): + null_val = ir.Constant(OperandVal.type, None) + return Gen.builder.icmp_signed('==', OperandVal, null_val, name="not_result") + zero = ir.Constant(OperandVal.type, 0) + return Gen.builder.icmp_signed('==', OperandVal, zero, name="not_result") + elif OpSymbol == '~': + if isinstance(OperandVal.type, ir.IntType): + mask = (1 << OperandVal.type.width) - 1 + return Gen.builder.xor(OperandVal, ir.Constant(OperandVal.type, mask), name="bnot_result") + return Gen.builder.xor(OperandVal, ir.Constant(OperandVal.type, -1), name="bnot_result") + elif OpSymbol == '+': + return OperandVal + elif OpSymbol == '-': + if isinstance(OperandVal.type, ir.IntType): + return Gen.builder.neg(OperandVal, name="neg_result") + elif isinstance(OperandVal.type, (ir.FloatType, ir.DoubleType)): + return Gen.builder.fneg(OperandVal, name="fneg_result") + return None + + def _HandleCompareLlvm(self, Node): + Gen = self.Trans.LlvmGen + LeftVal = self.HandleExprLlvm(Node.left) + if not LeftVal: + return None + is_unsigned = Gen._check_node_unsigned(Node.left) or (Gen._check_node_unsigned(Node.comparators[0]) if Node.comparators else False) + if len(Node.ops) == 1: + Op = Node.ops[0] + ComparatorSymbol = self.Trans.ExprHandler.GetComparatorSymbol(Op) + if not ComparatorSymbol: + return None + RightVal = self.HandleExprLlvm(Node.comparators[0]) + if not RightVal: + return None + if isinstance(LeftVal, ir.Constant) and isinstance(RightVal, ir.Constant): + if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType): + lv, rv = LeftVal.constant, RightVal.constant + lw, rw = LeftVal.type.width, RightVal.type.width + if lw < rw: + lv = lv if lv >= 0 else lv + (1 << lw) + elif rw < lw: + rv = rv if rv >= 0 else rv + (1 << rw) + if is_unsigned: + mask_l = (1 << max(lw, rw)) - 1 + lv = lv & mask_l + rv = rv & mask_l + cmp_map = { + '==': lv == rv, '!=': lv != rv, + '<': lv < rv, '>': lv > rv, + '<=': lv <= rv, '>=': lv >= rv, + } + result = cmp_map.get(ComparatorSymbol, False) + return ir.Constant(ir.IntType(1), 1 if result else 0) + if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType): + if LeftVal.type.width < RightVal.type.width: + # 如果宽类型常量值超出窄类型有符号范围,则必须用zext + # i8 类型默认使用 zext(系统编程中 i8 几乎总是无符号字节) + need_zext = is_unsigned or Gen._check_node_unsigned(Node.left) or LeftVal.type.width == 8 + if not need_zext and isinstance(RightVal, ir.Constant): + signed_max = (1 << (LeftVal.type.width - 1)) - 1 + try: + if RightVal.constant > signed_max or RightVal.constant < 0: + need_zext = True + except (TypeError, ValueError): + pass + if need_zext: + LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_left_cmp") + else: + LeftVal = Gen.builder.sext(LeftVal, RightVal.type, name="sext_left_cmp") + elif LeftVal.type.width > RightVal.type.width: + need_zext = is_unsigned or Gen._check_node_unsigned(Node.comparators[0]) or RightVal.type.width == 8 + if not need_zext and isinstance(LeftVal, ir.Constant): + signed_max = (1 << (RightVal.type.width - 1)) - 1 + try: + if LeftVal.constant > signed_max or LeftVal.constant < 0: + need_zext = True + except (TypeError, ValueError): + pass + if need_zext: + RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_right_cmp") + else: + RightVal = Gen.builder.sext(RightVal, LeftVal.type, name="sext_right_cmp") + elif isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.IntType): + if isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8 and isinstance(RightVal.type, ir.IntType) and RightVal.type.width == 8: + LeftVal = Gen._load(LeftVal, name="Load_char_ptr_cmp") + else: + if isinstance(RightVal, ir.Constant) and RightVal.constant == 0: + RightVal = ir.Constant(LeftVal.type, None) + else: + RightVal = Gen.builder.inttoptr(RightVal, LeftVal.type, name="int2ptr_cmp") + elif isinstance(RightVal.type, ir.PointerType) and isinstance(LeftVal.type, ir.IntType): + if isinstance(RightVal.type.pointee, ir.IntType) and RightVal.type.pointee.width == 8 and isinstance(LeftVal.type, ir.IntType) and LeftVal.type.width == 8: + RightVal = Gen._load(RightVal, name="Load_char_ptr_cmp") + else: + if isinstance(LeftVal, ir.Constant) and LeftVal.constant == 0: + LeftVal = ir.Constant(RightVal.type, None) + else: + LeftVal = Gen.builder.inttoptr(LeftVal, RightVal.type, name="int2ptr_cmp") + if isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.PointerType): + result = Gen.builder.icmp_unsigned(ComparatorSymbol, LeftVal, RightVal, name="cmpresult") + elif isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) or isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)): + if isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(RightVal.type, ir.IntType): + RightVal = Gen.builder.sitofp(RightVal, LeftVal.type, name="int_to_float_cmp") + elif isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(LeftVal.type, ir.IntType): + LeftVal = Gen.builder.sitofp(LeftVal, RightVal.type, name="int_to_float_cmp") + result = Gen.builder.fcmp_unordered(ComparatorSymbol, LeftVal, RightVal, name="cmpresult") + elif is_unsigned: + result = Gen.builder.icmp_unsigned(ComparatorSymbol, LeftVal, RightVal, name="cmpresult") + else: + result = Gen.builder.icmp_signed(ComparatorSymbol, LeftVal, RightVal, name="cmpresult") + return result + EndBB = Gen.func.append_basic_block(name="cmp.end") + result_val = None + PrevBB = Gen.builder.block + for i, (Op, Comparator) in enumerate(zip(Node.ops, Node.comparators)): + ComparatorSymbol = self.Trans.ExprHandler.GetComparatorSymbol(Op) + if not ComparatorSymbol: + continue + RightVal = self.HandleExprLlvm(Comparator) + if not RightVal: + continue + NextBB = Gen.func.append_basic_block(name="cmp.next") + if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType): + if LeftVal.type.width < RightVal.type.width: + need_zext = is_unsigned or Gen._check_node_unsigned(Node.left) or LeftVal.type.width == 8 + if not need_zext and isinstance(RightVal, ir.Constant): + signed_max = (1 << (LeftVal.type.width - 1)) - 1 + try: + if RightVal.constant > signed_max or RightVal.constant < 0: + need_zext = True + except (TypeError, ValueError): + pass + if need_zext: + LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name=f"zext_left_{i}") + else: + LeftVal = Gen.builder.sext(LeftVal, RightVal.type, name=f"sext_left_{i}") + elif LeftVal.type.width > RightVal.type.width: + need_zext = is_unsigned or Gen._check_node_unsigned(Comparator) or RightVal.type.width == 8 + if not need_zext and isinstance(LeftVal, ir.Constant): + signed_max = (1 << (RightVal.type.width - 1)) - 1 + try: + if LeftVal.constant > signed_max or LeftVal.constant < 0: + need_zext = True + except (TypeError, ValueError): + pass + if need_zext: + RightVal = Gen.builder.zext(RightVal, LeftVal.type, name=f"zext_right_{i}") + else: + RightVal = Gen.builder.sext(RightVal, LeftVal.type, name=f"sext_right_{i}") + if is_unsigned: + cmp_result = Gen.builder.icmp_unsigned(ComparatorSymbol, LeftVal, RightVal, name=f"cmp_{i}") + elif isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) or isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)): + if isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(RightVal.type, ir.IntType): + RightVal = Gen.builder.sitofp(RightVal, LeftVal.type, name=f"int_to_float_cmp_{i}") + elif isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(LeftVal.type, ir.IntType): + LeftVal = Gen.builder.sitofp(LeftVal, RightVal.type, name=f"int_to_float_cmp_{i}") + cmp_result = Gen.builder.fcmp_unordered(ComparatorSymbol, LeftVal, RightVal, name=f"cmp_{i}") + else: + cmp_result = Gen.builder.icmp_signed(ComparatorSymbol, LeftVal, RightVal, name=f"cmp_{i}") + if result_val is None: + result_val = cmp_result + else: + result_val = Gen.builder.and_(result_val, cmp_result, name=f"and_cmp_{i}") + Gen.builder.cbranch(cmp_result, NextBB, EndBB) + Gen.builder.position_at_start(NextBB) + LeftVal = RightVal + Gen.builder.branch(EndBB) + Gen.builder.position_at_start(EndBB) + final_result = Gen.builder.phi(ir.IntType(1), name="final_cmp") + final_result.add_incoming(ir.Constant(ir.IntType(1), 0), PrevBB) + for i in range(len(Node.ops)): + bb = Gen.func.append_basic_block(name=f"cmp.end.{i}") + final_result.add_incoming(ir.Constant(ir.IntType(1), 1), bb) + return final_result diff --git a/lib/core/Handles/HandlesExprUtils.py b/lib/core/Handles/HandlesExprUtils.py index 2dfda20..40db3fe 100644 --- a/lib/core/Handles/HandlesExprUtils.py +++ b/lib/core/Handles/HandlesExprUtils.py @@ -1,240 +1,240 @@ -from __future__ import annotations -from typing import TYPE_CHECKING -if TYPE_CHECKING: - from lib.core.translator import Translator -import ast -import llvmlite.ir as ir - - -class ExprUtils: - def __init__(self, translator: "Translator"): - self.Trans = translator - - def GetOpSymbol(self, Op): - OpMap = { - ast.Add: '+', ast.Sub: '-', ast.Mult: '*', ast.Div: '/', - ast.FloorDiv: '//', ast.Mod: '%', ast.Pow: '**', ast.BitAnd: '&', - ast.BitOr: '|', ast.BitXor: '^', ast.LShift: '<<', ast.RShift: '>>', - ast.MatMult: '@', - } - return OpMap.get(type(Op), None) - - def GetUnaryOpSymbol(self, Op): - OpMap = {ast.Invert: '~', ast.Not: 'not', ast.UAdd: '+', ast.USub: '-'} - return OpMap.get(type(Op), None) - - def GetComparatorSymbol(self, Op): - OpMap = { - ast.Eq: '==', ast.NotEq: '!=', ast.Lt: '<', ast.LtE: '<=', - ast.Gt: '>', ast.GtE: '>=', ast.Is: 'is', ast.IsNot: 'is not', - ast.In: 'in', ast.NotIn: 'not in', - } - return OpMap.get(type(Op), None) - - def _get_var_class(self, node, Gen): - if isinstance(node, ast.Name): - VarName = node.id - return Gen.var_struct_class.get(VarName) - if isinstance(node, ast.Attribute): - AttrName = node.attr - return Gen.var_struct_class.get(AttrName) - return None - - def _try_operator_overload(self, ClassName, op_name, obj_val, Gen, other_val=None): - FullMethodName = f'{ClassName}.{op_name}' - if not Gen._has_function(FullMethodName): - FullMethodName = f'{ClassName}.{op_name}__' - if Gen._has_function(FullMethodName): - func = Gen._get_function(FullMethodName) - call_args = [obj_val] - if other_val is not None: - call_args.append(other_val) - if len(func.ftype.args) == len(call_args): - for i, (expected_type, actual_val) in enumerate(zip(func.ftype.args, call_args)): - if isinstance(expected_type, ir.PointerType) and isinstance(actual_val.type, ir.PointerType): - if expected_type != actual_val.type: - if isinstance(expected_type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): - call_args[i] = Gen.builder.bitcast(actual_val, expected_type, name=f"bitcast_arg_{i}") - result = Gen.builder.call(func, call_args, name=f"call_{FullMethodName}") - return result - return None - - def _llvm_type_to_detailed_string(self, llvm_type, var_name=""): - info = { - 'name': "unknown", - 'size': 0, - 'signed': False, - 'ptr': False - } - if isinstance(llvm_type, ir.IntType): - info['size'] = llvm_type.width // 8 - info['signed'] = True - if llvm_type.width == 8: - info['name'] = "char" - elif llvm_type.width == 16: - info['name'] = "short" - elif llvm_type.width == 32: - info['name'] = "int" - elif llvm_type.width == 64: - info['name'] = "long long" - else: - info['name'] = f"int{llvm_type.width}" - elif isinstance(llvm_type, ir.DoubleType): - info['size'] = 8 - info['signed'] = True - info['name'] = "double" - elif isinstance(llvm_type, ir.FloatType): - info['size'] = 4 - info['signed'] = True - info['name'] = "float" - elif isinstance(llvm_type, ir.PointerType): - info['size'] = 8 - info['signed'] = False - info['ptr'] = True - pointee_info = self._llvm_type_to_detailed_string(llvm_type.pointee) - info['name'] = f"{pointee_info['name']}*" - elif isinstance(llvm_type, (ir.LiteralStructType, ir.IdentifiedStructType)): - size = 0 - for elem in llvm_type.elements: - elem_info = self._llvm_type_to_detailed_string(elem) - size += elem_info['size'] - info['size'] = size - info['signed'] = False - if isinstance(llvm_type, ir.IdentifiedStructType): - info['name'] = llvm_type.name - else: - info['name'] = "struct" - elif isinstance(llvm_type, ir.ArrayType): - elem_info = self._llvm_type_to_detailed_string(llvm_type.element) - info['size'] = elem_info['size'] * llvm_type.count - info['signed'] = elem_info['signed'] - info['name'] = f"{elem_info['name']}[]" - elif isinstance(llvm_type, ir.VoidType): - info['size'] = 0 - info['signed'] = False - info['name'] = "void" - else: - info['size'] = 0 - info['signed'] = False - info['name'] = str(llvm_type) - return info - - def _infer_expr_llvm_type_full(self, node): - Gen = self.Trans.LlvmGen - if isinstance(node, ast.Constant): - if isinstance(node.value, bool): - return ir.IntType(32) - elif isinstance(node.value, int): - return ir.IntType(32) - elif isinstance(node.value, float): - return ir.DoubleType() - elif isinstance(node.value, str): - if getattr(node, 'kind', None) == 'u': - return ir.PointerType(ir.IntType(16)) - return ir.PointerType(ir.IntType(8)) - return ir.IntType(32) - elif isinstance(node, ast.Name): - if node.id in Gen.variables: - var_ptr = Gen.variables[node.id] - if isinstance(var_ptr.type, ir.PointerType): - return var_ptr.type.pointee - return var_ptr.type - if node.id in Gen._reg_values: - return Gen._reg_values[node.id].type - return ir.IntType(32) - elif isinstance(node, ast.Attribute): - attr_name = node.attr - if attr_name in self.Trans.SymbolTable: - AttrInfo = self.Trans.SymbolTable[attr_name] - if getattr(AttrInfo, 'IsEnumMember', None): - return ir.IntType(32) - return ir.IntType(32) - elif isinstance(node, ast.BinOp): - left_type = self._infer_expr_llvm_type_full(node.left) - right_type = self._infer_expr_llvm_type_full(node.right) - if isinstance(left_type, (ir.FloatType, ir.DoubleType)) or isinstance(right_type, (ir.FloatType, ir.DoubleType)): - return ir.DoubleType() - if isinstance(left_type, ir.PointerType) or isinstance(right_type, ir.PointerType): - return ir.PointerType(ir.IntType(8)) - return ir.IntType(32) - elif isinstance(node, ast.UnaryOp): - return self._infer_expr_llvm_type_full(node.operand) - elif isinstance(node, ast.Subscript): - val_type = self._infer_expr_llvm_type_full(node.value) - if isinstance(val_type, ir.PointerType): - if isinstance(val_type.pointee, ir.IntType) and val_type.pointee.width == 8: - return ir.IntType(8) - if isinstance(val_type.pointee, ir.ArrayType): - return ir.PointerType(val_type.pointee.element) - return val_type.pointee - if isinstance(val_type, ir.ArrayType): - return val_type.element - if isinstance(val_type, ir.IntType): - return ir.IntType(8) - return ir.IntType(32) - elif isinstance(node, ast.Call): - if isinstance(node.func, ast.Name): - func_name = node.func.id - if Gen._has_function(func_name): - fn = Gen._get_function(func_name) - return fn.function_type.return_type - if func_name == 'len': - return ir.IntType(32) - if func_name == 'sizeof': - return ir.IntType(32) - if func_name == 'ord': - return ir.IntType(32) - if func_name == 'chr': - return ir.IntType(8) - if func_name == 'int': - return ir.IntType(32) - if func_name == 'float' or func_name == 'double': - return ir.DoubleType() - elif isinstance(node.func, ast.Attribute): - if isinstance(node.func.value, ast.Name) and node.func.value.id == 'c': - if node.func.attr == 'Deref': - return ir.IntType(64) - if isinstance(node.func.value, ast.Name) and node.func.value.id == 't': - if node.func.attr == 'CChar': - return ir.PointerType(ir.IntType(8)) - return ir.IntType(32) - elif isinstance(node, ast.Compare): - return ir.IntType(1) - elif isinstance(node, ast.BoolOp): - return ir.IntType(1) - elif isinstance(node, ast.IfExp): - return self._infer_expr_llvm_type_full(node.body) - elif isinstance(node, ast.Attribute): - return ir.PointerType(ir.IntType(8)) - return ir.IntType(32) - - def _collect_names(self, node, bound, free=None): - """收集 AST 节点中的绑定变量和自由变量 - - Args: - node: AST 节点 - bound: 集合,收集绑定变量(ast.Store 上下文) - free: 集合,收集自由变量(ast.Load 上下文),可为 None - """ - if free is None: - free = set() - if isinstance(node, ast.Name): - if isinstance(node.ctx, ast.Store): - bound.add(node.id) - elif isinstance(node.ctx, ast.Load): - free.add(node.id) - elif isinstance(node, (ast.Lambda, ast.FunctionDef, ast.AsyncFunctionDef)): - # 这些节点有自己的作用域,不递归进入 - # 但需要收集参数名作为 bound - if hasattr(node, 'args') and node.args: - for arg in node.args.args: - bound.add(arg.arg) - elif getattr(node, '_fields', None): - for field in node._fields: - value = getattr(node, field, None) - if isinstance(value, list): - for item in value: - if isinstance(item, (ast.stmt, ast.expr)): - self._collect_names(item, bound, free) - elif isinstance(value, (ast.stmt, ast.expr)): - self._collect_names(value, bound, free) +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +import ast +import llvmlite.ir as ir + + +class ExprUtils: + def __init__(self, translator: "Translator"): + self.Trans = translator + + def GetOpSymbol(self, Op): + OpMap = { + ast.Add: '+', ast.Sub: '-', ast.Mult: '*', ast.Div: '/', + ast.FloorDiv: '//', ast.Mod: '%', ast.Pow: '**', ast.BitAnd: '&', + ast.BitOr: '|', ast.BitXor: '^', ast.LShift: '<<', ast.RShift: '>>', + ast.MatMult: '@', + } + return OpMap.get(type(Op), None) + + def GetUnaryOpSymbol(self, Op): + OpMap = {ast.Invert: '~', ast.Not: 'not', ast.UAdd: '+', ast.USub: '-'} + return OpMap.get(type(Op), None) + + def GetComparatorSymbol(self, Op): + OpMap = { + ast.Eq: '==', ast.NotEq: '!=', ast.Lt: '<', ast.LtE: '<=', + ast.Gt: '>', ast.GtE: '>=', ast.Is: 'is', ast.IsNot: 'is not', + ast.In: 'in', ast.NotIn: 'not in', + } + return OpMap.get(type(Op), None) + + def _get_var_class(self, node, Gen): + if isinstance(node, ast.Name): + VarName = node.id + return Gen.var_struct_class.get(VarName) + if isinstance(node, ast.Attribute): + AttrName = node.attr + return Gen.var_struct_class.get(AttrName) + return None + + def _try_operator_overLoad(self, ClassName, op_name, obj_val, Gen, other_val=None): + FullMethodName = f'{ClassName}.{op_name}' + if not Gen._has_function(FullMethodName): + FullMethodName = f'{ClassName}.{op_name}__' + if Gen._has_function(FullMethodName): + func = Gen._get_function(FullMethodName) + call_args = [obj_val] + if other_val is not None: + call_args.append(other_val) + if len(func.ftype.args) == len(call_args): + for i, (expected_type, actual_val) in enumerate(zip(func.ftype.args, call_args)): + if isinstance(expected_type, ir.PointerType) and isinstance(actual_val.type, ir.PointerType): + if expected_type != actual_val.type: + if isinstance(expected_type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): + call_args[i] = Gen.builder.bitcast(actual_val, expected_type, name=f"bitcast_arg_{i}") + result = Gen.builder.call(func, call_args, name=f"call_{FullMethodName}") + return result + return None + + def _llvm_type_to_detailed_string(self, llvm_type, var_name=""): + info = { + 'name': "unknown", + 'size': 0, + 'signed': False, + 'ptr': False + } + if isinstance(llvm_type, ir.IntType): + info['size'] = llvm_type.width // 8 + info['signed'] = True + if llvm_type.width == 8: + info['name'] = "char" + elif llvm_type.width == 16: + info['name'] = "short" + elif llvm_type.width == 32: + info['name'] = "int" + elif llvm_type.width == 64: + info['name'] = "long long" + else: + info['name'] = f"int{llvm_type.width}" + elif isinstance(llvm_type, ir.DoubleType): + info['size'] = 8 + info['signed'] = True + info['name'] = "double" + elif isinstance(llvm_type, ir.FloatType): + info['size'] = 4 + info['signed'] = True + info['name'] = "float" + elif isinstance(llvm_type, ir.PointerType): + info['size'] = 8 + info['signed'] = False + info['ptr'] = True + pointee_info = self._llvm_type_to_detailed_string(llvm_type.pointee) + info['name'] = f"{pointee_info['name']}*" + elif isinstance(llvm_type, (ir.LiteralStructType, ir.IdentifiedStructType)): + size = 0 + for elem in llvm_type.elements: + elem_info = self._llvm_type_to_detailed_string(elem) + size += elem_info['size'] + info['size'] = size + info['signed'] = False + if isinstance(llvm_type, ir.IdentifiedStructType): + info['name'] = llvm_type.name + else: + info['name'] = "struct" + elif isinstance(llvm_type, ir.ArrayType): + elem_info = self._llvm_type_to_detailed_string(llvm_type.element) + info['size'] = elem_info['size'] * llvm_type.count + info['signed'] = elem_info['signed'] + info['name'] = f"{elem_info['name']}[]" + elif isinstance(llvm_type, ir.VoidType): + info['size'] = 0 + info['signed'] = False + info['name'] = "void" + else: + info['size'] = 0 + info['signed'] = False + info['name'] = str(llvm_type) + return info + + def _infer_expr_llvm_type_full(self, node): + Gen = self.Trans.LlvmGen + if isinstance(node, ast.Constant): + if isinstance(node.value, bool): + return ir.IntType(32) + elif isinstance(node.value, int): + return ir.IntType(32) + elif isinstance(node.value, float): + return ir.DoubleType() + elif isinstance(node.value, str): + if getattr(node, 'kind', None) == 'u': + return ir.PointerType(ir.IntType(16)) + return ir.PointerType(ir.IntType(8)) + return ir.IntType(32) + elif isinstance(node, ast.Name): + if node.id in Gen.variables: + var_ptr = Gen.variables[node.id] + if isinstance(var_ptr.type, ir.PointerType): + return var_ptr.type.pointee + return var_ptr.type + if node.id in Gen._reg_values: + return Gen._reg_values[node.id].type + return ir.IntType(32) + elif isinstance(node, ast.Attribute): + attr_name = node.attr + if attr_name in self.Trans.SymbolTable: + AttrInfo = self.Trans.SymbolTable[attr_name] + if getattr(AttrInfo, 'IsEnumMember', None): + return ir.IntType(32) + return ir.IntType(32) + elif isinstance(node, ast.BinOp): + left_type = self._infer_expr_llvm_type_full(node.left) + right_type = self._infer_expr_llvm_type_full(node.right) + if isinstance(left_type, (ir.FloatType, ir.DoubleType)) or isinstance(right_type, (ir.FloatType, ir.DoubleType)): + return ir.DoubleType() + if isinstance(left_type, ir.PointerType) or isinstance(right_type, ir.PointerType): + return ir.PointerType(ir.IntType(8)) + return ir.IntType(32) + elif isinstance(node, ast.UnaryOp): + return self._infer_expr_llvm_type_full(node.operand) + elif isinstance(node, ast.Subscript): + val_type = self._infer_expr_llvm_type_full(node.value) + if isinstance(val_type, ir.PointerType): + if isinstance(val_type.pointee, ir.IntType) and val_type.pointee.width == 8: + return ir.IntType(8) + if isinstance(val_type.pointee, ir.ArrayType): + return ir.PointerType(val_type.pointee.element) + return val_type.pointee + if isinstance(val_type, ir.ArrayType): + return val_type.element + if isinstance(val_type, ir.IntType): + return ir.IntType(8) + return ir.IntType(32) + elif isinstance(node, ast.Call): + if isinstance(node.func, ast.Name): + func_name = node.func.id + if Gen._has_function(func_name): + fn = Gen._get_function(func_name) + return fn.function_type.return_type + if func_name == 'len': + return ir.IntType(32) + if func_name == 'sizeof': + return ir.IntType(32) + if func_name == 'ord': + return ir.IntType(32) + if func_name == 'chr': + return ir.IntType(8) + if func_name == 'int': + return ir.IntType(32) + if func_name == 'float' or func_name == 'double': + return ir.DoubleType() + elif isinstance(node.func, ast.Attribute): + if isinstance(node.func.value, ast.Name) and node.func.value.id == 'c': + if node.func.attr == 'Deref': + return ir.IntType(64) + if isinstance(node.func.value, ast.Name) and node.func.value.id == 't': + if node.func.attr == 'CChar': + return ir.PointerType(ir.IntType(8)) + return ir.IntType(32) + elif isinstance(node, ast.Compare): + return ir.IntType(1) + elif isinstance(node, ast.BoolOp): + return ir.IntType(1) + elif isinstance(node, ast.IfExp): + return self._infer_expr_llvm_type_full(node.body) + elif isinstance(node, ast.Attribute): + return ir.PointerType(ir.IntType(8)) + return ir.IntType(32) + + def _collect_names(self, node, bound, free=None): + """收集 AST 节点中的绑定变量和自由变量 + + Args: + node: AST 节点 + bound: 集合,收集绑定变量(ast.Store 上下文) + free: 集合,收集自由变量(ast.Load 上下文),可为 None + """ + if free is None: + free = set() + if isinstance(node, ast.Name): + if isinstance(node.ctx, ast.Store): + bound.add(node.id) + elif isinstance(node.ctx, ast.Load): + free.add(node.id) + elif isinstance(node, (ast.Lambda, ast.FunctionDef, ast.AsyncFunctionDef)): + # 这些节点有自己的作用域,不递归进入 + # 但需要收集参数名作为 bound + if hasattr(node, 'args') and node.args: + for arg in node.args.args: + bound.add(arg.arg) + elif getattr(node, '_fields', None): + for field in node._fields: + value = getattr(node, field, None) + if isinstance(value, list): + for item in value: + if isinstance(item, (ast.stmt, ast.expr)): + self._collect_names(item, bound, free) + elif isinstance(value, (ast.stmt, ast.expr)): + self._collect_names(value, bound, free) diff --git a/lib/core/Handles/HandlesFor.py b/lib/core/Handles/HandlesFor.py index f4053a4..19752db 100644 --- a/lib/core/Handles/HandlesFor.py +++ b/lib/core/Handles/HandlesFor.py @@ -65,12 +65,12 @@ class ForHandle(BaseHandle): return if not isinstance(EndVal.type, ir.IntType): if isinstance(EndVal.type, ir.PointerType) and isinstance(EndVal.type.pointee, ir.IntType): - EndVal = Gen._load(EndVal, name="load_end") + EndVal = Gen._load(EndVal, name="Load_end") else: EndVal = Gen.builder.ptrtoint(EndVal, ir.IntType(64), name="end") if StartVal and not isinstance(StartVal.type, ir.IntType): if isinstance(StartVal.type, ir.PointerType) and isinstance(StartVal.type.pointee, ir.IntType): - StartVal = Gen._load(StartVal, name="load_start") + StartVal = Gen._load(StartVal, name="Load_start") else: StartVal = Gen.builder.ptrtoint(StartVal, ir.IntType(64), name="start") else: @@ -111,7 +111,7 @@ class ForHandle(BaseHandle): if isinstance(LoopVar.type, ir.PointerType) and isinstance(LoopVar.type.pointee, ir.IntType) and LoopVar.type.pointee == EndVal.type and isinstance(EndVal.type, ir.IntType) and StartVal.type == LoopVar.type.pointee and EndVal.type == StartVal.type: Gen._store(StartVal, LoopVar) else: - NewVar = Gen._alloca_entry(EndVal.type, name=TargetName) + NewVar = Gen._allocaEntry(EndVal.type, name=TargetName) if StartVal.type != EndVal.type: if isinstance(EndVal.type, ir.IntType) and isinstance(StartVal.type, ir.IntType): if StartVal.type.width < EndVal.type.width: @@ -122,7 +122,7 @@ class ForHandle(BaseHandle): Gen.variables[TargetName] = NewVar LoopVar = NewVar else: - LoopVar = Gen._alloca_entry(EndVal.type, name=TargetName) + LoopVar = Gen._allocaEntry(EndVal.type, name=TargetName) Gen.variables[TargetName] = LoopVar Gen._store(StartVal, LoopVar) if StepVal and isinstance(StepVal.type, ir.IntType) and isinstance(EndVal.type, ir.IntType): @@ -186,7 +186,7 @@ class ForHandle(BaseHandle): for name in Node.names: if name in Gen._reg_values and name not in Gen.variables: OldVal = Gen._reg_values[name] - var = Gen._alloca_entry(OldVal.type, name=name) + var = Gen._allocaEntry(OldVal.type, name=name) Gen._store(OldVal, var) Gen.variables[name] = var del Gen._reg_values[name] @@ -275,7 +275,7 @@ class ForHandle(BaseHandle): extra_params.append((var_name, var.type)) elif var_name in Gen._reg_values: OldVal = Gen._reg_values[var_name] - var = Gen._alloca_entry(OldVal.type, name=var_name) + var = Gen._allocaEntry(OldVal.type, name=var_name) Gen._store(OldVal, var) Gen.variables[var_name] = var del Gen._reg_values[var_name] @@ -292,7 +292,7 @@ class ForHandle(BaseHandle): Gen.variables[var_name] = found_var extra_params.append((var_name, found_var.type)) else: - var = Gen._alloca_entry(ir.IntType(32), name=var_name) + var = Gen._allocaEntry(ir.IntType(32), name=var_name) Gen.variables[var_name] = var extra_params.append((var_name, var.type)) if extra_params: @@ -334,11 +334,11 @@ class ForHandle(BaseHandle): TargetName = Node.target.id ElemType = ArrPtr.type.pointee.element ArrayCount = ArrPtr.type.pointee.count - IdxVal = Gen._alloca_entry(ir.IntType(32), name=f"arr_idx") + IdxVal = Gen._allocaEntry(ir.IntType(32), name=f"arr_idx") Gen.builder.store(ir.Constant(ir.IntType(32), 0), IdxVal) if TargetName in Gen._reg_values: del Gen._reg_values[TargetName] - LoopVar = Gen._alloca_entry(ElemType, name=TargetName) + LoopVar = Gen._allocaEntry(ElemType, name=TargetName) Gen.variables[TargetName] = LoopVar Gen._store(ir.Constant(ElemType, None), LoopVar) CondBB = Gen.func.append_basic_block(name="arrfor.cond") @@ -383,13 +383,13 @@ class ForHandle(BaseHandle): if not isinstance(Node.target, ast.Name): return TargetName = Node.target.id - Gen._unregister_temp_ptr(StrVal) + Gen._UnregisterTempPtr(StrVal) PtrVal = Gen.builder.alloca(ir.IntType(8).as_pointer(), name=f"str_ptr_copy") Gen.builder.store(StrVal, PtrVal) CharType = ir.IntType(8) if TargetName in Gen._reg_values: del Gen._reg_values[TargetName] - LoopVar = Gen._alloca_entry(CharType, name=TargetName) + LoopVar = Gen._allocaEntry(CharType, name=TargetName) Gen.variables[TargetName] = LoopVar Gen._store(ir.Constant(CharType, 0), LoopVar) CondBB = Gen.func.append_basic_block(name="strfor.cond") @@ -436,21 +436,21 @@ class ForHandle(BaseHandle): IterVal = self.HandleExprLlvm(Node.iter) if not IterVal: return - Gen._unregister_temp_ptr(IterVal) + Gen._UnregisterTempPtr(IterVal) if isinstance(IterVal.type, ir.PointerType) and isinstance(IterVal.type.pointee, ir.IntType) and IterVal.type.pointee.width == 8: IterVal = Gen.builder.bitcast(IterVal, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") IterCall = Gen._get_function(f'{ClassName}.__iter__') IterResult = Gen.builder.call(IterCall, [IterVal], name=f"call_{ClassName}.__iter__") - Gen._unregister_temp_ptr(IterResult) + Gen._UnregisterTempPtr(IterResult) if isinstance(IterResult.type, ir.PointerType) and isinstance(IterResult.type.pointee, ir.IntType) and IterResult.type.pointee.width == 8: IterResult = Gen.builder.bitcast(IterResult, ir.PointerType(Gen.structs[ClassName]), name=f"cast_iter_{ClassName}") NextCall = Gen._get_function(f'{ClassName}.__next__') - StopFlagPtr = Gen._alloca_entry(ir.IntType(1), name="stop_iter_flag") + StopFlagPtr = Gen._allocaEntry(ir.IntType(1), name="stop_iter_flag") Gen.builder.store(ir.Constant(ir.IntType(1), 0), StopFlagPtr) NextReturnType = NextCall.function_type.return_type if TargetName in Gen._reg_values: del Gen._reg_values[TargetName] - LoopVar = Gen._alloca_entry(NextReturnType, name=TargetName) + LoopVar = Gen._allocaEntry(NextReturnType, name=TargetName) Gen.variables[TargetName] = LoopVar CondBB = Gen.func.append_basic_block(name="iter.cond") BodyBB = Gen.func.append_basic_block(name="iter.body") @@ -469,7 +469,7 @@ class ForHandle(BaseHandle): and isinstance(last_param_type.pointee, ir.PointerType) and isinstance(last_param_type.pointee.pointee, ir.IntType) and last_param_type.pointee.pointee.width == 8): - null_msg = Gen._alloca_entry(ir.PointerType(ir.IntType(8)), name="eh_msg_out_null") + null_msg = Gen._allocaEntry(ir.PointerType(ir.IntType(8)), name="eh_msg_out_null") NextCallArgs.append(null_msg) NextVal = Gen.builder.call(NextCall, NextCallArgs, name=f"call_{ClassName}.__next__") StopFlag = Gen.builder.load(StopFlagPtr, name="stop_flag") diff --git a/lib/core/Handles/HandlesFunctions.py b/lib/core/Handles/HandlesFunctions.py index e7c0e50..8e27601 100644 --- a/lib/core/Handles/HandlesFunctions.py +++ b/lib/core/Handles/HandlesFunctions.py @@ -23,13 +23,16 @@ class FunctionHandle(BaseHandle): elif d.id == 'classmethod': meta |= FuncMeta.CLASS_METHOD elif isinstance(d, ast.Attribute): - if isinstance(d.value, ast.Name) and d.value.id == 'property': - if d.attr == 'setter': - meta |= FuncMeta.PROPERTY_SETTER - elif d.attr == 'getter': - meta |= FuncMeta.PROPERTY_GETTER - elif d.attr == 'deleter': - meta |= FuncMeta.PROPERTY_DELETER + if isinstance(d.value, ast.Name): + # 支持 @property.setter 和 @propname.setter 两种形式 + # @propname.setter 中 propname 是之前用 @property 定义的同名属性 + if d.value.id == 'property' or d.attr in ('setter', 'getter', 'deleter'): + if d.attr == 'setter': + meta |= FuncMeta.PROPERTY_SETTER + elif d.attr == 'getter': + meta |= FuncMeta.PROPERTY_GETTER + elif d.attr == 'deleter': + meta |= FuncMeta.PROPERTY_DELETER return meta def _body_contains_raise(self, body): @@ -189,8 +192,8 @@ class FunctionHandle(BaseHandle): if sym and isinstance(sym, dict): ret_type_str = sym.get('return_type', '') if ret_type_str and ret_type_str != 'int': - is_ptr = sym.get('is_ptr', False) - return (ret_type_str, is_ptr) + IsPtr = sym.get('IsPtr', False) + return (ret_type_str, IsPtr) elif isinstance(val, ast.Constant): if val.value is None: return ('char', True) @@ -204,8 +207,8 @@ class FunctionHandle(BaseHandle): if var_info and isinstance(var_info, dict): var_type = var_info.get('type', '') if var_type and var_type != 'int': - is_ptr = var_info.get('is_ptr', False) - return (var_type, is_ptr) + IsPtr = var_info.get('IsPtr', False) + return (var_type, IsPtr) elif isinstance(val, ast.Subscript): if (isinstance(val.value, ast.Attribute) and isinstance(val.value.value, ast.Name) @@ -264,8 +267,8 @@ class FunctionHandle(BaseHandle): parts = inner.split(',') elem_type_str = parts[0].strip() if elem_type_str and elem_type_str != 'int': - is_ptr = var_info.get('is_ptr', False) - return (elem_type_str, is_ptr) + IsPtr = var_info.get('IsPtr', False) + return (elem_type_str, IsPtr) return None def _GetFunctionSignatureLlvm(self, Node, Gen, ClassName=None, extra_params=None): @@ -368,7 +371,7 @@ class FunctionHandle(BaseHandle): ReturnTypeInfo = CTypeInfo() ReturnTypeInfo.BaseType = t.CChar() ReturnTypeInfo.PtrCount = 1 - if ReturnTypeInfo.IsVoid and not ReturnTypeInfo.IsState: + if ReturnTypeInfo.IsVoid and ReturnTypeInfo.PtrCount == 0 and not ReturnTypeInfo.IsState: ReturnTypeInfo = CTypeInfo() ReturnTypeInfo.BaseType = t.CInt() except Exception: # 回退:设置默认返回类型为 CInt @@ -762,8 +765,12 @@ class FunctionHandle(BaseHandle): for attr_name in self._pending_llvm_attrs[FuncName]: try: func.attributes.add(attr_name) - except Exception: - pass + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _config_mode + if _config_mode == "strict": + raise + _vlog().warning(f"添加函数属性失败: {_e}", "Exception") Gen.functions[MangledName] = func Gen.functions[FuncName] = func except Exception as _e: @@ -820,6 +827,12 @@ class FunctionHandle(BaseHandle): FuncName = f"{ClassName}.{RawFuncName}" else: FuncName = RawFuncName + # property setter/deleter 使用不同的函数名后缀,避免与 getter 冲突 + func_meta = self._ExtractFuncMeta(Node.decorator_list) + if FuncMeta.PROPERTY_SETTER in func_meta: + FuncName = FuncName + '$set' + elif FuncMeta.PROPERTY_DELETER in func_meta: + FuncName = FuncName + '$del' CReturnTypes = [] IsPtr = False fn_attrs = {} @@ -971,7 +984,7 @@ class FunctionHandle(BaseHandle): ReturnTypeInfo = CTypeInfo() ReturnTypeInfo.BaseType = t.CChar() ReturnTypeInfo.PtrCount = 1 - if ReturnTypeInfo.IsVoid and not ReturnTypeInfo.IsState: + if ReturnTypeInfo.IsVoid and ReturnTypeInfo.PtrCount == 0 and not ReturnTypeInfo.IsState: ReturnTypeInfo = CTypeInfo() ReturnTypeInfo.BaseType = t.CInt() except Exception: # 回退:设置默认返回类型为 CInt @@ -992,7 +1005,7 @@ class FunctionHandle(BaseHandle): IsMethod = False IsClassMethod = False ResolvedClassName = ClassName - func_meta = self._ExtractFuncMeta(Node.decorator_list) + # func_meta 已在函数开头提取(用于 setter/deleter 函数名后缀) if not ResolvedClassName: for potential_class in Gen.class_methods: if FuncName.startswith(f"{potential_class}."): @@ -1196,21 +1209,33 @@ class FunctionHandle(BaseHandle): if fn_attrs.get(attr_name): try: func.attributes.add(llvm_name) - except Exception: - pass + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _config_mode + if _config_mode == "strict": + raise + _vlog().warning(f"添加函数属性失败: {_e}", "Exception") for key in fn_attrs: if key.startswith('llvm.'): llvm_attr_name = key[5:] try: func.attributes.add(llvm_attr_name) - except Exception: - pass + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _config_mode + if _config_mode == "strict": + raise + _vlog().warning(f"添加函数属性失败: {_e}", "Exception") if hasattr(self, '_pending_llvm_attrs') and FuncName in self._pending_llvm_attrs: for attr_name in self._pending_llvm_attrs.pop(FuncName): try: func.attributes.add(attr_name) - except Exception: - pass + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _config_mode + if _config_mode == "strict": + raise + _vlog().warning(f"添加函数属性失败: {_e}", "Exception") # 记录自定义行为装饰器信息,供 DecoratorPass 使用 if behavior_decorators: if not hasattr(Gen, '_decorated_funcs'): @@ -1272,7 +1297,7 @@ class FunctionHandle(BaseHandle): break else: # 所有参数都存入 alloca,确保循环体中对参数的修改能正确反映 - var = Gen._alloca_entry(param.type, name=param_name) + var = Gen._allocaEntry(param.type, name=param_name) Gen._store(param, var) Gen.variables[param_name] = var if ResolvedClassName and (IsMethod or RawFuncName == '__init__'): @@ -1298,7 +1323,7 @@ class FunctionHandle(BaseHandle): va_list_size = 8 if is_windows else 24 va_list_align = 8 if is_windows else 16 va_list_type = ir.ArrayType(ir.IntType(8), va_list_size) - va_list_alloc = Gen._alloca_entry(va_list_type, name=f"{vararg_name}_va_list", align=va_list_align) + va_list_alloc = Gen._allocaEntry(va_list_type, name=f"{vararg_name}_va_list", align=va_list_align) va_list_ptr = Gen.builder.bitcast(va_list_alloc, ir.IntType(8).as_pointer(), name=f"{vararg_name}_va_list_i8ptr") Gen._variadic_info = { 'vararg_name': vararg_name, @@ -1307,7 +1332,7 @@ class FunctionHandle(BaseHandle): 'va_start_called': False, } if last_param_ptr: - last_param_alloc = Gen._alloca_entry(last_param_ptr.type, name="last_param_copy") + last_param_alloc = Gen._allocaEntry(last_param_ptr.type, name="last_param_copy") Gen.builder.store(last_param_ptr, last_param_alloc) Gen.emit_va_start(va_list_ptr) Gen._variadic_info['va_start_called'] = True @@ -1379,4 +1404,17 @@ class FunctionHandle(BaseHandle): existing.IsInline = True existing.InlineBody = Node.body existing.InlineParams = [arg.arg for arg in Node.args.args] + # property setter/deleter: 在原始 PropKey(不带后缀)下注册 MetaList + if FuncMeta.PROPERTY_SETTER in func_meta or FuncMeta.PROPERTY_DELETER in func_meta: + BasePropKey = f"{ClassName}.{RawFuncName}" if ClassName else RawFuncName + if BasePropKey in self.Trans.SymbolTable: + base_existing = self.Trans.SymbolTable[BasePropKey] + if func_meta != FuncMeta.NONE: + base_existing.MetaList = base_existing.MetaList | func_meta + else: + PropInfo = CTypeInfo() + PropInfo.Name = BasePropKey + PropInfo.IsFunction = True + PropInfo.MetaList = func_meta + self.Trans.SymbolTable[BasePropKey] = PropInfo return func diff --git a/lib/core/Handles/HandlesIf.py b/lib/core/Handles/HandlesIf.py index f11f3d6..3329eb7 100644 --- a/lib/core/Handles/HandlesIf.py +++ b/lib/core/Handles/HandlesIf.py @@ -1,302 +1,302 @@ -from __future__ import annotations -from typing import TYPE_CHECKING -if TYPE_CHECKING: - from lib.core.translator import Translator -from lib.core.Handles.HandlesBase import BaseHandle -import llvmlite.ir as ir -import ast - - -class IfHandle(BaseHandle): - def _get_attr_full_name(self, node): - if isinstance(node, ast.Attribute): - parts = [] - cur = node - while isinstance(cur, ast.Attribute): - parts.append(cur.attr) - cur = cur.value - if isinstance(cur, ast.Name): - parts.append(cur.id) - parts.reverse() - return '.'.join(parts) - return None - - def _is_cif_call(self, node): - if isinstance(node, ast.Call): - if isinstance(node.func, ast.Attribute): - if isinstance(node.func.value, ast.Name) and node.func.value.id == 'c': - return node.func.attr in ('CIf', 'CIfdef', 'CIfndef') - if isinstance(node.func, ast.Name): - return node.func.id in ('CIf', 'CIfdef', 'CIfndef') - return False - - def _resolve_macro_name(self, arg): - if isinstance(arg, ast.Name): - return arg.id - if isinstance(arg, ast.Constant) and isinstance(arg.value, str): - return arg.value - if isinstance(arg, ast.Attribute): - full_name = self._get_attr_full_name(arg) - if full_name: - return full_name - return None - - def _evaluate_cif_condition(self, node): - if not isinstance(node, ast.Call): - return None - args = node.args - if not args: - return False - if isinstance(node.func, ast.Attribute): - kind = node.func.attr - elif isinstance(node.func, ast.Name): - kind = node.func.id - else: - return None - if kind == 'CIfdef': - name = self._resolve_macro_name(args[0]) - if name is None: - return False - return self._is_macro_defined(name) - elif kind == 'CIfndef': - name = self._resolve_macro_name(args[0]) - if name is None: - return True - return not self._is_macro_defined(name) - elif kind == 'CIf': - return self._eval_const_expr(args[0]) - return None - - def _is_macro_defined(self, name): - Gen = self.Trans.LlvmGen - if hasattr(Gen, '_define_constants') and name in Gen._define_constants: - return True - if name in self.Trans.SymbolTable: - info = self.Trans.SymbolTable[name] - if getattr(info, 'IsDefine', False): - return True - platform_macros = self._get_platform_macros() - return name in platform_macros - - def _get_macro_value(self, name): - Gen = self.Trans.LlvmGen - if hasattr(Gen, '_define_constants') and name in Gen._define_constants: - val = Gen._define_constants[name] - if isinstance(val, (int, float)): - return val - if name in self.Trans.SymbolTable: - info = self.Trans.SymbolTable[name] - if getattr(info, 'IsDefine', False): - val = getattr(info, 'DefineValue', 0) - if isinstance(val, (int, float)): - return val - platform_macros = self._get_platform_macros() - if name in platform_macros: - return platform_macros[name] - return None - - def _get_platform_macros(self): - Gen = self.Trans.LlvmGen - macros = {} - pi = getattr(Gen, '_platform_info', {}) - ptr_size = getattr(Gen, 'ptr_size', 8) - # 根据目标平台设置宏(从三元组推导) - if pi.get('is_windows'): - macros['_WIN32'] = 1 - if not pi.get('is_32bit'): - macros['_WIN64'] = 1 - macros['WIN64'] = 1 - macros['WIN32'] = 1 - if pi.get('is_linux'): - macros['__linux__'] = 1 - if pi.get('is_macos'): - macros['__APPLE__'] = 1 - macros['__MACH__'] = 1 - if pi.get('is_x86_64'): - macros['__x86_64__'] = 1 - macros['__x86_64'] = 1 - macros['_M_X64'] = 1 - elif pi.get('is_arm64'): - macros['__aarch64__'] = 1 - macros['_M_ARM64'] = 1 - if not pi.get('is_32bit') and pi.get('is_linux'): - macros['__LP64__'] = 1 - elif pi.get('is_32bit'): - macros['_ILP32'] = 1 - macros['SIZEOF_VOID_P'] = ptr_size - macros['__SIZEOF_POINTER__'] = ptr_size - macros['NDEBUG'] = 0 - return macros - - def _eval_const_expr(self, node): - if isinstance(node, ast.Constant): - val = node.value - if isinstance(val, bool): - return 1 if val else 0 - if isinstance(val, int): - return val - if isinstance(val, float): - return 1 if val != 0.0 else 0 - return 0 - if isinstance(node, ast.Name): - name = node.id - val = self._get_macro_value(name) - if val is not None: - return val - return None - if isinstance(node, ast.Attribute): - full_key = self._get_attr_full_name(node) - if full_key: - val = self._get_macro_value(full_key) - if val is not None: - return val - short_name = full_key.split('.')[-1] if '.' in full_key else full_key - val = self._get_macro_value(short_name) - if val is not None: - return val - return None - if isinstance(node, ast.UnaryOp): - operand = self._eval_const_expr(node.operand) - if operand is None: - return None - if isinstance(node.op, ast.Not): - return 1 if not operand else 0 - if isinstance(node.op, ast.USub): - return -operand - if isinstance(node.op, ast.Invert): - return ~operand - return None - if isinstance(node, ast.BinOp): - left = self._eval_const_expr(node.left) - right = self._eval_const_expr(node.right) - if left is None or right is None: - return None - try: - if isinstance(node.op, ast.Add): - return left + right - elif isinstance(node.op, ast.Sub): - return left - right - elif isinstance(node.op, ast.Mult): - return left * right - elif isinstance(node.op, ast.FloorDiv): - return left // right if right != 0 else 0 - elif isinstance(node.op, ast.Mod): - return left % right if right != 0 else 0 - elif isinstance(node.op, ast.LShift): - return left << right - elif isinstance(node.op, ast.RShift): - return left >> right - elif isinstance(node.op, ast.BitOr): - return left | right - elif isinstance(node.op, ast.BitAnd): - return left & right - elif isinstance(node.op, ast.BitXor): - return left ^ right - except Exception: - return None - return None - if isinstance(node, ast.BoolOp): - if isinstance(node.op, ast.And): - for val in node.values: - result = self._eval_const_expr(val) - if result is None: - return None - if not result: - return 0 - return 1 - elif isinstance(node.op, ast.Or): - for val in node.values: - result = self._eval_const_expr(val) - if result is None: - return None - if result: - return 1 - return 0 - if isinstance(node, ast.Compare): - left = self._eval_const_expr(node.left) - if left is None: - return None - for op, comparator in zip(node.ops, node.comparators): - right = self._eval_const_expr(comparator) - if right is None: - return None - if isinstance(op, ast.Eq): - result = left == right - elif isinstance(op, ast.NotEq): - result = left != right - elif isinstance(op, ast.Lt): - result = left < right - elif isinstance(op, ast.LtE): - result = left <= right - elif isinstance(op, ast.Gt): - result = left > right - elif isinstance(op, ast.GtE): - result = left >= right - else: - return None - if not result: - return 0 - return 1 - if isinstance(node, ast.Call): - if self._is_cif_call(node): - return self._evaluate_cif_condition(node) - return None - - def _HandleIfLlvm(self, Node): - Gen = self.Trans.LlvmGen - if self._is_cif_call(Node.test): - compile_time_val = self._evaluate_cif_condition(Node.test) - if compile_time_val is not None: - if compile_time_val: - self.Trans.BodyHandler.HandleBodyLlvm(Node.body) - elif Node.orelse: - if isinstance(Node.orelse, list) and len(Node.orelse) == 1 and isinstance(Node.orelse[0], ast.If): - self._HandleIfLlvm(Node.orelse[0]) - else: - self.Trans.BodyHandler.HandleBodyLlvm(Node.orelse) - return - Cond = self.Trans.ExprHandler.HandleExprLlvm(Node.test) - if not Cond: - return - is_const = isinstance(Cond, ir.Constant) and isinstance(Cond.type, ir.IntType) and Cond.type.width == 1 - if is_const: - if Cond.constant: - self.Trans.BodyHandler.HandleBodyLlvm(Node.body) - elif Node.orelse: - if isinstance(Node.orelse, list) and len(Node.orelse) == 1 and isinstance(Node.orelse[0], ast.If): - self._HandleIfLlvm(Node.orelse[0]) - else: - self.Trans.BodyHandler.HandleBodyLlvm(Node.orelse) - return - if not isinstance(Cond.type, ir.IntType) or Cond.type.width != 1: - ClassName = self.Trans.ExprHandler._get_var_class(Node.test, Gen) - if ClassName and Gen._has_function(f'{ClassName}.__bool__'): - obj_val = Cond - if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8: - obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") - Cond = Gen.builder.call(Gen._get_function(f'{ClassName}.__bool__'), [obj_val], name=f"call_{ClassName}.__bool__") - if isinstance(Cond.type, ir.IntType) and Cond.type.width != 1: - Cond = Gen.builder.icmp_signed('!=', Cond, Gen._zero_const(Cond.type), name="bool_result") - else: - if isinstance(Cond.type, (ir.FloatType, ir.DoubleType)): - Cond = Gen.builder.fcmp_ordered('!=', Cond, ir.Constant(Cond.type, 0.0), name="ifcond") - else: - Cond = Gen.builder.icmp_signed('!=', Cond, Gen._zero_const(Cond.type), name="ifcond") - ThenBB = Gen.func.append_basic_block(name="then") - ElseBB = Gen.func.append_basic_block(name="else") if Node.orelse else None - MergeBB = Gen.func.append_basic_block(name="endif") - if not Gen.builder.block.is_terminated: - Gen.builder.cbranch(Cond, ThenBB, ElseBB if ElseBB else MergeBB) - Gen.builder.position_at_start(ThenBB) - self.Trans.BodyHandler.HandleBodyLlvm(Node.body) - if not Gen.builder.block.is_terminated: - Gen.builder.branch(MergeBB) - if ElseBB: - Gen.builder.position_at_start(ElseBB) - self.Trans.BodyHandler.HandleBodyLlvm(Node.orelse) - if not Gen.builder.block.is_terminated: - Gen.builder.branch(MergeBB) - if not MergeBB.is_terminated: - Gen.builder.position_at_start(MergeBB) - else: - Gen.builder.position_at_end(MergeBB) +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle +import llvmlite.ir as ir +import ast + + +class IfHandle(BaseHandle): + def _get_attr_full_name(self, node): + if isinstance(node, ast.Attribute): + parts = [] + cur = node + while isinstance(cur, ast.Attribute): + parts.append(cur.attr) + cur = cur.value + if isinstance(cur, ast.Name): + parts.append(cur.id) + parts.reverse() + return '.'.join(parts) + return None + + def _is_cif_call(self, node): + if isinstance(node, ast.Call): + if isinstance(node.func, ast.Attribute): + if isinstance(node.func.value, ast.Name) and node.func.value.id == 'c': + return node.func.attr in ('CIf', 'CIfdef', 'CIfndef') + if isinstance(node.func, ast.Name): + return node.func.id in ('CIf', 'CIfdef', 'CIfndef') + return False + + def _resolve_macro_name(self, arg): + if isinstance(arg, ast.Name): + return arg.id + if isinstance(arg, ast.Constant) and isinstance(arg.value, str): + return arg.value + if isinstance(arg, ast.Attribute): + full_name = self._get_attr_full_name(arg) + if full_name: + return full_name + return None + + def _evaluate_cif_condition(self, node): + if not isinstance(node, ast.Call): + return None + args = node.args + if not args: + return False + if isinstance(node.func, ast.Attribute): + kind = node.func.attr + elif isinstance(node.func, ast.Name): + kind = node.func.id + else: + return None + if kind == 'CIfdef': + name = self._resolve_macro_name(args[0]) + if name is None: + return False + return self._is_macro_defined(name) + elif kind == 'CIfndef': + name = self._resolve_macro_name(args[0]) + if name is None: + return True + return not self._is_macro_defined(name) + elif kind == 'CIf': + return self._eval_const_expr(args[0]) + return None + + def _is_macro_defined(self, name): + Gen = self.Trans.LlvmGen + if hasattr(Gen, '_define_constants') and name in Gen._define_constants: + return True + if name in self.Trans.SymbolTable: + info = self.Trans.SymbolTable[name] + if getattr(info, 'IsDefine', False): + return True + platform_macros = self._get_platform_macros() + return name in platform_macros + + def _get_macro_value(self, name): + Gen = self.Trans.LlvmGen + if hasattr(Gen, '_define_constants') and name in Gen._define_constants: + val = Gen._define_constants[name] + if isinstance(val, (int, float)): + return val + if name in self.Trans.SymbolTable: + info = self.Trans.SymbolTable[name] + if getattr(info, 'IsDefine', False): + val = getattr(info, 'DefineValue', 0) + if isinstance(val, (int, float)): + return val + platform_macros = self._get_platform_macros() + if name in platform_macros: + return platform_macros[name] + return None + + def _get_platform_macros(self): + Gen = self.Trans.LlvmGen + macros = {} + pi = getattr(Gen, '_platform_info', {}) + ptr_size = getattr(Gen, 'ptr_size', 8) + # 根据目标平台设置宏(从三元组推导) + if pi.get('is_windows'): + macros['_WIN32'] = 1 + if not pi.get('is_32bit'): + macros['_WIN64'] = 1 + macros['WIN64'] = 1 + macros['WIN32'] = 1 + if pi.get('is_linux'): + macros['__linux__'] = 1 + if pi.get('is_macos'): + macros['__APPLE__'] = 1 + macros['__MACH__'] = 1 + if pi.get('is_x86_64'): + macros['__x86_64__'] = 1 + macros['__x86_64'] = 1 + macros['_M_X64'] = 1 + elif pi.get('is_arm64'): + macros['__aarch64__'] = 1 + macros['_M_ARM64'] = 1 + if not pi.get('is_32bit') and pi.get('is_linux'): + macros['__LP64__'] = 1 + elif pi.get('is_32bit'): + macros['_ILP32'] = 1 + macros['SIZEOF_VOID_P'] = ptr_size + macros['__SIZEOF_POINTER__'] = ptr_size + macros['NDEBUG'] = 0 + return macros + + def _eval_const_expr(self, node): + if isinstance(node, ast.Constant): + val = node.value + if isinstance(val, bool): + return 1 if val else 0 + if isinstance(val, int): + return val + if isinstance(val, float): + return 1 if val != 0.0 else 0 + return 0 + if isinstance(node, ast.Name): + name = node.id + val = self._get_macro_value(name) + if val is not None: + return val + return None + if isinstance(node, ast.Attribute): + full_key = self._get_attr_full_name(node) + if full_key: + val = self._get_macro_value(full_key) + if val is not None: + return val + short_name = full_key.split('.')[-1] if '.' in full_key else full_key + val = self._get_macro_value(short_name) + if val is not None: + return val + return None + if isinstance(node, ast.UnaryOp): + operand = self._eval_const_expr(node.operand) + if operand is None: + return None + if isinstance(node.op, ast.Not): + return 1 if not operand else 0 + if isinstance(node.op, ast.USub): + return -operand + if isinstance(node.op, ast.Invert): + return ~operand + return None + if isinstance(node, ast.BinOp): + left = self._eval_const_expr(node.left) + right = self._eval_const_expr(node.right) + if left is None or right is None: + return None + try: + if isinstance(node.op, ast.Add): + return left + right + elif isinstance(node.op, ast.Sub): + return left - right + elif isinstance(node.op, ast.Mult): + return left * right + elif isinstance(node.op, ast.FloorDiv): + return left // right if right != 0 else 0 + elif isinstance(node.op, ast.Mod): + return left % right if right != 0 else 0 + elif isinstance(node.op, ast.LShift): + return left << right + elif isinstance(node.op, ast.RShift): + return left >> right + elif isinstance(node.op, ast.BitOr): + return left | right + elif isinstance(node.op, ast.BitAnd): + return left & right + elif isinstance(node.op, ast.BitXor): + return left ^ right + except Exception: + return None + return None + if isinstance(node, ast.BoolOp): + if isinstance(node.op, ast.And): + for val in node.values: + result = self._eval_const_expr(val) + if result is None: + return None + if not result: + return 0 + return 1 + elif isinstance(node.op, ast.Or): + for val in node.values: + result = self._eval_const_expr(val) + if result is None: + return None + if result: + return 1 + return 0 + if isinstance(node, ast.Compare): + left = self._eval_const_expr(node.left) + if left is None: + return None + for op, comparator in zip(node.ops, node.comparators): + right = self._eval_const_expr(comparator) + if right is None: + return None + if isinstance(op, ast.Eq): + result = left == right + elif isinstance(op, ast.NotEq): + result = left != right + elif isinstance(op, ast.Lt): + result = left < right + elif isinstance(op, ast.LtE): + result = left <= right + elif isinstance(op, ast.Gt): + result = left > right + elif isinstance(op, ast.GtE): + result = left >= right + else: + return None + if not result: + return 0 + return 1 + if isinstance(node, ast.Call): + if self._is_cif_call(node): + return self._evaluate_cif_condition(node) + return None + + def _HandleIfLlvm(self, Node): + Gen = self.Trans.LlvmGen + if self._is_cif_call(Node.test): + compile_time_val = self._evaluate_cif_condition(Node.test) + if compile_time_val is not None: + if compile_time_val: + self.Trans.BodyHandler.HandleBodyLlvm(Node.body) + elif Node.orelse: + if isinstance(Node.orelse, list) and len(Node.orelse) == 1 and isinstance(Node.orelse[0], ast.If): + self._HandleIfLlvm(Node.orelse[0]) + else: + self.Trans.BodyHandler.HandleBodyLlvm(Node.orelse) + return + Cond = self.Trans.ExprHandler.HandleExprLlvm(Node.test) + if not Cond: + return + is_const = isinstance(Cond, ir.Constant) and isinstance(Cond.type, ir.IntType) and Cond.type.width == 1 + if is_const: + if Cond.constant: + self.Trans.BodyHandler.HandleBodyLlvm(Node.body) + elif Node.orelse: + if isinstance(Node.orelse, list) and len(Node.orelse) == 1 and isinstance(Node.orelse[0], ast.If): + self._HandleIfLlvm(Node.orelse[0]) + else: + self.Trans.BodyHandler.HandleBodyLlvm(Node.orelse) + return + if not isinstance(Cond.type, ir.IntType) or Cond.type.width != 1: + ClassName = self.Trans.ExprHandler._get_var_class(Node.test, Gen) + if ClassName and Gen._has_function(f'{ClassName}.__bool__'): + obj_val = Cond + if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8: + obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") + Cond = Gen.builder.call(Gen._get_function(f'{ClassName}.__bool__'), [obj_val], name=f"call_{ClassName}.__bool__") + if isinstance(Cond.type, ir.IntType) and Cond.type.width != 1: + Cond = Gen.builder.icmp_signed('!=', Cond, Gen._ZeroConst(Cond.type), name="bool_result") + else: + if isinstance(Cond.type, (ir.FloatType, ir.DoubleType)): + Cond = Gen.builder.fcmp_ordered('!=', Cond, ir.Constant(Cond.type, 0.0), name="ifcond") + else: + Cond = Gen.builder.icmp_signed('!=', Cond, Gen._ZeroConst(Cond.type), name="ifcond") + ThenBB = Gen.func.append_basic_block(name="then") + ElseBB = Gen.func.append_basic_block(name="else") if Node.orelse else None + MergeBB = Gen.func.append_basic_block(name="endif") + if not Gen.builder.block.is_terminated: + Gen.builder.cbranch(Cond, ThenBB, ElseBB if ElseBB else MergeBB) + Gen.builder.position_at_start(ThenBB) + self.Trans.BodyHandler.HandleBodyLlvm(Node.body) + if not Gen.builder.block.is_terminated: + Gen.builder.branch(MergeBB) + if ElseBB: + Gen.builder.position_at_start(ElseBB) + self.Trans.BodyHandler.HandleBodyLlvm(Node.orelse) + if not Gen.builder.block.is_terminated: + Gen.builder.branch(MergeBB) + if not MergeBB.is_terminated: + Gen.builder.position_at_start(MergeBB) + else: + Gen.builder.position_at_end(MergeBB) diff --git a/lib/core/Handles/HandlesImports.py b/lib/core/Handles/HandlesImports.py index 620b5a7..86f5b61 100644 --- a/lib/core/Handles/HandlesImports.py +++ b/lib/core/Handles/HandlesImports.py @@ -2,7 +2,7 @@ from __future__ import annotations from typing import TYPE_CHECKING if TYPE_CHECKING: from lib.core.translator import Translator -from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo, FuncMeta +from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo, FuncMeta from lib.includes import t import ast import os @@ -13,13 +13,13 @@ import llvmlite.ir as ir class ImportHandle(BaseHandle): _stub_cache = {} _stub_cache_dir = None - _struct_load_cache = {} + _struct_Load_cache = {} _pyi_cache = {} _pyi_cache_dir = None _project_root_cache = None def _reset_file_cache(self): - self._struct_load_cache.clear() + self._struct_Load_cache.clear() def _find_project_root(self): if self._project_root_cache is not None: @@ -43,17 +43,17 @@ class ImportHandle(BaseHandle): return os.getcwd() def _EmitImportDeclarationsLlvm(self, Node, Gen): - if not getattr(self.Trans, '_imported_modules', None): - self.Trans._imported_modules = set() - if not getattr(self.Trans, '_import_aliases', None): - self.Trans._import_aliases = {} + if not getattr(self.Trans, '_ImportedModules', None): + self.Trans._ImportedModules = set() + if not getattr(self.Trans, '_ImportAliases', None): + self.Trans._ImportAliases = {} for alias in Node.names: name = alias.name if name in ('c', 't'): continue - self.Trans._imported_modules.add(name) + self.Trans._ImportedModules.add(name) if alias.asname: - self.Trans._import_aliases[alias.asname] = name + self.Trans._ImportAliases[alias.asname] = name # 同时在符号表中注册模块别名,以便 CTypeInfo.FromNode 能解析 AliasInfo = CTypeInfo() AliasInfo.IsModuleAlias = True @@ -63,7 +63,7 @@ class ImportHandle(BaseHandle): self._EmitModuleDeclarationsLlvm(name, Gen, register_module_name=current_module) def _RegisterFromImportAliases(self, Node, Gen, module): - """Register 'from module import y as z' aliases after module declarations are loaded""" + """Register 'from module import y as z' aliases after module declarations are Loaded""" if not Node.names: return for alias in Node.names: @@ -125,11 +125,11 @@ class ImportHandle(BaseHandle): def _EmitImportFromDeclarationsLlvm(self, Node, Gen): module = Node.module if Node.module else '' if module in ('c', 't'): - if not getattr(self.Trans, '_imported_modules', None): - self.Trans._imported_modules = set() - if not getattr(self.Trans, '_import_aliases', None): - self.Trans._import_aliases = {} - self.Trans._imported_modules.add(module) + if not getattr(self.Trans, '_ImportedModules', None): + self.Trans._ImportedModules = set() + if not getattr(self.Trans, '_ImportAliases', None): + self.Trans._ImportAliases = {} + self.Trans._ImportedModules.add(module) if not hasattr(self.Trans, '_t_c_imported_names'): self.Trans._t_c_imported_names = {} for alias in Node.names: @@ -137,10 +137,10 @@ class ImportHandle(BaseHandle): asname = alias.asname or name self.Trans._t_c_imported_names[asname] = (module, name) return - if not getattr(self.Trans, '_imported_modules', None): - self.Trans._imported_modules = set() - if not getattr(self.Trans, '_import_aliases', None): - self.Trans._import_aliases = {} + if not getattr(self.Trans, '_ImportedModules', None): + self.Trans._ImportedModules = set() + if not getattr(self.Trans, '_ImportAliases', None): + self.Trans._ImportAliases = {} current_module = self._get_current_module_name() if Node.level and Node.level > 0: current_file = getattr(self.Trans, 'CurrentFile', '') or '' @@ -154,20 +154,20 @@ class ImportHandle(BaseHandle): for ext in SearchExtensions: candidate = sub_path_base + ext if os.path.isfile(candidate): - self.Trans._imported_modules.add(module) + self.Trans._ImportedModules.add(module) self._LoadModuleDeclarationsFromFile(candidate, Gen, module_name=module, register_module_name=current_module) self._RegisterFromImportAliases(Node, Gen, module) return - module_sha1_map = getattr(Gen, 'module_sha1_map', {}) + ModuleSha1Map = getattr(Gen, 'ModuleSha1Map', {}) # 尝试完整模块名和短模块名 full_mod_name = f"{current_module}.{module}" if current_module else module - target_sha1 = module_sha1_map.get(full_mod_name) or module_sha1_map.get(module) + target_sha1 = ModuleSha1Map.get(full_mod_name) or ModuleSha1Map.get(module) if target_sha1: temp_dir = getattr(Gen, '_temp_dir', None) if temp_dir: sha1_pyi = os.path.join(temp_dir, f"{target_sha1}.pyi") if os.path.isfile(sha1_pyi): - self.Trans._imported_modules.add(module) + self.Trans._ImportedModules.add(module) self._LoadModuleDeclarationsFromFile(sha1_pyi, Gen, module_name=module, register_module_name=current_module) self._RegisterFromImportAliases(Node, Gen, module) return @@ -177,39 +177,39 @@ class ImportHandle(BaseHandle): SearchExtensions = ['.pyi', '.py'] pkg_name = '' if not module: - # When 'from . import name' is used, load the package's __init__ + # When 'from . import name' is used, Load the package's __init__ # to make package-level names (functions, classes, constants) available pkg_name = self._LoadPackageInitForRelativeImport(mod_dir, Gen, current_module) - # Also try to load each alias as a submodule + # Also try to Load each alias as a submodule for alias in Node.names: found_sub = False for ext in SearchExtensions: sub_path = os.path.join(mod_dir, alias.name + ext) if os.path.isfile(sub_path): - self.Trans._imported_modules.add(alias.name) + self.Trans._ImportedModules.add(alias.name) self._LoadModuleDeclarationsFromFile(sub_path, Gen, module_name=alias.name, register_module_name=current_module) if alias.asname: - self.Trans._import_aliases[alias.asname] = alias.name + self.Trans._ImportAliases[alias.asname] = alias.name found_sub = True break if not found_sub: # SHA1 map fallback for submodule - module_sha1_map = getattr(Gen, 'module_sha1_map', {}) - sub_module_path = f"{pkg_name}.{alias.name}" if pkg_name else alias.name - target_sha1 = module_sha1_map.get(sub_module_path) or module_sha1_map.get(alias.name) + ModuleSha1Map = getattr(Gen, 'ModuleSha1Map', {}) + sub_ModulePath = f"{pkg_name}.{alias.name}" if pkg_name else alias.name + target_sha1 = ModuleSha1Map.get(sub_ModulePath) or ModuleSha1Map.get(alias.name) if target_sha1: temp_dir = getattr(Gen, '_temp_dir', None) if temp_dir: sha1_pyi = os.path.join(temp_dir, f"{target_sha1}.pyi") if os.path.isfile(sha1_pyi): - self.Trans._imported_modules.add(sub_module_path) + self.Trans._ImportedModules.add(sub_ModulePath) self._LoadModuleDeclarationsFromFile(sha1_pyi, Gen, module_name=alias.name, register_module_name=current_module) if alias.asname: - self.Trans._import_aliases[alias.asname] = alias.name + self.Trans._ImportAliases[alias.asname] = alias.name self._RegisterFromImportAliases(Node, Gen, module or pkg_name) return - self.Trans._imported_modules.add(module) + self.Trans._ImportedModules.add(module) self._EmitModuleDeclarationsLlvm(module, Gen, register_module_name=current_module) self._RegisterFromImportAliases(Node, Gen, module) @@ -229,15 +229,15 @@ class ImportHandle(BaseHandle): reexport_names = [] if module_name and module_name != file_module_name and module_name != effective_register: reexport_names.append(module_name) - # When loading a submodule for 'from .xxx import yyy' inside a package's __init__.py, + # When Loading a submodule for 'from .xxx import yyy' inside a package's __init__.py, # re-export functions under the package name so 'pkg.func()' resolves correctly if reexport_package and reexport_package != file_module_name and reexport_package not in reexport_names: reexport_names.append(reexport_package) self._EmitExternalFuncDeclLlvm(node, Gen, source_module_name=file_module_name, register_module_name=effective_register, reexport_module_names=reexport_names if reexport_names else None) elif isinstance(node, ast.AnnAssign): - self._EmitExternalGlobalDeclLlvm(node, Gen, module_name=module_name, module_path=pyi_path) + self._EmitExternalGlobalDeclLlvm(node, Gen, module_name=module_name, ModulePath=pyi_path) elif isinstance(node, ast.Assign): - self._EmitExternalGlobalDeclLlvm(node, Gen, module_name=module_name, module_path=pyi_path) + self._EmitExternalGlobalDeclLlvm(node, Gen, module_name=module_name, ModulePath=pyi_path) elif isinstance(node, ast.ClassDef): if hasattr(node, 'type_params') and node.type_params: if not hasattr(self.Trans.ClassHandler, '_generic_class_templates'): @@ -263,9 +263,9 @@ class ImportHandle(BaseHandle): if os.path.isfile(candidate): actual_module = f"{register_module_name}.{node.module}" if register_module_name else node.module self._RegisterSubModuleSha1(candidate, actual_module, node.module, Gen) - if not getattr(self.Trans, '_imported_modules', None): - self.Trans._imported_modules = set() - self.Trans._imported_modules.add(actual_module) + if not getattr(self.Trans, '_ImportedModules', None): + self.Trans._ImportedModules = set() + self.Trans._ImportedModules.add(actual_module) for alias in node.names: if alias.name == '*': self._LoadModuleDeclarationsFromFile(candidate, Gen, module_name=module_name, register_module_name=register_module_name, reexport_package=reexport_package or module_name) @@ -276,16 +276,16 @@ class ImportHandle(BaseHandle): # SHA1 map 回退 if not found_sub: actual_module = f"{register_module_name}.{node.module}" if register_module_name else node.module - module_sha1_map = getattr(Gen, 'module_sha1_map', {}) - target_sha1 = module_sha1_map.get(actual_module) or module_sha1_map.get(node.module) + ModuleSha1Map = getattr(Gen, 'ModuleSha1Map', {}) + target_sha1 = ModuleSha1Map.get(actual_module) or ModuleSha1Map.get(node.module) if target_sha1: temp_dir = getattr(Gen, '_temp_dir', None) if temp_dir: sha1_pyi = os.path.join(temp_dir, f"{target_sha1}.pyi") if os.path.isfile(sha1_pyi): - if not getattr(self.Trans, '_imported_modules', None): - self.Trans._imported_modules = set() - self.Trans._imported_modules.add(actual_module) + if not getattr(self.Trans, '_ImportedModules', None): + self.Trans._ImportedModules = set() + self.Trans._ImportedModules.add(actual_module) for alias in node.names: if alias.name == '*': self._LoadModuleDeclarationsFromFile(sha1_pyi, Gen, module_name=module_name, register_module_name=register_module_name, reexport_package=reexport_package or module_name) @@ -301,10 +301,10 @@ class ImportHandle(BaseHandle): for ext in SearchExtensions: sub_path = os.path.join(mod_dir, alias.name + ext) if os.path.isfile(sub_path): - sub_module_path = f"{register_module_name}.{alias.name}" if register_module_name else alias.name - if not getattr(self.Trans, '_imported_modules', None): - self.Trans._imported_modules = set() - self.Trans._imported_modules.add(sub_module_path) + sub_ModulePath = f"{register_module_name}.{alias.name}" if register_module_name else alias.name + if not getattr(self.Trans, '_ImportedModules', None): + self.Trans._ImportedModules = set() + self.Trans._ImportedModules.add(sub_ModulePath) if alias.name == '*': self._LoadModuleDeclarationsFromFile(sub_path, Gen, module_name=module_name, register_module_name=register_module_name, reexport_package=reexport_package or module_name) else: @@ -313,17 +313,17 @@ class ImportHandle(BaseHandle): break # SHA1 map 回退 if not found_alias: - sub_module_path = f"{register_module_name}.{alias.name}" if register_module_name else alias.name - module_sha1_map = getattr(Gen, 'module_sha1_map', {}) - target_sha1 = module_sha1_map.get(sub_module_path) or module_sha1_map.get(alias.name) + sub_ModulePath = f"{register_module_name}.{alias.name}" if register_module_name else alias.name + ModuleSha1Map = getattr(Gen, 'ModuleSha1Map', {}) + target_sha1 = ModuleSha1Map.get(sub_ModulePath) or ModuleSha1Map.get(alias.name) if target_sha1: temp_dir = getattr(Gen, '_temp_dir', None) if temp_dir: sha1_pyi = os.path.join(temp_dir, f"{target_sha1}.pyi") if os.path.isfile(sha1_pyi): - if not getattr(self.Trans, '_imported_modules', None): - self.Trans._imported_modules = set() - self.Trans._imported_modules.add(sub_module_path) + if not getattr(self.Trans, '_ImportedModules', None): + self.Trans._ImportedModules = set() + self.Trans._ImportedModules.add(sub_ModulePath) if alias.name == '*': self._LoadModuleDeclarationsFromFile(sha1_pyi, Gen, module_name=module_name, register_module_name=register_module_name, reexport_package=reexport_package or module_name) else: @@ -339,52 +339,56 @@ class ImportHandle(BaseHandle): return None def _RegisterSubModuleSha1(self, candidate_path, actual_module, short_module, Gen): - """Register a submodule's SHA1 in module_sha1_map so cross-module class references work""" + """Register a submodule's SHA1 in ModuleSha1Map so cross-module class references work""" try: with open(candidate_path, 'r', encoding='utf-8') as f: sub_content = f.read() sub_sha1 = hashlib.sha1(sub_content.encode('utf-8')).hexdigest()[:16] - if hasattr(Gen, 'module_sha1_map'): - Gen.module_sha1_map[actual_module] = sub_sha1 - if short_module and short_module not in Gen.module_sha1_map: - Gen.module_sha1_map[short_module] = sub_sha1 - except Exception: - pass + if hasattr(Gen, 'ModuleSha1Map'): + Gen.ModuleSha1Map[actual_module] = sub_sha1 + if short_module and short_module not in Gen.ModuleSha1Map: + Gen.ModuleSha1Map[short_module] = sub_sha1 + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _config_mode + if _config_mode == "strict": + raise + _vlog().warning(f"处理导入失败: {_e}", "Exception") + + def _LoadPackageInitForRelativeImport(self, mod_dir, Gen, register_module_name): + """Load __init__.py from the package directory for 'from . import name' resolution. + This makes package-level names (functions, classes, constants) available. + Returns the package name.""" + pkg_name = os.path.basename(mod_dir) + init_Loaded = False + + # 跳过当前正在编译的文件,避免重复加载导致 class_members 重复 + current_sha1 = getattr(Gen, 'module_sha1', None) + ModuleSha1Map = getattr(Gen, 'ModuleSha1Map', {}) + pkg_sha1 = ModuleSha1Map.get(pkg_name) + if pkg_sha1 and pkg_sha1 == current_sha1: + return pkg_name + + # Try SHA1 map first (correct mangled names from stub) + if pkg_sha1: + temp_dir = getattr(Gen, '_temp_dir', None) + if temp_dir: + sha1_pyi = os.path.join(temp_dir, f"{pkg_sha1}.pyi") + if os.path.isfile(sha1_pyi): + self._LoadModuleDeclarationsFromFile(sha1_pyi, Gen, module_name=pkg_name, register_module_name=register_module_name) + init_Loaded = True + + # Fallback: try Loading __init__.py directly from the package directory + if not init_Loaded: + for ext in ['.pyi', '.py']: + init_path = os.path.join(mod_dir, '__init__' + ext) + if os.path.isfile(init_path): + self._LoadModuleDeclarationsFromFile(init_path, Gen, module_name=pkg_name, register_module_name=register_module_name) + init_Loaded = True + break + + return pkg_name - def _LoadPackageInitForRelativeImport(self, mod_dir, Gen, register_module_name): - """Load __init__.py from the package directory for 'from . import name' resolution. - This makes package-level names (functions, classes, constants) available. - Returns the package name.""" - pkg_name = os.path.basename(mod_dir) - init_loaded = False - - # 跳过当前正在编译的文件,避免重复加载导致 class_members 重复 - current_sha1 = getattr(Gen, 'module_sha1', None) - module_sha1_map = getattr(Gen, 'module_sha1_map', {}) - pkg_sha1 = module_sha1_map.get(pkg_name) - if pkg_sha1 and pkg_sha1 == current_sha1: - return pkg_name - - # Try SHA1 map first (correct mangled names from stub) - if pkg_sha1: - temp_dir = getattr(Gen, '_temp_dir', None) - if temp_dir: - sha1_pyi = os.path.join(temp_dir, f"{pkg_sha1}.pyi") - if os.path.isfile(sha1_pyi): - self._LoadModuleDeclarationsFromFile(sha1_pyi, Gen, module_name=pkg_name, register_module_name=register_module_name) - init_loaded = True - - # Fallback: try loading __init__.py directly from the package directory - if not init_loaded: - for ext in ['.pyi', '.py']: - init_path = os.path.join(mod_dir, '__init__' + ext) - if os.path.isfile(init_path): - self._LoadModuleDeclarationsFromFile(init_path, Gen, module_name=pkg_name, register_module_name=register_module_name) - init_loaded = True - break - - return pkg_name - def _EmitModuleDeclarationsLlvm(self, module_name, Gen, register_module_name=None): if module_name in ('pyzlib',): source_sig_files = getattr(self.Trans, '_source_module_sig_files', None) @@ -489,10 +493,10 @@ class ImportHandle(BaseHandle): self._EmitExternalFuncDeclLlvm(node, Gen, source_module_name=module_name, register_module_name=effective_register) has_functions_or_classes = True elif isinstance(node, ast.AnnAssign): - self._EmitExternalGlobalDeclLlvm(node, Gen, module_name=module_name, module_path=FullModulePath) + self._EmitExternalGlobalDeclLlvm(node, Gen, module_name=module_name, ModulePath=FullModulePath) has_functions_or_classes = True elif isinstance(node, ast.Assign): - self._EmitExternalGlobalDeclLlvm(node, Gen, module_name=module_name, module_path=FullModulePath) + self._EmitExternalGlobalDeclLlvm(node, Gen, module_name=module_name, ModulePath=FullModulePath) has_functions_or_classes = True elif isinstance(node, ast.ClassDef): if hasattr(node, 'type_params') and node.type_params: @@ -520,9 +524,9 @@ class ImportHandle(BaseHandle): if os.path.isfile(candidate): actual_module = f"{module_name}.{node.module}" if module_name else node.module self._RegisterSubModuleSha1(candidate, actual_module, node.module, Gen) - if not getattr(self.Trans, '_imported_modules', None): - self.Trans._imported_modules = set() - self.Trans._imported_modules.add(actual_module) + if not getattr(self.Trans, '_ImportedModules', None): + self.Trans._ImportedModules = set() + self.Trans._ImportedModules.add(actual_module) for alias in node.names: if alias.name == '*': self._LoadModuleDeclarationsFromFile(candidate, Gen, module_name=module_name, register_module_name=register_module_name, reexport_package=module_name) @@ -534,17 +538,17 @@ class ImportHandle(BaseHandle): # SHA1 map 回退:当文件查找失败时,从 SHA1 映射中查找子模块 stub if not found_sub: actual_module = f"{module_name}.{node.module}" if module_name else node.module - module_sha1_map = getattr(Gen, 'module_sha1_map', {}) + ModuleSha1Map = getattr(Gen, 'ModuleSha1Map', {}) # 尝试完整模块名和短模块名 - target_sha1 = module_sha1_map.get(actual_module) or module_sha1_map.get(node.module) + target_sha1 = ModuleSha1Map.get(actual_module) or ModuleSha1Map.get(node.module) if target_sha1: temp_dir = getattr(Gen, '_temp_dir', None) if temp_dir: sha1_pyi = os.path.join(temp_dir, f"{target_sha1}.pyi") if os.path.isfile(sha1_pyi): - if not getattr(self.Trans, '_imported_modules', None): - self.Trans._imported_modules = set() - self.Trans._imported_modules.add(actual_module) + if not getattr(self.Trans, '_ImportedModules', None): + self.Trans._ImportedModules = set() + self.Trans._ImportedModules.add(actual_module) for alias in node.names: if alias.name == '*': self._LoadModuleDeclarationsFromFile(sha1_pyi, Gen, module_name=module_name, register_module_name=register_module_name, reexport_package=module_name) @@ -561,10 +565,10 @@ class ImportHandle(BaseHandle): for ext in SearchExtensions: sub_path = os.path.join(mod_dir, alias.name + ext) if os.path.isfile(sub_path): - sub_module_path = f"{module_name}.{alias.name}" if module_name else alias.name - if not getattr(self.Trans, '_imported_modules', None): - self.Trans._imported_modules = set() - self.Trans._imported_modules.add(sub_module_path) + sub_ModulePath = f"{module_name}.{alias.name}" if module_name else alias.name + if not getattr(self.Trans, '_ImportedModules', None): + self.Trans._ImportedModules = set() + self.Trans._ImportedModules.add(sub_ModulePath) if alias.name == '*': self._LoadModuleDeclarationsFromFile(sub_path, Gen, module_name=module_name, register_module_name=register_module_name, reexport_package=module_name) else: @@ -574,17 +578,17 @@ class ImportHandle(BaseHandle): break # SHA1 map 回退 if not found_alias: - sub_module_path = f"{module_name}.{alias.name}" if module_name else alias.name - module_sha1_map = getattr(Gen, 'module_sha1_map', {}) - target_sha1 = module_sha1_map.get(sub_module_path) or module_sha1_map.get(alias.name) + sub_ModulePath = f"{module_name}.{alias.name}" if module_name else alias.name + ModuleSha1Map = getattr(Gen, 'ModuleSha1Map', {}) + target_sha1 = ModuleSha1Map.get(sub_ModulePath) or ModuleSha1Map.get(alias.name) if target_sha1: temp_dir = getattr(Gen, '_temp_dir', None) if temp_dir: sha1_pyi = os.path.join(temp_dir, f"{target_sha1}.pyi") if os.path.isfile(sha1_pyi): - if not getattr(self.Trans, '_imported_modules', None): - self.Trans._imported_modules = set() - self.Trans._imported_modules.add(sub_module_path) + if not getattr(self.Trans, '_ImportedModules', None): + self.Trans._ImportedModules = set() + self.Trans._ImportedModules.add(sub_ModulePath) if alias.name == '*': self._LoadModuleDeclarationsFromFile(sha1_pyi, Gen, module_name=module_name, register_module_name=register_module_name, reexport_package=module_name) else: @@ -603,13 +607,13 @@ class ImportHandle(BaseHandle): if module_name: self._LoadDeclarationsFromStubLlvm(module_name, Gen) - def _EmitExternalGlobalDeclLlvm(self, Node, Gen, module_name=None, module_path=None): + def _EmitExternalGlobalDeclLlvm(self, Node, Gen, module_name=None, ModulePath=None): """Emit external global variable declaration from imported module""" if isinstance(Node, ast.AnnAssign) and isinstance(Node.target, ast.Name): VarName = Node.target.id # 不再跳过 _ 开头的全局变量,跨模块引用需要声明它们 var_type = ir.IntType(32) - is_ptr = False + IsPtr = False is_string_val = False if VarName in Gen.module.globals: existing = Gen.module.globals[VarName] @@ -637,12 +641,12 @@ class ImportHandle(BaseHandle): var_type = ir.ArrayType(elem_type, 0) else: var_type = Gen._ctype_to_llvm(ElemTypeInfo) - is_ptr = False + IsPtr = False else: TypeInfo = CTypeInfo.FromNode(Node.annotation, self.Trans.SymbolTable) if TypeInfo: var_type = Gen._ctype_to_llvm(TypeInfo) - is_ptr = TypeInfo.IsPtr + IsPtr = TypeInfo.IsPtr elif isinstance(Node.annotation, ast.BinOp) and isinstance(Node.annotation.op, ast.BitOr): list_node = None for side in (Node.annotation.left, Node.annotation.right): @@ -665,20 +669,20 @@ class ImportHandle(BaseHandle): var_type = ir.ArrayType(elem_type, 0) else: var_type = Gen._ctype_to_llvm(ElemTypeInfo) - is_ptr = False + IsPtr = False else: TypeInfo = CTypeInfo.FromNode(Node.annotation, self.Trans.SymbolTable) if TypeInfo: var_type = Gen._ctype_to_llvm(TypeInfo) - is_ptr = TypeInfo.IsPtr + IsPtr = TypeInfo.IsPtr else: TypeInfo = CTypeInfo.FromNode(Node.annotation, self.Trans.SymbolTable) if TypeInfo: var_type = Gen._ctype_to_llvm(TypeInfo) - is_ptr = TypeInfo.IsPtr + IsPtr = TypeInfo.IsPtr if isinstance(var_type, ir.IdentifiedStructType) and (var_type.elements is None or len(var_type.elements) == 0): var_type = ir.IntType(32) - if Node.value and module_path and is_ptr and isinstance(Node.value, ast.Constant) and isinstance(Node.value.value, str): + if Node.value and ModulePath and IsPtr and isinstance(Node.value, ast.Constant) and isinstance(Node.value.value, str): str_val = Node.value.value + '\x00' str_bytes = str_val.encode('utf-8') arr_type = ir.ArrayType(ir.IntType(8), len(str_bytes)) @@ -743,13 +747,21 @@ class ImportHandle(BaseHandle): if Node.value: DefineValue = self._ExtractConstValue(Node.value) # 注册不带前缀的键名(例如 Z_NO_COMPRESSION) - self._RegisterCDefineSymbol(VarName, DefineValue, Node.lineno, module_path or 'unknown') + self._RegisterCDefineSymbol(VarName, DefineValue, Node.lineno, ModulePath or 'unknown') # 如果提供了模块名,也注册带模块前缀的键名 if module_name: FullName = f"{module_name}.{VarName}" - self._RegisterCDefineSymbol(FullName, DefineValue, Node.lineno, module_path or 'unknown') + self._RegisterCDefineSymbol(FullName, DefineValue, Node.lineno, ModulePath or 'unknown') return # 不再继续生成 LLVM 全局变量 - + + # t.State 标记的全局变量:只声明不定义(external linkage),避免 DSO/non-DSO 重定义 + if TypeInfo and TypeInfo.IsState: + if VarName not in Gen.module.globals: + gv = ir.GlobalVariable(Gen.module, var_type, name=VarName) + gv.linkage = 'external' + Gen._export_funcs.add(VarName) + return + gv = ir.GlobalVariable(Gen.module, var_type, name=VarName) if Node.value: @@ -768,7 +780,7 @@ class ImportHandle(BaseHandle): if VarName in Gen.module.globals: return gv = ir.GlobalVariable(Gen.module, ir.IntType(32), name=VarName) - if Node.value and module_path: + if Node.value and ModulePath: InitVal = self._ExtractValue(Node.value, ir.IntType(32), VarName) if InitVal is not None: gv.initializer = InitVal @@ -893,40 +905,40 @@ class ImportHandle(BaseHandle): return self._ExtractConstValue(value_node.args[0]) return None - def _ExtractTypedefOriginalType(self, value_node): - import ast - from lib.includes.t import CTypeRegistry - if isinstance(value_node, ast.Attribute): - if getattr(value_node.value, 'id', None) == 't': - llvm_str = CTypeRegistry.NameToLLVM(value_node.attr) - if llvm_str: - return llvm_str - elif isinstance(value_node, ast.Name): - llvm_str = CTypeRegistry.NameToLLVM(value_node.id) - if llvm_str: - return llvm_str - elif isinstance(value_node, ast.BinOp) and isinstance(value_node.op, ast.BitOr): - left = self._ExtractTypedefOriginalType(value_node.left) - right = self._ExtractTypedefOriginalType(value_node.right) - parts = [] - if left: - parts.append(left) - if right: - parts.append(right) - if parts: - return '|'.join(parts) - elif isinstance(value_node, ast.Call): - if isinstance(value_node.func, ast.Attribute): - if getattr(value_node.func.value, 'id', None) == 't': - llvm_str = CTypeRegistry.NameToLLVM(value_node.func.attr) - if llvm_str: - return llvm_str - elif isinstance(value_node.func, ast.Name): - llvm_str = CTypeRegistry.NameToLLVM(value_node.func.id) - if llvm_str: - return llvm_str - return None - + def _ExtractTypedefOriginalType(self, value_node): + import ast + from lib.includes.t import CTypeRegistry + if isinstance(value_node, ast.Attribute): + if getattr(value_node.value, 'id', None) == 't': + llvm_str = CTypeRegistry.NameToLLVM(value_node.attr) + if llvm_str: + return llvm_str + elif isinstance(value_node, ast.Name): + llvm_str = CTypeRegistry.NameToLLVM(value_node.id) + if llvm_str: + return llvm_str + elif isinstance(value_node, ast.BinOp) and isinstance(value_node.op, ast.BitOr): + left = self._ExtractTypedefOriginalType(value_node.left) + right = self._ExtractTypedefOriginalType(value_node.right) + parts = [] + if left: + parts.append(left) + if right: + parts.append(right) + if parts: + return '|'.join(parts) + elif isinstance(value_node, ast.Call): + if isinstance(value_node.func, ast.Attribute): + if getattr(value_node.func.value, 'id', None) == 't': + llvm_str = CTypeRegistry.NameToLLVM(value_node.func.attr) + if llvm_str: + return llvm_str + elif isinstance(value_node.func, ast.Name): + llvm_str = CTypeRegistry.NameToLLVM(value_node.func.id) + if llvm_str: + return llvm_str + return None + def _RegisterCDefineSymbol(self, FullName, DefineValue, lineno, FilePath): """Register CDefine constant to SymbolTable""" from lib.core.Handles.HandlesBase import CTypeInfo @@ -938,19 +950,19 @@ class ImportHandle(BaseHandle): # 直接添加到 SymbolTable 字典 self.Trans.SymbolTable[FullName] = info - def _check_annotation_for_state(self, annotation) -> bool: - import ast - if isinstance(annotation, ast.Attribute): - if hasattr(annotation, 'attr') and annotation.attr in ('CExport', 'CExtern', 'State'): - return True - if hasattr(annotation, 'value') and isinstance(annotation.value, ast.Name) and annotation.value.id == 't' and annotation.attr == 'State': - return True - elif isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr): - return self._check_annotation_for_state(annotation.left) or self._check_annotation_for_state(annotation.right) - elif isinstance(annotation, ast.Name): - return annotation.id in ('CExport', 'CExtern', 'State') - return False - + def _check_annotation_for_state(self, annotation) -> bool: + import ast + if isinstance(annotation, ast.Attribute): + if hasattr(annotation, 'attr') and annotation.attr in ('CExport', 'CExtern', 'State'): + return True + if hasattr(annotation, 'value') and isinstance(annotation.value, ast.Name) and annotation.value.id == 't' and annotation.attr == 'State': + return True + elif isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr): + return self._check_annotation_for_state(annotation.left) or self._check_annotation_for_state(annotation.right) + elif isinstance(annotation, ast.Name): + return annotation.id in ('CExport', 'CExtern', 'State') + return False + def _EmitExternalFuncDeclLlvm(self, Node, Gen, is_class_method=False, source_module_name=None, register_module_name=None, reexport_module_names=None): FuncName = Node.name if Node.returns and self._check_annotation_for_state(Node.returns): @@ -1086,13 +1098,15 @@ class ImportHandle(BaseHandle): elif d.id == 'classmethod': func_meta |= FuncMeta.CLASS_METHOD elif isinstance(d, ast.Attribute): - if isinstance(d.value, ast.Name) and d.value.id == 'property': - if d.attr == 'setter': - func_meta |= FuncMeta.PROPERTY_SETTER - elif d.attr == 'getter': - func_meta |= FuncMeta.PROPERTY_GETTER - elif d.attr == 'deleter': - func_meta |= FuncMeta.PROPERTY_DELETER + if isinstance(d.value, ast.Name): + # 支持 @property.setter 和 @propname.setter 两种形式 + if d.value.id == 'property' or d.attr in ('setter', 'getter', 'deleter'): + if d.attr == 'setter': + func_meta |= FuncMeta.PROPERTY_SETTER + elif d.attr == 'getter': + func_meta |= FuncMeta.PROPERTY_GETTER + elif d.attr == 'deleter': + func_meta |= FuncMeta.PROPERTY_DELETER if FuncName not in self.Trans.SymbolTable: FuncInfo = CTypeInfo() FuncInfo.Name = FuncName @@ -1103,6 +1117,28 @@ class ImportHandle(BaseHandle): existing = self.Trans.SymbolTable[FuncName] if existing.MetaList == FuncMeta.NONE and func_meta != FuncMeta.NONE: existing.MetaList = func_meta + # 同时注册带模块前缀的符号,以便 module.func_name 查找能命中 + if source_module_name and source_module_name not in ('c', 't'): + FullSymKey = f"{source_module_name}.{FuncName}" + if FullSymKey not in self.Trans.SymbolTable: + FullFuncInfo = CTypeInfo() + FullFuncInfo.Name = FullSymKey + FullFuncInfo.IsFunction = True + FullFuncInfo.MetaList = func_meta + self.Trans.SymbolTable[FullSymKey] = FullFuncInfo + # property setter/deleter: 在原始 PropKey(不带后缀)下注册 MetaList + if FuncMeta.PROPERTY_SETTER in func_meta or FuncMeta.PROPERTY_DELETER in func_meta: + BasePropKey = FuncName.replace('$set', '').replace('$del', '') + if BasePropKey in self.Trans.SymbolTable: + base_existing = self.Trans.SymbolTable[BasePropKey] + if func_meta != FuncMeta.NONE: + base_existing.MetaList = base_existing.MetaList | func_meta + else: + PropInfo = CTypeInfo() + PropInfo.Name = BasePropKey + PropInfo.IsFunction = True + PropInfo.MetaList = func_meta + self.Trans.SymbolTable[BasePropKey] = PropInfo if register_module_name and register_module_name != source_module_name: ReexportName = Gen._mangle_func_name(FuncName, module_name=register_module_name) Gen.functions[ReexportName] = func @@ -1207,10 +1243,10 @@ class ImportHandle(BaseHandle): return self._TryLoadStructFromStub(ClassName, Gen) source_sha1 = None - if actual_module_name and hasattr(Gen, 'module_sha1_map') and actual_module_name in Gen.module_sha1_map: - source_sha1 = Gen.module_sha1_map[actual_module_name] - elif module_name and hasattr(Gen, 'module_sha1_map') and module_name in Gen.module_sha1_map: - source_sha1 = Gen.module_sha1_map[module_name] + if actual_module_name and hasattr(Gen, 'ModuleSha1Map') and actual_module_name in Gen.ModuleSha1Map: + source_sha1 = Gen.ModuleSha1Map[actual_module_name] + elif module_name and hasattr(Gen, 'ModuleSha1Map') and module_name in Gen.ModuleSha1Map: + source_sha1 = Gen.ModuleSha1Map[module_name] # Track which module defines this class (for cross-module name mangling) if source_sha1: if not hasattr(Gen, 'class_sha1_map'): @@ -1268,9 +1304,15 @@ class ImportHandle(BaseHandle): is_item_prop_setter = any(isinstance(d, ast.Attribute) and d.attr == 'setter' and isinstance(d.value, ast.Name) and d.value.id == 'property' for d in item.decorator_list) is_item_prop_getter = any(isinstance(d, ast.Attribute) and d.attr == 'getter' and isinstance(d.value, ast.Name) and d.value.id == 'property' for d in item.decorator_list) is_item_prop_deleter = any(isinstance(d, ast.Attribute) and d.attr == 'deleter' and isinstance(d.value, ast.Name) and d.value.id == 'property' for d in item.decorator_list) - if FuncFullName not in Gen.functions: + # setter/deleter 使用不同的函数名后缀 + DeclFuncName = FuncFullName + if is_item_prop_setter: + DeclFuncName = FuncFullName + '$set' + elif is_item_prop_deleter: + DeclFuncName = FuncFullName + '$del' + if DeclFuncName not in Gen.functions: FuncDeclNode = ast.FunctionDef( - name=FuncFullName, + name=DeclFuncName, args=item.args, body=item.body, decorator_list=item.decorator_list, @@ -1290,10 +1332,11 @@ class ImportHandle(BaseHandle): func_meta |= FuncMeta.PROPERTY_GETTER if is_item_prop_deleter: func_meta |= FuncMeta.PROPERTY_DELETER - SymKey = FuncFullName + # setter/deleter 的 SymKey 使用带后缀的函数名 + SymKey = DeclFuncName if SymKey not in self.Trans.SymbolTable: FuncInfo = CTypeInfo() - FuncInfo.Name = FuncFullName + FuncInfo.Name = SymKey FuncInfo.IsFunction = True FuncInfo.MetaList = func_meta self.Trans.SymbolTable[SymKey] = FuncInfo @@ -1301,6 +1344,18 @@ class ImportHandle(BaseHandle): existing = self.Trans.SymbolTable[SymKey] if existing.MetaList == FuncMeta.NONE and func_meta != FuncMeta.NONE: existing.MetaList = func_meta + # setter/deleter: 同时在原始 PropKey(不带后缀)下注册 MetaList + if is_item_prop_setter or is_item_prop_deleter: + if FuncFullName in self.Trans.SymbolTable: + base_existing = self.Trans.SymbolTable[FuncFullName] + if func_meta != FuncMeta.NONE: + base_existing.MetaList = base_existing.MetaList | func_meta + else: + PropInfo = CTypeInfo() + PropInfo.Name = FuncFullName + PropInfo.IsFunction = True + PropInfo.MetaList = func_meta + self.Trans.SymbolTable[FuncFullName] = PropInfo if has_methods: if IsCVTable: Gen._cross_module_vtable_classes.add(ClassName) @@ -1308,8 +1363,8 @@ class ImportHandle(BaseHandle): NewFuncName = f'{ClassName}.__before_init__' if not Gen._has_function(NewFuncName) and (IsCpythonObject or IsCVTable): source_sha1 = None - if module_name and hasattr(Gen, 'module_sha1_map') and module_name in Gen.module_sha1_map: - source_sha1 = Gen.module_sha1_map[module_name] + if module_name and hasattr(Gen, 'ModuleSha1Map') and module_name in Gen.ModuleSha1Map: + source_sha1 = Gen.ModuleSha1Map[module_name] MangledName = Gen._mangle_name(NewFuncName) if not source_sha1 else f"{source_sha1}.{NewFuncName}" StructType = Gen.structs.get(ClassName) if StructType: @@ -1327,9 +1382,9 @@ class ImportHandle(BaseHandle): def _TryLoadStructFromStub(self, class_name: str, Gen): cache_key = class_name - if cache_key in self._struct_load_cache: + if cache_key in self._struct_Load_cache: return - self._struct_load_cache[cache_key] = True + self._struct_Load_cache[cache_key] = True import os, re ProjectRoot = self._find_project_root() @@ -1358,9 +1413,13 @@ class ImportHandle(BaseHandle): self._stub_cache.setdefault(short_name, []).append((full_name, struct_body, source_sha1)) if '.' in full_name: self._stub_cache.setdefault(full_name, []).append((full_name, struct_body, source_sha1)) - except Exception: - pass - + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _config_mode + if _config_mode == "strict": + raise + _vlog().warning(f"处理导入失败: {_e}", "Exception") + if class_name not in self._stub_cache: return @@ -1380,12 +1439,16 @@ class ImportHandle(BaseHandle): elem_types.append(et if et else ir.IntType(32)) try: st = Gen._get_or_create_struct(class_name, source_sha1=source_sha1, packed=is_packed) - if isinstance(st, ir.IdentifiedStructType) and (st.elements is None or len(st.elements) == 0): + if isinstance(st, ir.IdentifiedStructType) and st.is_opaque: st.set_body(*elem_types) if is_packed: Gen.class_packed.add(class_name) - except Exception: - pass + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _config_mode + if _config_mode == "strict": + raise + _vlog().warning(f"处理导入失败: {_e}", "Exception") stub_filename = source_sha1 + '.stub.ll' self._TryLoadClassMembersFromPyi(class_name, stub_filename, Gen) return @@ -1419,13 +1482,13 @@ class ImportHandle(BaseHandle): return source_sha1 = stub_filename.replace('.stub.ll', '') module_name = None - if hasattr(Gen, 'module_sha1_map'): - for mod_name, mod_sha1 in Gen.module_sha1_map.items(): + if hasattr(Gen, 'ModuleSha1Map'): + for mod_name, mod_sha1 in Gen.ModuleSha1Map.items(): if mod_sha1 == source_sha1 and '.' not in mod_name: module_name = mod_name break if module_name is None: - for mod_name, mod_sha1 in Gen.module_sha1_map.items(): + for mod_name, mod_sha1 in Gen.ModuleSha1Map.items(): if mod_sha1 == source_sha1: module_name = mod_name break @@ -1513,9 +1576,13 @@ class ImportHandle(BaseHandle): stub_ret = match.group(1).strip() stub_params = match.group(3).strip() self._stub_func_cache[stub_func_name] = (stub_ret, stub_params, '...' in stub_params, source_sha1) - except Exception: - pass - + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _config_mode + if _config_mode == "strict": + raise + _vlog().warning(f"处理导入失败: {_e}", "Exception") + if func_name not in self._stub_func_cache: return None @@ -1622,8 +1689,8 @@ class ImportHandle(BaseHandle): target_sha1 = os.path.basename(val).replace('.pyi', '') break if not target_sha1: - module_sha1_map = getattr(Gen, 'module_sha1_map', {}) - target_sha1 = module_sha1_map.get(module_name) + ModuleSha1Map = getattr(Gen, 'ModuleSha1Map', {}) + target_sha1 = ModuleSha1Map.get(module_name) if target_sha1: target_stub = f"{target_sha1}.stub.ll" @@ -1648,21 +1715,25 @@ class ImportHandle(BaseHandle): elif stripped.startswith('declare '): for m in re.finditer(r'%\"?([a-f0-9]{16})\.', stripped): needed_sha1s.add(m.group(1)) - except Exception: - pass - - preload_files = [] + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _config_mode + if _config_mode == "strict": + raise + _vlog().warning(f"处理导入失败: {_e}", "Exception") + + preLoad_files = [] for sha1 in needed_sha1s: dep_stub = f"{sha1}.stub.ll" if dep_stub in all_stub_files and dep_stub not in stub_files: - preload_files.append(dep_stub) + preLoad_files.append(dep_stub) - load_order = preload_files + stub_files + Load_order = preLoad_files + stub_files - for filename in load_order: + for filename in Load_order: stub_path = os.path.join(temp_dir, filename) source_sha1 = filename.replace('.stub.ll', '') - is_preload = filename in preload_files + is_preLoad = filename in preLoad_files try: with open(stub_path, 'r', encoding='utf-8') as f: content = f.read() @@ -1699,14 +1770,18 @@ class ImportHandle(BaseHandle): if isinstance(st, ir.IdentifiedStructType) and (st.elements is None or len(st.elements) == 0): try: st.set_body(*elem_types) - except Exception: - pass + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _config_mode + if _config_mode == "strict": + raise + _vlog().warning(f"处理导入失败: {_e}", "Exception") continue if not stripped.startswith('declare '): continue - if is_preload: + if is_preLoad: continue func_name_match = stripped.split('@', 1) @@ -1736,10 +1811,18 @@ class ImportHandle(BaseHandle): if '.' in func_name: short_name = func_name.split('.', 1)[1] Gen.functions[short_name] = func - except Exception: - pass - except Exception: - pass + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _config_mode + if _config_mode == "strict": + raise + _vlog().warning(f"处理导入失败: {_e}", "Exception") + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _config_mode + if _config_mode == "strict": + raise + _vlog().warning(f"处理导入失败: {_e}", "Exception") def _parse_llvm_declare(self, declare_line: str, Gen): """解析 LLVM declare 语句""" diff --git a/lib/core/Handles/HandlesMatch.py b/lib/core/Handles/HandlesMatch.py index 638feb8..f224008 100644 --- a/lib/core/Handles/HandlesMatch.py +++ b/lib/core/Handles/HandlesMatch.py @@ -1,333 +1,333 @@ -from __future__ import annotations -from typing import TYPE_CHECKING -if TYPE_CHECKING: - from lib.core.translator import Translator -from lib.core.Handles.HandlesBase import BaseHandle -import ast -import llvmlite.ir as ir - - -class MatchHandle(BaseHandle): - def _HandleMatchLlvm(self, Node): - Gen = self.Trans.LlvmGen - SubjectVal = self.HandleExprLlvm(Node.subject) - if not SubjectVal: - return - - IsRenumMatch = False - RenumName = None - SubjectPtr = None - if isinstance(Node.subject, ast.Name): - VarName = Node.subject.id - if VarName in self.Trans.SymbolTable: - TypeInfo = self.Trans.SymbolTable[VarName] - if getattr(TypeInfo, 'IsRenum', False): - IsRenumMatch = True - RenumName = TypeInfo.Name - SubjectPtr = Gen._load_var(VarName) - - if not IsRenumMatch: - for case in Node.cases: - if isinstance(case.pattern, ast.MatchClass): - cls_node = case.pattern.cls - VariantName = None - if isinstance(cls_node, ast.Name): - VariantName = cls_node.id - elif isinstance(cls_node, ast.Attribute): - VariantName = cls_node.attr - if VariantName and VariantName in self.Trans.SymbolTable: - SymInfo = self.Trans.SymbolTable[VariantName] - if getattr(SymInfo, 'IsEnumMember', False) and getattr(SymInfo, 'EnumName', None): - EnumName = SymInfo.EnumName - if EnumName in self.Trans.SymbolTable: - EnumInfo = self.Trans.SymbolTable[EnumName] - if getattr(EnumInfo, 'IsRenum', False): - IsRenumMatch = True - RenumName = EnumName - if SubjectPtr is None: - SubjectPtr = self.HandleExprLlvm(Node.subject) - break - - if IsRenumMatch and SubjectPtr: - self._HandleRenumMatchLlvm(Node, RenumName, SubjectPtr) - return - - if not isinstance(SubjectVal.type, ir.IntType): - try: - SubjectVal = Gen.builder.ptrtoint(SubjectVal, ir.IntType(64), name="match_subj") - SubjectVal = Gen.builder.trunc(SubjectVal, ir.IntType(32), name="match_subj_i32") - except Exception: # 回退:ptrtoint 失败时直接返回 - return - SwitchIntType = SubjectVal.type - DefaultBB = Gen.func.append_basic_block(name="match.default") - AfterBB = Gen.func.append_basic_block(name="match.end") - CaseBBs = [] - CaseValues = [] - HasDefault = False - HasNoBreak = [] - for i, case in enumerate(Node.cases): - pattern = case.pattern - if isinstance(pattern, ast.MatchValue): - Val = self.HandleExprLlvm(pattern.value) - if Val: - if isinstance(Val.type, ir.IntType): - if Val.type != SwitchIntType: - if Val.type.width > SwitchIntType.width: - CaseVal = ir.Constant(SwitchIntType, Val.constant & ((1 << SwitchIntType.width) - 1)) - else: - CaseVal = ir.Constant(SwitchIntType, Val.constant) - else: - CaseVal = Val - else: - try: - CaseVal = Gen.builder.ptrtoint(Val, SwitchIntType, name=f"case_val_{i}") - except Exception: # 回退:ptrtoint 失败时设默认值 0 - CaseVal = ir.Constant(SwitchIntType, 0) - CaseValues.append(CaseVal) - CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}")) - elif isinstance(pattern, ast.MatchOr): - for j, SubPattern in enumerate(pattern.patterns): - if isinstance(SubPattern, ast.MatchValue): - Val = self.HandleExprLlvm(SubPattern.value) - if Val: - if isinstance(Val.type, ir.IntType): - if Val.type != SwitchIntType: - if Val.type.width > SwitchIntType.width: - CaseVal = ir.Constant(SwitchIntType, Val.constant & ((1 << SwitchIntType.width) - 1)) - else: - CaseVal = ir.Constant(SwitchIntType, Val.constant) - else: - CaseVal = Val - else: - try: - CaseVal = Gen.builder.ptrtoint(Val, SwitchIntType, name=f"case_val_{i}_{j}") - except Exception: # 回退:ptrtoint 失败时设默认值 0 - CaseVal = ir.Constant(SwitchIntType, 0) - CaseValues.append(CaseVal) - CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}_{j}")) - elif isinstance(pattern, ast.MatchSingleton): - if pattern.value is None: - CaseValues.append(ir.Constant(SwitchIntType, 0)) - CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}")) - elif isinstance(pattern, ast.MatchAs): - if pattern.pattern is None: - HasDefault = True - CaseBBs.append(DefaultBB) - elif isinstance(pattern, ast.MatchSequence): - HasDefault = True - CaseBBs.append(DefaultBB) - def _HasNoBreak(stmts): - for stmt in stmts: - if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Call): - if isinstance(stmt.value.func, ast.Attribute): - if (isinstance(stmt.value.func.value, ast.Name) and - stmt.value.func.value.id == 'c' and - stmt.value.func.attr == 'NoBreak'): - return True - if getattr(stmt, 'body', None) and isinstance(stmt.body, list): - if _HasNoBreak(stmt.body): - return True - if getattr(stmt, 'orelse', None): - if isinstance(stmt.orelse, list) and _HasNoBreak(stmt.orelse): - return True - return False - HasNoBreak.append(_HasNoBreak(case.body) if case.body else False) - if not HasDefault: - CaseBBs.append(DefaultBB) - SwitchCases = [(val, bb) for val, bb in zip(CaseValues, CaseBBs) if bb != DefaultBB] - switch_instr = Gen.builder.switch(SubjectVal, DefaultBB) - for val, bb in SwitchCases: - switch_instr.add_case(val, bb) - CaseIdx = 0 - for i, case in enumerate(Node.cases): - pattern = case.pattern - if isinstance(pattern, ast.MatchOr): - NumSubCases = len(pattern.patterns) - for j in range(NumSubCases): - if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB: - Gen.builder.position_at_start(CaseBBs[CaseIdx]) - self.HandleBodyLlvm(case.body) - if not Gen.builder.block.is_terminated: - if not HasNoBreak[i]: - Gen.builder.branch(AfterBB) - CaseIdx += 1 - elif isinstance(pattern, (ast.MatchValue, ast.MatchSingleton)): - if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB: - Gen.builder.position_at_start(CaseBBs[CaseIdx]) - self.HandleBodyLlvm(case.body) - if not Gen.builder.block.is_terminated: - if not HasNoBreak[i]: - Gen.builder.branch(AfterBB) - CaseIdx += 1 - elif isinstance(pattern, ast.MatchAs): - if pattern.pattern is None: - Gen.builder.position_at_start(DefaultBB) - self.HandleBodyLlvm(case.body) - if not Gen.builder.block.is_terminated: - if not HasNoBreak[i]: - Gen.builder.branch(AfterBB) - CaseIdx += 1 - elif isinstance(pattern, ast.MatchSequence): - Gen.builder.position_at_start(DefaultBB) - self.HandleBodyLlvm(case.body) - if not Gen.builder.block.is_terminated: - if not HasNoBreak[i]: - Gen.builder.branch(AfterBB) - CaseIdx += 1 - if not HasDefault: - Gen.builder.position_at_start(DefaultBB) - Gen.builder.branch(AfterBB) - elif not any(isinstance(c.pattern, ast.MatchAs) and c.pattern.pattern is None for c in Node.cases) and not any(isinstance(c.pattern, ast.MatchSequence) for c in Node.cases): - Gen.builder.position_at_start(DefaultBB) - Gen.builder.branch(AfterBB) - Gen.builder.position_at_start(AfterBB) - - def _HandleRenumMatchLlvm(self, Node, RenumName, SubjectPtr): - Gen = self.Trans.LlvmGen - if isinstance(SubjectPtr.type, ir.PointerType) and isinstance(SubjectPtr.type.pointee, ir.PointerType): - SubjectPtr = Gen._load(SubjectPtr, name="load_match_subj") - tag_ptr = Gen.builder.gep(SubjectPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="match_tag_ptr") - TagVal = Gen._load(tag_ptr, name="match_tag_val") - DefaultBB = Gen.func.append_basic_block(name="match.default") - AfterBB = Gen.func.append_basic_block(name="match.end") - CaseBBs = [] - CaseValues = [] - CaseBindings = [] - HasDefault = False - HasNoBreak = [] - for i, case in enumerate(Node.cases): - pattern = case.pattern - bindings = [] - if isinstance(pattern, ast.MatchClass): - cls_node = pattern.cls - VariantName = None - if isinstance(cls_node, ast.Name): - VariantName = cls_node.id - elif isinstance(cls_node, ast.Attribute): - VariantName = cls_node.attr - if VariantName: - TagValue = None - if VariantName in self.Trans.SymbolTable: - SymInfo = self.Trans.SymbolTable[VariantName] - if getattr(SymInfo, 'IsEnumMember', False): - TagValue = SymInfo.value - if TagValue is not None: - CaseValues.append(ir.Constant(ir.IntType(32), TagValue)) - CaseBB = Gen.func.append_basic_block(name=f"match.case_{VariantName}") - CaseBBs.append(CaseBB) - NestedStructName = f"{RenumName}_{VariantName}" - if NestedStructName in Gen.structs: - members = Gen.class_members.get(NestedStructName, []) - payload_members = [(n, t) for n, t in members if n != '__tag'] - for j, sub_pat in enumerate(pattern.patterns): - if isinstance(sub_pat, ast.MatchAs) and sub_pat.name and j < len(payload_members): - bindings.append((sub_pat.name, payload_members[j][0], payload_members[j][1], j)) - CaseBindings.append(bindings) - else: - CaseValues.append(ir.Constant(ir.IntType(32), 0)) - CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}")) - CaseBindings.append([]) - elif isinstance(pattern, ast.MatchValue): - Val = self.HandleExprLlvm(pattern.value) - if Val: - if isinstance(Val.type, ir.IntType): - CaseVal = Val - else: - try: - CaseVal = Gen.builder.ptrtoint(Val, ir.IntType(32), name=f"case_val_{i}") - except Exception: # 回退:ptrtoint 失败时设默认值 0 - CaseVal = ir.Constant(ir.IntType(32), 0) - CaseValues.append(CaseVal) - CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}")) - CaseBindings.append([]) - elif isinstance(pattern, ast.MatchAs): - if pattern.pattern is None: - HasDefault = True - CaseBBs.append(DefaultBB) - CaseBindings.append([]) - elif isinstance(pattern, ast.MatchSequence): - HasDefault = True - CaseBBs.append(DefaultBB) - CaseBindings.append([]) - def _HasNoBreak(stmts): - for stmt in stmts: - if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Call): - if isinstance(stmt.value.func, ast.Attribute): - if (isinstance(stmt.value.func.value, ast.Name) and - stmt.value.func.value.id == 'c' and - stmt.value.func.attr == 'NoBreak'): - return True - if getattr(stmt, 'body', None) and isinstance(stmt.body, list): - if _HasNoBreak(stmt.body): - return True - if getattr(stmt, 'orelse', None): - if isinstance(stmt.orelse, list) and _HasNoBreak(stmt.orelse): - return True - return False - HasNoBreak.append(_HasNoBreak(case.body) if case.body else False) - if not HasDefault: - CaseBBs.append(DefaultBB) - SwitchCases = [(val, bb) for val, bb in zip(CaseValues, CaseBBs) if bb != DefaultBB] - switch_instr = Gen.builder.switch(TagVal, DefaultBB) - for val, bb in SwitchCases: - switch_instr.add_case(val, bb) - CaseIdx = 0 - for i, case in enumerate(Node.cases): - pattern = case.pattern - if isinstance(pattern, ast.MatchClass): - if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB: - Gen.builder.position_at_start(CaseBBs[CaseIdx]) - bindings = CaseBindings[CaseIdx] if CaseIdx < len(CaseBindings) else [] - cls_node = pattern.cls - VariantName = None - if isinstance(cls_node, ast.Name): - VariantName = cls_node.id - elif isinstance(cls_node, ast.Attribute): - VariantName = cls_node.attr - if VariantName: - NestedStructName = f"{RenumName}_{VariantName}" - if NestedStructName in Gen.structs: - NestedStructType = Gen.structs[NestedStructName] - NestedStructPtrType = ir.PointerType(NestedStructType) - variant_ptr = Gen.builder.bitcast(SubjectPtr, NestedStructPtrType, name=f"match_cast_{VariantName}") - for bind_name, member_name, member_type, member_idx in bindings: - elem_ptr = Gen.builder.gep(variant_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), member_idx + 1)], name=f"match_{bind_name}") - Gen.variables[bind_name] = elem_ptr - self.HandleBodyLlvm(case.body) - for bind_name, _, _, _ in bindings: - if bind_name in Gen.variables: - del Gen.variables[bind_name] - if not Gen.builder.block.is_terminated: - if not HasNoBreak[i]: - Gen.builder.branch(AfterBB) - CaseIdx += 1 - elif isinstance(pattern, ast.MatchValue): - if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB: - Gen.builder.position_at_start(CaseBBs[CaseIdx]) - self.HandleBodyLlvm(case.body) - if not Gen.builder.block.is_terminated: - if not HasNoBreak[i]: - Gen.builder.branch(AfterBB) - CaseIdx += 1 - elif isinstance(pattern, ast.MatchAs): - if pattern.pattern is None: - Gen.builder.position_at_start(DefaultBB) - self.HandleBodyLlvm(case.body) - if not Gen.builder.block.is_terminated: - if not HasNoBreak[i]: - Gen.builder.branch(AfterBB) - CaseIdx += 1 - elif isinstance(pattern, ast.MatchSequence): - Gen.builder.position_at_start(DefaultBB) - self.HandleBodyLlvm(case.body) - if not Gen.builder.block.is_terminated: - if not HasNoBreak[i]: - Gen.builder.branch(AfterBB) - CaseIdx += 1 - if not HasDefault: - Gen.builder.position_at_start(DefaultBB) - Gen.builder.branch(AfterBB) - elif not any(isinstance(c.pattern, ast.MatchAs) and c.pattern.pattern is None for c in Node.cases) and not any(isinstance(c.pattern, ast.MatchSequence) for c in Node.cases): - Gen.builder.position_at_start(DefaultBB) - Gen.builder.branch(AfterBB) - Gen.builder.position_at_start(AfterBB) +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle +import ast +import llvmlite.ir as ir + + +class MatchHandle(BaseHandle): + def _HandleMatchLlvm(self, Node): + Gen = self.Trans.LlvmGen + SubjectVal = self.HandleExprLlvm(Node.subject) + if not SubjectVal: + return + + IsRenumMatch = False + RenumName = None + SubjectPtr = None + if isinstance(Node.subject, ast.Name): + VarName = Node.subject.id + if VarName in self.Trans.SymbolTable: + TypeInfo = self.Trans.SymbolTable[VarName] + if getattr(TypeInfo, 'IsRenum', False): + IsRenumMatch = True + RenumName = TypeInfo.Name + SubjectPtr = Gen._loadVar(VarName) + + if not IsRenumMatch: + for case in Node.cases: + if isinstance(case.pattern, ast.MatchClass): + cls_node = case.pattern.cls + VariantName = None + if isinstance(cls_node, ast.Name): + VariantName = cls_node.id + elif isinstance(cls_node, ast.Attribute): + VariantName = cls_node.attr + if VariantName and VariantName in self.Trans.SymbolTable: + SymInfo = self.Trans.SymbolTable[VariantName] + if getattr(SymInfo, 'IsEnumMember', False) and getattr(SymInfo, 'EnumName', None): + EnumName = SymInfo.EnumName + if EnumName in self.Trans.SymbolTable: + EnumInfo = self.Trans.SymbolTable[EnumName] + if getattr(EnumInfo, 'IsRenum', False): + IsRenumMatch = True + RenumName = EnumName + if SubjectPtr is None: + SubjectPtr = self.HandleExprLlvm(Node.subject) + break + + if IsRenumMatch and SubjectPtr: + self._HandleRenumMatchLlvm(Node, RenumName, SubjectPtr) + return + + if not isinstance(SubjectVal.type, ir.IntType): + try: + SubjectVal = Gen.builder.ptrtoint(SubjectVal, ir.IntType(64), name="match_subj") + SubjectVal = Gen.builder.trunc(SubjectVal, ir.IntType(32), name="match_subj_i32") + except Exception: # 回退:ptrtoint 失败时直接返回 + return + SwitchIntType = SubjectVal.type + DefaultBB = Gen.func.append_basic_block(name="match.default") + AfterBB = Gen.func.append_basic_block(name="match.end") + CaseBBs = [] + CaseValues = [] + HasDefault = False + HasNoBreak = [] + for i, case in enumerate(Node.cases): + pattern = case.pattern + if isinstance(pattern, ast.MatchValue): + Val = self.HandleExprLlvm(pattern.value) + if Val: + if isinstance(Val.type, ir.IntType): + if Val.type != SwitchIntType: + if Val.type.width > SwitchIntType.width: + CaseVal = ir.Constant(SwitchIntType, Val.constant & ((1 << SwitchIntType.width) - 1)) + else: + CaseVal = ir.Constant(SwitchIntType, Val.constant) + else: + CaseVal = Val + else: + try: + CaseVal = Gen.builder.ptrtoint(Val, SwitchIntType, name=f"case_val_{i}") + except Exception: # 回退:ptrtoint 失败时设默认值 0 + CaseVal = ir.Constant(SwitchIntType, 0) + CaseValues.append(CaseVal) + CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}")) + elif isinstance(pattern, ast.MatchOr): + for j, SubPattern in enumerate(pattern.patterns): + if isinstance(SubPattern, ast.MatchValue): + Val = self.HandleExprLlvm(SubPattern.value) + if Val: + if isinstance(Val.type, ir.IntType): + if Val.type != SwitchIntType: + if Val.type.width > SwitchIntType.width: + CaseVal = ir.Constant(SwitchIntType, Val.constant & ((1 << SwitchIntType.width) - 1)) + else: + CaseVal = ir.Constant(SwitchIntType, Val.constant) + else: + CaseVal = Val + else: + try: + CaseVal = Gen.builder.ptrtoint(Val, SwitchIntType, name=f"case_val_{i}_{j}") + except Exception: # 回退:ptrtoint 失败时设默认值 0 + CaseVal = ir.Constant(SwitchIntType, 0) + CaseValues.append(CaseVal) + CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}_{j}")) + elif isinstance(pattern, ast.MatchSingleton): + if pattern.value is None: + CaseValues.append(ir.Constant(SwitchIntType, 0)) + CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}")) + elif isinstance(pattern, ast.MatchAs): + if pattern.pattern is None: + HasDefault = True + CaseBBs.append(DefaultBB) + elif isinstance(pattern, ast.MatchSequence): + HasDefault = True + CaseBBs.append(DefaultBB) + def _HasNoBreak(stmts): + for stmt in stmts: + if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Call): + if isinstance(stmt.value.func, ast.Attribute): + if (isinstance(stmt.value.func.value, ast.Name) and + stmt.value.func.value.id == 'c' and + stmt.value.func.attr == 'NoBreak'): + return True + if getattr(stmt, 'body', None) and isinstance(stmt.body, list): + if _HasNoBreak(stmt.body): + return True + if getattr(stmt, 'orelse', None): + if isinstance(stmt.orelse, list) and _HasNoBreak(stmt.orelse): + return True + return False + HasNoBreak.append(_HasNoBreak(case.body) if case.body else False) + if not HasDefault: + CaseBBs.append(DefaultBB) + SwitchCases = [(val, bb) for val, bb in zip(CaseValues, CaseBBs) if bb != DefaultBB] + switch_instr = Gen.builder.switch(SubjectVal, DefaultBB) + for val, bb in SwitchCases: + switch_instr.add_case(val, bb) + CaseIdx = 0 + for i, case in enumerate(Node.cases): + pattern = case.pattern + if isinstance(pattern, ast.MatchOr): + NumSubCases = len(pattern.patterns) + for j in range(NumSubCases): + if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB: + Gen.builder.position_at_start(CaseBBs[CaseIdx]) + self.HandleBodyLlvm(case.body) + if not Gen.builder.block.is_terminated: + if not HasNoBreak[i]: + Gen.builder.branch(AfterBB) + CaseIdx += 1 + elif isinstance(pattern, (ast.MatchValue, ast.MatchSingleton)): + if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB: + Gen.builder.position_at_start(CaseBBs[CaseIdx]) + self.HandleBodyLlvm(case.body) + if not Gen.builder.block.is_terminated: + if not HasNoBreak[i]: + Gen.builder.branch(AfterBB) + CaseIdx += 1 + elif isinstance(pattern, ast.MatchAs): + if pattern.pattern is None: + Gen.builder.position_at_start(DefaultBB) + self.HandleBodyLlvm(case.body) + if not Gen.builder.block.is_terminated: + if not HasNoBreak[i]: + Gen.builder.branch(AfterBB) + CaseIdx += 1 + elif isinstance(pattern, ast.MatchSequence): + Gen.builder.position_at_start(DefaultBB) + self.HandleBodyLlvm(case.body) + if not Gen.builder.block.is_terminated: + if not HasNoBreak[i]: + Gen.builder.branch(AfterBB) + CaseIdx += 1 + if not HasDefault: + Gen.builder.position_at_start(DefaultBB) + Gen.builder.branch(AfterBB) + elif not any(isinstance(c.pattern, ast.MatchAs) and c.pattern.pattern is None for c in Node.cases) and not any(isinstance(c.pattern, ast.MatchSequence) for c in Node.cases): + Gen.builder.position_at_start(DefaultBB) + Gen.builder.branch(AfterBB) + Gen.builder.position_at_start(AfterBB) + + def _HandleRenumMatchLlvm(self, Node, RenumName, SubjectPtr): + Gen = self.Trans.LlvmGen + if isinstance(SubjectPtr.type, ir.PointerType) and isinstance(SubjectPtr.type.pointee, ir.PointerType): + SubjectPtr = Gen._load(SubjectPtr, name="Load_match_subj") + tag_ptr = Gen.builder.gep(SubjectPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="match_tag_ptr") + TagVal = Gen._load(tag_ptr, name="match_tag_val") + DefaultBB = Gen.func.append_basic_block(name="match.default") + AfterBB = Gen.func.append_basic_block(name="match.end") + CaseBBs = [] + CaseValues = [] + CaseBindings = [] + HasDefault = False + HasNoBreak = [] + for i, case in enumerate(Node.cases): + pattern = case.pattern + bindings = [] + if isinstance(pattern, ast.MatchClass): + cls_node = pattern.cls + VariantName = None + if isinstance(cls_node, ast.Name): + VariantName = cls_node.id + elif isinstance(cls_node, ast.Attribute): + VariantName = cls_node.attr + if VariantName: + TagValue = None + if VariantName in self.Trans.SymbolTable: + SymInfo = self.Trans.SymbolTable[VariantName] + if getattr(SymInfo, 'IsEnumMember', False): + TagValue = SymInfo.value + if TagValue is not None: + CaseValues.append(ir.Constant(ir.IntType(32), TagValue)) + CaseBB = Gen.func.append_basic_block(name=f"match.case_{VariantName}") + CaseBBs.append(CaseBB) + NestedStructName = f"{RenumName}_{VariantName}" + if NestedStructName in Gen.structs: + members = Gen.class_members.get(NestedStructName, []) + payLoad_members = [(n, t) for n, t in members if n != '__tag'] + for j, sub_pat in enumerate(pattern.patterns): + if isinstance(sub_pat, ast.MatchAs) and sub_pat.name and j < len(payLoad_members): + bindings.append((sub_pat.name, payLoad_members[j][0], payLoad_members[j][1], j)) + CaseBindings.append(bindings) + else: + CaseValues.append(ir.Constant(ir.IntType(32), 0)) + CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}")) + CaseBindings.append([]) + elif isinstance(pattern, ast.MatchValue): + Val = self.HandleExprLlvm(pattern.value) + if Val: + if isinstance(Val.type, ir.IntType): + CaseVal = Val + else: + try: + CaseVal = Gen.builder.ptrtoint(Val, ir.IntType(32), name=f"case_val_{i}") + except Exception: # 回退:ptrtoint 失败时设默认值 0 + CaseVal = ir.Constant(ir.IntType(32), 0) + CaseValues.append(CaseVal) + CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}")) + CaseBindings.append([]) + elif isinstance(pattern, ast.MatchAs): + if pattern.pattern is None: + HasDefault = True + CaseBBs.append(DefaultBB) + CaseBindings.append([]) + elif isinstance(pattern, ast.MatchSequence): + HasDefault = True + CaseBBs.append(DefaultBB) + CaseBindings.append([]) + def _HasNoBreak(stmts): + for stmt in stmts: + if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Call): + if isinstance(stmt.value.func, ast.Attribute): + if (isinstance(stmt.value.func.value, ast.Name) and + stmt.value.func.value.id == 'c' and + stmt.value.func.attr == 'NoBreak'): + return True + if getattr(stmt, 'body', None) and isinstance(stmt.body, list): + if _HasNoBreak(stmt.body): + return True + if getattr(stmt, 'orelse', None): + if isinstance(stmt.orelse, list) and _HasNoBreak(stmt.orelse): + return True + return False + HasNoBreak.append(_HasNoBreak(case.body) if case.body else False) + if not HasDefault: + CaseBBs.append(DefaultBB) + SwitchCases = [(val, bb) for val, bb in zip(CaseValues, CaseBBs) if bb != DefaultBB] + switch_instr = Gen.builder.switch(TagVal, DefaultBB) + for val, bb in SwitchCases: + switch_instr.add_case(val, bb) + CaseIdx = 0 + for i, case in enumerate(Node.cases): + pattern = case.pattern + if isinstance(pattern, ast.MatchClass): + if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB: + Gen.builder.position_at_start(CaseBBs[CaseIdx]) + bindings = CaseBindings[CaseIdx] if CaseIdx < len(CaseBindings) else [] + cls_node = pattern.cls + VariantName = None + if isinstance(cls_node, ast.Name): + VariantName = cls_node.id + elif isinstance(cls_node, ast.Attribute): + VariantName = cls_node.attr + if VariantName: + NestedStructName = f"{RenumName}_{VariantName}" + if NestedStructName in Gen.structs: + NestedStructType = Gen.structs[NestedStructName] + NestedStructPtrType = ir.PointerType(NestedStructType) + variant_ptr = Gen.builder.bitcast(SubjectPtr, NestedStructPtrType, name=f"match_cast_{VariantName}") + for bind_name, member_name, member_type, member_idx in bindings: + elem_ptr = Gen.builder.gep(variant_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), member_idx + 1)], name=f"match_{bind_name}") + Gen.variables[bind_name] = elem_ptr + self.HandleBodyLlvm(case.body) + for bind_name, _, _, _ in bindings: + if bind_name in Gen.variables: + del Gen.variables[bind_name] + if not Gen.builder.block.is_terminated: + if not HasNoBreak[i]: + Gen.builder.branch(AfterBB) + CaseIdx += 1 + elif isinstance(pattern, ast.MatchValue): + if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB: + Gen.builder.position_at_start(CaseBBs[CaseIdx]) + self.HandleBodyLlvm(case.body) + if not Gen.builder.block.is_terminated: + if not HasNoBreak[i]: + Gen.builder.branch(AfterBB) + CaseIdx += 1 + elif isinstance(pattern, ast.MatchAs): + if pattern.pattern is None: + Gen.builder.position_at_start(DefaultBB) + self.HandleBodyLlvm(case.body) + if not Gen.builder.block.is_terminated: + if not HasNoBreak[i]: + Gen.builder.branch(AfterBB) + CaseIdx += 1 + elif isinstance(pattern, ast.MatchSequence): + Gen.builder.position_at_start(DefaultBB) + self.HandleBodyLlvm(case.body) + if not Gen.builder.block.is_terminated: + if not HasNoBreak[i]: + Gen.builder.branch(AfterBB) + CaseIdx += 1 + if not HasDefault: + Gen.builder.position_at_start(DefaultBB) + Gen.builder.branch(AfterBB) + elif not any(isinstance(c.pattern, ast.MatchAs) and c.pattern.pattern is None for c in Node.cases) and not any(isinstance(c.pattern, ast.MatchSequence) for c in Node.cases): + Gen.builder.position_at_start(DefaultBB) + Gen.builder.branch(AfterBB) + Gen.builder.position_at_start(AfterBB) diff --git a/lib/core/Handles/HandlesRaise.py b/lib/core/Handles/HandlesRaise.py index c1ecef3..b48ad65 100644 --- a/lib/core/Handles/HandlesRaise.py +++ b/lib/core/Handles/HandlesRaise.py @@ -1,135 +1,135 @@ -from __future__ import annotations -from typing import TYPE_CHECKING -if TYPE_CHECKING: - from lib.core.translator import Translator -from lib.core.Handles.HandlesBase import BaseHandle, EXCEPTION_CODE_MAP -import ast -import llvmlite.ir as ir - - -class RaiseHandle(BaseHandle): - def _get_exception_code(self, ExcName): - if ExcName in EXCEPTION_CODE_MAP: - return EXCEPTION_CODE_MAP[ExcName] - if ExcName in self.Trans.exception_registry: - return self.Trans.exception_registry[ExcName] - return 1 - - def _HandleRaiseLlvm(self, Node): - Gen = self.Trans.LlvmGen - exc_val = ir.Constant(ir.IntType(32), 1) - exc_msg = None - IsStopIteration = False - if Node.exc: - if isinstance(Node.exc, ast.Constant) and isinstance(Node.exc.value, int): - exc_val = ir.Constant(ir.IntType(32), Node.exc.value) - elif isinstance(Node.exc, ast.Name): - ExcName = Node.exc.id - if ExcName == 'StopIteration': - IsStopIteration = True - exc_val = ir.Constant(ir.IntType(32), self._get_exception_code(ExcName)) - elif isinstance(Node.exc, ast.Call) and isinstance(Node.exc.func, ast.Name): - ExcName = Node.exc.func.id - if ExcName == 'StopIteration': - IsStopIteration = True - exc_val = ir.Constant(ir.IntType(32), self._get_exception_code(ExcName)) - if Node.exc.args: - first_arg = Node.exc.args[0] - if isinstance(first_arg, ast.Constant) and isinstance(first_arg.value, str): - exc_msg = self.HandleExprLlvm(first_arg) - elif isinstance(first_arg, (ast.Name, ast.Call, ast.Attribute)): - arg_val = self.HandleExprLlvm(first_arg) - if arg_val: - if isinstance(arg_val.type, ir.PointerType): - if self._is_char_pointer(arg_val): - exc_msg = arg_val - else: - try: - exc_msg = Gen.builder.bitcast(arg_val, ir.PointerType(ir.IntType(8)), name="exc_msg_cast") - except Exception as _e: - if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": - self.Trans.LogWarning(f"异常被忽略: {_e}") - else: - try: - exc_msg = Gen.builder.inttoptr(arg_val, ir.PointerType(ir.IntType(8)), name="exc_msg_ptr") - except Exception as _e: - if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": - self.Trans.LogWarning(f"异常被忽略: {_e}") - else: - val = self.HandleExprLlvm(Node.exc) - if val: - if isinstance(val.type, ir.IntType): - if val.type.width != 32: - try: - val = Gen.builder.trunc(val, ir.IntType(32), name="exc_trunc") - except Exception: # 回退:trunc 失败时设默认值 1 - val = ir.Constant(ir.IntType(32), 1) - exc_val = val - else: - try: - val = Gen.builder.ptrtoint(val, ir.IntType(32), name="exc_ptr2int") - exc_val = val - except Exception as _e: - if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": - self.Trans.LogWarning(f"异常被忽略: {_e}") - if IsStopIteration: - if Gen._stop_iter_flag_param is not None: - Gen.builder.store(ir.Constant(ir.IntType(1), 1), Gen._stop_iter_flag_param) - if Gen.func and Gen.func.type.pointee.return_type != ir.VoidType(): - ret_type = Gen.func.type.pointee.return_type - Gen.builder.ret(ir.Constant(ret_type, 0)) - else: - Gen.builder.ret_void() - return - if Gen.eh_except_block_stack: - ExceptBB, EndBB, exception_code, eh_message = Gen.eh_except_block_stack[-1] - Gen._store(exc_val, exception_code) - if exc_msg: - Gen._store(exc_msg, eh_message) - else: - null_ptr = ir.Constant(ir.PointerType(ir.IntType(8)), None) - Gen._store(null_ptr, eh_message) - if Gen.func and ExceptBB and ExceptBB.function is Gen.func: - Gen.builder.branch(ExceptBB) - else: - eh_msg_arg = None - eh_code_arg = None - if Gen.func: - for arg in Gen.func.args: - if arg.name == '__eh_msg_out__': - eh_msg_arg = arg - elif arg.name == '__eh_code_out__': - eh_code_arg = arg - if eh_msg_arg is not None: - if exc_msg: - Gen.builder.store(exc_msg, eh_msg_arg) - else: - null_ptr = ir.Constant(ir.PointerType(ir.IntType(8)), None) - Gen.builder.store(null_ptr, eh_msg_arg) - if eh_code_arg is not None: - Gen.builder.store(exc_val, eh_code_arg) - if Gen.func and Gen.func.type.pointee.return_type == ir.IntType(32): - Gen.builder.ret(ir.Constant(ir.IntType(32), 1)) - else: - Gen.builder.ret_void() - else: - eh_msg_arg = None - eh_code_arg = None - if Gen.func: - for arg in Gen.func.args: - if arg.name == '__eh_msg_out__': - eh_msg_arg = arg - elif arg.name == '__eh_code_out__': - eh_code_arg = arg - if eh_msg_arg is not None: - if exc_msg: - Gen.builder.store(exc_msg, eh_msg_arg) - else: - null_ptr = ir.Constant(ir.PointerType(ir.IntType(8)), None) - Gen.builder.store(null_ptr, eh_msg_arg) - if eh_code_arg is not None: - Gen.builder.store(exc_val, eh_code_arg) - if Gen.func and Gen.func.type.pointee.return_type == ir.IntType(32): - Gen.builder.ret(ir.Constant(ir.IntType(32), 1)) - else: +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle, EXCEPTION_CODE_MAP +import ast +import llvmlite.ir as ir + + +class RaiseHandle(BaseHandle): + def _get_exception_code(self, ExcName): + if ExcName in EXCEPTION_CODE_MAP: + return EXCEPTION_CODE_MAP[ExcName] + if ExcName in self.Trans.exception_registry: + return self.Trans.exception_registry[ExcName] + return 1 + + def _HandleRaiseLlvm(self, Node): + Gen = self.Trans.LlvmGen + exc_val = ir.Constant(ir.IntType(32), 1) + exc_msg = None + IsStopIteration = False + if Node.exc: + if isinstance(Node.exc, ast.Constant) and isinstance(Node.exc.value, int): + exc_val = ir.Constant(ir.IntType(32), Node.exc.value) + elif isinstance(Node.exc, ast.Name): + ExcName = Node.exc.id + if ExcName == 'StopIteration': + IsStopIteration = True + exc_val = ir.Constant(ir.IntType(32), self._get_exception_code(ExcName)) + elif isinstance(Node.exc, ast.Call) and isinstance(Node.exc.func, ast.Name): + ExcName = Node.exc.func.id + if ExcName == 'StopIteration': + IsStopIteration = True + exc_val = ir.Constant(ir.IntType(32), self._get_exception_code(ExcName)) + if Node.exc.args: + first_arg = Node.exc.args[0] + if isinstance(first_arg, ast.Constant) and isinstance(first_arg.value, str): + exc_msg = self.HandleExprLlvm(first_arg) + elif isinstance(first_arg, (ast.Name, ast.Call, ast.Attribute)): + arg_val = self.HandleExprLlvm(first_arg) + if arg_val: + if isinstance(arg_val.type, ir.PointerType): + if self._is_char_pointer(arg_val): + exc_msg = arg_val + else: + try: + exc_msg = Gen.builder.bitcast(arg_val, ir.PointerType(ir.IntType(8)), name="exc_msg_cast") + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + self.Trans.LogWarning(f"异常被忽略: {_e}") + else: + try: + exc_msg = Gen.builder.inttoptr(arg_val, ir.PointerType(ir.IntType(8)), name="exc_msg_ptr") + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + self.Trans.LogWarning(f"异常被忽略: {_e}") + else: + val = self.HandleExprLlvm(Node.exc) + if val: + if isinstance(val.type, ir.IntType): + if val.type.width != 32: + try: + val = Gen.builder.trunc(val, ir.IntType(32), name="exc_trunc") + except Exception: # 回退:trunc 失败时设默认值 1 + val = ir.Constant(ir.IntType(32), 1) + exc_val = val + else: + try: + val = Gen.builder.ptrtoint(val, ir.IntType(32), name="exc_ptr2int") + exc_val = val + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + self.Trans.LogWarning(f"异常被忽略: {_e}") + if IsStopIteration: + if Gen._stop_iter_flag_param is not None: + Gen.builder.store(ir.Constant(ir.IntType(1), 1), Gen._stop_iter_flag_param) + if Gen.func and Gen.func.type.pointee.return_type != ir.VoidType(): + ret_type = Gen.func.type.pointee.return_type + Gen.builder.ret(ir.Constant(ret_type, 0)) + else: + Gen.builder.ret_void() + return + if Gen.eh_except_block_stack: + ExceptBB, EndBB, exception_code, eh_message = Gen.eh_except_block_stack[-1] + Gen._store(exc_val, exception_code) + if exc_msg: + Gen._store(exc_msg, eh_message) + else: + null_ptr = ir.Constant(ir.PointerType(ir.IntType(8)), None) + Gen._store(null_ptr, eh_message) + if Gen.func and ExceptBB and ExceptBB.function is Gen.func: + Gen.builder.branch(ExceptBB) + else: + eh_msg_arg = None + eh_code_arg = None + if Gen.func: + for arg in Gen.func.args: + if arg.name == '__eh_msg_out__': + eh_msg_arg = arg + elif arg.name == '__eh_code_out__': + eh_code_arg = arg + if eh_msg_arg is not None: + if exc_msg: + Gen.builder.store(exc_msg, eh_msg_arg) + else: + null_ptr = ir.Constant(ir.PointerType(ir.IntType(8)), None) + Gen.builder.store(null_ptr, eh_msg_arg) + if eh_code_arg is not None: + Gen.builder.store(exc_val, eh_code_arg) + if Gen.func and Gen.func.type.pointee.return_type == ir.IntType(32): + Gen.builder.ret(ir.Constant(ir.IntType(32), 1)) + else: + Gen.builder.ret_void() + else: + eh_msg_arg = None + eh_code_arg = None + if Gen.func: + for arg in Gen.func.args: + if arg.name == '__eh_msg_out__': + eh_msg_arg = arg + elif arg.name == '__eh_code_out__': + eh_code_arg = arg + if eh_msg_arg is not None: + if exc_msg: + Gen.builder.store(exc_msg, eh_msg_arg) + else: + null_ptr = ir.Constant(ir.PointerType(ir.IntType(8)), None) + Gen.builder.store(null_ptr, eh_msg_arg) + if eh_code_arg is not None: + Gen.builder.store(exc_val, eh_code_arg) + if Gen.func and Gen.func.type.pointee.return_type == ir.IntType(32): + Gen.builder.ret(ir.Constant(ir.IntType(32), 1)) + else: Gen.builder.ret_void() \ No newline at end of file diff --git a/lib/core/Handles/HandlesSpecialCall.py b/lib/core/Handles/HandlesSpecialCall.py index f2d57be..29520a1 100644 --- a/lib/core/Handles/HandlesSpecialCall.py +++ b/lib/core/Handles/HandlesSpecialCall.py @@ -1,354 +1,358 @@ -from __future__ import annotations -from typing import TYPE_CHECKING -if TYPE_CHECKING: - from lib.core.translator import Translator -from lib.core.Handles.HandlesBase import BaseHandle -import ast -import llvmlite.ir as ir - - -class CSpecialCallHandle(BaseHandle): - def _HandleCIfLlvm(self, Node): - Gen = self.Trans.LlvmGen - if Node.args: - ArgVal = self.HandleExprLlvm(Node.args[0]) - if ArgVal: - if isinstance(ArgVal, ir.Constant) and isinstance(ArgVal.type, ir.IntType): - return ir.Constant(ir.IntType(1), 1 if ArgVal.constant != 0 else 0) - if isinstance(ArgVal.type, ir.IntType): - return Gen.builder.icmp_signed('!=', ArgVal, Gen._zero_const(ArgVal.type), name="cif_cond") - if isinstance(ArgVal.type, ir.PointerType): - return Gen.builder.icmp_signed('!=', ArgVal, Gen._zero_const(ArgVal.type), name="cif_cond") - return ir.Constant(ir.IntType(1), 0) - def _HandleCAddrLlvm(self, Node): - Gen = self.Trans.LlvmGen - if not Node.args: - return ir.Constant(ir.IntType(8).as_pointer(), None) - Arg = Node.args[0] - if isinstance(Arg, ast.Call): - ClassName = None - if isinstance(Arg.func, ast.Name): - ClassName = Arg.func.id - elif isinstance(Arg.func, ast.Attribute): - ClassName = Arg.func.attr - if ClassName and ClassName in Gen.structs: - StructType = Gen.structs[ClassName] - if isinstance(StructType, ir.PointerType): - StructType = StructType.pointee - ObjPtr = Gen._alloca_entry(StructType, name=f"{ClassName}_obj") - Gen.builder.store(ir.Constant(StructType, None), ObjPtr) - ConstructorName = f"{ClassName}.__init__" - if ConstructorName in Gen.functions: - func = Gen.functions[ConstructorName] - InitArgs = [ObjPtr] - for carg in Arg.args: - ArgVal = self.HandleExprLlvm(carg) - if ArgVal: - InitArgs.append(ArgVal) - for kw in Arg.keywords: - ArgVal = self.HandleExprLlvm(kw.value) - if ArgVal: - InitArgs.append(ArgVal) - if hasattr(self.Trans.ExprCallHandle, '_append_eh_msg_out_arg'): - self.Trans.ExprCallHandle._append_eh_msg_out_arg(InitArgs, func, Gen) - adjusted = Gen._adjust_args(InitArgs, func) - Gen.builder.call(func, adjusted, name=f"{ClassName}_construct") - return Gen.builder.bitcast(ObjPtr, ir.IntType(8).as_pointer(), name=f"{ClassName}_as_i8ptr") - if isinstance(Arg, ast.Subscript): - SubPtr = self.Trans.ExprAttrHandle.HandleSubscriptPtrLlvm(Arg) - if SubPtr and isinstance(SubPtr.type, ir.PointerType): - return Gen.builder.bitcast(SubPtr, ir.IntType(8).as_pointer(), name="addr_subscript_as_i8ptr") - if isinstance(Arg, ast.Attribute): - AttrPtr = self.Trans.ExprAttrHandle._get_attr_ptr(Arg) - if AttrPtr and isinstance(AttrPtr.type, ir.PointerType): - return Gen.builder.bitcast(AttrPtr, ir.IntType(8).as_pointer(), name="addr_attr_as_i8ptr") - if isinstance(Arg, ast.Name): - VarName = Arg.id - if VarName in Gen.functions: - func = Gen.functions[VarName] - return Gen.builder.bitcast(func, ir.IntType(8).as_pointer(), name="addr_func_as_i8ptr") - if VarName in Gen.variables and Gen.variables[VarName] is not None: - var_ptr = Gen.variables[VarName] - if isinstance(var_ptr.type, ir.PointerType): - # For pointer-to-pointer allocas (var_ptr is T**): - # - If T is a named struct (@t.Object class), the variable semantically - # IS the struct, so c.Addr should return the struct pointer value. - # - If T is a primitive pointer type (e.g., i8*), the variable semantically - # holds a pointer, so c.Addr should return &var (alloca address). - if isinstance(var_ptr.type.pointee, ir.PointerType): - pointee = var_ptr.type.pointee.pointee - if isinstance(pointee, ir.IdentifiedStructType): - # @t.Object class variable — return loaded struct pointer - ArgVal = self.HandleExprLlvm(Arg) - if ArgVal and isinstance(ArgVal.type, ir.PointerType): - return Gen.builder.bitcast(ArgVal, ir.IntType(8).as_pointer(), name="addr_as_i8ptr") - # Pointer-type variable — return alloca address (&var) - return Gen.builder.bitcast(var_ptr, ir.IntType(8).as_pointer(), name="addr_as_i8ptr") - return Gen.builder.bitcast(var_ptr, ir.IntType(8).as_pointer(), name="addr_as_i8ptr") - ArgVal = self.HandleExprLlvm(Arg) - if ArgVal: - if isinstance(ArgVal.type, ir.IntType): - alloca = Gen._alloca(ArgVal.type, name="addr_tmp") - Gen._store(ArgVal, alloca) - return Gen.builder.bitcast(alloca, ir.IntType(8).as_pointer(), name="addr_as_i8ptr") - elif isinstance(ArgVal.type, ir.PointerType): - return Gen.builder.bitcast(ArgVal, ir.IntType(8).as_pointer(), name="addr_bitcast") - return ir.Constant(ir.IntType(8).as_pointer(), None) - - def _HandleCSetLlvm(self, Node): - Gen = self.Trans.LlvmGen - if len(Node.args) >= 2: - target_arg = Node.args[0] - value_arg = Node.args[1] - target_ptr = None - if isinstance(target_arg, ast.Call) and isinstance(target_arg.func, ast.Attribute): - if isinstance(target_arg.func.value, ast.Name) and target_arg.func.value.id == 'c': - if target_arg.func.attr == 'Deref' and target_arg.args: - deref_arg = target_arg.args[0] - if isinstance(deref_arg, ast.Name) and deref_arg.id in Gen.variables and Gen.variables[deref_arg.id] is not None: - target_ptr = Gen._load(Gen.variables[deref_arg.id], name="deref_load_ptr") - else: - inner_value = self.HandleExprLlvm(deref_arg) - if inner_value: - if isinstance(inner_value.type, ir.PointerType): - if isinstance(inner_value.type.pointee, ir.PointerType): - inner_value = Gen._load(inner_value, name="cast_deref") - target_ptr = inner_value - elif target_arg.func.attr == 'Addr' and target_arg.args: - target_ptr = self.HandleExprLlvm(target_arg) - elif isinstance(target_arg.func.value, ast.Name) and target_arg.func.value.id == 't': - type_attr = target_arg.func.attr - resolved_cname = self.Trans.TSpecialCallHandle._ResolveTAttrToCName(type_attr) - if target_arg.args and resolved_cname is not None: - inner_val = self.HandleExprLlvm(target_arg.args[0]) - if inner_val and isinstance(inner_val.type, ir.PointerType): - target_llvm_type = Gen._basic_type_to_llvm(resolved_cname) - if target_llvm_type: - target_ptr = Gen.builder.bitcast(inner_val, ir.PointerType(target_llvm_type), name="tcast_ptr") - if not target_ptr: - if isinstance(target_arg, ast.Subscript): - target_ptr = self.Trans.ExprAttrHandle.HandleSubscriptPtrLlvm(target_arg) - else: - target_ptr = self.HandleExprLlvm(target_arg) - Val = self.HandleExprLlvm(value_arg) - if target_ptr and Val: - if isinstance(target_ptr.type, ir.PointerType): - ValToStore = Val - pointee = target_ptr.type.pointee - if isinstance(pointee, ir.PointerType) and isinstance(pointee.pointee, ir.IntType) and pointee.pointee.width == 8: - if isinstance(Val.type, ir.PointerType) and isinstance(Val.type.pointee, ir.IntType) and Val.type.pointee.width == 8: - ValToStore = Val - elif isinstance(Val.type, ir.IntType): - ValToStore = Gen.builder.inttoptr(Val, pointee, name="int_to_ptr_set") - elif isinstance(pointee, ir.IntType): - if isinstance(Val.type, ir.ArrayType) and isinstance(Val.type.element, ir.IntType) and Val.type.element.width == 8: - zero = ir.Constant(ir.IntType(32), 0) - value_ptr = Gen.builder.gep(Val, [zero, zero], name="value_ptr") - ValToStore = Gen._load(value_ptr, name="load_value") - elif isinstance(Val.type, ir.PointerType) and isinstance(Val.type.pointee, ir.IntType) and Val.type.pointee.width == 8: - ValToStore = Gen._load(Val, name="load_char_value") - if isinstance(ValToStore.type, ir.IntType) and isinstance(pointee, ir.IntType): - if ValToStore.type.width < pointee.width: - ValToStore = Gen.builder.zext(ValToStore, pointee, name="zext_set") - elif ValToStore.type.width > pointee.width: - ValToStore = Gen.builder.trunc(ValToStore, pointee, name="trunc_set") - elif Val.type != pointee: - if isinstance(pointee, ir.PointerType) and isinstance(Val.type, ir.PointerType): - ValToStore = Gen.builder.bitcast(Val, pointee, name="bitcast_set") - Gen._store(ValToStore, target_ptr) - return ir.Constant(ir.IntType(32), 1) - - def _HandleCLoadLlvm(self, Node): - Gen = self.Trans.LlvmGen - if len(Node.args) < 2: - return ir.Constant(ir.IntType(32), 0) - src_val = self.HandleExprLlvm(Node.args[0]) - dst_val = self.HandleExprLlvm(Node.args[1]) - if not src_val or not dst_val: - return ir.Constant(ir.IntType(32), 0) - if not isinstance(src_val.type, ir.PointerType) or not isinstance(dst_val.type, ir.PointerType): - return ir.Constant(ir.IntType(32), 0) - loaded = Gen._load(src_val, name="cload_src") - if loaded is None: - return ir.Constant(ir.IntType(32), 0) - pointee = dst_val.type.pointee - val_to_store = loaded - if isinstance(pointee, ir.IntType) and isinstance(loaded.type, ir.IntType): - if loaded.type.width < pointee.width: - val_to_store = Gen.builder.zext(loaded, pointee, name="cload_zext") - elif loaded.type.width > pointee.width: - val_to_store = Gen.builder.trunc(loaded, pointee, name="cload_trunc") - elif isinstance(pointee, ir.PointerType) and isinstance(loaded.type, ir.PointerType): - val_to_store = Gen.builder.bitcast(loaded, pointee, name="cload_bitcast") - elif loaded.type != pointee: - target_ptr = Gen.builder.bitcast(src_val, ir.PointerType(pointee), name="cload_cast") - loaded = Gen._load(target_ptr, name="cload_casted") - if loaded is None: - return ir.Constant(ir.IntType(32), 0) - val_to_store = loaded - Gen._store(val_to_store, dst_val) - return ir.Constant(ir.IntType(32), 1) - - def _HandleCDerefLlvm(self, Node): - Gen = self.Trans.LlvmGen - if not Node.args: - return ir.Constant(ir.IntType(64), 0) - arg_val = self.HandleExprLlvm(Node.args[0]) - if arg_val is None: - return ir.Constant(ir.IntType(32), 0) - if isinstance(arg_val.type, ir.PointerType): - loaded = Gen._load(arg_val, name="deref") - if loaded is not None: - return loaded - return arg_val - - def _HandleCPtrToIntLlvm(self, Node): - Gen = self.Trans.LlvmGen - if not Node.args: - return ir.Constant(ir.IntType(64), 0) - arg_val = self.HandleExprLlvm(Node.args[0]) - if arg_val is None: - return ir.Constant(ir.IntType(64), 0) - if isinstance(arg_val.type, ir.PointerType): - return Gen.builder.ptrtoint(arg_val, ir.IntType(64), name="ptrtoint_result") - if isinstance(arg_val.type, ir.IntType): - if arg_val.type.width < 64: - return Gen.builder.zext(arg_val, ir.IntType(64), name="zext_ptrtoint") - elif arg_val.type.width > 64: - return Gen.builder.trunc(arg_val, ir.IntType(64), name="trunc_ptrtoint") - return arg_val - return ir.Constant(ir.IntType(64), 0) - - -class TSpecialCallHandle(BaseHandle): - - @staticmethod - def _ResolveTAttrToCName(attr: str) -> str: - from lib.includes.t import CTypeRegistry - ctype_cls = CTypeRegistry.GetClassByName(attr) - if ctype_cls is not None: - try: - inst = ctype_cls() - cname = getattr(inst, 'CName', '') - if cname: - return cname - except Exception: - pass - return None - - def _HandleTSpecialCallLlvm(self, Node): - Gen = self.Trans.LlvmGen - if not Node.args: - return None - attr = Node.func.attr - - if attr == 'CType': - return self._HandleCTypeLlvm(Node) - - target_type = self._ResolveTAttrToCName(attr) - if target_type is not None: - is_ptr_cast = False - if len(Node.args) >= 2: - second_arg = Node.args[1] - if isinstance(second_arg, ast.Attribute) and isinstance(second_arg.value, ast.Name) and second_arg.value.id == 't' and second_arg.attr == 'CPtr': - is_ptr_cast = True - elif isinstance(second_arg, ast.Name) and second_arg.id == 'CPtr': - is_ptr_cast = True - if is_ptr_cast: - return self._HandleTPtrCastLlvm(Node, attr) - if target_type == 'void': - target_type = 'void *' - return self.Trans.ExprCallHandle._HandleTypeCastLlvm(Node.args[0], target_type) - return None - - def _HandleCTypeLlvm(self, Node): - Gen = self.Trans.LlvmGen - arg_val = self.HandleExprLlvm(Node.args[0]) - if not arg_val: - return None - target_type_str = 'unsigned long long' - if len(Node.args) >= 2: - type_parts = [] - ptr_count = 0 - for i in range(1, len(Node.args)): - type_arg = Node.args[i] - if isinstance(type_arg, ast.Attribute) and isinstance(type_arg.value, ast.Name) and type_arg.value.id == 't': - type_attr = type_arg.attr - _PREFIX_MAP = { - 'CUnsigned': 'unsigned', 'CSigned': 'signed', - 'CConst': 'const', 'CVolatile': 'volatile', - } - if type_attr in _PREFIX_MAP: - type_parts.append(_PREFIX_MAP[type_attr]) - elif type_attr in ('CPtr', 'CArrayPtr'): - ptr_count += 1 - else: - resolved = self._ResolveTAttrToCName(type_attr) - if resolved is not None: - type_parts.append(resolved) - if type_parts: - target_type_str = ' '.join(type_parts) - if ptr_count > 0: - target_type_str += ' ' + '*' * ptr_count - if isinstance(arg_val.type, ir.PointerType): - int_val = Gen.builder.ptrtoint(arg_val, ir.IntType(64), name="ptr_to_int") - return int_val - return self.Trans.ExprCallHandle._HandleTypeCastLlvm(Node.args[0], target_type_str) - - def _HandleTPtrCastLlvm(self, Node, attr): - Gen = self.Trans.LlvmGen - from lib.includes.t import CTypeRegistry - if attr in ('CChar', 'CUnsignedChar'): - first_arg = Node.args[0] - if isinstance(first_arg, ast.Call) and isinstance(first_arg.func, ast.Attribute) and isinstance(first_arg.func.value, ast.Name) and first_arg.func.value.id == 't' and first_arg.func.attr == 'CInt' and first_arg.args: - inner_val = self.HandleExprLlvm(first_arg.args[0]) - if isinstance(inner_val.type, ir.PointerType): - return Gen.builder.bitcast(inner_val, ir.PointerType(ir.IntType(8)), name=f"c{attr.lower()}_ptr_from_cint") - expr_val = self.HandleExprLlvm(Node.args[0]) - if isinstance(expr_val.type, ir.IntType) and expr_val.type.width == 8: - var = Gen._alloca(ir.ArrayType(ir.IntType(8), 2), name=f"c{attr.lower()}_ptr") - zero = ir.Constant(ir.IntType(32), 0) - char_ptr = Gen.builder.gep(var, [zero, zero], name="char_ptr") - Gen._store(expr_val, char_ptr) - null_char = ir.Constant(ir.IntType(8), 0) - null_ptr = Gen.builder.gep(var, [zero, ir.Constant(ir.IntType(32), 1)], name="null_ptr") - Gen._store(null_char, null_ptr) - return char_ptr - elif isinstance(expr_val.type, ir.PointerType): - if isinstance(expr_val.type.pointee, ir.PointerType): - loaded_ptr = Gen._load(expr_val, name="load_ptr") - if isinstance(loaded_ptr.type, ir.PointerType) and isinstance(loaded_ptr.type.pointee, ir.IntType) and loaded_ptr.type.pointee.width == 8: - return loaded_ptr - if isinstance(expr_val.type.pointee, ir.IntType) and expr_val.type.pointee.width == 8: - return expr_val - return Gen.builder.bitcast(expr_val, ir.PointerType(ir.IntType(8)), name="cast_to_char_ptr") - elif isinstance(expr_val.type, ir.IntType): - if expr_val.type.width == 32: - expr_val = Gen.builder.zext(expr_val, ir.IntType(64), name="zext_to_64") - return Gen.builder.inttoptr(expr_val, ir.PointerType(ir.IntType(8)), name=f"inttoptr_c{attr.lower()}") - return Gen.emit_constant(0, 'int') - elif attr == 'CVoid': - return self.Trans.ExprCallHandle._HandleTypeCastLlvm(Node.args[0], 'void *') - elif attr == 'CInt': - expr_val = self.HandleExprLlvm(Node.args[0]) - if expr_val: - if isinstance(expr_val.type, ir.IntType): - if expr_val.type.width < 64: - expr_val = Gen.builder.zext(expr_val, ir.IntType(64), name="zext_to_64") - return Gen.builder.inttoptr(expr_val, ir.PointerType(ir.IntType(32)), name="cint_ptr") - return Gen.builder.bitcast(expr_val, ir.PointerType(ir.IntType(32)), name="cint_ptr") - else: - ctype_cls = CTypeRegistry.GetClassByName(attr) - if ctype_cls is not None: - llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls) - target_type = Gen._type_str_to_llvm(llvm_str) - if target_type and isinstance(target_type, (ir.IntType, ir.FloatType, ir.DoubleType)): - target_ptr_type = ir.PointerType(target_type) - expr_val = self.HandleExprLlvm(Node.args[0]) - if expr_val: - if isinstance(expr_val.type, ir.IntType): - if expr_val.type.width < 64: - expr_val = Gen.builder.zext(expr_val, ir.IntType(64), name="zext_to_64") - return Gen.builder.inttoptr(expr_val, target_ptr_type, name=f"{attr.lower()}_ptr") - return Gen.builder.bitcast(expr_val, target_ptr_type, name=f"{attr.lower()}_ptr") - return None +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle +import ast +import llvmlite.ir as ir + + +class CSpecialCallHandle(BaseHandle): + def _HandleCIfLlvm(self, Node): + Gen = self.Trans.LlvmGen + if Node.args: + ArgVal = self.HandleExprLlvm(Node.args[0]) + if ArgVal: + if isinstance(ArgVal, ir.Constant) and isinstance(ArgVal.type, ir.IntType): + return ir.Constant(ir.IntType(1), 1 if ArgVal.constant != 0 else 0) + if isinstance(ArgVal.type, ir.IntType): + return Gen.builder.icmp_signed('!=', ArgVal, Gen._ZeroConst(ArgVal.type), name="cif_cond") + if isinstance(ArgVal.type, ir.PointerType): + return Gen.builder.icmp_signed('!=', ArgVal, Gen._ZeroConst(ArgVal.type), name="cif_cond") + return ir.Constant(ir.IntType(1), 0) + def _HandleCAddrLlvm(self, Node): + Gen = self.Trans.LlvmGen + if not Node.args: + return ir.Constant(ir.IntType(8).as_pointer(), None) + Arg = Node.args[0] + if isinstance(Arg, ast.Call): + ClassName = None + if isinstance(Arg.func, ast.Name): + ClassName = Arg.func.id + elif isinstance(Arg.func, ast.Attribute): + ClassName = Arg.func.attr + if ClassName and ClassName in Gen.structs: + StructType = Gen.structs[ClassName] + if isinstance(StructType, ir.PointerType): + StructType = StructType.pointee + ObjPtr = Gen._allocaEntry(StructType, name=f"{ClassName}_obj") + Gen.builder.store(ir.Constant(StructType, None), ObjPtr) + ConstructorName = f"{ClassName}.__init__" + if ConstructorName in Gen.functions: + func = Gen.functions[ConstructorName] + InitArgs = [ObjPtr] + for carg in Arg.args: + ArgVal = self.HandleExprLlvm(carg) + if ArgVal: + InitArgs.append(ArgVal) + for kw in Arg.keywords: + ArgVal = self.HandleExprLlvm(kw.value) + if ArgVal: + InitArgs.append(ArgVal) + if hasattr(self.Trans.ExprCallHandle, '_append_eh_msg_out_arg'): + self.Trans.ExprCallHandle._append_eh_msg_out_arg(InitArgs, func, Gen) + adjusted = Gen._adjust_args(InitArgs, func) + Gen.builder.call(func, adjusted, name=f"{ClassName}_construct") + return Gen.builder.bitcast(ObjPtr, ir.IntType(8).as_pointer(), name=f"{ClassName}_as_i8ptr") + if isinstance(Arg, ast.Subscript): + SubPtr = self.Trans.ExprAttrHandle.HandleSubscriptPtrLlvm(Arg) + if SubPtr and isinstance(SubPtr.type, ir.PointerType): + return Gen.builder.bitcast(SubPtr, ir.IntType(8).as_pointer(), name="addr_subscript_as_i8ptr") + if isinstance(Arg, ast.Attribute): + AttrPtr = self.Trans.ExprAttrHandle._get_attr_ptr(Arg) + if AttrPtr and isinstance(AttrPtr.type, ir.PointerType): + return Gen.builder.bitcast(AttrPtr, ir.IntType(8).as_pointer(), name="addr_attr_as_i8ptr") + if isinstance(Arg, ast.Name): + VarName = Arg.id + if VarName in Gen.functions: + func = Gen.functions[VarName] + return Gen.builder.bitcast(func, ir.IntType(8).as_pointer(), name="addr_func_as_i8ptr") + if VarName in Gen.variables and Gen.variables[VarName] is not None: + var_ptr = Gen.variables[VarName] + if isinstance(var_ptr.type, ir.PointerType): + # For pointer-to-pointer allocas (var_ptr is T**): + # - If T is a named struct (@t.Object class), the variable semantically + # IS the struct, so c.Addr should return the struct pointer value. + # - If T is a primitive pointer type (e.g., i8*), the variable semantically + # holds a pointer, so c.Addr should return &var (alloca address). + if isinstance(var_ptr.type.pointee, ir.PointerType): + pointee = var_ptr.type.pointee.pointee + if isinstance(pointee, ir.IdentifiedStructType): + # @t.Object class variable — return Loaded struct pointer + ArgVal = self.HandleExprLlvm(Arg) + if ArgVal and isinstance(ArgVal.type, ir.PointerType): + return Gen.builder.bitcast(ArgVal, ir.IntType(8).as_pointer(), name="addr_as_i8ptr") + # Pointer-type variable — return alloca address (&var) + return Gen.builder.bitcast(var_ptr, ir.IntType(8).as_pointer(), name="addr_as_i8ptr") + return Gen.builder.bitcast(var_ptr, ir.IntType(8).as_pointer(), name="addr_as_i8ptr") + ArgVal = self.HandleExprLlvm(Arg) + if ArgVal: + if isinstance(ArgVal.type, ir.IntType): + alloca = Gen._alloca(ArgVal.type, name="addr_tmp") + Gen._store(ArgVal, alloca) + return Gen.builder.bitcast(alloca, ir.IntType(8).as_pointer(), name="addr_as_i8ptr") + elif isinstance(ArgVal.type, ir.PointerType): + return Gen.builder.bitcast(ArgVal, ir.IntType(8).as_pointer(), name="addr_bitcast") + return ir.Constant(ir.IntType(8).as_pointer(), None) + + def _HandleCSetLlvm(self, Node): + Gen = self.Trans.LlvmGen + if len(Node.args) >= 2: + target_arg = Node.args[0] + value_arg = Node.args[1] + target_ptr = None + if isinstance(target_arg, ast.Call) and isinstance(target_arg.func, ast.Attribute): + if isinstance(target_arg.func.value, ast.Name) and target_arg.func.value.id == 'c': + if target_arg.func.attr == 'Deref' and target_arg.args: + deref_arg = target_arg.args[0] + if isinstance(deref_arg, ast.Name) and deref_arg.id in Gen.variables and Gen.variables[deref_arg.id] is not None: + target_ptr = Gen._load(Gen.variables[deref_arg.id], name="deref_load_ptr") + else: + inner_value = self.HandleExprLlvm(deref_arg) + if inner_value: + if isinstance(inner_value.type, ir.PointerType): + if isinstance(inner_value.type.pointee, ir.PointerType): + inner_value = Gen._load(inner_value, name="cast_deref") + target_ptr = inner_value + elif target_arg.func.attr == 'Addr' and target_arg.args: + target_ptr = self.HandleExprLlvm(target_arg) + elif isinstance(target_arg.func.value, ast.Name) and target_arg.func.value.id == 't': + type_attr = target_arg.func.attr + resolved_cname = self.Trans.TSpecialCallHandle._ResolveTAttrToCName(type_attr) + if target_arg.args and resolved_cname is not None: + inner_val = self.HandleExprLlvm(target_arg.args[0]) + if inner_val and isinstance(inner_val.type, ir.PointerType): + target_llvm_type = Gen._basic_type_to_llvm(resolved_cname) + if target_llvm_type: + target_ptr = Gen.builder.bitcast(inner_val, ir.PointerType(target_llvm_type), name="tcast_ptr") + if not target_ptr: + if isinstance(target_arg, ast.Subscript): + target_ptr = self.Trans.ExprAttrHandle.HandleSubscriptPtrLlvm(target_arg) + else: + target_ptr = self.HandleExprLlvm(target_arg) + Val = self.HandleExprLlvm(value_arg) + if target_ptr and Val: + if isinstance(target_ptr.type, ir.PointerType): + ValToStore = Val + pointee = target_ptr.type.pointee + if isinstance(pointee, ir.PointerType) and isinstance(pointee.pointee, ir.IntType) and pointee.pointee.width == 8: + if isinstance(Val.type, ir.PointerType) and isinstance(Val.type.pointee, ir.IntType) and Val.type.pointee.width == 8: + ValToStore = Val + elif isinstance(Val.type, ir.IntType): + ValToStore = Gen.builder.inttoptr(Val, pointee, name="int_to_ptr_set") + elif isinstance(pointee, ir.IntType): + if isinstance(Val.type, ir.ArrayType) and isinstance(Val.type.element, ir.IntType) and Val.type.element.width == 8: + zero = ir.Constant(ir.IntType(32), 0) + value_ptr = Gen.builder.gep(Val, [zero, zero], name="value_ptr") + ValToStore = Gen._load(value_ptr, name="Load_value") + elif isinstance(Val.type, ir.PointerType) and isinstance(Val.type.pointee, ir.IntType) and Val.type.pointee.width == 8: + ValToStore = Gen._load(Val, name="Load_char_value") + if isinstance(ValToStore.type, ir.IntType) and isinstance(pointee, ir.IntType): + if ValToStore.type.width < pointee.width: + ValToStore = Gen.builder.zext(ValToStore, pointee, name="zext_set") + elif ValToStore.type.width > pointee.width: + ValToStore = Gen.builder.trunc(ValToStore, pointee, name="trunc_set") + elif Val.type != pointee: + if isinstance(pointee, ir.PointerType) and isinstance(Val.type, ir.PointerType): + ValToStore = Gen.builder.bitcast(Val, pointee, name="bitcast_set") + Gen._store(ValToStore, target_ptr) + return ir.Constant(ir.IntType(32), 1) + + def _HandleCLoadLlvm(self, Node): + Gen = self.Trans.LlvmGen + if len(Node.args) < 2: + return ir.Constant(ir.IntType(32), 0) + src_val = self.HandleExprLlvm(Node.args[0]) + dst_val = self.HandleExprLlvm(Node.args[1]) + if not src_val or not dst_val: + return ir.Constant(ir.IntType(32), 0) + if not isinstance(src_val.type, ir.PointerType) or not isinstance(dst_val.type, ir.PointerType): + return ir.Constant(ir.IntType(32), 0) + Loaded = Gen._load(src_val, name="cLoad_src") + if Loaded is None: + return ir.Constant(ir.IntType(32), 0) + pointee = dst_val.type.pointee + val_to_store = Loaded + if isinstance(pointee, ir.IntType) and isinstance(Loaded.type, ir.IntType): + if Loaded.type.width < pointee.width: + val_to_store = Gen.builder.zext(Loaded, pointee, name="cLoad_zext") + elif Loaded.type.width > pointee.width: + val_to_store = Gen.builder.trunc(Loaded, pointee, name="cLoad_trunc") + elif isinstance(pointee, ir.PointerType) and isinstance(Loaded.type, ir.PointerType): + val_to_store = Gen.builder.bitcast(Loaded, pointee, name="cLoad_bitcast") + elif Loaded.type != pointee: + target_ptr = Gen.builder.bitcast(src_val, ir.PointerType(pointee), name="cLoad_cast") + Loaded = Gen._load(target_ptr, name="cLoad_casted") + if Loaded is None: + return ir.Constant(ir.IntType(32), 0) + val_to_store = Loaded + Gen._store(val_to_store, dst_val) + return ir.Constant(ir.IntType(32), 1) + + def _HandleCDerefLlvm(self, Node): + Gen = self.Trans.LlvmGen + if not Node.args: + return ir.Constant(ir.IntType(64), 0) + arg_val = self.HandleExprLlvm(Node.args[0]) + if arg_val is None: + return ir.Constant(ir.IntType(32), 0) + if isinstance(arg_val.type, ir.PointerType): + Loaded = Gen._load(arg_val, name="deref") + if Loaded is not None: + return Loaded + return arg_val + + def _HandleCPtrToIntLlvm(self, Node): + Gen = self.Trans.LlvmGen + if not Node.args: + return ir.Constant(ir.IntType(64), 0) + arg_val = self.HandleExprLlvm(Node.args[0]) + if arg_val is None: + return ir.Constant(ir.IntType(64), 0) + if isinstance(arg_val.type, ir.PointerType): + return Gen.builder.ptrtoint(arg_val, ir.IntType(64), name="ptrtoint_result") + if isinstance(arg_val.type, ir.IntType): + if arg_val.type.width < 64: + return Gen.builder.zext(arg_val, ir.IntType(64), name="zext_ptrtoint") + elif arg_val.type.width > 64: + return Gen.builder.trunc(arg_val, ir.IntType(64), name="trunc_ptrtoint") + return arg_val + return ir.Constant(ir.IntType(64), 0) + + +class TSpecialCallHandle(BaseHandle): + + @staticmethod + def _ResolveTAttrToCName(attr: str) -> str: + from lib.includes.t import CTypeRegistry + ctype_cls = CTypeRegistry.GetClassByName(attr) + if ctype_cls is not None: + try: + inst = ctype_cls() + cname = getattr(inst, 'CName', '') + if cname: + return cname + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _config_mode + if _config_mode == "strict": + raise + _vlog().warning(f"处理函数调用失败: {_e}", "Exception") + return None + + def _HandleTSpecialCallLlvm(self, Node): + Gen = self.Trans.LlvmGen + if not Node.args: + return None + attr = Node.func.attr + + if attr == 'CType': + return self._HandleCTypeLlvm(Node) + + target_type = self._ResolveTAttrToCName(attr) + if target_type is not None: + IsPtr_cast = False + if len(Node.args) >= 2: + second_arg = Node.args[1] + if isinstance(second_arg, ast.Attribute) and isinstance(second_arg.value, ast.Name) and second_arg.value.id == 't' and second_arg.attr == 'CPtr': + IsPtr_cast = True + elif isinstance(second_arg, ast.Name) and second_arg.id == 'CPtr': + IsPtr_cast = True + if IsPtr_cast: + return self._HandleTPtrCastLlvm(Node, attr) + if target_type == 'void': + target_type = 'void *' + return self.Trans.ExprCallHandle._HandleTypeCastLlvm(Node.args[0], target_type) + return None + + def _HandleCTypeLlvm(self, Node): + Gen = self.Trans.LlvmGen + arg_val = self.HandleExprLlvm(Node.args[0]) + if not arg_val: + return None + target_type_str = 'unsigned long long' + if len(Node.args) >= 2: + type_parts = [] + ptr_count = 0 + for i in range(1, len(Node.args)): + type_arg = Node.args[i] + if isinstance(type_arg, ast.Attribute) and isinstance(type_arg.value, ast.Name) and type_arg.value.id == 't': + type_attr = type_arg.attr + _PREFIX_MAP = { + 'CUnsigned': 'unsigned', 'CSigned': 'signed', + 'CConst': 'const', 'CVolatile': 'volatile', + } + if type_attr in _PREFIX_MAP: + type_parts.append(_PREFIX_MAP[type_attr]) + elif type_attr in ('CPtr', 'CArrayPtr'): + ptr_count += 1 + else: + resolved = self._ResolveTAttrToCName(type_attr) + if resolved is not None: + type_parts.append(resolved) + if type_parts: + target_type_str = ' '.join(type_parts) + if ptr_count > 0: + target_type_str += ' ' + '*' * ptr_count + if isinstance(arg_val.type, ir.PointerType): + int_val = Gen.builder.ptrtoint(arg_val, ir.IntType(64), name="ptr_to_int") + return int_val + return self.Trans.ExprCallHandle._HandleTypeCastLlvm(Node.args[0], target_type_str) + + def _HandleTPtrCastLlvm(self, Node, attr): + Gen = self.Trans.LlvmGen + from lib.includes.t import CTypeRegistry + if attr in ('CChar', 'CUnsignedChar'): + first_arg = Node.args[0] + if isinstance(first_arg, ast.Call) and isinstance(first_arg.func, ast.Attribute) and isinstance(first_arg.func.value, ast.Name) and first_arg.func.value.id == 't' and first_arg.func.attr == 'CInt' and first_arg.args: + inner_val = self.HandleExprLlvm(first_arg.args[0]) + if isinstance(inner_val.type, ir.PointerType): + return Gen.builder.bitcast(inner_val, ir.PointerType(ir.IntType(8)), name=f"c{attr.lower()}_ptr_from_cint") + expr_val = self.HandleExprLlvm(Node.args[0]) + if isinstance(expr_val.type, ir.IntType) and expr_val.type.width == 8: + var = Gen._alloca(ir.ArrayType(ir.IntType(8), 2), name=f"c{attr.lower()}_ptr") + zero = ir.Constant(ir.IntType(32), 0) + char_ptr = Gen.builder.gep(var, [zero, zero], name="char_ptr") + Gen._store(expr_val, char_ptr) + null_char = ir.Constant(ir.IntType(8), 0) + null_ptr = Gen.builder.gep(var, [zero, ir.Constant(ir.IntType(32), 1)], name="null_ptr") + Gen._store(null_char, null_ptr) + return char_ptr + elif isinstance(expr_val.type, ir.PointerType): + if isinstance(expr_val.type.pointee, ir.PointerType): + Loaded_ptr = Gen._load(expr_val, name="load_ptr") + if isinstance(Loaded_ptr.type, ir.PointerType) and isinstance(Loaded_ptr.type.pointee, ir.IntType) and Loaded_ptr.type.pointee.width == 8: + return Loaded_ptr + if isinstance(expr_val.type.pointee, ir.IntType) and expr_val.type.pointee.width == 8: + return expr_val + return Gen.builder.bitcast(expr_val, ir.PointerType(ir.IntType(8)), name="cast_to_char_ptr") + elif isinstance(expr_val.type, ir.IntType): + if expr_val.type.width == 32: + expr_val = Gen.builder.zext(expr_val, ir.IntType(64), name="zext_to_64") + return Gen.builder.inttoptr(expr_val, ir.PointerType(ir.IntType(8)), name=f"inttoptr_c{attr.lower()}") + return Gen.emit_constant(0, 'int') + elif attr == 'CVoid': + return self.Trans.ExprCallHandle._HandleTypeCastLlvm(Node.args[0], 'void *') + elif attr == 'CInt': + expr_val = self.HandleExprLlvm(Node.args[0]) + if expr_val: + if isinstance(expr_val.type, ir.IntType): + if expr_val.type.width < 64: + expr_val = Gen.builder.zext(expr_val, ir.IntType(64), name="zext_to_64") + return Gen.builder.inttoptr(expr_val, ir.PointerType(ir.IntType(32)), name="cint_ptr") + return Gen.builder.bitcast(expr_val, ir.PointerType(ir.IntType(32)), name="cint_ptr") + else: + ctype_cls = CTypeRegistry.GetClassByName(attr) + if ctype_cls is not None: + llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls) + target_type = Gen._type_str_to_llvm(llvm_str) + if target_type and isinstance(target_type, (ir.IntType, ir.FloatType, ir.DoubleType)): + target_ptr_type = ir.PointerType(target_type) + expr_val = self.HandleExprLlvm(Node.args[0]) + if expr_val: + if isinstance(expr_val.type, ir.IntType): + if expr_val.type.width < 64: + expr_val = Gen.builder.zext(expr_val, ir.IntType(64), name="zext_to_64") + return Gen.builder.inttoptr(expr_val, target_ptr_type, name=f"{attr.lower()}_ptr") + return Gen.builder.bitcast(expr_val, target_ptr_type, name=f"{attr.lower()}_ptr") + return None diff --git a/lib/core/Handles/HandlesTry.py b/lib/core/Handles/HandlesTry.py index 93e63d4..0c8cc86 100644 --- a/lib/core/Handles/HandlesTry.py +++ b/lib/core/Handles/HandlesTry.py @@ -1,211 +1,211 @@ -from __future__ import annotations -from typing import TYPE_CHECKING -if TYPE_CHECKING: - from lib.core.translator import Translator -from lib.core.Handles.HandlesBase import BaseHandle, EXCEPTION_CODE_MAP -import ast -import llvmlite.ir as ir - - -class TryHandle(BaseHandle): - def _get_exception_type_code(self, type_node): - if isinstance(type_node, ast.Name): - name = type_node.id - if name in EXCEPTION_CODE_MAP: - return EXCEPTION_CODE_MAP[name] - if name in self.Trans.exception_registry: - return self.Trans.exception_registry[name] - return 1 - if isinstance(type_node, ast.Attribute): - name = type_node.attr - if name in EXCEPTION_CODE_MAP: - return EXCEPTION_CODE_MAP[name] - if name in self.Trans.exception_registry: - return self.Trans.exception_registry[name] - return 1 - if isinstance(type_node, ast.Tuple): - for elt in type_node.elts: - code = self._get_exception_type_code(elt) - if code != 1: - return code - return 1 - return 1 - - def _get_exception_name(self, type_node): - if isinstance(type_node, ast.Name): - return type_node.id - if isinstance(type_node, ast.Attribute): - return type_node.attr - return None - - def _get_all_match_codes(self, type_node): - name = self._get_exception_name(type_node) - if name is None: - return [self._get_exception_type_code(type_node)] - if name not in self.Trans.exception_registry: - return [self._get_exception_type_code(type_node)] - codes = [self.Trans.exception_registry[name]] - self._collect_descendant_codes(name, codes) - return codes - - def _collect_descendant_codes(self, parent_name, codes): - for child_name, parent in self.Trans.exception_parents.items(): - if parent == parent_name: - child_code = self.Trans.exception_registry.get(child_name) - if child_code is not None and child_code not in codes: - codes.append(child_code) - self._collect_descendant_codes(child_name, codes) - - def _HandleTryLlvm(self, Node): - Gen = self.Trans.LlvmGen - if not Gen.func: - return - exception_code = Gen._alloca_entry(ir.IntType(32), name="eh_code") - eh_message = Gen._alloca_entry(ir.PointerType(ir.IntType(8)), name="eh_message") - Gen._store(ir.Constant(ir.IntType(32), 0), exception_code) - Gen._store(ir.Constant(ir.PointerType(ir.IntType(8)), None), eh_message) - HasFinally = bool(Node.finalbody) - if HasFinally: - Gen.eh_finally_stack.append((None, None, None)) - else: - Gen.eh_finally_stack.append(None) - DispatchBB = Gen.func.append_basic_block(name="try.dispatch") - AfterBB = Gen.func.append_basic_block(name="try.after") - except_blocks = [] - for i, handler in enumerate(Node.handlers): - ExcTypeCodes = [1] - if handler.type: - ExcTypeCodes = self._get_all_match_codes(handler.type) - ExceptBB = Gen.func.append_basic_block(name=f"try.except_{i}") - Gen.eh_except_block_stack.append((DispatchBB, None, exception_code, eh_message)) - except_blocks.append((ExceptBB, ExcTypeCodes, handler)) - TryBB = Gen.func.append_basic_block(name="try.body") - ElseBB = None - if Node.orelse: - ElseBB = Gen.func.append_basic_block(name="try.else") - Gen.builder.branch(TryBB) - Gen.builder.position_at_start(TryBB) - self.HandleBodyLlvm(Node.body) - if not Gen.builder.block.is_terminated: - Gen._store(ir.Constant(ir.IntType(32), 0), exception_code) - if ElseBB: - Gen.builder.branch(ElseBB) - else: - Gen.builder.branch(AfterBB) - Gen.builder.position_at_start(DispatchBB) - eh_code_val = Gen._load(exception_code, name="load_eh_code") - next_check_bb = None - handler_var_map = {} - UnhandledBB = Gen.func.append_basic_block(name="try.unhandled") - for i, (ExceptBB, ExcTypeCodes, handler) in enumerate(except_blocks): - MatchBB = Gen.func.append_basic_block(name=f"try.match_{i}") - if i > 0 and next_check_bb is not None: - Gen.builder.position_at_start(next_check_bb) - eh_code_val = Gen._load(exception_code, name=f"load_eh_code_{i}") - if handler.type is None: - Gen.builder.branch(MatchBB) - else: - match_cond = None - for code in ExcTypeCodes: - is_code_match = Gen.builder.icmp_signed('==', eh_code_val, ir.Constant(ir.IntType(32), code), name=f"eh_match_{i}_c{code}") - if match_cond is None: - match_cond = is_code_match - else: - match_cond = Gen.builder.or_(match_cond, is_code_match, name=f"eh_match_any_{i}") - if i < len(except_blocks) - 1: - next_check_bb = Gen.func.append_basic_block(name=f"try.check_{i}") - else: - next_check_bb = UnhandledBB - Gen.builder.cbranch(match_cond, MatchBB, next_check_bb) - Gen.builder.position_at_start(MatchBB) - if handler.name: - var_alloca = Gen._alloca_entry(ir.IntType(8).as_pointer(), name=handler.name) - eh_msg_val = Gen._load(eh_message, name=f"load_eh_msg_{handler.name}") - Gen._store(eh_msg_val, var_alloca) - handler_var_map[i] = (handler.name, var_alloca, Gen.variables.get(handler.name)) - Gen.builder.branch(ExceptBB) - Gen.builder.position_at_start(UnhandledBB) - eh_msg_out_arg = None - eh_code_out_arg = None - if Gen.func and len(Gen.func.args) > 0: - for arg in Gen.func.args: - if arg.name == '__eh_msg_out__': - eh_msg_out_arg = arg - elif arg.name == '__eh_code_out__': - eh_code_out_arg = arg - if eh_msg_out_arg is not None and eh_code_out_arg is not None: - eh_msg_val = Gen._load(eh_message, name="load_eh_msg_propagate") - eh_code_val_prop = Gen._load(exception_code, name="load_eh_code_propagate") - Gen._store(eh_msg_val, eh_msg_out_arg) - Gen._store(eh_code_val_prop, eh_code_out_arg) - ret_type = getattr(Gen.func, 'ftype', None) and Gen.func.ftype.return_type if getattr(Gen, 'func', None) else None - if isinstance(ret_type, ir.IdentifiedStructType): - if ret_type.elements: - zero_val = ir.Constant(ret_type, [ - ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)) - else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType)) - else ir.Constant(et, ir.Undefined) for et in ret_type.elements]) - else: - zero_val = ir.Constant(ret_type, None) - Gen.builder.ret(zero_val) - elif isinstance(ret_type, ir.PointerType): - Gen.builder.ret(ir.Constant(ret_type, None)) - elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)): - Gen.builder.ret(ir.Constant(ret_type, 0.0)) - elif isinstance(ret_type, ir.IntType): - Gen.builder.ret(ir.Constant(ret_type, 1)) - elif isinstance(ret_type, ir.VoidType): - Gen.builder.ret_void() - else: - Gen.builder.ret(ir.Constant(ir.IntType(32), 1)) - else: - Gen._store(ir.Constant(ir.IntType(32), 0), exception_code) - Gen.builder.branch(AfterBB) - for idx, (ExceptBB, ExcTypeCodes, handler) in enumerate(except_blocks): - Gen.builder.position_at_start(ExceptBB) - old_var = None - if idx in handler_var_map: - hname, var_alloca, old_var = handler_var_map[idx] - Gen.variables[hname] = var_alloca - self.HandleBodyLlvm(handler.body) - if idx in handler_var_map: - hname, _, old_var = handler_var_map[idx] - if old_var is not None: - Gen.variables[hname] = old_var - elif hname in Gen.variables: - del Gen.variables[hname] - if not Gen.builder.block.is_terminated: - Gen.builder.branch(AfterBB) - Gen.eh_except_block_stack.pop() - if ElseBB: - Gen.builder.position_at_start(ElseBB) - self.HandleBodyLlvm(Node.orelse) - if not Gen.builder.block.is_terminated: - Gen.builder.branch(AfterBB) - Gen.builder.position_at_start(AfterBB) - if HasFinally: - Gen.eh_finally_stack.pop() - if Node.finalbody: - FinallyBB = Gen.func.append_basic_block(name="try.finally") - pending_ret_flag = Gen._alloca_entry(ir.IntType(32), name="pending_ret_flag") - pending_ret_val = Gen._alloca_entry(ir.IntType(32), name="pending_ret_val") if Gen.func.type.pointee.return_type == ir.IntType(32) else None - Gen.eh_finally_stack.append((FinallyBB, pending_ret_flag, pending_ret_val)) - Gen.builder.branch(FinallyBB) - Gen.builder.position_at_start(FinallyBB) - Gen._store(ir.Constant(ir.IntType(32), 0), pending_ret_flag) - self.HandleBodyLlvm(Node.finalbody) - if Gen.eh_finally_stack: - _, pending_ret_flag, pending_ret_val = Gen.eh_finally_stack[-1] - Gen.eh_finally_stack.pop() - ret_flag_val = Gen._load(pending_ret_flag, name="load_ret_flag") - ret_flag_is_set = Gen.builder.icmp_signed('!=', ret_flag_val, ir.Constant(ir.IntType(32), 0), name="check_ret_flag") - RetBB = Gen.func.append_basic_block(name="finally.ret") - ContinueBB = Gen.func.append_basic_block(name="try.continue") - Gen.builder.cbranch(ret_flag_is_set, RetBB, ContinueBB) - Gen.builder.position_at_start(RetBB) - if pending_ret_val: - ret_val = Gen._load(pending_ret_val, name="load_ret_val") - Gen.builder.ret(ret_val) - else: - Gen.builder.ret_void() +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle, EXCEPTION_CODE_MAP +import ast +import llvmlite.ir as ir + + +class TryHandle(BaseHandle): + def _get_exception_type_code(self, type_node): + if isinstance(type_node, ast.Name): + name = type_node.id + if name in EXCEPTION_CODE_MAP: + return EXCEPTION_CODE_MAP[name] + if name in self.Trans.exception_registry: + return self.Trans.exception_registry[name] + return 1 + if isinstance(type_node, ast.Attribute): + name = type_node.attr + if name in EXCEPTION_CODE_MAP: + return EXCEPTION_CODE_MAP[name] + if name in self.Trans.exception_registry: + return self.Trans.exception_registry[name] + return 1 + if isinstance(type_node, ast.Tuple): + for elt in type_node.elts: + code = self._get_exception_type_code(elt) + if code != 1: + return code + return 1 + return 1 + + def _get_exception_name(self, type_node): + if isinstance(type_node, ast.Name): + return type_node.id + if isinstance(type_node, ast.Attribute): + return type_node.attr + return None + + def _get_all_match_codes(self, type_node): + name = self._get_exception_name(type_node) + if name is None: + return [self._get_exception_type_code(type_node)] + if name not in self.Trans.exception_registry: + return [self._get_exception_type_code(type_node)] + codes = [self.Trans.exception_registry[name]] + self._collect_descendant_codes(name, codes) + return codes + + def _collect_descendant_codes(self, parent_name, codes): + for child_name, parent in self.Trans.exception_parents.items(): + if parent == parent_name: + child_code = self.Trans.exception_registry.get(child_name) + if child_code is not None and child_code not in codes: + codes.append(child_code) + self._collect_descendant_codes(child_name, codes) + + def _HandleTryLlvm(self, Node): + Gen = self.Trans.LlvmGen + if not Gen.func: + return + exception_code = Gen._allocaEntry(ir.IntType(32), name="eh_code") + eh_message = Gen._allocaEntry(ir.PointerType(ir.IntType(8)), name="eh_message") + Gen._store(ir.Constant(ir.IntType(32), 0), exception_code) + Gen._store(ir.Constant(ir.PointerType(ir.IntType(8)), None), eh_message) + HasFinally = bool(Node.finalbody) + if HasFinally: + Gen.eh_finally_stack.append((None, None, None)) + else: + Gen.eh_finally_stack.append(None) + DispatchBB = Gen.func.append_basic_block(name="try.dispatch") + AfterBB = Gen.func.append_basic_block(name="try.after") + except_blocks = [] + for i, handler in enumerate(Node.handlers): + ExcTypeCodes = [1] + if handler.type: + ExcTypeCodes = self._get_all_match_codes(handler.type) + ExceptBB = Gen.func.append_basic_block(name=f"try.except_{i}") + Gen.eh_except_block_stack.append((DispatchBB, None, exception_code, eh_message)) + except_blocks.append((ExceptBB, ExcTypeCodes, handler)) + TryBB = Gen.func.append_basic_block(name="try.body") + ElseBB = None + if Node.orelse: + ElseBB = Gen.func.append_basic_block(name="try.else") + Gen.builder.branch(TryBB) + Gen.builder.position_at_start(TryBB) + self.HandleBodyLlvm(Node.body) + if not Gen.builder.block.is_terminated: + Gen._store(ir.Constant(ir.IntType(32), 0), exception_code) + if ElseBB: + Gen.builder.branch(ElseBB) + else: + Gen.builder.branch(AfterBB) + Gen.builder.position_at_start(DispatchBB) + eh_code_val = Gen._load(exception_code, name="Load_eh_code") + next_check_bb = None + handler_var_map = {} + UnhandledBB = Gen.func.append_basic_block(name="try.unhandled") + for i, (ExceptBB, ExcTypeCodes, handler) in enumerate(except_blocks): + MatchBB = Gen.func.append_basic_block(name=f"try.match_{i}") + if i > 0 and next_check_bb is not None: + Gen.builder.position_at_start(next_check_bb) + eh_code_val = Gen._load(exception_code, name=f"Load_eh_code_{i}") + if handler.type is None: + Gen.builder.branch(MatchBB) + else: + match_cond = None + for code in ExcTypeCodes: + is_code_match = Gen.builder.icmp_signed('==', eh_code_val, ir.Constant(ir.IntType(32), code), name=f"eh_match_{i}_c{code}") + if match_cond is None: + match_cond = is_code_match + else: + match_cond = Gen.builder.or_(match_cond, is_code_match, name=f"eh_match_any_{i}") + if i < len(except_blocks) - 1: + next_check_bb = Gen.func.append_basic_block(name=f"try.check_{i}") + else: + next_check_bb = UnhandledBB + Gen.builder.cbranch(match_cond, MatchBB, next_check_bb) + Gen.builder.position_at_start(MatchBB) + if handler.name: + var_alloca = Gen._allocaEntry(ir.IntType(8).as_pointer(), name=handler.name) + eh_msg_val = Gen._load(eh_message, name=f"Load_eh_msg_{handler.name}") + Gen._store(eh_msg_val, var_alloca) + handler_var_map[i] = (handler.name, var_alloca, Gen.variables.get(handler.name)) + Gen.builder.branch(ExceptBB) + Gen.builder.position_at_start(UnhandledBB) + eh_msg_out_arg = None + eh_code_out_arg = None + if Gen.func and len(Gen.func.args) > 0: + for arg in Gen.func.args: + if arg.name == '__eh_msg_out__': + eh_msg_out_arg = arg + elif arg.name == '__eh_code_out__': + eh_code_out_arg = arg + if eh_msg_out_arg is not None and eh_code_out_arg is not None: + eh_msg_val = Gen._load(eh_message, name="Load_eh_msg_propagate") + eh_code_val_prop = Gen._load(exception_code, name="Load_eh_code_propagate") + Gen._store(eh_msg_val, eh_msg_out_arg) + Gen._store(eh_code_val_prop, eh_code_out_arg) + ret_type = getattr(Gen.func, 'ftype', None) and Gen.func.ftype.return_type if getattr(Gen, 'func', None) else None + if isinstance(ret_type, ir.IdentifiedStructType): + if ret_type.elements: + zero_val = ir.Constant(ret_type, [ + ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)) + else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType)) + else ir.Constant(et, ir.Undefined) for et in ret_type.elements]) + else: + zero_val = ir.Constant(ret_type, None) + Gen.builder.ret(zero_val) + elif isinstance(ret_type, ir.PointerType): + Gen.builder.ret(ir.Constant(ret_type, None)) + elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)): + Gen.builder.ret(ir.Constant(ret_type, 0.0)) + elif isinstance(ret_type, ir.IntType): + Gen.builder.ret(ir.Constant(ret_type, 1)) + elif isinstance(ret_type, ir.VoidType): + Gen.builder.ret_void() + else: + Gen.builder.ret(ir.Constant(ir.IntType(32), 1)) + else: + Gen._store(ir.Constant(ir.IntType(32), 0), exception_code) + Gen.builder.branch(AfterBB) + for idx, (ExceptBB, ExcTypeCodes, handler) in enumerate(except_blocks): + Gen.builder.position_at_start(ExceptBB) + old_var = None + if idx in handler_var_map: + hname, var_alloca, old_var = handler_var_map[idx] + Gen.variables[hname] = var_alloca + self.HandleBodyLlvm(handler.body) + if idx in handler_var_map: + hname, _, old_var = handler_var_map[idx] + if old_var is not None: + Gen.variables[hname] = old_var + elif hname in Gen.variables: + del Gen.variables[hname] + if not Gen.builder.block.is_terminated: + Gen.builder.branch(AfterBB) + Gen.eh_except_block_stack.pop() + if ElseBB: + Gen.builder.position_at_start(ElseBB) + self.HandleBodyLlvm(Node.orelse) + if not Gen.builder.block.is_terminated: + Gen.builder.branch(AfterBB) + Gen.builder.position_at_start(AfterBB) + if HasFinally: + Gen.eh_finally_stack.pop() + if Node.finalbody: + FinallyBB = Gen.func.append_basic_block(name="try.finally") + pending_ret_flag = Gen._allocaEntry(ir.IntType(32), name="pending_ret_flag") + pending_ret_val = Gen._allocaEntry(ir.IntType(32), name="pending_ret_val") if Gen.func.type.pointee.return_type == ir.IntType(32) else None + Gen.eh_finally_stack.append((FinallyBB, pending_ret_flag, pending_ret_val)) + Gen.builder.branch(FinallyBB) + Gen.builder.position_at_start(FinallyBB) + Gen._store(ir.Constant(ir.IntType(32), 0), pending_ret_flag) + self.HandleBodyLlvm(Node.finalbody) + if Gen.eh_finally_stack: + _, pending_ret_flag, pending_ret_val = Gen.eh_finally_stack[-1] + Gen.eh_finally_stack.pop() + ret_flag_val = Gen._load(pending_ret_flag, name="Load_ret_flag") + ret_flag_is_set = Gen.builder.icmp_signed('!=', ret_flag_val, ir.Constant(ir.IntType(32), 0), name="check_ret_flag") + RetBB = Gen.func.append_basic_block(name="finally.ret") + ContinueBB = Gen.func.append_basic_block(name="try.continue") + Gen.builder.cbranch(ret_flag_is_set, RetBB, ContinueBB) + Gen.builder.position_at_start(RetBB) + if pending_ret_val: + ret_val = Gen._load(pending_ret_val, name="Load_ret_val") + Gen.builder.ret(ret_val) + else: + Gen.builder.ret_void() Gen.builder.position_at_start(ContinueBB) \ No newline at end of file diff --git a/lib/core/Handles/HandlesTypeMerge.py b/lib/core/Handles/HandlesTypeMerge.py index 09ccf98..cf9f676 100644 --- a/lib/core/Handles/HandlesTypeMerge.py +++ b/lib/core/Handles/HandlesTypeMerge.py @@ -113,7 +113,7 @@ class HandlesTypeMerge(BaseHandle): # 解析 import 别名: 如 import fat32_types as types -> types -> fat32_types if ModulePath: - import_aliases = getattr(self.Trans, '_import_aliases', {}) + import_aliases = getattr(self.Trans, '_ImportAliases', {}) if ModulePath in import_aliases: ModulePath = import_aliases[ModulePath] else: diff --git a/lib/core/Handles/HandlesWhile.py b/lib/core/Handles/HandlesWhile.py index aecbbd8..754b026 100644 --- a/lib/core/Handles/HandlesWhile.py +++ b/lib/core/Handles/HandlesWhile.py @@ -1,54 +1,54 @@ -from __future__ import annotations -from typing import TYPE_CHECKING -if TYPE_CHECKING: - from lib.core.translator import Translator -from lib.core.Handles.HandlesBase import BaseHandle -import llvmlite.ir as ir - - -class WhileHandle(BaseHandle): - def _HandleWhileLlvm(self, Node): - Gen = self.Trans.LlvmGen - if Gen._direct_values: - for var_name in list(Gen._direct_values.keys()): - OldVal = Gen._direct_values.pop(var_name) - if var_name not in Gen.variables or Gen.variables.get(var_name) is None: - saved_block = Gen.builder.block - entry_block = Gen.func.entry_basic_block - Gen.builder.position_at_start(entry_block) - var = Gen.builder.alloca(OldVal.type, name=var_name) - Gen._store(OldVal, var) - Gen.builder.position_at_end(saved_block) - Gen.variables[var_name] = var - CondBB = Gen.func.append_basic_block(name="while.cond") - BodyBB = Gen.func.append_basic_block(name="while.body") - ElseBB = Gen.func.append_basic_block(name="while.else") if Node.orelse else None - AfterBB = Gen.func.append_basic_block(name="while.end") - Gen.loop_break_targets.append(AfterBB) - Gen.loop_continue_targets.append(CondBB) - Gen.builder.branch(CondBB) - Gen.builder.position_at_start(CondBB) - Cond = self.HandleExprLlvm(Node.test) - if Cond: - if not isinstance(Cond.type, ir.IntType) or Cond.type.width != 1: - if isinstance(Cond.type, (ir.FloatType, ir.DoubleType)): - Cond = Gen.builder.fcmp_ordered('!=', Cond, ir.Constant(Cond.type, 0.0), name="whilecond") - else: - Cond = Gen.builder.icmp_signed('!=', Cond, Gen._zero_const(Cond.type), name="whilecond") - if not Gen.builder.block.is_terminated: - Gen.builder.cbranch(Cond, BodyBB, ElseBB if ElseBB else AfterBB) - else: - if not Gen.builder.block.is_terminated: - Gen.builder.branch(ElseBB if ElseBB else AfterBB) - Gen.builder.position_at_start(BodyBB) - self.HandleBodyLlvm(Node.body) - if not Gen.builder.block.is_terminated: - Gen.builder.branch(CondBB) - Gen.loop_break_targets.pop() - Gen.loop_continue_targets.pop() - if ElseBB: - Gen.builder.position_at_start(ElseBB) - self.HandleBodyLlvm(Node.orelse) - if not Gen.builder.block.is_terminated: - Gen.builder.branch(AfterBB) - Gen.builder.position_at_start(AfterBB) +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle +import llvmlite.ir as ir + + +class WhileHandle(BaseHandle): + def _HandleWhileLlvm(self, Node): + Gen = self.Trans.LlvmGen + if Gen._direct_values: + for var_name in list(Gen._direct_values.keys()): + OldVal = Gen._direct_values.pop(var_name) + if var_name not in Gen.variables or Gen.variables.get(var_name) is None: + saved_block = Gen.builder.block + entry_block = Gen.func.entry_basic_block + Gen.builder.position_at_start(entry_block) + var = Gen.builder.alloca(OldVal.type, name=var_name) + Gen._store(OldVal, var) + Gen.builder.position_at_end(saved_block) + Gen.variables[var_name] = var + CondBB = Gen.func.append_basic_block(name="while.cond") + BodyBB = Gen.func.append_basic_block(name="while.body") + ElseBB = Gen.func.append_basic_block(name="while.else") if Node.orelse else None + AfterBB = Gen.func.append_basic_block(name="while.end") + Gen.loop_break_targets.append(AfterBB) + Gen.loop_continue_targets.append(CondBB) + Gen.builder.branch(CondBB) + Gen.builder.position_at_start(CondBB) + Cond = self.HandleExprLlvm(Node.test) + if Cond: + if not isinstance(Cond.type, ir.IntType) or Cond.type.width != 1: + if isinstance(Cond.type, (ir.FloatType, ir.DoubleType)): + Cond = Gen.builder.fcmp_ordered('!=', Cond, ir.Constant(Cond.type, 0.0), name="whilecond") + else: + Cond = Gen.builder.icmp_signed('!=', Cond, Gen._ZeroConst(Cond.type), name="whilecond") + if not Gen.builder.block.is_terminated: + Gen.builder.cbranch(Cond, BodyBB, ElseBB if ElseBB else AfterBB) + else: + if not Gen.builder.block.is_terminated: + Gen.builder.branch(ElseBB if ElseBB else AfterBB) + Gen.builder.position_at_start(BodyBB) + self.HandleBodyLlvm(Node.body) + if not Gen.builder.block.is_terminated: + Gen.builder.branch(CondBB) + Gen.loop_break_targets.pop() + Gen.loop_continue_targets.pop() + if ElseBB: + Gen.builder.position_at_start(ElseBB) + self.HandleBodyLlvm(Node.orelse) + if not Gen.builder.block.is_terminated: + Gen.builder.branch(AfterBB) + Gen.builder.position_at_start(AfterBB) diff --git a/lib/core/Handles/HandlesWith.py b/lib/core/Handles/HandlesWith.py index f6eae1d..1b1fc34 100644 --- a/lib/core/Handles/HandlesWith.py +++ b/lib/core/Handles/HandlesWith.py @@ -1,138 +1,138 @@ -from __future__ import annotations -from typing import TYPE_CHECKING -if TYPE_CHECKING: - from lib.core.translator import Translator -from lib.core.Handles.HandlesBase import BaseHandle -import ast -import llvmlite.ir as ir - - -class WithHandle(BaseHandle): - def _HandleWithLlvm(self, Node): - Gen = self.Trans.LlvmGen - for item in Node.items: - context_expr = item.context_expr - asname = None - target = getattr(item, 'optional_vars', getattr(item, 'target', getattr(item, 'asname', None))) - if target and isinstance(target, ast.Name): - asname = target.id - ClassName = None - if isinstance(context_expr, ast.Call): - if isinstance(context_expr.func, ast.Name): - ClassName = context_expr.func.id - elif isinstance(context_expr.func, ast.Attribute): - ClassName = context_expr.func.attr - if ClassName and ClassName not in Gen.structs: - if ClassName in self.Trans.SymbolTable: - SymInfo = self.Trans.SymbolTable[ClassName] - if getattr(SymInfo, 'IsStruct', False) or getattr(SymInfo, 'IsRenum', False): - pass - else: - ClassName = None - else: - ClassName = None - elif isinstance(context_expr, ast.Name): - VarName = context_expr.id - if VarName in Gen.var_struct_class: - ClassName = Gen.var_struct_class[VarName] - ctx_val = self.HandleExprLlvm(context_expr) - if not ctx_val: - continue - original_ctx_val = ctx_val - if ClassName and isinstance(ctx_val.type, ir.PointerType): - pointee = ctx_val.type.pointee - if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): - found = Gen.find_struct_by_pointee(pointee) - if found: - CN, ST = found - ClassName = CN - StructPtrType = ir.PointerType(Gen.structs[ClassName]) if ClassName and ClassName in Gen.structs else None - if StructPtrType and isinstance(ctx_val.type, ir.PointerType) and ctx_val.type.pointee != Gen.structs.get(ClassName): - ctx_val = Gen.builder.bitcast(ctx_val, StructPtrType, name="cast_with_ctx") - ctx_alloca = Gen._alloca_entry(ctx_val.type, name="__with_ctx") - Gen._store(ctx_val, ctx_alloca) - Gen._unregister_temp_ptr(ctx_val) - if ClassName: - Gen.var_struct_class['__with_ctx'] = ClassName - Gen._var_to_heap_ptr['__with_ctx'] = ctx_val - original_asname_heap_ptr = Gen._var_to_heap_ptr.get(asname) if asname else None - ctx_is_var_ref = isinstance(context_expr, ast.Name) - enter_result = None - if ClassName: - EnterFuncName = f'{ClassName}.__enter__' - if EnterFuncName in Gen.functions: - ctx_loaded = Gen._load(ctx_alloca, name="__with_ctx") - enter_call = Gen.builder.call(Gen.functions[EnterFuncName], [ctx_loaded], name="call_enter") - enter_result = enter_call - if isinstance(enter_call.type, ir.PointerType): - pointee = enter_call.type.pointee - if isinstance(pointee, ir.PointerType) and isinstance(pointee.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): - enter_result = Gen._load(enter_call, name="enter_deref") - elif self._is_char_pointer(enter_call) and StructPtrType: - enter_result = Gen.builder.bitcast(enter_call, StructPtrType, name="cast_enter") - if asname and enter_result: - if isinstance(enter_result.type, ir.PointerType) and isinstance(enter_result.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): - found = Gen.find_struct_by_pointee(enter_result.type.pointee) - if found: - CN, ST = found - Gen.var_struct_class[asname] = CN - Gen._var_to_heap_ptr[asname] = enter_result - Gen._register_local_heap_ptr(enter_result, VarName=asname) - if asname in Gen._reg_values: - OldVal = Gen._reg_values[asname] - var = Gen._alloca_entry(OldVal.type, name=asname) - Gen._store(OldVal, var) - Gen.variables[asname] = var - del Gen._reg_values[asname] - if asname in Gen.variables and Gen.variables[asname] is not None: - VarPtr = Gen.variables[asname] - if VarPtr.type.pointee == enter_result.type: - Gen._store(enter_result, VarPtr) - elif isinstance(VarPtr.type.pointee, ir.PointerType) and isinstance(enter_result.type, ir.PointerType): - CastedVal = Gen.builder.bitcast(enter_result, VarPtr.type.pointee, name=f"cast_{asname}") - Gen._store(CastedVal, VarPtr) - else: - NewVar = Gen._alloca(enter_result.type, name=asname) - Gen._store(enter_result, NewVar) - Gen.variables[asname] = NewVar - else: - Gen._reg_values[asname] = enter_result - Gen.variables[asname] = None - self.Trans.VarScopes.append({}) - if asname: - self.Trans.VarScopes[-1][asname] = True - self.HandleBodyLlvm(Node.body) - if self.Trans.VarScopes: - self.Trans.VarScopes.pop() - if ClassName: - ExitFuncName = f'{ClassName}.__exit__' - if ExitFuncName in Gen.functions: - ctx_loaded = Gen._load(ctx_alloca, name="__with_ctx") - Gen.builder.call(Gen.functions[ExitFuncName], [ctx_loaded], name="call_exit") - Gen._unregister_local_heap_ptr(original_ctx_val) - if ctx_val is not original_ctx_val: - Gen._unregister_local_heap_ptr(ctx_val) - if ctx_is_var_ref and original_asname_heap_ptr and original_asname_heap_ptr is not original_ctx_val and original_asname_heap_ptr is not ctx_val: - Gen._unregister_local_heap_ptr(original_asname_heap_ptr) - if '__with_ctx' in Gen._var_to_heap_ptr: - del Gen._var_to_heap_ptr['__with_ctx'] - if asname and enter_result is not None and isinstance(ctx_val.type, ir.PointerType) and isinstance(enter_result.type, ir.PointerType): - ctx_int = Gen.builder.ptrtoint(ctx_val, ir.IntType(64), name="ctx_int") - enter_int = Gen.builder.ptrtoint(enter_result, ir.IntType(64), name="enter_int") - same_ptr = Gen.builder.icmp_unsigned('==', ctx_int, enter_int, name="same_ptr_check") - with_free_bb = Gen.func.append_basic_block("with_free_ctx") - with_skip_bb = Gen.func.append_basic_block("with_skip_free") - Gen.builder.cbranch(same_ptr, with_skip_bb, with_free_bb) - Gen.builder.position_at_start(with_free_bb) - raw = Gen.builder.bitcast(ctx_val, ir.PointerType(ir.IntType(8)), name="with_free_cast") - free_func = Gen.get_or_declare_c_func('free', ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))])) - Gen.builder.call(free_func, [raw]) - Gen.builder.branch(with_skip_bb) - Gen.builder.position_at_start(with_skip_bb) - Gen._unregister_local_heap_ptr(enter_result) - Gen._unregister_local_heap_ptr(original_ctx_val) - elif isinstance(ctx_val.type, ir.PointerType): - raw = Gen.builder.bitcast(ctx_val, ir.PointerType(ir.IntType(8)), name="with_free_cast") - free_func = Gen.get_or_declare_c_func('free', ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))])) - Gen.builder.call(free_func, [raw]) +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle +import ast +import llvmlite.ir as ir + + +class WithHandle(BaseHandle): + def _HandleWithLlvm(self, Node): + Gen = self.Trans.LlvmGen + for item in Node.items: + context_expr = item.context_expr + asname = None + target = getattr(item, 'optional_vars', getattr(item, 'target', getattr(item, 'asname', None))) + if target and isinstance(target, ast.Name): + asname = target.id + ClassName = None + if isinstance(context_expr, ast.Call): + if isinstance(context_expr.func, ast.Name): + ClassName = context_expr.func.id + elif isinstance(context_expr.func, ast.Attribute): + ClassName = context_expr.func.attr + if ClassName and ClassName not in Gen.structs: + if ClassName in self.Trans.SymbolTable: + SymInfo = self.Trans.SymbolTable[ClassName] + if getattr(SymInfo, 'IsStruct', False) or getattr(SymInfo, 'IsRenum', False): + pass + else: + ClassName = None + else: + ClassName = None + elif isinstance(context_expr, ast.Name): + VarName = context_expr.id + if VarName in Gen.var_struct_class: + ClassName = Gen.var_struct_class[VarName] + ctx_val = self.HandleExprLlvm(context_expr) + if not ctx_val: + continue + original_ctx_val = ctx_val + if ClassName and isinstance(ctx_val.type, ir.PointerType): + pointee = ctx_val.type.pointee + if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): + found = Gen.find_struct_by_pointee(pointee) + if found: + CN, ST = found + ClassName = CN + StructPtrType = ir.PointerType(Gen.structs[ClassName]) if ClassName and ClassName in Gen.structs else None + if StructPtrType and isinstance(ctx_val.type, ir.PointerType) and ctx_val.type.pointee != Gen.structs.get(ClassName): + ctx_val = Gen.builder.bitcast(ctx_val, StructPtrType, name="cast_with_ctx") + ctx_alloca = Gen._allocaEntry(ctx_val.type, name="__with_ctx") + Gen._store(ctx_val, ctx_alloca) + Gen._UnregisterTempPtr(ctx_val) + if ClassName: + Gen.var_struct_class['__with_ctx'] = ClassName + Gen._var_to_heap_ptr['__with_ctx'] = ctx_val + original_asname_heap_ptr = Gen._var_to_heap_ptr.get(asname) if asname else None + ctx_is_var_ref = isinstance(context_expr, ast.Name) + enter_result = None + if ClassName: + EnterFuncName = f'{ClassName}.__enter__' + if EnterFuncName in Gen.functions: + ctx_Loaded = Gen._load(ctx_alloca, name="__with_ctx") + enter_call = Gen.builder.call(Gen.functions[EnterFuncName], [ctx_Loaded], name="call_enter") + enter_result = enter_call + if isinstance(enter_call.type, ir.PointerType): + pointee = enter_call.type.pointee + if isinstance(pointee, ir.PointerType) and isinstance(pointee.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): + enter_result = Gen._load(enter_call, name="enter_deref") + elif self._is_char_pointer(enter_call) and StructPtrType: + enter_result = Gen.builder.bitcast(enter_call, StructPtrType, name="cast_enter") + if asname and enter_result: + if isinstance(enter_result.type, ir.PointerType) and isinstance(enter_result.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): + found = Gen.find_struct_by_pointee(enter_result.type.pointee) + if found: + CN, ST = found + Gen.var_struct_class[asname] = CN + Gen._var_to_heap_ptr[asname] = enter_result + Gen._register_local_heap_ptr(enter_result, VarName=asname) + if asname in Gen._reg_values: + OldVal = Gen._reg_values[asname] + var = Gen._allocaEntry(OldVal.type, name=asname) + Gen._store(OldVal, var) + Gen.variables[asname] = var + del Gen._reg_values[asname] + if asname in Gen.variables and Gen.variables[asname] is not None: + VarPtr = Gen.variables[asname] + if VarPtr.type.pointee == enter_result.type: + Gen._store(enter_result, VarPtr) + elif isinstance(VarPtr.type.pointee, ir.PointerType) and isinstance(enter_result.type, ir.PointerType): + CastedVal = Gen.builder.bitcast(enter_result, VarPtr.type.pointee, name=f"cast_{asname}") + Gen._store(CastedVal, VarPtr) + else: + NewVar = Gen._alloca(enter_result.type, name=asname) + Gen._store(enter_result, NewVar) + Gen.variables[asname] = NewVar + else: + Gen._reg_values[asname] = enter_result + Gen.variables[asname] = None + self.Trans.VarScopes.append({}) + if asname: + self.Trans.VarScopes[-1][asname] = True + self.HandleBodyLlvm(Node.body) + if self.Trans.VarScopes: + self.Trans.VarScopes.pop() + if ClassName: + ExitFuncName = f'{ClassName}.__exit__' + if ExitFuncName in Gen.functions: + ctx_Loaded = Gen._load(ctx_alloca, name="__with_ctx") + Gen.builder.call(Gen.functions[ExitFuncName], [ctx_Loaded], name="call_exit") + Gen._unregister_local_heap_ptr(original_ctx_val) + if ctx_val is not original_ctx_val: + Gen._unregister_local_heap_ptr(ctx_val) + if ctx_is_var_ref and original_asname_heap_ptr and original_asname_heap_ptr is not original_ctx_val and original_asname_heap_ptr is not ctx_val: + Gen._unregister_local_heap_ptr(original_asname_heap_ptr) + if '__with_ctx' in Gen._var_to_heap_ptr: + del Gen._var_to_heap_ptr['__with_ctx'] + if asname and enter_result is not None and isinstance(ctx_val.type, ir.PointerType) and isinstance(enter_result.type, ir.PointerType): + ctx_int = Gen.builder.ptrtoint(ctx_val, ir.IntType(64), name="ctx_int") + enter_int = Gen.builder.ptrtoint(enter_result, ir.IntType(64), name="enter_int") + same_ptr = Gen.builder.icmp_unsigned('==', ctx_int, enter_int, name="same_ptr_check") + with_free_bb = Gen.func.append_basic_block("with_free_ctx") + with_skip_bb = Gen.func.append_basic_block("with_skip_free") + Gen.builder.cbranch(same_ptr, with_skip_bb, with_free_bb) + Gen.builder.position_at_start(with_free_bb) + raw = Gen.builder.bitcast(ctx_val, ir.PointerType(ir.IntType(8)), name="with_free_cast") + free_func = Gen.get_or_declare_c_func('free', ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))])) + Gen.builder.call(free_func, [raw]) + Gen.builder.branch(with_skip_bb) + Gen.builder.position_at_start(with_skip_bb) + Gen._unregister_local_heap_ptr(enter_result) + Gen._unregister_local_heap_ptr(original_ctx_val) + elif isinstance(ctx_val.type, ir.PointerType): + raw = Gen.builder.bitcast(ctx_val, ir.PointerType(ir.IntType(8)), name="with_free_cast") + free_func = Gen.get_or_declare_c_func('free', ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))])) + Gen.builder.call(free_func, [raw]) Gen._unregister_local_heap_ptr(original_ctx_val) \ No newline at end of file diff --git a/lib/core/Handles/__init__.py b/lib/core/Handles/__init__.py index ba56367..b7c469e 100644 --- a/lib/core/Handles/__init__.py +++ b/lib/core/Handles/__init__.py @@ -27,6 +27,6 @@ from .HandlesTry import TryHandle from .HandlesAssert import AssertHandle from .HandlesRaise import RaiseHandle from .HandlesMatch import MatchHandle -from .HandlesClassDef import ClassHandle +from .HandlesClassDef import ClassHandle from .HandlesFunctions import FunctionHandle -from .HandlesImports import ImportHandle +from .HandlesImports import ImportHandle diff --git a/lib/core/LLVMCG/BaseGen.py b/lib/core/LLVMCG/BaseGen.py new file mode 100644 index 0000000..e944925 --- /dev/null +++ b/lib/core/LLVMCG/BaseGen.py @@ -0,0 +1,412 @@ +from __future__ import annotations +import re +import ast +import os +import hashlib +import llvmlite.ir as ir +from llvmlite.ir.values import _Undefined + + +class VaArgInstruction(ir.Instruction): + def descr(self, buf): + ptr = self.operands[0] + buf.append("va_arg {0} {1}, {2}\n".format( + ptr.type, ptr.get_reference(), self.type)) + + +class BaseGenMixin: + + @staticmethod + def _parse_triple(triple): + """解析目标三元组,返回平台信息字典""" + info = { + 'is_windows': False, 'is_linux': False, 'is_macos': False, + 'is_x86_64': False, 'is_arm64': False, 'is_32bit': False, + 'ptr_size': 8, 'long_size': 8, 'wchar_t_size': 32, + } + if not triple: + return info + triple_lower = triple.lower() + # 检测操作系统 + if 'windows' in triple_lower or 'win32' in triple_lower or 'mingw' in triple_lower or 'msvc' in triple_lower or 'cygwin' in triple_lower: + info['is_windows'] = True + # Windows LLP64: long = 32 位, wchar_t = 16 位 + info['long_size'] = 32 + info['wchar_t_size'] = 16 + elif 'linux' in triple_lower: + info['is_linux'] = True + elif 'darwin' in triple_lower or 'macos' in triple_lower or 'apple' in triple_lower: + info['is_macos'] = True + # 检测架构 + if 'x86_64' in triple_lower or 'amd64' in triple_lower or 'x64' in triple_lower: + info['is_x86_64'] = True + elif 'aarch64' in triple_lower or 'arm64' in triple_lower: + info['is_arm64'] = True + elif 'i386' in triple_lower or 'i686' in triple_lower or 'arm' in triple_lower: + info['is_32bit'] = True + info['ptr_size'] = 4 + info['long_size'] = 32 + if info['is_windows']: + info['wchar_t_size'] = 16 + else: + info['wchar_t_size'] = 32 + return info + + def __init__(self, triple=None, datalayout=None): + self.module = ir.Module(name="transpyc_module") + if triple: + self.module.triple = triple + else: + self.module.triple = "x86_64-none-elf" + if datalayout: + self.module.data_layout = datalayout + else: + self.module.data_layout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + + # 解析目标平台信息 + self._platform_info = self._parse_triple(self.module.triple) + self.ptr_size = self._platform_info['ptr_size'] + # 根据目标平台配置 t 模块中的平台相关类型大小 + import t as _t + _t.configure_platform(self.module.triple) + self.builder = None + self.func = None + self.functions = {} + self.variables = {} + self._direct_values = {} + self._reg_values = {} + self.var_signedness = {} + self._unsigned_results = {} + self.string_const_counter = 0 + self.Vtables = {} + self.class_methods = {} + self.class_members = {} + self.class_member_defaults = {} + self.class_member_signeds = {} + self.class_member_bitfields = {} + self.class_member_byteorders = {} + self.class_member_element_class = {} + self.class_member_bitoffsets = {} + self.structs = {} + self.typedef_int_widths = {} # typedef名称 -> 底层整数位宽 (如 'UINT' -> 32, 'BYTE' -> 8) + self._cross_module_vtable_classes = set() + self.class_vtable = set() + self.class_parent = {} + # Store member annotations for deferred type resolution (cross-module class references) + self.class_member_annotations = {} + self.loop_break_targets = [] + self.loop_continue_targets = [] + self.eh_jmp_buf_stack = [] + self.eh_except_block_stack = [] + self.eh_finally_stack = [] + self.global_vars = set() + self.nonlocal_params = {} + self._variable_scope_stack = [] # Stack of outer scope variables for nested function nonlocal lookup + self.var_struct_class = {} + self.global_struct_class = {} + self.var_type_info = {} + self.var_const_flags = {} + self._current_source_file = None + self._current_source_lines = [] + self._ns_cache = {} + self._type_cache = {} + self._typedef_cache = {} + self._func_sig_cache = {} + self.var_type_assignments = {} + self._temp_struct_ptrs = [] + self._stop_iter_flag_param = None + self._local_heap_ptrs = [] + self._var_to_heap_ptr = {} + self.known_return_types = {} + self._current_lineno = 0 + self._current_node_info = "" + self.module_sha1 = None + self.ModuleSha1Map = {} + self._temp_dir = None + self._export_funcs = set() + self._export_extern_funcs = set() + self._current_module_func_names = set() + self.class_packed = set() + self._define_constants = {} + pi = self._platform_info + # 根据目标平台设置宏(声明式,从三元组推导) + if pi['is_windows']: + self._define_constants['_WIN32'] = 1 + if not pi['is_32bit']: + self._define_constants['_WIN64'] = 1 + self._define_constants['WIN64'] = 1 + self._define_constants['WIN32'] = 1 + if pi['is_linux']: + self._define_constants['__linux__'] = 1 + if pi['is_macos']: + self._define_constants['__APPLE__'] = 1 + self._define_constants['__MACH__'] = 1 + if pi['is_x86_64']: + self._define_constants['__x86_64__'] = 1 + self._define_constants['__x86_64'] = 1 + self._define_constants['_M_X64'] = 1 + elif pi['is_arm64']: + self._define_constants['__aarch64__'] = 1 + self._define_constants['_M_ARM64'] = 1 + if not pi['is_32bit'] and pi['is_linux']: + self._define_constants['__LP64__'] = 1 + elif pi['is_32bit']: + self._define_constants['_ILP32'] = 1 + self._define_constants['SIZEOF_VOID_P'] = pi['ptr_size'] + self._define_constants['__SIZEOF_POINTER__'] = pi['ptr_size'] + + def find_struct_by_pointee(self, pointee): + """根据 pointee 类型查找匹配的结构体,返回 (class_name, struct_type) 或 None""" + for class_name, struct_type in self.structs.items(): + if pointee == struct_type: + return (class_name, struct_type) + return None + + def _get_or_create_struct(self, name, source_sha1=None, packed=False): + clean_name = name.replace(' *', '').replace('*', '').replace(' ', '_').replace('const', 'const_').replace('volatile', 'volatile_') + if clean_name in self.structs: + existing = self.structs[clean_name] + if packed and isinstance(existing, ir.IdentifiedStructType) and not existing.packed: + existing.packed = True + return existing + if clean_name in {'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum', 'Void', 'void'}: + return ir.IntType(8) + if hasattr(self, 'SymbolTable') and self.SymbolTable and clean_name in self.SymbolTable: + Entry = self.SymbolTable[clean_name] + if hasattr(Entry, 'IsTypedef') and Entry.IsTypedef: + resolved_str = self._resolve_typedef(clean_name) + if resolved_str != clean_name: + return self._type_str_to_llvm(resolved_str) + if hasattr(Entry, 'BaseType') and Entry.BaseType: + from lib.includes import t as _t + if not isinstance(Entry.BaseType, (_t._CTypedef,)) or getattr(Entry, 'PtrCount', 0) > 0: + resolved = self._resolve_ctype_to_str(Entry) + if resolved: + return self._type_str_to_llvm(resolved) + if hasattr(Entry, 'IsRenum') and Entry.IsRenum: + if clean_name in self.structs: + return self.structs[clean_name] + if hasattr(Entry, 'IsEnum') and Entry.IsEnum: + return ir.IntType(32) + if hasattr(Entry, 'IsExceptionClass') and Entry.IsExceptionClass: + return ir.IntType(32) + if hasattr(Entry, 'BaseType'): + from lib.includes import t as _t + if isinstance(Entry.BaseType, type) and issubclass(Entry.BaseType, _t.CEnum): + return ir.IntType(32) + if Entry.BaseType is _t.CEnum: + return ir.IntType(32) + if source_sha1: + ns_name = f"{source_sha1}.{clean_name}" + elif hasattr(self, '_struct_sha1_map') and clean_name in self._struct_sha1_map: + ns_name = f"{self._struct_sha1_map[clean_name]}.{clean_name}" + else: + ns_name = self._mangle_name(clean_name) + st = ir.IdentifiedStructType(self.module, name=ns_name, packed=packed) + self.structs[clean_name] = st + # 尝试解析 typedef 的底层整数位宽 + width = self._resolve_typedef_int_width(clean_name) + if width is not None: + self.typedef_int_widths[clean_name] = width + return st + + def _resolve_typedef_int_width(self, name: str): + """解析 typedef 名称的底层整数位宽 + + 通过 CTypeRegistry 和 BuiltinTypeMap 动态解析, + 替代硬编码的 TYPEDEF_NAMES 映射表。 + 返回 int 位宽或 None(无法解析)。 + """ + from lib.includes.t import CTypeRegistry + from lib.core.Handles.HandlesBase import BuiltinTypeMap + + # 1. 先查 BuiltinTypeMap(覆盖 BYTEPTR 等指针别名) + bm = BuiltinTypeMap.Get(name) + if bm: + ctype_cls, ptr_count = bm + if ptr_count > 0: + return None # 指针类型,不是整数 typedef + llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls) + if llvm_str and llvm_str.startswith('i') and llvm_str[1:].isdigit(): + return int(llvm_str[1:]) + + # 2. 再查 SymbolTable(用户定义的 typedef) + if hasattr(self, 'SymbolTable') and self.SymbolTable and name in self.SymbolTable: + Entry = self.SymbolTable[name] + if hasattr(Entry, 'IsTypedef') and Entry.IsTypedef: + if hasattr(Entry, 'BaseType') and Entry.BaseType: + from lib.includes import t as _t + if not isinstance(Entry.BaseType, (_t._CTypedef,)) and getattr(Entry, 'PtrCount', 0) == 0: + llvm_str = CTypeRegistry.CTypeToLLVM(type(Entry.BaseType) if isinstance(Entry.BaseType, _t.CType) else Entry.BaseType) + if llvm_str and llvm_str.startswith('i') and llvm_str[1:].isdigit(): + return int(llvm_str[1:]) + if hasattr(Entry, 'OriginalType') and Entry.OriginalType: + from lib.core.Handles.HandlesBase import CTypeInfo as _CTypeInfo + if isinstance(Entry.OriginalType, _CTypeInfo) and Entry.OriginalType.BaseType: + if not isinstance(Entry.OriginalType.BaseType, (_t._CTypedef,)) and getattr(Entry.OriginalType, 'PtrCount', 0) == 0: + llvm_str = CTypeRegistry.CTypeToLLVM(type(Entry.OriginalType.BaseType) if isinstance(Entry.OriginalType.BaseType, _t.CType) else Entry.OriginalType.BaseType) + if llvm_str and llvm_str.startswith('i') and llvm_str[1:].isdigit(): + return int(llvm_str[1:]) + + # 3. 尝试 CTypeRegistry 直接按名称查找 + ctype_cls = CTypeRegistry.GetClassByName(name) + if ctype_cls: + llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls) + if llvm_str and llvm_str.startswith('i') and llvm_str[1:].isdigit(): + return int(llvm_str[1:]) + + # 4. 特殊名称(非整数类型,但需要标记为 typedef 以跳过 opaque 定义) + _SPECIAL_TYPEDEFS = { + 'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion', + 'CStruct', 'enum', 'REnum', 'renum', + 'list', 'dict', 'tuple', 'set', 'str', 'bytes', 'array', 'type', + } + if name in _SPECIAL_TYPEDEFS: + return 0 # 标记为 typedef,但位宽为 0(非整数) + + return None + + def _set_node_info(self, node, extra_info=""): + if hasattr(node, 'lineno'): + self._current_lineno = node.lineno + else: + self._current_lineno = 0 + if hasattr(node, 'col_offset'): + self._current_node_info = f"line {self._current_lineno}, col {node.col_offset}" + else: + self._current_node_info = f"line {self._current_lineno}" + if extra_info: + self._current_node_info += f" ({extra_info})" + + def _set_source_info(self, filepath): + self._current_source_file = filepath + try: + with open(filepath, 'r', encoding='utf-8') as f: + self._current_source_lines = f.readlines() + except Exception: # 文件读取失败时回退为空行列表 + self._current_source_lines = [] + + def _ns_hash(self): + if 'workspace' in self._ns_cache: + return self._ns_cache['workspace'] + cwd = os.getcwd().replace('\\', '/').lower() + digest = hashlib.sha1(cwd.encode('utf-8')).hexdigest()[:12] + self._ns_cache['workspace'] = digest + return digest + + def _skip_mangle(self, name): + skip_prefixes = ('llvm.', 'str_const_', 'printf', 'memset_pattern') + if any(name.startswith(p) for p in skip_prefixes): + return True + if '.' in name: + parts = name.split('.', 1) + if len(parts[0]) >= 8 and all(c in '0123456789abcdef' for c in parts[0]): + return True + return False + + def _mangle_name(self, name): + if self._skip_mangle(name): + return name + if name in self._export_funcs: + return name + if self.module_sha1: + return f"{self.module_sha1}.{name}" + return name + + def _find_function(self, name): + if name in self.functions: + return self.functions[name] + g = self.module.globals.get(name) + if g and isinstance(g, ir.Function): + self.functions[name] = g + return g + mangled = self._mangle_func_name(name) + if mangled != name: + if mangled in self.functions: + self.functions[name] = self.functions[mangled] + return self.functions[mangled] + g = self.module.globals.get(mangled) + if g and isinstance(g, ir.Function): + self.functions[mangled] = g + self.functions[name] = g + return g + for sha1 in self.ModuleSha1Map.values(): + prefixed = f"{sha1}.{name}" + if prefixed in self.functions: + self.functions[name] = self.functions[prefixed] + return self.functions[prefixed] + g = self.module.globals.get(prefixed) + if g and isinstance(g, ir.Function): + self.functions[prefixed] = g + self.functions[name] = g + return g + return None + + def _has_function(self, name): + return self._find_function(name) is not None + + def _get_or_declare_function(self, mangled_name, func_type): + for g in self.module.globals: + if isinstance(g, ir.Function) and g.name == mangled_name: + return g + return ir.Function(self.module, func_type, name=mangled_name) + + def _get_function(self, name): + func = self._find_function(name) + return func + + def _mangle_func_name(self, name, module_name=None): + if name in self._export_funcs: + return name + if name in self._export_extern_funcs and name not in self._current_module_func_names: + return name + # main 函数作为程序入口点,永远不混淆 + if name == 'main': + return name + # Try class_sha1_map first for class methods (e.g., 'md5.__init__' -> class 'md5') + class_sha1_map = getattr(self, 'class_sha1_map', {}) + if class_sha1_map: + if '.' in name: + base_class = name.split('.')[0] + if base_class in class_sha1_map: + sha1 = class_sha1_map[base_class] + return f"{sha1}.{name}" + elif name in class_sha1_map: + sha1 = class_sha1_map[name] + return f"{sha1}.{name}" + # If module_name is already a SHA1 hash (16 hex chars), use it directly + if module_name and len(module_name) == 16 and all(c in '0123456789abcdef' for c in module_name): + return f"{module_name}.{name}" + if module_name and module_name in self.ModuleSha1Map: + sha1 = self.ModuleSha1Map[module_name] + return f"{sha1}.{name}" + # Try parent package name (e.g., 'hashlib' -> 'hashlib.__init__') + if module_name: + init_name = f"{module_name}.__init__" + if init_name in self.ModuleSha1Map: + sha1 = self.ModuleSha1Map[init_name] + return f"{sha1}.{name}" + if self._skip_mangle(name): + return name + if self.module_sha1: + return f"{self.module_sha1}.{name}" + return name + + def _get_source_line(self, lineno): + if 0 < lineno <= len(self._current_source_lines): + return self._current_source_lines[lineno - 1].rstrip('\r\n') + return None + + def _get_node_info(self): + info = "" + if self._current_node_info: + info = f" [{self._current_node_info}]" + if self._current_source_file: + info += f" in {self._current_source_file}" + lineno = self._current_lineno + if lineno > 0: + info += f", line {lineno}:" + source_line = self._get_source_line(lineno) + if source_line: + info += f"\n → {source_line}" + return info diff --git a/lib/core/LLVMCG/ExprGen.py b/lib/core/LLVMCG/ExprGen.py new file mode 100644 index 0000000..78202d4 --- /dev/null +++ b/lib/core/LLVMCG/ExprGen.py @@ -0,0 +1,353 @@ +from __future__ import annotations +import llvmlite.ir as ir + + +class ExprGenMixin: + def emit_constant(self, value, type_name='int'): + if type_name == 'int': + return ir.Constant(ir.IntType(32), int(value)) + elif type_name == 'uint64_t' or type_name == 'unsigned long long': + return ir.Constant(ir.IntType(64), int(value)) + elif type_name == 'uint32_t' or type_name == 'unsigned int': + return ir.Constant(ir.IntType(32), int(value)) + elif type_name == 'uint16_t' or type_name == 'unsigned short': + return ir.Constant(ir.IntType(16), int(value)) + elif type_name == 'uint8_t' or type_name == 'unsigned char': + return ir.Constant(ir.IntType(8), int(value)) + elif type_name == 'int64_t' or type_name == 'long long': + return ir.Constant(ir.IntType(64), int(value)) + elif type_name == 'int32_t' or type_name == 'int': + return ir.Constant(ir.IntType(32), int(value)) + elif type_name == 'int16_t' or type_name == 'short': + return ir.Constant(ir.IntType(16), int(value)) + elif type_name == 'int8_t' or type_name == 'char': + return ir.Constant(ir.IntType(8), int(value)) + elif type_name == 'float' or type_name == 'float32_t' or type_name == 'FLOAT32': + return ir.Constant(ir.FloatType(), float(value)) + elif type_name == 'double' or type_name == 'float64_t' or type_name == 'FLOAT64': + return ir.Constant(ir.DoubleType(), float(value)) + elif type_name == 'float16_t' or type_name == 'FLOAT16': + return ir.Constant(ir.IntType(16), int(value)) + elif type_name == 'float8_t' or type_name == 'FLOAT8': + return ir.Constant(ir.IntType(8), int(value)) + elif type_name == 'float128_t' or type_name == 'FLOAT128': + return ir.Constant(ir.IntType(128), int(value)) + elif type_name == 'string': + encoded = value.encode('utf-8') + b'\x00' + str_type = ir.ArrayType(ir.IntType(8), len(encoded)) + str_const = ir.Constant(str_type, bytearray(encoded)) + global_var = ir.GlobalVariable(self.module, str_type, name=f"str_const_{self.string_const_counter}") + self.string_const_counter += 1 + global_var.initializer = str_const + global_var.linkage = 'internal' + return self.builder.bitcast(global_var, ir.PointerType(ir.IntType(8)), name="str") + return ir.Constant(ir.IntType(32), int(value)) + + def emit_binary_op(self, op, left, right, is_unsigned=False): + # 处理指针和整数之间的类型转换 + if isinstance(left.type, ir.PointerType) and isinstance(right.type, ir.IntType): + right = self.builder.zext(right, ir.IntType(64), name="int2ptrint") + if op == '+' or op == 'Add': + return self.builder.gep(left, [right], name="ptr_add") + elif op == '-' or op == 'Sub': + return self.builder.gep(left, [self.builder.neg(right, name="neg")], name="ptr_sub") + if isinstance(left.type, ir.IntType) and isinstance(right.type, ir.PointerType): + left = self.builder.zext(left, ir.IntType(64), name="int2ptrint2") + if op == '+' or op == 'Add': + return self.builder.gep(right, [left], name="ptr_add_rev") + is_float = isinstance(left.type, (ir.FloatType, ir.DoubleType)) or \ + isinstance(right.type, (ir.FloatType, ir.DoubleType)) + if is_float: + if isinstance(left.type, (ir.FloatType, ir.DoubleType)): + ftype = left.type + elif isinstance(right.type, (ir.FloatType, ir.DoubleType)): + ftype = right.type + else: + ftype = ir.DoubleType() + if not isinstance(left.type, (ir.FloatType, ir.DoubleType)): + left = self._to_float(left, ftype) + elif left.type != ftype: + if isinstance(left.type, ir.FloatType) and isinstance(ftype, ir.DoubleType): + left = self.builder.fpext(left, ftype, name="fpext_l") + else: + left = self.builder.fptrunc(left, ftype, name="fptrunc_l") + if not isinstance(right.type, (ir.FloatType, ir.DoubleType)): + right = self._to_float(right, ftype) + elif right.type != ftype: + if isinstance(right.type, ir.FloatType) and isinstance(ftype, ir.DoubleType): + right = self.builder.fpext(right, ftype, name="fpext_r") + else: + right = self.builder.fptrunc(right, ftype, name="fptrunc_r") + float_ops = { + '+': self.builder.fadd, 'Add': self.builder.fadd, + '-': self.builder.fsub, 'Sub': self.builder.fsub, + '*': self.builder.fmul, 'Mult': self.builder.fmul, + '/': self.builder.fdiv, 'Div': self.builder.fdiv, + '%': self.builder.frem, 'Mod': self.builder.frem, + } + float_cmp_ops = { + '==': '==', 'Eq': '==', '!=': '!=', 'NotEq': '!=', + '<': '<', 'Lt': '<', '<=': '<=', 'LtE': '<=', + '>': '>', 'Gt': '>', '>=': '>=', 'GtE': '>=', + } + if op in float_ops: + return float_ops[op](left, right, name=op) + if op in float_cmp_ops: + return self.builder.fcmp_ordered(float_cmp_ops[op], left, right, name=op) + if is_unsigned: + ops = { + '+': self.builder.add, 'Add': self.builder.add, + '-': self.builder.sub, 'Sub': self.builder.sub, + '*': self.builder.mul, 'Mult': self.builder.mul, + '/': self.builder.udiv, 'Div': self.builder.udiv, + '%': self.builder.urem, 'Mod': self.builder.urem, + '//': self.builder.udiv, 'FloorDiv': self.builder.udiv, + } + else: + ops = { + '+': self.builder.add, 'Add': self.builder.add, + '-': self.builder.sub, 'Sub': self.builder.sub, + '*': self.builder.mul, 'Mult': self.builder.mul, + '/': self.builder.sdiv, 'Div': self.builder.sdiv, + '%': self.builder.srem, 'Mod': self.builder.srem, + '//': self.builder.sdiv, 'FloorDiv': self.builder.sdiv, + } + cmp_ops = { + '==': '==', 'Eq': '==', '!=': '!=', 'NotEq': '!=', + '<': '<', 'Lt': '<', '<=': '<=', 'LtE': '<=', + '>': '>', 'Gt': '>', '>=': '>=', 'GtE': '>=', + } + logic_ops = { + '&&': self.builder.and_, 'And': self.builder.and_, + '||': self.builder.or_, 'Or': self.builder.or_, + } + if op in ('>>', 'RShift') and not is_unsigned: + if isinstance(left.type, ir.IntType): + if left.type.width == 8: + is_unsigned = True + elif left.type.width == 16: + is_unsigned = True + elif left.type.width == 32: + if hasattr(self, '_last_var_name') and self._last_var_name: + is_unsigned = self._is_var_unsigned(self._last_var_name) + elif left.type.width == 64: + if hasattr(self, '_last_var_name') and self._last_var_name: + is_unsigned = self._is_var_unsigned(self._last_var_name) + shift_ops = { + '>>': self.builder.lshr if is_unsigned else self.builder.ashr, + 'RShift': self.builder.lshr if is_unsigned else self.builder.ashr, + '<<': self.builder.shl, 'LShift': self.builder.shl, + } + bit_ops = { + '&': self.builder.and_, + '|': self.builder.or_, + '^': self.builder.xor, + } + if op == '**' or op == 'Pow': + if isinstance(left, ir.Constant) and isinstance(right, ir.Constant): + try: + lv = left.constant + rv = right.constant + if isinstance(lv, int) and isinstance(rv, int) and rv >= 0: + result = lv ** rv + return ir.Constant(left.type, result) + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + import logging; logging.warning(f"异常被忽略: {_e}") + pass + if isinstance(left.type, (ir.FloatType, ir.DoubleType)): + ftype = left.type + elif isinstance(right.type, (ir.FloatType, ir.DoubleType)): + ftype = right.type + else: + ftype = ir.DoubleType() + lf = self._to_float(left, ftype) + rf = self._to_float(right, ftype) + powf = self.module.globals.get('llvm.pow.f64') + if not powf: + fnty = ir.FunctionType(ir.DoubleType(), [ir.DoubleType(), ir.DoubleType()]) + powf = ir.Function(self.module, fnty, name='llvm.pow.f64') + if lf.type != ir.DoubleType(): + lf = self.builder.fpext(lf, ir.DoubleType(), name="ext_f64") + if rf.type != ir.DoubleType(): + rf = self.builder.fpext(rf, ir.DoubleType(), name="ext_f64") + result = self.builder.call(powf, [lf, rf], name="pow") + both_int = isinstance(left.type, ir.IntType) and isinstance(right.type, ir.IntType) + right_is_pos_int_const = isinstance(right, ir.Constant) and isinstance(right.constant, int) and right.constant >= 0 + if both_int and right_is_pos_int_const: + return self.builder.fptosi(result, left.type, name="pow2int") + if isinstance(left.type, ir.FloatType): + return self.builder.fptrunc(result, ir.FloatType(), name="pow2f32") + return result + if op in ops: + try: + return ops[op](left, right, name=op) + except Exception as e: + raise ValueError(f"{e}{self._get_node_info()}") + if op in shift_ops: + try: + return shift_ops[op](left, right, name=op) + except Exception as e: + raise ValueError(f"{e}{self._get_node_info()}") + if op in bit_ops: + try: + return bit_ops[op](left, right, name=op) + except Exception as e: + raise ValueError(f"{e}{self._get_node_info()}") + if op in cmp_ops: + try: + if is_unsigned: + return self.builder.icmp_unsigned(cmp_ops[op], left, right, name=op) + return self.builder.icmp_signed(cmp_ops[op], left, right, name=op) + except Exception as e: + raise ValueError(f"{e}{self._get_node_info()}") + if op in logic_ops: + try: + return logic_ops[op](left, right, name=op) + except Exception as e: + raise ValueError(f"{e}{self._get_node_info()}") + return left + + def _to_float(self, val, ftype=None): + if ftype is None: + ftype = ir.DoubleType() + if isinstance(val.type, (ir.FloatType, ir.DoubleType)): + if val.type == ftype: + return val + if isinstance(val.type, ir.FloatType) and isinstance(ftype, ir.DoubleType): + return self.builder.fpext(val, ftype, name="fpext") + return self.builder.fptrunc(val, ftype, name="fptrunc") + if isinstance(val.type, ir.IntType): + if val.type.width == 1: + val = self.builder.zext(val, ir.IntType(32), name="bool2i32") + return self.builder.sitofp(val, ftype, name="int2float") + return val + + def emit_return(self, value=None): + if not self.builder or self.builder.block.is_terminated: + return + if value is not None: + self._unregister_local_heap_ptr(value) + self._emit_local_heap_frees() + if hasattr(self, '_variadic_info') and self._variadic_info and self._variadic_info.get('va_start_called'): + va_list_ptr = self._variadic_info['va_list_ptr'] + self.emit_va_end(va_list_ptr) + if value is None: + if self.func and hasattr(self.func, 'ftype'): + ret_type = self.func.ftype.return_type + if isinstance(ret_type, ir.IntType): + self.builder.ret(ir.Constant(ret_type, 0)) + elif isinstance(ret_type, ir.PointerType): + self.builder.ret(ir.Constant(ret_type, None)) + elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)): + self.builder.ret(ir.Constant(ret_type, 0.0)) + elif isinstance(ret_type, ir.IdentifiedStructType): + if ret_type.elements: + zero_val = ir.Constant(ret_type, [ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)) else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType)) else ir.Constant(et, ir.Undefined) for et in ret_type.elements]) + else: + zero_val = ir.Constant(ret_type, None) + self.builder.ret(zero_val) + elif isinstance(ret_type, ir.ArrayType): + self.builder.ret(ir.Constant(ret_type, None)) + else: + self.builder.ret_void() + else: + self.builder.ret_void() + else: + if self.func and hasattr(self.func, 'ftype'): + ret_type = self.func.ftype.return_type + if ret_type != value.type: + if isinstance(ret_type, ir.PointerType) and isinstance(value.type, ir.PointerType): + if value.type.pointee == ret_type: + value = self._load(value, name="ret_Load") + else: + value = self.builder.bitcast(value, ret_type, name="ret_cast") + elif isinstance(value.type, ir.PointerType) and not isinstance(ret_type, ir.PointerType): + if isinstance(value.type.pointee, ir.IntType) and isinstance(ret_type, ir.IntType) and value.type.pointee.width == ret_type.width: + value = self._load(value, name="ret_Load") + elif isinstance(ret_type, ir.IntType): + value = self.builder.ptrtoint(value, ret_type, name="ret_ptrtoint") + elif isinstance(value.type.pointee, ret_type.__class__) and not isinstance(value.type.pointee, ir.IntType): + value = self._load(value, name="ret_Load") + elif isinstance(value.type.pointee, ir.PointerType): + Loaded = self._load(value, name="ret_deref") + if Loaded.type == ret_type: + value = Loaded + elif isinstance(ret_type, ir.IntType): + value = self.builder.ptrtoint(Loaded, ret_type, name="ret_ptrtoint") + elif isinstance(ret_type, ir.IntType) and isinstance(value.type, ir.IntType): + if value.type.width < ret_type.width: + # 有符号值用 sext,无符号值用 zext + is_unsigned = id(value) in self._unsigned_results + if is_unsigned: + value = self.builder.zext(value, ret_type, name="ret_zext") + else: + value = self.builder.sext(value, ret_type, name="ret_sext") + elif value.type.width > ret_type.width: + value = self.builder.trunc(value, ret_type, name="ret_trunc") + elif isinstance(ret_type, ir.PointerType) and isinstance(value.type, ir.IntType): + value = self.builder.inttoptr(value, ret_type, name="ret_inttoptr") + elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)) and isinstance(value.type, ir.IntType): + value = self.builder.sitofp(value, ret_type, name="ret_int2float") + elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)) and isinstance(value.type, (ir.FloatType, ir.DoubleType)): + if ret_type != value.type: + value = self.builder.fpext(value, ret_type, name="ret_fpext") + self.builder.ret(value) + + def _emit_printf(self, args, unsigned_flags=None, sep=" ", end="\n"): + if not args: + return None + if unsigned_flags is None: + unsigned_flags = [] + format_str = "" + cast_args = [] + for i, arg in enumerate(args): + is_u = i < len(unsigned_flags) and unsigned_flags[i] + if isinstance(arg.type, ir.IntType): + if arg.type.width == 8: + format_str += "%c" + ext = self.builder.zext(arg, ir.IntType(32), name="char2int") + cast_args.append(ext) + elif arg.type.width == 64: + format_str += "%llu" if is_u else "%lld" + cast_args.append(arg) + else: + format_str += "%u" if is_u else "%d" + cast_args.append(arg) + elif isinstance(arg.type, (ir.FloatType, ir.DoubleType)): + format_str += "%f" + cast_args.append(arg) + elif isinstance(arg.type, ir.PointerType): + if isinstance(arg.type.pointee, ir.IntType) and arg.type.pointee.width == 8: + format_str += "%s" + cast_args.append(arg) + else: + format_str += "%d" + int_val = self.builder.ptrtoint(arg, ir.IntType(64), name="ptr2int") + trunc_val = self.builder.trunc(int_val, ir.IntType(32), name="trunc") + cast_args.append(trunc_val) + else: + format_str += "%d" + cast_args.append(arg) + if sep is not None and i < len(args) - 1: + format_str += sep + if end is not None: + format_str += end + string_type = ir.ArrayType(ir.IntType(8), len(format_str.encode('utf-8')) + 1) + string_const = ir.Constant(string_type, bytearray(format_str + '\x00', 'utf-8')) + global_var = ir.GlobalVariable(self.module, string_type, name=f"str_const_{self.string_const_counter}") + self.string_const_counter += 1 + global_var.initializer = string_const + global_var.linkage = 'internal' + format_ptr = self.builder.bitcast(global_var, ir.PointerType(ir.IntType(8))) + call_args = [format_ptr] + cast_args + printf_func = self.get_or_declare_c_func('printf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True)) + return self.builder.call(printf_func, call_args, name="call_printf") + + def emit_sizeof(self, type_name): + for class_name, struct_type in self.structs.items(): + if type_name == class_name: + size = self._get_struct_size(struct_type) + if size > 0: + return ir.Constant(ir.IntType(64), size) + return ir.Constant(ir.IntType(64), 4) diff --git a/lib/core/LLVMCG/FuncGen.py b/lib/core/LLVMCG/FuncGen.py new file mode 100644 index 0000000..faadbf2 --- /dev/null +++ b/lib/core/LLVMCG/FuncGen.py @@ -0,0 +1,386 @@ +from __future__ import annotations +import ast +import os +import llvmlite.ir as ir + + +class FuncGenMixin: + + def setup_from_symbol_table(self, SymbolTable): + self.SymbolTable = SymbolTable + for name, info in SymbolTable.items(): + if not isinstance(info, dict): + if hasattr(info, 'get'): + info = dict(info) if hasattr(info, '__iter__') else {} + else: + continue + TypeKind = info.get('type', '') + if TypeKind == 'struct': + ClassName = name + self.class_methods[ClassName] = [] + self.class_members[ClassName] = [] + members = info.get('members', {}) + if members: + for MemberName, MemberInfo in members.items(): + if isinstance(MemberInfo, dict): + MemberType = self._type_str_to_llvm(MemberInfo.get('type', 'int'), MemberInfo.get('IsPtr', False)) + self.class_members[ClassName].append((MemberName, MemberType)) + elif isinstance(MemberInfo, _CTypeInfo): + MemberType = self._ctype_to_llvm(MemberInfo) + if MemberType is None: + MemberType = self._type_str_to_llvm(MemberInfo.ToString(), MemberInfo.IsPtr) + self.class_members[ClassName].append((MemberName, MemberType)) + self._generate_structs() + self._create_Vtable_globals() + + def register_method(self, ClassName, MethodName): + if ClassName not in self.class_methods: + self.class_methods[ClassName] = [] + if ClassName not in self.class_members: + self.class_members[ClassName] = [] + self._generate_structs() + self._create_Vtable_globals() + if MethodName not in self.class_methods[ClassName]: + self.class_methods[ClassName].append(MethodName) + + def _adjust_args(self, args, func): + adjusted = [] + for i, (arg, param) in enumerate(zip(args, func.args)): + if arg.type != param.type: + if isinstance(arg.type, ir.PointerType) and isinstance(param.type, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): + if arg.type.pointee == param.type or (hasattr(arg.type.pointee, 'name') and hasattr(param.type, 'name') and arg.type.pointee.name == param.type.name): + adjusted.append(self._load(arg, name=f"Load_arg_{i}")) + continue + try: + if isinstance(arg.type, ir.IntType) and isinstance(param.type, ir.PointerType): + if isinstance(param.type.pointee, ir.IntType) and param.type.pointee.width == 8 and arg.type.width == 8: + # 当参数是 i8(字符值)而函数期望 i8*(字符串指针)时 + # 为字符值分配内存,创建 null-terminated 字符串 + tmp = self._alloca(ir.ArrayType(ir.IntType(8), 2), name=f"char2str_arg_{i}") + zero = ir.Constant(ir.IntType(32), 0) + char_ptr = self.builder.gep(tmp, [zero, zero], name=f"char2str_ptr_{i}") + self._store(arg, char_ptr) + null_ptr = self.builder.gep(tmp, [zero, ir.Constant(ir.IntType(32), 1)], name=f"char2str_null_{i}") + self._store(ir.Constant(ir.IntType(8), 0), null_ptr) + adjusted.append(char_ptr) + else: + if isinstance(arg.type, ir.PointerType) and isinstance(param.type, ir.IntType): + # 当参数是指针而函数期望整数时,使用 ptrtoint + adjusted.append(self.builder.ptrtoint(arg, param.type, name=f"ptrtoint_arg_{i}")) + else: + if arg.type.width < 32: + arg = self.builder.zext(arg, ir.IntType(32), name=f"zext_arg_{i}") + adjusted.append(self.builder.inttoptr(arg, param.type, name=f"inttoptr_arg_{i}")) + elif isinstance(arg.type, ir.PointerType) and isinstance(param.type, ir.IntType): + # 当参数是指针而函数期望整数时,使用 ptrtoint + adjusted.append(self.builder.ptrtoint(arg, param.type, name=f"ptrtoint_arg_{i}")) + elif isinstance(arg.type, ir.PointerType) and isinstance(param.type, ir.PointerType): + if isinstance(arg.type.pointee, ir.PointerType) and isinstance(param.type.pointee, ir.IntType): + Loaded = self._load(arg, name=f"Load_arg_{i}") + adjusted.append(Loaded) + elif isinstance(arg.type.pointee, ir.ArrayType) and isinstance(param.type.pointee, (ir.IntType, ir.FloatType, ir.DoubleType)): + zero = ir.Constant(ir.IntType(32), 0) + elem_ptr = self.builder.gep(arg, [zero, zero], name=f"array_decay_arg_{i}") + if elem_ptr.type != param.type: + adjusted.append(self.builder.bitcast(elem_ptr, param.type, name=f"cast_arg_{i}")) + else: + adjusted.append(elem_ptr) + elif isinstance(arg.type.pointee, ir.ArrayType) and isinstance(param.type.pointee, ir.PointerType): + zero = ir.Constant(ir.IntType(32), 0) + elem_ptr = self.builder.gep(arg, [zero, zero], name=f"array_decay_arg_{i}") + if elem_ptr.type != param.type: + adjusted.append(self.builder.bitcast(elem_ptr, param.type, name=f"cast_arg_{i}")) + else: + adjusted.append(elem_ptr) + else: + adjusted.append(self.builder.bitcast(arg, param.type, name=f"cast_arg_{i}")) + else: + if isinstance(arg.type, ir.PointerType) and isinstance(param.type, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): + if arg.type.pointee == param.type or (hasattr(arg.type.pointee, 'name') and hasattr(param.type, 'name') and arg.type.pointee.name == param.type.name): + adjusted.append(self._load(arg, name=f"Load_arg_{i}")) + elif isinstance(arg.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): + tmp = self._alloca(param.type, name=f"temp_arg_{i}") + Loaded = self.builder.bitcast(arg, ir.PointerType(param.type), name=f"cast_arg_{i}") + Loaded_val = self._load(Loaded, name=f"Load_arg_{i}") + self._store(Loaded_val, tmp) + adjusted.append(self._load(tmp, name=f"reLoad_arg_{i}")) + else: + tmp = self._alloca(param.type, name=f"temp_arg_{i}") + cast_ptr = self.builder.bitcast(arg, ir.PointerType(param.type), name=f"cast_arg_{i}") + Loaded_val = self._load(cast_ptr, name=f"Load_arg_{i}") + self._store(Loaded_val, tmp) + adjusted.append(self._load(tmp, name=f"reLoad_arg_{i}")) + elif isinstance(arg.type, ir.PointerType) and arg.type.pointee == param.type: + adjusted.append(self._load(arg, name=f"Load_arg_{i}")) + elif isinstance(param.type, ir.PointerType) and param.type.pointee == arg.type: + tmp = self._alloca(arg.type, name=f"temp_arg_{i}") + self._store(arg, tmp) + adjusted.append(tmp) + elif isinstance(arg.type, ir.IntType) and isinstance(param.type, ir.IntType): + if arg.type.width < param.type.width: + # 整数扩展:使用 sext(符号扩展)以正确处理负数 + adjusted.append(self.builder.sext(arg, param.type, name=f"sext_arg_{i}")) + else: + adjusted.append(self.builder.trunc(arg, param.type, name=f"trunc_arg_{i}")) + elif isinstance(arg.type, (ir.FloatType, ir.DoubleType)) and isinstance(param.type, (ir.FloatType, ir.DoubleType)): + if isinstance(arg.type, ir.DoubleType) and isinstance(param.type, ir.FloatType): + adjusted.append(self.builder.fptrunc(arg, param.type, name=f"fptrunc_arg_{i}")) + elif isinstance(arg.type, ir.FloatType) and isinstance(param.type, ir.DoubleType): + adjusted.append(self.builder.fpext(arg, param.type, name=f"fpext_arg_{i}")) + else: + adjusted.append(arg) + elif isinstance(arg.type, (ir.FloatType, ir.DoubleType)) and isinstance(param.type, ir.IntType): + adjusted.append(self.builder.fptosi(arg, param.type, name=f"fptosi_arg_{i}")) + elif isinstance(arg.type, ir.IntType) and isinstance(param.type, (ir.FloatType, ir.DoubleType)): + adjusted.append(self.builder.sitofp(arg, param.type, name=f"sitofp_arg_{i}")) + elif isinstance(arg.type, ir.IntType) and isinstance(param.type, ir.PointerType): + # 整数转指针:inttoptr + if arg.type.width < 64: + i64_val = self.builder.sext(arg, ir.IntType(64), name=f"sext_arg_{i}") + adjusted.append(self.builder.inttoptr(i64_val, param.type, name=f"inttoptr_arg_{i}")) + else: + adjusted.append(self.builder.inttoptr(arg, param.type, name=f"inttoptr_arg_{i}")) + elif isinstance(arg.type, ir.PointerType) and isinstance(param.type, ir.IntType): + # 指针转整数:ptrtoint + i64_val = self.builder.ptrtoint(arg, ir.IntType(64), name=f"ptrtoint_arg_{i}") + if i64_val.type.width > param.type.width: + adjusted.append(self.builder.trunc(i64_val, param.type, name=f"trunc_arg_{i}")) + elif i64_val.type.width < param.type.width: + adjusted.append(self.builder.sext(i64_val, param.type, name=f"sext_arg_{i}")) + else: + adjusted.append(i64_val) + else: + adjusted.append(self.builder.bitcast(arg, param.type, name=f"cast_arg_{i}")) + except Exception: # 参数类型调整失败时使用简化回退逻辑 + if isinstance(arg.type, ir.PointerType) and isinstance(param.type, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): + if arg.type.pointee == param.type or (hasattr(arg.type.pointee, 'name') and hasattr(param.type, 'name') and arg.type.pointee.name == param.type.name): + adjusted.append(self._load(arg, name=f"Load_arg_{i}")) + else: + adjusted.append(self.builder.bitcast(arg, param.type, name=f"cast_arg_{i}")) + elif isinstance(arg.type, ir.PointerType) and arg.type.pointee == param.type: + adjusted.append(self._load(arg, name=f"Load_arg_{i}")) + elif isinstance(param.type, ir.PointerType) and param.type.pointee == arg.type: + tmp = self._alloca(arg.type, name=f"temp_arg_{i}") + self._store(arg, tmp) + adjusted.append(tmp) + else: + adjusted.append(arg) + else: + adjusted.append(arg) + while len(adjusted) < len(func.args): + missing_idx = len(adjusted) + param = func.args[missing_idx] + param_type = param.type if hasattr(param, 'type') else param + if isinstance(param_type, ir.PointerType): + adjusted.append(ir.Constant(param_type, None)) + elif isinstance(param_type, ir.IntType): + adjusted.append(ir.Constant(param_type, 0)) + elif isinstance(param_type, (ir.FloatType, ir.DoubleType)): + adjusted.append(ir.Constant(param_type, 0.0)) + else: + adjusted.append(ir.Constant(ir.IntType(32), 0)) + if func.type.pointee.var_arg: + for i in range(len(func.args), len(args)): + arg = args[i] + adjusted.append(arg) + return adjusted + + def _get_member_offset(self, field_name, ClassName=None): + has_vtable = ClassName and (ClassName in self.class_vtable or ClassName in self._cross_module_vtable_classes) + base = 1 if has_vtable else 0 + if ClassName and ClassName in self.structs: + struct_type = self.structs[ClassName] + if isinstance(struct_type, ir.IdentifiedStructType) and struct_type.elements is not None and len(struct_type.elements) > 0: + if ClassName in self.class_members: + expected_fields = len(self.class_members[ClassName]) + actual_elements = len(struct_type.elements) + if base > 0 and actual_elements == expected_fields: + base = 0 + if ClassName and ClassName in self.class_members: + for i, (name, _) in enumerate(self.class_members[ClassName]): + if name == field_name: + return base + i + short_name = ClassName.split('.')[-1] if ClassName and '.' in ClassName else None + if short_name and short_name in self.class_members: + for i, (name, _) in enumerate(self.class_members[short_name]): + if name == field_name: + return base + i + if ClassName and field_name: + if ClassName not in self.class_members or field_name not in [n for n, _ in self.class_members.get(ClassName, [])]: + if hasattr(self, '_Trans') and self._Trans and hasattr(self._Trans, 'ImportHandler'): + sha1_map = getattr(self, 'ModuleSha1Map', {}) + for mod_name, mod_sha1 in sha1_map.items(): + stub_name = f"{mod_sha1}.stub.ll" + self._Trans.ImportHandler._TryLoadClassMembersFromPyi(ClassName, stub_name, self) + if ClassName in self.class_members and len(self.class_members[ClassName]) > 0: + for i, (name, _) in enumerate(self.class_members[ClassName]): + if name == field_name: + return base + i + break + if short_name: + for mod_name, mod_sha1 in sha1_map.items(): + stub_name = f"{mod_sha1}.stub.ll" + self._Trans.ImportHandler._TryLoadClassMembersFromPyi(short_name, stub_name, self) + if short_name in self.class_members and len(self.class_members[short_name]) > 0: + for i, (name, _) in enumerate(self.class_members[short_name]): + if name == field_name: + return base + i + break + if ClassName and field_name: + for cn_key in self.class_members: + if cn_key == ClassName or cn_key.endswith(f'.{ClassName}') or (short_name and (cn_key == short_name or cn_key.endswith(f'.{short_name}'))): + for i, (name, _) in enumerate(self.class_members[cn_key]): + if name == field_name: + return base + i + if ClassName and ClassName in self.structs: + struct_type = self.structs[ClassName] + if isinstance(struct_type, ir.IdentifiedStructType) and struct_type.elements is not None and len(struct_type.elements) > 0: + for cn_key, members in self.class_members.items(): + if cn_key == short_name or (short_name and cn_key.endswith(f'.{short_name}')): + for i, (name, _) in enumerate(members): + if name == field_name and i < len(struct_type.elements): + return i + break + else: + if short_name: + for cn_key, members in self.class_members.items(): + sn = cn_key.split('.')[-1] if '.' in cn_key else cn_key + if sn == short_name: + for i, (name, _) in enumerate(members): + if name == field_name and i < len(struct_type.elements): + return i + break + if ClassName and field_name and ClassName not in self.class_members: + if hasattr(self, '_Trans') and self._Trans and hasattr(self._Trans, 'ImportHandler'): + for temp_dir_candidate in [getattr(self, '_temp_dir', None)]: + if temp_dir_candidate and os.path.isdir(temp_dir_candidate): + for pyi_file in os.listdir(temp_dir_candidate): + if pyi_file.endswith('.pyi'): + stub_name = pyi_file.replace('.pyi', '.stub.ll') + short_cn = short_name if short_name else ClassName + self._Trans.ImportHandler._TryLoadClassMembersFromPyi(short_cn, stub_name, self) + if short_cn in self.class_members and len(self.class_members[short_cn]) > 0: + for i, (name, _) in enumerate(self.class_members[short_cn]): + if name == field_name: + return base + i + break + if ClassName and ClassName in self.structs and (ClassName not in self.class_members or len(self.class_members.get(ClassName, [])) == 0): + struct_type = self.structs[ClassName] + if isinstance(struct_type, ir.IdentifiedStructType) and struct_type.elements is not None: + if hasattr(self, '_Trans') and self._Trans and hasattr(self._Trans, 'ClassHandler'): + class_handler = self._Trans.ClassHandler + if hasattr(self, '_current_tree') and self._current_tree: + for node in ast.iter_child_nodes(self._current_tree): + if isinstance(node, ast.ClassDef) and (node.name == ClassName or node.name == short_name): + if node.name not in self.class_members: + self.class_members[node.name] = [] + if len(self.class_members[node.name]) == 0: + class_handler._PreRegisterClassMembers(node, self) + if ClassName in self.class_members: + for i, (name, _) in enumerate(self.class_members[ClassName]): + if name == field_name: + return base + i + if short_name and short_name in self.class_members: + for i, (name, _) in enumerate(self.class_members[short_name]): + if name == field_name: + return base + i + break + return None + + def _resolve_class_for_var(self, var_name): + for ClassName in self.class_methods: + if var_name == ClassName or var_name.startswith(f"__with_{ClassName}_"): + return ClassName + if var_name in self.variables: + var = self.variables[var_name] + if isinstance(var.type, ir.PointerType): + for ClassName, struct_type in self.structs.items(): + if var.type.pointee == struct_type: + return ClassName + if isinstance(var.type.pointee, ir.PointerType) and var.type.pointee.pointee == struct_type: + return ClassName + return None + + def _GetOrCreateFunc(self, FuncName, ArgTypes): + mangled_name = self._mangle_func_name(FuncName) + if mangled_name in self.functions: + return self.functions[mangled_name] + FuncType = self._InferFuncTypeForCall(FuncName, ArgTypes) + try: + func = ir.Function(self.module, FuncType, name=mangled_name) + except Exception: # 函数名冲突时添加前缀重试 + func = ir.Function(self.module, FuncType, name=f"_{mangled_name}") + self.functions[mangled_name] = func + return func + + def _resolve_method_class(self, MethodName): + for ClassName, methods in self.class_methods.items(): + if MethodName in methods: + return ClassName + full_name = f"{ClassName}.{MethodName}" + if full_name in methods: + return ClassName + return None + + def _infer_return_type(self, FuncName): + if FuncName in self.functions: + return self.functions[FuncName].type.pointee.return_type + if FuncName in self.known_return_types: + return self.known_return_types[FuncName] + for ClassName, methods in self.class_methods.items(): + for method in methods: + if FuncName == method: + return ir.VoidType() + return ir.IntType(32) + + def _InferFuncTypeForCall(self, FuncName, ArgTypes): + return_type = self._infer_return_type(FuncName) + if not ArgTypes: + for ClassName, methods in self.class_methods.items(): + if FuncName in methods: + if ClassName in self.structs: + ArgTypes = [ir.PointerType(self.structs[ClassName])] + else: + ArgTypes = [ir.PointerType(ir.LiteralStructType([ir.PointerType(ir.IntType(8)), ir.IntType(32)]))] + break + else: + ArgTypes = [ir.IntType(32)] + return ir.FunctionType(return_type, ArgTypes) + + def _get_or_declare_func(self, name, func_type): + import re + for fname, fobj in self.functions.items(): + if fname == name: + return fobj + if re.match(r'^[0-9a-f]{16,}\.' + re.escape(name) + r'$', fname): + return fobj + func_decl = ir.Function(self.module, func_type, name=name) + self.functions[name] = func_decl + return func_decl + + def get_or_declare_c_func(self, name, fallback_type=None): + if name in self.functions: + return self.functions[name] + import re + for fname, fobj in self.functions.items(): + if re.match(r'^[0-9a-f]{16,}\.' + re.escape(name) + r'$', fname): + return fobj + stub_func_type = None + if hasattr(self, '_import_handler_ref') and self._import_handler_ref: + try: + stub_func_type = self._import_handler_ref._LookupStubFuncType(name, self) + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _config_mode + if _config_mode == "strict": + raise + _vlog().warning(f"查找桩函数类型失败: {_e}", "Exception") + if stub_func_type: + func_decl = ir.Function(self.module, stub_func_type, name=name) + self.functions[name] = func_decl + return func_decl + if fallback_type is not None: + func_decl = ir.Function(self.module, fallback_type, name=name) + self.functions[name] = func_decl + return func_decl + return None diff --git a/lib/core/LLVMCG/MemoryOps.py b/lib/core/LLVMCG/MemoryOps.py new file mode 100644 index 0000000..7945429 --- /dev/null +++ b/lib/core/LLVMCG/MemoryOps.py @@ -0,0 +1,312 @@ +from __future__ import annotations +import llvmlite.ir as ir + + +class MemoryOpsMixin: + + def _register_local_heap_ptr(self, val, ClassName=None, VarName=None): + if isinstance(val.type, ir.PointerType): + pointee = val.type.pointee + if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): + self._local_heap_ptrs.append((val, 'struct', ClassName)) + elif isinstance(pointee, ir.IntType) and pointee.width == 8: + self._local_heap_ptrs.append((val, 'i8', ClassName)) + if VarName: + self._var_to_heap_ptr[VarName] = val + + def _unregister_local_heap_ptr(self, val): + self._local_heap_ptrs = [(v, t, cn) for v, t, cn in self._local_heap_ptrs if v is not val] + + def _emit_local_heap_frees(self): + if not self._local_heap_ptrs or not self.builder: + return + # 创建一个集合来跟踪已经删除的对象 + deleted_objects = set() + for ptr, ptr_type, ClassName in self._local_heap_ptrs: + # 先检查指针是否为 null + if ptr_type == 'i8': + # 对于 i8* 类型的指针,加载其值并检查是否为 null + Loaded_ptr = self.builder.load(ptr, name="load_ptr") + null_ptr = ir.Constant(ir.PointerType(ir.IntType(8)), None) + is_null = self.builder.icmp_unsigned('==', Loaded_ptr, null_ptr, name="is_null") + # 创建一个基本块来处理非 null 的情况 + not_null_block = self.builder.append_basic_block(name="not_null") + # 创建一个基本块来处理下一个对象 + next_block = self.builder.append_basic_block(name="next") + # 如果指针为 null,跳转到下一个对象 + self.builder.cbranch(is_null, next_block, not_null_block) + # 切换到非 null 的基本块 + self.builder.position_at_end(not_null_block) + # 然后调用 __del__ 方法 + if ClassName and self._has_function(f'{ClassName}.__del__'): + if isinstance(ptr.type, ir.PointerType) and isinstance(ptr.type.pointee, ir.IntType) and ptr.type.pointee.width == 8: + cast_ptr = self.builder.bitcast(ptr, ir.PointerType(self.structs[ClassName]), name=f"cast_{ClassName}") + else: + cast_ptr = ptr + if cast_ptr not in deleted_objects: + self.builder.call(self._get_function(f'{ClassName}.__del__'), [cast_ptr], name=f"call_{ClassName}.__del__") + deleted_objects.add(cast_ptr) + # 最后释放内存 + if ptr_type == 'struct': + raw = self.builder.bitcast(ptr, ir.PointerType(ir.IntType(8)), name="local_free_cast") + elif ptr_type == 'i8': + raw = ptr + else: + continue + free_type = ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))]) + free_func = self._get_or_declare_func('free', free_type) + self.builder.call(free_func, [raw]) + # 如果是 i8* 类型的指针,跳转到下一个对象 + if ptr_type == 'i8': + self.builder.branch(next_block) + # 切换到下一个对象的基本块 + self.builder.position_at_end(next_block) + self._local_heap_ptrs = [] + + def _RegisterTempPtr(self, val): + if isinstance(val.type, ir.PointerType): + pointee = val.type.pointee + if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): + for CN, ST in self.structs.items(): + if pointee == ST: + self._temp_struct_ptrs.append(val) + return + elif isinstance(pointee, ir.IntType) and pointee.width == 8: + self._temp_struct_ptrs.append(val) + + def _UnregisterTempPtr(self, val): + self._temp_struct_ptrs = [t for t in self._temp_struct_ptrs if t is not val] + + def _EmitTempFrees(self): + if not self._temp_struct_ptrs or not self.builder: + return + for ptr in self._temp_struct_ptrs: + if isinstance(ptr.type, ir.PointerType) and isinstance(ptr.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): + raw = self.builder.bitcast(ptr, ir.PointerType(ir.IntType(8)), name="free_cast") + elif isinstance(ptr.type, ir.PointerType) and isinstance(ptr.type.pointee, ir.IntType) and ptr.type.pointee.width == 8: + raw = ptr + else: + continue + free_type = ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))]) + free_func = self._get_or_declare_func('free', free_type) + self.builder.call(free_func, [raw]) + self._temp_struct_ptrs = [] + + def _ZeroConst(self, typ): + if isinstance(typ, ir.PointerType): + return ir.Constant(typ, None) + return ir.Constant(typ, 0) + + def _alloca(self, typ, name='', align=None, size=None): + if align is None: + align = self._get_align(typ) + if size is not None: + instr = self.builder.alloca(typ, size=size, name=name) + else: + instr = self.builder.alloca(typ, name=name) + if align: + instr.align = align + return instr + + def _allocaEntry(self, typ, name='', align=None): + if align is None: + align = self._get_align(typ) + saved_block = self.builder.block + entry_block = self.func.entry_basic_block + if entry_block.instructions: + first_instr = entry_block.instructions[0] + self.builder.position_before(first_instr) + instr = self.builder.alloca(typ, name=name) + if align: + instr.align = align + self.builder.position_at_end(saved_block) + else: + self.builder.position_at_start(entry_block) + instr = self.builder.alloca(typ, name=name) + if align: + instr.align = align + self.builder.position_at_end(saved_block) + return instr + + def _load(self, ptr, name='', align=None): + if align is None: + if isinstance(ptr.type, ir.PointerType): + align = self._get_align(ptr.type.pointee) + else: + align = 0 + if isinstance(ptr.type, ir.PointerType): + pointee_type = ptr.type.pointee + if isinstance(pointee_type, ir.IdentifiedStructType) and pointee_type.name in self.typedef_int_widths: + width = self.typedef_int_widths[pointee_type.name] + if width > 0: + actual_type = ir.IntType(width) + bitcast_ptr = self.builder.bitcast(ptr, ir.PointerType(actual_type), name="typedef_bitcast_Load") + return self.builder.load(bitcast_ptr, name=name, align=align) + return self.builder.load(ptr, name=name, align=align) + + def _Load_var(self, name): + if name in self._direct_values: + return self._direct_values[name] + if name in self.variables and self.variables[name] is not None: + VarPtr = self.variables[name] + if isinstance(VarPtr, ir.GlobalVariable) and isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): + return VarPtr + if isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): + return VarPtr + return self._load(VarPtr, name=name) + if name in self.global_vars and name in self.module.globals: + GVar = self.module.globals[name] + self.variables[name] = GVar + if isinstance(GVar, ir.Function): + return GVar + if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): + return GVar + return self._load(GVar, name=name) + if name in self.module.globals: + GVar = self.module.globals[name] + self.variables[name] = GVar + if isinstance(GVar, ir.Function): + return GVar + if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): + return GVar + return self._load(GVar, name=name) + return None + + def _store_var(self, name, value): + if name in self._direct_values: + old_val = self._direct_values.pop(name) + if name not in self.variables or self.variables[name] is None: + var = self.builder.alloca(old_val.type, name=name) + self._store(old_val, var) + self.variables[name] = var + if name in self.variables and self.variables[name] is not None: + self._store(value, self.variables[name]) + else: + var = self.builder.alloca(value.type, name=name) + self._store(value, var) + self.variables[name] = var + + def _ensure_alloca(self, name, llvm_type): + if name in self._direct_values: + val = self._direct_values.pop(name) + var = self.builder.alloca(llvm_type, name=name) + self._store(val, var) + self.variables[name] = var + return var + if name in self.variables and self.variables[name] is not None: + return self.variables[name] + var = self.builder.alloca(llvm_type, name=name) + self.variables[name] = var + return var + + def _coerce_value(self, val, target_type): + if val.type == target_type: + return val + if isinstance(target_type, ir.IdentifiedStructType) and target_type.name in self.typedef_int_widths: + if isinstance(val.type, ir.IntType): + return val + if isinstance(target_type, ir.IntType) and isinstance(val.type, ir.IntType): + if target_type.width < val.type.width: + return self.builder.trunc(val, target_type, name="trunc_store") + else: + # 使用 sext(符号扩展)以正确处理负数 + return self.builder.sext(val, target_type, name="sext_store") + if isinstance(target_type, ir.PointerType) and isinstance(val.type, ir.PointerType): + if isinstance(val, ir.Constant) and val.constant is None: + return ir.Constant(target_type, None) + return self.builder.bitcast(val, target_type, name="ptr_bitcast_store") + if isinstance(target_type, ir.PointerType) and isinstance(val.type, ir.IntType): + if val.type.width < 64: + val = self.builder.zext(val, ir.IntType(64), name="zext_ptr_store") + return self.builder.inttoptr(val, target_type, name="int_to_ptr_store") + if isinstance(target_type, ir.IntType) and isinstance(val.type, ir.PointerType): + if isinstance(val.type.pointee, ir.IntType) and val.type.pointee.width == target_type.width: + return self.builder.load(val, name="load_ptr_as_int_store") + if target_type.width <= 8 and isinstance(val.type.pointee, ir.IntType): + Loaded = self.builder.load(val, name="load_ptr_byte_store") + if Loaded.type != target_type: + if isinstance(Loaded.type, ir.IntType) and isinstance(target_type, ir.IntType): + if target_type.width < Loaded.type.width: + return self.builder.trunc(Loaded, target_type, name="trunc_ptr_byte_store") + return self.builder.zext(Loaded, target_type, name="zext_ptr_byte_store") + return Loaded + return self.builder.ptrtoint(val, target_type, name="ptr_to_int_store") + if isinstance(target_type, ir.FloatType) and isinstance(val.type, ir.DoubleType): + return self.builder.fptrunc(val, target_type, name="fptrunc_store") + if isinstance(target_type, ir.DoubleType) and isinstance(val.type, ir.FloatType): + return self.builder.fpext(val, target_type, name="fpext_store") + if isinstance(target_type, ir.IntType) and isinstance(val.type, (ir.FloatType, ir.DoubleType)): + return self.builder.fptosi(val, target_type, name="fptosi_store") + if isinstance(target_type, (ir.FloatType, ir.DoubleType)) and isinstance(val.type, ir.IntType): + return self.builder.sitofp(val, target_type, name="sitofp_store") + if isinstance(target_type, ir.ArrayType) and isinstance(val.type, ir.ArrayType): + if target_type.count == val.type.count and target_type.element == val.type.element: + return val + if (isinstance(target_type.element, ir.IntType) and target_type.element.width == 8 + and isinstance(val.type.element, ir.IntType) and val.type.element.width == 8): + if target_type.count > val.type.count: + padded = list(val.constant) if hasattr(val, 'constant') else [] + if padded and len(padded) == val.type.count: + padded.extend([ir.Constant(ir.IntType(8), 0)] * (target_type.count - val.type.count)) + return ir.Constant(target_type, padded) + elif target_type.count < val.type.count: + trimmed = list(val.constant) if hasattr(val, 'constant') else [] + if trimmed and len(trimmed) == val.type.count: + return ir.Constant(target_type, trimmed[:target_type.count]) + if isinstance(val.type, ir.PointerType) and not isinstance(target_type, ir.PointerType): + if val.type.pointee == target_type: + return self.builder.load(val, name="Load_struct_for_store") + if isinstance(val.type.pointee, ir.IdentifiedStructType) and isinstance(target_type, ir.IdentifiedStructType): + if val.type.pointee.name == target_type.name: + Loaded = self.builder.load(val, name="Load_struct_for_store") + if Loaded.type == target_type: + return Loaded + return None + + def _store(self, val, ptr, align=None): + if align is None: + if isinstance(ptr.type, ir.PointerType): + align = self._get_align(ptr.type.pointee) + else: + align = 0 + if isinstance(ptr.type, ir.PointerType): + target_type = ptr.type.pointee + if isinstance(target_type, ir.IdentifiedStructType) and target_type.name in self.typedef_int_widths: + if isinstance(val.type, ir.IntType): + width = self.typedef_int_widths[target_type.name] + if width > 0: + actual_type = ir.IntType(width) + bitcast_ptr = self.builder.bitcast(ptr, ir.PointerType(actual_type), name="typedef_bitcast") + if val.type.width != actual_type.width: + if val.type.width > actual_type.width: + val = self.builder.trunc(val, actual_type, name="trunc_typedef") + else: + val = self.builder.zext(val, actual_type, name="zext_typedef") + return self.builder.store(val, bitcast_ptr, align=align) + if val.type != target_type: + if isinstance(val, ir.Constant) and val.constant is None: + if isinstance(target_type, ir.PointerType): + val = ir.Constant(target_type, None) + elif isinstance(target_type, ir.IdentifiedStructType): + val = ir.Constant(ir.PointerType(target_type), None) + ptr = self.builder.bitcast(ptr, ir.PointerType(ir.PointerType(target_type)), name="null_struct_ptr_cast") + else: + coerced = self._coerce_value(val, target_type) + if coerced is not None: + val = coerced + else: + src_info = self._get_node_info() + raise TypeError(f"cannot store {val.type} to {ptr.type}: mismatching types{src_info}") + return self.builder.store(val, ptr, align=align) + + def _get_var_ptr(self, name): + if name in self._reg_values: + val = self._reg_values[name] + var = self._alloca(val.type, name=name) + self._store(val, var) + self.variables[name] = var + del self._reg_values[name] + return var + if name in self.variables and self.variables[name] is not None: + return self.variables[name] + return None diff --git a/lib/core/LLVMCG/StructGen.py b/lib/core/LLVMCG/StructGen.py new file mode 100644 index 0000000..2c0f089 --- /dev/null +++ b/lib/core/LLVMCG/StructGen.py @@ -0,0 +1,463 @@ +from __future__ import annotations +import re +import ast +import llvmlite.ir as ir +from llvmlite.ir.values import _Undefined + + +class StructGenMixin: + + def _get_align(self, llvm_type): + if isinstance(llvm_type, ir.IntType): + return max(1, llvm_type.width // 8) + if isinstance(llvm_type, ir.FloatType): + return 4 + if isinstance(llvm_type, ir.DoubleType): + return 8 + if isinstance(llvm_type, ir.PointerType): + return self.ptr_size + if isinstance(llvm_type, ir.ArrayType): + return self._get_align(llvm_type.element) + if isinstance(llvm_type, ir.LiteralStructType): + return max((self._get_align(f) for f in llvm_type.elements), default=1) + if isinstance(llvm_type, ir.IdentifiedStructType): + if llvm_type.elements is None or len(llvm_type.elements) == 0: + return self.ptr_size # opaque struct, assume pointer alignment + return max((self._get_align(f) for f in llvm_type.elements), default=1) + if isinstance(llvm_type, ir.VoidType): + return 0 + return 4 + + def _get_struct_size(self, llvm_type): + if isinstance(llvm_type, ir.IntType): + return max(1, llvm_type.width // 8) + if isinstance(llvm_type, ir.FloatType): + return 4 + if isinstance(llvm_type, ir.DoubleType): + return 8 + if isinstance(llvm_type, ir.PointerType): + return self.ptr_size + if isinstance(llvm_type, ir.ArrayType): + return self._get_struct_size(llvm_type.element) * llvm_type.count + if isinstance(llvm_type, ir.LiteralStructType): + total = 0 + max_align = 1 + for f in llvm_type.fields: + fa = self._get_align(f) + fs = self._get_struct_size(f) + max_align = max(max_align, fa) + if fa > 1: + total = (total + fa - 1) // fa * fa + total += fs + if max_align > 1: + total = (total + max_align - 1) // max_align * max_align + return total + if isinstance(llvm_type, ir.IdentifiedStructType): + if llvm_type.elements is None or len(llvm_type.elements) == 0: + return self.ptr_size # opaque struct, assume pointer size + total = 0 + max_align = 1 + for f in llvm_type.elements: + fa = self._get_align(f) + fs = self._get_struct_size(f) + max_align = max(max_align, fa) + if fa > 1: + total = (total + fa - 1) // fa * fa + total += fs + if max_align > 1: + total = (total + max_align - 1) // max_align * max_align + return total + return 4 + + @staticmethod + def _strip_unnecessary_quotes(ir_str): + def _unquote(m): + prefix = m.group(1) + name = m.group(2) + if '.' in name: + return m.group(0) + if re.match(r'^[a-zA-Z_$][a-zA-Z0-9_$]*$', name): + return prefix + name + return m.group(0) + return re.sub(r'([@%])"([^"]+)"', _unquote, ir_str) + + def finalize(self): + self._set_Vtable_initializers() + self._fix_global_var_init() + try: + ir_text = str(self.module) + except TypeError as e: + for func in self.module.functions: + for block in func.blocks: + for instr in block.instructions: + try: + str(instr) + except TypeError as te: + pass + raise + ir_text = self._strip_unnecessary_quotes(ir_text) + struct_defs = [] + struct_names = set() + for ClassName, struct_type in self.structs.items(): + if isinstance(struct_type, ir.IdentifiedStructType): + sname = struct_type.name + if sname[0].isdigit() or '.' in sname or not sname.replace('_', '').replace('.', '').isalnum(): + sname_ir = f'%"{sname}"' + else: + sname_ir = f'%{sname}' + if struct_type.elements is None or len(struct_type.elements) == 0: + if ClassName not in self.typedef_int_widths: + struct_names.add(sname) + struct_defs.append(f'{sname_ir} = type opaque') + continue + elems = ', '.join(str(e) for e in struct_type.elements) + if struct_type.packed: + struct_defs.append(f'{sname_ir} = type <{{ {elems} }}>') + else: + struct_defs.append(f'{sname_ir} = type {{ {elems} }}') + struct_names.add(sname) + if struct_defs: + lines = ir_text.split('\n') + filtered = [] + for line in lines: + stripped = line.strip() + skip = False + for name in struct_names: + if name[0].isdigit() or '.' in name or not name.replace('_', '').replace('.', '').isalnum(): + patterns = [f'%"{name}" = type', f'%"{name}"=type', f'%{name} = type', f'%{name}=type'] + else: + patterns = [f'%{name} = type', f'%{name}= type', f'%{name}=type'] + for p in patterns: + if stripped.startswith(p): + skip = True + break + if skip: + break + if not skip: + filtered.append(line) + ir_text = '\n'.join(filtered) + header_end = ir_text.find('\ndefine') + if header_end == -1: + header_end = ir_text.find('\ndeclare') + if header_end == -1: + header_end = ir_text.find('\n@') + if header_end == -1: + header_end = len(ir_text) + insert_pos = ir_text.rfind('\n', 0, header_end) + if insert_pos == -1: + insert_pos = header_end + struct_block = '\n'.join(struct_defs) + '\n' + ir_text = ir_text[:insert_pos + 1] + struct_block + ir_text[insert_pos + 1:] + for name in struct_names: + if name[0].isdigit() or '.' in name: + ir_text = re.sub( + r'%' + re.escape(name) + r'(?=[^a-zA-Z0-9_$\.]|$)', + r'%"' + name + r'"', + ir_text + ) + + return ir_text + + def _collect_classes_and_methods(self, ast_nodes, parent=None): + current_class = None + for node in ast_nodes: + if isinstance(node, str): + continue + node.parent = parent + node_type = type(node).__name__ + if node_type == 'Struct': + if hasattr(node, 'name'): + current_class = node.name + self.class_methods[current_class] = [] + self.class_members[current_class] = [] + if hasattr(node, 'decls') and node.decls: + for decl in node.decls: + if type(decl).__name__ == 'Decl' and hasattr(decl, 'name'): + member_type = self._get_type(decl.type) if hasattr(decl, 'type') else ir.IntType(32) + self.class_members[current_class].append((decl.name, member_type)) + elif node_type == 'FuncDef': + if current_class and current_class in self.class_methods: + MethodName = node.decl.name if hasattr(node.decl, 'name') else 'unknown_method' + if not MethodName.startswith(f"{current_class}."): + MethodName = f"{current_class}.{MethodName}" + self.class_methods[current_class].append(MethodName) + if hasattr(node, 'body') and isinstance(node.body, list): + self._collect_classes_and_methods(node.body, parent=node) + elif hasattr(node, 'BlockItems') and node.BlockItems: + self._collect_classes_and_methods(node.BlockItems, parent=node) + + def _generate_structs(self): + all_classes = set(self.class_methods.keys()) | set(self.class_members.keys()) + + preserved_structs = {} + for name, st in self.structs.items(): + if name not in all_classes: + preserved_structs[name] = st + elif isinstance(st, ir.IdentifiedStructType): + preserved_structs[name] = st + + self.structs.clear() + + for name, st in preserved_structs.items(): + self.structs[name] = st + + # Step 1: 先为所有类创建空的 struct,确保后面可以正确引用 + all_classes = set(self.class_methods.keys()) | set(self.class_members.keys()) + for ClassName in all_classes: + is_packed = ClassName in self.class_packed + if hasattr(self, 'SymbolTable') and self.SymbolTable and ClassName in self.SymbolTable: + Entry = self.SymbolTable[ClassName] + if hasattr(Entry, 'IsExceptionClass') and Entry.IsExceptionClass: + continue + if hasattr(Entry, 'IsEnum') and Entry.IsEnum: + if not getattr(Entry, 'IsRenum', False): + continue + if hasattr(Entry, 'IsTypedef') and Entry.IsTypedef: + if hasattr(Entry, 'BaseType') and Entry.BaseType and not isinstance(Entry.BaseType, (type(None),)): + import lib.includes.t as _t + if not isinstance(Entry.BaseType, (_t._CTypedef,)): + continue + if ClassName in self.structs: + if is_packed: + self.structs[ClassName].packed = True + continue + mangled_name = self._mangle_name(ClassName) + struct_type = ir.IdentifiedStructType(self.module, mangled_name, packed=is_packed) + self.structs[ClassName] = struct_type + + # Step 2: 解析跨模块的成员类型 + for ClassName, annotations in self.class_member_annotations.items(): + if ClassName not in self.class_members: + continue + for i, (member_name, member_type) in enumerate(self.class_members[ClassName]): + if member_name in annotations: + annotation = annotations[member_name] + ResolvedType = None + + if isinstance(annotation, ast.Attribute): + ClassTypeName = annotation.attr + if ClassTypeName in self.structs: + ResolvedType = self.structs[ClassTypeName] + elif isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr): + left = annotation.left + if isinstance(left, ast.Attribute): + ClassTypeName = left.attr + if ClassTypeName in self.structs: + ResolvedType = self.structs[ClassTypeName] + + if ResolvedType: + self.class_members[ClassName][i] = (member_name, ResolvedType) + + struct_name_map = {} + for struct_name, struct in self.structs.items(): + try: + struct_name_map[struct.name] = struct + except AssertionError: + struct_name_map[struct_name] = struct + orig = getattr(struct, '_original_name', None) + if orig: + struct_name_map[orig] = struct + + # Step 3: 更新成员类型,确保使用正确的 mangled struct 引用 + for ClassName in all_classes: + if ClassName not in self.class_members: + continue + for i, (member_name, member_type) in enumerate(self.class_members[ClassName]): + if isinstance(member_type, ir.PointerType): + pointee = member_type.pointee + if isinstance(pointee, ir.IdentifiedStructType): + try: + pname = pointee.name + except AssertionError: + pname = None + struct = struct_name_map.get(pname) if pname else None + if struct is None: + orig = getattr(pointee, '_original_name', None) + struct = struct_name_map.get(orig) if orig else None + if struct is not None: + self.class_members[ClassName][i] = (member_name, ir.PointerType(struct)) + else: + raw_name = pname or '' + if raw_name.startswith('struct.'): + raw_name = raw_name[7:] + new_struct = self._get_or_create_struct(raw_name) + self.class_members[ClassName][i] = (member_name, ir.PointerType(new_struct)) + elif isinstance(member_type, ir.IdentifiedStructType): + try: + mname = member_type.name + except AssertionError: + mname = None + struct = struct_name_map.get(mname) if mname else None + if struct is None: + orig = getattr(member_type, '_original_name', None) + struct = struct_name_map.get(orig) if orig else None + if struct is not None: + self.class_members[ClassName][i] = (member_name, struct) + else: + raw_name = mname or '' + if raw_name.startswith('struct.'): + raw_name = raw_name[7:] + new_struct = self._get_or_create_struct(raw_name) + self.class_members[ClassName][i] = (member_name, new_struct) + + # Step 4: 创建最终的 structs 并设置正确的成员类型 + for ClassName in all_classes: + if hasattr(self, 'SymbolTable') and self.SymbolTable and ClassName in self.SymbolTable: + Entry = self.SymbolTable[ClassName] + if hasattr(Entry, 'IsExceptionClass') and Entry.IsExceptionClass: + continue + if hasattr(Entry, 'IsEnum') and Entry.IsEnum: + if not getattr(Entry, 'IsRenum', False): + continue + existing_st = self.structs.get(ClassName) + if isinstance(existing_st, ir.IdentifiedStructType) and existing_st.elements is not None and len(existing_st.elements) > 0: + # 即使 struct 已有元素,也需要修正 packed 属性 + if ClassName in self.class_packed and not existing_st.packed: + existing_st.packed = True + continue + has_vtable = ClassName in self.class_vtable or ClassName in self._cross_module_vtable_classes + if not has_vtable: + p = self.class_parent.get(ClassName) + while p: + if p in self.class_vtable or p in self._cross_module_vtable_classes: + has_vtable = True + self.class_vtable.add(ClassName) + break + p = self.class_parent.get(p) + has_bitfield = ClassName in self.class_member_bitfields and any( + self.class_member_bitfields[ClassName].get(name, 0) > 0 + for name, _ in self.class_members.get(ClassName, []) + ) + all_members = self.class_members.get(ClassName, []) + all_bitfield = all( + self.class_member_bitfields.get(ClassName, {}).get(name, 0) > 0 + for name, _ in all_members + ) if all_members else False + + mangled_name = self._mangle_name(ClassName) + + if has_bitfield and all_bitfield: + total_bits = sum(self.class_member_bitfields.get(ClassName, {}).get(name, 0) + for name, _ in all_members) + if total_bits <= 8: + storage_type = ir.IntType(8) + elif total_bits <= 16: + storage_type = ir.IntType(16) + elif total_bits <= 32: + storage_type = ir.IntType(32) + else: + storage_type = ir.IntType(64) + member_types = [storage_type] + bitfield_offsets = {} + current_bit_offset = 0 + for name, _ in all_members: + bit_width = self.class_member_bitfields.get(ClassName, {}).get(name, 0) + bitfield_offsets[name] = current_bit_offset + current_bit_offset += bit_width + self.class_member_bitoffsets[ClassName] = bitfield_offsets + else: + member_types = [] + if has_vtable: + member_types.append(ir.PointerType(ir.IntType(8))) + if ClassName in self.class_members: + for _, member_type in self.class_members[ClassName]: + if member_type is None: + member_type = ir.IntType(32) + member_types.append(member_type) + else: + member_types = [ir.IntType(8)] + + # 获取之前创建的 struct 并设置成员 + struct_type = self.structs[ClassName] + if ClassName in self.class_packed: + struct_type.packed = True + # 只在未设置 body 时设置,避免重复定义错误 + if struct_type.elements is None: + struct_type.set_body(*member_types) + + def _create_Vtable_globals(self): + for ClassName, methods in self.class_methods.items(): + if ClassName in self.Vtables: + continue + if not methods: + continue + if ClassName not in self.class_vtable and ClassName not in self._cross_module_vtable_classes: + continue + VtableType = ir.ArrayType(ir.PointerType(ir.IntType(8)), len(methods)) + Vtable = ir.GlobalVariable(self.module, VtableType, name=self._mangle_name(f"{ClassName}_Vtable")) + Vtable.initializer = ir.Constant(VtableType, [ir.Constant(ir.PointerType(ir.IntType(8)), None)] * len(methods)) + Vtable.linkage = 'internal' + self.Vtables[ClassName] = Vtable + + def _fix_global_var_init(self): + for gv_name, gv in list(self.module.globals.items()): + if not isinstance(gv, ir.GlobalVariable): + continue + if gv.linkage in ('external', 'extern_weak'): + continue + needs_fix = False + if gv.initializer is None: + needs_fix = True + elif hasattr(gv.initializer, 'constant') and isinstance(gv.initializer.constant, _Undefined): + needs_fix = True + elif isinstance(gv.initializer, ir.Constant): + if isinstance(gv.initializer.constant, list): + if any(hasattr(c, 'constant') and isinstance(c.constant, _Undefined) for c in gv.initializer.constant): + needs_fix = True + if not needs_fix: + continue + gv.initializer = ir.Constant(gv.value_type, None) + if gv_name.startswith('str_const_') or gv_name.endswith('_Vtable') or gv_name.endswith('_str'): + gv.linkage = 'internal' + + def _zero_value_for_type(self, var_type): + if isinstance(var_type, ir.IntType): + return ir.Constant(var_type, 0) + elif isinstance(var_type, (ir.FloatType, ir.DoubleType)): + return ir.Constant(var_type, 0.0) + elif isinstance(var_type, ir.PointerType): + return ir.Constant(var_type, None) + elif isinstance(var_type, ir.ArrayType): + elem_zv = self._zero_value_for_type(var_type.element) + if elem_zv is None: + return None + return ir.Constant(var_type, [elem_zv] * var_type.count) + elif isinstance(var_type, ir.BaseStructType): + if var_type.elements is not None and len(var_type.elements) > 0: + elem_zvs = [self._zero_value_for_type(m) for m in var_type.elements] + if any(zv is None for zv in elem_zvs): + return None + return ir.Constant(var_type, elem_zvs) + return None + return None + + def _set_Vtable_initializers(self): + for ClassName, methods in self.class_methods.items(): + if ClassName not in self.Vtables: + continue + if not methods: + continue + struct_type = self.structs.get(ClassName) + if not struct_type: + continue + Vtable = self.Vtables[ClassName] + Vtable_entries = [] + for MethodName in methods: + short_name = MethodName.split('.')[-1] if '.' in MethodName else MethodName + full_MethodName = f"{ClassName}.{short_name}" + func = None + if full_MethodName in self.functions: + func = self.functions[full_MethodName] + if func is None: + parent_cls = self.class_parent.get(ClassName) + while parent_cls: + parent_full = f"{parent_cls}.{short_name}" + if parent_full in self.functions: + func = self.functions[parent_full] + break + parent_cls = self.class_parent.get(parent_cls) + if func is None: + Vtable_entries.append(ir.Constant(ir.PointerType(ir.IntType(8)), None)) + continue + Vtable_entries.append(func.bitcast(ir.PointerType(ir.IntType(8)))) + Vtable.initializer = ir.Constant(Vtable.type.pointee, Vtable_entries) diff --git a/lib/core/LLVMCG/TypeConvert.py b/lib/core/LLVMCG/TypeConvert.py new file mode 100644 index 0000000..ac64018 --- /dev/null +++ b/lib/core/LLVMCG/TypeConvert.py @@ -0,0 +1,618 @@ +from __future__ import annotations +import ast +import llvmlite.ir as ir + + +class TypeConvertMixin: + + def _ctype_to_llvm(self, type_info): + from lib.includes import t as _t + from lib.includes.t import CTypeRegistry + from lib.core.Handles.HandlesBase import CTypeInfo as _CTypeInfo + + if type_info is None: + return ir.IntType(32) + + if isinstance(type_info, str): + return self._type_str_to_llvm(type_info) + + if not isinstance(type_info, _CTypeInfo): + return ir.IntType(32) + + if type_info.IsFuncPtr: + return ir.IntType(8).as_pointer() + + if type_info.IsState and type_info.PtrCount == 0 and not type_info.IsTypedef: + if type_info.BaseType is None or (isinstance(type_info.BaseType, type) and issubclass(type_info.BaseType, _t.CVoid)) or isinstance(type_info.BaseType, _t.CVoid): + return ir.VoidType() + + if type_info.IsTypedef and type_info.Name: + resolved = self._resolve_typedef_ctype(type_info) + if resolved is not None: + return resolved + + BaseType = self._base_ctype_to_llvm(type_info.BaseType, type_info) + + result = BaseType + for _ in range(type_info.PtrCount): + if isinstance(result, ir.VoidType): + result = ir.IntType(8).as_pointer() + else: + result = ir.PointerType(result) + + for dim in reversed(type_info.ArrayDims): + try: + dim_val = int(dim) + if dim_val > 0: + result = ir.ArrayType(result, dim_val) + except (ValueError, TypeError): + pass + + return result + + def _resolve_typedef_ctype(self, type_info): + from lib.includes import t as _t + from lib.core.Handles.HandlesBase import CTypeInfo as _CTypeInfo + + name = type_info.Name + if not name or not hasattr(self, 'SymbolTable') or not self.SymbolTable: + return None + + entry = self.SymbolTable.get(name) + if not entry or not isinstance(entry, _CTypeInfo): + return None + + if entry.BaseType and (not isinstance(entry.BaseType, _t._CTypedef) or entry.PtrCount > 0): + resolved = entry.Copy() + resolved.IsTypedef = False + if type_info.PtrCount > resolved.PtrCount: + resolved.PtrCount = type_info.PtrCount + return self._ctype_to_llvm(resolved) + + if entry.OriginalType: + if isinstance(entry.OriginalType, _CTypeInfo): + resolved = entry.OriginalType.Copy() + resolved.IsTypedef = False + if type_info.PtrCount > resolved.PtrCount: + resolved.PtrCount = type_info.PtrCount + return self._ctype_to_llvm(resolved) + elif isinstance(entry.OriginalType, str): + resolved = _CTypeInfo.FromTypeName(entry.OriginalType) + if resolved and resolved.BaseType: + resolved.IsTypedef = False + if type_info.PtrCount > resolved.PtrCount: + resolved.PtrCount = type_info.PtrCount + return self._ctype_to_llvm(resolved) + + return None + + def _base_ctype_to_llvm(self, BaseType, type_info=None): + from lib.includes import t as _t + from lib.includes.t import CTypeRegistry + + if BaseType is None: + return ir.VoidType() + + if isinstance(BaseType, (tuple, list)): + elem_types = [self._base_ctype_to_llvm(bt, type_info) for bt in BaseType] + return ir.LiteralStructType(elem_types) if elem_types else ir.IntType(32) + + if isinstance(BaseType, type) and issubclass(BaseType, _t.CType): + BaseType = BaseType() + + if isinstance(BaseType, _t.CVoid): + return ir.VoidType() + + if isinstance(BaseType, _t.CStruct): + struct_name = getattr(BaseType, 'name', '') or (type_info.Name if type_info else '') + if struct_name and struct_name in self.structs: + return self.structs[struct_name] + if struct_name: + return self._get_or_create_struct(struct_name) + return ir.LiteralStructType([]) + + if isinstance(BaseType, (_t.CEnum, _t.REnum)): + enum_name = type_info.Name if type_info else '' + if enum_name and enum_name in self.structs: + return self.structs[enum_name] + return ir.IntType(32) + + if isinstance(BaseType, _t.CUnion): + union_name = type_info.Name if type_info else '' + if union_name and union_name in self.structs: + return self.structs[union_name] + if union_name: + return self._get_or_create_struct(union_name) + return ir.IntType(32) + + if isinstance(BaseType, _t._CTypedef): + typedef_name = getattr(BaseType, 'value', '') or (type_info.Name if type_info else '') + if typedef_name and hasattr(self, 'SymbolTable') and self.SymbolTable: + from lib.core.Handles.HandlesBase import CTypeInfo as _CTypeInfo + entry = self.SymbolTable.get(typedef_name) + if entry and isinstance(entry, _CTypeInfo) and entry.BaseType: + if not isinstance(entry.BaseType, _t._CTypedef) or entry.PtrCount > 0: + return self._base_ctype_to_llvm(entry.BaseType, entry) + return ir.IntType(32) + + if isinstance(BaseType, _t.CDefine): + # Use 64-bit type if the define value exceeds 32-bit range + if type_info and hasattr(type_info, 'DefineValue') and isinstance(type_info.DefineValue, int): + if type_info.DefineValue < 0 or type_info.DefineValue > 0xFFFFFFFF: + return ir.IntType(64) + return ir.IntType(32) + + if isinstance(BaseType, _t.CPass): + return ir.VoidType() + + llvm_str = CTypeRegistry.CTypeToLLVM(type(BaseType)) + return self._llvm_str_to_ir(llvm_str) + + def _llvm_str_to_ir(self, llvm_str): + _map = { + 'void': ir.VoidType, 'i1': lambda: ir.IntType(1), + 'i8': lambda: ir.IntType(8), 'i16': lambda: ir.IntType(16), + 'i32': lambda: ir.IntType(32), 'i64': lambda: ir.IntType(64), + 'i128': lambda: ir.IntType(128), 'half': lambda: ir.IntType(16), + 'float': ir.FloatType, 'double': ir.DoubleType, + 'fp128': lambda: ir.IntType(128), 'i8*': lambda: ir.IntType(8).as_pointer(), + 'f8': lambda: ir.IntType(8), 'f16': lambda: ir.IntType(16), + 'f32': ir.FloatType, 'f64': ir.DoubleType, 'f128': lambda: ir.IntType(128), + } + factory = _map.get(llvm_str) + if factory: + return factory() if callable(factory) else factory + return ir.IntType(32) + + def _resolve_typedef(self, type_name: str) -> str: + if type_name in {'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum'}: + return type_name + if type_name == 'Callable': + return 'Callable' + visited = set() + current = type_name + while current not in visited: + visited.add(current) + if hasattr(self, 'SymbolTable') and self.SymbolTable and current in self.SymbolTable: + Entry = self.SymbolTable[current] + if isinstance(Entry, dict) and Entry.get('type') == 'typedef': + OriginalType = Entry.get('OriginalType', '') + if OriginalType: + current = OriginalType + continue + elif hasattr(Entry, 'IsTypedef') and Entry.IsTypedef: + if hasattr(Entry, 'OriginalType') and Entry.OriginalType: + if isinstance(Entry.OriginalType, _CTypeInfo): + if Entry.OriginalType.IsFuncPtr: + return 'Callable' + return Entry.OriginalType.ToString() if Entry.OriginalType.BaseType else current + elif isinstance(Entry.OriginalType, str): + current = Entry.OriginalType + continue + if hasattr(Entry, 'BaseType') and Entry.BaseType: + from lib.includes import t as _t + if not isinstance(Entry.BaseType, (_t._CTypedef,)) or getattr(Entry, 'PtrCount', 0) > 0: + resolved = self._resolve_ctype_to_str(Entry) + if resolved and resolved != current: + current = resolved + continue + from lib.core.Handles.HandlesBase import BuiltinTypeMap + bm = BuiltinTypeMap.Get(current) + if bm: + base_cls = bm[0] + try: + instance = base_cls() + cname = getattr(instance, 'CName', '') + if cname: + current = cname + ' *' * bm[1] + continue + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + import logging; logging.warning(f"异常被忽略: {_e}") + pass + from lib.core.Handles.HandlesBase import BuiltinTypeMap + bm = BuiltinTypeMap.Get(current) + if bm and bm[1] > 0: + base_cls = bm[0] + try: + instance = base_cls() + cname = getattr(instance, 'CName', '') + if cname: + current = cname + ' *' * bm[1] + continue + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + import logging; logging.warning(f"异常被忽略: {_e}") + pass + break + return current + + def _resolve_ctype_to_str(self, type_info) -> str: + from lib.includes import t as _t + parts = [] + base = type_info.BaseType + if base is None or base is _t.CVoid or isinstance(base, _t.CVoid): + parts.append('void') + elif isinstance(base, _t._CTypedef) or base is _t._CTypedef: + return '' + elif isinstance(base, _t.CStruct) or base is _t.CStruct: + parts.append(f'struct {getattr(base, "name", "")}') + elif isinstance(base, _t.CEnum) or base is _t.CEnum: + parts.append(f'enum {getattr(base, "name", "")}') + else: + cname = getattr(base, 'CName', '') + if not cname and isinstance(base, type) and issubclass(base, _t.CType): + try: + inst = base() + cname = getattr(inst, 'CName', '') + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + import logging; logging.warning(f"异常被忽略: {_e}") + pass + if cname: + parts.append(cname) + else: + return '' + if type_info.PtrCount > 0: + parts.append('*' * type_info.PtrCount) + return ' '.join(parts) + + def _type_str_to_llvm(self, type_str, IsPtr=False): + type_str = type_str.strip() + cache_key = (type_str, IsPtr) + cached = self._type_cache.get(cache_key) + if cached is not None: + return cached + result = self._type_str_to_llvm_impl(type_str, IsPtr) + if result is not None: + if isinstance(result, (ir.IntType, ir.FloatType, ir.DoubleType, ir.VoidType)): + self._type_cache[cache_key] = result + elif isinstance(result, ir.PointerType) and isinstance(result.pointee, (ir.IntType, ir.FloatType, ir.DoubleType, ir.VoidType)): + self._type_cache[cache_key] = result + elif isinstance(result, ir.ArrayType) and not isinstance(result.element, (ir.IdentifiedStructType, ir.LiteralStructType)): + self._type_cache[cache_key] = result + return result + + _CType2LLVM = _type_str_to_llvm + + def _type_str_to_llvm_impl(self, type_str, IsPtr=False): + array_dims = [] + dim_match = __import__('re').findall(r'\[(\d+)\]', type_str) + if dim_match: + array_dims = [int(d) for d in dim_match] + type_str = __import__('re').sub(r'\s*\[\d+\]', '', type_str).strip() + result = self._type_str_to_llvm_base(type_str, IsPtr) + for dim in reversed(array_dims): + result = ir.ArrayType(result, dim) + return result + + def _type_str_to_llvm_base(self, type_str, IsPtr=False): + ptr_depth = 0 + while type_str.endswith('*'): + ptr_depth += 1 + type_str = type_str[:-1].strip() + if ptr_depth > 0: + IsPtr = True + if type_str in {'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum'}: + if IsPtr: + result = ir.IntType(8).as_pointer() + for _ in range(ptr_depth - 1): + result = ir.PointerType(result) + return result + return ir.IntType(32) + if type_str in {'const', 'volatile'}: + return ir.IntType(8) + if type_str == 'Callable': + return ir.IntType(8).as_pointer() + if type_str.startswith('const '): + inner_type = self._type_str_to_llvm(type_str[6:].strip(), IsPtr) + return inner_type + if type_str.startswith('volatile '): + inner_type = self._type_str_to_llvm(type_str[9:].strip(), IsPtr) + return inner_type + if type_str.startswith('const_'): + inner_type = self._type_str_to_llvm(type_str[6:], IsPtr) + return inner_type + if type_str.startswith('volatile_'): + inner_type = self._type_str_to_llvm(type_str[9:], IsPtr) + return inner_type + if type_str.startswith('static '): + return self._type_str_to_llvm(type_str[7:].strip(), IsPtr) + if type_str.startswith('extern '): + return self._type_str_to_llvm(type_str[7:].strip(), IsPtr) + if type_str.startswith('register '): + return self._type_str_to_llvm(type_str[9:].strip(), IsPtr) + if type_str.startswith('inline '): + return self._type_str_to_llvm(type_str[7:].strip(), IsPtr) + if type_str.startswith('export '): + return self._type_str_to_llvm(type_str[7:].strip(), IsPtr) + resolved = self._resolve_typedef(type_str) + if resolved != type_str: + if '*' in resolved: + IsPtr = False + return self._type_str_to_llvm(resolved, IsPtr) + if type_str.endswith('*'): + BaseType = type_str[:-1].strip() + base_llvm = self._basic_type_to_llvm(BaseType) + if base_llvm is not None and isinstance(base_llvm, ir.VoidType): + result = ir.IntType(8).as_pointer() + for _ in range(ptr_depth): + result = ir.PointerType(result) + return result + if base_llvm is not None and not isinstance(base_llvm, ir.VoidType): + if isinstance(base_llvm, ir.PointerType): + return base_llvm + return ir.PointerType(base_llvm) + if BaseType in self.structs: + return ir.PointerType(self.structs[BaseType]) + if BaseType.startswith('struct '): + stripped = BaseType[7:].strip() + if stripped in self.structs: + return ir.PointerType(self.structs[stripped]) + if '.' in BaseType: + LastPart = BaseType.split('.')[-1] + if LastPart in self.structs: + return ir.PointerType(self.structs[LastPart]) + placeholder = self._get_or_create_struct(LastPart) + return ir.PointerType(placeholder) + if base_llvm is not None and isinstance(base_llvm, ir.VoidType): + return ir.PointerType(ir.IntType(8)) + if type_str.startswith('{') and type_str.endswith('}'): + inner = type_str[1:-1].strip() + elem_strs = [] + depth = 0 + current = '' + for ch in inner: + if ch == ',' and depth == 0: + elem_strs.append(current.strip()) + current = '' + else: + if ch == '{': + depth += 1 + elif ch == '}': + depth -= 1 + current += ch + if current.strip(): + elem_strs.append(current.strip()) + elem_types = [] + for es in elem_strs: + et = self._type_str_to_llvm(es, '*' in es) + if isinstance(et, ir.VoidType): + et = ir.IntType(8).as_pointer() + elem_types.append(et) + if elem_types: + return ir.LiteralStructType(elem_types) + return ir.IntType(32) + if type_str in {'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum'}: + return ir.IntType(32) + if type_str.startswith('%'): + stripped = type_str[1:] + if stripped in {'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum'}: + return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32)) + basic_stripped = self._basic_type_to_llvm(stripped) + if basic_stripped is not None: + if IsPtr and not isinstance(basic_stripped, ir.VoidType): + return ir.PointerType(basic_stripped) + return basic_stripped + if hasattr(self, 'SymbolTable') and self.SymbolTable and type_str in self.SymbolTable: + _Entry = self.SymbolTable[type_str] + if hasattr(_Entry, 'IsTypedef') and _Entry.IsTypedef: + resolved_str = self._resolve_typedef(type_str) + if resolved_str != type_str: + return self._type_str_to_llvm(resolved_str, IsPtr) + if hasattr(_Entry, 'BaseType') and _Entry.BaseType: + from lib.includes import t as _t + if not isinstance(_Entry.BaseType, (_t._CTypedef,)) or getattr(_Entry, 'PtrCount', 0) > 0: + resolved = self._resolve_ctype_to_str(_Entry) + if resolved: + return self._type_str_to_llvm(resolved, IsPtr) + if hasattr(_Entry, 'IsRenum') and _Entry.IsRenum: + if type_str in self.structs: + return self.structs[type_str] + if hasattr(_Entry, 'IsEnum') and _Entry.IsEnum: + return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32)) + if hasattr(_Entry, 'IsExceptionClass') and _Entry.IsExceptionClass: + return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32)) + if hasattr(_Entry, 'BaseType'): + from lib.includes import t as _t + if (isinstance(_Entry.BaseType, type) and issubclass(_Entry.BaseType, _t.CEnum)) or _Entry.BaseType is _t.CEnum: + return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32)) + for ClassName in self.structs: + if type_str == ClassName: + if IsPtr: + return ir.PointerType(self.structs[ClassName]) + return self.structs[ClassName] + if '.' in type_str and not type_str.startswith('%'): + LastPart = type_str.split('.')[-1] + basic_last = self._basic_type_to_llvm(LastPart) + if basic_last is not None: + if IsPtr and not isinstance(basic_last, ir.VoidType): + return ir.PointerType(basic_last) + return basic_last + if hasattr(self, 'SymbolTable') and self.SymbolTable and LastPart in self.SymbolTable: + _Entry = self.SymbolTable[LastPart] + if hasattr(_Entry, 'IsTypedef') and _Entry.IsTypedef: + resolved_str = self._resolve_typedef(LastPart) + if resolved_str != LastPart: + return self._type_str_to_llvm(resolved_str, IsPtr) + if hasattr(_Entry, 'BaseType') and _Entry.BaseType: + from lib.includes import t as _t + if not isinstance(_Entry.BaseType, (_t._CTypedef,)) or getattr(_Entry, 'PtrCount', 0) > 0: + resolved = self._resolve_ctype_to_str(_Entry) + if resolved: + return self._type_str_to_llvm(resolved, IsPtr) + if hasattr(_Entry, 'IsRenum') and _Entry.IsRenum: + if LastPart in self.structs: + return self.structs[LastPart] + if hasattr(_Entry, 'IsEnum') and _Entry.IsEnum: + return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32)) + if hasattr(_Entry, 'IsExceptionClass') and _Entry.IsExceptionClass: + return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32)) + if hasattr(_Entry, 'BaseType'): + from lib.includes import t as _t + if (isinstance(_Entry.BaseType, type) and issubclass(_Entry.BaseType, _t.CEnum)) or _Entry.BaseType is _t.CEnum: + return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32)) + if LastPart in self.structs: + if IsPtr: + return ir.PointerType(self.structs[LastPart]) + return self.structs[LastPart] + placeholder = self._get_or_create_struct(LastPart) + if IsPtr: + return ir.PointerType(placeholder) + return placeholder + if type_str.startswith('struct '): + stripped = type_str[7:].strip().replace(' *', '').replace('*', '') + if stripped in self.structs: + if IsPtr: + return ir.PointerType(self.structs[stripped]) + return self.structs[stripped] + basic_match = self._basic_type_to_llvm(stripped) + if basic_match is not None: + if IsPtr and not isinstance(basic_match, ir.VoidType): + return ir.PointerType(basic_match) + return basic_match + placeholder = self._get_or_create_struct(stripped) + if IsPtr: + return ir.PointerType(placeholder) + return placeholder + if type_str.startswith('%struct.'): + stripped = type_str[8:].strip().replace(' *', '').replace('*', '') + if stripped in self.structs: + if IsPtr: + return ir.PointerType(self.structs[stripped]) + return self.structs[stripped] + basic_match = self._basic_type_to_llvm(stripped) + if basic_match is not None: + if IsPtr and not isinstance(basic_match, ir.VoidType): + return ir.PointerType(basic_match) + return basic_match + placeholder = self._get_or_create_struct(stripped) + if IsPtr: + return ir.PointerType(placeholder) + return placeholder + if type_str.startswith('union '): + stripped = type_str[6:].strip() + basic_match = self._basic_type_to_llvm(stripped) + if basic_match is not None: + if IsPtr and not isinstance(basic_match, ir.VoidType): + return ir.PointerType(basic_match) + return basic_match + if type_str.endswith('*'): + pointee = self._type_str_to_llvm(type_str[:-1].strip()) + if isinstance(pointee, ir.VoidType): + return ir.PointerType(ir.IntType(8)) + return ir.PointerType(pointee) + result = self._basic_type_to_llvm(type_str) + if result is None: + result = ir.IntType(32) + if IsPtr: + if isinstance(result, ir.VoidType): + result = ir.PointerType(ir.IntType(8)) + elif isinstance(result, ir.PointerType): + pass + else: + result = ir.PointerType(result) + for _ in range(ptr_depth - 1): + result = ir.PointerType(result) + return result + + def _llvm_str_to_ir(self, llvm_str): + _LLVM_IR_TYPES = { + 'void': ir.VoidType(), 'i1': ir.IntType(1), 'i8': ir.IntType(8), + 'i16': ir.IntType(16), 'i32': ir.IntType(32), 'i64': ir.IntType(64), + 'i128': ir.IntType(128), 'float': ir.FloatType(), 'double': ir.DoubleType(), + 'half': ir.IntType(16), 'fp128': ir.IntType(128), + } + return _LLVM_IR_TYPES.get(llvm_str) + + def _basic_type_to_llvm(self, type_str): + _LLVM_IR_TYPES = { + 'void': ir.VoidType(), 'i1': ir.IntType(1), 'i8': ir.IntType(8), + 'i16': ir.IntType(16), 'i32': ir.IntType(32), 'i64': ir.IntType(64), + 'i128': ir.IntType(128), 'f32': ir.FloatType(), 'f64': ir.DoubleType(), + 'half': ir.IntType(16), 'fp128': ir.IntType(128), + } + if type_str in _LLVM_IR_TYPES: + return _LLVM_IR_TYPES[type_str] + from lib.includes.t import CTypeRegistry + resolved = CTypeRegistry.ResolveName(type_str) + if resolved is not None: + ctype_cls, ptr_level = resolved + llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls) + if llvm_str: + base = self._llvm_str_to_ir(llvm_str) + if base is not None: + for _ in range(ptr_level): + if isinstance(base, ir.VoidType): + base = ir.IntType(8).as_pointer() + else: + base = ir.PointerType(base) + return base + cnameres = CTypeRegistry.CNameToClass(type_str) + if cnameres is not None: + llvm_str = CTypeRegistry.CTypeToLLVM(cnameres) + if llvm_str: + return self._llvm_str_to_ir(llvm_str) + if type_str == '*': + return ir.IntType(8) + if type_str in ('const_', 'const'): + return ir.IntType(8) + return None + + def _is_type_unsigned(self, type_str): + s = type_str.strip() + if s.endswith('*'): + return True + if s.startswith('unsigned'): + return True + from lib.includes.t import CTypeRegistry + resolved = CTypeRegistry.ResolveName(s) + if resolved is not None: + ctype_cls, _ = resolved + try: + inst = ctype_cls() + if getattr(inst, 'IsSigned', None) is False: + return True + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _config_mode + if _config_mode == "strict": + raise + _vlog().warning(f"判断类型符号性失败: {_e}", "Exception") + cnameres = CTypeRegistry.CNameToClass(s) + if cnameres is not None: + try: + inst = cnameres() + if getattr(inst, 'IsSigned', None) is False: + return True + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _config_mode + if _config_mode == "strict": + raise + _vlog().warning(f"判断类型符号性失败: {_e}", "Exception") + return False + + def _record_var_signedness(self, name, type_str_or_bool): + if isinstance(type_str_or_bool, bool): + self.var_signedness[name] = type_str_or_bool + else: + self.var_signedness[name] = self._is_type_unsigned(type_str_or_bool) + + def _is_var_unsigned(self, name): + return self.var_signedness.get(name, False) + + def _check_node_unsigned(self, node): + if isinstance(node, ast.Name): + return self._is_var_unsigned(node.id) + if isinstance(node, ast.BinOp): + return self._check_node_unsigned(node.left) or self._check_node_unsigned(node.right) + if isinstance(node, ast.UnaryOp): + return self._check_node_unsigned(node.operand) + if isinstance(node, ast.Call): + return False + if isinstance(node, ast.Subscript): + return self._check_node_unsigned(node.value) + if isinstance(node, ast.Attribute): + return self._check_node_unsigned(node.value) + return False diff --git a/lib/core/LLVMCG/VaArg.py b/lib/core/LLVMCG/VaArg.py new file mode 100644 index 0000000..b3d5370 --- /dev/null +++ b/lib/core/LLVMCG/VaArg.py @@ -0,0 +1,94 @@ +from __future__ import annotations +import sys +import llvmlite.ir as ir +from lib.core.LLVMCG.BaseGen import VaArgInstruction + + +class VaArgMixin: + + def _get_va_start_intrinsic(self): + if 'llvm.va_start' in self.functions: + return self.functions['llvm.va_start'] + ftype = ir.FunctionType(ir.VoidType(), [ir.IntType(8).as_pointer()]) + func = ir.Function(self.module, ftype, name='llvm.va_start') + self.functions['llvm.va_start'] = func + return func + + def _get_va_end_intrinsic(self): + if 'llvm.va_end' in self.functions: + return self.functions['llvm.va_end'] + ftype = ir.FunctionType(ir.VoidType(), [ir.IntType(8).as_pointer()]) + func = ir.Function(self.module, ftype, name='llvm.va_end') + self.functions['llvm.va_end'] = func + return func + + def emit_va_start(self, va_list_ptr): + if not self.builder: + return None + func = self._get_va_start_intrinsic() + i8ptr_type = ir.IntType(8).as_pointer() + if va_list_ptr.type == i8ptr_type: + self.builder.call(func, [va_list_ptr]) + else: + ptr = self.builder.bitcast(va_list_ptr, i8ptr_type, name="va_list_i8ptr") + self.builder.call(func, [ptr]) + return None + + def _emit_stack_align(self, alignment=16): + if not self.builder: + return None + void = ir.VoidType() + asm_type = ir.FunctionType(void, []) + mask = -alignment + asm_str = f"andq ${mask}, %rsp" + asm_func = ir.InlineAsm(asm_type, asm_str, "~{dirflag},~{fpsr},~{flags},~{rsp}", side_effect=True) + self.builder.call(asm_func, [], name="align_stack") + return None + + def emit_va_end(self, va_list_ptr): + if not self.builder: + return None + func = self._get_va_end_intrinsic() + i8ptr_type = ir.IntType(8).as_pointer() + if va_list_ptr.type == i8ptr_type: + self.builder.call(func, [va_list_ptr]) + else: + ptr = self.builder.bitcast(va_list_ptr, i8ptr_type, name="va_list_i8ptr") + self.builder.call(func, [ptr]) + return None + + def emit_va_arg(self, va_list_ptr, arg_type): + if not self.builder: + return self._ZeroConst(arg_type) + if not hasattr(self, '_va_arg_counter'): + self._va_arg_counter = 0 + self._va_arg_counter += 1 + import sys + is_x86_64 = sys.platform in ('win32', 'win64', 'windows', 'linux', 'linux2', 'darwin') + if is_x86_64: + if isinstance(arg_type, ir.PointerType): + va_arg_type = ir.IntType(64) + elif isinstance(arg_type, (ir.FloatType, ir.DoubleType)): + va_arg_type = ir.DoubleType() + elif isinstance(arg_type, ir.IntType) and arg_type.width < 64: + va_arg_type = ir.IntType(64) + else: + va_arg_type = arg_type + instr = VaArgInstruction(self.builder.block, va_arg_type, 'va_arg', (va_list_ptr,), name=f'va_arg_raw_{self._va_arg_counter}') + self.builder._insert(instr) + if va_arg_type != arg_type: + if isinstance(arg_type, ir.PointerType): + result = self.builder.inttoptr(instr, arg_type, name=f'va_arg_ptr_{self._va_arg_counter}') + elif isinstance(arg_type, ir.FloatType): + result = self.builder.fptrunc(instr, arg_type, name=f'va_arg_fptrunc_{self._va_arg_counter}') + else: + result = self.builder.trunc(instr, arg_type, name=f'va_arg_trunc_{self._va_arg_counter}') + else: + result = instr + return result + else: + if isinstance(arg_type, ir.IntType) and arg_type.width < 64: + arg_type = ir.IntType(64) + instr = VaArgInstruction(self.builder.block, arg_type, 'va_arg', (va_list_ptr,), name=f'va_arg_raw_{self._va_arg_counter}') + self.builder._insert(instr) + return instr diff --git a/lib/core/LLVMCG/__init__.py b/lib/core/LLVMCG/__init__.py new file mode 100644 index 0000000..6b231e9 --- /dev/null +++ b/lib/core/LLVMCG/__init__.py @@ -0,0 +1,34 @@ +""" +LLVMCG 包 - LLVM 代码生成器模块 + +将 LlvmCodeGenerator.py 拆分为多个 Mixin 模块: +- BaseGen: 基础设施(__init__、平台解析、名称修饰、函数查找) +- TypeConvert: 类型转换(CType -> LLVM IR 类型) +- StructGen: 结构体生成(struct/vtable 定义与初始化) +- MemoryOps: 内存操作(alloca/Load/store/coerce) +- ExprGen: 表达式生成(常量、二元运算、返回、printf) +- FuncGen: 函数处理(参数调整、成员偏移、函数声明) +- VaArg: 变长参数处理(va_start/va_end/va_arg) +""" + +from lib.core.LLVMCG.BaseGen import ( + BaseGenMixin, + VaArgInstruction, +) +from lib.core.LLVMCG.TypeConvert import TypeConvertMixin +from lib.core.LLVMCG.StructGen import StructGenMixin +from lib.core.LLVMCG.MemoryOps import MemoryOpsMixin +from lib.core.LLVMCG.ExprGen import ExprGenMixin +from lib.core.LLVMCG.FuncGen import FuncGenMixin +from lib.core.LLVMCG.VaArg import VaArgMixin + +__all__ = [ + 'BaseGenMixin', + 'TypeConvertMixin', + 'StructGenMixin', + 'MemoryOpsMixin', + 'ExprGenMixin', + 'FuncGenMixin', + 'VaArgMixin', + 'VaArgInstruction', +] diff --git a/lib/core/LlvmCodeGenerator.py b/lib/core/LlvmCodeGenerator.py index 2f3c786..78fbd1c 100644 --- a/lib/core/LlvmCodeGenerator.py +++ b/lib/core/LlvmCodeGenerator.py @@ -1,2556 +1,46 @@ -import re -import ast -import os -import hashlib +# LLVM 代码生成器主类 +# 通过 Mixin 模式组合各功能模块,保持向后兼容的导入路径 +# +# 拆分后的模块位于 lib/core/LLVMCG/ 目录下: +# - BaseGen.py: __init__、平台解析、名称修饰、函数查找 +# - TypeConvert.py: 类型转换(CType -> LLVM IR) +# - StructGen.py: 结构体生成(struct/vtable) +# - MemoryOps.py: 内存操作(alloca/Load/store) +# - ExprGen.py: 表达式生成(常量、二元运算、返回) +# - FuncGen.py: 函数处理(参数调整、成员偏移) +# - VaArg.py: 变长参数处理 + +from lib.core.LLVMCG.BaseGen import BaseGenMixin, VaArgInstruction +from lib.core.LLVMCG.TypeConvert import TypeConvertMixin +from lib.core.LLVMCG.StructGen import StructGenMixin +from lib.core.LLVMCG.MemoryOps import MemoryOpsMixin +from lib.core.LLVMCG.ExprGen import ExprGenMixin +from lib.core.LLVMCG.FuncGen import FuncGenMixin +from lib.core.LLVMCG.VaArg import VaArgMixin + +# from lib.core.Translator.LlvmGenerator import LlvmGeneratorMixin + import llvmlite.ir as ir -from llvmlite.ir.values import _Undefined -from lib.core.AsmIntelToAtt import convert as _intel_to_att -TYPEDEF_NAMES = {'UINT', 'INT', 'BYTE', 'BYTEPTR', 'WORD', 'DWORD', 'QWORD', - 'INT8', 'INT16', 'INT32', 'INT64', 'UINT8', 'UINT16', 'UINT32', 'UINT64', - 'INTPTR', 'UINTPTR', 'SIZE_T', 'SSIZE_T', 'PTRDIFF_T', - 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum', - 'atomic_int', 'atomic_uint', 'atomic_long', 'atomic_ulong', - 'atomic_int8', 'atomic_uint8', 'atomic_int16', 'atomic_uint16', - 'atomic_int32', 'atomic_uint32', 'atomic_int64', 'atomic_uint64', - 'atomic_ptr', 'atomic_flag', 'typedef', - 'list', 'dict', 'tuple', 'set', 'str', 'bytes', 'array', - 'BOOL', 'type'} +class LlvmCodeGenerator( + BaseGenMixin, + TypeConvertMixin, + StructGenMixin, + MemoryOpsMixin, + ExprGenMixin, + FuncGenMixin, + VaArgMixin, +): + """LLVM IR 代码生成器 -class VaArgInstruction(ir.Instruction): - def descr(self, buf): - ptr = self.operands[0] - buf.append("va_arg {0} {1}, {2}\n".format( - ptr.type, ptr.get_reference(), self.type)) + 通过 Mixin 模式组合各功能模块。 + 实际方法实现分布在 lib/core/LLVMCG/ 下的各模块中。 + """ + #builder: ir.IRBuilder = None + #_Trans: LlvmGeneratorMixin = None + pass -class LlvmCodeGenerator: - - @staticmethod - def _parse_triple(triple): - """解析目标三元组,返回平台信息字典""" - info = { - 'is_windows': False, 'is_linux': False, 'is_macos': False, - 'is_x86_64': False, 'is_arm64': False, 'is_32bit': False, - 'ptr_size': 8, 'long_size': 8, 'wchar_t_size': 32, - } - if not triple: - return info - triple_lower = triple.lower() - # 检测操作系统 - if 'windows' in triple_lower or 'win32' in triple_lower or 'mingw' in triple_lower or 'msvc' in triple_lower or 'cygwin' in triple_lower: - info['is_windows'] = True - # Windows LLP64: long = 32 位, wchar_t = 16 位 - info['long_size'] = 32 - info['wchar_t_size'] = 16 - elif 'linux' in triple_lower: - info['is_linux'] = True - elif 'darwin' in triple_lower or 'macos' in triple_lower or 'apple' in triple_lower: - info['is_macos'] = True - # 检测架构 - if 'x86_64' in triple_lower or 'amd64' in triple_lower or 'x64' in triple_lower: - info['is_x86_64'] = True - elif 'aarch64' in triple_lower or 'arm64' in triple_lower: - info['is_arm64'] = True - elif 'i386' in triple_lower or 'i686' in triple_lower or 'arm' in triple_lower: - info['is_32bit'] = True - info['ptr_size'] = 4 - info['long_size'] = 32 - if info['is_windows']: - info['wchar_t_size'] = 16 - else: - info['wchar_t_size'] = 32 - return info - - def __init__(self, triple=None, datalayout=None): - self.module = ir.Module(name="transpyc_module") - if triple: - self.module.triple = triple - else: - self.module.triple = "x86_64-none-elf" - if datalayout: - self.module.data_layout = datalayout - else: - self.module.data_layout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" - - # 解析目标平台信息 - self._platform_info = self._parse_triple(self.module.triple) - self.ptr_size = self._platform_info['ptr_size'] - # 根据目标平台配置 t 模块中的平台相关类型大小 - import t as _t - _t.configure_platform(self.module.triple) - self.builder = None - self.func = None - self.functions = {} - self.variables = {} - self._direct_values = {} - self._reg_values = {} - self.var_signedness = {} - self._unsigned_results = {} - self.string_const_counter = 0 - self.Vtables = {} - self.class_methods = {} - self.class_members = {} - self.class_member_defaults = {} - self.class_member_signeds = {} - self.class_member_bitfields = {} - self.class_member_byteorders = {} - self.class_member_element_class = {} - self.class_member_bitoffsets = {} - self.structs = {} - self._cross_module_vtable_classes = set() - self.class_vtable = set() - self.class_parent = {} - # Store member annotations for deferred type resolution (cross-module class references) - self.class_member_annotations = {} - self.loop_break_targets = [] - self.loop_continue_targets = [] - self.eh_jmp_buf_stack = [] - self.eh_except_block_stack = [] - self.eh_finally_stack = [] - self.global_vars = set() - self.nonlocal_params = {} - self._variable_scope_stack = [] # Stack of outer scope variables for nested function nonlocal lookup - self.var_struct_class = {} - self.global_struct_class = {} - self.var_type_info = {} - self.var_const_flags = {} - self._current_source_file = None - self._current_source_lines = [] - self._ns_cache = {} - self._type_cache = {} - self._typedef_cache = {} - self._func_sig_cache = {} - self.var_type_assignments = {} - self._temp_struct_ptrs = [] - self._stop_iter_flag_param = None - self._local_heap_ptrs = [] - self._var_to_heap_ptr = {} - self.known_return_types = {} - self._current_lineno = 0 - self._current_node_info = "" - self.module_sha1 = None - self.module_sha1_map = {} - self._temp_dir = None - self._export_funcs = set() - self._export_extern_funcs = set() - self._current_module_func_names = set() - self.class_packed = set() - self._define_constants = {} - pi = self._platform_info - # 根据目标平台设置宏(声明式,从三元组推导) - if pi['is_windows']: - self._define_constants['_WIN32'] = 1 - if not pi['is_32bit']: - self._define_constants['_WIN64'] = 1 - self._define_constants['WIN64'] = 1 - self._define_constants['WIN32'] = 1 - if pi['is_linux']: - self._define_constants['__linux__'] = 1 - if pi['is_macos']: - self._define_constants['__APPLE__'] = 1 - self._define_constants['__MACH__'] = 1 - if pi['is_x86_64']: - self._define_constants['__x86_64__'] = 1 - self._define_constants['__x86_64'] = 1 - self._define_constants['_M_X64'] = 1 - elif pi['is_arm64']: - self._define_constants['__aarch64__'] = 1 - self._define_constants['_M_ARM64'] = 1 - if not pi['is_32bit'] and pi['is_linux']: - self._define_constants['__LP64__'] = 1 - elif pi['is_32bit']: - self._define_constants['_ILP32'] = 1 - self._define_constants['SIZEOF_VOID_P'] = pi['ptr_size'] - self._define_constants['__SIZEOF_POINTER__'] = pi['ptr_size'] - - def find_struct_by_pointee(self, pointee): - """根据 pointee 类型查找匹配的结构体,返回 (class_name, struct_type) 或 None""" - for class_name, struct_type in self.structs.items(): - if pointee == struct_type: - return (class_name, struct_type) - return None - - def _get_or_create_struct(self, name, source_sha1=None, packed=False): - clean_name = name.replace(' *', '').replace('*', '').replace(' ', '_').replace('const', 'const_').replace('volatile', 'volatile_') - if clean_name in self.structs: - existing = self.structs[clean_name] - if packed and isinstance(existing, ir.IdentifiedStructType) and not existing.packed: - existing.packed = True - return existing - if clean_name in {'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum', 'Void', 'void'}: - return ir.IntType(8) - if hasattr(self, 'SymbolTable') and self.SymbolTable and clean_name in self.SymbolTable: - Entry = self.SymbolTable[clean_name] - if hasattr(Entry, 'IsTypedef') and Entry.IsTypedef: - resolved_str = self._resolve_typedef(clean_name) - if resolved_str != clean_name: - return self._type_str_to_llvm(resolved_str) - if hasattr(Entry, 'BaseType') and Entry.BaseType: - from lib.includes import t as _t - if not isinstance(Entry.BaseType, (_t._CTypedef,)) or getattr(Entry, 'PtrCount', 0) > 0: - resolved = self._resolve_ctype_to_str(Entry) - if resolved: - return self._type_str_to_llvm(resolved) - if hasattr(Entry, 'IsRenum') and Entry.IsRenum: - if clean_name in self.structs: - return self.structs[clean_name] - if hasattr(Entry, 'IsEnum') and Entry.IsEnum: - return ir.IntType(32) - if hasattr(Entry, 'IsExceptionClass') and Entry.IsExceptionClass: - return ir.IntType(32) - if hasattr(Entry, 'BaseType'): - from lib.includes import t as _t - if isinstance(Entry.BaseType, type) and issubclass(Entry.BaseType, _t.CEnum): - return ir.IntType(32) - if Entry.BaseType is _t.CEnum: - return ir.IntType(32) - if source_sha1: - ns_name = f"{source_sha1}.{clean_name}" - elif hasattr(self, '_struct_sha1_map') and clean_name in self._struct_sha1_map: - ns_name = f"{self._struct_sha1_map[clean_name]}.{clean_name}" - else: - ns_name = self._mangle_name(clean_name) - st = ir.IdentifiedStructType(self.module, name=ns_name, packed=packed) - self.structs[clean_name] = st - return st - - def _set_node_info(self, node, extra_info=""): - if hasattr(node, 'lineno'): - self._current_lineno = node.lineno - else: - self._current_lineno = 0 - if hasattr(node, 'col_offset'): - self._current_node_info = f"line {self._current_lineno}, col {node.col_offset}" - else: - self._current_node_info = f"line {self._current_lineno}" - if extra_info: - self._current_node_info += f" ({extra_info})" - - def _set_source_info(self, filepath): - self._current_source_file = filepath - try: - with open(filepath, 'r', encoding='utf-8') as f: - self._current_source_lines = f.readlines() - except Exception: # 文件读取失败时回退为空行列表 - self._current_source_lines = [] - - def _ns_hash(self): - if 'workspace' in self._ns_cache: - return self._ns_cache['workspace'] - cwd = os.getcwd().replace('\\', '/').lower() - digest = hashlib.sha1(cwd.encode('utf-8')).hexdigest()[:12] - self._ns_cache['workspace'] = digest - return digest - - def _skip_mangle(self, name): - skip_prefixes = ('llvm.', 'str_const_', 'printf', 'memset_pattern') - if any(name.startswith(p) for p in skip_prefixes): - return True - if '.' in name: - parts = name.split('.', 1) - if len(parts[0]) >= 8 and all(c in '0123456789abcdef' for c in parts[0]): - return True - return False - - def _mangle_name(self, name): - if self._skip_mangle(name): - return name - if name in self._export_funcs: - return name - if self.module_sha1: - return f"{self.module_sha1}.{name}" - return name - - def _find_function(self, name): - if name in self.functions: - return self.functions[name] - g = self.module.globals.get(name) - if g and isinstance(g, ir.Function): - self.functions[name] = g - return g - mangled = self._mangle_func_name(name) - if mangled != name: - if mangled in self.functions: - self.functions[name] = self.functions[mangled] - return self.functions[mangled] - g = self.module.globals.get(mangled) - if g and isinstance(g, ir.Function): - self.functions[mangled] = g - self.functions[name] = g - return g - for sha1 in self.module_sha1_map.values(): - prefixed = f"{sha1}.{name}" - if prefixed in self.functions: - self.functions[name] = self.functions[prefixed] - return self.functions[prefixed] - g = self.module.globals.get(prefixed) - if g and isinstance(g, ir.Function): - self.functions[prefixed] = g - self.functions[name] = g - return g - return None - - def _has_function(self, name): - return self._find_function(name) is not None - - def _get_or_declare_function(self, mangled_name, func_type): - for g in self.module.globals: - if isinstance(g, ir.Function) and g.name == mangled_name: - return g - return ir.Function(self.module, func_type, name=mangled_name) - - def _get_function(self, name): - func = self._find_function(name) - return func - - def _mangle_func_name(self, name, module_name=None): - if name in self._export_funcs: - return name - if name in self._export_extern_funcs and name not in self._current_module_func_names: - return name - # main 函数作为程序入口点,永远不混淆 - if name == 'main': - return name - # Try class_sha1_map first for class methods (e.g., 'md5.__init__' -> class 'md5') - class_sha1_map = getattr(self, 'class_sha1_map', {}) - if class_sha1_map: - if '.' in name: - base_class = name.split('.')[0] - if base_class in class_sha1_map: - sha1 = class_sha1_map[base_class] - return f"{sha1}.{name}" - elif name in class_sha1_map: - sha1 = class_sha1_map[name] - return f"{sha1}.{name}" - # If module_name is already a SHA1 hash (16 hex chars), use it directly - if module_name and len(module_name) == 16 and all(c in '0123456789abcdef' for c in module_name): - return f"{module_name}.{name}" - if module_name and module_name in self.module_sha1_map: - sha1 = self.module_sha1_map[module_name] - return f"{sha1}.{name}" - # Try parent package name (e.g., 'hashlib' -> 'hashlib.__init__') - if module_name: - init_name = f"{module_name}.__init__" - if init_name in self.module_sha1_map: - sha1 = self.module_sha1_map[init_name] - return f"{sha1}.{name}" - if self._skip_mangle(name): - return name - if self.module_sha1: - return f"{self.module_sha1}.{name}" - return name - - def _get_source_line(self, lineno): - if 0 < lineno <= len(self._current_source_lines): - return self._current_source_lines[lineno - 1].rstrip('\r\n') - return None - - def _get_node_info(self): - info = "" - if self._current_node_info: - info = f" [{self._current_node_info}]" - if self._current_source_file: - info += f" in {self._current_source_file}" - lineno = self._current_lineno - if lineno > 0: - info += f", line {lineno}:" - source_line = self._get_source_line(lineno) - if source_line: - info += f"\n → {source_line}" - return info - - def _register_local_heap_ptr(self, val, ClassName=None, VarName=None): - if isinstance(val.type, ir.PointerType): - pointee = val.type.pointee - if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): - self._local_heap_ptrs.append((val, 'struct', ClassName)) - elif isinstance(pointee, ir.IntType) and pointee.width == 8: - self._local_heap_ptrs.append((val, 'i8', ClassName)) - if VarName: - self._var_to_heap_ptr[VarName] = val - - def _unregister_local_heap_ptr(self, val): - self._local_heap_ptrs = [(v, t, cn) for v, t, cn in self._local_heap_ptrs if v is not val] - - def _emit_local_heap_frees(self): - if not self._local_heap_ptrs or not self.builder: - return - # 创建一个集合来跟踪已经删除的对象 - deleted_objects = set() - for ptr, ptr_type, ClassName in self._local_heap_ptrs: - # 先检查指针是否为 null - if ptr_type == 'i8': - # 对于 i8* 类型的指针,加载其值并检查是否为 null - loaded_ptr = self.builder.load(ptr, name="load_ptr") - null_ptr = ir.Constant(ir.PointerType(ir.IntType(8)), None) - is_null = self.builder.icmp_unsigned('==', loaded_ptr, null_ptr, name="is_null") - # 创建一个基本块来处理非 null 的情况 - not_null_block = self.builder.append_basic_block(name="not_null") - # 创建一个基本块来处理下一个对象 - next_block = self.builder.append_basic_block(name="next") - # 如果指针为 null,跳转到下一个对象 - self.builder.cbranch(is_null, next_block, not_null_block) - # 切换到非 null 的基本块 - self.builder.position_at_end(not_null_block) - # 然后调用 __del__ 方法 - if ClassName and self._has_function(f'{ClassName}.__del__'): - if isinstance(ptr.type, ir.PointerType) and isinstance(ptr.type.pointee, ir.IntType) and ptr.type.pointee.width == 8: - cast_ptr = self.builder.bitcast(ptr, ir.PointerType(self.structs[ClassName]), name=f"cast_{ClassName}") - else: - cast_ptr = ptr - if cast_ptr not in deleted_objects: - self.builder.call(self._get_function(f'{ClassName}.__del__'), [cast_ptr], name=f"call_{ClassName}.__del__") - deleted_objects.add(cast_ptr) - # 最后释放内存 - if ptr_type == 'struct': - raw = self.builder.bitcast(ptr, ir.PointerType(ir.IntType(8)), name="local_free_cast") - elif ptr_type == 'i8': - raw = ptr - else: - continue - free_type = ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))]) - free_func = self._get_or_declare_func('free', free_type) - self.builder.call(free_func, [raw]) - # 如果是 i8* 类型的指针,跳转到下一个对象 - if ptr_type == 'i8': - self.builder.branch(next_block) - # 切换到下一个对象的基本块 - self.builder.position_at_end(next_block) - self._local_heap_ptrs = [] - - def _register_temp_ptr(self, val): - if isinstance(val.type, ir.PointerType): - pointee = val.type.pointee - if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): - for CN, ST in self.structs.items(): - if pointee == ST: - self._temp_struct_ptrs.append(val) - return - elif isinstance(pointee, ir.IntType) and pointee.width == 8: - self._temp_struct_ptrs.append(val) - - def _unregister_temp_ptr(self, val): - self._temp_struct_ptrs = [t for t in self._temp_struct_ptrs if t is not val] - - def _emit_temp_frees(self): - if not self._temp_struct_ptrs or not self.builder: - return - for ptr in self._temp_struct_ptrs: - if isinstance(ptr.type, ir.PointerType) and isinstance(ptr.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): - raw = self.builder.bitcast(ptr, ir.PointerType(ir.IntType(8)), name="free_cast") - elif isinstance(ptr.type, ir.PointerType) and isinstance(ptr.type.pointee, ir.IntType) and ptr.type.pointee.width == 8: - raw = ptr - else: - continue - free_type = ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))]) - free_func = self._get_or_declare_func('free', free_type) - self.builder.call(free_func, [raw]) - self._temp_struct_ptrs = [] - - def setup_from_symbol_table(self, SymbolTable): - self.SymbolTable = SymbolTable - for name, info in SymbolTable.items(): - if not isinstance(info, dict): - if hasattr(info, 'get'): - info = dict(info) if hasattr(info, '__iter__') else {} - else: - continue - TypeKind = info.get('type', '') - if TypeKind == 'struct': - ClassName = name - self.class_methods[ClassName] = [] - self.class_members[ClassName] = [] - members = info.get('members', {}) - if members: - for MemberName, MemberInfo in members.items(): - if isinstance(MemberInfo, dict): - MemberType = self._type_str_to_llvm(MemberInfo.get('type', 'int'), MemberInfo.get('IsPtr', False)) - self.class_members[ClassName].append((MemberName, MemberType)) - elif isinstance(MemberInfo, _CTypeInfo): - MemberType = self._ctype_to_llvm(MemberInfo) - if MemberType is None: - MemberType = self._type_str_to_llvm(MemberInfo.ToString(), MemberInfo.IsPtr) - self.class_members[ClassName].append((MemberName, MemberType)) - self._generate_structs() - self._create_Vtable_globals() - - def register_method(self, ClassName, MethodName): - if ClassName not in self.class_methods: - self.class_methods[ClassName] = [] - if ClassName not in self.class_members: - self.class_members[ClassName] = [] - self._generate_structs() - self._create_Vtable_globals() - if MethodName not in self.class_methods[ClassName]: - self.class_methods[ClassName].append(MethodName) - - def _ctype_to_llvm(self, type_info): - from lib.includes import t as _t - from lib.includes.t import CTypeRegistry - from lib.core.Handles.HandlesBase import CTypeInfo as _CTypeInfo - - if type_info is None: - return ir.IntType(32) - - if isinstance(type_info, str): - return self._type_str_to_llvm(type_info) - - if not isinstance(type_info, _CTypeInfo): - return ir.IntType(32) - - if type_info.IsFuncPtr: - return ir.IntType(8).as_pointer() - - if type_info.IsState and type_info.PtrCount == 0 and not type_info.IsTypedef: - if type_info.BaseType is None or (isinstance(type_info.BaseType, type) and issubclass(type_info.BaseType, _t.CVoid)) or isinstance(type_info.BaseType, _t.CVoid): - return ir.VoidType() - - if type_info.IsTypedef and type_info.Name: - resolved = self._resolve_typedef_ctype(type_info) - if resolved is not None: - return resolved - - base_type = self._base_ctype_to_llvm(type_info.BaseType, type_info) - - result = base_type - for _ in range(type_info.PtrCount): - if isinstance(result, ir.VoidType): - result = ir.IntType(8).as_pointer() - else: - result = ir.PointerType(result) - - for dim in reversed(type_info.ArrayDims): - try: - dim_val = int(dim) - if dim_val > 0: - result = ir.ArrayType(result, dim_val) - except (ValueError, TypeError): - pass - - return result - - def _resolve_typedef_ctype(self, type_info): - from lib.includes import t as _t - from lib.core.Handles.HandlesBase import CTypeInfo as _CTypeInfo - - name = type_info.Name - if not name or not hasattr(self, 'SymbolTable') or not self.SymbolTable: - return None - - entry = self.SymbolTable.get(name) - if not entry or not isinstance(entry, _CTypeInfo): - return None - - if entry.BaseType and (not isinstance(entry.BaseType, _t._CTypedef) or entry.PtrCount > 0): - resolved = entry.Copy() - resolved.IsTypedef = False - if type_info.PtrCount > resolved.PtrCount: - resolved.PtrCount = type_info.PtrCount - return self._ctype_to_llvm(resolved) - - if entry.OriginalType: - if isinstance(entry.OriginalType, _CTypeInfo): - resolved = entry.OriginalType.Copy() - resolved.IsTypedef = False - if type_info.PtrCount > resolved.PtrCount: - resolved.PtrCount = type_info.PtrCount - return self._ctype_to_llvm(resolved) - elif isinstance(entry.OriginalType, str): - resolved = _CTypeInfo.FromTypeName(entry.OriginalType) - if resolved and resolved.BaseType: - resolved.IsTypedef = False - if type_info.PtrCount > resolved.PtrCount: - resolved.PtrCount = type_info.PtrCount - return self._ctype_to_llvm(resolved) - - return None - - def _base_ctype_to_llvm(self, base_type, type_info=None): - from lib.includes import t as _t - from lib.includes.t import CTypeRegistry - - if base_type is None: - return ir.VoidType() - - if isinstance(base_type, (tuple, list)): - elem_types = [self._base_ctype_to_llvm(bt, type_info) for bt in base_type] - return ir.LiteralStructType(elem_types) if elem_types else ir.IntType(32) - - if isinstance(base_type, type) and issubclass(base_type, _t.CType): - base_type = base_type() - - if isinstance(base_type, _t.CVoid): - return ir.VoidType() - - if isinstance(base_type, _t.CStruct): - struct_name = getattr(base_type, 'name', '') or (type_info.Name if type_info else '') - if struct_name and struct_name in self.structs: - return self.structs[struct_name] - if struct_name: - return self._get_or_create_struct(struct_name) - return ir.LiteralStructType([]) - - if isinstance(base_type, (_t.CEnum, _t.REnum)): - enum_name = type_info.Name if type_info else '' - if enum_name and enum_name in self.structs: - return self.structs[enum_name] - return ir.IntType(32) - - if isinstance(base_type, _t.CUnion): - union_name = type_info.Name if type_info else '' - if union_name and union_name in self.structs: - return self.structs[union_name] - if union_name: - return self._get_or_create_struct(union_name) - return ir.IntType(32) - - if isinstance(base_type, _t._CTypedef): - typedef_name = getattr(base_type, 'value', '') or (type_info.Name if type_info else '') - if typedef_name and hasattr(self, 'SymbolTable') and self.SymbolTable: - from lib.core.Handles.HandlesBase import CTypeInfo as _CTypeInfo - entry = self.SymbolTable.get(typedef_name) - if entry and isinstance(entry, _CTypeInfo) and entry.BaseType: - if not isinstance(entry.BaseType, _t._CTypedef) or entry.PtrCount > 0: - return self._base_ctype_to_llvm(entry.BaseType, entry) - return ir.IntType(32) - - if isinstance(base_type, _t.CDefine): - # Use 64-bit type if the define value exceeds 32-bit range - if type_info and hasattr(type_info, 'DefineValue') and isinstance(type_info.DefineValue, int): - if type_info.DefineValue < 0 or type_info.DefineValue > 0xFFFFFFFF: - return ir.IntType(64) - return ir.IntType(32) - - if isinstance(base_type, _t.CPass): - return ir.VoidType() - - llvm_str = CTypeRegistry.CTypeToLLVM(type(base_type)) - return self._llvm_str_to_ir(llvm_str) - - def _llvm_str_to_ir(self, llvm_str): - _map = { - 'void': ir.VoidType, 'i1': lambda: ir.IntType(1), - 'i8': lambda: ir.IntType(8), 'i16': lambda: ir.IntType(16), - 'i32': lambda: ir.IntType(32), 'i64': lambda: ir.IntType(64), - 'i128': lambda: ir.IntType(128), 'half': lambda: ir.IntType(16), - 'float': ir.FloatType, 'double': ir.DoubleType, - 'fp128': lambda: ir.IntType(128), 'i8*': lambda: ir.IntType(8).as_pointer(), - 'f8': lambda: ir.IntType(8), 'f16': lambda: ir.IntType(16), - 'f32': ir.FloatType, 'f64': ir.DoubleType, 'f128': lambda: ir.IntType(128), - } - factory = _map.get(llvm_str) - if factory: - return factory() if callable(factory) else factory - return ir.IntType(32) - - def _resolve_typedef(self, type_name: str) -> str: - if type_name in {'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum'}: - return type_name - if type_name == 'Callable': - return 'Callable' - visited = set() - current = type_name - while current not in visited: - visited.add(current) - if hasattr(self, 'SymbolTable') and self.SymbolTable and current in self.SymbolTable: - Entry = self.SymbolTable[current] - if isinstance(Entry, dict) and Entry.get('type') == 'typedef': - OriginalType = Entry.get('OriginalType', '') - if OriginalType: - current = OriginalType - continue - elif hasattr(Entry, 'IsTypedef') and Entry.IsTypedef: - if hasattr(Entry, 'OriginalType') and Entry.OriginalType: - if isinstance(Entry.OriginalType, _CTypeInfo): - if Entry.OriginalType.IsFuncPtr: - return 'Callable' - return Entry.OriginalType.ToString() if Entry.OriginalType.BaseType else current - elif isinstance(Entry.OriginalType, str): - current = Entry.OriginalType - continue - if hasattr(Entry, 'BaseType') and Entry.BaseType: - from lib.includes import t as _t - if not isinstance(Entry.BaseType, (_t._CTypedef,)) or getattr(Entry, 'PtrCount', 0) > 0: - resolved = self._resolve_ctype_to_str(Entry) - if resolved and resolved != current: - current = resolved - continue - from lib.core.Handles.HandlesBase import BuiltinTypeMap - bm = BuiltinTypeMap.Get(current) - if bm: - base_cls = bm[0] - try: - instance = base_cls() - cname = getattr(instance, 'CName', '') - if cname: - current = cname + ' *' * bm[1] - continue - except Exception as _e: - if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": - import logging; logging.warning(f"异常被忽略: {_e}") - pass - from lib.core.Handles.HandlesBase import BuiltinTypeMap - bm = BuiltinTypeMap.Get(current) - if bm and bm[1] > 0: - base_cls = bm[0] - try: - instance = base_cls() - cname = getattr(instance, 'CName', '') - if cname: - current = cname + ' *' * bm[1] - continue - except Exception as _e: - if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": - import logging; logging.warning(f"异常被忽略: {_e}") - pass - break - return current - - def _resolve_ctype_to_str(self, type_info) -> str: - from lib.includes import t as _t - parts = [] - base = type_info.BaseType - if base is None or base is _t.CVoid or isinstance(base, _t.CVoid): - parts.append('void') - elif isinstance(base, _t._CTypedef) or base is _t._CTypedef: - return '' - elif isinstance(base, _t.CStruct) or base is _t.CStruct: - parts.append(f'struct {getattr(base, "name", "")}') - elif isinstance(base, _t.CEnum) or base is _t.CEnum: - parts.append(f'enum {getattr(base, "name", "")}') - else: - cname = getattr(base, 'CName', '') - if not cname and isinstance(base, type) and issubclass(base, _t.CType): - try: - inst = base() - cname = getattr(inst, 'CName', '') - except Exception as _e: - if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": - import logging; logging.warning(f"异常被忽略: {_e}") - pass - if cname: - parts.append(cname) - else: - return '' - if type_info.PtrCount > 0: - parts.append('*' * type_info.PtrCount) - return ' '.join(parts) - - def _type_str_to_llvm(self, type_str, IsPtr=False): - type_str = type_str.strip() - cache_key = (type_str, IsPtr) - cached = self._type_cache.get(cache_key) - if cached is not None: - return cached - result = self._type_str_to_llvm_impl(type_str, IsPtr) - if result is not None: - if isinstance(result, (ir.IntType, ir.FloatType, ir.DoubleType, ir.VoidType)): - self._type_cache[cache_key] = result - elif isinstance(result, ir.PointerType) and isinstance(result.pointee, (ir.IntType, ir.FloatType, ir.DoubleType, ir.VoidType)): - self._type_cache[cache_key] = result - elif isinstance(result, ir.ArrayType) and not isinstance(result.element, (ir.IdentifiedStructType, ir.LiteralStructType)): - self._type_cache[cache_key] = result - return result - - _CType2LLVM = _type_str_to_llvm - - def _type_str_to_llvm_impl(self, type_str, IsPtr=False): - array_dims = [] - dim_match = __import__('re').findall(r'\[(\d+)\]', type_str) - if dim_match: - array_dims = [int(d) for d in dim_match] - type_str = __import__('re').sub(r'\s*\[\d+\]', '', type_str).strip() - result = self._type_str_to_llvm_base(type_str, IsPtr) - for dim in reversed(array_dims): - result = ir.ArrayType(result, dim) - return result - - def _type_str_to_llvm_base(self, type_str, IsPtr=False): - ptr_depth = 0 - while type_str.endswith('*'): - ptr_depth += 1 - type_str = type_str[:-1].strip() - if ptr_depth > 0: - IsPtr = True - if type_str in {'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum'}: - if IsPtr: - result = ir.IntType(8).as_pointer() - for _ in range(ptr_depth - 1): - result = ir.PointerType(result) - return result - return ir.IntType(32) - if type_str in {'const', 'volatile'}: - return ir.IntType(8) - if type_str == 'Callable': - return ir.IntType(8).as_pointer() - if type_str.startswith('const '): - inner_type = self._type_str_to_llvm(type_str[6:].strip(), IsPtr) - return inner_type - if type_str.startswith('volatile '): - inner_type = self._type_str_to_llvm(type_str[9:].strip(), IsPtr) - return inner_type - if type_str.startswith('const_'): - inner_type = self._type_str_to_llvm(type_str[6:], IsPtr) - return inner_type - if type_str.startswith('volatile_'): - inner_type = self._type_str_to_llvm(type_str[9:], IsPtr) - return inner_type - if type_str.startswith('static '): - return self._type_str_to_llvm(type_str[7:].strip(), IsPtr) - if type_str.startswith('extern '): - return self._type_str_to_llvm(type_str[7:].strip(), IsPtr) - if type_str.startswith('register '): - return self._type_str_to_llvm(type_str[9:].strip(), IsPtr) - if type_str.startswith('inline '): - return self._type_str_to_llvm(type_str[7:].strip(), IsPtr) - if type_str.startswith('export '): - return self._type_str_to_llvm(type_str[7:].strip(), IsPtr) - resolved = self._resolve_typedef(type_str) - if resolved != type_str: - if '*' in resolved: - IsPtr = False - return self._type_str_to_llvm(resolved, IsPtr) - if type_str.endswith('*'): - base_type = type_str[:-1].strip() - base_llvm = self._basic_type_to_llvm(base_type) - if base_llvm is not None and isinstance(base_llvm, ir.VoidType): - result = ir.IntType(8).as_pointer() - for _ in range(ptr_depth): - result = ir.PointerType(result) - return result - if base_llvm is not None and not isinstance(base_llvm, ir.VoidType): - if isinstance(base_llvm, ir.PointerType): - return base_llvm - return ir.PointerType(base_llvm) - if base_type in self.structs: - return ir.PointerType(self.structs[base_type]) - if base_type.startswith('struct '): - stripped = base_type[7:].strip() - if stripped in self.structs: - return ir.PointerType(self.structs[stripped]) - if '.' in base_type: - last_part = base_type.split('.')[-1] - if last_part in self.structs: - return ir.PointerType(self.structs[last_part]) - placeholder = self._get_or_create_struct(last_part) - return ir.PointerType(placeholder) - if base_llvm is not None and isinstance(base_llvm, ir.VoidType): - return ir.PointerType(ir.IntType(8)) - if type_str.startswith('{') and type_str.endswith('}'): - inner = type_str[1:-1].strip() - elem_strs = [] - depth = 0 - current = '' - for ch in inner: - if ch == ',' and depth == 0: - elem_strs.append(current.strip()) - current = '' - else: - if ch == '{': - depth += 1 - elif ch == '}': - depth -= 1 - current += ch - if current.strip(): - elem_strs.append(current.strip()) - elem_types = [] - for es in elem_strs: - et = self._type_str_to_llvm(es, '*' in es) - if isinstance(et, ir.VoidType): - et = ir.IntType(8).as_pointer() - elem_types.append(et) - if elem_types: - return ir.LiteralStructType(elem_types) - return ir.IntType(32) - if type_str in {'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum'}: - return ir.IntType(32) - if type_str.startswith('%'): - stripped = type_str[1:] - if stripped in {'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum'}: - return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32)) - basic_stripped = self._basic_type_to_llvm(stripped) - if basic_stripped is not None: - if IsPtr and not isinstance(basic_stripped, ir.VoidType): - return ir.PointerType(basic_stripped) - return basic_stripped - if hasattr(self, 'SymbolTable') and self.SymbolTable and type_str in self.SymbolTable: - _Entry = self.SymbolTable[type_str] - if hasattr(_Entry, 'IsTypedef') and _Entry.IsTypedef: - resolved_str = self._resolve_typedef(type_str) - if resolved_str != type_str: - return self._type_str_to_llvm(resolved_str, IsPtr) - if hasattr(_Entry, 'BaseType') and _Entry.BaseType: - from lib.includes import t as _t - if not isinstance(_Entry.BaseType, (_t._CTypedef,)) or getattr(_Entry, 'PtrCount', 0) > 0: - resolved = self._resolve_ctype_to_str(_Entry) - if resolved: - return self._type_str_to_llvm(resolved, IsPtr) - if hasattr(_Entry, 'IsRenum') and _Entry.IsRenum: - if type_str in self.structs: - return self.structs[type_str] - if hasattr(_Entry, 'IsEnum') and _Entry.IsEnum: - return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32)) - if hasattr(_Entry, 'IsExceptionClass') and _Entry.IsExceptionClass: - return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32)) - if hasattr(_Entry, 'BaseType'): - from lib.includes import t as _t - if (isinstance(_Entry.BaseType, type) and issubclass(_Entry.BaseType, _t.CEnum)) or _Entry.BaseType is _t.CEnum: - return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32)) - for ClassName in self.structs: - if type_str == ClassName: - if IsPtr: - return ir.PointerType(self.structs[ClassName]) - return self.structs[ClassName] - if '.' in type_str and not type_str.startswith('%'): - last_part = type_str.split('.')[-1] - basic_last = self._basic_type_to_llvm(last_part) - if basic_last is not None: - if IsPtr and not isinstance(basic_last, ir.VoidType): - return ir.PointerType(basic_last) - return basic_last - if hasattr(self, 'SymbolTable') and self.SymbolTable and last_part in self.SymbolTable: - _Entry = self.SymbolTable[last_part] - if hasattr(_Entry, 'IsTypedef') and _Entry.IsTypedef: - resolved_str = self._resolve_typedef(last_part) - if resolved_str != last_part: - return self._type_str_to_llvm(resolved_str, IsPtr) - if hasattr(_Entry, 'BaseType') and _Entry.BaseType: - from lib.includes import t as _t - if not isinstance(_Entry.BaseType, (_t._CTypedef,)) or getattr(_Entry, 'PtrCount', 0) > 0: - resolved = self._resolve_ctype_to_str(_Entry) - if resolved: - return self._type_str_to_llvm(resolved, IsPtr) - if hasattr(_Entry, 'IsRenum') and _Entry.IsRenum: - if last_part in self.structs: - return self.structs[last_part] - if hasattr(_Entry, 'IsEnum') and _Entry.IsEnum: - return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32)) - if hasattr(_Entry, 'IsExceptionClass') and _Entry.IsExceptionClass: - return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32)) - if hasattr(_Entry, 'BaseType'): - from lib.includes import t as _t - if (isinstance(_Entry.BaseType, type) and issubclass(_Entry.BaseType, _t.CEnum)) or _Entry.BaseType is _t.CEnum: - return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32)) - if last_part in self.structs: - if IsPtr: - return ir.PointerType(self.structs[last_part]) - return self.structs[last_part] - placeholder = self._get_or_create_struct(last_part) - if IsPtr: - return ir.PointerType(placeholder) - return placeholder - if type_str.startswith('struct '): - stripped = type_str[7:].strip().replace(' *', '').replace('*', '') - if stripped in self.structs: - if IsPtr: - return ir.PointerType(self.structs[stripped]) - return self.structs[stripped] - basic_match = self._basic_type_to_llvm(stripped) - if basic_match is not None: - if IsPtr and not isinstance(basic_match, ir.VoidType): - return ir.PointerType(basic_match) - return basic_match - placeholder = self._get_or_create_struct(stripped) - if IsPtr: - return ir.PointerType(placeholder) - return placeholder - if type_str.startswith('%struct.'): - stripped = type_str[8:].strip().replace(' *', '').replace('*', '') - if stripped in self.structs: - if IsPtr: - return ir.PointerType(self.structs[stripped]) - return self.structs[stripped] - basic_match = self._basic_type_to_llvm(stripped) - if basic_match is not None: - if IsPtr and not isinstance(basic_match, ir.VoidType): - return ir.PointerType(basic_match) - return basic_match - placeholder = self._get_or_create_struct(stripped) - if IsPtr: - return ir.PointerType(placeholder) - return placeholder - if type_str.startswith('union '): - stripped = type_str[6:].strip() - basic_match = self._basic_type_to_llvm(stripped) - if basic_match is not None: - if IsPtr and not isinstance(basic_match, ir.VoidType): - return ir.PointerType(basic_match) - return basic_match - if type_str.endswith('*'): - pointee = self._type_str_to_llvm(type_str[:-1].strip()) - if isinstance(pointee, ir.VoidType): - return ir.PointerType(ir.IntType(8)) - return ir.PointerType(pointee) - result = self._basic_type_to_llvm(type_str) - if result is None: - result = ir.IntType(32) - if IsPtr: - if isinstance(result, ir.VoidType): - result = ir.PointerType(ir.IntType(8)) - elif isinstance(result, ir.PointerType): - pass - else: - result = ir.PointerType(result) - for _ in range(ptr_depth - 1): - result = ir.PointerType(result) - return result - - def _llvm_str_to_ir(self, llvm_str): - _LLVM_IR_TYPES = { - 'void': ir.VoidType(), 'i1': ir.IntType(1), 'i8': ir.IntType(8), - 'i16': ir.IntType(16), 'i32': ir.IntType(32), 'i64': ir.IntType(64), - 'i128': ir.IntType(128), 'float': ir.FloatType(), 'double': ir.DoubleType(), - 'half': ir.IntType(16), 'fp128': ir.IntType(128), - } - return _LLVM_IR_TYPES.get(llvm_str) - - def _basic_type_to_llvm(self, type_str): - _LLVM_IR_TYPES = { - 'void': ir.VoidType(), 'i1': ir.IntType(1), 'i8': ir.IntType(8), - 'i16': ir.IntType(16), 'i32': ir.IntType(32), 'i64': ir.IntType(64), - 'i128': ir.IntType(128), 'f32': ir.FloatType(), 'f64': ir.DoubleType(), - 'half': ir.IntType(16), 'fp128': ir.IntType(128), - } - if type_str in _LLVM_IR_TYPES: - return _LLVM_IR_TYPES[type_str] - from lib.includes.t import CTypeRegistry - resolved = CTypeRegistry.ResolveName(type_str) - if resolved is not None: - ctype_cls, ptr_level = resolved - llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls) - if llvm_str: - base = self._llvm_str_to_ir(llvm_str) - if base is not None: - for _ in range(ptr_level): - if isinstance(base, ir.VoidType): - base = ir.IntType(8).as_pointer() - else: - base = ir.PointerType(base) - return base - cnameres = CTypeRegistry.CNameToClass(type_str) - if cnameres is not None: - llvm_str = CTypeRegistry.CTypeToLLVM(cnameres) - if llvm_str: - return self._llvm_str_to_ir(llvm_str) - if type_str == '*': - return ir.IntType(8) - if type_str in ('const_', 'const'): - return ir.IntType(8) - return None - - def _is_type_unsigned(self, type_str): - s = type_str.strip() - if s.endswith('*'): - return True - if s.startswith('unsigned'): - return True - from lib.includes.t import CTypeRegistry - resolved = CTypeRegistry.ResolveName(s) - if resolved is not None: - ctype_cls, _ = resolved - try: - inst = ctype_cls() - if getattr(inst, 'IsSigned', None) is False: - return True - except Exception: - pass - cnameres = CTypeRegistry.CNameToClass(s) - if cnameres is not None: - try: - inst = cnameres() - if getattr(inst, 'IsSigned', None) is False: - return True - except Exception: - pass - return False - - def _record_var_signedness(self, name, type_str_or_bool): - if isinstance(type_str_or_bool, bool): - self.var_signedness[name] = type_str_or_bool - else: - self.var_signedness[name] = self._is_type_unsigned(type_str_or_bool) - - def _is_var_unsigned(self, name): - return self.var_signedness.get(name, False) - - def _check_node_unsigned(self, node): - if isinstance(node, ast.Name): - return self._is_var_unsigned(node.id) - if isinstance(node, ast.BinOp): - return self._check_node_unsigned(node.left) or self._check_node_unsigned(node.right) - if isinstance(node, ast.UnaryOp): - return self._check_node_unsigned(node.operand) - if isinstance(node, ast.Call): - return False - if isinstance(node, ast.Subscript): - return self._check_node_unsigned(node.value) - if isinstance(node, ast.Attribute): - return self._check_node_unsigned(node.value) - return False - - def _get_align(self, llvm_type): - if isinstance(llvm_type, ir.IntType): - return max(1, llvm_type.width // 8) - if isinstance(llvm_type, ir.FloatType): - return 4 - if isinstance(llvm_type, ir.DoubleType): - return 8 - if isinstance(llvm_type, ir.PointerType): - return self.ptr_size - if isinstance(llvm_type, ir.ArrayType): - return self._get_align(llvm_type.element) - if isinstance(llvm_type, ir.LiteralStructType): - return max((self._get_align(f) for f in llvm_type.elements), default=1) - if isinstance(llvm_type, ir.IdentifiedStructType): - if llvm_type.elements is None or len(llvm_type.elements) == 0: - return self.ptr_size # opaque struct, assume pointer alignment - return max((self._get_align(f) for f in llvm_type.elements), default=1) - if isinstance(llvm_type, ir.VoidType): - return 0 - return 4 - - def _get_struct_size(self, llvm_type): - if isinstance(llvm_type, ir.IntType): - return max(1, llvm_type.width // 8) - if isinstance(llvm_type, ir.FloatType): - return 4 - if isinstance(llvm_type, ir.DoubleType): - return 8 - if isinstance(llvm_type, ir.PointerType): - return self.ptr_size - if isinstance(llvm_type, ir.ArrayType): - return self._get_struct_size(llvm_type.element) * llvm_type.count - if isinstance(llvm_type, ir.LiteralStructType): - total = 0 - max_align = 1 - for f in llvm_type.fields: - fa = self._get_align(f) - fs = self._get_struct_size(f) - max_align = max(max_align, fa) - if fa > 1: - total = (total + fa - 1) // fa * fa - total += fs - if max_align > 1: - total = (total + max_align - 1) // max_align * max_align - return total - if isinstance(llvm_type, ir.IdentifiedStructType): - if llvm_type.elements is None or len(llvm_type.elements) == 0: - return self.ptr_size # opaque struct, assume pointer size - total = 0 - max_align = 1 - for f in llvm_type.elements: - fa = self._get_align(f) - fs = self._get_struct_size(f) - max_align = max(max_align, fa) - if fa > 1: - total = (total + fa - 1) // fa * fa - total += fs - if max_align > 1: - total = (total + max_align - 1) // max_align * max_align - return total - return 4 - - @staticmethod - def _strip_unnecessary_quotes(ir_str): - def _unquote(m): - prefix = m.group(1) - name = m.group(2) - if '.' in name: - return m.group(0) - if re.match(r'^[a-zA-Z_$][a-zA-Z0-9_$]*$', name): - return prefix + name - return m.group(0) - return re.sub(r'([@%])"([^"]+)"', _unquote, ir_str) - - def finalize(self): - self._set_Vtable_initializers() - self._fix_global_var_init() - try: - ir_text = str(self.module) - except TypeError as e: - for func in self.module.functions: - for block in func.blocks: - for instr in block.instructions: - try: - str(instr) - except TypeError as te: - pass - raise - ir_text = self._strip_unnecessary_quotes(ir_text) - struct_defs = [] - struct_names = set() - typedef_names = TYPEDEF_NAMES - for ClassName, struct_type in self.structs.items(): - if isinstance(struct_type, ir.IdentifiedStructType): - sname = struct_type.name - if sname[0].isdigit() or '.' in sname or not sname.replace('_', '').replace('.', '').isalnum(): - sname_ir = f'%"{sname}"' - else: - sname_ir = f'%{sname}' - if struct_type.elements is None or len(struct_type.elements) == 0: - if ClassName not in typedef_names: - struct_names.add(sname) - struct_defs.append(f'{sname_ir} = type opaque') - continue - elems = ', '.join(str(e) for e in struct_type.elements) - if struct_type.packed: - struct_defs.append(f'{sname_ir} = type <{{ {elems} }}>') - else: - struct_defs.append(f'{sname_ir} = type {{ {elems} }}') - struct_names.add(sname) - if struct_defs: - lines = ir_text.split('\n') - filtered = [] - for line in lines: - stripped = line.strip() - skip = False - for name in struct_names: - if name[0].isdigit() or '.' in name or not name.replace('_', '').replace('.', '').isalnum(): - patterns = [f'%"{name}" = type', f'%"{name}"=type', f'%{name} = type', f'%{name}=type'] - else: - patterns = [f'%{name} = type', f'%{name}= type', f'%{name}=type'] - for p in patterns: - if stripped.startswith(p): - skip = True - break - if skip: - break - if not skip: - filtered.append(line) - ir_text = '\n'.join(filtered) - header_end = ir_text.find('\ndefine') - if header_end == -1: - header_end = ir_text.find('\ndeclare') - if header_end == -1: - header_end = ir_text.find('\n@') - if header_end == -1: - header_end = len(ir_text) - insert_pos = ir_text.rfind('\n', 0, header_end) - if insert_pos == -1: - insert_pos = header_end - struct_block = '\n'.join(struct_defs) + '\n' - ir_text = ir_text[:insert_pos + 1] + struct_block + ir_text[insert_pos + 1:] - for name in struct_names: - if name[0].isdigit() or '.' in name: - ir_text = re.sub( - r'%' + re.escape(name) + r'(?=[^a-zA-Z0-9_$\.]|$)', - r'%"' + name + r'"', - ir_text - ) - - return ir_text - - def _collect_classes_and_methods(self, ast_nodes, parent=None): - current_class = None - for node in ast_nodes: - if isinstance(node, str): - continue - node.parent = parent - node_type = type(node).__name__ - if node_type == 'Struct': - if hasattr(node, 'name'): - current_class = node.name - self.class_methods[current_class] = [] - self.class_members[current_class] = [] - if hasattr(node, 'decls') and node.decls: - for decl in node.decls: - if type(decl).__name__ == 'Decl' and hasattr(decl, 'name'): - member_type = self._get_type(decl.type) if hasattr(decl, 'type') else ir.IntType(32) - self.class_members[current_class].append((decl.name, member_type)) - elif node_type == 'FuncDef': - if current_class and current_class in self.class_methods: - MethodName = node.decl.name if hasattr(node.decl, 'name') else 'unknown_method' - if not MethodName.startswith(f"{current_class}."): - MethodName = f"{current_class}.{MethodName}" - self.class_methods[current_class].append(MethodName) - if hasattr(node, 'body') and isinstance(node.body, list): - self._collect_classes_and_methods(node.body, parent=node) - elif hasattr(node, 'BlockItems') and node.BlockItems: - self._collect_classes_and_methods(node.BlockItems, parent=node) - - def _generate_structs(self): - all_classes = set(self.class_methods.keys()) | set(self.class_members.keys()) - - preserved_structs = {} - for name, st in self.structs.items(): - if name not in all_classes: - preserved_structs[name] = st - elif isinstance(st, ir.IdentifiedStructType): - preserved_structs[name] = st - - self.structs.clear() - - for name, st in preserved_structs.items(): - self.structs[name] = st - - # Step 1: 先为所有类创建空的 struct,确保后面可以正确引用 - all_classes = set(self.class_methods.keys()) | set(self.class_members.keys()) - for ClassName in all_classes: - is_packed = ClassName in self.class_packed - if hasattr(self, 'SymbolTable') and self.SymbolTable and ClassName in self.SymbolTable: - Entry = self.SymbolTable[ClassName] - if hasattr(Entry, 'IsExceptionClass') and Entry.IsExceptionClass: - continue - if hasattr(Entry, 'IsEnum') and Entry.IsEnum: - if not getattr(Entry, 'IsRenum', False): - continue - if hasattr(Entry, 'IsTypedef') and Entry.IsTypedef: - if hasattr(Entry, 'BaseType') and Entry.BaseType and not isinstance(Entry.BaseType, (type(None),)): - import lib.includes.t as _t - if not isinstance(Entry.BaseType, (_t._CTypedef,)): - continue - if ClassName in self.structs: - if is_packed: - self.structs[ClassName].packed = True - continue - mangled_name = self._mangle_name(ClassName) - struct_type = ir.IdentifiedStructType(self.module, mangled_name, packed=is_packed) - self.structs[ClassName] = struct_type - - # Step 2: 解析跨模块的成员类型 - for ClassName, annotations in self.class_member_annotations.items(): - if ClassName not in self.class_members: - continue - for i, (member_name, member_type) in enumerate(self.class_members[ClassName]): - if member_name in annotations: - annotation = annotations[member_name] - ResolvedType = None - - if isinstance(annotation, ast.Attribute): - ClassTypeName = annotation.attr - if ClassTypeName in self.structs: - ResolvedType = self.structs[ClassTypeName] - elif isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr): - left = annotation.left - if isinstance(left, ast.Attribute): - ClassTypeName = left.attr - if ClassTypeName in self.structs: - ResolvedType = self.structs[ClassTypeName] - - if ResolvedType: - self.class_members[ClassName][i] = (member_name, ResolvedType) - - struct_name_map = {} - for struct_name, struct in self.structs.items(): - try: - struct_name_map[struct.name] = struct - except AssertionError: - struct_name_map[struct_name] = struct - orig = getattr(struct, '_original_name', None) - if orig: - struct_name_map[orig] = struct - - # Step 3: 更新成员类型,确保使用正确的 mangled struct 引用 - for ClassName in all_classes: - if ClassName not in self.class_members: - continue - for i, (member_name, member_type) in enumerate(self.class_members[ClassName]): - if isinstance(member_type, ir.PointerType): - pointee = member_type.pointee - if isinstance(pointee, ir.IdentifiedStructType): - try: - pname = pointee.name - except AssertionError: - pname = None - struct = struct_name_map.get(pname) if pname else None - if struct is None: - orig = getattr(pointee, '_original_name', None) - struct = struct_name_map.get(orig) if orig else None - if struct is not None: - self.class_members[ClassName][i] = (member_name, ir.PointerType(struct)) - else: - raw_name = pname or '' - if raw_name.startswith('struct.'): - raw_name = raw_name[7:] - new_struct = self._get_or_create_struct(raw_name) - self.class_members[ClassName][i] = (member_name, ir.PointerType(new_struct)) - elif isinstance(member_type, ir.IdentifiedStructType): - try: - mname = member_type.name - except AssertionError: - mname = None - struct = struct_name_map.get(mname) if mname else None - if struct is None: - orig = getattr(member_type, '_original_name', None) - struct = struct_name_map.get(orig) if orig else None - if struct is not None: - self.class_members[ClassName][i] = (member_name, struct) - else: - raw_name = mname or '' - if raw_name.startswith('struct.'): - raw_name = raw_name[7:] - new_struct = self._get_or_create_struct(raw_name) - self.class_members[ClassName][i] = (member_name, new_struct) - - # Step 4: 创建最终的 structs 并设置正确的成员类型 - for ClassName in all_classes: - if hasattr(self, 'SymbolTable') and self.SymbolTable and ClassName in self.SymbolTable: - Entry = self.SymbolTable[ClassName] - if hasattr(Entry, 'IsExceptionClass') and Entry.IsExceptionClass: - continue - if hasattr(Entry, 'IsEnum') and Entry.IsEnum: - if not getattr(Entry, 'IsRenum', False): - continue - existing_st = self.structs.get(ClassName) - if isinstance(existing_st, ir.IdentifiedStructType) and existing_st.elements is not None and len(existing_st.elements) > 0: - # 即使 struct 已有元素,也需要修正 packed 属性 - if ClassName in self.class_packed and not existing_st.packed: - existing_st.packed = True - continue - has_vtable = ClassName in self.class_vtable or ClassName in self._cross_module_vtable_classes - if not has_vtable: - p = self.class_parent.get(ClassName) - while p: - if p in self.class_vtable or p in self._cross_module_vtable_classes: - has_vtable = True - self.class_vtable.add(ClassName) - break - p = self.class_parent.get(p) - has_bitfield = ClassName in self.class_member_bitfields and any( - self.class_member_bitfields[ClassName].get(name, 0) > 0 - for name, _ in self.class_members.get(ClassName, []) - ) - all_members = self.class_members.get(ClassName, []) - all_bitfield = all( - self.class_member_bitfields.get(ClassName, {}).get(name, 0) > 0 - for name, _ in all_members - ) if all_members else False - - mangled_name = self._mangle_name(ClassName) - - if has_bitfield and all_bitfield: - total_bits = sum(self.class_member_bitfields.get(ClassName, {}).get(name, 0) - for name, _ in all_members) - if total_bits <= 8: - storage_type = ir.IntType(8) - elif total_bits <= 16: - storage_type = ir.IntType(16) - elif total_bits <= 32: - storage_type = ir.IntType(32) - else: - storage_type = ir.IntType(64) - member_types = [storage_type] - bitfield_offsets = {} - current_bit_offset = 0 - for name, _ in all_members: - bit_width = self.class_member_bitfields.get(ClassName, {}).get(name, 0) - bitfield_offsets[name] = current_bit_offset - current_bit_offset += bit_width - self.class_member_bitoffsets[ClassName] = bitfield_offsets - else: - member_types = [] - if has_vtable: - member_types.append(ir.PointerType(ir.IntType(8))) - if ClassName in self.class_members: - for _, member_type in self.class_members[ClassName]: - if member_type is None: - member_type = ir.IntType(32) - member_types.append(member_type) - else: - member_types = [ir.IntType(8)] - - # 获取之前创建的 struct 并设置成员 - struct_type = self.structs[ClassName] - if ClassName in self.class_packed: - struct_type.packed = True - # 只在未设置 body 时设置,避免重复定义错误 - if struct_type.elements is None: - struct_type.set_body(*member_types) - - def _create_Vtable_globals(self): - for ClassName, methods in self.class_methods.items(): - if ClassName in self.Vtables: - continue - if not methods: - continue - if ClassName not in self.class_vtable and ClassName not in self._cross_module_vtable_classes: - continue - VtableType = ir.ArrayType(ir.PointerType(ir.IntType(8)), len(methods)) - Vtable = ir.GlobalVariable(self.module, VtableType, name=self._mangle_name(f"{ClassName}_Vtable")) - Vtable.initializer = ir.Constant(VtableType, [ir.Constant(ir.PointerType(ir.IntType(8)), None)] * len(methods)) - Vtable.linkage = 'internal' - self.Vtables[ClassName] = Vtable - - def _fix_global_var_init(self): - for gv_name, gv in list(self.module.globals.items()): - if not isinstance(gv, ir.GlobalVariable): - continue - if gv.linkage in ('external', 'extern_weak'): - continue - needs_fix = False - if gv.initializer is None: - needs_fix = True - elif hasattr(gv.initializer, 'constant') and isinstance(gv.initializer.constant, _Undefined): - needs_fix = True - elif isinstance(gv.initializer, ir.Constant): - if isinstance(gv.initializer.constant, list): - if any(hasattr(c, 'constant') and isinstance(c.constant, _Undefined) for c in gv.initializer.constant): - needs_fix = True - if not needs_fix: - continue - gv.initializer = ir.Constant(gv.value_type, None) - if gv_name.startswith('str_const_') or gv_name.endswith('_Vtable') or gv_name.endswith('_str'): - gv.linkage = 'internal' - - def _zero_value_for_type(self, var_type): - if isinstance(var_type, ir.IntType): - return ir.Constant(var_type, 0) - elif isinstance(var_type, (ir.FloatType, ir.DoubleType)): - return ir.Constant(var_type, 0.0) - elif isinstance(var_type, ir.PointerType): - return ir.Constant(var_type, None) - elif isinstance(var_type, ir.ArrayType): - elem_zv = self._zero_value_for_type(var_type.element) - if elem_zv is None: - return None - return ir.Constant(var_type, [elem_zv] * var_type.count) - elif isinstance(var_type, ir.BaseStructType): - if var_type.elements is not None and len(var_type.elements) > 0: - elem_zvs = [self._zero_value_for_type(m) for m in var_type.elements] - if any(zv is None for zv in elem_zvs): - return None - return ir.Constant(var_type, elem_zvs) - return None - return None - - def _set_Vtable_initializers(self): - for ClassName, methods in self.class_methods.items(): - if ClassName not in self.Vtables: - continue - if not methods: - continue - struct_type = self.structs.get(ClassName) - if not struct_type: - continue - Vtable = self.Vtables[ClassName] - Vtable_entries = [] - for MethodName in methods: - short_name = MethodName.split('.')[-1] if '.' in MethodName else MethodName - full_MethodName = f"{ClassName}.{short_name}" - func = None - if full_MethodName in self.functions: - func = self.functions[full_MethodName] - if func is None: - parent_cls = self.class_parent.get(ClassName) - while parent_cls: - parent_full = f"{parent_cls}.{short_name}" - if parent_full in self.functions: - func = self.functions[parent_full] - break - parent_cls = self.class_parent.get(parent_cls) - if func is None: - Vtable_entries.append(ir.Constant(ir.PointerType(ir.IntType(8)), None)) - continue - Vtable_entries.append(func.bitcast(ir.PointerType(ir.IntType(8)))) - Vtable.initializer = ir.Constant(Vtable.type.pointee, Vtable_entries) - - def _adjust_args(self, args, func): - adjusted = [] - for i, (arg, param) in enumerate(zip(args, func.args)): - if arg.type != param.type: - if isinstance(arg.type, ir.PointerType) and isinstance(param.type, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): - if arg.type.pointee == param.type or (hasattr(arg.type.pointee, 'name') and hasattr(param.type, 'name') and arg.type.pointee.name == param.type.name): - adjusted.append(self._load(arg, name=f"load_arg_{i}")) - continue - try: - if isinstance(arg.type, ir.IntType) and isinstance(param.type, ir.PointerType): - if isinstance(param.type.pointee, ir.IntType) and param.type.pointee.width == 8 and arg.type.width == 8: - # 当参数是 i8(字符值)而函数期望 i8*(字符串指针)时 - # 为字符值分配内存,创建 null-terminated 字符串 - tmp = self._alloca(ir.ArrayType(ir.IntType(8), 2), name=f"char2str_arg_{i}") - zero = ir.Constant(ir.IntType(32), 0) - char_ptr = self.builder.gep(tmp, [zero, zero], name=f"char2str_ptr_{i}") - self._store(arg, char_ptr) - null_ptr = self.builder.gep(tmp, [zero, ir.Constant(ir.IntType(32), 1)], name=f"char2str_null_{i}") - self._store(ir.Constant(ir.IntType(8), 0), null_ptr) - adjusted.append(char_ptr) - else: - if isinstance(arg.type, ir.PointerType) and isinstance(param.type, ir.IntType): - # 当参数是指针而函数期望整数时,使用 ptrtoint - adjusted.append(self.builder.ptrtoint(arg, param.type, name=f"ptrtoint_arg_{i}")) - else: - if arg.type.width < 32: - arg = self.builder.zext(arg, ir.IntType(32), name=f"zext_arg_{i}") - adjusted.append(self.builder.inttoptr(arg, param.type, name=f"inttoptr_arg_{i}")) - elif isinstance(arg.type, ir.PointerType) and isinstance(param.type, ir.IntType): - # 当参数是指针而函数期望整数时,使用 ptrtoint - adjusted.append(self.builder.ptrtoint(arg, param.type, name=f"ptrtoint_arg_{i}")) - elif isinstance(arg.type, ir.PointerType) and isinstance(param.type, ir.PointerType): - if isinstance(arg.type.pointee, ir.PointerType) and isinstance(param.type.pointee, ir.IntType): - loaded = self._load(arg, name=f"load_arg_{i}") - adjusted.append(loaded) - elif isinstance(arg.type.pointee, ir.ArrayType) and isinstance(param.type.pointee, (ir.IntType, ir.FloatType, ir.DoubleType)): - zero = ir.Constant(ir.IntType(32), 0) - elem_ptr = self.builder.gep(arg, [zero, zero], name=f"array_decay_arg_{i}") - if elem_ptr.type != param.type: - adjusted.append(self.builder.bitcast(elem_ptr, param.type, name=f"cast_arg_{i}")) - else: - adjusted.append(elem_ptr) - elif isinstance(arg.type.pointee, ir.ArrayType) and isinstance(param.type.pointee, ir.PointerType): - zero = ir.Constant(ir.IntType(32), 0) - elem_ptr = self.builder.gep(arg, [zero, zero], name=f"array_decay_arg_{i}") - if elem_ptr.type != param.type: - adjusted.append(self.builder.bitcast(elem_ptr, param.type, name=f"cast_arg_{i}")) - else: - adjusted.append(elem_ptr) - else: - adjusted.append(self.builder.bitcast(arg, param.type, name=f"cast_arg_{i}")) - else: - if isinstance(arg.type, ir.PointerType) and isinstance(param.type, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): - if arg.type.pointee == param.type or (hasattr(arg.type.pointee, 'name') and hasattr(param.type, 'name') and arg.type.pointee.name == param.type.name): - adjusted.append(self._load(arg, name=f"load_arg_{i}")) - elif isinstance(arg.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): - tmp = self._alloca(param.type, name=f"temp_arg_{i}") - loaded = self.builder.bitcast(arg, ir.PointerType(param.type), name=f"cast_arg_{i}") - loaded_val = self._load(loaded, name=f"load_arg_{i}") - self._store(loaded_val, tmp) - adjusted.append(self._load(tmp, name=f"reload_arg_{i}")) - else: - tmp = self._alloca(param.type, name=f"temp_arg_{i}") - cast_ptr = self.builder.bitcast(arg, ir.PointerType(param.type), name=f"cast_arg_{i}") - loaded_val = self._load(cast_ptr, name=f"load_arg_{i}") - self._store(loaded_val, tmp) - adjusted.append(self._load(tmp, name=f"reload_arg_{i}")) - elif isinstance(arg.type, ir.PointerType) and arg.type.pointee == param.type: - adjusted.append(self._load(arg, name=f"load_arg_{i}")) - elif isinstance(param.type, ir.PointerType) and param.type.pointee == arg.type: - tmp = self._alloca(arg.type, name=f"temp_arg_{i}") - self._store(arg, tmp) - adjusted.append(tmp) - elif isinstance(arg.type, ir.IntType) and isinstance(param.type, ir.IntType): - if arg.type.width < param.type.width: - # 整数扩展:使用 sext(符号扩展)以正确处理负数 - adjusted.append(self.builder.sext(arg, param.type, name=f"sext_arg_{i}")) - else: - adjusted.append(self.builder.trunc(arg, param.type, name=f"trunc_arg_{i}")) - elif isinstance(arg.type, (ir.FloatType, ir.DoubleType)) and isinstance(param.type, (ir.FloatType, ir.DoubleType)): - if isinstance(arg.type, ir.DoubleType) and isinstance(param.type, ir.FloatType): - adjusted.append(self.builder.fptrunc(arg, param.type, name=f"fptrunc_arg_{i}")) - elif isinstance(arg.type, ir.FloatType) and isinstance(param.type, ir.DoubleType): - adjusted.append(self.builder.fpext(arg, param.type, name=f"fpext_arg_{i}")) - else: - adjusted.append(arg) - elif isinstance(arg.type, (ir.FloatType, ir.DoubleType)) and isinstance(param.type, ir.IntType): - adjusted.append(self.builder.fptosi(arg, param.type, name=f"fptosi_arg_{i}")) - elif isinstance(arg.type, ir.IntType) and isinstance(param.type, (ir.FloatType, ir.DoubleType)): - adjusted.append(self.builder.sitofp(arg, param.type, name=f"sitofp_arg_{i}")) - elif isinstance(arg.type, ir.IntType) and isinstance(param.type, ir.PointerType): - # 整数转指针:inttoptr - if arg.type.width < 64: - i64_val = self.builder.sext(arg, ir.IntType(64), name=f"sext_arg_{i}") - adjusted.append(self.builder.inttoptr(i64_val, param.type, name=f"inttoptr_arg_{i}")) - else: - adjusted.append(self.builder.inttoptr(arg, param.type, name=f"inttoptr_arg_{i}")) - elif isinstance(arg.type, ir.PointerType) and isinstance(param.type, ir.IntType): - # 指针转整数:ptrtoint - i64_val = self.builder.ptrtoint(arg, ir.IntType(64), name=f"ptrtoint_arg_{i}") - if i64_val.type.width > param.type.width: - adjusted.append(self.builder.trunc(i64_val, param.type, name=f"trunc_arg_{i}")) - elif i64_val.type.width < param.type.width: - adjusted.append(self.builder.sext(i64_val, param.type, name=f"sext_arg_{i}")) - else: - adjusted.append(i64_val) - else: - adjusted.append(self.builder.bitcast(arg, param.type, name=f"cast_arg_{i}")) - except Exception: # 参数类型调整失败时使用简化回退逻辑 - if isinstance(arg.type, ir.PointerType) and isinstance(param.type, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): - if arg.type.pointee == param.type or (hasattr(arg.type.pointee, 'name') and hasattr(param.type, 'name') and arg.type.pointee.name == param.type.name): - adjusted.append(self._load(arg, name=f"load_arg_{i}")) - else: - adjusted.append(self.builder.bitcast(arg, param.type, name=f"cast_arg_{i}")) - elif isinstance(arg.type, ir.PointerType) and arg.type.pointee == param.type: - adjusted.append(self._load(arg, name=f"load_arg_{i}")) - elif isinstance(param.type, ir.PointerType) and param.type.pointee == arg.type: - tmp = self._alloca(arg.type, name=f"temp_arg_{i}") - self._store(arg, tmp) - adjusted.append(tmp) - else: - adjusted.append(arg) - else: - adjusted.append(arg) - while len(adjusted) < len(func.args): - missing_idx = len(adjusted) - param = func.args[missing_idx] - param_type = param.type if hasattr(param, 'type') else param - if isinstance(param_type, ir.PointerType): - adjusted.append(ir.Constant(param_type, None)) - elif isinstance(param_type, ir.IntType): - adjusted.append(ir.Constant(param_type, 0)) - elif isinstance(param_type, (ir.FloatType, ir.DoubleType)): - adjusted.append(ir.Constant(param_type, 0.0)) - else: - adjusted.append(ir.Constant(ir.IntType(32), 0)) - if func.type.pointee.var_arg: - for i in range(len(func.args), len(args)): - arg = args[i] - adjusted.append(arg) - return adjusted - - def _get_member_offset(self, field_name, ClassName=None): - has_vtable = ClassName and (ClassName in self.class_vtable or ClassName in self._cross_module_vtable_classes) - base = 1 if has_vtable else 0 - if ClassName and ClassName in self.structs: - struct_type = self.structs[ClassName] - if isinstance(struct_type, ir.IdentifiedStructType) and struct_type.elements is not None and len(struct_type.elements) > 0: - if ClassName in self.class_members: - expected_fields = len(self.class_members[ClassName]) - actual_elements = len(struct_type.elements) - if base > 0 and actual_elements == expected_fields: - base = 0 - if ClassName and ClassName in self.class_members: - for i, (name, _) in enumerate(self.class_members[ClassName]): - if name == field_name: - return base + i - short_name = ClassName.split('.')[-1] if ClassName and '.' in ClassName else None - if short_name and short_name in self.class_members: - for i, (name, _) in enumerate(self.class_members[short_name]): - if name == field_name: - return base + i - if ClassName and field_name: - if ClassName not in self.class_members or field_name not in [n for n, _ in self.class_members.get(ClassName, [])]: - if hasattr(self, '_Trans') and self._Trans and hasattr(self._Trans, 'ImportHandler'): - sha1_map = getattr(self, 'module_sha1_map', {}) - for mod_name, mod_sha1 in sha1_map.items(): - stub_name = f"{mod_sha1}.stub.ll" - self._Trans.ImportHandler._TryLoadClassMembersFromPyi(ClassName, stub_name, self) - if ClassName in self.class_members and len(self.class_members[ClassName]) > 0: - for i, (name, _) in enumerate(self.class_members[ClassName]): - if name == field_name: - return base + i - break - if short_name: - for mod_name, mod_sha1 in sha1_map.items(): - stub_name = f"{mod_sha1}.stub.ll" - self._Trans.ImportHandler._TryLoadClassMembersFromPyi(short_name, stub_name, self) - if short_name in self.class_members and len(self.class_members[short_name]) > 0: - for i, (name, _) in enumerate(self.class_members[short_name]): - if name == field_name: - return base + i - break - if ClassName and field_name: - for cn_key in self.class_members: - if cn_key == ClassName or cn_key.endswith(f'.{ClassName}') or (short_name and (cn_key == short_name or cn_key.endswith(f'.{short_name}'))): - for i, (name, _) in enumerate(self.class_members[cn_key]): - if name == field_name: - return base + i - if ClassName and ClassName in self.structs: - struct_type = self.structs[ClassName] - if isinstance(struct_type, ir.IdentifiedStructType) and struct_type.elements is not None and len(struct_type.elements) > 0: - for cn_key, members in self.class_members.items(): - if cn_key == short_name or (short_name and cn_key.endswith(f'.{short_name}')): - for i, (name, _) in enumerate(members): - if name == field_name and i < len(struct_type.elements): - return i - break - else: - if short_name: - for cn_key, members in self.class_members.items(): - sn = cn_key.split('.')[-1] if '.' in cn_key else cn_key - if sn == short_name: - for i, (name, _) in enumerate(members): - if name == field_name and i < len(struct_type.elements): - return i - break - if ClassName and field_name and ClassName not in self.class_members: - if hasattr(self, '_Trans') and self._Trans and hasattr(self._Trans, 'ImportHandler'): - for temp_dir_candidate in [getattr(self, '_temp_dir', None)]: - if temp_dir_candidate and os.path.isdir(temp_dir_candidate): - for pyi_file in os.listdir(temp_dir_candidate): - if pyi_file.endswith('.pyi'): - stub_name = pyi_file.replace('.pyi', '.stub.ll') - short_cn = short_name if short_name else ClassName - self._Trans.ImportHandler._TryLoadClassMembersFromPyi(short_cn, stub_name, self) - if short_cn in self.class_members and len(self.class_members[short_cn]) > 0: - for i, (name, _) in enumerate(self.class_members[short_cn]): - if name == field_name: - return base + i - break - if ClassName and ClassName in self.structs and (ClassName not in self.class_members or len(self.class_members.get(ClassName, [])) == 0): - struct_type = self.structs[ClassName] - if isinstance(struct_type, ir.IdentifiedStructType) and struct_type.elements is not None: - if hasattr(self, '_Trans') and self._Trans and hasattr(self._Trans, 'ClassHandler'): - class_handler = self._Trans.ClassHandler - if hasattr(self, '_current_tree') and self._current_tree: - for node in ast.iter_child_nodes(self._current_tree): - if isinstance(node, ast.ClassDef) and (node.name == ClassName or node.name == short_name): - if node.name not in self.class_members: - self.class_members[node.name] = [] - if len(self.class_members[node.name]) == 0: - class_handler._PreRegisterClassMembers(node, self) - if ClassName in self.class_members: - for i, (name, _) in enumerate(self.class_members[ClassName]): - if name == field_name: - return base + i - if short_name and short_name in self.class_members: - for i, (name, _) in enumerate(self.class_members[short_name]): - if name == field_name: - return base + i - break - return None - - def _resolve_class_for_var(self, var_name): - for ClassName in self.class_methods: - if var_name == ClassName or var_name.startswith(f"__with_{ClassName}_"): - return ClassName - if var_name in self.variables: - var = self.variables[var_name] - if isinstance(var.type, ir.PointerType): - for ClassName, struct_type in self.structs.items(): - if var.type.pointee == struct_type: - return ClassName - if isinstance(var.type.pointee, ir.PointerType) and var.type.pointee.pointee == struct_type: - return ClassName - return None - - def _GetOrCreateFunc(self, FuncName, ArgTypes): - mangled_name = self._mangle_func_name(FuncName) - if mangled_name in self.functions: - return self.functions[mangled_name] - FuncType = self._InferFuncTypeForCall(FuncName, ArgTypes) - try: - func = ir.Function(self.module, FuncType, name=mangled_name) - except Exception: # 函数名冲突时添加前缀重试 - func = ir.Function(self.module, FuncType, name=f"_{mangled_name}") - self.functions[mangled_name] = func - return func - - def _resolve_method_class(self, MethodName): - for ClassName, methods in self.class_methods.items(): - if MethodName in methods: - return ClassName - full_name = f"{ClassName}.{MethodName}" - if full_name in methods: - return ClassName - return None - - def _get_va_start_intrinsic(self): - if 'llvm.va_start' in self.functions: - return self.functions['llvm.va_start'] - ftype = ir.FunctionType(ir.VoidType(), [ir.IntType(8).as_pointer()]) - func = ir.Function(self.module, ftype, name='llvm.va_start') - self.functions['llvm.va_start'] = func - return func - - def _get_va_end_intrinsic(self): - if 'llvm.va_end' in self.functions: - return self.functions['llvm.va_end'] - ftype = ir.FunctionType(ir.VoidType(), [ir.IntType(8).as_pointer()]) - func = ir.Function(self.module, ftype, name='llvm.va_end') - self.functions['llvm.va_end'] = func - return func - - def emit_va_start(self, va_list_ptr): - if not self.builder: - return None - func = self._get_va_start_intrinsic() - i8ptr_type = ir.IntType(8).as_pointer() - if va_list_ptr.type == i8ptr_type: - self.builder.call(func, [va_list_ptr]) - else: - ptr = self.builder.bitcast(va_list_ptr, i8ptr_type, name="va_list_i8ptr") - self.builder.call(func, [ptr]) - return None - - def _emit_stack_align(self, alignment=16): - if not self.builder: - return None - void = ir.VoidType() - asm_type = ir.FunctionType(void, []) - mask = -alignment - intel_asm = f"and rsp, {mask}" - asm_str = _intel_to_att(intel_asm) - asm_func = ir.InlineAsm(asm_type, asm_str, "~{dirflag},~{fpsr},~{flags},~{rsp}", side_effect=True) - self.builder.call(asm_func, [], name="align_stack") - return None - - def emit_va_end(self, va_list_ptr): - if not self.builder: - return None - func = self._get_va_end_intrinsic() - i8ptr_type = ir.IntType(8).as_pointer() - if va_list_ptr.type == i8ptr_type: - self.builder.call(func, [va_list_ptr]) - else: - ptr = self.builder.bitcast(va_list_ptr, i8ptr_type, name="va_list_i8ptr") - self.builder.call(func, [ptr]) - return None - - def emit_va_arg(self, va_list_ptr, arg_type): - if not self.builder: - return self._zero_const(arg_type) - if not hasattr(self, '_va_arg_counter'): - self._va_arg_counter = 0 - self._va_arg_counter += 1 - import sys - is_x86_64 = sys.platform in ('win32', 'win64', 'windows', 'linux', 'linux2', 'darwin') - if is_x86_64: - if isinstance(arg_type, ir.PointerType): - va_arg_type = ir.IntType(64) - elif isinstance(arg_type, (ir.FloatType, ir.DoubleType)): - va_arg_type = ir.DoubleType() - elif isinstance(arg_type, ir.IntType) and arg_type.width < 64: - va_arg_type = ir.IntType(64) - else: - va_arg_type = arg_type - instr = VaArgInstruction(self.builder.block, va_arg_type, 'va_arg', (va_list_ptr,), name=f'va_arg_raw_{self._va_arg_counter}') - self.builder._insert(instr) - if va_arg_type != arg_type: - if isinstance(arg_type, ir.PointerType): - result = self.builder.inttoptr(instr, arg_type, name=f'va_arg_ptr_{self._va_arg_counter}') - elif isinstance(arg_type, ir.FloatType): - result = self.builder.fptrunc(instr, arg_type, name=f'va_arg_fptrunc_{self._va_arg_counter}') - else: - result = self.builder.trunc(instr, arg_type, name=f'va_arg_trunc_{self._va_arg_counter}') - else: - result = instr - return result - else: - if isinstance(arg_type, ir.IntType) and arg_type.width < 64: - arg_type = ir.IntType(64) - instr = VaArgInstruction(self.builder.block, arg_type, 'va_arg', (va_list_ptr,), name=f'va_arg_raw_{self._va_arg_counter}') - self.builder._insert(instr) - return instr - - def _infer_return_type(self, FuncName): - if FuncName in self.functions: - return self.functions[FuncName].type.pointee.return_type - if FuncName in self.known_return_types: - return self.known_return_types[FuncName] - for ClassName, methods in self.class_methods.items(): - for method in methods: - if FuncName == method: - return ir.VoidType() - return ir.IntType(32) - - def _InferFuncTypeForCall(self, FuncName, ArgTypes): - return_type = self._infer_return_type(FuncName) - if not ArgTypes: - for ClassName, methods in self.class_methods.items(): - if FuncName in methods: - if ClassName in self.structs: - ArgTypes = [ir.PointerType(self.structs[ClassName])] - else: - ArgTypes = [ir.PointerType(ir.LiteralStructType([ir.PointerType(ir.IntType(8)), ir.IntType(32)]))] - break - else: - ArgTypes = [ir.IntType(32)] - return ir.FunctionType(return_type, ArgTypes) - - def _zero_const(self, typ): - if isinstance(typ, ir.PointerType): - return ir.Constant(typ, None) - return ir.Constant(typ, 0) - - def _alloca(self, typ, name='', align=None, size=None): - if align is None: - align = self._get_align(typ) - if size is not None: - instr = self.builder.alloca(typ, size=size, name=name) - else: - instr = self.builder.alloca(typ, name=name) - if align: - instr.align = align - return instr - - def _alloca_entry(self, typ, name='', align=None): - if align is None: - align = self._get_align(typ) - saved_block = self.builder.block - entry_block = self.func.entry_basic_block - if entry_block.instructions: - first_instr = entry_block.instructions[0] - self.builder.position_before(first_instr) - instr = self.builder.alloca(typ, name=name) - if align: - instr.align = align - self.builder.position_at_end(saved_block) - else: - self.builder.position_at_start(entry_block) - instr = self.builder.alloca(typ, name=name) - if align: - instr.align = align - self.builder.position_at_end(saved_block) - return instr - - def _load(self, ptr, name='', align=None): - if align is None: - if isinstance(ptr.type, ir.PointerType): - align = self._get_align(ptr.type.pointee) - else: - align = 0 - if isinstance(ptr.type, ir.PointerType): - pointee_type = ptr.type.pointee - typedef_names = TYPEDEF_NAMES - if isinstance(pointee_type, ir.IdentifiedStructType) and pointee_type.name in typedef_names: - actual_type = ir.IntType(32) - if pointee_type.name in {'BYTE', 'INT8', 'UINT8'}: - actual_type = ir.IntType(8) - elif pointee_type.name in {'WORD', 'INT16', 'UINT16'}: - actual_type = ir.IntType(16) - elif pointee_type.name in {'DWORD', 'INT32', 'UINT32'}: - actual_type = ir.IntType(32) - elif pointee_type.name in {'QWORD', 'INT64', 'UINT64'}: - actual_type = ir.IntType(64) - bitcast_ptr = self.builder.bitcast(ptr, ir.PointerType(actual_type), name="typedef_bitcast_load") - return self.builder.load(bitcast_ptr, name=name, align=align) - return self.builder.load(ptr, name=name, align=align) - - def _load_var(self, name): - if name in self._direct_values: - return self._direct_values[name] - if name in self.variables and self.variables[name] is not None: - VarPtr = self.variables[name] - if isinstance(VarPtr, ir.GlobalVariable) and isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): - return VarPtr - if isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): - return VarPtr - return self._load(VarPtr, name=name) - if name in self.global_vars and name in self.module.globals: - GVar = self.module.globals[name] - self.variables[name] = GVar - if isinstance(GVar, ir.Function): - return GVar - if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): - return GVar - return self._load(GVar, name=name) - if name in self.module.globals: - GVar = self.module.globals[name] - self.variables[name] = GVar - if isinstance(GVar, ir.Function): - return GVar - if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): - return GVar - return self._load(GVar, name=name) - return None - - def _store_var(self, name, value): - if name in self._direct_values: - old_val = self._direct_values.pop(name) - if name not in self.variables or self.variables[name] is None: - var = self.builder.alloca(old_val.type, name=name) - self._store(old_val, var) - self.variables[name] = var - if name in self.variables and self.variables[name] is not None: - self._store(value, self.variables[name]) - else: - var = self.builder.alloca(value.type, name=name) - self._store(value, var) - self.variables[name] = var - - def _ensure_alloca(self, name, llvm_type): - if name in self._direct_values: - val = self._direct_values.pop(name) - var = self.builder.alloca(llvm_type, name=name) - self._store(val, var) - self.variables[name] = var - return var - if name in self.variables and self.variables[name] is not None: - return self.variables[name] - var = self.builder.alloca(llvm_type, name=name) - self.variables[name] = var - return var - - def _coerce_value(self, val, target_type): - if val.type == target_type: - return val - typedef_names = TYPEDEF_NAMES - if isinstance(target_type, ir.IdentifiedStructType) and target_type.name in typedef_names: - if isinstance(val.type, ir.IntType): - return val - if isinstance(target_type, ir.IntType) and isinstance(val.type, ir.IntType): - if target_type.width < val.type.width: - return self.builder.trunc(val, target_type, name="trunc_store") - else: - # 使用 sext(符号扩展)以正确处理负数 - return self.builder.sext(val, target_type, name="sext_store") - if isinstance(target_type, ir.PointerType) and isinstance(val.type, ir.PointerType): - if isinstance(val, ir.Constant) and val.constant is None: - return ir.Constant(target_type, None) - return self.builder.bitcast(val, target_type, name="ptr_bitcast_store") - if isinstance(target_type, ir.PointerType) and isinstance(val.type, ir.IntType): - if val.type.width < 64: - val = self.builder.zext(val, ir.IntType(64), name="zext_ptr_store") - return self.builder.inttoptr(val, target_type, name="int_to_ptr_store") - if isinstance(target_type, ir.IntType) and isinstance(val.type, ir.PointerType): - if isinstance(val.type.pointee, ir.IntType) and val.type.pointee.width == target_type.width: - return self.builder.load(val, name="load_ptr_as_int_store") - if target_type.width <= 8 and isinstance(val.type.pointee, ir.IntType): - loaded = self.builder.load(val, name="load_ptr_byte_store") - if loaded.type != target_type: - if isinstance(loaded.type, ir.IntType) and isinstance(target_type, ir.IntType): - if target_type.width < loaded.type.width: - return self.builder.trunc(loaded, target_type, name="trunc_ptr_byte_store") - return self.builder.zext(loaded, target_type, name="zext_ptr_byte_store") - return loaded - return self.builder.ptrtoint(val, target_type, name="ptr_to_int_store") - if isinstance(target_type, ir.FloatType) and isinstance(val.type, ir.DoubleType): - return self.builder.fptrunc(val, target_type, name="fptrunc_store") - if isinstance(target_type, ir.DoubleType) and isinstance(val.type, ir.FloatType): - return self.builder.fpext(val, target_type, name="fpext_store") - if isinstance(target_type, ir.IntType) and isinstance(val.type, (ir.FloatType, ir.DoubleType)): - return self.builder.fptosi(val, target_type, name="fptosi_store") - if isinstance(target_type, (ir.FloatType, ir.DoubleType)) and isinstance(val.type, ir.IntType): - return self.builder.sitofp(val, target_type, name="sitofp_store") - if isinstance(target_type, ir.ArrayType) and isinstance(val.type, ir.ArrayType): - if target_type.count == val.type.count and target_type.element == val.type.element: - return val - if (isinstance(target_type.element, ir.IntType) and target_type.element.width == 8 - and isinstance(val.type.element, ir.IntType) and val.type.element.width == 8): - if target_type.count > val.type.count: - padded = list(val.constant) if hasattr(val, 'constant') else [] - if padded and len(padded) == val.type.count: - padded.extend([ir.Constant(ir.IntType(8), 0)] * (target_type.count - val.type.count)) - return ir.Constant(target_type, padded) - elif target_type.count < val.type.count: - trimmed = list(val.constant) if hasattr(val, 'constant') else [] - if trimmed and len(trimmed) == val.type.count: - return ir.Constant(target_type, trimmed[:target_type.count]) - if isinstance(val.type, ir.PointerType) and not isinstance(target_type, ir.PointerType): - if val.type.pointee == target_type: - return self.builder.load(val, name="load_struct_for_store") - if isinstance(val.type.pointee, ir.IdentifiedStructType) and isinstance(target_type, ir.IdentifiedStructType): - if val.type.pointee.name == target_type.name: - loaded = self.builder.load(val, name="load_struct_for_store") - if loaded.type == target_type: - return loaded - return None - - def _store(self, val, ptr, align=None): - if align is None: - if isinstance(ptr.type, ir.PointerType): - align = self._get_align(ptr.type.pointee) - else: - align = 0 - if isinstance(ptr.type, ir.PointerType): - target_type = ptr.type.pointee - typedef_names = TYPEDEF_NAMES - if isinstance(target_type, ir.IdentifiedStructType) and target_type.name in typedef_names: - if isinstance(val.type, ir.IntType): - actual_type = ir.IntType(32) - if target_type.name in {'BYTE', 'INT8', 'UINT8'}: - actual_type = ir.IntType(8) - elif target_type.name in {'WORD', 'INT16', 'UINT16'}: - actual_type = ir.IntType(16) - elif target_type.name in {'DWORD', 'INT32', 'UINT32'}: - actual_type = ir.IntType(32) - elif target_type.name in {'QWORD', 'INT64', 'UINT64'}: - actual_type = ir.IntType(64) - bitcast_ptr = self.builder.bitcast(ptr, ir.PointerType(actual_type), name="typedef_bitcast") - if val.type.width != actual_type.width: - if val.type.width > actual_type.width: - val = self.builder.trunc(val, actual_type, name="trunc_typedef") - else: - val = self.builder.zext(val, actual_type, name="zext_typedef") - return self.builder.store(val, bitcast_ptr, align=align) - if val.type != target_type: - if isinstance(val, ir.Constant) and val.constant is None: - if isinstance(target_type, ir.PointerType): - val = ir.Constant(target_type, None) - elif isinstance(target_type, ir.IdentifiedStructType): - val = ir.Constant(ir.PointerType(target_type), None) - ptr = self.builder.bitcast(ptr, ir.PointerType(ir.PointerType(target_type)), name="null_struct_ptr_cast") - else: - coerced = self._coerce_value(val, target_type) - if coerced is not None: - val = coerced - else: - src_info = self._get_node_info() - raise TypeError(f"cannot store {val.type} to {ptr.type}: mismatching types{src_info}") - return self.builder.store(val, ptr, align=align) - - def _get_var_ptr(self, name): - if name in self._reg_values: - val = self._reg_values[name] - var = self._alloca(val.type, name=name) - self._store(val, var) - self.variables[name] = var - del self._reg_values[name] - return var - if name in self.variables and self.variables[name] is not None: - return self.variables[name] - return None - - def emit_constant(self, value, type_name='int'): - if type_name == 'int': - return ir.Constant(ir.IntType(32), int(value)) - elif type_name == 'uint64_t' or type_name == 'unsigned long long': - return ir.Constant(ir.IntType(64), int(value)) - elif type_name == 'uint32_t' or type_name == 'unsigned int': - return ir.Constant(ir.IntType(32), int(value)) - elif type_name == 'uint16_t' or type_name == 'unsigned short': - return ir.Constant(ir.IntType(16), int(value)) - elif type_name == 'uint8_t' or type_name == 'unsigned char': - return ir.Constant(ir.IntType(8), int(value)) - elif type_name == 'int64_t' or type_name == 'long long': - return ir.Constant(ir.IntType(64), int(value)) - elif type_name == 'int32_t' or type_name == 'int': - return ir.Constant(ir.IntType(32), int(value)) - elif type_name == 'int16_t' or type_name == 'short': - return ir.Constant(ir.IntType(16), int(value)) - elif type_name == 'int8_t' or type_name == 'char': - return ir.Constant(ir.IntType(8), int(value)) - elif type_name == 'float' or type_name == 'float32_t' or type_name == 'FLOAT32': - return ir.Constant(ir.FloatType(), float(value)) - elif type_name == 'double' or type_name == 'float64_t' or type_name == 'FLOAT64': - return ir.Constant(ir.DoubleType(), float(value)) - elif type_name == 'float16_t' or type_name == 'FLOAT16': - return ir.Constant(ir.IntType(16), int(value)) - elif type_name == 'float8_t' or type_name == 'FLOAT8': - return ir.Constant(ir.IntType(8), int(value)) - elif type_name == 'float128_t' or type_name == 'FLOAT128': - return ir.Constant(ir.IntType(128), int(value)) - elif type_name == 'string': - encoded = value.encode('utf-8') + b'\x00' - str_type = ir.ArrayType(ir.IntType(8), len(encoded)) - str_const = ir.Constant(str_type, bytearray(encoded)) - global_var = ir.GlobalVariable(self.module, str_type, name=f"str_const_{self.string_const_counter}") - self.string_const_counter += 1 - global_var.initializer = str_const - global_var.linkage = 'internal' - return self.builder.bitcast(global_var, ir.PointerType(ir.IntType(8)), name="str") - return ir.Constant(ir.IntType(32), int(value)) - - def emit_binary_op(self, op, left, right, is_unsigned=False): - # 处理指针和整数之间的类型转换 - if isinstance(left.type, ir.PointerType) and isinstance(right.type, ir.IntType): - right = self.builder.zext(right, ir.IntType(64), name="int2ptrint") - if op == '+' or op == 'Add': - return self.builder.gep(left, [right], name="ptr_add") - elif op == '-' or op == 'Sub': - return self.builder.gep(left, [self.builder.neg(right, name="neg")], name="ptr_sub") - if isinstance(left.type, ir.IntType) and isinstance(right.type, ir.PointerType): - left = self.builder.zext(left, ir.IntType(64), name="int2ptrint2") - if op == '+' or op == 'Add': - return self.builder.gep(right, [left], name="ptr_add_rev") - is_float = isinstance(left.type, (ir.FloatType, ir.DoubleType)) or \ - isinstance(right.type, (ir.FloatType, ir.DoubleType)) - if is_float: - if isinstance(left.type, (ir.FloatType, ir.DoubleType)): - ftype = left.type - elif isinstance(right.type, (ir.FloatType, ir.DoubleType)): - ftype = right.type - else: - ftype = ir.DoubleType() - if not isinstance(left.type, (ir.FloatType, ir.DoubleType)): - left = self._to_float(left, ftype) - elif left.type != ftype: - if isinstance(left.type, ir.FloatType) and isinstance(ftype, ir.DoubleType): - left = self.builder.fpext(left, ftype, name="fpext_l") - else: - left = self.builder.fptrunc(left, ftype, name="fptrunc_l") - if not isinstance(right.type, (ir.FloatType, ir.DoubleType)): - right = self._to_float(right, ftype) - elif right.type != ftype: - if isinstance(right.type, ir.FloatType) and isinstance(ftype, ir.DoubleType): - right = self.builder.fpext(right, ftype, name="fpext_r") - else: - right = self.builder.fptrunc(right, ftype, name="fptrunc_r") - float_ops = { - '+': self.builder.fadd, 'Add': self.builder.fadd, - '-': self.builder.fsub, 'Sub': self.builder.fsub, - '*': self.builder.fmul, 'Mult': self.builder.fmul, - '/': self.builder.fdiv, 'Div': self.builder.fdiv, - '%': self.builder.frem, 'Mod': self.builder.frem, - } - float_cmp_ops = { - '==': '==', 'Eq': '==', '!=': '!=', 'NotEq': '!=', - '<': '<', 'Lt': '<', '<=': '<=', 'LtE': '<=', - '>': '>', 'Gt': '>', '>=': '>=', 'GtE': '>=', - } - if op in float_ops: - return float_ops[op](left, right, name=op) - if op in float_cmp_ops: - return self.builder.fcmp_ordered(float_cmp_ops[op], left, right, name=op) - if is_unsigned: - ops = { - '+': self.builder.add, 'Add': self.builder.add, - '-': self.builder.sub, 'Sub': self.builder.sub, - '*': self.builder.mul, 'Mult': self.builder.mul, - '/': self.builder.udiv, 'Div': self.builder.udiv, - '%': self.builder.urem, 'Mod': self.builder.urem, - '//': self.builder.udiv, 'FloorDiv': self.builder.udiv, - } - else: - ops = { - '+': self.builder.add, 'Add': self.builder.add, - '-': self.builder.sub, 'Sub': self.builder.sub, - '*': self.builder.mul, 'Mult': self.builder.mul, - '/': self.builder.sdiv, 'Div': self.builder.sdiv, - '%': self.builder.srem, 'Mod': self.builder.srem, - '//': self.builder.sdiv, 'FloorDiv': self.builder.sdiv, - } - cmp_ops = { - '==': '==', 'Eq': '==', '!=': '!=', 'NotEq': '!=', - '<': '<', 'Lt': '<', '<=': '<=', 'LtE': '<=', - '>': '>', 'Gt': '>', '>=': '>=', 'GtE': '>=', - } - logic_ops = { - '&&': self.builder.and_, 'And': self.builder.and_, - '||': self.builder.or_, 'Or': self.builder.or_, - } - if op in ('>>', 'RShift') and not is_unsigned: - if isinstance(left.type, ir.IntType): - if left.type.width == 8: - is_unsigned = True - elif left.type.width == 16: - is_unsigned = True - elif left.type.width == 32: - if hasattr(self, '_last_var_name') and self._last_var_name: - is_unsigned = self._is_var_unsigned(self._last_var_name) - elif left.type.width == 64: - if hasattr(self, '_last_var_name') and self._last_var_name: - is_unsigned = self._is_var_unsigned(self._last_var_name) - shift_ops = { - '>>': self.builder.lshr if is_unsigned else self.builder.ashr, - 'RShift': self.builder.lshr if is_unsigned else self.builder.ashr, - '<<': self.builder.shl, 'LShift': self.builder.shl, - } - bit_ops = { - '&': self.builder.and_, - '|': self.builder.or_, - '^': self.builder.xor, - } - if op == '**' or op == 'Pow': - if isinstance(left, ir.Constant) and isinstance(right, ir.Constant): - try: - lv = left.constant - rv = right.constant - if isinstance(lv, int) and isinstance(rv, int) and rv >= 0: - result = lv ** rv - return ir.Constant(left.type, result) - except Exception as _e: - if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": - import logging; logging.warning(f"异常被忽略: {_e}") - pass - if isinstance(left.type, (ir.FloatType, ir.DoubleType)): - ftype = left.type - elif isinstance(right.type, (ir.FloatType, ir.DoubleType)): - ftype = right.type - else: - ftype = ir.DoubleType() - lf = self._to_float(left, ftype) - rf = self._to_float(right, ftype) - powf = self.module.globals.get('llvm.pow.f64') - if not powf: - fnty = ir.FunctionType(ir.DoubleType(), [ir.DoubleType(), ir.DoubleType()]) - powf = ir.Function(self.module, fnty, name='llvm.pow.f64') - if lf.type != ir.DoubleType(): - lf = self.builder.fpext(lf, ir.DoubleType(), name="ext_f64") - if rf.type != ir.DoubleType(): - rf = self.builder.fpext(rf, ir.DoubleType(), name="ext_f64") - result = self.builder.call(powf, [lf, rf], name="pow") - both_int = isinstance(left.type, ir.IntType) and isinstance(right.type, ir.IntType) - right_is_pos_int_const = isinstance(right, ir.Constant) and isinstance(right.constant, int) and right.constant >= 0 - if both_int and right_is_pos_int_const: - return self.builder.fptosi(result, left.type, name="pow2int") - if isinstance(left.type, ir.FloatType): - return self.builder.fptrunc(result, ir.FloatType(), name="pow2f32") - return result - if op in ops: - try: - return ops[op](left, right, name=op) - except Exception as e: - raise ValueError(f"{e}{self._get_node_info()}") - if op in shift_ops: - try: - return shift_ops[op](left, right, name=op) - except Exception as e: - raise ValueError(f"{e}{self._get_node_info()}") - if op in bit_ops: - try: - return bit_ops[op](left, right, name=op) - except Exception as e: - raise ValueError(f"{e}{self._get_node_info()}") - if op in cmp_ops: - try: - if is_unsigned: - return self.builder.icmp_unsigned(cmp_ops[op], left, right, name=op) - return self.builder.icmp_signed(cmp_ops[op], left, right, name=op) - except Exception as e: - raise ValueError(f"{e}{self._get_node_info()}") - if op in logic_ops: - try: - return logic_ops[op](left, right, name=op) - except Exception as e: - raise ValueError(f"{e}{self._get_node_info()}") - return left - - def _to_float(self, val, ftype=None): - if ftype is None: - ftype = ir.DoubleType() - if isinstance(val.type, (ir.FloatType, ir.DoubleType)): - if val.type == ftype: - return val - if isinstance(val.type, ir.FloatType) and isinstance(ftype, ir.DoubleType): - return self.builder.fpext(val, ftype, name="fpext") - return self.builder.fptrunc(val, ftype, name="fptrunc") - if isinstance(val.type, ir.IntType): - if val.type.width == 1: - val = self.builder.zext(val, ir.IntType(32), name="bool2i32") - return self.builder.sitofp(val, ftype, name="int2float") - return val - - def emit_return(self, value=None): - if not self.builder or self.builder.block.is_terminated: - return - if value is not None: - self._unregister_local_heap_ptr(value) - self._emit_local_heap_frees() - if hasattr(self, '_variadic_info') and self._variadic_info and self._variadic_info.get('va_start_called'): - va_list_ptr = self._variadic_info['va_list_ptr'] - self.emit_va_end(va_list_ptr) - if value is None: - if self.func and hasattr(self.func, 'ftype'): - ret_type = self.func.ftype.return_type - if isinstance(ret_type, ir.IntType): - self.builder.ret(ir.Constant(ret_type, 0)) - elif isinstance(ret_type, ir.PointerType): - self.builder.ret(ir.Constant(ret_type, None)) - elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)): - self.builder.ret(ir.Constant(ret_type, 0.0)) - elif isinstance(ret_type, ir.IdentifiedStructType): - if ret_type.elements: - zero_val = ir.Constant(ret_type, [ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)) else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType)) else ir.Constant(et, ir.Undefined) for et in ret_type.elements]) - else: - zero_val = ir.Constant(ret_type, None) - self.builder.ret(zero_val) - elif isinstance(ret_type, ir.ArrayType): - self.builder.ret(ir.Constant(ret_type, None)) - else: - self.builder.ret_void() - else: - self.builder.ret_void() - else: - if self.func and hasattr(self.func, 'ftype'): - ret_type = self.func.ftype.return_type - if ret_type != value.type: - if isinstance(ret_type, ir.PointerType) and isinstance(value.type, ir.PointerType): - if value.type.pointee == ret_type: - value = self._load(value, name="ret_load") - else: - value = self.builder.bitcast(value, ret_type, name="ret_cast") - elif isinstance(value.type, ir.PointerType) and not isinstance(ret_type, ir.PointerType): - if isinstance(value.type.pointee, ir.IntType) and isinstance(ret_type, ir.IntType) and value.type.pointee.width == ret_type.width: - value = self._load(value, name="ret_load") - elif isinstance(ret_type, ir.IntType): - value = self.builder.ptrtoint(value, ret_type, name="ret_ptrtoint") - elif isinstance(value.type.pointee, ret_type.__class__) and not isinstance(value.type.pointee, ir.IntType): - value = self._load(value, name="ret_load") - elif isinstance(value.type.pointee, ir.PointerType): - loaded = self._load(value, name="ret_deref") - if loaded.type == ret_type: - value = loaded - elif isinstance(ret_type, ir.IntType): - value = self.builder.ptrtoint(loaded, ret_type, name="ret_ptrtoint") - elif isinstance(ret_type, ir.IntType) and isinstance(value.type, ir.IntType): - if value.type.width < ret_type.width: - # 有符号值用 sext,无符号值用 zext - is_unsigned = id(value) in self._unsigned_results - if is_unsigned: - value = self.builder.zext(value, ret_type, name="ret_zext") - else: - value = self.builder.sext(value, ret_type, name="ret_sext") - elif value.type.width > ret_type.width: - value = self.builder.trunc(value, ret_type, name="ret_trunc") - elif isinstance(ret_type, ir.PointerType) and isinstance(value.type, ir.IntType): - value = self.builder.inttoptr(value, ret_type, name="ret_inttoptr") - elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)) and isinstance(value.type, ir.IntType): - value = self.builder.sitofp(value, ret_type, name="ret_int2float") - elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)) and isinstance(value.type, (ir.FloatType, ir.DoubleType)): - if ret_type != value.type: - value = self.builder.fpext(value, ret_type, name="ret_fpext") - self.builder.ret(value) - - def _emit_printf(self, args, unsigned_flags=None, sep=" ", end="\n"): - if not args: - return None - if unsigned_flags is None: - unsigned_flags = [] - format_str = "" - cast_args = [] - for i, arg in enumerate(args): - is_u = i < len(unsigned_flags) and unsigned_flags[i] - if isinstance(arg.type, ir.IntType): - if arg.type.width == 8: - format_str += "%c" - ext = self.builder.zext(arg, ir.IntType(32), name="char2int") - cast_args.append(ext) - elif arg.type.width == 64: - format_str += "%llu" if is_u else "%lld" - cast_args.append(arg) - else: - format_str += "%u" if is_u else "%d" - cast_args.append(arg) - elif isinstance(arg.type, (ir.FloatType, ir.DoubleType)): - format_str += "%f" - cast_args.append(arg) - elif isinstance(arg.type, ir.PointerType): - if isinstance(arg.type.pointee, ir.IntType) and arg.type.pointee.width == 8: - format_str += "%s" - cast_args.append(arg) - else: - format_str += "%d" - int_val = self.builder.ptrtoint(arg, ir.IntType(64), name="ptr2int") - trunc_val = self.builder.trunc(int_val, ir.IntType(32), name="trunc") - cast_args.append(trunc_val) - else: - format_str += "%d" - cast_args.append(arg) - if sep is not None and i < len(args) - 1: - format_str += sep - if end is not None: - format_str += end - string_type = ir.ArrayType(ir.IntType(8), len(format_str.encode('utf-8')) + 1) - string_const = ir.Constant(string_type, bytearray(format_str + '\x00', 'utf-8')) - global_var = ir.GlobalVariable(self.module, string_type, name=f"str_const_{self.string_const_counter}") - self.string_const_counter += 1 - global_var.initializer = string_const - global_var.linkage = 'internal' - format_ptr = self.builder.bitcast(global_var, ir.PointerType(ir.IntType(8))) - call_args = [format_ptr] + cast_args - printf_func = self.get_or_declare_c_func('printf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True)) - return self.builder.call(printf_func, call_args, name="call_printf") - - def _get_or_declare_func(self, name, func_type): - import re - for fname, fobj in self.functions.items(): - if fname == name: - return fobj - if re.match(r'^[0-9a-f]{16,}\.' + re.escape(name) + r'$', fname): - return fobj - func_decl = ir.Function(self.module, func_type, name=name) - self.functions[name] = func_decl - return func_decl - - def get_or_declare_c_func(self, name, fallback_type=None): - if name in self.functions: - return self.functions[name] - import re - for fname, fobj in self.functions.items(): - if re.match(r'^[0-9a-f]{16,}\.' + re.escape(name) + r'$', fname): - return fobj - stub_func_type = None - if hasattr(self, '_import_handler_ref') and self._import_handler_ref: - try: - stub_func_type = self._import_handler_ref._LookupStubFuncType(name, self) - except Exception: - pass - if stub_func_type: - func_decl = ir.Function(self.module, stub_func_type, name=name) - self.functions[name] = func_decl - return func_decl - if fallback_type is not None: - func_decl = ir.Function(self.module, fallback_type, name=name) - self.functions[name] = func_decl - return func_decl - return None - - def emit_sizeof(self, type_name): - for class_name, struct_type in self.structs.items(): - if type_name == class_name: - size = self._get_struct_size(struct_type) - if size > 0: - return ir.Constant(ir.IntType(64), size) - return ir.Constant(ir.IntType(64), 4) +# 向后兼容:重新导出常量和辅助类 +__all__ = ['LlvmCodeGenerator', 'VaArgInstruction'] diff --git a/lib/core/SymbolNode.py b/lib/core/SymbolNode.py index 1042448..d32e497 100644 --- a/lib/core/SymbolNode.py +++ b/lib/core/SymbolNode.py @@ -1,207 +1,207 @@ -from __future__ import annotations -from typing import Any, Dict, Optional, TYPE_CHECKING -if TYPE_CHECKING: - from lib.core.Handles.HandlesBase import CTypeInfo - -from lib.includes import t - - -class SymbolNode: - """符号表节点,类似 AST 节点的树形结构 - - attributes 存储 CTypeInfo 对象,不再使用 TypeInfo - """ - - def __init__(self, name: str, NodeType: str, lineno: int = 0, file: str = '', parent: SymbolNode | None = None): - from lib.core.Handles.HandlesBase import CTypeInfo - self.name: str = name - self.type: str = NodeType - self.lineno: int = lineno - self.file: str = file - self.parent: SymbolNode | None = parent - self.children: Dict[str, SymbolNode] = {} - self.attributes: CTypeInfo = CTypeInfo() - self.attributes.Name = name - self.attributes.Lineno = lineno - - def get(self, key: str, default: Any = None) -> Any: - """获取属性值""" - if hasattr(self.attributes, key): - return getattr(self.attributes, key) - return self.attributes._extra.get(key, default) - - def set(self, key: str, value: Any): - """设置属性值""" - if hasattr(self.attributes, key): - attr = getattr(type(self.attributes), key, None) - if isinstance(attr, property) and attr.fset is None: - return - setattr(self.attributes, key, value) - else: - self.attributes._extra[key] = value - - def HasChild(self, name: str) -> bool: - """检查是否有子节点""" - return name in self.children - - def GetChild(self, name: str) -> Optional[SymbolNode]: - """获取子节点""" - return self.children.get(name) - - def AddChild(self, node: SymbolNode): - """添加子节点""" - node.parent = self - self.children[node.name] = node - - def RemoveChild(self, name: str) -> bool: - """删除子节点""" - if name in self.children: - del self.children[name] - return True - return False - - def find(self, path: str, separator: str = '.') -> Optional[SymbolNode]: - """根据路径查找节点,如 'test.ClassA'""" - parts = path.split(separator) - current = self - - for part in parts: - if current.HasChild(part): - current = current.GetChild(part) - else: - return None - - return current - - def ToDict(self) -> Dict[str, Any]: - """转换为字典格式""" - result = { - 'type': self.type, - 'lineno': self.lineno, - 'file': self.file, - **self.attributes.entry - } - - if self.children: - result['children'] = {name: child.ToDict() for name, child in self.children.items()} - - return result - - @classmethod - def FromDict(cls, name: str, data: Dict[str, Any]) -> SymbolNode: - """从字典创建节点(兼容性)""" - node = cls(name=name, NodeType=data.get('type', 'unknown')) - node.lineno = data.get('lineno', 0) - node.file = data.get('file', '') - - for key, value in data.items(): - if key not in ('type', 'lineno', 'file', 'children'): - node.set(key, value) - - if 'children' in data: - for ChildName, ChildData in data['children'].items(): - node.AddChild(cls.FromDict(ChildName, ChildData)) - - return node - - @classmethod - def CreateMember(cls, name: str, TypeName: str | None = None, TypeInfo: 'CTypeInfo | None' = None, IsPtr: bool = False, dims: list[int] | None = None, lineno: int = 0, file: str = '') -> SymbolNode: - """创建成员节点(工厂函数)""" - from lib.core.Handles.HandlesBase import CTypeInfo - node = cls(name=name, NodeType='member', lineno=lineno, file=file) - node.attributes = CTypeInfo() - node.attributes.Name = name - node.attributes.Lineno = lineno - if TypeInfo is not None: - node.attributes = TypeInfo - node.attributes.Name = name - node.attributes.Lineno = lineno - else: - if TypeName is not None: - node.attributes.BaseType = CTypeInfo.CreateFromTypeName(TypeName) - if IsPtr: - node.attributes.PtrCount = 1 - if dims: - node.attributes.ArrayDims = list(dims) - return node - - @classmethod - def CreateClass(cls, name: str, TypeKind: type, members: dict | None = None, lineno: int = 0, file: str = '', IsCpythonObject: bool = False, IsPacked: bool = False) -> SymbolNode: - """创建类节点(工厂函数)""" - from lib.core.Handles.HandlesBase import CTypeInfo - node = cls(name=name, NodeType=TypeKind, lineno=lineno, file=file) - node.attributes = CTypeInfo() - node.attributes.Name = name - node.attributes.Lineno = lineno - node.attributes.IsCpythonObject = IsCpythonObject - node.attributes.IsPacked = IsPacked - if members: - for MemberName, MemberInfo in members.items(): - if isinstance(MemberInfo, CTypeInfo): - node.attributes.Members[MemberName] = MemberInfo - elif isinstance(MemberInfo, dict): - CTypeMember = CTypeInfo() - type_str = MemberInfo.get('type', 'int') - is_ptr = MemberInfo.get('IsPtr', False) - if isinstance(type_str, str): - try: - resolved = CTypeInfo.FromTypeName(type_str) - if resolved and resolved.BaseType: - CTypeMember = resolved - else: - CTypeMember.BaseType = t.CInt() - except Exception: - CTypeMember.BaseType = t.CInt() - else: - CTypeMember.BaseType = t.CInt() - if is_ptr and not CTypeMember.IsPtr: - CTypeMember.PtrCount = max(CTypeMember.PtrCount, 1) - node.attributes.Members[MemberName] = CTypeMember - if TypeKind == 'struct': - node.attributes.IsStruct = True - elif TypeKind == 'enum': - node.attributes.IsEnum = True - elif TypeKind == 'union': - node.attributes.IsUnion = True - elif TypeKind == 'typedef': - node.attributes.IsTypedef = True - elif TypeKind == 'exception': - node.attributes.IsExceptionClass = True - return node - - @classmethod - def CreateTypedef(cls, name: str, OriginalType, members: dict | None = None, lineno: int = 0, file: str = '') -> SymbolNode: - from lib.core.Handles.HandlesBase import CTypeInfo - node = cls(name=name, NodeType='typedef', lineno=lineno, file=file) - node.attributes = CTypeInfo() - node.attributes.Name = name - node.attributes.Lineno = lineno - node.attributes.IsTypedef = True - if isinstance(OriginalType, CTypeInfo): - node.attributes.OriginalType = OriginalType - elif isinstance(OriginalType, str): - node.attributes.OriginalType = CTypeInfo.FromTypeName(OriginalType) if OriginalType else None - else: - node.attributes.OriginalType = OriginalType - return node - - @classmethod - def CreateAnonymous(cls, name: str, IsUnion: bool, members: dict, lineno: int = 0, file: str = '') -> SymbolNode: - """创建匿名类型节点(工厂函数)""" - from lib.core.Handles.HandlesBase import CTypeInfo - NodeType = t.CUnion if IsUnion else t.CStruct - node = cls(name=name, NodeType=NodeType, lineno=lineno, file=file) - node.attributes = CTypeInfo() - node.attributes.Name = name - node.attributes.Lineno = lineno - node.attributes.IsAnonymous = True - if IsUnion: - node.attributes.IsUnion = True - else: - node.attributes.IsStruct = True - return node - - @classmethod - def CreateModule(cls, name: str, lineno: int = 0, file: str = '') -> SymbolNode: - """创建模块节点(工厂函数)""" - return cls(name=name, NodeType='module', lineno=lineno, file=file) +from __future__ import annotations +from typing import Any, Dict, Optional, TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.Handles.HandlesBase import CTypeInfo + +from lib.includes import t + + +class SymbolNode: + """符号表节点,类似 AST 节点的树形结构 + + attributes 存储 CTypeInfo 对象,不再使用 TypeInfo + """ + + def __init__(self, name: str, NodeType: str, lineno: int = 0, file: str = '', parent: SymbolNode | None = None): + from lib.core.Handles.HandlesBase import CTypeInfo + self.name: str = name + self.type: str = NodeType + self.lineno: int = lineno + self.file: str = file + self.parent: SymbolNode | None = parent + self.children: Dict[str, SymbolNode] = {} + self.attributes: CTypeInfo = CTypeInfo() + self.attributes.Name = name + self.attributes.Lineno = lineno + + def get(self, key: str, default: Any = None) -> Any: + """获取属性值""" + if hasattr(self.attributes, key): + return getattr(self.attributes, key) + return self.attributes._extra.get(key, default) + + def set(self, key: str, value: Any): + """设置属性值""" + if hasattr(self.attributes, key): + attr = getattr(type(self.attributes), key, None) + if isinstance(attr, property) and attr.fset is None: + return + setattr(self.attributes, key, value) + else: + self.attributes._extra[key] = value + + def HasChild(self, name: str) -> bool: + """检查是否有子节点""" + return name in self.children + + def GetChild(self, name: str) -> Optional[SymbolNode]: + """获取子节点""" + return self.children.get(name) + + def AddChild(self, node: SymbolNode): + """添加子节点""" + node.parent = self + self.children[node.name] = node + + def RemoveChild(self, name: str) -> bool: + """删除子节点""" + if name in self.children: + del self.children[name] + return True + return False + + def find(self, path: str, separator: str = '.') -> Optional[SymbolNode]: + """根据路径查找节点,如 'test.ClassA'""" + parts = path.split(separator) + current = self + + for part in parts: + if current.HasChild(part): + current = current.GetChild(part) + else: + return None + + return current + + def ToDict(self) -> Dict[str, Any]: + """转换为字典格式""" + result = { + 'type': self.type, + 'lineno': self.lineno, + 'file': self.file, + **self.attributes.entry + } + + if self.children: + result['children'] = {name: child.ToDict() for name, child in self.children.items()} + + return result + + @classmethod + def FromDict(cls, name: str, data: Dict[str, Any]) -> SymbolNode: + """从字典创建节点(兼容性)""" + node = cls(name=name, NodeType=data.get('type', 'unknown')) + node.lineno = data.get('lineno', 0) + node.file = data.get('file', '') + + for key, value in data.items(): + if key not in ('type', 'lineno', 'file', 'children'): + node.set(key, value) + + if 'children' in data: + for ChildName, ChildData in data['children'].items(): + node.AddChild(cls.FromDict(ChildName, ChildData)) + + return node + + @classmethod + def CreateMember(cls, name: str, TypeName: str | None = None, TypeInfo: 'CTypeInfo | None' = None, IsPtr: bool = False, dims: list[int] | None = None, lineno: int = 0, file: str = '') -> SymbolNode: + """创建成员节点(工厂函数)""" + from lib.core.Handles.HandlesBase import CTypeInfo + node = cls(name=name, NodeType='member', lineno=lineno, file=file) + node.attributes = CTypeInfo() + node.attributes.Name = name + node.attributes.Lineno = lineno + if TypeInfo is not None: + node.attributes = TypeInfo + node.attributes.Name = name + node.attributes.Lineno = lineno + else: + if TypeName is not None: + node.attributes.BaseType = CTypeInfo.create_FromTypeName(TypeName) + if IsPtr: + node.attributes.PtrCount = 1 + if dims: + node.attributes.ArrayDims = list(dims) + return node + + @classmethod + def CreateClass(cls, name: str, TypeKind: type, members: dict | None = None, lineno: int = 0, file: str = '', IsCpythonObject: bool = False, IsPacked: bool = False) -> SymbolNode: + """创建类节点(工厂函数)""" + from lib.core.Handles.HandlesBase import CTypeInfo + node = cls(name=name, NodeType=TypeKind, lineno=lineno, file=file) + node.attributes = CTypeInfo() + node.attributes.Name = name + node.attributes.Lineno = lineno + node.attributes.IsCpythonObject = IsCpythonObject + node.attributes.IsPacked = IsPacked + if members: + for MemberName, MemberInfo in members.items(): + if isinstance(MemberInfo, CTypeInfo): + node.attributes.Members[MemberName] = MemberInfo + elif isinstance(MemberInfo, dict): + CTypeMember = CTypeInfo() + type_str = MemberInfo.get('type', 'int') + IsPtr = MemberInfo.get('IsPtr', False) + if isinstance(type_str, str): + try: + resolved = CTypeInfo.FromTypeName(type_str) + if resolved and resolved.BaseType: + CTypeMember = resolved + else: + CTypeMember.BaseType = t.CInt() + except Exception: + CTypeMember.BaseType = t.CInt() + else: + CTypeMember.BaseType = t.CInt() + if IsPtr and not CTypeMember.IsPtr: + CTypeMember.PtrCount = max(CTypeMember.PtrCount, 1) + node.attributes.Members[MemberName] = CTypeMember + if TypeKind == 'struct': + node.attributes.is_struct = True + elif TypeKind == 'enum': + node.attributes.IsEnum = True + elif TypeKind == 'union': + node.attributes.IsUnion = True + elif TypeKind == 'typedef': + node.attributes.IsTypedef = True + elif TypeKind == 'exception': + node.attributes.IsExceptionClass = True + return node + + @classmethod + def CreateTypedef(cls, name: str, OriginalType, members: dict | None = None, lineno: int = 0, file: str = '') -> SymbolNode: + from lib.core.Handles.HandlesBase import CTypeInfo + node = cls(name=name, NodeType='typedef', lineno=lineno, file=file) + node.attributes = CTypeInfo() + node.attributes.Name = name + node.attributes.Lineno = lineno + node.attributes.IsTypedef = True + if isinstance(OriginalType, CTypeInfo): + node.attributes.OriginalType = OriginalType + elif isinstance(OriginalType, str): + node.attributes.OriginalType = CTypeInfo.FromTypeName(OriginalType) if OriginalType else None + else: + node.attributes.OriginalType = OriginalType + return node + + @classmethod + def CreateAnonymous(cls, name: str, IsUnion: bool, members: dict, lineno: int = 0, file: str = '') -> SymbolNode: + """创建匿名类型节点(工厂函数)""" + from lib.core.Handles.HandlesBase import CTypeInfo + NodeType = t.CUnion if IsUnion else t.CStruct + node = cls(name=name, NodeType=NodeType, lineno=lineno, file=file) + node.attributes = CTypeInfo() + node.attributes.Name = name + node.attributes.Lineno = lineno + node.attributes.IsAnonymous = True + if IsUnion: + node.attributes.IsUnion = True + else: + node.attributes.is_struct = True + return node + + @classmethod + def CreateModule(cls, name: str, lineno: int = 0, file: str = '') -> SymbolNode: + """创建模块节点(工厂函数)""" + return cls(name=name, NodeType='module', lineno=lineno, file=file) diff --git a/lib/core/SymbolTable.py b/lib/core/SymbolTable.py index f669362..8358bf3 100644 --- a/lib/core/SymbolTable.py +++ b/lib/core/SymbolTable.py @@ -364,12 +364,12 @@ class SymbolTable: OriginalType_kind = 'struct' if OriginalClass in self: OrigTypeInfo = self[OriginalClass] - if OrigTypeInfo.TypeCls in (t.CStruct, t.CEnum, t.CUnion): - if OrigTypeInfo.TypeCls is t.CStruct: + if OrigTypeInfo.type_cls in (t.CStruct, t.CEnum, t.CUnion): + if OrigTypeInfo.type_cls is t.CStruct: OriginalType_kind = 'struct' - elif OrigTypeInfo.TypeCls is t.CEnum: + elif OrigTypeInfo.type_cls is t.CEnum: OriginalType_kind = 'enum' - elif OrigTypeInfo.TypeCls is t.CUnion: + elif OrigTypeInfo.type_cls is t.CUnion: OriginalType_kind = 'union' if prefix == prefixes[0]: @@ -510,7 +510,7 @@ class SymbolTable: except Exception as e: import traceback print(traceback.format_exc()) - print(f"[SymbolTable Error] Failed to load module: {FilePath} - {e}") + print(f"[SymbolTable Error] Failed to Load module: {FilePath} - {e}") return [] def _GetLLVMTypeStr(self, node): diff --git a/lib/core/Translator/AnnotationLoader.py b/lib/core/Translator/AnnotationLoader.py new file mode 100644 index 0000000..91dec3d --- /dev/null +++ b/lib/core/Translator/AnnotationLoader.py @@ -0,0 +1,401 @@ +from __future__ import annotations + +import ast +import sys +import os + +from lib.core.SymbolNode import SymbolNode +from lib.core.Handles.HandlesBase import CTypeInfo +from lib.includes import t + + +class AnnotationLoaderMixin: + """注解模块加载 Mixin + + 提供注解模块/文件的加载与符号表注册能力。 + """ + + def _LoadAnnotationModule(self, ModuleName: str, library_name: str = None, parse_method: str = 'auto'): + """加载注解模块并将 CType 子类注册为 typedef + + 支持两种模式: + 1. AST 模式:如果 ModuleName 是文件路径,解析文件提取 CType + 2. importlib 模式:如果 ModuleName 是模块名,导入模块提取 CType + + Args: + ModuleName: 模块名或文件路径 + library_name: 手动指定的库名称,用于注册到符号表。如果为 None,则从 ModuleName 推断 + parse_method: 解析方法,可选值: + - 'auto': 自动检测(默认) + - 'file': 强制使用 AST 模式(文件路径) + - 'module': 强制使用 importlib 模式(模块名) + """ + import importlib + import sys + import os + + CurrentDir = os.path.dirname(os.path.abspath(__file__)) + ProjectRoot = os.path.dirname(os.path.dirname(os.path.dirname(CurrentDir))) + if ProjectRoot not in sys.path: + sys.path.insert(0, ProjectRoot) + + def register_to_symboltable(module, lib_name: str = None, source_file: str = None): + """将模块中的 CType 子类和 CEnum 类注册到符号表""" + from lib.includes.t import CType, CEnum + count = 0 + for AttrName in dir(module): + attr = getattr(module, AttrName) + # 优先检查是否是 CEnum 子类(枚举) + if isinstance(attr, type) and issubclass(attr, CEnum) and attr is not CEnum: + # 注册枚举类型 + EnumNode = SymbolNode.CreateClass( + name=AttrName, + TypeKind='enum', + lineno=0 + ) + EnumNode.set('enum_class', attr) + EnumNode.set('source', 'annotation_module') + EnumNode.set('library_name', lib_name) + EnumNode.set('file', source_file) + self.SymbolTable[AttrName] = EnumNode.attributes + if lib_name: + FullName = f'{lib_name}.{AttrName}' + full_EnumNode = SymbolNode.CreateClass( + name=FullName, + TypeKind='enum', + lineno=0 + ) + full_EnumNode.set('enum_class', attr) + full_EnumNode.set('source', 'annotation_module') + full_EnumNode.set('library_name', lib_name) + full_EnumNode.set('file', source_file) + self.SymbolTable[FullName] = full_EnumNode.attributes + # 枚举成员也需要注册 + for MemberName in dir(attr): + if not MemberName.startswith('_'): + member = getattr(attr, MemberName, None) + if isinstance(member, int): + MemberNode = CTypeInfo() + MemberNode.Name = MemberName + MemberNode.BaseType = t.CEnum(AttrName) + MemberNode.value = member + MemberNode.EnumName = AttrName + MemberNode.library_name = lib_name + MemberNode.IsEnumMember = True + self.SymbolTable[MemberName] = MemberNode + self.SymbolTable[f"{AttrName}.{MemberName}"] = MemberNode + self.SymbolTable[f"{AttrName}_{MemberName}"] = MemberNode + if lib_name: + self.SymbolTable[f"{lib_name}.{AttrName}.{MemberName}"] = MemberNode + self.SymbolTable[f"{lib_name}_{AttrName}_{MemberName}"] = MemberNode + count += 1 + # 检查是否是 CType 子类(typedef 别名) + elif isinstance(attr, type) and issubclass(attr, CType) and attr is not CType: + # 继承 CType 的类是类型别名(typedef),不是结构体 + # 使用手动指定的库名称作为前缀 + if lib_name: + FullName = f'{lib_name}.{AttrName}' + else: + FullName = AttrName + # 同时注册带前缀和不带前缀的名称(都是 typedef 别名) + TypedefNode = SymbolNode.CreateClass( + name=AttrName, + TypeKind='typedef', + lineno=0 + ) + TypedefNode.set('OriginalType', attr().CName) + TypedefNode.set('source', 'annotation_module') + TypedefNode.set('library_name', lib_name) + TypedefNode.set('file', source_file) + self.SymbolTable[AttrName] = TypedefNode.attributes + if lib_name and FullName != AttrName: + FullTypedef_node = SymbolNode.CreateClass( + name=FullName, + TypeKind='typedef', + lineno=0 + ) + FullTypedef_node.set('OriginalType', attr().CName) + FullTypedef_node.set('source', 'annotation_module') + FullTypedef_node.set('library_name', lib_name) + FullTypedef_node.set('file', source_file) + self.SymbolTable[FullName] = FullTypedef_node.attributes + count += 1 + # 检查是否是下划线前缀的 CType 子类(如 _CTypedef -> CTypedef) + elif AttrName.startswith('_') and len(AttrName) > 1: + PublicName = AttrName[1:] + PublicAttr = getattr(module, PublicName, None) + if PublicAttr is not None and not isinstance(attr, type): + continue + if isinstance(attr, type) and issubclass(attr, CType) and attr is not CType: + if PublicName not in self.SymbolTable: + if lib_name: + FullName = f'{lib_name}.{PublicName}' + else: + FullName = PublicName + TypedefNode = SymbolNode.CreateClass( + name=PublicName, + TypeKind='typedef', + lineno=0 + ) + TypedefNode.set('OriginalType', attr().CName) + TypedefNode.set('source', 'annotation_module') + TypedefNode.set('library_name', lib_name) + TypedefNode.set('file', source_file) + self.SymbolTable[PublicName] = TypedefNode.attributes + if lib_name and FullName != PublicName: + FullTypedef_node = SymbolNode.CreateClass( + name=FullName, + TypeKind='typedef', + lineno=0 + ) + FullTypedef_node.set('OriginalType', attr().CName) + FullTypedef_node.set('source', 'annotation_module') + FullTypedef_node.set('library_name', lib_name) + FullTypedef_node.set('file', source_file) + self.SymbolTable[FullName] = FullTypedef_node.attributes + count += 1 + return count + + # 确定解析方法 + use_file_mode = False + if parse_method == 'file': + use_file_mode = True + elif parse_method == 'module': + use_file_mode = False + else: # auto + use_file_mode = os.path.isfile(ModuleName) + + # 确定库名称 + lib_name = library_name + if lib_name is None: + if use_file_mode: + # 从文件路径推断库名称 + lib_name = os.path.splitext(os.path.basename(ModuleName))[0] + else: + # 模块名就是库名称 + lib_name = ModuleName + + # 根据解析方法加载模块 + if use_file_mode: + # AST 模式:使用 AST 解析文件,不执行代码 + try: + # 临时保存当前的 EmbeddedAssignments 和 TypedefAssignments + saved_embedded = self.EmbeddedAssignments.copy() + saved_typedef = self.TypedefAssignments.copy() + + # 清空 PD 收集(注解文件不应该收集 PD 语句) + self.EmbeddedAssignments = {} + self.TypedefAssignments = {} + + # 直接调用 ParsePythonFile 解析文件提取类型信息 + # 注意:这不会执行任何 Python 代码,只是解析 AST + # UpdateCurrentFile=False 表示不修改 CurrentFile + self.ParsePythonFile(ModuleName, UpdateCurrentFile=False) + + # 恢复主代码文件的 PD 收集 + self.EmbeddedAssignments = saved_embedded + self.TypedefAssignments = saved_typedef + + # 从文件名推断类型前缀(如 test_t -> test_t.xxx) + TypePrefix = lib_name + count = 0 + + # 检查符号表中新增的类型(注解文件解析后的所有 struct 类型) + # 需要检查这些类型是否继承自 CType,如果是则是 typedef 别名 + new_types = [] + for TypeName, TypeInfo in self.SymbolTable.items(): + if TypeInfo.IsStruct: + new_types.append(TypeName) + + # 再次遍历 AST,检测继承自 CType 的类 + try: + with open(ModuleName, 'r', encoding='utf-8') as f: + ann_content = f.read() + ann_tree = ast.parse(ann_content) + for node in ann_tree.body: + if isinstance(node, ast.ClassDef): + ClassName = node.name + # 检查是否有基类 + for base in node.bases: + if isinstance(base, ast.Name) and base.id == 'CType': + # 这个类继承自 CType,是 typedef 别名 + # 更新符号表中的类型为 typedef + if ClassName in self.SymbolTable: + TypedefNode = SymbolNode.CreateClass( + name=ClassName, + TypeKind='typedef', + lineno=0 + ) + TypedefNode.set('OriginalType', self.SymbolTable[ClassName].get('OriginalType', f'struct {ClassName}')) + TypedefNode.set('source', 'annotation_module') + TypedefNode.set('is_ctype_subclass', True) + self.SymbolTable[ClassName] = TypedefNode.attributes + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _ConfigMode + if _ConfigMode == "strict": + raise + _vlog().warning(f"解析注解文件类型定义失败: {_e}", "Exception") + + # 为所有新增的类型添加库前缀和 source 标记 + for TypeName in new_types: + # 添加带前缀的类型名 + FullName = f'{TypePrefix}.{TypeName}' + TypeInfo = self.SymbolTable[TypeName].copy() + TypeInfo['source'] = 'annotation_module' + TypeInfo['original_name'] = TypeName + self.SymbolTable[FullName] = TypeInfo + count += 1 + + # 再次遍历 AST,查找注解文件中的 typedef 语句(AnnAssign with t.CTypedef) + # 注意:必须在类定义处理完之后再处理 typedef + typedef_annots = [] + # 查找 CEnum 成员变量(AnnAssign with t.CEnum | t.State 或 t.CEnum) + cEnumMembers = [] + try: + with open(ModuleName, 'r', encoding='utf-8') as f: + ann_content = f.read() + ann_tree = ast.parse(ann_content) + for node in ann_tree.body: + # 检测 xxx: t.CEnum 形式的枚举成员变量 + if isinstance(node, ast.AnnAssign): + if isinstance(node.target, ast.Name) and node.annotation: + TargetName = node.target.id + # 检查注解是否是 BinOp (Union) 或直接是 Attribute + IsCenum = False + if isinstance(node.annotation, ast.BinOp): + # 检查是否包含 CEnum + annot_str = ast.dump(node.annotation) + if 'CEnum' in annot_str: + IsCenum = True + elif isinstance(node.annotation, ast.Attribute): + # 直接是 t.CEnum + if node.annotation.attr == t.CEnum.__name__: + IsCenum = True + + if IsCenum: + # 检查值是否是 Constant (枚举成员值) + if node.value and isinstance(node.value, ast.Constant): + value = node.value.value + else: + value = None + cEnumMembers.append((TargetName, value)) + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _ConfigMode + if _ConfigMode == "strict": + raise + _vlog().warning(f"解析 CEnum 成员变量失败: {_e}", "Exception") + + # 处理 CEnum 成员变量 + for TargetName, value in cEnumMembers: + # 注册枚举成员 + MemberNode = CTypeInfo() + MemberNode.Name = TargetName + MemberNode.BaseType = t.CEnum(TypePrefix) + MemberNode.value = value + MemberNode.EnumName = TypePrefix + MemberNode.library_name = TypePrefix + MemberNode.IsEnumMember = True + self.SymbolTable[TargetName] = MemberNode + self.SymbolTable[f"{TypePrefix}.{TargetName}"] = MemberNode + self.SymbolTable[f"{TypePrefix}_{TargetName}"] = MemberNode + + try: + with open(ModuleName, 'r', encoding='utf-8') as f: + ann_content = f.read() + ann_tree = ast.parse(ann_content) + for node in ann_tree.body: + # 检测 xxx: t.CTypedef = xxx 形式的 typedef 语句 + if isinstance(node, ast.AnnAssign): + if isinstance(node.target, ast.Name) and node.annotation and node.value: + TargetName = node.target.id + # 检查注解是否是 t.CTypedef + if isinstance(node.annotation, ast.Attribute): + if isinstance(node.annotation.value, ast.Name): + if node.annotation.value.id == 't' and node.annotation.attr == 'CTypedef': + # 检查值是否是 Name + if isinstance(node.value, ast.Name): + original_name = node.value.id + typedef_annots.append((TargetName, original_name)) + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _ConfigMode + if _ConfigMode == "strict": + raise + _vlog().warning(f"解析 typedef 语句失败: {_e}", "Exception") + + # 处理 typedef 注解 + for TargetName, original_name in typedef_annots: + # 检查原始类型是否在符号表中(带前缀或不带前缀) + orig_with_prefix = f'{TypePrefix}.{original_name}' + if orig_with_prefix in self.SymbolTable: + # 添加带前缀的 typedef 别名 + FullTypedef_name = f'{TypePrefix}.{TargetName}' + TypedefNode = SymbolNode.CreateClass( + name=FullTypedef_name, + TypeKind='typedef', + lineno=0 + ) + orig_entry = self.SymbolTable.get(orig_with_prefix, {}) + orig_type_str = f'struct {original_name}' + if isinstance(orig_entry, dict): + if orig_entry.get('type') == 'typedef': + orig_type_str = orig_entry.get('OriginalType', f'struct {original_name}') + elif orig_entry.get('type') == 'enum': + orig_type_str = f'enum {original_name}' + elif hasattr(orig_entry, 'IsTypedef') and orig_entry.IsTypedef: + orig_type_str = getattr(orig_entry, 'OriginalType', f'struct {original_name}') + elif hasattr(orig_entry, 'IsEnum') and orig_entry.IsEnum: + orig_type_str = f'enum {original_name}' + TypedefNode.set('OriginalType', orig_type_str) + TypedefNode.set('source', 'annotation_module') + TypedefNode.set('original_name', TargetName) + self.SymbolTable[FullTypedef_name] = TypedefNode.attributes + count += 1 + + self.AnnotationModules.add(lib_name) + return count + except Exception as e: + # 恢复 PD 收集 + self.EmbeddedAssignments = saved_embedded + self.TypedefAssignments = saved_typedef + self.LogWarning(f"AST模式加载注解模块失败: {ModuleName}, 错误: {e}") + return 0 + else: + # importlib 模式:导入模块 + try: + module = importlib.import_module(ModuleName) + count = register_to_symboltable(module, lib_name, None) + self.AnnotationModules.add(lib_name) + return count + except ImportError: + self.LogWarning(f"importlib模式加载注解模块失败: {ModuleName}") + return 0 + except Exception as e: + self.LogWarning(f"加载注解模块失败: {ModuleName}, 错误: {e}") + return 0 + + def _LoadAnnotationFiles(self, FilePaths: list): + """加载多个注解文件并注册到符号表 + + Args: + FilePaths: 文件路径列表,每个元素可以是: + - str: 文件路径或模块名 + - tuple: (path, options) 或 (path, library_name, parse_method) + """ + for item in FilePaths: + if isinstance(item, tuple): + if len(item) >= 3: + path, library_name, parse_method = item[:3] + count = self._loadAnnotationModule(path, library_name, parse_method) + elif len(item) == 2: + path, library_name = item + count = self._loadAnnotationModule(path, library_name, 'auto') + else: + count = self._loadAnnotationModule(item) + else: + count = self._loadAnnotationModule(item) + + # 别名,保持向后兼容 + LoadAnnotationFiles = _LoadAnnotationFiles diff --git a/lib/core/Translator/BaseTranslator.py b/lib/core/Translator/BaseTranslator.py new file mode 100644 index 0000000..8d38afa --- /dev/null +++ b/lib/core/Translator/BaseTranslator.py @@ -0,0 +1,154 @@ +from __future__ import annotations + +from typing import Dict +import sys +import os + +from lib.core.Exportable import Exportable + +sys.path.append(os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__)))), 'lib', 'includes')) +from lib.includes import c +from lib.includes import t +from lib.utils.helpers import DetectFileType +from lib.core.Handles import ( + IfHandle, ForHandle, WhileHandle, + AnnAssignHandle, + HandlesTypeMerge, ExprHandle, BodyHandle, + ReturnHandle, AssignHandle, AugAssignHandle, DeleteHandle, + WithHandle, TryHandle, AssertHandle, RaiseHandle, MatchHandle, + ExprUtils, ExprOpsHandle, ExprAttrHandle, ExprBuiltinHandle, + ExprAsmHandle, ExprFormatHandle, ExprLambdaHandle, ExprCallHandle, + CSpecialCallHandle, TSpecialCallHandle, + ClassHandle, + FunctionHandle, + ImportHandle +) +from lib.core.Handles.HandlesBase import CTypeInfo +from lib.core.SymbolTable import SymbolTable +from lib.core.SymbolNode import SymbolNode +from lib.constants.config import mode as _ConfigMode +from lib.core.LlvmCodeGenerator import LlvmCodeGenerator + + +def _StrictLog(logger, msg): + """在 strict 模式下记录异常日志""" + if _ConfigMode == "strict": + logger(msg) + + +class BaseTranslatorMixin: + """代码转换器基础 Mixin + + 提供 __init__、日志、调试输出与表达式处理等基础能力。 + """ + + def __init__(self): + self.VarScopes: list[Dict[str, SymbolNode]] = [{}] # 跟踪变量作用域,第一个是全局作用域 + self.FunctionReturnTypes: Dict[str, CTypeInfo] = {} # 记录函数名和其返回类型 + self.CurrentCReturnTypes: list[CTypeInfo] = None # 当前函数的 CReturn 类型列表 + self._CurrentCpythonObjectClass: str = None # 当前正在处理的 CPython 对象类名 + self.FunctionDefCache: dict = {} # 函数定义缓存 + self.OriginalLines: list[str] = [] # 原始代码行 + self.Content: str = '' + self.DebugFile: str | None = None # 调试输出文件路径 + self.IsHeader: bool = False # 是否生成头文件(仅处理定义、宏、导入等,忽略函数体) + self.AnnotationModules: set[str] = set() # 注解模块集合,用于识别类型定义模块 + self.Warnings: list[str] = [] # 警告日志 + self._ErrorStack = [] # 错误栈,按顺序收集错误位置 + self.Errors = [] # 错误日志 + self.SliceCount = 0 # 切片计数 + self.SliceInfos = [] # 切片信息列表 + self.SliceLevel = 3 # 切片优化级别 + self.GeneratedTypes = set() # 在当前代码中生成的类型(struct/typedef) + self.EmbeddedAssignments = {} # {ClassName: [var1, var2, ...]} 嵌入的实例化变量 + self.TypedefAssignments = {} # {ClassName: [(var1, IsPtr), ...]} 嵌入的 typedef/指针变量 + self.ChainAssignmentArrays = [] # 链式赋值数组形式 [(ClassName, VarName, ArraySize_node), ...] + self.tree = None # 保存解析后的 AST 树 + self.LibraryPaths = ['.'] # 库搜索路径列表,默认包含当前目录 + self.InClass = False # 是否正在处理 class 定义 + self._UserTypeModules = {} + self._source_module_sig_files = {} + self._global_function_default_args: dict = {} + self.exception_registry: dict = {} + self.exception_parents: dict = {} + self._next_exception_code: int = 100 + + # 导出表 + self.Exportable = Exportable(filename='') + + self.SymbolTable = SymbolTable(self) + self.IfHandler = IfHandle(self) + self.ForHandler = ForHandle(self) + self.WhileHandler = WhileHandle(self) + self.AnnAssignHandler = AnnAssignHandle(self) + self.TypeMergeHandler = HandlesTypeMerge(self) + self.ExprHandler = ExprHandle(self) + self.ExprUtils = ExprUtils(self) + self.ExprOpsHandle = ExprOpsHandle(self) + self.ExprAttrHandle = ExprAttrHandle(self) + self.ExprBuiltinHandle = ExprBuiltinHandle(self) + self.ExprAsmHandle = ExprAsmHandle(self) + self.ExprFormatHandle = ExprFormatHandle(self) + self.ExprLambdaHandle = ExprLambdaHandle(self) + self.ExprCallHandle = ExprCallHandle(self) + self.CSpecialCallHandle = CSpecialCallHandle(self) + self.TSpecialCallHandle = TSpecialCallHandle(self) + self.ClassHandler = ClassHandle(self) + self.FunctionHandler = FunctionHandle(self) + self.ImportHandler = ImportHandle(self) + self.BodyHandler = BodyHandle(self) + self.ReturnHandler = ReturnHandle(self) + self.AssignHandler = AssignHandle(self) + self.AugAssignHandler = AugAssignHandle(self) + self.DeleteHandler = DeleteHandle(self) + self.WithHandler = WithHandle(self) + self.TryHandler = TryHandle(self) + self.AssertHandler = AssertHandle(self) + self.RaiseHandler = RaiseHandle(self) + self.MatchHandler = MatchHandle(self) + + def LogWarning(self, message: str, LineNum: int = None): + """记录警告 + + Args: + message: 警告消息 + LineNum: 行号(可选) + """ + warning = f"Warning: {message}" + if LineNum is not None: + warning += f" (line {LineNum})" + self.Warnings.append(warning) + + def LogError(self, message: str, LineNum: int = None): + """记录错误 + + Args: + message: 错误消息 + LineNum: 行号 + """ + print(f"[ERROR] {message}") + entry = {'message': message, 'line': LineNum} + self.Errors.append(entry) + + # 检查 config 中是否有 debug 文件 + DebugFile = None + if hasattr(self, 'config') and self.config: + DebugFile = getattr(self.config, 'debug', None) + + if DebugFile: + with open(DebugFile, 'a', encoding='utf-8') as f: + LineInfo = f' line {LineNum}' if LineNum else '' + f.write(f'[ERROR]{LineInfo}: {message}\n') + + def SetDebugFile(self, FilePath): + """设置调试输出文件""" + self.DebugFile = FilePath + + def DebugPrint(self, *args, **kwargs): + """输出调试信息到文件""" + if self.DebugFile: + with open(self.DebugFile, 'a', encoding='utf-8') as f: + print(*args, file=f, **kwargs) + + def HandleExpr(self, Node, UseSingleQuote=False, VarType=None): + return self.ExprHandler.HandleExpr(Node, UseSingleQuote, VarType) diff --git a/lib/core/Translator/ConstEval.py b/lib/core/Translator/ConstEval.py new file mode 100644 index 0000000..780e1a2 --- /dev/null +++ b/lib/core/Translator/ConstEval.py @@ -0,0 +1,186 @@ +from __future__ import annotations + +import ast +import llvmlite.ir as ir + + +class ConstEvalMixin: + """常量表达式求值 Mixin + + 提供数组初始化常量构建与常量表达式求值能力。 + """ + + def _BuildArrayInitConstants(self, value_node, ElemType, elem_type_node, ArrayCount, Gen): + from lib.core.Handles.HandlesAssign import AssignHandle + _zv = AssignHandle._zero_value(ElemType) + _fallback = _zv if _zv is not None else ir.Constant(ElemType, ir.Undefined) + if not isinstance(value_node, (ast.List, ast.Set)): + return None + if isinstance(ElemType, ir.ArrayType): + constants = [] + for elt in value_node.elts: + if isinstance(elt, (ast.List, ast.Set)): + inner_consts = self._BuildMultiDimArrayInitConstants(elt, ElemType, Gen) + if inner_consts: + try: + constants.append(ir.Constant(ElemType, inner_consts)) + except Exception: # fallback to _fallback on constant construction failure + constants.append(_fallback) + else: + constants.append(_fallback) + else: + constants.append(_fallback) + while len(constants) < ArrayCount: + constants.append(_fallback) + return constants[:ArrayCount] + StructName = None + if isinstance(elem_type_node, ast.Name) and elem_type_node.id in Gen.structs: + StructName = elem_type_node.id + constants = [] + for elt in value_node.elts: + if StructName and isinstance(elt, ast.Call) and isinstance(elt.func, ast.Name) and elt.func.id == StructName: + const = self.ClassHandler._BuildStructConstant(elt, StructName, Gen) + if const: + constants.append(const) + else: + constants.append(_fallback) + elif isinstance(elt, ast.Constant): + const = self.ClassHandler._BuildScalarConstant(elt, ElemType) + if const: + constants.append(const) + else: + constants.append(_fallback) + elif isinstance(elt, ast.UnaryOp): + const = self.ClassHandler._BuildScalarConstant(elt, ElemType) + if const: + constants.append(const) + else: + constants.append(_fallback) + elif isinstance(elt, ast.Call) and isinstance(elt.func, ast.Name) and elt.func.id == 'chr': + if elt.args and isinstance(elt.args[0], ast.Constant) and isinstance(elt.args[0].value, int): + try: + constants.append(ir.Constant(ElemType, elt.args[0].value & 0xFF)) + except Exception: # fallback to _fallback on constant construction failure + constants.append(_fallback) + else: + constants.append(_fallback) + elif isinstance(elt, ast.Call) and isinstance(elt.func, ast.Name) and elt.func.id == 'ord': + if elt.args and isinstance(elt.args[0], ast.Constant) and isinstance(elt.args[0].value, str) and len(elt.args[0].value) == 1: + try: + constants.append(ir.Constant(ElemType, ord(elt.args[0].value))) + except Exception: # fallback to _fallback on constant construction failure + constants.append(_fallback) + else: + constants.append(_fallback) + else: + const_val = self._try_eval_const_call(elt, Gen) + if const_val is not None: + try: + constants.append(ir.Constant(ElemType, const_val)) + except Exception: # fallback to _fallback on constant construction failure + constants.append(_fallback) + else: + constants.append(_fallback) + while len(constants) < ArrayCount: + constants.append(_fallback) + return constants[:ArrayCount] + + def _try_eval_const_call(self, node, Gen): + import ast + if isinstance(node, ast.Call): + func_name = None + if isinstance(node.func, ast.Name): + func_name = node.func.id + elif isinstance(node.func, ast.Attribute): + func_name = node.func.attr + if func_name: + arg_vals = [] + for arg in node.args: + v = self._try_eval_const_expr(arg, Gen) + if v is None: + return None + arg_vals.append(v) + if func_name == 'COLOR_RGB' and len(arg_vals) == 3: + r, g, b = arg_vals + return (255 << 24) | (int(b) << 16) | (int(g) << 8) | int(r) + if func_name in Gen._DefineConstants: + return Gen._DefineConstants[func_name] + for key in Gen.functions: + if key.endswith(f'__{func_name}'): + return None + return None + return self._try_eval_const_expr(node, Gen) + + def _try_eval_const_expr(self, node, Gen): + import ast + if isinstance(node, ast.Constant): + return node.value + elif isinstance(node, ast.BinOp): + left = self._try_eval_const_expr(node.left, Gen) + right = self._try_eval_const_expr(node.right, Gen) + if left is None or right is None: + return None + if isinstance(node.op, ast.Add): + return left + right + elif isinstance(node.op, ast.Sub): + return left - right + elif isinstance(node.op, ast.Mult): + return left * right + elif isinstance(node.op, ast.LShift): + return left << right + elif isinstance(node.op, ast.RShift): + return left >> right + elif isinstance(node.op, ast.BitOr): + return left | right + elif isinstance(node.op, ast.BitAnd): + return left & right + elif isinstance(node.op, ast.BitXor): + return left ^ right + elif isinstance(node, ast.UnaryOp): + operand = self._try_eval_const_expr(node.operand, Gen) + if operand is None: + return None + if isinstance(node.op, ast.USub): + return -operand + elif isinstance(node.op, ast.Invert): + return ~operand + elif isinstance(node, ast.Name): + if node.id in getattr(Gen, '_DefineConstants', {}): + return Gen._DefineConstants[node.id] + return None + + def _BuildMultiDimArrayInitConstants(self, value_node, ArrayType, Gen): + from lib.core.Handles.HandlesAssign import AssignHandle + inner_type = ArrayType.element + count = ArrayType.count + elts = list(value_node.elts) if hasattr(value_node, 'elts') else [] + _zv = AssignHandle._zero_value(inner_type) + _fallback = _zv if _zv is not None else ir.Constant(inner_type, ir.Undefined) + constants = [] + for elt in elts: + if isinstance(inner_type, ir.ArrayType): + if isinstance(elt, (ast.List, ast.Set)): + inner_consts = self._BuildMultiDimArrayInitConstants(elt, inner_type, Gen) + if inner_consts: + constants.append(ir.Constant(inner_type, inner_consts)) + else: + constants.append(_fallback) + else: + constants.append(_fallback) + elif isinstance(elt, ast.Constant): + const = self.ClassHandler._BuildScalarConstant(elt, inner_type) + if const: + constants.append(const) + else: + constants.append(_fallback) + elif isinstance(elt, ast.UnaryOp): + const = self.ClassHandler._BuildScalarConstant(elt, inner_type) + if const: + constants.append(const) + else: + constants.append(_fallback) + else: + constants.append(_fallback) + while len(constants) < count: + constants.append(_fallback) + return constants[:count] diff --git a/lib/core/Translator/LlvmGenerator.py b/lib/core/Translator/LlvmGenerator.py new file mode 100644 index 0000000..a56d18a --- /dev/null +++ b/lib/core/Translator/LlvmGenerator.py @@ -0,0 +1,622 @@ +from __future__ import annotations + +import ast +import os +import re +import llvmlite.ir as ir + +from lib.core.LlvmCodeGenerator import LlvmCodeGenerator +from lib.core.SymbolNode import SymbolNode +from lib.core.Handles.HandlesBase import CTypeInfo +from lib.includes import t +from lib.constants.config import mode as _config_mode +from lib.core.Translator.BaseTranslator import _StrictLog + + +class LlvmGeneratorMixin: + """LLVM IR 生成 Mixin + + 提供 LLVM IR 直接生成、模块级 LLVM IR 处理与 C 代码生成入口能力。 + """ + + def GenerateLlvmDirect(self, Tree): + Gen = self.LlvmGen + + # 预扫描:为所有 -> str 注解的函数注册正确的返回类型 i8* + # 这样在类方法中调用这些函数时,前向声明会使用正确的类型 + for Node in ast.iter_child_nodes(Tree): + if isinstance(Node, ast.FunctionDef): + if Node.returns and isinstance(Node.returns, ast.Name) and Node.returns.id == 'str': + Gen.known_return_types[Node.name] = ir.PointerType(ir.IntType(8)) + + # 首先收集所有 CDefine 常量,确保类定义中可以引用 + def _extract_call_const_val(node): + if isinstance(node, ast.Call): + if isinstance(node.func, ast.Attribute): + if getattr(node.func.value, 'id', None) == 't': + if node.args and isinstance(node.args[0], ast.Constant): + return node.args[0].value + elif isinstance(node.func, ast.Name): + if node.args and isinstance(node.args[0], ast.Constant): + return node.args[0].value + return None + + for Node in ast.iter_child_nodes(Tree): + if isinstance(Node, ast.AnnAssign) and isinstance(Node.target, ast.Name) and Node.value: + TypeInfo = self.TypeMergeHandler.GetCTypeInfo(Node.annotation) + if TypeInfo and TypeInfo.BaseType and hasattr(TypeInfo.BaseType, 'CName') and TypeInfo.BaseType.CName == '#define': + val = None + if isinstance(Node.value, ast.Constant): + val = Node.value.value + else: + val = _extract_call_const_val(Node.value) + if val is not None: + if not hasattr(Gen, '_define_constants'): + Gen._define_constants = {} + Gen._define_constants[Node.target.id] = val + from lib.core.Handles.HandlesBase import CTypeInfo as _CTypeInfo + sym_info = _CTypeInfo() + sym_info.IsDefine = True + sym_info.DefineValue = val + self.SymbolTable[Node.target.id] = sym_info + elif isinstance(Node, ast.Assign): + for target in Node.targets: + if isinstance(target, ast.Name): + TypeInfo = None + if Node.type_comment: + try: + tc_ast = ast.parse(Node.type_comment, mode='eval') + TypeInfo = self.TypeMergeHandler.GetCTypeInfo(tc_ast.body) + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _config_mode + if _config_mode == "strict": + raise + _vlog().warning(f"解析类型注释失败: {_e}", "Exception") + if TypeInfo and TypeInfo.BaseType and hasattr(TypeInfo.BaseType, 'CName') and TypeInfo.BaseType.CName == '#define': + val = None + if isinstance(Node.value, ast.Constant): + val = Node.value.value + else: + val = _extract_call_const_val(Node.value) + if val is not None: + if not hasattr(Gen, '_define_constants'): + Gen._define_constants = {} + Gen._define_constants[target.id] = val + from lib.core.Handles.HandlesBase import CTypeInfo as _CTypeInfo + sym_info = _CTypeInfo() + sym_info.IsDefine = True + sym_info.DefineValue = val + self.SymbolTable[target.id] = sym_info + + # 预扫描所有顶层函数定义,填充 FunctionDefCache(不创建 LLVM 声明) + # 这样类方法编译时遇到未声明的函数可以按需前向声明 + for Node in ast.iter_child_nodes(Tree): + if isinstance(Node, ast.FunctionDef): + FuncName = Node.name + if FuncName not in self.FunctionDefCache: + self.FunctionDefCache[FuncName] = Node + + # 首先处理所有导入语句,确保模块在类型解析前被加载 + for Node in ast.iter_child_nodes(Tree): + Gen._set_node_info(Node) + try: + if isinstance(Node, ast.Import): + self.ImportHandler._EmitImportDeclarationsLlvm(Node, Gen) + elif isinstance(Node, ast.ImportFrom): + self.ImportHandler._EmitImportFromDeclarationsLlvm(Node, Gen) + except Exception as e: + lineno = getattr(Node, 'lineno', 0) + source_line = Gen._get_source_line(lineno) + src_file = getattr(Gen, '_current_source_file', '') + src_path = src_file if src_file else 'unknown' + line_info = "源代码 (%s, line %d)" % (src_path, lineno) + if source_line: + line_info += ":\n %d | %s" % (lineno, source_line) + self._ErrorStack.append((type(e).__name__, str(e), line_info)) + + # 预创建全局变量(带初始化器),确保类方法编译时能引用全局数组等 + Gen._current_tree = Tree + for Node in ast.iter_child_nodes(Tree): + if isinstance(Node, ast.AnnAssign): + self.AssignHandler._EmitGlobalAnnAssignLlvm(Node, Gen) + elif isinstance(Node, ast.Assign): + self.AssignHandler._EmitGlobalAssignLlvm(Node, Gen) + + # 前向声明所有顶层函数,确保类方法编译时能找到这些函数 + for Node in ast.iter_child_nodes(Tree): + if isinstance(Node, ast.FunctionDef): + self.FunctionHandler._EmitFunctionForwardDeclLlvm(Node, Gen) + + # 首先处理所有类定义(包括 CUnion),确保类型定义在使用前完成 + for Node in ast.iter_child_nodes(Tree): + if isinstance(Node, ast.ClassDef): + self.ClassHandler._EmitClassLlvm(Node, Gen) + + Gen._generate_structs() + Gen._create_Vtable_globals() + + for Node in ast.iter_child_nodes(Tree): + Gen._set_node_info(Node) + try: + if isinstance(Node, ast.Import): + continue + elif isinstance(Node, ast.ImportFrom): + continue + elif isinstance(Node, ast.ClassDef): + continue + elif isinstance(Node, ast.FunctionDef): + self.FunctionHandler._EmitFunctionLlvm(Node, Gen) + elif isinstance(Node, ast.AnnAssign): + self.AssignHandler._EmitGlobalAnnAssignLlvm(Node, Gen) + elif isinstance(Node, ast.Assign): + self.AssignHandler._EmitGlobalAssignLlvm(Node, Gen) + elif isinstance(Node, ast.If): + pass + elif isinstance(Node, ast.Expr): + self._HandleModuleLevelExprLlvm(Node, Gen) + except Exception as e: + lineno = getattr(Node, 'lineno', 0) + source_line = Gen._get_source_line(lineno) + src_file = getattr(Gen, '_current_source_file', '') + src_path = src_file if src_file else 'unknown' + line_info = "源代码 (%s, line %d)" % (src_path, lineno) + if source_line: + line_info += ":\n %d | %s" % (lineno, source_line) + self._ErrorStack.append((type(e).__name__, str(e), line_info)) + raise + Gen._set_Vtable_initializers() + # 执行 DecoratorPass:为带自定义装饰器的函数生成 wrapper + from lib.core.DecoratorPass import run as _run_decorator_pass + _run_decorator_pass(Gen) + ir_code = Gen.finalize() + return ir_code + + def _HandleModuleLevelExprLlvm(self, Node, Gen): + if not isinstance(Node.value, ast.Call): + return + call = Node.value + if not isinstance(call.func, ast.Attribute): + return + if not isinstance(call.func.value, ast.Name) or call.func.value.id != 'c': + return + func_name = call.func.attr + if func_name == 'LLVMIR': + self._HandleModuleLevelLLVMIR(call, Gen) + + def _HandleModuleLevelLLVMIR(self, Node, Gen): + if not Node.args: + return + first_arg = Node.args[0] + if isinstance(first_arg, ast.Constant) and isinstance(first_arg.value, str): + ir_text = first_arg.value + elif isinstance(first_arg, ast.JoinedStr): + parts = [] + for value in first_arg.values: + if isinstance(value, ast.Constant) and isinstance(value.value, str): + parts.append(value.value) + elif isinstance(value, ast.FormattedValue): + parts.append('') + ir_text = ''.join(parts) + else: + return + self._InsertModuleLevelLLVMIR(Gen, ir_text) + + def _InsertModuleLevelLLVMIR(self, Gen, ir_text): + import re + for line in ir_text.strip().split('\n'): + line = line.strip() + if not line: + continue + module_flags_match = re.match(r'!llvm\.module\.flags\s*=\s*!\{(!\d+)\}', line) + if module_flags_match: + ref = module_flags_match.group(1) + if not hasattr(Gen, '_pending_module_flags'): + Gen._pending_module_flags = [] + Gen._pending_module_flags_refs = ref + continue + metadata_match = re.match(r'(!\d+)\s*=\s*!\{(.+)\}', line) + if metadata_match: + md_id = metadata_match.group(1) + md_body = metadata_match.group(2) + fields = [] + for field_str in re.split(r',\s*', md_body): + field_str = field_str.strip() + if not field_str: + continue + int_m = re.match(r'^i32\s+(\d+)$', field_str) + if int_m: + fields.append(ir.Constant(ir.IntType(32), int(int_m.group(1)))) + continue + str_m = re.match(r'^"([^"]*)"$', field_str) + if str_m: + fields.append(ir.MetaDataString(Gen.module, str_m.group(1))) + continue + mdstr_m = re.match(r'^!"([^"]*)"$', field_str) + if mdstr_m: + fields.append(ir.MetaDataString(Gen.module, mdstr_m.group(1))) + continue + int_m2 = re.match(r'^(\d+)$', field_str) + if int_m2: + fields.append(ir.Constant(ir.IntType(32), int(int_m2.group(1)))) + continue + ref_m = re.match(r'^(!\d+)$', field_str) + if ref_m: + fields.append(ref_m.group(1)) + continue + if fields: + if not hasattr(Gen, '_pending_metadata'): + Gen._pending_metadata = [] + Gen._pending_metadata.append((md_id, fields)) + continue + self._FlushModuleMetadata(Gen) + + def _FlushModuleMetadata(self, Gen): + if not hasattr(Gen, '_pending_metadata') or not Gen._pending_metadata: + return + md_map = {} + for md_id, fields in Gen._pending_metadata: + resolved = [] + for f in fields: + if isinstance(f, str) and f.startswith('!'): + ref = md_map.get(f) + if ref: + resolved.append(ref) + else: + resolved.append(f) + md_value = Gen.module.add_metadata(resolved) + md_map[md_id] = md_value + if hasattr(Gen, '_pending_module_flags_refs'): + ref = Gen._pending_module_flags_refs + md_node = md_map.get(ref) + if md_node: + Gen.module.add_named_metadata('llvm.module.flags', md_node) + Gen._pending_metadata = [] + Gen._pending_module_flags_refs = None + + def GenerateCCode(self, Tree, target='llvm'): + """生成代码 + + Args: + Tree: Python AST 树 + target: 目标代码类型,仅支持 'llvm' + + Returns: + 生成的代码字符串 + """ + self._generated_vars = set() + self.VarScopes = [{}] # 全局作用域 + + # 预扫描 import 语句,注册别名,确保类型解析时能正确解析模块别名 + if not getattr(self, '_ImportAliases', None): + self._ImportAliases = {} + if not getattr(self, '_ImportedModules', None): + self._ImportedModules = set() + for Node in ast.iter_child_nodes(Tree): + if isinstance(Node, ast.Import): + for alias in Node.names: + name = alias.name + if name in ('c', 't'): + continue + self._ImportedModules.add(name) + if alias.asname: + self._ImportAliases[alias.asname] = name + elif isinstance(Node, ast.ImportFrom): + module_name = Node.module + if module_name and module_name not in ('c', 't'): + self._ImportedModules.add(module_name) + for alias in Node.names: + if alias.asname: + self._ImportAliases[alias.asname] = f"{module_name}.{alias.name}" + + for Node in ast.iter_child_nodes(Tree): + if isinstance(Node, ast.ClassDef): + ClassName = Node.name + + # 检查是否是特殊类型(枚举或联合体) + IsSpecialType = False + if Node.bases: + for base in Node.bases: + if hasattr(base, 'attr'): + if base.attr in ['CEnum', 'Enum', 'CUnion', 'REnum']: + IsSpecialType = True + break + elif hasattr(base, 'id'): + if base.id in ['CEnum', 'Enum', 'CUnion', 'REnum']: + IsSpecialType = True + break + + # 如果是特殊类型,跳过这里的处理(由 HandleClassDef 处理) + if IsSpecialType: + continue + + members = {} + IsTypedef = False + TypedefName = None + + if hasattr(Node, 'annotation') and Node.annotation: + try: + AnnotationStr = ast.dump(Node.annotation) + if 'CTypedef' in AnnotationStr: + IsTypedef = True + if isinstance(Node.annotation, ast.Call): + if Node.annotation.args: + if isinstance(Node.annotation.args[0], ast.Constant): + TypedefName = Node.annotation.args[0].value + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _config_mode + if _config_mode == "strict": + raise + _vlog().warning(f"解析 typedef 注解失败: {_e}", "Exception") + + if not IsTypedef: + for item in Node.body: + if isinstance(item, ast.Assign): + for target in item.targets: + if isinstance(target, ast.Name) and target.id == '__annotations__': + if isinstance(item.value, ast.Dict): + for key, value in zip(item.value.keys, item.value.values): + if isinstance(key, ast.Constant) and key.value == '__type__': + value_str = ast.dump(value) + if 'CTypedef' in value_str: + IsTypedef = True + if isinstance(value, ast.Call): + if value.args: + if isinstance(value.args[0], ast.Constant): + TypedefName = value.args[0].value + + if IsTypedef: + TypedefKey = TypedefName if TypedefName else ClassName + TypedefNode = SymbolNode.CreateClass( + name=TypedefKey, + TypeKind='typedef', + lineno=0 + ) + TypedefNode.set('OriginalType', f'struct {ClassName}') + TypedefNode.set('IsComplete', True) + TypedefNode.set('file', '') + self.SymbolTable[TypedefKey] = TypedefNode.attributes + + for item in Node.body: + if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name): + VarName = item.target.id + try: + TypeInfo = self.TypeMergeHandler.GetCTypeInfo(item.annotation) + if TypeInfo is None: + TypeInfo = CTypeInfo() + TypeInfo.BaseType = t.CInt() + IsPtr = TypeInfo.IsPtr + if not IsPtr: + if isinstance(item.annotation, ast.BinOp) and isinstance(item.annotation.op, ast.BitOr): + LeftStr = ast.dump(item.annotation.left) + RightStr = ast.dump(item.annotation.right) + if 'CPtr' in LeftStr or 'CPtr' in RightStr: + IsPtr = True + dims = [] + if hasattr(item.annotation, 'slice') and isinstance(item.annotation.slice, ast.Constant): + if isinstance(item.annotation.value, ast.Name): + if item.annotation.value.id == 't': + if hasattr(item.annotation, 'slice'): + try: + dims.append(int(item.annotation.slice.value)) + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + self.LogWarning(f"异常被忽略: {_e}") + MemberInfo = TypeInfo.Copy() + if dims: + MemberInfo.ArrayDims = [str(d) for d in dims] + members[VarName] = MemberInfo + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + self.LogWarning(f"异常被忽略: {_e}") + + if not IsTypedef: + StructNode = SymbolNode.CreateClass( + name=ClassName, + TypeKind='struct', + members=members, + lineno=0 + ) + StructNode.set('file', '') + if ClassName in self.SymbolTable: + existing = self.SymbolTable[ClassName] + if hasattr(existing, 'IsCpythonObject') and existing.IsCpythonObject: + StructNode.set('IsCpythonObject', True) + self.SymbolTable[ClassName] = StructNode.attributes + elif isinstance(Node, ast.FunctionDef): + FuncName = Node.name + FuncNode = SymbolNode.CreateClass( + name=FuncName, + TypeKind='function', + lineno=0 + ) + FuncNode.set('file', '') + self.SymbolTable[FuncName] = FuncNode.attributes + elif isinstance(Node, ast.AnnAssign): + if isinstance(Node.target, ast.Name): + VarName = Node.target.id + + VarType = 'unknown' + IsPtr = False + IsTypedef_assignment = False + + if Node.annotation: + try: + AnnotationStr = ast.dump(Node.annotation) + if 'CTypedef' in AnnotationStr: + IsTypedef_assignment = True + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + self.LogWarning(f"异常被忽略: {_e}") + + if IsTypedef_assignment and Node.value: + if isinstance(Node.value, ast.Name): + OriginalType = Node.value.id + if OriginalType in self.GeneratedTypes: + if OriginalType in self.SymbolTable: + OriginalInfo = self.SymbolTable[OriginalType] + if isinstance(OriginalInfo, dict): + actual_type = OriginalInfo.get('type', 'struct') + elif isinstance(OriginalInfo, CTypeInfo): + if OriginalInfo.IsEnum: + actual_type = 'enum' + elif OriginalInfo.IsTypedef: + actual_type = 'typedef' + elif OriginalInfo.IsStruct: + actual_type = 'struct' + else: + actual_type = 'struct' + else: + actual_type = 'struct' + if actual_type == 'enum': + TypedefNode = SymbolNode.CreateClass( + name=VarName, + TypeKind='typedef', + lineno=0 + ) + TypedefNode.set('OriginalType', f'enum {OriginalType}') + TypedefNode.set('file', '') + self.SymbolTable[VarName] = TypedefNode.attributes + elif actual_type == 'typedef': + TypedefNode = SymbolNode.CreateClass( + name=VarName, + TypeKind='typedef', + lineno=0 + ) + if isinstance(OriginalInfo, dict): + TypedefNode.set('OriginalType', OriginalInfo.get('OriginalType', f'struct {OriginalType}')) + elif isinstance(OriginalInfo, CTypeInfo) and OriginalInfo.OriginalType: + TypedefNode.set('OriginalType', OriginalInfo.OriginalType) + else: + TypedefNode.set('OriginalType', f'struct {OriginalType}') + TypedefNode.set('PendingTypedef', True) + TypedefNode.set('file', '') + self.SymbolTable[VarName] = TypedefNode.attributes + else: + TypedefNode = SymbolNode.CreateClass( + name=VarName, + TypeKind='typedef', + lineno=0 + ) + TypedefNode.set('OriginalType', f'struct {OriginalType}') + TypedefNode.set('PendingTypedef', True) + TypedefNode.set('file', '') + self.SymbolTable[VarName] = TypedefNode.attributes + self.GeneratedTypes.add(VarName) + continue + else: + if OriginalType in self.SymbolTable: + OriginalInfo = self.SymbolTable[OriginalType] + if isinstance(OriginalInfo, dict): + actual_type = OriginalInfo.get('type', 'struct') + elif isinstance(OriginalInfo, CTypeInfo): + if OriginalInfo.IsEnum: + actual_type = 'enum' + elif OriginalInfo.IsTypedef: + actual_type = 'typedef' + elif OriginalInfo.IsStruct: + actual_type = 'struct' + else: + actual_type = 'struct' + else: + actual_type = 'struct' + if actual_type == 'typedef': + TypedefNode = SymbolNode.CreateClass( + name=VarName, + TypeKind='typedef', + lineno=0 + ) + if isinstance(OriginalInfo, dict): + TypedefNode.set('OriginalType', OriginalInfo.get('OriginalType', f'struct {OriginalType}')) + elif isinstance(OriginalInfo, CTypeInfo) and OriginalInfo.OriginalType: + TypedefNode.set('OriginalType', OriginalInfo.OriginalType) + else: + TypedefNode.set('OriginalType', f'struct {OriginalType}') + TypedefNode.set('PendingTypedef', True) + TypedefNode.set('file', '') + self.SymbolTable[VarName] = TypedefNode.attributes + self.GeneratedTypes.add(VarName) + if isinstance(OriginalInfo, dict): + OriginalInfo['skip_generation'] = True + continue + elif actual_type == 'struct': + TypedefNode = SymbolNode.CreateClass( + name=VarName, + TypeKind='typedef', + lineno=0 + ) + TypedefNode.set('OriginalType', f'struct {OriginalType}') + TypedefNode.set('PendingTypedef', True) + TypedefNode.set('file', '') + self.SymbolTable[VarName] = TypedefNode.attributes + self.GeneratedTypes.add(VarName) + if isinstance(OriginalInfo, dict): + OriginalInfo['skip_generation'] = True + continue + elif actual_type == 'enum': + TypedefNode = SymbolNode.CreateClass( + name=VarName, + TypeKind='typedef', + lineno=0 + ) + TypedefNode.set('OriginalType', f'enum {OriginalType}') + TypedefNode.set('PendingTypedef', True) + TypedefNode.set('file', '') + self.SymbolTable[VarName] = TypedefNode.attributes + self.GeneratedTypes.add(VarName) + if isinstance(OriginalInfo, dict): + OriginalInfo['skip_generation'] = True + continue + elif isinstance(Node.value, ast.Attribute): + from lib.core.Handles.HandlesBase import CTypeHelper + CName = CTypeHelper.GetCName(Node.value.attr) + if CName: + TypedefNode = SymbolNode.CreateClass( + name=VarName, + TypeKind='typedef', + lineno=0 + ) + TypedefNode.set('OriginalType', CName) + TypedefNode.set('file', '') + self.SymbolTable[VarName] = TypedefNode.attributes + self.GeneratedTypes.add(VarName) + continue + + if Node.annotation: + try: + TypeInfo = self.TypeMergeHandler.GetCTypeInfo(Node.annotation) + IsPtr = TypeInfo.IsPtr if TypeInfo else False + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + self.LogWarning(f"异常被忽略: {_e}") + var_node = SymbolNode.CreateClass( + name=VarName, + TypeKind='variable', + lineno=0 + ) + var_node.set('IsPtr', IsPtr) + var_node.set('file', '') + self.SymbolTable[VarName] = var_node.attributes + + self.LlvmGen = LlvmCodeGenerator( + triple=getattr(self, 'triple', None), + datalayout=getattr(self, 'datalayout', None), + ) + self.LlvmGen._Trans = self + self.LlvmGen._import_handler_ref = self.ImportHandler + if hasattr(self, '_module_sha1'): + self.LlvmGen.module_sha1 = self._module_sha1 + if hasattr(self, '_ModuleSha1Map'): + self.LlvmGen.ModuleSha1Map = self._ModuleSha1Map + if hasattr(self, '_struct_sha1_map'): + self.LlvmGen._struct_sha1_map = self._struct_sha1_map + if hasattr(self, '_temp_dir'): + self.LlvmGen._temp_dir = self._temp_dir + if hasattr(self, '_export_extern_funcs'): + self.LlvmGen._export_extern_funcs = self._export_extern_funcs + self.LlvmGen.setup_from_symbol_table(self.SymbolTable) + if hasattr(self, 'CurrentFile') and self.CurrentFile: + self.LlvmGen._set_source_info(self.CurrentFile) + + return self.GenerateLlvmDirect(Tree) diff --git a/lib/core/Translator/PythonParser.py b/lib/core/Translator/PythonParser.py new file mode 100644 index 0000000..2dcea13 --- /dev/null +++ b/lib/core/Translator/PythonParser.py @@ -0,0 +1,460 @@ +from __future__ import annotations + +import ast +import os +import sys +import json +import struct + +from lib.utils.helpers import DetectFileType +from lib.core.SymbolNode import SymbolNode +from lib.core.Handles.HandlesBase import CTypeInfo +from lib.includes import t +from lib.constants.config import mode as _ConfigMode +from lib.core.Translator.BaseTranslator import _StrictLog + + +class PythonParserMixin: + """Python 文件解析 Mixin + + 提供辅助文件解析、symbin 文件加载与 Python 源文件解析能力。 + """ + + def ParseHelperFiles(self, HelperFiles, encoding='utf-8'): + """解析辅助文件,提取符号信息 + + 支持 .py, .c, .h 和 .symbin 文件 + """ + for FilePath in HelperFiles: + ext = DetectFileType(FilePath) + if ext == '.py': + self.ParsePythonFile(FilePath, encoding, UpdateCurrentFile=False) + elif ext == '.c': + pass # .c 文件解析已移除,不再使用旧的正则解析路径 + elif FilePath.endswith('.symbin'): + self.LoadSymbinFile(FilePath) + + def LoadSymbinFile(self, FilePath): + """从.symbin文件加载符号表 + + Args: + FilePath: .symbin文件路径 + """ + try: + with open(FilePath, 'rb') as f: + data = f.read() + + # 导入序列化函数(避免循环导入) + import sys + import os + import json + import struct + + # 解析二进制格式 + if len(data) < 4: + print(f"Warning: Invalid symbin file (too short): {FilePath}") + return + + # 解析4字节长度头(小端序) + length = struct.unpack(' 1: + # 第二个参数应该是一个列表 + dim_arg = PostdefNode.args[1] + if isinstance(dim_arg, ast.List): + for DimExpr in dim_arg.elts: + dimensions.append(DimExpr) + + # 如果没有从 Postdefinition 参数中获取维度,尝试从类型注解中的 Subscript 获取 + # 例如:memory_block_t[MAX_ORDER + 1] | t.CPtr + if not dimensions: + def extract_subscript_dims(node): + """递归提取 Subscript 节点的维度""" + dims = [] + if isinstance(node, ast.Subscript): + # 提取当前维度 + if isinstance(node.slice, ast.Constant): + dims.append(ast.Constant(value=node.slice.value)) + elif isinstance(node.slice, ast.Name): + dims.append(ast.Name(id=node.slice.id, ctx=ast.Load())) + elif isinstance(node.slice, ast.BinOp): + dims.append(node.slice) + # 递归提取更外层的维度 + dims.extend(extract_subscript_dims(node.value)) + elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr): + # 处理 Type | t.CPtr 的情况,检查左侧 + dims.extend(extract_subscript_dims(node.left)) + return dims + + # 从注解中提取维度 + subscript_dims = extract_subscript_dims(annotation) + if subscript_dims: + # 反转维度顺序(从内到外) + dimensions = list(reversed(subscript_dims)) + + # 获取赋值值 + value = None + if hasattr(NextNode, 'value') and NextNode.value is not None: + value = NextNode.value + + # 添加到对应的 assignments + # 对于 t.Postdefinition(...),只有包含 CTypedef 或 CPtr 时才视为 typedef 类型 + if HasCtypedef or IsPtr: + if ClassKey not in self.TypedefAssignments: + self.TypedefAssignments[ClassKey] = [] + # 如果有维度信息,使用字典存储 + if dimensions: + self.TypedefAssignments[ClassKey].append({ + 'name': TargetName, + 'IsPtr': IsPtr, + 'dimensions': dimensions, + 'value': value + }) + else: + self.TypedefAssignments[ClassKey].append((TargetName, IsPtr)) + else: + if ClassKey not in self.EmbeddedAssignments: + self.EmbeddedAssignments[ClassKey] = [] + # 如果有维度信息,使用字典存储 + if dimensions: + self.EmbeddedAssignments[ClassKey].append({ + 'name': TargetName, + 'dimensions': dimensions, + 'value': value + }) + else: + self.EmbeddedAssignments[ClassKey].append(TargetName) + + # 检查是否有 __set_default__ 初始化 + if '__set_default__' in original_AnnotationStr: + self._handle_set_default_in_parse(ClassKey, TargetName, ClassName, NextNode) + j += 1 + continue + # 再处理旧格式:xxx: t.CTypedef = xxx 或 xxx: t.CPtr = xxx + # 注意:这种格式的 typedef 不应该被合并到结构体定义中, + # 而应该生成独立的 typedef 语句,所以不添加到 TypedefAssignments + elif NextNode.annotation and isinstance(NextNode.annotation, ast.Attribute): + if isinstance(NextNode.annotation.value, ast.Name): + annot_id = NextNode.annotation.value.id + annot_attr = NextNode.annotation.attr + if annot_id == 't' and NextNode.value: + if isinstance(NextNode.value, ast.Name): + ValueName = NextNode.value.id + if ValueName == ClassName: + # 检查是 CTypedef 还是 CPtr + if annot_attr == t.CPtr.__name__: + # t.CPtr 表示指针变量,加入 TypedefAssignments,设置 IsPtr=True + if ClassKey not in self.TypedefAssignments: + self.TypedefAssignments[ClassKey] = [] + self.TypedefAssignments[ClassKey].append((TargetName, True)) + j += 1 + continue + # 注意:t.CTypedef 不在这里处理,由 HandlesAnnAssign 生成独立的 typedef 语句 + # 如果不是特殊赋值,停止收集 + break + + i = j + continue + + i += 1 + + # 提取类定义(作为结构体) + for node in ast.walk(tree): + if isinstance(node, ast.ClassDef): + ClassName = node.name + # 先把类名加入 GeneratedTypes,这样 GetTypeName 可以正确识别 + self.GeneratedTypes.add(ClassName) + + # 检测是否是 CEnum + IsCenum = False + for base in node.bases: + if isinstance(base, ast.Attribute): + BaseStr = ast.dump(base) + if 'CEnum' in BaseStr or 'REnum' in BaseStr: + IsCenum = True + break + elif isinstance(base, ast.Name): + if 'CEnum' in base.id or 'REnum' in base.id: + IsCenum = True + break + + # 检测是否有 @t.Object 装饰器或继承自 t.Object + IsCpythonObject = False + if hasattr(node, 'decorator_list') and node.decorator_list: + for decorator in node.decorator_list: + if isinstance(decorator, ast.Attribute): + if (hasattr(decorator.value, 'id') and + decorator.value.id == 't' and + decorator.attr == 'Object'): + IsCpythonObject = True + break + elif isinstance(decorator, ast.Call): + if isinstance(decorator.func, ast.Attribute): + if (hasattr(decorator.func.value, 'id') and + decorator.func.value.id == 't' and + decorator.func.attr == 'Object'): + IsCpythonObject = True + break + elif isinstance(decorator.func, ast.Name): + if decorator.func.id == 'Object': + IsCpythonObject = True + break + elif isinstance(decorator, ast.Name): + if decorator.id == 'Object': + IsCpythonObject = True + break + if not IsCpythonObject and hasattr(node, 'bases') and node.bases: + for base in node.bases: + if isinstance(base, ast.Attribute): + if (hasattr(base.value, 'id') and + base.value.id == 't' and + base.attr == 'Object'): + IsCpythonObject = True + break + elif isinstance(base, ast.Name): + if base.id == 'Object': + IsCpythonObject = True + break + + if IsCenum: + # 注册为 enum 类型 + EnumNode = SymbolNode.CreateClass( + name=ClassName, + TypeKind='enum', + lineno=0 + ) + EnumNode.set('file', '') + self.SymbolTable[ClassName] = EnumNode.attributes + + # 注册 enum 成员 + for item in node.body: + if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name): + MemberName = item.target.id + MemberNode = CTypeInfo() + MemberNode.Name = MemberName + MemberNode.BaseType = t.CEnum(ClassName) + MemberNode.value = None + MemberNode.EnumName = ClassName + MemberNode.library_name = None + MemberNode.IsEnumMember = True + self.SymbolTable[MemberName] = MemberNode + self.SymbolTable[f"{ClassName}.{MemberName}"] = MemberNode + self.SymbolTable[f"{ClassName}_{MemberName}"] = MemberNode + + continue + + # 检测是否是 Anonymous + IsAnonymous = False + + # 提取结构体成员信息 + members = {} + for item in node.body: + if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name): + VarName = item.target.id + try: + TypeInfo = self.TypeMergeHandler.GetCTypeInfo(item.annotation) + if TypeInfo is None: + TypeInfo = CTypeInfo() + TypeInfo.BaseType = t.CInt() + IsPtr = TypeInfo.IsPtr + if not IsPtr: + if isinstance(item.annotation, ast.BinOp) and isinstance(item.annotation.op, ast.BitOr): + LeftStr = ast.dump(item.annotation.left) + RightStr = ast.dump(item.annotation.right) + if 'CPtr' in LeftStr or 'CPtr' in RightStr: + IsPtr = True + dims = [] + if hasattr(item.annotation, 'slice') and isinstance(item.annotation.slice, ast.Constant): + if isinstance(item.annotation.value, ast.Name): + if item.annotation.value.id == 't': + if hasattr(item.annotation, 'slice'): + try: + dims.append(int(item.annotation.slice.value)) + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _ConfigMode + if _ConfigMode == "strict": + raise + _vlog().warning(f"解析数组维度失败: {_e}", "Exception") + MemberInfo = TypeInfo.Copy() + if dims: + MemberInfo.ArrayDims = [str(d) for d in dims] + members[VarName] = MemberInfo + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _ConfigMode + if _ConfigMode == "strict": + raise + _vlog().warning(f"解析结构体成员失败: {_e}", "Exception") + StructNode = SymbolNode.CreateClass( + name=ClassName, + TypeKind='struct', + members=members, + lineno=0, + IsCpythonObject=IsCpythonObject + ) + StructNode.set('file', '') + StructNode.set('IsAnonymous', IsAnonymous) + self.SymbolTable[ClassName] = StructNode.attributes + elif isinstance(node, ast.FunctionDef): + FuncName = node.name + FuncNode = SymbolNode.CreateClass( + name=FuncName, + TypeKind='function', + lineno=0 + ) + FuncNode.set('file', '') + self.SymbolTable[FuncName] = FuncNode.attributes + elif isinstance(node, ast.AnnAssign): + if isinstance(node.target, ast.Name): + VarName = node.target.id + # 检查是否是 t.CTypedef 格式,如果是则跳过(由 HandleClassDef 处理) + is_ctypedef = False + if node.annotation: + if isinstance(node.annotation, ast.Attribute): + if isinstance(node.annotation.value, ast.Name): + if node.annotation.value.id == 't' and node.annotation.attr == 'CTypedef': + is_ctypedef = True + elif isinstance(node.annotation, ast.BinOp) and isinstance(node.annotation.op, ast.BitOr): + def _has_ctype(ann): + if isinstance(ann, ast.Attribute): + return hasattr(ann.value, 'id') and ann.value.id == 't' and ann.attr == 'CTypedef' + if isinstance(ann, ast.BinOp) and isinstance(ann.op, ast.BitOr): + return _has_ctype(ann.left) or _has_ctype(ann.right) + if isinstance(ann, ast.Subscript): + return _has_ctype(ann.value) + return False + if _has_ctype(node.annotation): + is_ctypedef = True + if not is_ctypedef: + IsPtr = False + if node.annotation: + try: + TypeInfo = self.TypeMergeHandler.GetCTypeInfo(node.annotation) + IsPtr = TypeInfo.IsPtr if TypeInfo else False + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _ConfigMode + if _ConfigMode == "strict": + raise + _vlog().warning(f"获取类型信息失败(ParsePythonFile): {_e}", "Exception") + var_node = SymbolNode.CreateClass( + name=VarName, + TypeKind='variable', + lineno=0 + ) + var_node.set('IsPtr', IsPtr) + var_node.set('file', '') + self.SymbolTable[VarName] = var_node.attributes + except Exception as e: + print(f'Warning: Failed to parse Python file {FilePath}: {e}') + + # ParseCFile 已移除 - .h/.c 文件的旧正则解析路径不再使用 + # 类型解析现在直接通过 CTypeInfo 对象进行,不经过中间字符串格式 diff --git a/lib/core/Translator/__init__.py b/lib/core/Translator/__init__.py new file mode 100644 index 0000000..84114dc --- /dev/null +++ b/lib/core/Translator/__init__.py @@ -0,0 +1,11 @@ +"""Translator 包 - 代码转换器模块""" +from lib.core.Translator.BaseTranslator import BaseTranslatorMixin, _StrictLog +from lib.core.Translator.AnnotationLoader import AnnotationLoaderMixin +from lib.core.Translator.PythonParser import PythonParserMixin +from lib.core.Translator.LlvmGenerator import LlvmGeneratorMixin +from lib.core.Translator.ConstEval import ConstEvalMixin + +__all__ = [ + 'BaseTranslatorMixin', 'AnnotationLoaderMixin', 'PythonParserMixin', + 'LlvmGeneratorMixin', 'ConstEvalMixin', '_StrictLog' +] diff --git a/lib/core/logger.py b/lib/core/VLogger.py similarity index 90% rename from lib/core/logger.py rename to lib/core/VLogger.py index 00752df..865c99a 100644 --- a/lib/core/logger.py +++ b/lib/core/VLogger.py @@ -1,297 +1,322 @@ -""" -TransPyC 彩色日志系统 -支持终端颜色输出和日志文件转储 -""" - -import sys -import os -from datetime import datetime -from typing import Optional - -# ANSI 颜色代码 -class Colors: - RESET = '\033[0m' - BOLD = '\033[1m' - DIM = '\033[2m' - UNDERLINE = '\033[4m' - - # 前景色 - BLACK = '\033[30m' - RED = '\033[31m' - GREEN = '\033[32m' - YELLOW = '\033[33m' - BLUE = '\033[34m' - MAGENTA = '\033[35m' - CYAN = '\033[36m' - WHITE = '\033[37m' - - # 高亮前景色 - BRIGHT_RED = '\033[91m' - BRIGHT_GREEN = '\033[92m' - BRIGHT_YELLOW = '\033[93m' - BRIGHT_BLUE = '\033[94m' - BRIGHT_MAGENTA = '\033[95m' - BRIGHT_CYAN = '\033[96m' - - # 背景色 - BG_RED = '\033[41m' - BG_GREEN = '\033[42m' - BG_YELLOW = '\033[43m' - BG_BLUE = '\033[44m' - BG_MAGENTA = '\033[45m' - BG_CYAN = '\033[46m' - - # 渐变颜色(用于详细日志) - GRAY = '\033[90m' - -# 检查是否支持颜色 -def supports_color(): - if not hasattr(sys.stdout, 'isatty'): - return False - if not sys.stdout.isatty(): - return False - if os.environ.get('NO_COLOR'): - return False - if os.environ.get('FORCE_COLOR'): - return True - return True - -# 全局颜色支持标志 -USE_COLORS = supports_color() - -# 日志级别 -class LogLevel: - DEBUG = 0 - INFO = 1 - WARNING = 2 - ERROR = 3 - CRITICAL = 4 - -class Logger: - def __init__(self, name: str = "TransPyC", log_file: Optional[str] = None, - level: int = LogLevel.INFO, use_colors: bool = True): - self.name = name - self.level = level - self.use_colors = use_colors and USE_COLORS - self.log_file = log_file - self.file_handler = None - - if log_file: - os.makedirs(os.path.dirname(os.path.abspath(log_file)), exist_ok=True) - self.file_handler = open(log_file, 'w', encoding='utf-8') - - # 进度跟踪 - self.current_phase = "" - self.total_items = 0 - self.current_item = 0 - - def _colorize(self, text: str, color: str) -> str: - if self.use_colors: - return f"{color}{text}{Colors.RESET}" - return text - - def _format_time(self) -> str: - return datetime.now().strftime("%H:%M:%S") - - def _write(self, message: str, level: str = ""): - # 输出到控制台 - print(message, file=sys.stdout) - sys.stdout.flush() - - # 输出到文件 - if self.file_handler: - # 文件输出不带颜色 - clean_msg = message - for color in vars(Colors).values(): - if isinstance(color, str) and color.startswith('\033'): - clean_msg = clean_msg.replace(color, '') - timestamp = self._format_time() - self.file_handler.write(f"[{timestamp}] {level} {clean_msg}\n") - self.file_handler.flush() - - def set_phase(self, phase: str, total: int = 0): - self.current_phase = phase - self.total_items = total - self.current_item = 0 - self.progress(phase, 0, total) - - def progress(self, message: str = "", current: int = 0, total: int = 0): - if total > 0: - self.total_items = total - if current > 0: - self.current_item = current - - if self.total_items > 0: - percent = (self.current_item / self.total_items) * 100 - bar_length = 30 - filled = int(bar_length * self.current_item / self.total_items) - bar = '█' * filled + '░' * (bar_length - filled) - status = f"[{self._colorize(bar, Colors.BLUE)}] {self.current_item}/{self.total_items} ({percent:.1f}%)" - else: - status = "" - - msg = f"{self._colorize('▶', Colors.BRIGHT_CYAN)} {self.current_phase}" - if status: - msg += f" {status}" - if message: - msg += f" - {message}" - - # 使用 \r 实现进度更新 - sys.stdout.write('\r' + msg) - sys.stdout.flush() - - def debug(self, message: str, category: str = ""): - if self.level > LogLevel.DEBUG: - return - - prefix = self._colorize("DEBUG", Colors.GRAY) - if category: - prefix += f"[{self._colorize(category, Colors.CYAN)}]" - - msg = f"{self._colorize('├', Colors.GRAY)} {prefix}: {message}" - self._write(msg, "DEBUG") - - def info(self, message: str, category: str = ""): - prefix = self._colorize("INFO", Colors.GREEN) - if category: - prefix += f"[{self._colorize(category, Colors.CYAN)}]" - - msg = f"{self._colorize('├', Colors.GREEN)} {prefix}: {message}" - self._write(msg, "INFO") - - def warning(self, message: str, category: str = ""): - prefix = self._colorize("WARN", Colors.BRIGHT_YELLOW) - if category: - prefix += f"[{self._colorize(category, Colors.CYAN)}]" - - msg = f"{self._colorize('├', Colors.YELLOW)} {prefix}: {message}" - self._write(msg, "WARNING") - - def error(self, message: str, category: str = "", exception: Optional[Exception] = None): - prefix = self._colorize("ERROR", Colors.BRIGHT_RED) - if category: - prefix += f"[{self._colorize(category, Colors.CYAN)}]" - - msg = f"{self._colorize('├', Colors.RED)} {prefix}: {message}" - if exception: - msg += f"\n{self._colorize('│', Colors.RED)} Exception: {type(exception).__name__}: {exception}" - self._write(msg, "ERROR") - - def critical(self, message: str, category: str = ""): - prefix = self._colorize("CRITICAL", Colors.BG_RED + Colors.WHITE + Colors.BOLD) - if category: - prefix += f"[{self._colorize(category, Colors.CYAN)}]" - - msg = f"{self._colorize('╠', Colors.RED)} {prefix}: {message}" - self._write(msg, "CRITICAL") - - def success(self, message: str, category: str = ""): - prefix = self._colorize("SUCCESS", Colors.BRIGHT_GREEN) - if category: - prefix += f"[{self._colorize(category, Colors.CYAN)}]" - - msg = f"{self._colorize('├', Colors.GREEN)} {prefix}: {message}" - self._write(msg, "SUCCESS") - - def compile_error(self, message: str, file: str = "", line: int = 0, code: str = ""): - """编译错误格式化输出""" - header = self._colorize("编译错误", Colors.BG_RED + Colors.WHITE + Colors.BOLD) - - msg = f"\n{self._colorize('╔', Colors.RED)}{header}{self._colorize('╗', Colors.RED)}\n" - - if file and line > 0: - location = f"{self._colorize(file, Colors.CYAN)}:{self._colorize(str(line), Colors.YELLOW)}" - msg += f"{self._colorize('║', Colors.RED)} 位置:{location}\n" - - if code: - msg += f"{self._colorize('║', Colors.RED)} 代码:{self._colorize(code, Colors.WHITE)}\n" - - msg += f"{self._colorize('║', Colors.RED)} 错误:{self._colorize(message, Colors.BRIGHT_RED)}\n" - msg += f"{self._colorize('╚', Colors.RED)}{self._colorize('═' * 50, Colors.RED)}{self._colorize('╝', Colors.RED)}" - - self._write(msg, "ERROR") - - def compile_warning(self, message: str, file: str = "", line: int = 0, code: str = ""): - """编译警告格式化输出""" - header = self._colorize("警告", Colors.BG_YELLOW + Colors.BLACK) - - msg = f"\n{self._colorize('╔', Colors.YELLOW)}{header}{self._colorize('╗', Colors.YELLOW)}\n" - - if file and line > 0: - location = f"{self._colorize(file, Colors.CYAN)}:{self._colorize(str(line), Colors.YELLOW)}" - msg += f"{self._colorize('║', Colors.YELLOW)} 位置:{location}\n" - - if code: - msg += f"{self._colorize('║', Colors.YELLOW)} 代码:{self._colorize(code, Colors.WHITE)}\n" - - msg += f"{self._colorize('║', Colors.YELLOW)} 警告:{self._colorize(message, Colors.BRIGHT_YELLOW)}\n" - msg += f"{self._colorize('╚', Colors.YELLOW)}{self._colorize('═' * 50, Colors.YELLOW)}{self._colorize('╝', Colors.YELLOW)}" - - self._write(msg, "WARNING") - - def summary(self, stats: dict): - """输出编译摘要""" - header = self._colorize("编译摘要", Colors.BG_BLUE + Colors.WHITE + Colors.BOLD) - - msg = f"\n{self._colorize('╔', Colors.BLUE)}{header}{self._colorize('╗', Colors.BLUE)}\n" - - for key, value in stats.items(): - color = Colors.GREEN if value > 0 else Colors.WHITE - msg += f"{self._colorize('║', Colors.BLUE)} {key}: {self._colorize(str(value), color)}\n" - - msg += f"{self._colorize('╚', Colors.BLUE)}{self._colorize('═' * 50, Colors.BLUE)}{self._colorize('╝', Colors.BLUE)}" - - self._write(msg, "SUMMARY") - - def close(self): - if self.file_handler: - self.file_handler.close() - self.info(f"日志已保存到:{self.log_file}") - -# 全局日志实例 -_global_logger: Optional[Logger] = None - -def get_logger(name: str = "TransPyC", log_file: Optional[str] = None, - level: int = LogLevel.INFO, use_colors: bool = True) -> Logger: - global _global_logger - if _global_logger is None: - _global_logger = Logger(name, log_file, level, use_colors) - return _global_logger - -def set_logger(logger: Logger): - global _global_logger - _global_logger = logger - -# 便捷函数 -def debug(msg, category=""): - get_logger().debug(msg, category) - -def info(msg, category=""): - get_logger().info(msg, category) - -def warning(msg, category=""): - get_logger().warning(msg, category) - -def error(msg, category="", exception=None): - get_logger().error(msg, category, exception) - -def critical(msg, category=""): - get_logger().critical(msg, category) - -def success(msg, category=""): - get_logger().success(msg, category) - -def compile_error(msg, file="", line=0, code=""): - get_logger().compile_error(msg, file, line, code) - -def compile_warning(msg, file="", line=0, code=""): - get_logger().compile_warning(msg, file, line, code) - -def set_phase(phase, total=0): - get_logger().set_phase(phase, total) - -def progress(message="", current=0, total=0): - get_logger().progress(message, current, total) - -def summary(stats): - get_logger().summary(stats) +""" +TransPyC 彩色日志系统 +支持终端颜色输出和日志文件转储 +""" + +import sys +import os +from datetime import datetime +from typing import Optional + +# ANSI 颜色代码 +class Colors: + RESET = '\033[0m' + BOLD = '\033[1m' + DIM = '\033[2m' + UNDERLINE = '\033[4m' + + # 前景色 + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + + # 高亮前景色 + BRIGHT_RED = '\033[91m' + BRIGHT_GREEN = '\033[92m' + BRIGHT_YELLOW = '\033[93m' + BRIGHT_BLUE = '\033[94m' + BRIGHT_MAGENTA = '\033[95m' + BRIGHT_CYAN = '\033[96m' + + # 背景色 + BG_RED = '\033[41m' + BG_GREEN = '\033[42m' + BG_YELLOW = '\033[43m' + BG_BLUE = '\033[44m' + BG_MAGENTA = '\033[45m' + BG_CYAN = '\033[46m' + + # 渐变颜色(用于详细日志) + GRAY = '\033[90m' + +# 检查是否支持颜色 +def supports_color(): + if not hasattr(sys.stdout, 'isatty'): + return False + if not sys.stdout.isatty(): + return False + if os.environ.get('NO_COLOR'): + return False + if os.environ.get('FORCE_COLOR'): + return True + return True + +# 全局颜色支持标志 +USE_COLORS = supports_color() + +# 日志级别 +class LogLevel: + DEBUG = 0 + INFO = 1 + WARNING = 2 + ERROR = 3 + CRITICAL = 4 + +class Logger: + def __init__(self, name: str = "TransPyC", log_file: Optional[str] = None, + level: int = LogLevel.INFO, use_colors: bool = True): + self.name = name + self.level = level + self.use_colors = use_colors and USE_COLORS + self.log_file = log_file + self.file_handler = None + + if log_file: + os.makedirs(os.path.dirname(os.path.abspath(log_file)), exist_ok=True) + self.file_handler = open(log_file, 'w', encoding='utf-8') + + # 进度跟踪 + self.current_phase = "" + self.total_items = 0 + self.current_item = 0 + + def _colorize(self, text: str, color: str) -> str: + if self.use_colors: + return f"{color}{text}{Colors.RESET}" + return text + + def _format_time(self) -> str: + return datetime.now().strftime("%H:%M:%S") + + def _write(self, message: str, level: str = ""): + # 输出到控制台 + print(message, file=sys.stdout) + sys.stdout.flush() + + # 输出到文件 + if self.file_handler: + # 文件输出不带颜色 + clean_msg = message + for color in vars(Colors).values(): + if isinstance(color, str) and color.startswith('\033'): + clean_msg = clean_msg.replace(color, '') + timestamp = self._format_time() + self.file_handler.write(f"[{timestamp}] {level} {clean_msg}\n") + self.file_handler.flush() + + def set_phase(self, phase: str, total: int = 0): + self.current_phase = phase + self.total_items = total + self.current_item = 0 + self.progress(phase, 0, total) + + def progress(self, message: str = "", current: int = 0, total: int = 0): + if total > 0: + self.total_items = total + if current > 0: + self.current_item = current + + if self.total_items > 0: + percent = (self.current_item / self.total_items) * 100 + bar_length = 30 + filled = int(bar_length * self.current_item / self.total_items) + bar = '█' * filled + '░' * (bar_length - filled) + status = f"[{self._colorize(bar, Colors.BLUE)}] {self.current_item}/{self.total_items} ({percent:.1f}%)" + else: + status = "" + + msg = f"{self._colorize('▶', Colors.BRIGHT_CYAN)} {self.current_phase}" + if status: + msg += f" {status}" + if message: + msg += f" - {message}" + + # 使用 \r 实现进度更新 + sys.stdout.write('\r' + msg) + sys.stdout.flush() + + def debug(self, message: str, category: str = ""): + if self.level > LogLevel.DEBUG: + return + + prefix = self._colorize("DEBUG", Colors.GRAY) + if category: + prefix += f"[{self._colorize(category, Colors.CYAN)}]" + + msg = f"{self._colorize('├', Colors.GRAY)} {prefix}: {message}" + self._write(msg, "DEBUG") + + def info(self, message: str, category: str = ""): + prefix = self._colorize("INFO", Colors.GREEN) + if category: + prefix += f"[{self._colorize(category, Colors.CYAN)}]" + + msg = f"{self._colorize('├', Colors.GREEN)} {prefix}: {message}" + self._write(msg, "INFO") + + def warning(self, message: str, category: str = ""): + prefix = self._colorize("WARN", Colors.BRIGHT_YELLOW) + if category: + prefix += f"[{self._colorize(category, Colors.CYAN)}]" + + msg = f"{self._colorize('├', Colors.YELLOW)} {prefix}: {message}" + self._write(msg, "WARNING") + + def error(self, message: str, category: str = "", exception: Optional[Exception] = None): + prefix = self._colorize("ERROR", Colors.BRIGHT_RED) + if category: + prefix += f"[{self._colorize(category, Colors.CYAN)}]" + + msg = f"{self._colorize('├', Colors.RED)} {prefix}: {message}" + if exception: + msg += f"\n{self._colorize('│', Colors.RED)} Exception: {type(exception).__name__}: {exception}" + self._write(msg, "ERROR") + + def critical(self, message: str, category: str = ""): + prefix = self._colorize("CRITICAL", Colors.BG_RED + Colors.WHITE + Colors.BOLD) + if category: + prefix += f"[{self._colorize(category, Colors.CYAN)}]" + + msg = f"{self._colorize('╠', Colors.RED)} {prefix}: {message}" + self._write(msg, "CRITICAL") + + def success(self, message: str, category: str = ""): + prefix = self._colorize("SUCCESS", Colors.BRIGHT_GREEN) + if category: + prefix += f"[{self._colorize(category, Colors.CYAN)}]" + + msg = f"{self._colorize('├', Colors.GREEN)} {prefix}: {message}" + self._write(msg, "SUCCESS") + + def compile_error(self, message: str, file: str = "", line: int = 0, code: str = ""): + """编译错误格式化输出""" + header = self._colorize("编译错误", Colors.BG_RED + Colors.WHITE + Colors.BOLD) + + msg = f"\n{self._colorize('╔', Colors.RED)}{header}{self._colorize('╗', Colors.RED)}\n" + + if file and line > 0: + location = f"{self._colorize(file, Colors.CYAN)}:{self._colorize(str(line), Colors.YELLOW)}" + msg += f"{self._colorize('║', Colors.RED)} 位置:{location}\n" + + if code: + msg += f"{self._colorize('║', Colors.RED)} 代码:{self._colorize(code, Colors.WHITE)}\n" + + msg += f"{self._colorize('║', Colors.RED)} 错误:{self._colorize(message, Colors.BRIGHT_RED)}\n" + msg += f"{self._colorize('╚', Colors.RED)}{self._colorize('═' * 50, Colors.RED)}{self._colorize('╝', Colors.RED)}" + + self._write(msg, "ERROR") + + def compile_warning(self, message: str, file: str = "", line: int = 0, code: str = ""): + """编译警告格式化输出""" + header = self._colorize("警告", Colors.BG_YELLOW + Colors.BLACK) + + msg = f"\n{self._colorize('╔', Colors.YELLOW)}{header}{self._colorize('╗', Colors.YELLOW)}\n" + + if file and line > 0: + location = f"{self._colorize(file, Colors.CYAN)}:{self._colorize(str(line), Colors.YELLOW)}" + msg += f"{self._colorize('║', Colors.YELLOW)} 位置:{location}\n" + + if code: + msg += f"{self._colorize('║', Colors.YELLOW)} 代码:{self._colorize(code, Colors.WHITE)}\n" + + msg += f"{self._colorize('║', Colors.YELLOW)} 警告:{self._colorize(message, Colors.BRIGHT_YELLOW)}\n" + msg += f"{self._colorize('╚', Colors.YELLOW)}{self._colorize('═' * 50, Colors.YELLOW)}{self._colorize('╝', Colors.YELLOW)}" + + self._write(msg, "WARNING") + + def summary(self, stats: dict): + """输出编译摘要""" + header = self._colorize("编译摘要", Colors.BG_BLUE + Colors.WHITE + Colors.BOLD) + + msg = f"\n{self._colorize('╔', Colors.BLUE)}{header}{self._colorize('╗', Colors.BLUE)}\n" + + for key, value in stats.items(): + color = Colors.GREEN if value > 0 else Colors.WHITE + msg += f"{self._colorize('║', Colors.BLUE)} {key}: {self._colorize(str(value), color)}\n" + + msg += f"{self._colorize('╚', Colors.BLUE)}{self._colorize('═' * 50, Colors.BLUE)}{self._colorize('╝', Colors.BLUE)}" + + self._write(msg, "SUMMARY") + + def close(self): + if self.file_handler: + self.file_handler.close() + self.info(f"日志已保存到:{self.log_file}") + +# 全局日志实例 +_global_logger: Optional[Logger] = None + +def get_logger(name: str = "TransPyC", log_file: Optional[str] = None, + level: int = LogLevel.INFO, use_colors: bool = True) -> Logger: + global _global_logger + if _global_logger is None: + _global_logger = Logger(name, log_file, level, use_colors) + return _global_logger + +def set_logger(logger: Logger): + global _global_logger + _global_logger = logger + +# 便捷函数 +def debug(msg, category=""): + get_logger().debug(msg, category) + +def info(msg, category=""): + get_logger().info(msg, category) + +def warning(msg, category=""): + get_logger().warning(msg, category) + +def error(msg, category="", exception=None): + get_logger().error(msg, category, exception) + +def critical(msg, category=""): + get_logger().critical(msg, category) + +def success(msg, category=""): + get_logger().success(msg, category) + +def compile_error(msg, file="", line=0, code=""): + get_logger().compile_error(msg, file, line, code) + +def compile_warning(msg, file="", line=0, code=""): + get_logger().compile_warning(msg, file, line, code) + +def set_phase(phase, total=0): + get_logger().set_phase(phase, total) + +def progress(message="", current=0, total=0): + get_logger().progress(message, current, total) + +def summary(stats): + get_logger().summary(stats) + + +def safe_call(func, *args, context: str = "", **kwargs): + """安全调用函数,在异常时根据模式处理。 + + - strict 模式:重新抛出异常 + - relaxed 模式:打印彩色警告日志并返回 None + + Args: + func: 要调用的可调用对象 + *args, **kwargs: 传给 func 的参数 + context: 描述性上下文(用于日志消息) + + Returns: + func 的返回值,或 None(异常时) + """ + try: + return func(*args, **kwargs) + except Exception as e: + from lib.constants.config import mode as _ConfigMode + msg = f"{context}: {type(e).__name__}: {e}" if context else f"{type(e).__name__}: {e}" + if _ConfigMode == "strict": + raise + get_logger().warning(msg, "Exception") + return None diff --git a/lib/core/stub_generator.py b/lib/core/stub_generator.py index 76bd2e2..20d92fa 100644 --- a/lib/core/stub_generator.py +++ b/lib/core/stub_generator.py @@ -422,7 +422,7 @@ class CHeaderParser: self.variables[VarName] = { 'name': VarName, 'type': TypeStr, - 'is_ptr': IsPtr, + 'IsPtr': IsPtr, 'is_array': IsArray, 'array_size': int(ArraySize) if ArraySize and ArraySize.isdigit() else None, } @@ -452,7 +452,7 @@ class CHeaderParser: members.append({ 'name': MemberName, 'type': MemberType, - 'is_ptr': True, + 'IsPtr': True, }) continue simple_match = re.match(r'([\w\s]+?)\s+(\w+)', line) @@ -614,7 +614,7 @@ class PythonStubGenerator: if StructInfo['members']: for member in StructInfo['members']: MemberName = member['name'] - IsPtr = member.get('is_ptr', False) + IsPtr = member.get('IsPtr', False) IsArray = member.get('is_array', False) ArraySize = member.get('array_size') PyType = CTypeMapper.MapType(member['type'], IsPtr=IsPtr) @@ -636,7 +636,7 @@ class PythonStubGenerator: self.OutputLines.append(f'class {UnionName}(t.CUnion):') if UnionInfo['members']: for member in UnionInfo['members']: - PyType = CTypeMapper.MapType(member['type'], IsPtr=member.get('is_ptr', False)) + PyType = CTypeMapper.MapType(member['type'], IsPtr=member.get('IsPtr', False)) self.OutputLines.append(f' {member["name"]}: {PyType}') else: self.OutputLines.append(' pass') @@ -662,7 +662,7 @@ class PythonStubGenerator: if not self.parser.variables: return for VarName, VarInfo in self.parser.variables.items(): - PyType = CTypeMapper.MapType(VarInfo['type'], IsPtr=VarInfo['is_ptr'], IsArray=VarInfo['is_array']) + PyType = CTypeMapper.MapType(VarInfo['type'], IsPtr=VarInfo['IsPtr'], IsArray=VarInfo['is_array']) self.OutputLines.append(f'{VarName}: {PyType}') self.OutputLines.append('') diff --git a/lib/core/translator.py b/lib/core/translator.py index 55b2455..65dda2b 100644 --- a/lib/core/translator.py +++ b/lib/core/translator.py @@ -1,1726 +1,33 @@ # 核心转换逻辑 -import ast -import sys -import os -import llvmlite.ir as ir -sys.path.append(os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'lib', 'includes')) -from ..includes import c -from ..includes import t -from typing import Dict -from lib.utils.helpers import ( - DetectFileType -) -from lib.core.Handles import ( - IfHandle, ForHandle, WhileHandle, - AnnAssignHandle, - HandlesTypeMerge, ExprHandle, BodyHandle, - ReturnHandle, AssignHandle, AugAssignHandle, DeleteHandle, - WithHandle, TryHandle, AssertHandle, RaiseHandle, MatchHandle, - ExprUtils, ExprOpsHandle, ExprAttrHandle, ExprBuiltinHandle, - ExprAsmHandle, ExprFormatHandle, ExprLambdaHandle, ExprCallHandle, - CSpecialCallHandle, TSpecialCallHandle, - ClassHandle, - FunctionHandle, - ImportHandle -) -from lib.core.Handles.HandlesBase import CTypeInfo -from lib.core.SymbolTable import SymbolTable -from lib.core.SymbolNode import SymbolNode -from lib.constants.config import mode as _config_mode -from lib.core.LlvmCodeGenerator import LlvmCodeGenerator - - -def _strict_log(logger, msg): - """在 strict 模式下记录异常日志""" - if _config_mode == "strict": - logger(msg) - - -class Translator: - """代码转换器""" - - def __init__(self): - self.VarScopes = [{}] # 跟踪变量作用域,第一个是全局作用域 - self.FunctionReturnTypes: Dict[str, CTypeInfo] = {} # 记录函数名和其返回类型 - self.CurrentCReturnTypes: list = None # 当前函数的 CReturn 类型列表 - self._CurrentCpythonObjectClass: str = None # 当前正在处理的 CPython 对象类名 - self.FunctionDefCache: dict = {} # 函数定义缓存 - self.OriginalLines = [] # 原始代码行 - self.Content = '' - self.DebugFile = None # 调试输出文件路径 - self.IsHeader = False # 是否生成头文件(仅处理定义、宏、导入等,忽略函数体) - self.AnnotationModules = set() # 注解模块集合,用于识别类型定义模块 - self.Warnings = [] # 警告日志 - self._error_stack = [] # 错误栈,按顺序收集错误位置 - self.Errors = [] # 错误日志 - self.SliceCount = 0 # 切片计数 - self.SliceInfos = [] # 切片信息列表 - self.SliceLevel = 3 # 切片优化级别 - self.GeneratedTypes = set() # 在当前代码中生成的类型(struct/typedef) - self.EmbeddedAssignments = {} # {ClassName: [var1, var2, ...]} 嵌入的实例化变量 - self.TypedefAssignments = {} # {ClassName: [(var1, IsPtr), ...]} 嵌入的 typedef/指针变量 - self.ChainAssignmentArrays = [] # 链式赋值数组形式 [(ClassName, VarName, ArraySize_node), ...] - self.tree = None # 保存解析后的 AST 树 - self.LibraryPaths = ['.'] # 库搜索路径列表,默认包含当前目录 - self.InClass = False # 是否正在处理 class 定义 - self._UserTypeModules = {} - self._source_module_sig_files = {} - self._global_function_default_args: dict = {} - self.exception_registry: dict = {} - self.exception_parents: dict = {} - self._next_exception_code: int = 100 - - # 导出表 - from lib.core.export_table import ExportTable - self.ExportTable = ExportTable(filename='') - - self.SymbolTable = SymbolTable(self) - self.IfHandler = IfHandle(self) - self.ForHandler = ForHandle(self) - self.WhileHandler = WhileHandle(self) - self.AnnAssignHandler = AnnAssignHandle(self) - self.TypeMergeHandler = HandlesTypeMerge(self) - self.ExprHandler = ExprHandle(self) - self.ExprUtils = ExprUtils(self) - self.ExprOpsHandle = ExprOpsHandle(self) - self.ExprAttrHandle = ExprAttrHandle(self) - self.ExprBuiltinHandle = ExprBuiltinHandle(self) - self.ExprAsmHandle = ExprAsmHandle(self) - self.ExprFormatHandle = ExprFormatHandle(self) - self.ExprLambdaHandle = ExprLambdaHandle(self) - self.ExprCallHandle = ExprCallHandle(self) - self.CSpecialCallHandle = CSpecialCallHandle(self) - self.TSpecialCallHandle = TSpecialCallHandle(self) - self.ClassHandler = ClassHandle(self) - self.FunctionHandler = FunctionHandle(self) - self.ImportHandler = ImportHandle(self) - self.BodyHandler = BodyHandle(self) - self.ReturnHandler = ReturnHandle(self) - self.AssignHandler = AssignHandle(self) - self.AugAssignHandler = AugAssignHandle(self) - self.DeleteHandler = DeleteHandle(self) - self.WithHandler = WithHandle(self) - self.TryHandler = TryHandle(self) - self.AssertHandler = AssertHandle(self) - self.RaiseHandler = RaiseHandle(self) - self.MatchHandler = MatchHandle(self) - - def LogWarning(self, message: str, LineNum: int = None): - """记录警告 - - Args: - message: 警告消息 - LineNum: 行号(可选) - """ - warning = f"Warning: {message}" - if LineNum is not None: - warning += f" (line {LineNum})" - self.Warnings.append(warning) - - def LogError(self, message: str, LineNum: int = None): - """记录错误 - - Args: - message: 错误消息 - LineNum: 行号 - """ - print(f"[ERROR] {message}") - entry = {'message': message, 'line': LineNum} - self.Errors.append(entry) - - # 检查 config 中是否有 debug 文件 - DebugFile = None - if hasattr(self, 'config') and self.config: - DebugFile = getattr(self.config, 'debug', None) - - if DebugFile: - with open(DebugFile, 'a', encoding='utf-8') as f: - line_info = f' line {LineNum}' if LineNum else '' - f.write(f'[ERROR]{line_info}: {message}\n') - - def _LoadAnnotationModule(self, ModuleName: str, library_name: str = None, parse_method: str = 'auto'): - """加载注解模块并将 CType 子类注册为 typedef - - 支持两种模式: - 1. AST 模式:如果 ModuleName 是文件路径,解析文件提取 CType - 2. importlib 模式:如果 ModuleName 是模块名,导入模块提取 CType - - Args: - ModuleName: 模块名或文件路径 - library_name: 手动指定的库名称,用于注册到符号表。如果为 None,则从 ModuleName 推断 - parse_method: 解析方法,可选值: - - 'auto': 自动检测(默认) - - 'file': 强制使用 AST 模式(文件路径) - - 'module': 强制使用 importlib 模式(模块名) - """ - import importlib - import importlib.util - import sys - import os - - CurrentDir = os.path.dirname(os.path.abspath(__file__)) - ProjectRoot = os.path.dirname(os.path.dirname(os.path.dirname(CurrentDir))) - if ProjectRoot not in sys.path: - sys.path.insert(0, ProjectRoot) - - def register_to_symboltable(module, lib_name: str = None, source_file: str = None): - """将模块中的 CType 子类和 CEnum 类注册到符号表""" - from lib.includes.t import CType, CEnum - count = 0 - for AttrName in dir(module): - attr = getattr(module, AttrName) - # 优先检查是否是 CEnum 子类(枚举) - if isinstance(attr, type) and issubclass(attr, CEnum) and attr is not CEnum: - # 注册枚举类型 - EnumNode = SymbolNode.CreateClass( - name=AttrName, - TypeKind='enum', - lineno=0 - ) - EnumNode.set('enum_class', attr) - EnumNode.set('source', 'annotation_module') - EnumNode.set('library_name', lib_name) - EnumNode.set('file', source_file) - self.SymbolTable[AttrName] = EnumNode.attributes - if lib_name: - FullName = f'{lib_name}.{AttrName}' - full_EnumNode = SymbolNode.CreateClass( - name=FullName, - TypeKind='enum', - lineno=0 - ) - full_EnumNode.set('enum_class', attr) - full_EnumNode.set('source', 'annotation_module') - full_EnumNode.set('library_name', lib_name) - full_EnumNode.set('file', source_file) - self.SymbolTable[FullName] = full_EnumNode.attributes - # 枚举成员也需要注册 - for MemberName in dir(attr): - if not MemberName.startswith('_'): - member = getattr(attr, MemberName, None) - if isinstance(member, int): - MemberNode = CTypeInfo() - MemberNode.Name = MemberName - MemberNode.BaseType = t.CEnum(AttrName) - MemberNode.value = member - MemberNode.EnumName = AttrName - MemberNode.library_name = lib_name - MemberNode.IsEnumMember = True - self.SymbolTable[MemberName] = MemberNode - self.SymbolTable[f"{AttrName}.{MemberName}"] = MemberNode - self.SymbolTable[f"{AttrName}_{MemberName}"] = MemberNode - if lib_name: - self.SymbolTable[f"{lib_name}.{AttrName}.{MemberName}"] = MemberNode - self.SymbolTable[f"{lib_name}_{AttrName}_{MemberName}"] = MemberNode - count += 1 - # 检查是否是 CType 子类(typedef 别名) - elif isinstance(attr, type) and issubclass(attr, CType) and attr is not CType: - # 继承 CType 的类是类型别名(typedef),不是结构体 - # 使用手动指定的库名称作为前缀 - if lib_name: - FullName = f'{lib_name}.{AttrName}' - else: - FullName = AttrName - # 同时注册带前缀和不带前缀的名称(都是 typedef 别名) - TypedefNode = SymbolNode.CreateClass( - name=AttrName, - TypeKind='typedef', - lineno=0 - ) - TypedefNode.set('OriginalType', attr().CName) - TypedefNode.set('source', 'annotation_module') - TypedefNode.set('library_name', lib_name) - TypedefNode.set('file', source_file) - self.SymbolTable[AttrName] = TypedefNode.attributes - if lib_name and FullName != AttrName: - FullTypedef_node = SymbolNode.CreateClass( - name=FullName, - TypeKind='typedef', - lineno=0 - ) - FullTypedef_node.set('OriginalType', attr().CName) - FullTypedef_node.set('source', 'annotation_module') - FullTypedef_node.set('library_name', lib_name) - FullTypedef_node.set('file', source_file) - self.SymbolTable[FullName] = FullTypedef_node.attributes - count += 1 - # 检查是否是下划线前缀的 CType 子类(如 _CTypedef -> CTypedef) - elif AttrName.startswith('_') and len(AttrName) > 1: - PublicName = AttrName[1:] - PublicAttr = getattr(module, PublicName, None) - if PublicAttr is not None and not isinstance(attr, type): - continue - if isinstance(attr, type) and issubclass(attr, CType) and attr is not CType: - if PublicName not in self.SymbolTable: - if lib_name: - FullName = f'{lib_name}.{PublicName}' - else: - FullName = PublicName - TypedefNode = SymbolNode.CreateClass( - name=PublicName, - TypeKind='typedef', - lineno=0 - ) - TypedefNode.set('OriginalType', attr().CName) - TypedefNode.set('source', 'annotation_module') - TypedefNode.set('library_name', lib_name) - TypedefNode.set('file', source_file) - self.SymbolTable[PublicName] = TypedefNode.attributes - if lib_name and FullName != PublicName: - FullTypedef_node = SymbolNode.CreateClass( - name=FullName, - TypeKind='typedef', - lineno=0 - ) - FullTypedef_node.set('OriginalType', attr().CName) - FullTypedef_node.set('source', 'annotation_module') - FullTypedef_node.set('library_name', lib_name) - FullTypedef_node.set('file', source_file) - self.SymbolTable[FullName] = FullTypedef_node.attributes - count += 1 - return count - - # 确定解析方法 - use_file_mode = False - if parse_method == 'file': - use_file_mode = True - elif parse_method == 'module': - use_file_mode = False - else: # auto - use_file_mode = os.path.isfile(ModuleName) - - # 确定库名称 - lib_name = library_name - if lib_name is None: - if use_file_mode: - # 从文件路径推断库名称 - lib_name = os.path.splitext(os.path.basename(ModuleName))[0] - else: - # 模块名就是库名称 - lib_name = ModuleName - - # 根据解析方法加载模块 - if use_file_mode: - # AST 模式:使用 AST 解析文件,不执行代码 - try: - # 临时保存当前的 EmbeddedAssignments 和 TypedefAssignments - saved_embedded = self.EmbeddedAssignments.copy() - saved_typedef = self.TypedefAssignments.copy() - - # 清空 PD 收集(注解文件不应该收集 PD 语句) - self.EmbeddedAssignments = {} - self.TypedefAssignments = {} - - # 直接调用 ParsePythonFile 解析文件提取类型信息 - # 注意:这不会执行任何 Python 代码,只是解析 AST - # UpdateCurrentFile=False 表示不修改 CurrentFile - self.ParsePythonFile(ModuleName, UpdateCurrentFile=False) - - # 恢复主代码文件的 PD 收集 - self.EmbeddedAssignments = saved_embedded - self.TypedefAssignments = saved_typedef - - # 从文件名推断类型前缀(如 test_t -> test_t.xxx) - TypePrefix = lib_name - count = 0 - - # 检查符号表中新增的类型(注解文件解析后的所有 struct 类型) - # 需要检查这些类型是否继承自 CType,如果是则是 typedef 别名 - new_types = [] - for TypeName, TypeInfo in self.SymbolTable.items(): - if TypeInfo.IsStruct: - new_types.append(TypeName) - - # 再次遍历 AST,检测继承自 CType 的类 - try: - with open(ModuleName, 'r', encoding='utf-8') as f: - ann_content = f.read() - ann_tree = ast.parse(ann_content) - for node in ann_tree.body: - if isinstance(node, ast.ClassDef): - ClassName = node.name - # 检查是否有基类 - for base in node.bases: - if isinstance(base, ast.Name) and base.id == 'CType': - # 这个类继承自 CType,是 typedef 别名 - # 更新符号表中的类型为 typedef - if ClassName in self.SymbolTable: - TypedefNode = SymbolNode.CreateClass( - name=ClassName, - TypeKind='typedef', - lineno=0 - ) - TypedefNode.set('OriginalType', self.SymbolTable[ClassName].get('OriginalType', f'struct {ClassName}')) - TypedefNode.set('source', 'annotation_module') - TypedefNode.set('is_ctype_subclass', True) - self.SymbolTable[ClassName] = TypedefNode.attributes - except Exception as e: - pass # 忽略解析错误 - - # 为所有新增的类型添加库前缀和 source 标记 - for TypeName in new_types: - # 添加带前缀的类型名 - FullName = f'{TypePrefix}.{TypeName}' - TypeInfo = self.SymbolTable[TypeName].copy() - TypeInfo['source'] = 'annotation_module' - TypeInfo['original_name'] = TypeName - self.SymbolTable[FullName] = TypeInfo - count += 1 - - # 再次遍历 AST,查找注解文件中的 typedef 语句(AnnAssign with t.CTypedef) - # 注意:必须在类定义处理完之后再处理 typedef - typedef_annots = [] - # 查找 CEnum 成员变量(AnnAssign with t.CEnum | t.State 或 t.CEnum) - cEnumMembers = [] - try: - with open(ModuleName, 'r', encoding='utf-8') as f: - ann_content = f.read() - ann_tree = ast.parse(ann_content) - for node in ann_tree.body: - # 检测 xxx: t.CEnum 形式的枚举成员变量 - if isinstance(node, ast.AnnAssign): - if isinstance(node.target, ast.Name) and node.annotation: - TargetName = node.target.id - # 检查注解是否是 BinOp (Union) 或直接是 Attribute - IsCenum = False - if isinstance(node.annotation, ast.BinOp): - # 检查是否包含 CEnum - annot_str = ast.dump(node.annotation) - if 'CEnum' in annot_str: - IsCenum = True - elif isinstance(node.annotation, ast.Attribute): - # 直接是 t.CEnum - if node.annotation.attr == t.CEnum.__name__: - IsCenum = True - - if IsCenum: - # 检查值是否是 Constant (枚举成员值) - if node.value and isinstance(node.value, ast.Constant): - value = node.value.value - else: - value = None - cEnumMembers.append((TargetName, value)) - except Exception as e: - pass # 忽略解析错误 - - # 处理 CEnum 成员变量 - for TargetName, value in cEnumMembers: - # 注册枚举成员 - MemberNode = CTypeInfo() - MemberNode.Name = TargetName - MemberNode.BaseType = t.CEnum(TypePrefix) - MemberNode.value = value - MemberNode.EnumName = TypePrefix - MemberNode.library_name = TypePrefix - MemberNode.IsEnumMember = True - self.SymbolTable[TargetName] = MemberNode - self.SymbolTable[f"{TypePrefix}.{TargetName}"] = MemberNode - self.SymbolTable[f"{TypePrefix}_{TargetName}"] = MemberNode - - try: - with open(ModuleName, 'r', encoding='utf-8') as f: - ann_content = f.read() - ann_tree = ast.parse(ann_content) - for node in ann_tree.body: - # 检测 xxx: t.CTypedef = xxx 形式的 typedef 语句 - if isinstance(node, ast.AnnAssign): - if isinstance(node.target, ast.Name) and node.annotation and node.value: - TargetName = node.target.id - # 检查注解是否是 t.CTypedef - if isinstance(node.annotation, ast.Attribute): - if isinstance(node.annotation.value, ast.Name): - if node.annotation.value.id == 't' and node.annotation.attr == 'CTypedef': - # 检查值是否是 Name - if isinstance(node.value, ast.Name): - original_name = node.value.id - typedef_annots.append((TargetName, original_name)) - except Exception as e: - pass # 忽略解析错误 - - # 处理 typedef 注解 - for TargetName, original_name in typedef_annots: - # 检查原始类型是否在符号表中(带前缀或不带前缀) - orig_with_prefix = f'{TypePrefix}.{original_name}' - if orig_with_prefix in self.SymbolTable: - # 添加带前缀的 typedef 别名 - FullTypedef_name = f'{TypePrefix}.{TargetName}' - TypedefNode = SymbolNode.CreateClass( - name=FullTypedef_name, - TypeKind='typedef', - lineno=0 - ) - orig_entry = self.SymbolTable.get(orig_with_prefix, {}) - orig_type_str = f'struct {original_name}' - if isinstance(orig_entry, dict): - if orig_entry.get('type') == 'typedef': - orig_type_str = orig_entry.get('OriginalType', f'struct {original_name}') - elif orig_entry.get('type') == 'enum': - orig_type_str = f'enum {original_name}' - elif hasattr(orig_entry, 'IsTypedef') and orig_entry.IsTypedef: - orig_type_str = getattr(orig_entry, 'OriginalType', f'struct {original_name}') - elif hasattr(orig_entry, 'IsEnum') and orig_entry.IsEnum: - orig_type_str = f'enum {original_name}' - TypedefNode.set('OriginalType', orig_type_str) - TypedefNode.set('source', 'annotation_module') - TypedefNode.set('original_name', TargetName) - self.SymbolTable[FullTypedef_name] = TypedefNode.attributes - count += 1 - - self.AnnotationModules.add(lib_name) - return count - except Exception as e: - # 恢复 PD 收集 - self.EmbeddedAssignments = saved_embedded - self.TypedefAssignments = saved_typedef - self.LogWarning(f"AST模式加载注解模块失败: {ModuleName}, 错误: {e}") - return 0 - else: - # importlib 模式:导入模块 - try: - module = importlib.import_module(ModuleName) - count = register_to_symboltable(module, lib_name, None) - self.AnnotationModules.add(lib_name) - return count - except ImportError: - self.LogWarning(f"importlib模式加载注解模块失败: {ModuleName}") - return 0 - except Exception as e: - self.LogWarning(f"加载注解模块失败: {ModuleName}, 错误: {e}") - return 0 - - def _LoadAnnotationFiles(self, FilePaths: list): - """加载多个注解文件并注册到符号表 - - Args: - FilePaths: 文件路径列表,每个元素可以是: - - str: 文件路径或模块名 - - tuple: (path, options) 或 (path, library_name, parse_method) - """ - for item in FilePaths: - if isinstance(item, tuple): - if len(item) >= 3: - path, library_name, parse_method = item[:3] - count = self._LoadAnnotationModule(path, library_name, parse_method) - elif len(item) == 2: - path, library_name = item - count = self._LoadAnnotationModule(path, library_name, 'auto') - else: - count = self._LoadAnnotationModule(item) - else: - count = self._LoadAnnotationModule(item) - - # 别名,保持向后兼容 - LoadAnnotationFiles = _LoadAnnotationFiles - - def SetDebugFile(self, FilePath): - """设置调试输出文件""" - self.DebugFile = FilePath - - def DebugPrint(self, *args, **kwargs): - """输出调试信息到文件""" - if self.DebugFile: - with open(self.DebugFile, 'a', encoding='utf-8') as f: - print(*args, file=f, **kwargs) - - def ParseHelperFiles(self, HelperFiles, encoding='utf-8'): - """解析辅助文件,提取符号信息 - - 支持 .py, .c, .h 和 .symbin 文件 - """ - for FilePath in HelperFiles: - ext = DetectFileType(FilePath) - if ext == '.py': - self.ParsePythonFile(FilePath, encoding, UpdateCurrentFile=False) - elif ext == '.c': - pass # .c 文件解析已移除,不再使用旧的正则解析路径 - elif FilePath.endswith('.symbin'): - self.LoadSymbinFile(FilePath) - - def LoadSymbinFile(self, FilePath): - """从.symbin文件加载符号表 - - Args: - FilePath: .symbin文件路径 - """ - try: - with open(FilePath, 'rb') as f: - data = f.read() - - # 导入序列化函数(避免循环导入) - import sys - import os - import json - import struct - - # 解析二进制格式 - if len(data) < 4: - print(f"Warning: Invalid symbin file (too short): {FilePath}") - return - - # 解析4字节长度头(小端序) - length = struct.unpack(' 1: - # 第二个参数应该是一个列表 - dim_arg = PostdefNode.args[1] - if isinstance(dim_arg, ast.List): - for DimExpr in dim_arg.elts: - dimensions.append(DimExpr) - - # 如果没有从 Postdefinition 参数中获取维度,尝试从类型注解中的 Subscript 获取 - # 例如:memory_block_t[MAX_ORDER + 1] | t.CPtr - if not dimensions: - def extract_subscript_dims(node): - """递归提取 Subscript 节点的维度""" - dims = [] - if isinstance(node, ast.Subscript): - # 提取当前维度 - if isinstance(node.slice, ast.Constant): - dims.append(ast.Constant(value=node.slice.value)) - elif isinstance(node.slice, ast.Name): - dims.append(ast.Name(id=node.slice.id, ctx=ast.Load())) - elif isinstance(node.slice, ast.BinOp): - dims.append(node.slice) - # 递归提取更外层的维度 - dims.extend(extract_subscript_dims(node.value)) - elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr): - # 处理 Type | t.CPtr 的情况,检查左侧 - dims.extend(extract_subscript_dims(node.left)) - return dims - - # 从注解中提取维度 - subscript_dims = extract_subscript_dims(annotation) - if subscript_dims: - # 反转维度顺序(从内到外) - dimensions = list(reversed(subscript_dims)) - - # 获取赋值值 - value = None - if hasattr(NextNode, 'value') and NextNode.value is not None: - value = NextNode.value - - # 添加到对应的 assignments - # 对于 t.Postdefinition(...),只有包含 CTypedef 或 CPtr 时才视为 typedef 类型 - if HasCtypedef or IsPtr: - if ClassKey not in self.TypedefAssignments: - self.TypedefAssignments[ClassKey] = [] - # 如果有维度信息,使用字典存储 - if dimensions: - self.TypedefAssignments[ClassKey].append({ - 'name': TargetName, - 'IsPtr': IsPtr, - 'dimensions': dimensions, - 'value': value - }) - else: - self.TypedefAssignments[ClassKey].append((TargetName, IsPtr)) - else: - if ClassKey not in self.EmbeddedAssignments: - self.EmbeddedAssignments[ClassKey] = [] - # 如果有维度信息,使用字典存储 - if dimensions: - self.EmbeddedAssignments[ClassKey].append({ - 'name': TargetName, - 'dimensions': dimensions, - 'value': value - }) - else: - self.EmbeddedAssignments[ClassKey].append(TargetName) - - # 检查是否有 __set_default__ 初始化 - if '__set_default__' in original_AnnotationStr: - self._handle_set_default_in_parse(ClassKey, TargetName, ClassName, NextNode) - j += 1 - continue - # 再处理旧格式:xxx: t.CTypedef = xxx 或 xxx: t.CPtr = xxx - # 注意:这种格式的 typedef 不应该被合并到结构体定义中, - # 而应该生成独立的 typedef 语句,所以不添加到 TypedefAssignments - elif NextNode.annotation and isinstance(NextNode.annotation, ast.Attribute): - if isinstance(NextNode.annotation.value, ast.Name): - annot_id = NextNode.annotation.value.id - annot_attr = NextNode.annotation.attr - if annot_id == 't' and NextNode.value: - if isinstance(NextNode.value, ast.Name): - ValueName = NextNode.value.id - if ValueName == ClassName: - # 检查是 CTypedef 还是 CPtr - if annot_attr == t.CPtr.__name__: - # t.CPtr 表示指针变量,加入 TypedefAssignments,设置 IsPtr=True - if ClassKey not in self.TypedefAssignments: - self.TypedefAssignments[ClassKey] = [] - self.TypedefAssignments[ClassKey].append((TargetName, True)) - j += 1 - continue - # 注意:t.CTypedef 不在这里处理,由 HandlesAnnAssign 生成独立的 typedef 语句 - # 如果不是特殊赋值,停止收集 - break - - i = j - continue - - i += 1 - - # 提取类定义(作为结构体) - for node in ast.walk(tree): - if isinstance(node, ast.ClassDef): - ClassName = node.name - # 先把类名加入 GeneratedTypes,这样 GetTypeName 可以正确识别 - self.GeneratedTypes.add(ClassName) - - # 检测是否是 CEnum - IsCenum = False - for base in node.bases: - if isinstance(base, ast.Attribute): - BaseStr = ast.dump(base) - if 'CEnum' in BaseStr or 'REnum' in BaseStr: - IsCenum = True - break - elif isinstance(base, ast.Name): - if 'CEnum' in base.id or 'REnum' in base.id: - IsCenum = True - break - - # 检测是否有 @t.Object 装饰器或继承自 t.Object - IsCpythonObject = False - if hasattr(node, 'decorator_list') and node.decorator_list: - for decorator in node.decorator_list: - if isinstance(decorator, ast.Attribute): - if (hasattr(decorator.value, 'id') and - decorator.value.id == 't' and - decorator.attr == 'Object'): - IsCpythonObject = True - break - elif isinstance(decorator, ast.Call): - if isinstance(decorator.func, ast.Attribute): - if (hasattr(decorator.func.value, 'id') and - decorator.func.value.id == 't' and - decorator.func.attr == 'Object'): - IsCpythonObject = True - break - elif isinstance(decorator.func, ast.Name): - if decorator.func.id == 'Object': - IsCpythonObject = True - break - elif isinstance(decorator, ast.Name): - if decorator.id == 'Object': - IsCpythonObject = True - break - if not IsCpythonObject and hasattr(node, 'bases') and node.bases: - for base in node.bases: - if isinstance(base, ast.Attribute): - if (hasattr(base.value, 'id') and - base.value.id == 't' and - base.attr == 'Object'): - IsCpythonObject = True - break - elif isinstance(base, ast.Name): - if base.id == 'Object': - IsCpythonObject = True - break - - if IsCenum: - # 注册为 enum 类型 - EnumNode = SymbolNode.CreateClass( - name=ClassName, - TypeKind='enum', - lineno=0 - ) - EnumNode.set('file', '') - self.SymbolTable[ClassName] = EnumNode.attributes - - # 注册 enum 成员 - for item in node.body: - if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name): - MemberName = item.target.id - MemberNode = CTypeInfo() - MemberNode.Name = MemberName - MemberNode.BaseType = t.CEnum(ClassName) - MemberNode.value = None - MemberNode.EnumName = ClassName - MemberNode.library_name = None - MemberNode.IsEnumMember = True - self.SymbolTable[MemberName] = MemberNode - self.SymbolTable[f"{ClassName}.{MemberName}"] = MemberNode - self.SymbolTable[f"{ClassName}_{MemberName}"] = MemberNode - - continue - - # 检测是否是 Anonymous - IsAnonymous = False - - # 提取结构体成员信息 - members = {} - for item in node.body: - if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name): - VarName = item.target.id - try: - TypeInfo = self.TypeMergeHandler.GetCTypeInfo(item.annotation) - if TypeInfo is None: - TypeInfo = CTypeInfo() - TypeInfo.BaseType = t.CInt() - IsPtr = TypeInfo.IsPtr - if not IsPtr: - if isinstance(item.annotation, ast.BinOp) and isinstance(item.annotation.op, ast.BitOr): - LeftStr = ast.dump(item.annotation.left) - RightStr = ast.dump(item.annotation.right) - if 'CPtr' in LeftStr or 'CPtr' in RightStr: - IsPtr = True - dims = [] - if hasattr(item.annotation, 'slice') and isinstance(item.annotation.slice, ast.Constant): - if isinstance(item.annotation.value, ast.Name): - if item.annotation.value.id == 't': - if hasattr(item.annotation, 'slice'): - try: - dims.append(int(item.annotation.slice.value)) - except Exception as _e: - _strict_log(self.LogError, f"解析数组维度失败: {_e}") - pass - MemberInfo = TypeInfo.Copy() - if dims: - MemberInfo.ArrayDims = [str(d) for d in dims] - members[VarName] = MemberInfo - except Exception as _e: - _strict_log(self.LogError, f"解析结构体成员失败: {_e}") - pass - StructNode = SymbolNode.CreateClass( - name=ClassName, - TypeKind='struct', - members=members, - lineno=0, - IsCpythonObject=IsCpythonObject - ) - StructNode.set('file', '') - StructNode.set('IsAnonymous', IsAnonymous) - self.SymbolTable[ClassName] = StructNode.attributes - elif isinstance(node, ast.FunctionDef): - FuncName = node.name - FuncNode = SymbolNode.CreateClass( - name=FuncName, - TypeKind='function', - lineno=0 - ) - FuncNode.set('file', '') - self.SymbolTable[FuncName] = FuncNode.attributes - elif isinstance(node, ast.AnnAssign): - if isinstance(node.target, ast.Name): - VarName = node.target.id - # 检查是否是 t.CTypedef 格式,如果是则跳过(由 HandleClassDef 处理) - is_ctypedef = False - if node.annotation: - if isinstance(node.annotation, ast.Attribute): - if isinstance(node.annotation.value, ast.Name): - if node.annotation.value.id == 't' and node.annotation.attr == 'CTypedef': - is_ctypedef = True - elif isinstance(node.annotation, ast.BinOp) and isinstance(node.annotation.op, ast.BitOr): - def _has_ctype(ann): - if isinstance(ann, ast.Attribute): - return hasattr(ann.value, 'id') and ann.value.id == 't' and ann.attr == 'CTypedef' - if isinstance(ann, ast.BinOp) and isinstance(ann.op, ast.BitOr): - return _has_ctype(ann.left) or _has_ctype(ann.right) - if isinstance(ann, ast.Subscript): - return _has_ctype(ann.value) - return False - if _has_ctype(node.annotation): - is_ctypedef = True - if not is_ctypedef: - IsPtr = False - if node.annotation: - try: - TypeInfo = self.TypeMergeHandler.GetCTypeInfo(node.annotation) - IsPtr = TypeInfo.IsPtr if TypeInfo else False - except Exception as _e: - _strict_log(self.LogError, f"获取类型信息失败(ParsePythonFile): {_e}") - pass - var_node = SymbolNode.CreateClass( - name=VarName, - TypeKind='variable', - lineno=0 - ) - var_node.set('IsPtr', IsPtr) - var_node.set('file', '') - self.SymbolTable[VarName] = var_node.attributes - except Exception as e: - print(f'Warning: Failed to parse Python file {FilePath}: {e}') - - # ParseCFile 已移除 - .h/.c 文件的旧正则解析路径不再使用 - # 类型解析现在直接通过 CTypeInfo 对象进行,不经过中间字符串格式 - - def GenerateLlvmDirect(self, Tree): - Gen = self.LlvmGen - - # 预扫描:为所有 -> str 注解的函数注册正确的返回类型 i8* - # 这样在类方法中调用这些函数时,前向声明会使用正确的类型 - for Node in ast.iter_child_nodes(Tree): - if isinstance(Node, ast.FunctionDef): - if Node.returns and isinstance(Node.returns, ast.Name) and Node.returns.id == 'str': - Gen.known_return_types[Node.name] = ir.PointerType(ir.IntType(8)) - - # 首先收集所有 CDefine 常量,确保类定义中可以引用 - def _extract_call_const_val(node): - if isinstance(node, ast.Call): - if isinstance(node.func, ast.Attribute): - if getattr(node.func.value, 'id', None) == 't': - if node.args and isinstance(node.args[0], ast.Constant): - return node.args[0].value - elif isinstance(node.func, ast.Name): - if node.args and isinstance(node.args[0], ast.Constant): - return node.args[0].value - return None - - for Node in ast.iter_child_nodes(Tree): - if isinstance(Node, ast.AnnAssign) and isinstance(Node.target, ast.Name) and Node.value: - TypeInfo = self.TypeMergeHandler.GetCTypeInfo(Node.annotation) - if TypeInfo and TypeInfo.BaseType and hasattr(TypeInfo.BaseType, 'CName') and TypeInfo.BaseType.CName == '#define': - val = None - if isinstance(Node.value, ast.Constant): - val = Node.value.value - else: - val = _extract_call_const_val(Node.value) - if val is not None: - if not hasattr(Gen, '_define_constants'): - Gen._define_constants = {} - Gen._define_constants[Node.target.id] = val - from lib.core.Handles.HandlesBase import CTypeInfo as _CTypeInfo - sym_info = _CTypeInfo() - sym_info.IsDefine = True - sym_info.DefineValue = val - self.SymbolTable[Node.target.id] = sym_info - elif isinstance(Node, ast.Assign): - for target in Node.targets: - if isinstance(target, ast.Name): - TypeInfo = None - if Node.type_comment: - try: - tc_ast = ast.parse(Node.type_comment, mode='eval') - TypeInfo = self.TypeMergeHandler.GetCTypeInfo(tc_ast.body) - except Exception as _e: - _strict_log(self.LogError, f"解析类型注释失败: {_e}") - pass - if TypeInfo and TypeInfo.BaseType and hasattr(TypeInfo.BaseType, 'CName') and TypeInfo.BaseType.CName == '#define': - val = None - if isinstance(Node.value, ast.Constant): - val = Node.value.value - else: - val = _extract_call_const_val(Node.value) - if val is not None: - if not hasattr(Gen, '_define_constants'): - Gen._define_constants = {} - Gen._define_constants[target.id] = val - from lib.core.Handles.HandlesBase import CTypeInfo as _CTypeInfo - sym_info = _CTypeInfo() - sym_info.IsDefine = True - sym_info.DefineValue = val - self.SymbolTable[target.id] = sym_info - - # 预扫描所有顶层函数定义,填充 FunctionDefCache(不创建 LLVM 声明) - # 这样类方法编译时遇到未声明的函数可以按需前向声明 - for Node in ast.iter_child_nodes(Tree): - if isinstance(Node, ast.FunctionDef): - FuncName = Node.name - if FuncName not in self.FunctionDefCache: - self.FunctionDefCache[FuncName] = Node - - # 首先处理所有导入语句,确保模块在类型解析前被加载 - for Node in ast.iter_child_nodes(Tree): - Gen._set_node_info(Node) - try: - if isinstance(Node, ast.Import): - self.ImportHandler._EmitImportDeclarationsLlvm(Node, Gen) - elif isinstance(Node, ast.ImportFrom): - self.ImportHandler._EmitImportFromDeclarationsLlvm(Node, Gen) - except Exception as e: - lineno = getattr(Node, 'lineno', 0) - source_line = Gen._get_source_line(lineno) - src_file = getattr(Gen, '_current_source_file', '') - src_path = src_file if src_file else 'unknown' - line_info = "源代码 (%s, line %d)" % (src_path, lineno) - if source_line: - line_info += ":\n %d | %s" % (lineno, source_line) - self._error_stack.append((type(e).__name__, str(e), line_info)) - - # 预创建全局变量(带初始化器),确保类方法编译时能引用全局数组等 - Gen._current_tree = Tree - for Node in ast.iter_child_nodes(Tree): - if isinstance(Node, ast.AnnAssign): - self.AssignHandler._EmitGlobalAnnAssignLlvm(Node, Gen) - elif isinstance(Node, ast.Assign): - self.AssignHandler._EmitGlobalAssignLlvm(Node, Gen) - - # 前向声明所有顶层函数,确保类方法编译时能找到这些函数 - for Node in ast.iter_child_nodes(Tree): - if isinstance(Node, ast.FunctionDef): - self.FunctionHandler._EmitFunctionForwardDeclLlvm(Node, Gen) - - # 首先处理所有类定义(包括 CUnion),确保类型定义在使用前完成 - for Node in ast.iter_child_nodes(Tree): - if isinstance(Node, ast.ClassDef): - self.ClassHandler._EmitClassLlvm(Node, Gen) - - Gen._generate_structs() - Gen._create_Vtable_globals() - - for Node in ast.iter_child_nodes(Tree): - Gen._set_node_info(Node) - try: - if isinstance(Node, ast.Import): - continue - elif isinstance(Node, ast.ImportFrom): - continue - elif isinstance(Node, ast.ClassDef): - continue - elif isinstance(Node, ast.FunctionDef): - self.FunctionHandler._EmitFunctionLlvm(Node, Gen) - elif isinstance(Node, ast.AnnAssign): - self.AssignHandler._EmitGlobalAnnAssignLlvm(Node, Gen) - elif isinstance(Node, ast.Assign): - self.AssignHandler._EmitGlobalAssignLlvm(Node, Gen) - elif isinstance(Node, ast.If): - pass - elif isinstance(Node, ast.Expr): - self._HandleModuleLevelExprLlvm(Node, Gen) - except Exception as e: - lineno = getattr(Node, 'lineno', 0) - source_line = Gen._get_source_line(lineno) - src_file = getattr(Gen, '_current_source_file', '') - src_path = src_file if src_file else 'unknown' - line_info = "源代码 (%s, line %d)" % (src_path, lineno) - if source_line: - line_info += ":\n %d | %s" % (lineno, source_line) - self._error_stack.append((type(e).__name__, str(e), line_info)) - raise - Gen._set_Vtable_initializers() - # 执行 DecoratorPass:为带自定义装饰器的函数生成 wrapper - from lib.core.DecoratorPass import run as _run_decorator_pass - _run_decorator_pass(Gen) - ir_code = Gen.finalize() - return ir_code - - def _HandleModuleLevelExprLlvm(self, Node, Gen): - if not isinstance(Node.value, ast.Call): - return - call = Node.value - if not isinstance(call.func, ast.Attribute): - return - if not isinstance(call.func.value, ast.Name) or call.func.value.id != 'c': - return - func_name = call.func.attr - if func_name == 'LLVMIR': - self._HandleModuleLevelLLVMIR(call, Gen) - - def _HandleModuleLevelLLVMIR(self, Node, Gen): - if not Node.args: - return - first_arg = Node.args[0] - if isinstance(first_arg, ast.Constant) and isinstance(first_arg.value, str): - ir_text = first_arg.value - elif isinstance(first_arg, ast.JoinedStr): - parts = [] - for value in first_arg.values: - if isinstance(value, ast.Constant) and isinstance(value.value, str): - parts.append(value.value) - elif isinstance(value, ast.FormattedValue): - parts.append('') - ir_text = ''.join(parts) - else: - return - self._InsertModuleLevelLLVMIR(Gen, ir_text) - - def _InsertModuleLevelLLVMIR(self, Gen, ir_text): - import re - for line in ir_text.strip().split('\n'): - line = line.strip() - if not line: - continue - module_flags_match = re.match(r'!llvm\.module\.flags\s*=\s*!\{(!\d+)\}', line) - if module_flags_match: - ref = module_flags_match.group(1) - if not hasattr(Gen, '_pending_module_flags'): - Gen._pending_module_flags = [] - Gen._pending_module_flags_refs = ref - continue - metadata_match = re.match(r'(!\d+)\s*=\s*!\{(.+)\}', line) - if metadata_match: - md_id = metadata_match.group(1) - md_body = metadata_match.group(2) - fields = [] - for field_str in re.split(r',\s*', md_body): - field_str = field_str.strip() - if not field_str: - continue - int_m = re.match(r'^i32\s+(\d+)$', field_str) - if int_m: - fields.append(ir.Constant(ir.IntType(32), int(int_m.group(1)))) - continue - str_m = re.match(r'^"([^"]*)"$', field_str) - if str_m: - fields.append(ir.MetaDataString(Gen.module, str_m.group(1))) - continue - mdstr_m = re.match(r'^!"([^"]*)"$', field_str) - if mdstr_m: - fields.append(ir.MetaDataString(Gen.module, mdstr_m.group(1))) - continue - int_m2 = re.match(r'^(\d+)$', field_str) - if int_m2: - fields.append(ir.Constant(ir.IntType(32), int(int_m2.group(1)))) - continue - ref_m = re.match(r'^(!\d+)$', field_str) - if ref_m: - fields.append(ref_m.group(1)) - continue - if fields: - if not hasattr(Gen, '_pending_metadata'): - Gen._pending_metadata = [] - Gen._pending_metadata.append((md_id, fields)) - continue - self._FlushModuleMetadata(Gen) - - def _FlushModuleMetadata(self, Gen): - if not hasattr(Gen, '_pending_metadata') or not Gen._pending_metadata: - return - md_map = {} - for md_id, fields in Gen._pending_metadata: - resolved = [] - for f in fields: - if isinstance(f, str) and f.startswith('!'): - ref = md_map.get(f) - if ref: - resolved.append(ref) - else: - resolved.append(f) - md_value = Gen.module.add_metadata(resolved) - md_map[md_id] = md_value - if hasattr(Gen, '_pending_module_flags_refs'): - ref = Gen._pending_module_flags_refs - md_node = md_map.get(ref) - if md_node: - Gen.module.add_named_metadata('llvm.module.flags', md_node) - Gen._pending_metadata = [] - Gen._pending_module_flags_refs = None - - def _BuildArrayInitConstants(self, value_node, ElemType, elem_type_node, ArrayCount, Gen): - from lib.core.Handles.HandlesAssign import AssignHandle - _zv = AssignHandle._zero_value(ElemType) - _fallback = _zv if _zv is not None else ir.Constant(ElemType, ir.Undefined) - if not isinstance(value_node, (ast.List, ast.Set)): - return None - if isinstance(ElemType, ir.ArrayType): - constants = [] - for elt in value_node.elts: - if isinstance(elt, (ast.List, ast.Set)): - inner_consts = self._BuildMultiDimArrayInitConstants(elt, ElemType, Gen) - if inner_consts: - try: - constants.append(ir.Constant(ElemType, inner_consts)) - except Exception: # fallback to _fallback on constant construction failure - constants.append(_fallback) - else: - constants.append(_fallback) - else: - constants.append(_fallback) - while len(constants) < ArrayCount: - constants.append(_fallback) - return constants[:ArrayCount] - StructName = None - if isinstance(elem_type_node, ast.Name) and elem_type_node.id in Gen.structs: - StructName = elem_type_node.id - constants = [] - for elt in value_node.elts: - if StructName and isinstance(elt, ast.Call) and isinstance(elt.func, ast.Name) and elt.func.id == StructName: - const = self.ClassHandler._BuildStructConstant(elt, StructName, Gen) - if const: - constants.append(const) - else: - constants.append(_fallback) - elif isinstance(elt, ast.Constant): - const = self.ClassHandler._BuildScalarConstant(elt, ElemType) - if const: - constants.append(const) - else: - constants.append(_fallback) - elif isinstance(elt, ast.UnaryOp): - const = self.ClassHandler._BuildScalarConstant(elt, ElemType) - if const: - constants.append(const) - else: - constants.append(_fallback) - elif isinstance(elt, ast.Call) and isinstance(elt.func, ast.Name) and elt.func.id == 'chr': - if elt.args and isinstance(elt.args[0], ast.Constant) and isinstance(elt.args[0].value, int): - try: - constants.append(ir.Constant(ElemType, elt.args[0].value & 0xFF)) - except Exception: # fallback to _fallback on constant construction failure - constants.append(_fallback) - else: - constants.append(_fallback) - elif isinstance(elt, ast.Call) and isinstance(elt.func, ast.Name) and elt.func.id == 'ord': - if elt.args and isinstance(elt.args[0], ast.Constant) and isinstance(elt.args[0].value, str) and len(elt.args[0].value) == 1: - try: - constants.append(ir.Constant(ElemType, ord(elt.args[0].value))) - except Exception: # fallback to _fallback on constant construction failure - constants.append(_fallback) - else: - constants.append(_fallback) - else: - const_val = self._try_eval_const_call(elt, Gen) - if const_val is not None: - try: - constants.append(ir.Constant(ElemType, const_val)) - except Exception: # fallback to _fallback on constant construction failure - constants.append(_fallback) - else: - constants.append(_fallback) - while len(constants) < ArrayCount: - constants.append(_fallback) - return constants[:ArrayCount] - - def _try_eval_const_call(self, node, Gen): - import ast - if isinstance(node, ast.Call): - func_name = None - if isinstance(node.func, ast.Name): - func_name = node.func.id - elif isinstance(node.func, ast.Attribute): - func_name = node.func.attr - if func_name: - arg_vals = [] - for arg in node.args: - v = self._try_eval_const_expr(arg, Gen) - if v is None: - return None - arg_vals.append(v) - if func_name == 'COLOR_RGB' and len(arg_vals) == 3: - r, g, b = arg_vals - return (255 << 24) | (int(b) << 16) | (int(g) << 8) | int(r) - if func_name in Gen._define_constants: - return Gen._define_constants[func_name] - for key in Gen.functions: - if key.endswith(f'__{func_name}'): - return None - return None - return self._try_eval_const_expr(node, Gen) - - def _try_eval_const_expr(self, node, Gen): - import ast - if isinstance(node, ast.Constant): - return node.value - elif isinstance(node, ast.BinOp): - left = self._try_eval_const_expr(node.left, Gen) - right = self._try_eval_const_expr(node.right, Gen) - if left is None or right is None: - return None - if isinstance(node.op, ast.Add): - return left + right - elif isinstance(node.op, ast.Sub): - return left - right - elif isinstance(node.op, ast.Mult): - return left * right - elif isinstance(node.op, ast.LShift): - return left << right - elif isinstance(node.op, ast.RShift): - return left >> right - elif isinstance(node.op, ast.BitOr): - return left | right - elif isinstance(node.op, ast.BitAnd): - return left & right - elif isinstance(node.op, ast.BitXor): - return left ^ right - elif isinstance(node, ast.UnaryOp): - operand = self._try_eval_const_expr(node.operand, Gen) - if operand is None: - return None - if isinstance(node.op, ast.USub): - return -operand - elif isinstance(node.op, ast.Invert): - return ~operand - elif isinstance(node, ast.Name): - if node.id in getattr(Gen, '_define_constants', {}): - return Gen._define_constants[node.id] - return None - - def _BuildMultiDimArrayInitConstants(self, value_node, ArrayType, Gen): - from lib.core.Handles.HandlesAssign import AssignHandle - inner_type = ArrayType.element - count = ArrayType.count - elts = list(value_node.elts) if hasattr(value_node, 'elts') else [] - _zv = AssignHandle._zero_value(inner_type) - _fallback = _zv if _zv is not None else ir.Constant(inner_type, ir.Undefined) - constants = [] - for elt in elts: - if isinstance(inner_type, ir.ArrayType): - if isinstance(elt, (ast.List, ast.Set)): - inner_consts = self._BuildMultiDimArrayInitConstants(elt, inner_type, Gen) - if inner_consts: - constants.append(ir.Constant(inner_type, inner_consts)) - else: - constants.append(_fallback) - else: - constants.append(_fallback) - elif isinstance(elt, ast.Constant): - const = self.ClassHandler._BuildScalarConstant(elt, inner_type) - if const: - constants.append(const) - else: - constants.append(_fallback) - elif isinstance(elt, ast.UnaryOp): - const = self.ClassHandler._BuildScalarConstant(elt, inner_type) - if const: - constants.append(const) - else: - constants.append(_fallback) - else: - constants.append(_fallback) - while len(constants) < count: - constants.append(_fallback) - return constants[:count] - - def GenerateCCode(self, Tree, target='llvm'): - """生成代码 - - Args: - Tree: Python AST 树 - target: 目标代码类型,仅支持 'llvm' - - Returns: - 生成的代码字符串 - """ - self._generated_vars = set() - self.VarScopes = [{}] # 全局作用域 - - # 预扫描 import 语句,注册别名,确保类型解析时能正确解析模块别名 - if not getattr(self, '_import_aliases', None): - self._import_aliases = {} - if not getattr(self, '_imported_modules', None): - self._imported_modules = set() - for Node in ast.iter_child_nodes(Tree): - if isinstance(Node, ast.Import): - for alias in Node.names: - name = alias.name - if name in ('c', 't'): - continue - self._imported_modules.add(name) - if alias.asname: - self._import_aliases[alias.asname] = name - elif isinstance(Node, ast.ImportFrom): - module_name = Node.module - if module_name and module_name not in ('c', 't'): - self._imported_modules.add(module_name) - for alias in Node.names: - if alias.asname: - self._import_aliases[alias.asname] = f"{module_name}.{alias.name}" - - for Node in ast.iter_child_nodes(Tree): - if isinstance(Node, ast.ClassDef): - ClassName = Node.name - - # 检查是否是特殊类型(枚举或联合体) - IsSpecialType = False - if Node.bases: - for base in Node.bases: - if hasattr(base, 'attr'): - if base.attr in ['CEnum', 'Enum', 'CUnion', 'REnum']: - IsSpecialType = True - break - elif hasattr(base, 'id'): - if base.id in ['CEnum', 'Enum', 'CUnion', 'REnum']: - IsSpecialType = True - break - - # 如果是特殊类型,跳过这里的处理(由 HandleClassDef 处理) - if IsSpecialType: - continue - - members = {} - IsTypedef = False - TypedefName = None - - if hasattr(Node, 'annotation') and Node.annotation: - try: - AnnotationStr = ast.dump(Node.annotation) - if 'CTypedef' in AnnotationStr: - IsTypedef = True - if isinstance(Node.annotation, ast.Call): - if Node.annotation.args: - if isinstance(Node.annotation.args[0], ast.Constant): - TypedefName = Node.annotation.args[0].value - except Exception: - pass - - if not IsTypedef: - for item in Node.body: - if isinstance(item, ast.Assign): - for target in item.targets: - if isinstance(target, ast.Name) and target.id == '__annotations__': - if isinstance(item.value, ast.Dict): - for key, value in zip(item.value.keys, item.value.values): - if isinstance(key, ast.Constant) and key.value == '__type__': - value_str = ast.dump(value) - if 'CTypedef' in value_str: - IsTypedef = True - if isinstance(value, ast.Call): - if value.args: - if isinstance(value.args[0], ast.Constant): - TypedefName = value.args[0].value - - if IsTypedef: - TypedefKey = TypedefName if TypedefName else ClassName - TypedefNode = SymbolNode.CreateClass( - name=TypedefKey, - TypeKind='typedef', - lineno=0 - ) - TypedefNode.set('OriginalType', f'struct {ClassName}') - TypedefNode.set('IsComplete', True) - TypedefNode.set('file', '') - self.SymbolTable[TypedefKey] = TypedefNode.attributes - - for item in Node.body: - if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name): - VarName = item.target.id - try: - TypeInfo = self.TypeMergeHandler.GetCTypeInfo(item.annotation) - if TypeInfo is None: - TypeInfo = CTypeInfo() - TypeInfo.BaseType = t.CInt() - IsPtr = TypeInfo.IsPtr - if not IsPtr: - if isinstance(item.annotation, ast.BinOp) and isinstance(item.annotation.op, ast.BitOr): - LeftStr = ast.dump(item.annotation.left) - RightStr = ast.dump(item.annotation.right) - if 'CPtr' in LeftStr or 'CPtr' in RightStr: - IsPtr = True - dims = [] - if hasattr(item.annotation, 'slice') and isinstance(item.annotation.slice, ast.Constant): - if isinstance(item.annotation.value, ast.Name): - if item.annotation.value.id == 't': - if hasattr(item.annotation, 'slice'): - try: - dims.append(int(item.annotation.slice.value)) - except Exception as _e: - if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": - self.LogWarning(f"异常被忽略: {_e}") - MemberInfo = TypeInfo.Copy() - if dims: - MemberInfo.ArrayDims = [str(d) for d in dims] - members[VarName] = MemberInfo - except Exception as _e: - if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": - self.LogWarning(f"异常被忽略: {_e}") - - if not IsTypedef: - StructNode = SymbolNode.CreateClass( - name=ClassName, - TypeKind='struct', - members=members, - lineno=0 - ) - StructNode.set('file', '') - if ClassName in self.SymbolTable: - existing = self.SymbolTable[ClassName] - if hasattr(existing, 'IsCpythonObject') and existing.IsCpythonObject: - StructNode.set('IsCpythonObject', True) - self.SymbolTable[ClassName] = StructNode.attributes - elif isinstance(Node, ast.FunctionDef): - FuncName = Node.name - FuncNode = SymbolNode.CreateClass( - name=FuncName, - TypeKind='function', - lineno=0 - ) - FuncNode.set('file', '') - self.SymbolTable[FuncName] = FuncNode.attributes - elif isinstance(Node, ast.AnnAssign): - if isinstance(Node.target, ast.Name): - VarName = Node.target.id - - VarType = 'unknown' - IsPtr = False - IsTypedef_assignment = False - - if Node.annotation: - try: - AnnotationStr = ast.dump(Node.annotation) - if 'CTypedef' in AnnotationStr: - IsTypedef_assignment = True - except Exception as _e: - if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": - self.LogWarning(f"异常被忽略: {_e}") - - if IsTypedef_assignment and Node.value: - if isinstance(Node.value, ast.Name): - OriginalType = Node.value.id - if OriginalType in self.GeneratedTypes: - if OriginalType in self.SymbolTable: - OriginalInfo = self.SymbolTable[OriginalType] - if isinstance(OriginalInfo, dict): - actual_type = OriginalInfo.get('type', 'struct') - elif isinstance(OriginalInfo, CTypeInfo): - if OriginalInfo.IsEnum: - actual_type = 'enum' - elif OriginalInfo.IsTypedef: - actual_type = 'typedef' - elif OriginalInfo.IsStruct: - actual_type = 'struct' - else: - actual_type = 'struct' - else: - actual_type = 'struct' - if actual_type == 'enum': - TypedefNode = SymbolNode.CreateClass( - name=VarName, - TypeKind='typedef', - lineno=0 - ) - TypedefNode.set('OriginalType', f'enum {OriginalType}') - TypedefNode.set('file', '') - self.SymbolTable[VarName] = TypedefNode.attributes - elif actual_type == 'typedef': - TypedefNode = SymbolNode.CreateClass( - name=VarName, - TypeKind='typedef', - lineno=0 - ) - if isinstance(OriginalInfo, dict): - TypedefNode.set('OriginalType', OriginalInfo.get('OriginalType', f'struct {OriginalType}')) - elif isinstance(OriginalInfo, CTypeInfo) and OriginalInfo.OriginalType: - TypedefNode.set('OriginalType', OriginalInfo.OriginalType) - else: - TypedefNode.set('OriginalType', f'struct {OriginalType}') - TypedefNode.set('PendingTypedef', True) - TypedefNode.set('file', '') - self.SymbolTable[VarName] = TypedefNode.attributes - else: - TypedefNode = SymbolNode.CreateClass( - name=VarName, - TypeKind='typedef', - lineno=0 - ) - TypedefNode.set('OriginalType', f'struct {OriginalType}') - TypedefNode.set('PendingTypedef', True) - TypedefNode.set('file', '') - self.SymbolTable[VarName] = TypedefNode.attributes - self.GeneratedTypes.add(VarName) - continue - else: - if OriginalType in self.SymbolTable: - OriginalInfo = self.SymbolTable[OriginalType] - if isinstance(OriginalInfo, dict): - actual_type = OriginalInfo.get('type', 'struct') - elif isinstance(OriginalInfo, CTypeInfo): - if OriginalInfo.IsEnum: - actual_type = 'enum' - elif OriginalInfo.IsTypedef: - actual_type = 'typedef' - elif OriginalInfo.IsStruct: - actual_type = 'struct' - else: - actual_type = 'struct' - else: - actual_type = 'struct' - if actual_type == 'typedef': - TypedefNode = SymbolNode.CreateClass( - name=VarName, - TypeKind='typedef', - lineno=0 - ) - if isinstance(OriginalInfo, dict): - TypedefNode.set('OriginalType', OriginalInfo.get('OriginalType', f'struct {OriginalType}')) - elif isinstance(OriginalInfo, CTypeInfo) and OriginalInfo.OriginalType: - TypedefNode.set('OriginalType', OriginalInfo.OriginalType) - else: - TypedefNode.set('OriginalType', f'struct {OriginalType}') - TypedefNode.set('PendingTypedef', True) - TypedefNode.set('file', '') - self.SymbolTable[VarName] = TypedefNode.attributes - self.GeneratedTypes.add(VarName) - if isinstance(OriginalInfo, dict): - OriginalInfo['skip_generation'] = True - continue - elif actual_type == 'struct': - TypedefNode = SymbolNode.CreateClass( - name=VarName, - TypeKind='typedef', - lineno=0 - ) - TypedefNode.set('OriginalType', f'struct {OriginalType}') - TypedefNode.set('PendingTypedef', True) - TypedefNode.set('file', '') - self.SymbolTable[VarName] = TypedefNode.attributes - self.GeneratedTypes.add(VarName) - if isinstance(OriginalInfo, dict): - OriginalInfo['skip_generation'] = True - continue - elif actual_type == 'enum': - TypedefNode = SymbolNode.CreateClass( - name=VarName, - TypeKind='typedef', - lineno=0 - ) - TypedefNode.set('OriginalType', f'enum {OriginalType}') - TypedefNode.set('PendingTypedef', True) - TypedefNode.set('file', '') - self.SymbolTable[VarName] = TypedefNode.attributes - self.GeneratedTypes.add(VarName) - if isinstance(OriginalInfo, dict): - OriginalInfo['skip_generation'] = True - continue - elif isinstance(Node.value, ast.Attribute): - from lib.core.Handles.HandlesBase import CTypeHelper - CName = CTypeHelper.GetCName(Node.value.attr) - if CName: - TypedefNode = SymbolNode.CreateClass( - name=VarName, - TypeKind='typedef', - lineno=0 - ) - TypedefNode.set('OriginalType', CName) - TypedefNode.set('file', '') - self.SymbolTable[VarName] = TypedefNode.attributes - self.GeneratedTypes.add(VarName) - continue - - if Node.annotation: - try: - TypeInfo = self.TypeMergeHandler.GetCTypeInfo(Node.annotation) - IsPtr = TypeInfo.IsPtr if TypeInfo else False - except Exception as _e: - if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": - self.LogWarning(f"异常被忽略: {_e}") - var_node = SymbolNode.CreateClass( - name=VarName, - TypeKind='variable', - lineno=0 - ) - var_node.set('IsPtr', IsPtr) - var_node.set('file', '') - self.SymbolTable[VarName] = var_node.attributes - - self.LlvmGen = LlvmCodeGenerator( - triple=getattr(self, 'triple', None), - datalayout=getattr(self, 'datalayout', None), - ) - self.LlvmGen._Trans = self - self.LlvmGen._import_handler_ref = self.ImportHandler - if hasattr(self, '_module_sha1'): - self.LlvmGen.module_sha1 = self._module_sha1 - if hasattr(self, '_module_sha1_map'): - self.LlvmGen.module_sha1_map = self._module_sha1_map - if hasattr(self, '_struct_sha1_map'): - self.LlvmGen._struct_sha1_map = self._struct_sha1_map - if hasattr(self, '_temp_dir'): - self.LlvmGen._temp_dir = self._temp_dir - if hasattr(self, '_export_extern_funcs'): - self.LlvmGen._export_extern_funcs = self._export_extern_funcs - self.LlvmGen.setup_from_symbol_table(self.SymbolTable) - if hasattr(self, 'CurrentFile') and self.CurrentFile: - self.LlvmGen._set_source_info(self.CurrentFile) - - return self.GenerateLlvmDirect(Tree) - - def HandleExpr(self, Node, UseSingleQuote=False, VarType=None): - return self.ExprHandler.HandleExpr(Node, UseSingleQuote, VarType) +# 通过 Mixin 模式组合各功能模块 +# +# 拆分后的模块位于 lib/core/Translator/ 目录下: +# - BaseTranslator.py: __init__、日志、Handle 实例化 +# - AnnotationLoader.py: 注解模块加载 +# - PythonParser.py: Python 文件解析 +# - LlvmGenerator.py: LLVM IR 生成 +# - ConstEval.py: 常量表达式求值 + +from lib.core.Translator.BaseTranslator import BaseTranslatorMixin, _StrictLog +from lib.core.Translator.AnnotationLoader import AnnotationLoaderMixin +from lib.core.Translator.PythonParser import PythonParserMixin +from lib.core.Translator.LlvmGenerator import LlvmGeneratorMixin +from lib.core.Translator.ConstEval import ConstEvalMixin + + +class Translator( + BaseTranslatorMixin, + AnnotationLoaderMixin, + PythonParserMixin, + LlvmGeneratorMixin, + ConstEvalMixin, +): + """代码转换器 + + 通过 Mixin 模式组合各功能模块。 + 实际方法实现分布在 lib/core/Translator/ 下的各模块中。 + """ + pass + + +__all__ = ['Translator', '_StrictLog'] diff --git a/lib/includes/t.py b/lib/includes/t.py index 450e83a..09400d5 100644 --- a/lib/includes/t.py +++ b/lib/includes/t.py @@ -56,8 +56,12 @@ def _build_type_maps(): if _cname and _obj.IsBasicType(): _BASIC_TYPES_MAP[_cname] = _cname _T_TYPE_PATTERNS.append((_name, _cname)) - except Exception: - pass + except Exception as _e: + from lib.core.VLogger import get_logger as _vlog + from lib.constants.config import mode as _ConfigMode + if _ConfigMode == "strict": + raise + _vlog().warning(f"构建类型映射时实例化 CType 子类失败: {_e}", "Exception") # ============================================================================= diff --git a/temp_error.txt b/temp_error.txt deleted file mode 100644 index cdcc976..0000000 --- a/temp_error.txt +++ /dev/null @@ -1 +0,0 @@ -[编译终止] 1 个文件翻译失败 diff --git a/temp_error2.txt b/temp_error2.txt deleted file mode 100644 index cdcc976..0000000 --- a/temp_error2.txt +++ /dev/null @@ -1 +0,0 @@ -[编译终止] 1 个文件翻译失败 diff --git a/test_debug.py b/test_debug.py deleted file mode 100644 index 3546fbc..0000000 --- a/test_debug.py +++ /dev/null @@ -1,32 +0,0 @@ -import sys, ast -sys.path.insert(0, '.') -from lib.includes.t import CTypeRegistry -CTypeRegistry._build() - -from lib.core.Handles.HandlesBase import CTypeInfo -from lib.core.Handles.HandlesTypeMerge import TypeMergeHandler -from lib.includes import t - -class MockTrans: - SymbolTable = {} - -trans = MockTrans() -handler = TypeMergeHandler(trans) - -# Parse "t.CVoid | t.CPtr" -code = "t.CVoid | t.CPtr" -tree = ast.parse(code, mode='eval') -binop = tree.body - -result = handler.MergeTypes(binop) -if result: - print(f'MergeTypes(t.CVoid | t.CPtr):') - print(f' BaseType: {result.BaseType}') - print(f' PtrCount: {result.PtrCount}') - print(f' IsVoid: {result.IsVoid}') - print(f' IsPtr: {result.IsPtr}') - print(f' IsTypedef: {result.IsTypedef}') - print(f' Name: {result.Name}') - print(f' ToString: {result.ToString()}') -else: - print('MergeTypes returned None') diff --git a/test_regex.py b/test_regex.py deleted file mode 100644 index ac04290..0000000 --- a/test_regex.py +++ /dev/null @@ -1,24 +0,0 @@ -import re - -name = '1347c4edf991da6f.Widget' -ir_text = '%1347c4edf991da6f.Widget = type { i8*, i32, i32, i32, i32, i32, i8*, i32, i32, i32 }' -pattern = r'%' + re.escape(name) + r'(?=[^a-zA-Z0-9_$\.]|$)' -print('Pattern:', pattern) -m = re.search(pattern, ir_text) -if m: - print('Match:', m.group(0)) -else: - print('No match') - -result = re.sub(pattern, r'%"' + name + r'"', ir_text) -print('Result:', result) - -ir_text2 = '%"1347c4edf991da6f.Widget" = type { i8*, i32, i32, i32, i32, i32, i8*, i32, i32, i32 }' -m2 = re.search(pattern, ir_text2) -if m2: - print('Match2:', m2.group(0)) -else: - print('No match2') - -result2 = re.sub(pattern, r'%"' + name + r'"', ir_text2) -print('Result2:', result2) diff --git a/test_sret b/test_sret deleted file mode 100644 index 6cf51f7..0000000 --- a/test_sret +++ /dev/null @@ -1,27 +0,0 @@ -=== AST Tree (Compact) === -Module(body=[Import(names=[alias(name='t'), alias(name='c')]), FunctionDef(name='get_rect', args=arguments(posonlyargs=[], args=[arg(arg='style', annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load())), arg(arg='th', annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load())), arg(arg='wx', annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load())), arg(arg='wy', annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load())), arg(arg='ww', annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()))], kwonlyargs=[], kw_defaults=[], defaults=[]), body=[AnnAssign(target=Name(id='btn_w', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), value=Constant(value=10), simple=1), AnnAssign(target=Name(id='btn_h', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), value=Constant(value=10), simple=1), AnnAssign(target=Name(id='btn_x', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), value=BinOp(left=BinOp(left=BinOp(left=Name(id='wx', ctx=Load()), op=Add(), right=Name(id='ww', ctx=Load())), op=Sub(), right=Name(id='btn_w', ctx=Load())), op=Sub(), right=Constant(value=4)), simple=1), AnnAssign(target=Name(id='btn_y', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), value=BinOp(left=Name(id='wy', ctx=Load()), op=Add(), right=BinOp(left=BinOp(left=Name(id='th', ctx=Load()), op=Sub(), right=Name(id='btn_h', ctx=Load())), op=FloorDiv(), right=Constant(value=2))), simple=1), AnnAssign(target=Name(id='max_bx', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), value=BinOp(left=Name(id='btn_x', ctx=Load()), op=Sub(), right=Constant(value=2)), simple=1), AnnAssign(target=Name(id='min_bx', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), value=BinOp(left=Name(id='max_bx', ctx=Load()), op=Sub(), right=Constant(value=2)), simple=1), Return(value=Tuple(elts=[Name(id='btn_w', ctx=Load()), Name(id='btn_h', ctx=Load()), Name(id='btn_x', ctx=Load()), Name(id='btn_y', ctx=Load()), Name(id='max_bx', ctx=Load()), Name(id='min_bx', ctx=Load())], ctx=Load()))], decorator_list=[Call(func=Attribute(value=Name(id='c', ctx=Load()), attr='CReturn', ctx=Load()), args=[Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load())], keywords=[])], returns=Subscript(value=Name(id='tuple', ctx=Load()), slice=Tuple(elts=[Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load())], ctx=Load()), ctx=Load()), type_params=[]), FunctionDef(name='main', args=arguments(posonlyargs=[], args=[], kwonlyargs=[], kw_defaults=[], defaults=[]), body=[AnnAssign(target=Name(id='bw', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), value=Constant(value=0), simple=1), AnnAssign(target=Name(id='bh', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), value=Constant(value=0), simple=1), AnnAssign(target=Name(id='bx', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), value=Constant(value=0), simple=1), AnnAssign(target=Name(id='by', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), value=Constant(value=0), simple=1), AnnAssign(target=Name(id='mbx', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), value=Constant(value=0), simple=1), AnnAssign(target=Name(id='mnbx', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), value=Constant(value=0), simple=1), Assign(targets=[Tuple(elts=[Name(id='bw', ctx=Store()), Name(id='bh', ctx=Store()), Name(id='bx', ctx=Store()), Name(id='by', ctx=Store()), Name(id='mbx', ctx=Store()), Name(id='mnbx', ctx=Store())], ctx=Store())], value=Call(func=Name(id='get_rect', ctx=Load()), args=[Constant(value=1), Constant(value=30), Constant(value=100), Constant(value=200), Constant(value=800)], keywords=[])), Expr(value=Call(func=Name(id='printf', ctx=Load()), args=[Constant(value='btn_w=%d btn_h=%d btn_x=%d btn_y=%d max_bx=%d min_bx=%d\n'), Name(id='bw', ctx=Load()), Name(id='bh', ctx=Load()), Name(id='bx', ctx=Load()), Name(id='by', ctx=Load()), Name(id='mbx', ctx=Load()), Name(id='mnbx', ctx=Load())], keywords=[])), Return(value=Constant(value=0))], decorator_list=[], returns=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), type_params=[])], type_ignores=[]) - -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t -[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... -[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t