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,954 @@
1
+ /**
2
+ * TurboPython Runtime - Formatting Utilities
3
+ *
4
+ * Python-style printing for bools, floats, and char-to-string conversion.
5
+ */
6
+
7
+ #pragma once
8
+
9
+ #include <cassert>
10
+ #include <cctype>
11
+ #include <charconv>
12
+ #include <cmath>
13
+ #include <cstdint>
14
+ #include <cstdlib>
15
+ #include <iostream>
16
+ #include <iomanip>
17
+ #include <optional>
18
+ #include <ranges>
19
+ #include <sstream>
20
+ #include <string>
21
+ #include <string_view>
22
+ #include <system_error>
23
+ #include <type_traits>
24
+ #include <vector>
25
+
26
+ #include "core.hpp"
27
+ #include "enum.hpp"
28
+
29
+ namespace tpy {
30
+
31
+ /**
32
+ * Helper struct for Python-style bool printing.
33
+ *
34
+ * Matches Python's repr for bools: prints "True" or "False".
35
+ */
36
+ struct print_bool {
37
+ bool value;
38
+ explicit print_bool(bool v) : value(v) {}
39
+ };
40
+
41
+ inline std::ostream& operator<<(std::ostream& os, const print_bool& pb) {
42
+ os << (pb.value ? "True" : "False");
43
+ return os;
44
+ }
45
+
46
+ /**
47
+ * Helper struct for float printing that matches Python's repr() behavior.
48
+ *
49
+ * - Whole numbers display with ".0" (e.g., "5.0" not "5")
50
+ * - Large numbers use decimal notation for reasonable range
51
+ * - Very small numbers (< 0.0001) use scientific notation like Python
52
+ * - Uses shortest representation that round-trips correctly
53
+ */
54
+ struct print_float {
55
+ double value;
56
+ explicit print_float(double v) : value(v) {}
57
+ };
58
+
59
+ inline std::string format_float(double value) {
60
+ // Special cases
61
+ if (std::isnan(value)) return "nan";
62
+ if (std::isinf(value)) return value > 0 ? "inf" : "-inf";
63
+
64
+ // Python switches to scientific for |x| < 1e-4 or |x| >= 1e16; otherwise
65
+ // it uses fixed notation. std::to_chars's `shortest` form picks the
66
+ // shortest of the two, which doesn't always agree with Python -- so we
67
+ // pick the format ourselves and hand it to to_chars (no precision arg ->
68
+ // shortest round-tripping form within that format).
69
+ double abs_val = std::fabs(value);
70
+ bool use_scientific = (abs_val != 0.0 && abs_val < 1e-4) || abs_val >= 1e16;
71
+
72
+ // 32 bytes covers the worst case: scientific
73
+ // "-1.7976931348623157e+308" (~24 chars), fixed up to ~22 chars within
74
+ // our [1e-4, 1e16) band. Exponent padding is done on the std::string
75
+ // afterwards, not in this buffer.
76
+ char buf[32];
77
+ auto r = std::to_chars(
78
+ buf, buf + sizeof(buf), value,
79
+ use_scientific ? std::chars_format::scientific : std::chars_format::fixed);
80
+ assert(r.ec == std::errc{});
81
+ std::string s(buf, r.ptr);
82
+
83
+ if (use_scientific) {
84
+ // std::to_chars emits the exponent with no leading zeros (e.g. "1e-5");
85
+ // Python pads single-digit exponents to two digits ("1e-05").
86
+ auto e_pos = s.find('e');
87
+ if (e_pos != std::string::npos) {
88
+ std::size_t digits_pos = e_pos + 2; // skip 'e' and sign
89
+ std::size_t digit_count = s.size() - digits_pos;
90
+ if (digit_count < 2) {
91
+ s.insert(digits_pos, std::string(2 - digit_count, '0'));
92
+ }
93
+ }
94
+ } else {
95
+ // Whole numbers come back without a decimal point (e.g. "1");
96
+ // Python's repr() always shows ".0" for floats.
97
+ if (s.find('.') == std::string::npos) {
98
+ s += ".0";
99
+ }
100
+ }
101
+ return s;
102
+ }
103
+
104
+ inline std::ostream& operator<<(std::ostream& os, const print_float& pf) {
105
+ os << format_float(pf.value);
106
+ return os;
107
+ }
108
+
109
+ /**
110
+ * repr_quote_string - Python-style repr of a string.
111
+ *
112
+ * Produces the Python repr form: outer quotes plus C-style escapes for
113
+ * `\\`, `\n`, `\r`, `\t`, the active quote character, and other ASCII
114
+ * control bytes (`\xNN`). Bytes >= 0x80 are passed through as-is so a
115
+ * UTF-8-encoded string round-trips visually.
116
+ *
117
+ * Quote selection follows CPython: prefer `'`, switch to `"` only when
118
+ * the string contains `'` and no `"`.
119
+ */
120
+ inline std::string repr_quote_string(std::string_view s) {
121
+ bool has_single = s.find('\'') != std::string_view::npos;
122
+ bool has_double = s.find('"') != std::string_view::npos;
123
+ char quote = (has_single && !has_double) ? '"' : '\'';
124
+ std::string out;
125
+ out.reserve(s.size() + 2);
126
+ out.push_back(quote);
127
+ for (auto ch : s) {
128
+ unsigned char c = static_cast<unsigned char>(ch);
129
+ switch (c) {
130
+ case '\\': out.append("\\\\"); break;
131
+ case '\n': out.append("\\n"); break;
132
+ case '\r': out.append("\\r"); break;
133
+ case '\t': out.append("\\t"); break;
134
+ default:
135
+ if (ch == quote) {
136
+ out.push_back('\\');
137
+ out.push_back(ch);
138
+ } else if (c < 0x20 || c == 0x7f) {
139
+ static const char kHex[] = "0123456789abcdef";
140
+ out.append("\\x");
141
+ out.push_back(kHex[c >> 4]);
142
+ out.push_back(kHex[c & 0xf]);
143
+ } else {
144
+ out.push_back(ch);
145
+ }
146
+ break;
147
+ }
148
+ }
149
+ out.push_back(quote);
150
+ return out;
151
+ }
152
+
153
+ /**
154
+ * char_to_str - Convert a char to a string_view.
155
+ *
156
+ * Returns a string_view pointing to a static single-character string.
157
+ * Uses a lookup table to avoid allocation.
158
+ */
159
+ inline std::string_view char_to_str(char c) {
160
+ // Static array of single-character null-terminated strings
161
+ static const char chars[256][2] = {
162
+ "\x00", "\x01", "\x02", "\x03", "\x04", "\x05", "\x06", "\x07",
163
+ "\x08", "\x09", "\x0a", "\x0b", "\x0c", "\x0d", "\x0e", "\x0f",
164
+ "\x10", "\x11", "\x12", "\x13", "\x14", "\x15", "\x16", "\x17",
165
+ "\x18", "\x19", "\x1a", "\x1b", "\x1c", "\x1d", "\x1e", "\x1f",
166
+ " ", "!", "\"", "#", "$", "%", "&", "'", "(", ")", "*", "+", ",", "-", ".", "/",
167
+ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ":", ";", "<", "=", ">", "?",
168
+ "@", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O",
169
+ "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "[", "\\", "]", "^", "_",
170
+ "`", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o",
171
+ "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "{", "|", "}", "~", "\x7f",
172
+ "\x80", "\x81", "\x82", "\x83", "\x84", "\x85", "\x86", "\x87",
173
+ "\x88", "\x89", "\x8a", "\x8b", "\x8c", "\x8d", "\x8e", "\x8f",
174
+ "\x90", "\x91", "\x92", "\x93", "\x94", "\x95", "\x96", "\x97",
175
+ "\x98", "\x99", "\x9a", "\x9b", "\x9c", "\x9d", "\x9e", "\x9f",
176
+ "\xa0", "\xa1", "\xa2", "\xa3", "\xa4", "\xa5", "\xa6", "\xa7",
177
+ "\xa8", "\xa9", "\xaa", "\xab", "\xac", "\xad", "\xae", "\xaf",
178
+ "\xb0", "\xb1", "\xb2", "\xb3", "\xb4", "\xb5", "\xb6", "\xb7",
179
+ "\xb8", "\xb9", "\xba", "\xbb", "\xbc", "\xbd", "\xbe", "\xbf",
180
+ "\xc0", "\xc1", "\xc2", "\xc3", "\xc4", "\xc5", "\xc6", "\xc7",
181
+ "\xc8", "\xc9", "\xca", "\xcb", "\xcc", "\xcd", "\xce", "\xcf",
182
+ "\xd0", "\xd1", "\xd2", "\xd3", "\xd4", "\xd5", "\xd6", "\xd7",
183
+ "\xd8", "\xd9", "\xda", "\xdb", "\xdc", "\xdd", "\xde", "\xdf",
184
+ "\xe0", "\xe1", "\xe2", "\xe3", "\xe4", "\xe5", "\xe6", "\xe7",
185
+ "\xe8", "\xe9", "\xea", "\xeb", "\xec", "\xed", "\xee", "\xef",
186
+ "\xf0", "\xf1", "\xf2", "\xf3", "\xf4", "\xf5", "\xf6", "\xf7",
187
+ "\xf8", "\xf9", "\xfa", "\xfb", "\xfc", "\xfd", "\xfe", "\xff"
188
+ };
189
+ return std::string_view(chars[static_cast<unsigned char>(c)], 1);
190
+ }
191
+
192
+ /**
193
+ * str_concat - Concatenate two string-like values into a new std::string.
194
+ *
195
+ * Takes both sides as string_view (zero-copy from std::string, string_view,
196
+ * and const char*) and performs a single optimally-sized allocation.
197
+ */
198
+ inline std::string str_concat(std::string_view a, std::string_view b) {
199
+ std::string result;
200
+ result.reserve(a.size() + b.size());
201
+ result.append(a);
202
+ result.append(b);
203
+ return result;
204
+ }
205
+
206
+ // -- str.split / str.join helpers ------------------------------------------
207
+ // split returns vector<string> (copies) rather than vector<string_view> because
208
+ // TurboPython has no borrow checker to prevent mutation of the source while
209
+ // views exist. A future splitview() could return views for perf-critical code.
210
+
211
+ inline std::vector<std::string> str_split(std::string_view s, std::string_view sep) {
212
+ if (sep.empty()) {
213
+ raise_value_error("empty separator");
214
+ }
215
+ std::vector<std::string> result;
216
+ size_t start = 0;
217
+ while (true) {
218
+ size_t pos = s.find(sep, start);
219
+ if (pos == std::string_view::npos) {
220
+ result.emplace_back(s.substr(start));
221
+ break;
222
+ }
223
+ result.emplace_back(s.substr(start, pos - start));
224
+ start = pos + sep.size();
225
+ }
226
+ return result;
227
+ }
228
+
229
+ inline std::vector<std::string> str_split(std::string_view s, std::string_view sep, int32_t maxsplit) {
230
+ if (sep.empty()) {
231
+ raise_value_error("empty separator");
232
+ }
233
+ if (maxsplit < 0) {
234
+ return str_split(s, sep);
235
+ }
236
+ std::vector<std::string> result;
237
+ size_t start = 0;
238
+ int32_t splits = 0;
239
+ while (splits < maxsplit) {
240
+ size_t pos = s.find(sep, start);
241
+ if (pos == std::string_view::npos) break;
242
+ result.emplace_back(s.substr(start, pos - start));
243
+ start = pos + sep.size();
244
+ ++splits;
245
+ }
246
+ result.emplace_back(s.substr(start));
247
+ return result;
248
+ }
249
+
250
+ inline std::vector<std::string> str_split_whitespace(std::string_view s) {
251
+ std::vector<std::string> result;
252
+ size_t i = 0;
253
+ while (i < s.size()) {
254
+ while (i < s.size() && std::isspace(static_cast<unsigned char>(s[i]))) ++i;
255
+ if (i >= s.size()) break;
256
+ size_t start = i;
257
+ while (i < s.size() && !std::isspace(static_cast<unsigned char>(s[i]))) ++i;
258
+ result.emplace_back(s.substr(start, i - start));
259
+ }
260
+ return result;
261
+ }
262
+
263
+ inline std::vector<std::string> str_split_whitespace(std::string_view s, int32_t maxsplit) {
264
+ if (maxsplit < 0) {
265
+ return str_split_whitespace(s);
266
+ }
267
+ std::vector<std::string> result;
268
+ size_t i = 0;
269
+ int32_t splits = 0;
270
+ while (i < s.size()) {
271
+ while (i < s.size() && std::isspace(static_cast<unsigned char>(s[i]))) ++i;
272
+ if (i >= s.size()) break;
273
+ if (splits >= maxsplit) {
274
+ result.emplace_back(s.substr(i));
275
+ return result;
276
+ }
277
+ size_t start = i;
278
+ while (i < s.size() && !std::isspace(static_cast<unsigned char>(s[i]))) ++i;
279
+ result.emplace_back(s.substr(start, i - start));
280
+ ++splits;
281
+ }
282
+ return result;
283
+ }
284
+
285
+ template<typename Container>
286
+ requires std::ranges::input_range<const Container>
287
+ inline std::string str_join(std::string_view sep, const Container& items) {
288
+ std::string result;
289
+ bool first = true;
290
+ for (const auto& item : items) {
291
+ if (!first) result.append(sep);
292
+ result.append(std::string_view(item));
293
+ first = false;
294
+ }
295
+ return result;
296
+ }
297
+
298
+ inline std::string str_join(std::string_view sep, std::initializer_list<const char*> items) {
299
+ std::string result;
300
+ bool first = true;
301
+ for (auto item : items) {
302
+ if (!first) result.append(sep);
303
+ result.append(item);
304
+ first = false;
305
+ }
306
+ return result;
307
+ }
308
+
309
+ inline std::string str_join(std::string_view sep, std::initializer_list<std::string_view> items) {
310
+ std::string result;
311
+ bool first = true;
312
+ for (auto item : items) {
313
+ if (!first) result.append(sep);
314
+ result.append(item);
315
+ first = false;
316
+ }
317
+ return result;
318
+ }
319
+
320
+ // -- str.strip / lstrip / rstrip -------------------------------------------
321
+
322
+ inline std::string_view str_strip(std::string_view s) {
323
+ size_t start = 0;
324
+ while (start < s.size() && std::isspace(static_cast<unsigned char>(s[start]))) ++start;
325
+ size_t end = s.size();
326
+ while (end > start && std::isspace(static_cast<unsigned char>(s[end - 1]))) --end;
327
+ return s.substr(start, end - start);
328
+ }
329
+
330
+ inline std::string_view str_lstrip(std::string_view s) {
331
+ size_t start = 0;
332
+ while (start < s.size() && std::isspace(static_cast<unsigned char>(s[start]))) ++start;
333
+ return s.substr(start);
334
+ }
335
+
336
+ inline std::string_view str_rstrip(std::string_view s) {
337
+ size_t end = s.size();
338
+ while (end > 0 && std::isspace(static_cast<unsigned char>(s[end - 1]))) --end;
339
+ return s.substr(0, end);
340
+ }
341
+
342
+ // -- str.replace -----------------------------------------------------------
343
+
344
+ inline std::string str_replace(std::string_view s, std::string_view old_sub, std::string_view new_sub) {
345
+ if (old_sub.empty()) {
346
+ // Python semantics: insert new_sub between every character and at both ends
347
+ std::string result;
348
+ result.reserve(s.size() + new_sub.size() * (s.size() + 1));
349
+ for (size_t i = 0; i < s.size(); ++i) {
350
+ result.append(new_sub);
351
+ result += s[i];
352
+ }
353
+ result.append(new_sub);
354
+ return result;
355
+ }
356
+ std::string result;
357
+ size_t start = 0;
358
+ while (true) {
359
+ size_t pos = s.find(old_sub, start);
360
+ if (pos == std::string_view::npos) {
361
+ result.append(s.substr(start));
362
+ break;
363
+ }
364
+ result.append(s.substr(start, pos - start));
365
+ result.append(new_sub);
366
+ start = pos + old_sub.size();
367
+ }
368
+ return result;
369
+ }
370
+
371
+ // -- str.find / rfind / index ----------------------------------------------
372
+
373
+ inline int32_t str_find(std::string_view s, std::string_view sub) {
374
+ auto pos = s.find(sub);
375
+ return pos == std::string_view::npos ? -1 : static_cast<int32_t>(pos);
376
+ }
377
+
378
+ inline int32_t str_rfind(std::string_view s, std::string_view sub) {
379
+ auto pos = s.rfind(sub);
380
+ return pos == std::string_view::npos ? -1 : static_cast<int32_t>(pos);
381
+ }
382
+
383
+ inline int32_t str_index(std::string_view s, std::string_view sub) {
384
+ auto pos = s.find(sub);
385
+ if (pos == std::string_view::npos) {
386
+ raise_value_error("substring not found");
387
+ }
388
+ return static_cast<int32_t>(pos);
389
+ }
390
+
391
+ // -- str.startswith / endswith ---------------------------------------------
392
+
393
+ inline bool str_startswith(std::string_view s, std::string_view prefix) {
394
+ return s.starts_with(prefix);
395
+ }
396
+
397
+ inline bool str_endswith(std::string_view s, std::string_view suffix) {
398
+ return s.ends_with(suffix);
399
+ }
400
+
401
+ // -- str.upper / lower -----------------------------------------------------
402
+
403
+ inline std::string str_upper(std::string_view s) {
404
+ std::string result(s);
405
+ for (auto& c : result) c = static_cast<char>(std::toupper(static_cast<unsigned char>(c)));
406
+ return result;
407
+ }
408
+
409
+ inline std::string str_lower(std::string_view s) {
410
+ std::string result(s);
411
+ for (auto& c : result) c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
412
+ return result;
413
+ }
414
+
415
+ // -- str.__mul__ (string repetition) ---------------------------------------
416
+
417
+ inline std::string str_repeat(std::string_view s, int32_t n) {
418
+ if (n <= 0) return {};
419
+ std::string result;
420
+ result.reserve(s.size() * static_cast<size_t>(n));
421
+ for (int32_t i = 0; i < n; ++i) result.append(s);
422
+ return result;
423
+ }
424
+
425
+ // -- str.count -------------------------------------------------------------
426
+
427
+ inline int32_t str_count(std::string_view s, std::string_view sub) {
428
+ if (sub.empty()) {
429
+ return static_cast<int32_t>(s.size()) + 1;
430
+ }
431
+ int32_t n = 0;
432
+ size_t start = 0;
433
+ while (true) {
434
+ size_t pos = s.find(sub, start);
435
+ if (pos == std::string_view::npos) break;
436
+ ++n;
437
+ start = pos + sub.size();
438
+ }
439
+ return n;
440
+ }
441
+
442
+ // -- str.isdigit / isalpha / isalnum / isspace -----------------------------
443
+
444
+ inline bool str_isdigit(std::string_view s) {
445
+ if (s.empty()) return false;
446
+ for (auto c : s) if (!std::isdigit(static_cast<unsigned char>(c))) return false;
447
+ return true;
448
+ }
449
+
450
+ inline bool str_isalpha(std::string_view s) {
451
+ if (s.empty()) return false;
452
+ for (auto c : s) if (!std::isalpha(static_cast<unsigned char>(c))) return false;
453
+ return true;
454
+ }
455
+
456
+ inline bool str_isalnum(std::string_view s) {
457
+ if (s.empty()) return false;
458
+ for (auto c : s) if (!std::isalnum(static_cast<unsigned char>(c))) return false;
459
+ return true;
460
+ }
461
+
462
+ inline bool str_isspace(std::string_view s) {
463
+ if (s.empty()) return false;
464
+ for (auto c : s) if (!std::isspace(static_cast<unsigned char>(c))) return false;
465
+ return true;
466
+ }
467
+
468
+ // -- str.isupper / islower -------------------------------------------------
469
+
470
+ inline bool str_isupper(std::string_view s) {
471
+ bool has_cased = false;
472
+ for (auto c : s) {
473
+ unsigned char uc = static_cast<unsigned char>(c);
474
+ if (std::islower(uc)) return false;
475
+ if (std::isupper(uc)) has_cased = true;
476
+ }
477
+ return has_cased;
478
+ }
479
+
480
+ inline bool str_islower(std::string_view s) {
481
+ bool has_cased = false;
482
+ for (auto c : s) {
483
+ unsigned char uc = static_cast<unsigned char>(c);
484
+ if (std::isupper(uc)) return false;
485
+ if (std::islower(uc)) has_cased = true;
486
+ }
487
+ return has_cased;
488
+ }
489
+
490
+ // -- str.capitalize / title / swapcase -------------------------------------
491
+
492
+ inline std::string str_capitalize(std::string_view s) {
493
+ std::string result(s);
494
+ if (!result.empty()) {
495
+ result[0] = static_cast<char>(std::toupper(static_cast<unsigned char>(result[0])));
496
+ for (size_t i = 1; i < result.size(); ++i)
497
+ result[i] = static_cast<char>(std::tolower(static_cast<unsigned char>(result[i])));
498
+ }
499
+ return result;
500
+ }
501
+
502
+ inline std::string str_title(std::string_view s) {
503
+ std::string result(s);
504
+ bool after_boundary = true;
505
+ for (size_t i = 0; i < result.size(); ++i) {
506
+ unsigned char uc = static_cast<unsigned char>(result[i]);
507
+ if (std::isalpha(uc)) {
508
+ result[i] = static_cast<char>(after_boundary ? std::toupper(uc) : std::tolower(uc));
509
+ after_boundary = false;
510
+ } else {
511
+ after_boundary = true;
512
+ }
513
+ }
514
+ return result;
515
+ }
516
+
517
+ inline std::string str_swapcase(std::string_view s) {
518
+ std::string result(s);
519
+ for (auto& c : result) {
520
+ unsigned char uc = static_cast<unsigned char>(c);
521
+ if (std::isupper(uc)) c = static_cast<char>(std::tolower(uc));
522
+ else if (std::islower(uc)) c = static_cast<char>(std::toupper(uc));
523
+ }
524
+ return result;
525
+ }
526
+
527
+ // -- str.removeprefix / removesuffix ---------------------------------------
528
+
529
+ inline std::string_view str_removeprefix(std::string_view s, std::string_view prefix) {
530
+ if (s.starts_with(prefix)) return s.substr(prefix.size());
531
+ return s;
532
+ }
533
+
534
+ inline std::string_view str_removesuffix(std::string_view s, std::string_view suffix) {
535
+ if (!suffix.empty() && s.ends_with(suffix)) return s.substr(0, s.size() - suffix.size());
536
+ return s;
537
+ }
538
+
539
+ // -- str.rindex ------------------------------------------------------------
540
+
541
+ inline int32_t str_rindex(std::string_view s, std::string_view sub) {
542
+ auto pos = s.rfind(sub);
543
+ if (pos == std::string_view::npos) {
544
+ raise_value_error("substring not found");
545
+ }
546
+ return static_cast<int32_t>(pos);
547
+ }
548
+
549
+ // -- str.splitlines --------------------------------------------------------
550
+
551
+ inline std::vector<std::string> str_splitlines(std::string_view s) {
552
+ std::vector<std::string> result;
553
+ size_t start = 0;
554
+ for (size_t i = 0; i < s.size(); ++i) {
555
+ if (s[i] == '\n') {
556
+ result.emplace_back(s.substr(start, i - start));
557
+ start = i + 1;
558
+ } else if (s[i] == '\r') {
559
+ result.emplace_back(s.substr(start, i - start));
560
+ if (i + 1 < s.size() && s[i + 1] == '\n') ++i;
561
+ start = i + 1;
562
+ }
563
+ }
564
+ if (start < s.size()) {
565
+ result.emplace_back(s.substr(start));
566
+ }
567
+ return result;
568
+ }
569
+
570
+ /**
571
+ * bool_to_str - Convert bool to "True" or "False" string.
572
+ * Returns const char* pointing to static storage (safe for std::string_view).
573
+ */
574
+ inline const char* bool_to_str(bool x) {
575
+ return x ? "True" : "False";
576
+ }
577
+
578
+ /**
579
+ * fixed_to_str - Convert any fixed-width integer to string.
580
+ * 8-bit types are promoted to int to avoid char interpretation.
581
+ */
582
+ template<typename T>
583
+ inline std::string fixed_to_str(T x) {
584
+ if constexpr (sizeof(T) == 1)
585
+ return std::to_string(static_cast<int>(x));
586
+ else
587
+ return std::to_string(x);
588
+ }
589
+
590
+ /**
591
+ * float_to_str - Convert double to string.
592
+ * Produces Python-like output (removes trailing zeros after decimal point).
593
+ * Note: Returns std::string. Caller must ensure the result is used immediately
594
+ * or stored in std::string/auto, not std::string_view.
595
+ */
596
+ inline std::string float_to_str(double x) {
597
+ // Use Python's repr-like approach: shortest representation that round-trips
598
+ std::ostringstream oss;
599
+ oss << std::setprecision(15) << x;
600
+ std::string result = oss.str();
601
+
602
+ // If no decimal point and no exponent, add .0 for Python compatibility
603
+ if (result.find('.') == std::string::npos && result.find('e') == std::string::npos) {
604
+ result += ".0";
605
+ }
606
+
607
+ // Remove trailing zeros after decimal point (but keep at least one digit)
608
+ size_t dot = result.find('.');
609
+ if (dot != std::string::npos) {
610
+ size_t e_pos = result.find('e');
611
+ size_t end = (e_pos != std::string::npos) ? e_pos : result.size();
612
+ while (end > dot + 2 && result[end - 1] == '0') {
613
+ --end;
614
+ }
615
+ if (e_pos != std::string::npos) {
616
+ result = result.substr(0, end) + result.substr(e_pos);
617
+ } else {
618
+ result = result.substr(0, end);
619
+ }
620
+ }
621
+ return result;
622
+ }
623
+
624
+ /**
625
+ * float_from_str - Convert string to double.
626
+ * Panics on invalid input (Python raises ValueError).
627
+ * Supports optional leading/trailing whitespace, sign, and special values
628
+ * "inf", "infinity", "-inf", "-infinity", "nan" (case-insensitive).
629
+ */
630
+ inline double float_from_str(std::string_view s) {
631
+ size_t start = 0;
632
+ while (start < s.size() && std::isspace(static_cast<unsigned char>(s[start]))) ++start;
633
+ size_t end = s.size();
634
+ while (end > start && std::isspace(static_cast<unsigned char>(s[end - 1]))) --end;
635
+
636
+ if (start >= end) {
637
+ raise_value_error("could not convert string to float: '{}'", s);
638
+ }
639
+
640
+ std::string trimmed(s.substr(start, end - start));
641
+ char* endptr;
642
+ double result = std::strtod(trimmed.c_str(), &endptr);
643
+
644
+ if (endptr != trimmed.c_str() + trimmed.size()) {
645
+ raise_value_error("could not convert string to float: '{}'", s);
646
+ }
647
+
648
+ return result;
649
+ }
650
+
651
+ /**
652
+ * float32_from_str - Convert string to float (32-bit).
653
+ * Same as float_from_str but narrows to single precision.
654
+ * Out-of-range values produce +/-inf (matching Python behavior).
655
+ */
656
+ inline float float32_from_str(std::string_view s) {
657
+ double d = float_from_str(s);
658
+ return static_cast<float>(d);
659
+ }
660
+
661
+ /**
662
+ * print_optional_val - Print a std::optional<T> as Python would.
663
+ *
664
+ * Prints "None" for empty optional, otherwise prints the value.
665
+ * The Formatter template parameter controls how the value is printed:
666
+ * - void (default): prints the value directly via operator<<
667
+ * - print_bool: prints True/False
668
+ * - print_float: prints Python-style float
669
+ */
670
+ template<typename Formatter, typename T>
671
+ struct print_optional_val {
672
+ const std::optional<T>& opt;
673
+ explicit print_optional_val(const std::optional<T>& o) : opt(o) {}
674
+ };
675
+
676
+ // Deduction guide: print_optional_val(opt) deduces Formatter=void
677
+ template<typename T>
678
+ print_optional_val(const std::optional<T>&) -> print_optional_val<void, T>;
679
+
680
+ template<typename Formatter, typename T>
681
+ inline std::ostream& operator<<(std::ostream& os, const print_optional_val<Formatter, T>& po) {
682
+ if (po.opt.has_value()) {
683
+ if constexpr (std::is_same_v<Formatter, void>) {
684
+ if constexpr (std::is_enum_v<T>
685
+ && requires(T x) { ::tpy::EnumUtil<T>::name(x); }) {
686
+ // Enum: route through the shared EnumUtil formatter.
687
+ // Avoids requiring an operator<< for the enum (which
688
+ // @native enums don't emit -- would conflict with any
689
+ // user-provided one).
690
+ ::tpy::detail::write_enum_repr(os, *po.opt);
691
+ } else {
692
+ os << *po.opt;
693
+ }
694
+ } else {
695
+ os << Formatter(*po.opt);
696
+ }
697
+ } else {
698
+ os << "None";
699
+ }
700
+ return os;
701
+ }
702
+
703
+ /**
704
+ * print_optional - Print a nullable pointer as Python would.
705
+ *
706
+ * Prints "None" for nullptr, otherwise prints the pointed-to value.
707
+ * The optional Formatter template arg (default void) lets callers route
708
+ * the pointee through a wrapper printer -- e.g. ListPrinter<vector<T>>
709
+ * for nullable containers whose underlying type lacks a plain operator<<.
710
+ */
711
+ template<typename Formatter, typename T>
712
+ struct print_optional {
713
+ const T* ptr;
714
+ explicit print_optional(const T* p) : ptr(p) {}
715
+ };
716
+
717
+ // Deduction guide: print_optional(ptr) deduces Formatter=void.
718
+ template<typename T>
719
+ print_optional(const T*) -> print_optional<void, T>;
720
+
721
+ template<typename Formatter, typename T>
722
+ inline std::ostream& operator<<(std::ostream& os, const print_optional<Formatter, T>& po) {
723
+ if (po.ptr) {
724
+ if constexpr (std::is_same_v<Formatter, void>) {
725
+ os << *(po.ptr);
726
+ } else {
727
+ os << Formatter(*(po.ptr));
728
+ }
729
+ } else {
730
+ os << "None";
731
+ }
732
+ return os;
733
+ }
734
+
735
+ /**
736
+ * ptr_to_optional - Convert a T* nullable pointer to std::optional<T>.
737
+ *
738
+ * nullptr → std::nullopt, otherwise copies the pointed-to value.
739
+ * Used at the T* → std::optional<T> boundary (e.g., assigning a pointer-local
740
+ * to an optional record field).
741
+ */
742
+ template<typename T>
743
+ std::optional<T> ptr_to_optional(const T* ptr) {
744
+ if (ptr) return *ptr;
745
+ return std::nullopt;
746
+ }
747
+
748
+ /**
749
+ * ptr_to_optional_move - Move a pointee value into a fresh std::optional<T>.
750
+ *
751
+ * nullptr -> std::nullopt; otherwise constructs the optional from std::move
752
+ * of the pointee. Used by Own[tuple[T_ref|None,...]] call sites where sema
753
+ * has cleared each element as movable (last-use lvalue, fresh rvalue, or
754
+ * explicit copy()). Caller is giving up ownership of the pointee; moving
755
+ * lifts to the storage form without copying.
756
+ */
757
+ template<typename T>
758
+ std::optional<T> ptr_to_optional_move(T* ptr) {
759
+ if (ptr) return std::optional<T>{std::move(*ptr)};
760
+ return std::nullopt;
761
+ }
762
+
763
+ /**
764
+ * optional_to_ptr - Convert std::optional<T>& to T* (mutable).
765
+ *
766
+ * Empty optional → nullptr, otherwise pointer to stored value.
767
+ * Used at the std::optional<T> → T* boundary (e.g., reading an optional
768
+ * record field into a pointer-local variable).
769
+ */
770
+ template<typename T>
771
+ T* optional_to_ptr(std::optional<T>& opt) {
772
+ if (opt.has_value()) return &*opt;
773
+ return nullptr;
774
+ }
775
+
776
+ template<typename T>
777
+ const T* optional_to_ptr(const std::optional<T>& opt) {
778
+ if (opt.has_value()) return &*opt;
779
+ return nullptr;
780
+ }
781
+
782
+ namespace detail {
783
+
784
+ // Per-element conversion used by tuple_to_storage / tuple_to_pointer.
785
+ // Dispatch on the destination slot type so mixed tuples (e.g. Ptr[T] +
786
+ // Optional[U]) convert only the slots that need it -- a Src-typed overload
787
+ // set would lift every T*/const T* slot to std::optional regardless of the
788
+ // Dest shape.
789
+
790
+ template<typename Dest, typename Src>
791
+ inline Dest to_optional_form(Src&& s) {
792
+ using SrcD = std::remove_cvref_t<Src>;
793
+ using DestD = std::remove_cvref_t<Dest>;
794
+ if constexpr (std::is_same_v<SrcD, DestD>) {
795
+ return std::forward<Src>(s);
796
+ } else if constexpr (std::is_pointer_v<SrcD>) {
797
+ return ptr_to_optional(s);
798
+ } else {
799
+ return std::forward<Src>(s);
800
+ }
801
+ }
802
+
803
+ // Per-element conversion for tuple_to_storage_move: pointer-form sources
804
+ // move the pointee into the optional; same-shape sources pass through.
805
+ template<typename Dest, typename Src>
806
+ inline Dest to_optional_form_move(Src&& s) {
807
+ using SrcD = std::remove_cvref_t<Src>;
808
+ using DestD = std::remove_cvref_t<Dest>;
809
+ if constexpr (std::is_same_v<SrcD, DestD>) {
810
+ return std::forward<Src>(s);
811
+ } else if constexpr (std::is_pointer_v<SrcD>) {
812
+ return ptr_to_optional_move(s);
813
+ } else {
814
+ return std::forward<Src>(s);
815
+ }
816
+ }
817
+
818
+ template<typename Dest, typename Src>
819
+ inline Dest to_pointer_form(Src&& s) {
820
+ using SrcD = std::remove_cvref_t<Src>;
821
+ using DestD = std::remove_cvref_t<Dest>;
822
+ if constexpr (std::is_same_v<SrcD, DestD>) {
823
+ return std::forward<Src>(s);
824
+ } else if constexpr (std::is_pointer_v<SrcD> && std::is_pointer_v<DestD>) {
825
+ // Pointer-form source already; allow implicit qualification adjustment
826
+ // (P* -> const P*) without round-tripping through optional_to_ptr.
827
+ // Removing const would require const_cast and is not a valid use case.
828
+ static_assert(std::is_const_v<std::remove_pointer_t<DestD>>
829
+ || !std::is_const_v<std::remove_pointer_t<SrcD>>,
830
+ "to_pointer_form: cannot remove const from pointer");
831
+ return s;
832
+ } else if constexpr (std::is_pointer_v<DestD>) {
833
+ return optional_to_ptr(s);
834
+ } else {
835
+ return std::forward<Src>(s);
836
+ }
837
+ }
838
+
839
+ } // namespace detail
840
+
841
+ template<typename ToTuple, typename FromTuple, std::size_t... I>
842
+ inline ToTuple tuple_to_storage_impl(FromTuple&& t, std::index_sequence<I...>) {
843
+ return ToTuple(detail::to_optional_form<std::tuple_element_t<I, ToTuple>>(
844
+ std::get<I>(std::forward<FromTuple>(t)))...);
845
+ }
846
+
847
+ // Lift a pointer-form tuple (T*, ..., U) to storage-form (std::optional<T>, ..., U).
848
+ // Plain elements pass through unchanged. Used at field-write boundaries where
849
+ // the field stores std::tuple<std::optional<...>, ...> but the source is a
850
+ // borrow-form tuple from a function return / param / local.
851
+ template<typename ToTuple, typename FromTuple>
852
+ inline ToTuple tuple_to_storage(FromTuple&& t) {
853
+ using F = std::remove_reference_t<FromTuple>;
854
+ return tuple_to_storage_impl<ToTuple>(std::forward<FromTuple>(t),
855
+ std::make_index_sequence<std::tuple_size_v<F>>{});
856
+ }
857
+
858
+ template<typename ToTuple, typename FromTuple, std::size_t... I>
859
+ inline ToTuple tuple_to_storage_move_impl(FromTuple&& t, std::index_sequence<I...>) {
860
+ return ToTuple(detail::to_optional_form_move<std::tuple_element_t<I, ToTuple>>(
861
+ std::get<I>(std::forward<FromTuple>(t)))...);
862
+ }
863
+
864
+ // Move-variant of tuple_to_storage: each pointer-form element's pointee is
865
+ // moved into the destination optional. Emitted at Own[tuple[T_ref|None,...]]
866
+ // call sites where sema has cleared every element as movable (last-use
867
+ // lvalue, fresh rvalue, or explicit copy() rvalue). Required for the
868
+ // move-at-last-use semantic that distinguishes Own[tuple] from a bare-tuple
869
+ // borrow boundary.
870
+ template<typename ToTuple, typename FromTuple>
871
+ inline ToTuple tuple_to_storage_move(FromTuple&& t) {
872
+ using F = std::remove_reference_t<FromTuple>;
873
+ return tuple_to_storage_move_impl<ToTuple>(std::forward<FromTuple>(t),
874
+ std::make_index_sequence<std::tuple_size_v<F>>{});
875
+ }
876
+
877
+ template<typename ToTuple, typename FromTuple, std::size_t... I>
878
+ inline ToTuple tuple_to_pointer_impl(FromTuple&& t, std::index_sequence<I...>) {
879
+ return ToTuple(detail::to_pointer_form<std::tuple_element_t<I, ToTuple>>(
880
+ std::get<I>(std::forward<FromTuple>(t)))...);
881
+ }
882
+
883
+ // Lower a storage-form tuple (std::optional<T>, ..., U) to pointer-form
884
+ // (T*, ..., U). Plain elements pass through unchanged. Used at field-read
885
+ // boundaries where the consumer is a pointer-form tuple param.
886
+ template<typename ToTuple, typename FromTuple>
887
+ inline ToTuple tuple_to_pointer(FromTuple&& t) {
888
+ using F = std::remove_reference_t<FromTuple>;
889
+ return tuple_to_pointer_impl<ToTuple>(std::forward<FromTuple>(t),
890
+ std::make_index_sequence<std::tuple_size_v<F>>{});
891
+ }
892
+
893
+ namespace detail {
894
+
895
+ // Per-element conversion from a value-form source slot to the corresponding
896
+ // borrow-form destination slot. `s` is always an lvalue ref to a slot in
897
+ // the source value tuple, so taking addresses / binding refs is safe -- the
898
+ // caller's tuple temp lives for the whole full-expression.
899
+ //
900
+ // Source slots may already be in borrow form when codegen mixes rvalue and
901
+ // lvalue elements at the same site (e.g. (T(1), &local) -> std::tuple<T,
902
+ // T*>): same-shape Src/Dest pass through; only Src=value + Dest=pointer
903
+ // takes the address.
904
+ template<typename Dest, typename Src>
905
+ inline Dest borrow_value_elem(Src& s) {
906
+ using DestNoRef = std::remove_reference_t<Dest>;
907
+ using SrcD = std::remove_cv_t<Src>;
908
+ using DestNoRefCV = std::remove_cv_t<DestNoRef>;
909
+ if constexpr (std::is_same_v<SrcD, DestNoRefCV>) {
910
+ return s;
911
+ } else if constexpr (std::is_pointer_v<DestNoRef>
912
+ && !std::is_pointer_v<SrcD>) {
913
+ return &s;
914
+ } else {
915
+ return s;
916
+ }
917
+ }
918
+
919
+ } // namespace detail
920
+
921
+ template<typename ToTuple, typename FromTuple, std::size_t... I>
922
+ inline ToTuple tuple_value_to_borrow_impl(FromTuple& t, std::index_sequence<I...>) {
923
+ return ToTuple(detail::borrow_value_elem<std::tuple_element_t<I, ToTuple>>(
924
+ std::get<I>(t))...);
925
+ }
926
+
927
+ // Convert a value-form source tuple (rvalue or lvalue) to a borrow-form
928
+ // destination tuple (T*, T&, or const T*-form slots). Used at tuple-literal
929
+ // sites whose target tuple has borrow-form slots and at least one literal
930
+ // element is an rvalue (e.g. `f((Point(1), 42))` where `f` takes a
931
+ // `tuple[Point | None, Int32]` or `tuple[Point, Int32]`).
932
+ //
933
+ // The caller materializes the source tuple as a temporary -- C++ extends
934
+ // its lifetime to the end of the surrounding full-expression, so the
935
+ // addresses / refs in the returned tuple stay valid through the call.
936
+ template<typename ToTuple, typename FromTuple>
937
+ inline ToTuple tuple_value_to_borrow(FromTuple&& t) {
938
+ using F = std::remove_reference_t<FromTuple>;
939
+ F& lref = t;
940
+ return tuple_value_to_borrow_impl<ToTuple>(
941
+ lref, std::make_index_sequence<std::tuple_size_v<F>>{});
942
+ }
943
+
944
+ // Default repr for records without __repr__/__str__: "<ClassName object at 0xADDR>"
945
+ template<typename T>
946
+ inline std::ostream& print_object_default(std::ostream& os, std::string_view class_name, const T& obj) {
947
+ auto flags = os.flags();
948
+ os << "<" << class_name << " object at 0x"
949
+ << std::hex << reinterpret_cast<uintptr_t>(&obj) << ">";
950
+ os.flags(flags);
951
+ return os;
952
+ }
953
+
954
+ } // namespace tpy