tpy-lang 0.3.0.dev0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (333) hide show
  1. tpy_lang-0.3.0.dev0.dist-info/METADATA +151 -0
  2. tpy_lang-0.3.0.dev0.dist-info/RECORD +333 -0
  3. tpy_lang-0.3.0.dev0.dist-info/WHEEL +4 -0
  4. tpy_lang-0.3.0.dev0.dist-info/entry_points.txt +3 -0
  5. tpyc/__init__.py +104 -0
  6. tpyc/__main__.py +6 -0
  7. tpyc/_buildinfo.py +1 -0
  8. tpyc/_data/docs/LANGUAGE_FEATURES.md +6278 -0
  9. tpyc/_data/docs/STDLIB_ROADMAP.md +1258 -0
  10. tpyc/_data/docs/TPY_FOR_AGENTS.md +556 -0
  11. tpyc/_data/lib/tpy/_bindings/__init__.py +6 -0
  12. tpyc/_data/lib/tpy/_bindings/pcre2.py +173 -0
  13. tpyc/_data/lib/tpy/_bindings/posix_socket.py +161 -0
  14. tpyc/_data/lib/tpy/_functools_macros.py +80 -0
  15. tpyc/_data/lib/tpy/_macro_helpers.py +161 -0
  16. tpyc/_data/lib/tpy/argparse.py +2062 -0
  17. tpyc/_data/lib/tpy/asyncio/__init__.py +744 -0
  18. tpyc/_data/lib/tpy/asyncio/_executor.py +515 -0
  19. tpyc/_data/lib/tpy/base64.py +410 -0
  20. tpyc/_data/lib/tpy/bisect.py +39 -0
  21. tpyc/_data/lib/tpy/builtins.py +38 -0
  22. tpyc/_data/lib/tpy/dataclasses.py +354 -0
  23. tpyc/_data/lib/tpy/enum.py +23 -0
  24. tpyc/_data/lib/tpy/functools.py +33 -0
  25. tpyc/_data/lib/tpy/hashlib.py +206 -0
  26. tpyc/_data/lib/tpy/heapq.py +118 -0
  27. tpyc/_data/lib/tpy/io.py +395 -0
  28. tpyc/_data/lib/tpy/json.py +221 -0
  29. tpyc/_data/lib/tpy/math.py +406 -0
  30. tpyc/_data/lib/tpy/random.py +597 -0
  31. tpyc/_data/lib/tpy/re.py +467 -0
  32. tpyc/_data/lib/tpy/socket.py +379 -0
  33. tpyc/_data/lib/tpy/struct.py +178 -0
  34. tpyc/_data/lib/tpy/sys.py +40 -0
  35. tpyc/_data/lib/tpy/time.py +39 -0
  36. tpyc/_data/lib/tpy/tpy/__init__.py +78 -0
  37. tpyc/_data/lib/tpy/tpy/_bootstrap/__init__.py +10 -0
  38. tpyc/_data/lib/tpy/tpy/_bootstrap/_decorators.py +37 -0
  39. tpyc/_data/lib/tpy/tpy/_bootstrap/_extern.py +64 -0
  40. tpyc/_data/lib/tpy/tpy/_builtins/__init__.py +11 -0
  41. tpyc/_data/lib/tpy/tpy/_builtins/_bytes.py +378 -0
  42. tpyc/_data/lib/tpy/tpy/_builtins/_dict.py +151 -0
  43. tpyc/_data/lib/tpy/tpy/_builtins/_exceptions.py +125 -0
  44. tpyc/_data/lib/tpy/tpy/_builtins/_funcs.py +681 -0
  45. tpyc/_data/lib/tpy/tpy/_builtins/_io.py +97 -0
  46. tpyc/_data/lib/tpy/tpy/_builtins/_list.py +127 -0
  47. tpyc/_data/lib/tpy/tpy/_builtins/_range.py +52 -0
  48. tpyc/_data/lib/tpy/tpy/_builtins/_set.py +139 -0
  49. tpyc/_data/lib/tpy/tpy/_builtins/_super.py +11 -0
  50. tpyc/_data/lib/tpy/tpy/_builtins/_types.py +661 -0
  51. tpyc/_data/lib/tpy/tpy/_core/__init__.py +23 -0
  52. tpyc/_data/lib/tpy/tpy/_core/_bytes_view.py +129 -0
  53. tpyc/_data/lib/tpy/tpy/_core/_containers.py +137 -0
  54. tpyc/_data/lib/tpy/tpy/_core/_functions.py +40 -0
  55. tpyc/_data/lib/tpy/tpy/_core/_types.py +2061 -0
  56. tpyc/_data/lib/tpy/tpy/_typing/__init__.py +77 -0
  57. tpyc/_data/lib/tpy/tpy/_version.py +29 -0
  58. tpyc/_data/lib/tpy/tpy/bits.py +28 -0
  59. tpyc/_data/lib/tpy/tpy/coro/__init__.py +127 -0
  60. tpyc/_data/lib/tpy/tpy/extern.py +8 -0
  61. tpyc/_data/lib/tpy/tpy/mem.py +49 -0
  62. tpyc/_data/lib/tpy/tpy/unsafe.py +195 -0
  63. tpyc/_data/lib/tpy/tpy/version.py +21 -0
  64. tpyc/_data/lib/tpy/typing.py +13 -0
  65. tpyc/_data/runtime/cpp/include/tpy/any.hpp +461 -0
  66. tpyc/_data/runtime/cpp/include/tpy/as_ostream.hpp +117 -0
  67. tpyc/_data/runtime/cpp/include/tpy/async.hpp +76 -0
  68. tpyc/_data/runtime/cpp/include/tpy/bigint.hpp +1343 -0
  69. tpyc/_data/runtime/cpp/include/tpy/builtins.hpp +400 -0
  70. tpyc/_data/runtime/cpp/include/tpy/bytes_ops.hpp +469 -0
  71. tpyc/_data/runtime/cpp/include/tpy/container_ops.hpp +487 -0
  72. tpyc/_data/runtime/cpp/include/tpy/copy_iter.hpp +82 -0
  73. tpyc/_data/runtime/cpp/include/tpy/core.hpp +558 -0
  74. tpyc/_data/runtime/cpp/include/tpy/dict_ops.hpp +289 -0
  75. tpyc/_data/runtime/cpp/include/tpy/dunder.hpp +750 -0
  76. tpyc/_data/runtime/cpp/include/tpy/dynamic.hpp +44 -0
  77. tpyc/_data/runtime/cpp/include/tpy/enum.hpp +40 -0
  78. tpyc/_data/runtime/cpp/include/tpy/file.hpp +245 -0
  79. tpyc/_data/runtime/cpp/include/tpy/fixed_int.hpp +317 -0
  80. tpyc/_data/runtime/cpp/include/tpy/format.hpp +954 -0
  81. tpyc/_data/runtime/cpp/include/tpy/frame_slot.hpp +120 -0
  82. tpyc/_data/runtime/cpp/include/tpy/generator.hpp +47 -0
  83. tpyc/_data/runtime/cpp/include/tpy/iterable_ops.hpp +122 -0
  84. tpyc/_data/runtime/cpp/include/tpy/itertools.hpp +749 -0
  85. tpyc/_data/runtime/cpp/include/tpy/next_iter.hpp +82 -0
  86. tpyc/_data/runtime/cpp/include/tpy/ordered_map.hpp +518 -0
  87. tpyc/_data/runtime/cpp/include/tpy/ordered_set.hpp +337 -0
  88. tpyc/_data/runtime/cpp/include/tpy/own_iter.hpp +54 -0
  89. tpyc/_data/runtime/cpp/include/tpy/pascal_graph_sdl.hpp +192 -0
  90. tpyc/_data/runtime/cpp/include/tpy/printing.hpp +302 -0
  91. tpyc/_data/runtime/cpp/include/tpy/protocols.hpp +61 -0
  92. tpyc/_data/runtime/cpp/include/tpy/range.hpp +115 -0
  93. tpyc/_data/runtime/cpp/include/tpy/ranges.hpp +212 -0
  94. tpyc/_data/runtime/cpp/include/tpy/set_ops.hpp +265 -0
  95. tpyc/_data/runtime/cpp/include/tpy/slice.hpp +47 -0
  96. tpyc/_data/runtime/cpp/include/tpy/span_iter.hpp +42 -0
  97. tpyc/_data/runtime/cpp/include/tpy/stdlib/math.hpp +41 -0
  98. tpyc/_data/runtime/cpp/include/tpy/stdlib/pcre2_h.hpp +96 -0
  99. tpyc/_data/runtime/cpp/include/tpy/stdlib/random.hpp +25 -0
  100. tpyc/_data/runtime/cpp/include/tpy/stdlib/socket_h.hpp +145 -0
  101. tpyc/_data/runtime/cpp/include/tpy/stdlib/time.hpp +62 -0
  102. tpyc/_data/runtime/cpp/include/tpy/system.hpp +121 -0
  103. tpyc/_data/runtime/cpp/include/tpy/throwable.hpp +55 -0
  104. tpyc/_data/runtime/cpp/include/tpy/tpy.hpp +156 -0
  105. tpyc/_data/runtime/cpp/include/tpy/type_name.hpp +77 -0
  106. tpyc/_data/runtime/cpp/include/tpy/type_traits.hpp +240 -0
  107. tpyc/_data/runtime/cpp/include/tpy/uninit_array_storage.hpp +250 -0
  108. tpyc/_data/runtime/cpp/include/tpy/uninit_heap_storage.hpp +277 -0
  109. tpyc/_data/runtime/cpp/include/tpy/varargs.hpp +174 -0
  110. tpyc/_data/runtime/cpp/include/tpy/variant_ref.hpp +118 -0
  111. tpyc/_data/runtime/cpp/src/stdlib/socket_impl.cpp +104 -0
  112. tpyc/_data/runtime/cpp/third_party/README.md +58 -0
  113. tpyc/_data/runtime/cpp/third_party/pcre2/AUTHORS +36 -0
  114. tpyc/_data/runtime/cpp/third_party/pcre2/CMakeLists.txt +1233 -0
  115. tpyc/_data/runtime/cpp/third_party/pcre2/COPYING +5 -0
  116. tpyc/_data/runtime/cpp/third_party/pcre2/ChangeLog +3097 -0
  117. tpyc/_data/runtime/cpp/third_party/pcre2/HACKING +853 -0
  118. tpyc/_data/runtime/cpp/third_party/pcre2/INSTALL +368 -0
  119. tpyc/_data/runtime/cpp/third_party/pcre2/LICENCE +94 -0
  120. tpyc/_data/runtime/cpp/third_party/pcre2/NEWS +492 -0
  121. tpyc/_data/runtime/cpp/third_party/pcre2/NON-AUTOTOOLS-BUILD +430 -0
  122. tpyc/_data/runtime/cpp/third_party/pcre2/README +956 -0
  123. tpyc/_data/runtime/cpp/third_party/pcre2/cmake/COPYING-CMAKE-SCRIPTS +22 -0
  124. tpyc/_data/runtime/cpp/third_party/pcre2/cmake/FindEditline.cmake +16 -0
  125. tpyc/_data/runtime/cpp/third_party/pcre2/cmake/FindPackageHandleStandardArgs.cmake +58 -0
  126. tpyc/_data/runtime/cpp/third_party/pcre2/cmake/FindReadline.cmake +29 -0
  127. tpyc/_data/runtime/cpp/third_party/pcre2/cmake/pcre2-config-version.cmake.in +15 -0
  128. tpyc/_data/runtime/cpp/third_party/pcre2/cmake/pcre2-config.cmake.in +148 -0
  129. tpyc/_data/runtime/cpp/third_party/pcre2/config-cmake.h.in +56 -0
  130. tpyc/_data/runtime/cpp/third_party/pcre2/libpcre2-16.pc.in +13 -0
  131. tpyc/_data/runtime/cpp/third_party/pcre2/libpcre2-32.pc.in +13 -0
  132. tpyc/_data/runtime/cpp/third_party/pcre2/libpcre2-8.pc.in +13 -0
  133. tpyc/_data/runtime/cpp/third_party/pcre2/libpcre2-posix.pc.in +13 -0
  134. tpyc/_data/runtime/cpp/third_party/pcre2/pcre2-config.in +121 -0
  135. tpyc/_data/runtime/cpp/third_party/pcre2/src/config.h +483 -0
  136. tpyc/_data/runtime/cpp/third_party/pcre2/src/config.h.generic +483 -0
  137. tpyc/_data/runtime/cpp/third_party/pcre2/src/config.h.in +460 -0
  138. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2.h +1010 -0
  139. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2.h.generic +1010 -0
  140. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2.h.in +1010 -0
  141. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_auto_possess.c +1371 -0
  142. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_chartables.c +196 -0
  143. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_chartables.c.dist +196 -0
  144. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_chkdint.c +96 -0
  145. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_compile.c +11001 -0
  146. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_config.c +252 -0
  147. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_context.c +510 -0
  148. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_convert.c +1189 -0
  149. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_dfa_match.c +4119 -0
  150. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_dftables.c +297 -0
  151. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_error.c +345 -0
  152. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_extuni.c +162 -0
  153. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_find_bracket.c +219 -0
  154. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_fuzzsupport.c +792 -0
  155. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_internal.h +2084 -0
  156. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_intmodedep.h +940 -0
  157. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_jit_compile.c +14972 -0
  158. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_jit_match.c +200 -0
  159. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_jit_misc.c +234 -0
  160. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_jit_neon_inc.h +354 -0
  161. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_jit_simd_inc.h +2355 -0
  162. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_jit_test.c +2528 -0
  163. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_maketables.c +165 -0
  164. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_match.c +7777 -0
  165. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_match_data.c +185 -0
  166. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_newline.c +243 -0
  167. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_ord2utf.c +120 -0
  168. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_pattern_info.c +432 -0
  169. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_printint.c +886 -0
  170. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_script_run.c +344 -0
  171. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_serialize.c +286 -0
  172. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_string_utils.c +237 -0
  173. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_study.c +1915 -0
  174. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_substitute.c +1009 -0
  175. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_substring.c +550 -0
  176. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_tables.c +234 -0
  177. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_ucd.c +5460 -0
  178. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_ucp.h +396 -0
  179. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_ucptables.c +1533 -0
  180. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_valid_utf.c +398 -0
  181. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_xclass.c +308 -0
  182. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2demo.c +497 -0
  183. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2grep.c +4606 -0
  184. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2posix.c +425 -0
  185. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2posix.h +187 -0
  186. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2posix_test.c +209 -0
  187. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2test.c +9708 -0
  188. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitExecAllocatorApple.c +137 -0
  189. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitExecAllocatorCore.c +327 -0
  190. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitExecAllocatorFreeBSD.c +89 -0
  191. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitExecAllocatorPosix.c +62 -0
  192. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitExecAllocatorWindows.c +40 -0
  193. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitProtExecAllocatorNetBSD.c +72 -0
  194. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitProtExecAllocatorPosix.c +172 -0
  195. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitWXExecAllocatorPosix.c +141 -0
  196. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitWXExecAllocatorWindows.c +102 -0
  197. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitConfig.h +142 -0
  198. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitConfigCPU.h +188 -0
  199. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitConfigInternal.h +907 -0
  200. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitLir.c +3561 -0
  201. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitLir.h +2466 -0
  202. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeARM_32.c +4636 -0
  203. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeARM_64.c +3491 -0
  204. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeARM_T2_32.c +4302 -0
  205. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeLOONGARCH_64.c +3765 -0
  206. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeMIPS_32.c +472 -0
  207. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeMIPS_64.c +387 -0
  208. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeMIPS_common.c +4259 -0
  209. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativePPC_32.c +485 -0
  210. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativePPC_64.c +719 -0
  211. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativePPC_common.c +3161 -0
  212. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeRISCV_32.c +142 -0
  213. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeRISCV_64.c +222 -0
  214. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeRISCV_common.c +3121 -0
  215. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeS390X.c +4526 -0
  216. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeX86_32.c +1685 -0
  217. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeX86_64.c +1398 -0
  218. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeX86_common.c +5001 -0
  219. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitSerialize.c +516 -0
  220. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitUtils.c +344 -0
  221. tpyc/_data/runtime/cpp/third_party/pcre2.sources.txt +54 -0
  222. tpyc/_data/runtime/cpp/third_party/pcre2.vendor.json +7 -0
  223. tpyc/build/__init__.py +7 -0
  224. tpyc/build/pcre2.py +122 -0
  225. tpyc/build/third_party.py +413 -0
  226. tpyc/cli.py +822 -0
  227. tpyc/codegen_cpp/__init__.py +18 -0
  228. tpyc/codegen_cpp/builtins.py +484 -0
  229. tpyc/codegen_cpp/context.py +2064 -0
  230. tpyc/codegen_cpp/expressions.py +5940 -0
  231. tpyc/codegen_cpp/functions.py +1913 -0
  232. tpyc/codegen_cpp/gen_async.py +3258 -0
  233. tpyc/codegen_cpp/gen_generators.py +657 -0
  234. tpyc/codegen_cpp/generator.py +2258 -0
  235. tpyc/codegen_cpp/match.py +1997 -0
  236. tpyc/codegen_cpp/param_const.py +172 -0
  237. tpyc/codegen_cpp/protocols.py +907 -0
  238. tpyc/codegen_cpp/records.py +1654 -0
  239. tpyc/codegen_cpp/resumable_cfg.py +1651 -0
  240. tpyc/codegen_cpp/statements.py +4963 -0
  241. tpyc/codegen_cpp/string_dispatch.py +76 -0
  242. tpyc/codegen_cpp/test_context.py +46 -0
  243. tpyc/codegen_cpp/test_param_const.py +113 -0
  244. tpyc/codegen_cpp/test_resumable_cfg.py +182 -0
  245. tpyc/codegen_cpp/type_resolution.py +53 -0
  246. tpyc/codegen_cpp/types.py +436 -0
  247. tpyc/codegen_cpp/variant_access.py +135 -0
  248. tpyc/coercions.py +749 -0
  249. tpyc/compilation_context.py +57 -0
  250. tpyc/compiler.py +3945 -0
  251. tpyc/cycle_detection.py +358 -0
  252. tpyc/diagnostics.py +135 -0
  253. tpyc/dump_types.py +353 -0
  254. tpyc/frontend_diagnostics.py +47 -0
  255. tpyc/frontend_ir/__init__.py +140 -0
  256. tpyc/frontend_ir/lower.py +1098 -0
  257. tpyc/frontend_ir/nodes.py +718 -0
  258. tpyc/frontend_ir/resolver_adapter.py +151 -0
  259. tpyc/frontend_plugin.py +209 -0
  260. tpyc/install_docs.py +81 -0
  261. tpyc/liveness.py +756 -0
  262. tpyc/macro_api.py +1724 -0
  263. tpyc/macro_loader.py +497 -0
  264. tpyc/module_names.py +64 -0
  265. tpyc/modules/__init__.py +31 -0
  266. tpyc/modules/defs.py +89 -0
  267. tpyc/modules/registry.py +36 -0
  268. tpyc/modules/resolver.py +192 -0
  269. tpyc/modules/type_resolution.py +629 -0
  270. tpyc/namespace.py +172 -0
  271. tpyc/parse/__init__.py +84 -0
  272. tpyc/parse/imports.py +490 -0
  273. tpyc/parse/nodes.py +1732 -0
  274. tpyc/parse/parser.py +4043 -0
  275. tpyc/parse/resolve_refs.py +466 -0
  276. tpyc/parse/type_resolver.py +1060 -0
  277. tpyc/prescan.py +254 -0
  278. tpyc/qnames.py +149 -0
  279. tpyc/repl.py +529 -0
  280. tpyc/repl_backends.py +848 -0
  281. tpyc/sema/__init__.py +21 -0
  282. tpyc/sema/analyzer.py +3625 -0
  283. tpyc/sema/bound_check.py +72 -0
  284. tpyc/sema/builder_trace.py +684 -0
  285. tpyc/sema/calls.py +5406 -0
  286. tpyc/sema/compatibility.py +2107 -0
  287. tpyc/sema/context.py +1243 -0
  288. tpyc/sema/expressions.py +3737 -0
  289. tpyc/sema/flow_facts.py +199 -0
  290. tpyc/sema/init_tracker.py +150 -0
  291. tpyc/sema/list_literals.py +69 -0
  292. tpyc/sema/literal_utils.py +27 -0
  293. tpyc/sema/local_deduction.py +1088 -0
  294. tpyc/sema/macros.py +179 -0
  295. tpyc/sema/match.py +1177 -0
  296. tpyc/sema/method_expansion.py +347 -0
  297. tpyc/sema/methods.py +2197 -0
  298. tpyc/sema/mutation_propagation.py +268 -0
  299. tpyc/sema/narrowing.py +857 -0
  300. tpyc/sema/numeric_lattice.py +160 -0
  301. tpyc/sema/operators.py +402 -0
  302. tpyc/sema/overloads.py +841 -0
  303. tpyc/sema/protocols.py +1209 -0
  304. tpyc/sema/reach_analysis.py +202 -0
  305. tpyc/sema/registration.py +3156 -0
  306. tpyc/sema/scope_tracker.py +193 -0
  307. tpyc/sema/statements.py +4426 -0
  308. tpyc/sema/type_ops.py +1879 -0
  309. tpyc/sema/value_range.py +181 -0
  310. tpyc/symbol_binding.py +259 -0
  311. tpyc/test_c3_mro.py +208 -0
  312. tpyc/test_cli_argv.py +52 -0
  313. tpyc/test_compiler.py +559 -0
  314. tpyc/test_contains_type_param.py +101 -0
  315. tpyc/test_cycle_detection.py +221 -0
  316. tpyc/test_dump_types.py +225 -0
  317. tpyc/test_install_docs.py +65 -0
  318. tpyc/test_local_cpp_form.py +135 -0
  319. tpyc/test_macro_loader.py +76 -0
  320. tpyc/test_method_expansion.py +254 -0
  321. tpyc/test_nominal_identity.py +182 -0
  322. tpyc/test_overloads.py +410 -0
  323. tpyc/test_parse.py +303 -0
  324. tpyc/test_parse_type_ref.py +506 -0
  325. tpyc/test_parse_version_info.py +58 -0
  326. tpyc/test_reach_analysis.py +72 -0
  327. tpyc/test_ref_type.py +216 -0
  328. tpyc/test_send_sync_substitution.py +276 -0
  329. tpyc/test_tuple_mutation_propagation.py +206 -0
  330. tpyc/test_type_def_registry.py +1729 -0
  331. tpyc/test_union_types.py +195 -0
  332. tpyc/type_def_registry.py +975 -0
  333. tpyc/typesys.py +5104 -0
