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,18 @@
1
+ """
2
+ TurboPython C++ Code Generator Package
3
+
4
+ Generates C++ code from the analyzed TurboPython AST:
5
+ - Records -> structs with constructors
6
+ - Functions -> free functions
7
+ - Protocols -> C++20 concepts
8
+ - Pointer field access (.) -> arrow operator (->)
9
+ """
10
+
11
+ from .context import CodeGenError, CodeGenOptions
12
+ from .generator import CodeGenerator
13
+
14
+ __all__ = [
15
+ 'CodeGenerator',
16
+ 'CodeGenError',
17
+ 'CodeGenOptions',
18
+ ]
@@ -0,0 +1,484 @@
1
+ """
2
+ TurboPython Builtin Code Generation
3
+
4
+ Code generation for builtin functions, type constructors, and print().
5
+ """
6
+
7
+ from __future__ import annotations
8
+ from typing import TYPE_CHECKING
9
+
10
+ from ..typesys import (
11
+ TpyType, IntLiteralType,
12
+ NominalType, OptionalType, NoneType, TypeParamRef, TypeParamKind, FunctionInfo, RecordInfo,
13
+ ListRepeatType,
14
+ TupleType, OwnType, is_protocol_type, unwrap_readonly, is_any_str_type, is_any_bytes_type,
15
+ make_ref,
16
+ is_float_type, is_integer_type,
17
+ )
18
+ from ..parse import (
19
+ TpyExpr, TpyCall, TpyStrLiteral, TpyArrayLiteral, TpyNoneLiteral, TpyCoerce,
20
+ TpyBoolLiteral, TpyFieldAccess,
21
+ )
22
+
23
+ from .context import escape_cpp_string, CodeGenError, expand_cpp_template, qualify_native_name, cpp_string_literal_expr
24
+ from ..type_def_registry import (
25
+ is_dict_view, is_set, is_dict, is_array, is_span, is_list,
26
+ is_fixed_int_type, is_big_int_type, is_bool_type, is_float32_type, is_float64_type,
27
+ is_bytearray_type, int_traits_of, is_enum_type, enum_info_of,
28
+ )
29
+
30
+ if TYPE_CHECKING:
31
+ from .context import CodeGenContext
32
+ from .types import TypeResolver
33
+
34
+
35
+ # float(str) special-value tokens that fold to constexpr numeric_limits at
36
+ # codegen, bypassing the non-constexpr runtime tpy::float_from_str. Matches
37
+ # CPython's case-insensitive, whitespace-trimming semantics. Note: CPython
38
+ # preserves the sign bit for float("-nan"), so emitting -quiet_NaN() (IEEE 754
39
+ # sign-bit flip) is bit-for-bit equivalent, not just functionally-isnan.
40
+ _FLOAT_STR_CONSTANTS: dict[str, str] = {
41
+ "nan": "std::numeric_limits<double>::quiet_NaN()",
42
+ "+nan": "std::numeric_limits<double>::quiet_NaN()",
43
+ "-nan": "-std::numeric_limits<double>::quiet_NaN()",
44
+ "inf": "std::numeric_limits<double>::infinity()",
45
+ "+inf": "std::numeric_limits<double>::infinity()",
46
+ "-inf": "-std::numeric_limits<double>::infinity()",
47
+ "infinity": "std::numeric_limits<double>::infinity()",
48
+ "+infinity": "std::numeric_limits<double>::infinity()",
49
+ "-infinity": "-std::numeric_limits<double>::infinity()",
50
+ }
51
+
52
+
53
+ class BuiltinGenerator:
54
+ """Generates C++ code for builtin functions and type constructors."""
55
+
56
+ def __init__(self, ctx: CodeGenContext, types: TypeResolver):
57
+ self.ctx = ctx
58
+ self.types = types
59
+ # Will be set by expressions module to avoid circular import
60
+ self._gen_expr = None
61
+ self._gen_expr_deref = None
62
+ self._gen_call_arg = None
63
+ self._get_cpp_declared_type = None
64
+
65
+ def set_expr_generator(self, gen_expr, gen_expr_deref, gen_call_arg,
66
+ get_cpp_declared_type):
67
+ """Set expression generator functions (to break circular dependency)."""
68
+ self._gen_expr = gen_expr
69
+ self._gen_expr_deref = gen_expr_deref
70
+ self._gen_call_arg = gen_call_arg
71
+ self._get_cpp_declared_type = get_cpp_declared_type
72
+
73
+ def gen_call_from_fi(self, fi: FunctionInfo, receiver: str | None,
74
+ gen_args: list[str], *,
75
+ self_type: TpyType | None = None,
76
+ type_args: tuple[TpyType, ...] | None = None) -> str:
77
+ """Generate a call from a resolved FunctionInfo.
78
+
79
+ Unified entry point for cpp_template, native_function, and native member calls.
80
+ receiver is None for free function calls (no self).
81
+ self_type: receiver's TpyType (for {cpp} expansion in method templates).
82
+ type_args: inferred type arguments paired with fi.type_params by position.
83
+ """
84
+ if fi.cpp_template:
85
+ template = fi.cpp_template
86
+ # Substitute method-level type params
87
+ effective_subst: dict[str, TpyType] | None = None
88
+ if type_args and fi.type_params:
89
+ effective_subst = dict(zip(fi.type_params, type_args))
90
+ if effective_subst:
91
+ for name, typ in effective_subst.items():
92
+ placeholder = f"{{{name}}}"
93
+ if placeholder in template and hasattr(typ, "to_cpp"):
94
+ template = template.replace(placeholder, typ.to_cpp_stored())
95
+ # {cpp} substitutes the (substituted) return-type spelling.
96
+ # Used by free functions whose template needs the full
97
+ # return-type C++ shape rather than just `{T}` -- e.g.
98
+ # `unsafe_cast[T] -> Ptr[T]` wants `Ptr[None]` to lower to
99
+ # `void*` (PtrType's special-case) rather than `std::monostate*`.
100
+ if "{cpp}" in template and fi.return_type is not None:
101
+ ret_type = fi.return_type
102
+ if effective_subst:
103
+ ret_type = self.types.substitute_type_params(ret_type, effective_subst)
104
+ template = template.replace("{cpp}", ret_type.to_cpp())
105
+ if receiver is not None:
106
+ return expand_cpp_template(template, receiver, *gen_args,
107
+ self_type=self_type)
108
+ return template.format(*gen_args)
109
+ if fi.native_function and fi.native_name:
110
+ all_args = [receiver] + gen_args if receiver is not None else gen_args
111
+ return f"{qualify_native_name(fi.native_name)}({', '.join(all_args)})"
112
+ if fi.native_name:
113
+ args_str = ", ".join(gen_args)
114
+ if receiver is not None:
115
+ return f"{receiver}.{fi.native_name}({args_str})"
116
+ return f"{qualify_native_name(fi.native_name)}({args_str})"
117
+ args_str = ", ".join(gen_args)
118
+ if receiver is not None:
119
+ return f"{receiver}.{fi.name}({args_str})"
120
+ return f"{fi.name}({args_str})"
121
+
122
+ def get_type_method_fi(self, tpy_type: TpyType, method_name: str) -> FunctionInfo | None:
123
+ """Look up a single-overload method's FunctionInfo from the registry.
124
+
125
+ Returns None for multi-overload methods (use resolved_function_info instead).
126
+ Falls back to dunder protocol templates for protocol types.
127
+ """
128
+ record_info = self.ctx.analyzer.registry.get_record_for_type(tpy_type)
129
+ if record_info:
130
+ overloads = record_info.get_method_overloads(method_name)
131
+ if len(overloads) > 1:
132
+ if method_name == "__getitem__":
133
+ # Multi-overload __getitem__: find the integer-index overload
134
+ for fi in overloads:
135
+ if (len(fi.params) == 1
136
+ and is_integer_type(fi.params[0].type)
137
+ and (fi.cpp_template or fi.native_function or fi.native_name)):
138
+ return fi
139
+ return None
140
+ if method_name == "__setitem__":
141
+ # Multi-overload __setitem__: find the integer-index overload
142
+ for fi in overloads:
143
+ if (len(fi.params) == 2
144
+ and is_integer_type(fi.params[0].type)
145
+ and (fi.cpp_template or fi.native_function or fi.native_name)):
146
+ return fi
147
+ return None
148
+ raise RuntimeError(
149
+ f"get_type_method_fi called for multi-overload method "
150
+ f"'{method_name}' on {tpy_type}; use resolved_function_info instead"
151
+ )
152
+ if overloads:
153
+ fi = overloads[0]
154
+ if fi.cpp_template or fi.native_function or fi.native_name:
155
+ return fi
156
+ # Dunder protocol templates (e.g., __getitem__ -> ::tpy::__getitem__)
157
+ if is_protocol_type(tpy_type):
158
+ from ..modules import get_dunder_cpp_template
159
+ tmpl = get_dunder_cpp_template(method_name)
160
+ if tmpl:
161
+ from ..typesys import VOID
162
+ return FunctionInfo(name=method_name, params=[], return_type=VOID,
163
+ cpp_template=tmpl)
164
+ return None
165
+
166
+ def gen_method_from_function_info(self, obj: str, args: list[TpyExpr],
167
+ method: FunctionInfo) -> str:
168
+ """Generate method call code from a FunctionInfo with pre-generated args."""
169
+ gen_args = [self._gen_call_arg(arg, method.params[i].type if i < len(method.params) else None,
170
+ inline_template=True)
171
+ for i, arg in enumerate(args)]
172
+ return self.gen_call_from_fi(method, obj, gen_args)
173
+
174
+
175
+ def _match_overload_args(self, args: list[TpyExpr],
176
+ overloads: list[FunctionInfo]) -> tuple[FunctionInfo, list[str]]:
177
+ """Match a builtin call to an overload and generate C++ arg expressions.
178
+
179
+ Returns (matched_overload, gen_args). Raises RuntimeError if no match.
180
+ """
181
+ arg_types = [self.ctx.get_expr_type(arg) for arg in args]
182
+
183
+ for overload in overloads:
184
+ if len(overload.params) != len(args):
185
+ continue
186
+ if all(self._builtin_codegen_type_matches(arg, arg_t, ptype)
187
+ for arg, arg_t, (_, ptype) in zip(args, arg_types, overload.params)):
188
+ gen_args = [self._gen_call_arg(arg, ptype, inline_template=True)
189
+ for arg, (_, ptype) in zip(args, overload.params)]
190
+ return overload, gen_args
191
+
192
+ raise RuntimeError(f"No matching overload for {overloads[0].name if overloads else '?'}")
193
+
194
+ def gen_range_args(self, expr: TpyCall) -> list[str]:
195
+ """Generate individual C++ arg expressions for range().
196
+
197
+ Returns the generated arg list (e.g. ["0", "10", "2"]) rather than
198
+ formatting into the full template string. Used by the counter-loop
199
+ optimisation in statements.py.
200
+ """
201
+ fi = expr.resolved_function_info
202
+ return [self._gen_expr_deref(arg, ptype)
203
+ for arg, (_, ptype) in zip(expr.args, fi.params)]
204
+
205
+ @staticmethod
206
+ def _try_float_str_fold(fi: FunctionInfo, args: list[TpyExpr]) -> str | None:
207
+ """Fold `float("nan"/"inf"/"-inf"/...)` to a constexpr numeric_limits.
208
+
209
+ Returns the C++ expression string if the call resolves to the builtin
210
+ `float.__init__(str)` with a recognized special-value literal arg;
211
+ otherwise None (caller proceeds with the normal native dispatch that
212
+ emits `tpy::float_from_str(...)`).
213
+ """
214
+ if not (fi.is_method and fi.name == "__init__" and len(args) == 1):
215
+ return None
216
+ if fi.owning_type_qname != "builtins.float":
217
+ return None
218
+ arg = args[0]
219
+ if not isinstance(arg, TpyStrLiteral):
220
+ return None
221
+ return _FLOAT_STR_CONSTANTS.get(arg.value.strip().lower())
222
+
223
+ def gen_template_or_native_call(self, args: list[TpyExpr],
224
+ overloads: list[FunctionInfo], *,
225
+ fi: FunctionInfo | None = None,
226
+ type_args: tuple[TpyType, ...] | None = None) -> str:
227
+ """Generate C++ for a @cpp_template or @native function call.
228
+
229
+ Generates arg expressions, then delegates to gen_call_from_fi.
230
+ fi: resolved FunctionInfo (when available from sema).
231
+ type_args: inferred type arguments for generic calls.
232
+ """
233
+ if fi and (fi.cpp_template or fi.native_name):
234
+ # float("nan"/"inf"/"-inf"/aliases) -> constexpr numeric_limits fold.
235
+ # Defensive: gen_template_or_native_call is currently called for
236
+ # free functions / module functions, not record __init__, so this
237
+ # won't fire for float.__init__ today (that path goes through
238
+ # _gen_call / _gen_method_call direct calls to gen_call_from_fi,
239
+ # which have their own fold invocations). Kept here so a future
240
+ # caller that passes fi=float.__init__ through this entry point
241
+ # still folds correctly. Gated on fi.is_method + fi.owning_type_qname
242
+ # so user shadows of `float` don't fold.
243
+ folded = self._try_float_str_fold(fi, args)
244
+ if folded is not None:
245
+ return folded
246
+ # cpp_template substitutes the arg expression textually, so a
247
+ # bare lvalue arg is fine when it's not a last-use consume --
248
+ # skip gen_call_arg's lvalue->rvalue copy-temp in that case.
249
+ inline_template = bool(fi.cpp_template)
250
+ gen_args = [self._gen_call_arg(arg, ptype, inline_template=inline_template)
251
+ for arg, (_, ptype) in zip(args, fi.params)]
252
+ return self.gen_call_from_fi(fi, None, gen_args, type_args=type_args)
253
+ # Fallback: re-resolve (shouldn't normally be needed)
254
+ overload, gen_args = self._match_overload_args(args, overloads)
255
+ return self.gen_call_from_fi(overload, None, gen_args, type_args=type_args)
256
+
257
+ def _builtin_codegen_type_matches(self, arg: TpyExpr, arg_type: TpyType, param_type: TpyType) -> bool:
258
+ """Check if an argument matches a parameter type for codegen purposes."""
259
+ # Direct type match
260
+ if isinstance(arg_type, type(param_type)) and arg_type == param_type:
261
+ return True
262
+ # Protocol parameter: sema already verified conformance, accept any arg
263
+ if is_protocol_type(param_type):
264
+ return True
265
+ # IntLiteral can match Int32 (if compile-time) or BigInt (if runtime)
266
+ if isinstance(arg_type, IntLiteralType):
267
+ if is_big_int_type(param_type):
268
+ return self.types.is_runtime_bigint(arg, arg_type)
269
+ if is_fixed_int_type(param_type):
270
+ return not self.types.is_runtime_bigint(arg, arg_type)
271
+ # INT TypeParamRef can match Int32 or BigInt (it's a compile-time constant)
272
+ if isinstance(arg_type, TypeParamRef) and arg_type.kind == TypeParamKind.INT:
273
+ return is_integer_type(param_type)
274
+ # TpyCoerce nodes match their expected type
275
+ if isinstance(arg, TpyCoerce):
276
+ return arg.expected_type == param_type
277
+ return False
278
+
279
+ def gen_print(self, args: list[TpyExpr], kwargs: dict[str, TpyExpr] = None) -> str:
280
+ """Generate stream call for print().
281
+
282
+ Default sink is std::cout. With `file=`, uses ::tpy::as_ostream(<f>)
283
+ to dispatch on the static type (TextFile, StdStream, std::ostream&,
284
+ or generic Writable via streambuf adapter). With `flush=True`,
285
+ appends `<< std::flush` to the chain. sep= and end= accept literals
286
+ or runtime string expressions.
287
+ """
288
+ kwargs = kwargs or {}
289
+
290
+ # sep / end resolve to a single ready-to-emit C++ token (or None to
291
+ # skip emission). Literals shorten to a quoted string; runtime exprs
292
+ # render via _gen_expr_deref. Empty literals are skipped entirely so
293
+ # `print(..., sep="")` doesn't emit a redundant `<< ""`.
294
+ def chain_token(kw_name: str, default_literal: str) -> str | None:
295
+ kw_expr = kwargs.get(kw_name)
296
+ if kw_expr is None:
297
+ return f'"{default_literal}"' if default_literal else None
298
+ if isinstance(kw_expr, TpyStrLiteral):
299
+ if not kw_expr.value:
300
+ return None
301
+ return cpp_string_literal_expr(kw_expr.value)
302
+ return self._gen_expr_deref(kw_expr)
303
+
304
+ end_token = chain_token("end", "\\n")
305
+ sep_token = chain_token("sep", " ")
306
+
307
+ # Sink: default cout, or as_ostream(file) when file= is provided.
308
+ if "file" in kwargs:
309
+ sink = f"::tpy::as_ostream({self._gen_expr_deref(kwargs['file'])})"
310
+ else:
311
+ sink = "std::cout"
312
+
313
+ # flush=True appends `<< std::flush` to the chain.
314
+ flush_expr = kwargs.get("flush")
315
+ flush_on = isinstance(flush_expr, TpyBoolLiteral) and flush_expr.value
316
+
317
+ if not args:
318
+ tail = []
319
+ if end_token is not None:
320
+ tail.append(end_token)
321
+ if flush_on:
322
+ tail.append("std::flush")
323
+ if not tail:
324
+ return ""
325
+ return f"{sink} << " + " << ".join(tail)
326
+
327
+ parts = []
328
+ for i, arg in enumerate(args):
329
+ if i > 0 and sep_token is not None:
330
+ parts.append(sep_token)
331
+
332
+ arg_type = unwrap_readonly(self.types.get_resolved_type(arg))
333
+ if isinstance(arg_type, OwnType):
334
+ arg_type = arg_type.wrapped
335
+
336
+ # When sema narrowed an optional field to its inner type,
337
+ # the C++ field is still std::optional<T> -- use the declared
338
+ # type for print formatting decisions.
339
+ if (not isinstance(arg_type, OptionalType)
340
+ and isinstance(arg, TpyFieldAccess)):
341
+ declared = self._get_cpp_declared_type(arg)
342
+ if isinstance(declared, OptionalType):
343
+ arg_type = declared
344
+
345
+ if isinstance(arg, TpyNoneLiteral):
346
+ parts.append('"None"')
347
+ elif isinstance(arg_type, NoneType):
348
+ # NoneType-typed expression (e.g. `x = await none_coro()`).
349
+ # std::monostate has no operator<<, so a direct `std::cout
350
+ # << x` won't compile; evaluate the expression for side
351
+ # effects, discard, then emit the literal.
352
+ expr_code = self._gen_expr_deref(arg)
353
+ parts.append(f'((void)({expr_code}), "None")')
354
+ elif isinstance(arg, TpyStrLiteral):
355
+ parts.append(cpp_string_literal_expr(arg.value))
356
+ elif self.types.is_runtime_bigint(arg, arg_type):
357
+ # BigInt has operator<< for std::ostream, no .to_string() needed
358
+ parts.append(self._gen_expr_deref(arg))
359
+ elif is_float64_type(arg_type):
360
+ parts.append(f'::tpy::print_float({self._gen_expr_deref(arg)})')
361
+ elif is_float32_type(arg_type):
362
+ parts.append(f'::tpy::print_float(static_cast<double>({self._gen_expr_deref(arg)}))')
363
+ elif is_bool_type(arg_type):
364
+ # Bool uses Python-style formatting via ::tpy::print_bool
365
+ parts.append(f'::tpy::print_bool({self._gen_expr_deref(arg)})')
366
+ elif isinstance(arg_type, OptionalType) and arg_type.uses_pointer_repr():
367
+ # Pointer-repr Optional source: container/dict/set/bytes inners
368
+ # need an explicit Formatter -- the underlying types lack a
369
+ # plain operator<<, so the default `os << *ptr` path fails to
370
+ # compile. Other inners stay on CTAD. Field access always uses
371
+ # print_optional_val (field storage is std::optional<T>).
372
+ inner = arg_type.inner
373
+ gen = self._gen_expr(arg)
374
+ inner_cpp = inner.to_cpp()
375
+ fmt = self._optional_container_formatter(inner, inner_cpp)
376
+ fn = "print_optional_val" if isinstance(arg, TpyFieldAccess) else "print_optional"
377
+ tmpl = f"<{fmt}, {inner_cpp}>" if fmt is not None else ""
378
+ parts.append(f'::tpy::{fn}{tmpl}({gen})')
379
+ elif isinstance(arg_type, OptionalType) and not arg_type.uses_pointer_repr():
380
+ # Optional value-type: use print_optional_val with inner-type-aware formatting.
381
+ # Render the bare optional storage here (NOT _gen_expr_deref) -- print_optional_val
382
+ # consumes the std::optional<T> directly to print "None" vs the value. _gen_expr_deref
383
+ # would unwrap narrowed value-Optional fields, forcing a redundant rewrap on the way
384
+ # into the function.
385
+ inner = arg_type.inner
386
+ gen = self._gen_expr(arg)
387
+ inner_cpp = inner.to_cpp()
388
+ if is_bool_type(inner):
389
+ parts.append(f'::tpy::print_optional_val<::tpy::print_bool, {inner_cpp}>({gen})')
390
+ elif is_float_type(inner):
391
+ parts.append(f'::tpy::print_optional_val<::tpy::print_float, {inner_cpp}>({gen})')
392
+ elif (fmt := self._optional_container_formatter(inner, inner_cpp)) is not None:
393
+ parts.append(f'::tpy::print_optional_val<{fmt}, {inner_cpp}>({gen})')
394
+ else:
395
+ parts.append(f'::tpy::print_optional_val({gen})')
396
+ elif isinstance(arg_type, TupleType):
397
+ parts.append(f'::tpy::TuplePrinter({self._gen_expr_deref(arg)})')
398
+ elif is_any_str_type(arg_type):
399
+ # Strings print as-is (not using ListPrinter)
400
+ parts.append(self._gen_expr_deref(arg))
401
+ elif is_bytearray_type(arg_type):
402
+ parts.append(f'::tpy::ByteArrayPrinter({self._gen_expr_deref(arg)})')
403
+ elif is_any_bytes_type(arg_type):
404
+ parts.append(f'::tpy::BytesPrinter({self._gen_expr_deref(arg)})')
405
+ elif is_dict(arg_type):
406
+ # Dict uses DictPrinter for {k: v, ...} formatting
407
+ parts.append(f'::tpy::DictPrinter({self._gen_expr_deref(arg)})')
408
+ elif is_set(arg_type):
409
+ # Set uses SetPrinter for {a, b, c} or set() formatting
410
+ parts.append(f'::tpy::SetPrinter({self._gen_expr_deref(arg)})')
411
+ elif is_dict_view(arg_type):
412
+ # Dict views use their own operator<< for printing
413
+ parts.append(self._gen_expr_deref(arg))
414
+ elif is_array(arg_type) or is_span(arg_type) or is_list(arg_type) or isinstance(arg_type, ListRepeatType):
415
+ # Sequence containers use ListPrinter for [a, b, c] formatting
416
+ if isinstance(arg, TpyArrayLiteral):
417
+ # Array literals need explicit type for ListPrinter CTAD
418
+ cpp_type = arg_type.to_cpp()
419
+ parts.append(f'::tpy::ListPrinter({cpp_type}{self._gen_expr(arg)})')
420
+ else:
421
+ parts.append(f'::tpy::ListPrinter({self._gen_expr_deref(arg)})')
422
+ elif isinstance(arg_type, TypeParamRef):
423
+ # Generic type parameter -- use ValuePrinter for runtime dispatch
424
+ parts.append(f'::tpy::ValuePrinter({self._gen_expr_deref(arg)})')
425
+ elif is_enum_type(arg_type) and (einfo := enum_info_of(arg_type)) is not None and einfo.is_native:
426
+ # @native enums: no operator<< is emitted (would conflict
427
+ # with user-provided one). Route through __repr__ which
428
+ # the runtime template resolves via EnumUtil. Tpy-defined
429
+ # enums keep the raw-emit path below (their operator<< is
430
+ # still emitted; preserves existing behavior).
431
+ parts.append(f'::tpy::__repr__({self._gen_expr_deref(arg)})')
432
+ else:
433
+ # FixedInt, Char, Bool, literals, etc. - direct output
434
+ expr_code = self._gen_expr_deref(arg)
435
+ # 8-bit integers need cast to avoid char interpretation in std::cout
436
+ arg_tr = int_traits_of(arg_type)
437
+ if arg_tr is not None and arg_tr.bits == 8:
438
+ expr_code = f"static_cast<int>({expr_code})"
439
+ parts.append(expr_code)
440
+
441
+ if end_token is not None:
442
+ parts.append(end_token)
443
+
444
+ if flush_on:
445
+ parts.append("std::flush")
446
+
447
+ return f"{sink} << " + " << ".join(parts)
448
+
449
+ def _optional_container_formatter(self, inner: TpyType, inner_cpp: str) -> str | None:
450
+ """Pick a Formatter type for print_optional / print_optional_val when
451
+ the Optional inner is a container/tuple/bytes type whose underlying C++
452
+ representation lacks a plain `operator<<` (list/Array/Span ->
453
+ vector/array/span, dict -> ordered_map, set -> ordered_set, tuple ->
454
+ std::tuple, bytes/bytearray -> vector<uint8_t>). Returns the Formatter
455
+ type string or None when no wrapper is needed (dict_view types have
456
+ their own operator<<, so the default print_optional/_val path works).
457
+ """
458
+ # bytearray is also "any bytes" per is_any_bytes_type, so check the
459
+ # narrower bytearray predicate first to keep the bytearray(b'...')
460
+ # repr distinct from bytes' b'...' repr.
461
+ if is_bytearray_type(inner):
462
+ return "::tpy::ByteArrayPrinter"
463
+ if is_any_bytes_type(inner):
464
+ return "::tpy::BytesPrinter"
465
+ if isinstance(inner, TupleType):
466
+ elem_cpps = ", ".join(et.to_cpp() for et in inner.element_types)
467
+ return f"::tpy::TuplePrinter<{elem_cpps}>"
468
+ if is_dict(inner):
469
+ type_args = inner.type_args
470
+ if type_args and len(type_args) >= 2:
471
+ key_cpp = type_args[0].to_cpp()
472
+ value_cpp = type_args[1].to_cpp()
473
+ return f"::tpy::DictPrinter<{key_cpp}, {value_cpp}>"
474
+ return None
475
+ if is_set(inner):
476
+ type_args = inner.type_args
477
+ if type_args:
478
+ elem_cpp = type_args[0].to_cpp()
479
+ return f"::tpy::SetPrinter<{elem_cpp}>"
480
+ return None
481
+ if (is_list(inner) or is_array(inner) or is_span(inner)
482
+ or isinstance(inner, ListRepeatType)):
483
+ return f"::tpy::ListPrinter<{inner_cpp}>"
484
+ return None