@@ -0,0 +1,558 @@
1
+ /**
2
+ * TurboPython Runtime - Core Utilities
3
+ *
4
+ * Panic handling and pointer operations.
5
+ */
6
+
7
+ #pragma once
8
+
9
+ #include <cmath>
10
+ #include <concepts>
11
+ #include <cstdio>
12
+ #include <cstdlib>
13
+ #include <cxxabi.h>
14
+ #include <exception>
15
+ #include <expected>
16
+ #include <format>
17
+ #include <memory>
18
+ #include <optional>
19
+ #include <ostream>
20
+ #include <string>
21
+ #include <string_view>
22
+ #include <type_traits>
23
+ #include <typeinfo>
24
+ #include <utility>
25
+ #include <variant>
26
+
27
+ #include "throwable.hpp"
28
+ #include "type_traits.hpp"
29
+
30
+ namespace tpy {
31
+
32
+ // Python exception hierarchy. Inherits Throwable -> std::exception so
33
+ // `except as e` borrows route through the Throwable vtable for clone()
34
+ // and __raise__() while plain C++ throw/catch still works.
35
+ struct BaseException : ::tpy::Throwable {
36
+ std::string message;
37
+ BaseException() = default;
38
+ explicit BaseException(std::string msg) : message(std::move(msg)) {}
39
+ explicit BaseException(std::string_view msg) : message(msg) {}
40
+ // Disambiguates string-literal calls that would otherwise be ambiguous
41
+ // between the std::string and std::string_view ctors above.
42
+ explicit BaseException(const char* msg) : message(msg) {}
43
+ const char* what() const noexcept override { return message.c_str(); }
44
+ std::string_view __str__() const { return message; }
45
+ friend std::ostream& operator<<(std::ostream& os, const BaseException& e) { return os << e.message; }
46
+ TPY_THROWABLE_VIRTUALS(BaseException)
47
+ };
48
+ struct Exception : BaseException { using BaseException::BaseException; TPY_THROWABLE_VIRTUALS(Exception) };
49
+ struct ValueError : Exception { using Exception::Exception; TPY_THROWABLE_VIRTUALS(ValueError) };
50
+ struct OSError : Exception { using Exception::Exception; TPY_THROWABLE_VIRTUALS(OSError) };
51
+ struct FileNotFoundError : OSError { using OSError::OSError; TPY_THROWABLE_VIRTUALS(FileNotFoundError) };
52
+ struct AttributeError : Exception { using Exception::Exception; TPY_THROWABLE_VIRTUALS(AttributeError) };
53
+ struct AssertionError : Exception { using Exception::Exception; TPY_THROWABLE_VIRTUALS(AssertionError) };
54
+ struct IndexError : Exception { using Exception::Exception; TPY_THROWABLE_VIRTUALS(IndexError) };
55
+ struct KeyError : Exception { using Exception::Exception; TPY_THROWABLE_VIRTUALS(KeyError) };
56
+ struct ArithmeticError : Exception { using Exception::Exception; TPY_THROWABLE_VIRTUALS(ArithmeticError) };
57
+ struct ZeroDivisionError : ArithmeticError { using ArithmeticError::ArithmeticError; TPY_THROWABLE_VIRTUALS(ZeroDivisionError) };
58
+ struct OverflowError : ArithmeticError { using ArithmeticError::ArithmeticError; TPY_THROWABLE_VIRTUALS(OverflowError) };
59
+ struct TypeError : Exception { using Exception::Exception; TPY_THROWABLE_VIRTUALS(TypeError) };
60
+ struct NotImplementedError : Exception { using Exception::Exception; TPY_THROWABLE_VIRTUALS(NotImplementedError) };
61
+ struct RuntimeError : Exception { using Exception::Exception; TPY_THROWABLE_VIRTUALS(RuntimeError) };
62
+ struct MemoryError : Exception { using Exception::Exception; TPY_THROWABLE_VIRTUALS(MemoryError) };
63
+ struct StopIteration : Exception { TPY_THROWABLE_VIRTUALS(StopIteration) };
64
+ struct StopAsyncIteration : Exception { using Exception::Exception; TPY_THROWABLE_VIRTUALS(StopAsyncIteration) };
65
+ struct TimeoutError : Exception { using Exception::Exception; TPY_THROWABLE_VIRTUALS(TimeoutError) };
66
+
67
+ // Forward decl: raise_fixedint_overflow (below) calls tpy_panic, whose
68
+ // definition lives later in this header.
69
+ [[noreturn]] inline void tpy_panic(std::string_view msg);
70
+
71
+ // raise<E>(msg) / raise<E>(fmt, args...) -- throw a Python-shaped exception.
72
+ //
73
+ // Every runtime site that surfaces a catchable error goes through this so
74
+ // the underlying policy (currently always `throw`) can be swapped at compile
75
+ // time later (e.g. abort-on-error builds, or routing to `tpy_panic` in
76
+ // `@noalloc` regions) without rewriting call sites.
77
+ //
78
+ // Two forms:
79
+ // raise<E>(msg) -- pre-built std::string_view message
80
+ // raise<E>(fmt, args...) -- std::format-style; format string validated
81
+ // against the arg types at compile time. Single
82
+ // trailing arg disambiguates against the
83
+ // string_view overload.
84
+ //
85
+ // Not constexpr; calling from a constexpr function is permitted under
86
+ // C++23 P2448 as long as the call is never reached during constant
87
+ // evaluation.
88
+ template<typename E>
89
+ requires std::derived_from<E, BaseException>
90
+ [[noreturn]] inline void raise(std::string_view msg) {
91
+ throw E(msg);
92
+ }
93
+ template<typename E, typename T, typename... Rest>
94
+ requires std::derived_from<E, BaseException>
95
+ [[noreturn]] inline void raise(std::format_string<T, Rest...> fmt, T&& arg,
96
+ Rest&&... rest) {
97
+ throw E(std::format(fmt, std::forward<T>(arg), std::forward<Rest>(rest)...));
98
+ }
99
+
100
+ // `assert cond[, msg]` failure path. Thin wrapper around `raise<AssertionError>`
101
+ // that supplies the no-message default `"assertion failed"`. Codegen emits
102
+ // `raise_assertion_error()` for `assert cond` (no message) and
103
+ // `raise_assertion_error(<msg-expr>)` for `assert cond, msg`.
104
+ [[noreturn]] inline void raise_assertion_error(std::string_view msg = "assertion failed") {
105
+ raise<AssertionError>(msg);
106
+ }
107
+ template<typename T, typename... Rest>
108
+ [[noreturn]] inline void raise_assertion_error(std::format_string<T, Rest...> fmt, T&& arg,
109
+ Rest&&... rest) {
110
+ raise<AssertionError>(fmt, std::forward<T>(arg), std::forward<Rest>(rest)...);
111
+ }
112
+
113
+ // Per-class raise helpers (Phase 20 Stage 4b). Decouple every runtime
114
+ // throw site from `raise<E>` (which is template-instantiated against the
115
+ // concrete C++ class) so that Stage 4c can move the exception classes
116
+ // out of core.hpp without rewriting every call site. After Stage 4c
117
+ // these helpers move to `lib/tpy/tpy/_builtins/_raise.py` and the
118
+ // forward declarations relocate to throwable.hpp; their bodies become
119
+ // TPy-defined `raise X(msg)` one-liners resolved at link time.
120
+ #define TPY_DEFINE_RAISE_HELPER(name, ExceptionClass) \
121
+ [[noreturn]] inline void name(std::string_view msg) { \
122
+ raise<ExceptionClass>(msg); \
123
+ } \
124
+ template<typename T, typename... Rest> \
125
+ [[noreturn]] inline void name(std::format_string<T, Rest...> fmt, T&& arg, \
126
+ Rest&&... rest) { \
127
+ raise<ExceptionClass>(fmt, std::forward<T>(arg), std::forward<Rest>(rest)...); \
128
+ }
129
+
130
+ TPY_DEFINE_RAISE_HELPER(raise_value_error, ValueError)
131
+ TPY_DEFINE_RAISE_HELPER(raise_type_error, TypeError)
132
+ TPY_DEFINE_RAISE_HELPER(raise_index_error, IndexError)
133
+ TPY_DEFINE_RAISE_HELPER(raise_key_error, KeyError)
134
+ TPY_DEFINE_RAISE_HELPER(raise_attribute_error, AttributeError)
135
+ TPY_DEFINE_RAISE_HELPER(raise_arithmetic_error, ArithmeticError)
136
+ TPY_DEFINE_RAISE_HELPER(raise_zero_division_error, ZeroDivisionError)
137
+ TPY_DEFINE_RAISE_HELPER(raise_overflow_error, OverflowError)
138
+ TPY_DEFINE_RAISE_HELPER(raise_os_error, OSError)
139
+ TPY_DEFINE_RAISE_HELPER(raise_file_not_found_error, FileNotFoundError)
140
+ TPY_DEFINE_RAISE_HELPER(raise_runtime_error, RuntimeError)
141
+ TPY_DEFINE_RAISE_HELPER(raise_not_implemented_error, NotImplementedError)
142
+ TPY_DEFINE_RAISE_HELPER(raise_memory_error, MemoryError)
143
+
144
+ [[noreturn]] inline void raise_stop_iteration() {
145
+ throw StopIteration{};
146
+ }
147
+
148
+ // Fixed-width integer arithmetic overflow. CPython promotes to unbounded
149
+ // BigInt and never overflows; TPy uses fixed-width storage (Int8..Int64,
150
+ // UInt8..UInt64) and panics on overflow by default. Routed through this
151
+ // helper so the policy can be made switchable later (per build / module /
152
+ // function: none / panic / throw OverflowError) without rewriting the call
153
+ // sites. Currently always panics.
154
+ [[noreturn]] inline void raise_fixedint_overflow(std::string_view msg) {
155
+ tpy_panic(msg);
156
+ }
157
+ template<typename T, typename... Rest>
158
+ [[noreturn]] inline void raise_fixedint_overflow(std::format_string<T, Rest...> fmt,
159
+ T&& arg, Rest&&... rest) {
160
+ tpy_panic(std::format(fmt, std::forward<T>(arg), std::forward<Rest>(rest)...));
161
+ }
162
+
163
+ // Portable replacement for std::unexpected(). Some libc++ versions (e.g. zig's
164
+ // bundled clang) expose both the deprecated std::unexpected() function and the
165
+ // C++23 std::unexpected<E> class template, making the name ambiguous. This wrapper
166
+ // avoids naming std::unexpected entirely by using std::unexpect tag construction.
167
+ template<typename E>
168
+ struct Unexpected {
169
+ E error;
170
+ template<typename T>
171
+ operator std::expected<T, E>() && {
172
+ return std::expected<T, E>{std::unexpect, std::move(error)};
173
+ }
174
+ template<typename T>
175
+ operator std::expected<T, E>() const& {
176
+ return std::expected<T, E>{std::unexpect, error};
177
+ }
178
+ };
179
+
180
+ template<typename E>
181
+ Unexpected<std::remove_cvref_t<E>> make_unexpected(E&& e) {
182
+ return Unexpected<std::remove_cvref_t<E>>{std::forward<E>(e)};
183
+ }
184
+
185
+ // next(iterator) -- forwards __next__() result (std::expected<T, StopIteration>)
186
+ template<typename Iter>
187
+ auto next(Iter& it) -> decltype(it.__next__()) {
188
+ return it.__next__();
189
+ }
190
+
191
+ // Strip the inline-namespace tokens libc++ and libstdc++ inject into
192
+ // demangled std:: type names (`std::__1::basic_string` /
193
+ // `std::__cxx11::basic_string`) and collapse the libstdc++ "> >" template
194
+ // closer to ">>". Without this the panic snapshots would diverge by
195
+ // host standard library.
196
+ inline void normalize_stdlib_typename(std::string& s) {
197
+ auto strip = [&s](std::string_view marker) {
198
+ for (size_t pos = 0; (pos = s.find(marker, pos)) != std::string::npos; ) {
199
+ s.erase(pos, marker.size());
200
+ }
201
+ };
202
+ strip("__1::");
203
+ strip("__cxx11::");
204
+ for (size_t pos = 0; (pos = s.find("> >", pos)) != std::string::npos; ) {
205
+ s.erase(pos + 1, 1);
206
+ }
207
+ }
208
+
209
+ // Demangle a std::type_info::name() result to a human-readable form
210
+ // (e.g. "tpy::BigInt" instead of "N3tpy6BigIntE"). Used by exception
211
+ // messages that name the offending C++ type. Falls back to the mangled
212
+ // name if demangling fails (typeid name is null-terminated, so the
213
+ // fallback is always usable).
214
+ inline std::string demangle_type_name(const char* mangled) {
215
+ int status = 0;
216
+ char* d = abi::__cxa_demangle(mangled, nullptr, nullptr, &status);
217
+ std::string result = (status == 0 && d) ? std::string(d) : std::string(mangled);
218
+ std::free(d);
219
+ normalize_stdlib_typename(result);
220
+ return result;
221
+ }
222
+
223
+ /**
224
+ * Panic and abort - called on fatal runtime errors.
225
+ */
226
+ [[noreturn]] inline void tpy_panic(std::string_view msg) {
227
+ std::fputs("TurboPython panic: ", stderr);
228
+ std::fwrite(msg.data(), 1, msg.size(), stderr);
229
+ std::fputc('\n', stderr);
230
+ std::exit(1);
231
+ }
232
+
233
+ // Normalizes uncaught-exception output across libstdc++/libc++. Installed from
234
+ // codegen-emitted main() via std::set_terminate; not installed when codegen
235
+ // runs in --no-main mode, so host applications keep their own terminate handler.
236
+ [[noreturn]] inline void tpy_terminate_handler() noexcept {
237
+ std::string type_name = "unknown";
238
+ const char* what_msg = nullptr;
239
+
240
+ // Hold ex across the print: what_msg points into the exception object,
241
+ // which is only guaranteed to outlive any active exception_ptr owning it.
242
+ std::exception_ptr ex = std::current_exception();
243
+ if (ex) {
244
+ try {
245
+ std::rethrow_exception(ex);
246
+ } catch (const std::exception& e) {
247
+ type_name = demangle_type_name(typeid(e).name());
248
+ what_msg = e.what();
249
+ } catch (...) {
250
+ }
251
+ }
252
+
253
+ // Flush any pending pre-panic output (prints from finally bodies,
254
+ // partial lines, etc.) so users see the load-bearing side effects
255
+ // that ran before the panic. `_Exit` below bypasses all stream
256
+ // flushing, so without this the user sees only the panic message.
257
+ // `std::cout` is sync'd with C's stdout by default, so fflush
258
+ // alone covers both streams (avoids dragging in `<iostream>`).
259
+ std::fflush(stdout);
260
+
261
+ std::fputs("TurboPython panic: uncaught ", stderr);
262
+ std::fwrite(type_name.data(), 1, type_name.size(), stderr);
263
+ if (what_msg && *what_msg) {
264
+ std::fputs(": ", stderr);
265
+ std::fputs(what_msg, stderr);
266
+ }
267
+ std::fputc('\n', stderr);
268
+
269
+ std::_Exit(1);
270
+ }
271
+
272
+ /**
273
+ * Checked pointer dereference - panics if pointer is null.
274
+ * Used for implicit Ptr[T] -> T coercion.
275
+ */
276
+ template <typename T>
277
+ T& deref_check(T* ptr) {
278
+ if (ptr == nullptr) {
279
+ tpy_panic("null pointer dereference");
280
+ }
281
+ return *ptr;
282
+ }
283
+
284
+ template <typename T>
285
+ const T& deref_check(const T* ptr) {
286
+ if (ptr == nullptr) {
287
+ tpy_panic("null pointer dereference");
288
+ }
289
+ return *ptr;
290
+ }
291
+
292
+ // User types with __deref__() method
293
+ template <typename T>
294
+ requires requires(T& t) { t.__deref__(); }
295
+ decltype(auto) deref_check(T& obj) {
296
+ return obj.__deref__();
297
+ }
298
+
299
+ /**
300
+ * Checked optional dereference - panics if optional is empty.
301
+ */
302
+ template <typename T>
303
+ T& deref_optional_check(std::optional<T>& opt) {
304
+ if (!opt.has_value()) {
305
+ tpy_panic("null optional dereference");
306
+ }
307
+ return *opt;
308
+ }
309
+
310
+ template <typename T>
311
+ const T& deref_optional_check(const std::optional<T>& opt) {
312
+ if (!opt.has_value()) {
313
+ tpy_panic("null optional dereference");
314
+ }
315
+ return *opt;
316
+ }
317
+
318
+ /**
319
+ * Checked TypedDict optional-field access -- throws KeyError if the
320
+ * field is absent. Used by codegen for `td["key"]` on a `total=False`
321
+ * TypedDict. Distinct from deref_optional_check (which says "null optional
322
+ * dereference") so it matches the existing TPy KeyError convention for
323
+ * dict[k] misses, and avoids raw std::optional::value() whose
324
+ * bad_optional_access::what() text diverges between libstdc++ and libc++.
325
+ */
326
+ template <typename T>
327
+ T& typed_dict_field_check(std::optional<T>& opt) {
328
+ if (!opt.has_value()) {
329
+ raise_key_error("KeyError");
330
+ }
331
+ return *opt;
332
+ }
333
+
334
+ template <typename T>
335
+ const T& typed_dict_field_check(const std::optional<T>& opt) {
336
+ if (!opt.has_value()) {
337
+ raise_key_error("KeyError");
338
+ }
339
+ return *opt;
340
+ }
341
+
342
+ /**
343
+ * Optional truthiness helper - matches Python semantics for Optional[value]:
344
+ * value is truthy only when engaged and contained value is truthy.
345
+ */
346
+ template <typename T>
347
+ inline bool is_truthy(const std::optional<T>& opt) {
348
+ return opt.has_value() && static_cast<bool>(*opt);
349
+ }
350
+
351
+ // String truthiness: non-empty is truthy (std::string has no operator bool)
352
+ inline bool is_truthy(const std::optional<std::string>& opt) {
353
+ return opt.has_value() && !opt->empty();
354
+ }
355
+
356
+ inline bool is_truthy(const std::optional<std::string_view>& opt) {
357
+ return opt.has_value() && !opt->empty();
358
+ }
359
+
360
+ /**
361
+ * Destroy an object at a pointer location.
362
+ * No-op for trivially destructible types (scalars, PODs).
363
+ */
364
+ template <typename T>
365
+ void destroy_at(T* p) {
366
+ if constexpr (!std::is_trivially_destructible_v<T>) {
367
+ p->~T();
368
+ }
369
+ }
370
+
371
+ /**
372
+ * Heap-allocate a T and move-construct it from `value` (combined alloc+init).
373
+ * The std::unique_ptr<T> overload below covers the abstract-@dynamic case
374
+ * where the caller has already heap-allocated; it just releases the handle.
375
+ */
376
+ template <typename T>
377
+ T* heap_take(T&& value) {
378
+ T* p = static_cast<T*>(::operator new(sizeof(T), std::align_val_t(alignof(T))));
379
+ ::new(static_cast<void*>(p)) T(std::move(value));
380
+ return p;
381
+ }
382
+
383
+ template <typename T>
384
+ T* heap_take(std::unique_ptr<T> value) {
385
+ return value.release();
386
+ }
387
+
388
+ /**
389
+ * Destroy and free a heap-allocated T previously produced by heap_take.
390
+ *
391
+ * For polymorphic T (a class with a virtual destructor -- typically the
392
+ * abstract @dynamic protocol base), uses scalar `delete p`. Per [expr.delete],
393
+ * `delete p` with virtual destructor routes through the vtable's *deleting
394
+ * destructor*, which knows the dynamic type and calls the matching operator
395
+ * delete (aligned form if the dynamic type is over-aligned). This is the
396
+ * correct disposal path -- the compiler handles alignment via the vtable.
397
+ *
398
+ * For non-polymorphic T, manually destroys and frees with the same alignment
399
+ * heap_take used. Static and dynamic types coincide, so alignof(T) matches.
400
+ */
401
+ template <typename T>
402
+ void heap_release(T* p) {
403
+ if constexpr (std::has_virtual_destructor_v<T>) {
404
+ delete p; // virtual deleting destructor handles alignment + dynamic size
405
+ } else {
406
+ tpy::destroy_at(p);
407
+ ::operator delete(p, std::align_val_t(alignof(T)));
408
+ }
409
+ }
410
+
411
+ /**
412
+ * Replace the heap-stored T at `p` with `value`, returning the live slot.
413
+ *
414
+ * Concrete T: same allocation, destroy + placement-new. Abstract @dynamic
415
+ * T: the slot's size depends on the dynamic type, so reconstruction
416
+ * requires free + reallocate -- returned pointer differs from input.
417
+ *
418
+ * Precondition: `value` must not alias `*p`. The abstract branch frees
419
+ * `*p` before consuming `value`; an aliased payload would be UAF.
420
+ * Callers must propagate the returned pointer.
421
+ */
422
+ template <typename T>
423
+ T* heap_replace(T* p, own_param_t<T> value) {
424
+ if constexpr (is_dyn_protocol_base_v<T>) {
425
+ heap_release(p);
426
+ return heap_take(std::move(value));
427
+ } else {
428
+ tpy::destroy_at(p);
429
+ ::new(static_cast<void*>(p)) T(std::move(value));
430
+ return p;
431
+ }
432
+ }
433
+
434
+ /**
435
+ * Convert a heap-allocated T* into an Own[T] by transferring ownership.
436
+ *
437
+ * Abstract @dynamic T: adopt as unique_ptr<T> (T-typed local impossible).
438
+ * Concrete T: move out, destroy the moved-from slot, free its storage.
439
+ */
440
+ template <typename T>
441
+ own_return_t<T> transfer_ownership(T* p) {
442
+ if constexpr (is_dyn_protocol_base_v<T>) {
443
+ return std::unique_ptr<T>(p);
444
+ } else {
445
+ T val = std::move(*p);
446
+ tpy::destroy_at(p);
447
+ ::operator delete(p, std::align_val_t(alignof(T)));
448
+ return val;
449
+ }
450
+ }
451
+
452
+ /**
453
+ * Checked true division for floats -- throws ZeroDivisionError on a
454
+ * zero divisor to match Python semantics.
455
+ */
456
+ inline constexpr double truediv(double a, double b) {
457
+ if (b == 0.0) raise_zero_division_error("float division by zero");
458
+ return a / b;
459
+ }
460
+
461
+ // Constant-evaluation helpers: std::floor / std::fmod are constexpr under
462
+ // C++23 P1383 in libstdc++ (GCC 13+), but libc++ (Apple clang / macOS) has
463
+ // not shipped that yet. When the stdlib advertises P1383 we call through
464
+ // unconditionally; otherwise we fall back to hand-rolled constexpr paths
465
+ // selected via `if consteval`. Fallbacks are correct for finite values in
466
+ // long long range, which is the regime Final literals live in; the runtime
467
+ // path is unchanged. Once every supported stdlib defines the feature macro,
468
+ // drop the `#else` branches entirely.
469
+ #if defined(__cpp_lib_constexpr_cmath) && __cpp_lib_constexpr_cmath >= 202202L
470
+ #define TPY_CMATH_CONSTEXPR 1
471
+ #else
472
+ #define TPY_CMATH_CONSTEXPR 0
473
+ #endif
474
+
475
+ inline constexpr double floordiv(double a, double b) {
476
+ if (b == 0.0) raise_zero_division_error("float floor division by zero");
477
+ #if TPY_CMATH_CONSTEXPR
478
+ return std::floor(a / b);
479
+ #else
480
+ if consteval {
481
+ double q = a / b;
482
+ long long i = static_cast<long long>(q);
483
+ double d = static_cast<double>(i);
484
+ return (d > q) ? d - 1.0 : d;
485
+ }
486
+ return std::floor(a / b);
487
+ #endif
488
+ }
489
+
490
+ inline constexpr double fmod(double a, double b) {
491
+ if (b == 0.0) raise_zero_division_error("float modulo");
492
+ // Python's `%` uses floor semantics (sign-of-divisor) where C's std::fmod
493
+ // uses truncation (sign-of-dividend). Compute the truncated remainder,
494
+ // shift toward the divisor when the signs disagree, and on zero results
495
+ // adopt the divisor's sign (matches CPython's float_rem in floatobject.c).
496
+ #if TPY_CMATH_CONSTEXPR
497
+ double m = std::fmod(a, b);
498
+ #else
499
+ double m;
500
+ if consteval {
501
+ long long i = static_cast<long long>(a / b);
502
+ m = a - static_cast<double>(i) * b;
503
+ } else {
504
+ m = std::fmod(a, b);
505
+ }
506
+ #endif
507
+ if (m != 0.0) {
508
+ if ((m < 0.0) != (b < 0.0)) m += b;
509
+ } else {
510
+ m = (b < 0.0) ? -0.0 : 0.0;
511
+ }
512
+ return m;
513
+ }
514
+
515
+ // Float32 arithmetic helpers
516
+ inline constexpr float truediv_f32(float a, float b) {
517
+ if (b == 0.0f) raise_zero_division_error("float division by zero");
518
+ return a / b;
519
+ }
520
+
521
+ inline constexpr float floordiv_f32(float a, float b) {
522
+ if (b == 0.0f) raise_zero_division_error("float floor division by zero");
523
+ #if TPY_CMATH_CONSTEXPR
524
+ return std::floor(a / b);
525
+ #else
526
+ if consteval {
527
+ float q = a / b;
528
+ long long i = static_cast<long long>(q);
529
+ float d = static_cast<float>(i);
530
+ return (d > q) ? d - 1.0f : d;
531
+ }
532
+ return std::floor(a / b);
533
+ #endif
534
+ }
535
+
536
+ inline constexpr float fmod_f32(float a, float b) {
537
+ if (b == 0.0f) raise_zero_division_error("float modulo");
538
+ // Python's `%` uses floor semantics (sign-of-divisor); see fmod above.
539
+ #if TPY_CMATH_CONSTEXPR
540
+ float m = std::fmod(a, b);
541
+ #else
542
+ float m;
543
+ if consteval {
544
+ long long i = static_cast<long long>(a / b);
545
+ m = a - static_cast<float>(i) * b;
546
+ } else {
547
+ m = std::fmod(a, b);
548
+ }
549
+ #endif
550
+ if (m != 0.0f) {
551
+ if ((m < 0.0f) != (b < 0.0f)) m += b;
552
+ } else {
553
+ m = (b < 0.0f) ? -0.0f : 0.0f;
554
+ }
555
+ return m;
556
+ }
557
+
558
+ } // namespace tpy