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,461 @@
1
+ /**
2
+ * TurboPython Runtime - Any (typing.Any)
3
+ *
4
+ * Type-erased value cell. Holds any concrete copyable value via std::any
5
+ * plus a per-type ops table for the universal operations (print, str,
6
+ * repr, bool, equals, hash) that the compiler dispatches on raw `Any`.
7
+ *
8
+ * v1 stores copyable contents only -- the std::any backing requires
9
+ * CopyConstructible. Move-only support is deferred (would require a
10
+ * custom wrapper with destroy/move slots replacing std::any).
11
+ *
12
+ * See docs/ANY_TYPE_DESIGN.md for the full design.
13
+ *
14
+ * Depends on: dunder.hpp (__str__, __repr__, __hash__), builtins.hpp
15
+ * (to_bool), core.hpp (raise<E>, tpy_panic, demangle_type_name),
16
+ * type_name.hpp (user-facing TPy type names).
17
+ */
18
+
19
+ #pragma once
20
+
21
+ #include <any>
22
+ #include <concepts>
23
+ #include <cstdint>
24
+ #include <format>
25
+ #include <ostream>
26
+ #include <string>
27
+ #include <string_view>
28
+ #include <type_traits>
29
+ #include <typeinfo>
30
+ #include <utility>
31
+
32
+ namespace tpy {
33
+
34
+ // Forward declarations from other tpy headers; these resolve via ADL when
35
+ // any.hpp is included after dunder.hpp / builtins.hpp / core.hpp via the
36
+ // umbrella tpy.hpp. We do not include them directly to keep this header
37
+ // self-contained when read in isolation.
38
+
39
+ struct AnyOps;
40
+
41
+ // ---------------------------------------------------------------------
42
+ // Any: std::any storage + per-type ops table
43
+ // ---------------------------------------------------------------------
44
+
45
+ struct Any {
46
+ std::any value;
47
+ const AnyOps* ops;
48
+
49
+ // Default-constructed Any is the empty/moved-from state. TPy source
50
+ // does not allow this (no default-init for non-trivial types); it
51
+ // arises only from std::any moves. Operations on an empty Any panic
52
+ // -- see any_cast_or_panic / any_eq / any_hash below.
53
+ Any() noexcept : value(), ops(nullptr) {}
54
+
55
+ Any(std::any v, const AnyOps* o) noexcept
56
+ : value(std::move(v)), ops(o) {}
57
+
58
+ bool empty() const noexcept { return !value.has_value(); }
59
+ };
60
+
61
+ // ---------------------------------------------------------------------
62
+ // AnyOps: dispatch table for universal operations
63
+ // ---------------------------------------------------------------------
64
+ //
65
+ // `equals` and `hash` are populated only for types that satisfy the
66
+ // corresponding compile-time concept (operator== / tpy::__hash__). When
67
+ // null, the runtime path panics or returns False per the design doc.
68
+
69
+ struct AnyOps {
70
+ void (*print)(std::ostream&, const std::any&);
71
+ void (*str)(std::string&, const std::any&);
72
+ void (*repr)(std::string&, const std::any&);
73
+ bool (*to_bool)(const std::any&);
74
+ bool (*equals)(const std::any&, const std::any&); // null if T not Eq
75
+ std::uint64_t (*hash)(const std::any&); // null if T not Hashable
76
+ // User-facing TPy type name of the cell's T (e.g. "int", "str",
77
+ // "module.MyClass"). Cold-path; only consulted by panic messages.
78
+ std::string (*type_name)();
79
+ };
80
+
81
+ // ---------------------------------------------------------------------
82
+ // Per-T conditional slot generation
83
+ // ---------------------------------------------------------------------
84
+
85
+ namespace detail {
86
+
87
+ template <typename T>
88
+ concept any_str_capable = requires(const T& t) {
89
+ { ::tpy::__str__(t) } -> std::convertible_to<std::string>;
90
+ };
91
+
92
+ // The concept stays on `::tpy::__repr__` rather than `::tpy::repr_of`
93
+ // because repr_of is a single template that always SFINAE-passes here
94
+ // (then hard-errors inside), so it can't act as a capability check.
95
+ // `::tpy::__repr__(t)` resolves against the explicit overload set: if no
96
+ // matching __repr__ exists for T (e.g. raw containers like
97
+ // std::vector<T>, ordered_set<T> -- they print via *Printer wrappers,
98
+ // not free __repr__), the requires-clause cleanly fails and the slot
99
+ // falls back to __str__/typeid. The actual call site uses repr_of so
100
+ // ADL into a user record's namespace still picks up per-record default
101
+ // overrides.
102
+ template <typename T>
103
+ concept any_repr_capable = requires(const T& t) {
104
+ { ::tpy::__repr__(t) } -> std::convertible_to<std::string>;
105
+ };
106
+
107
+ // Mirror tpy::to_bool's acceptance criteria. Going through `tpy::to_bool`
108
+ // itself would instantiate its `static_assert(false, ...)` for
109
+ // non-capable T at concept-check time and break compilation.
110
+ template <typename T>
111
+ concept any_to_bool_capable =
112
+ std::is_same_v<T, std::monostate> ||
113
+ std::is_constructible_v<bool, T> ||
114
+ requires(const T& t) { { t.empty() } -> std::convertible_to<bool>; } ||
115
+ requires(const T& t) { { t.__bool__() } -> std::convertible_to<bool>; };
116
+
117
+ template <typename T>
118
+ concept any_eq_capable = requires(const T& a, const T& b) {
119
+ { a == b } -> std::convertible_to<bool>;
120
+ };
121
+
122
+ template <typename T>
123
+ concept any_hash_capable = requires(const T& t) {
124
+ { ::tpy::__hash__(t) } -> std::convertible_to<std::uint64_t>;
125
+ };
126
+
127
+ // Mangled typeid name as the fallback for types without __str__/__repr__.
128
+ // Python's default is `<ClassName object at 0x...>`; TPy has no class-name
129
+ // registry, so the typeid's mangled name is the best we can do.
130
+ inline std::string fallback_object_repr(const std::any& a) {
131
+ std::string s = "<";
132
+ s += a.type().name();
133
+ s += " object>";
134
+ return s;
135
+ }
136
+
137
+ // Resolve the per-T value of type T from std::any once, then pick a
138
+ // rendering: prefer_repr=false favours __str__ over __repr__ (str/print
139
+ // slots); prefer_repr=true inverts (repr slot). Sink can be either
140
+ // std::string& (append) or std::ostream& (operator<<); _emit_to is
141
+ // overloaded for both.
142
+ inline void _emit_to(std::string& buf, std::string_view s) { buf.append(s); }
143
+ inline void _emit_to(std::ostream& os, std::string_view s) { os << s; }
144
+
145
+ template <typename T, bool prefer_repr, typename Sink>
146
+ inline void _write_str_or_repr(Sink& sink, const std::any& a) {
147
+ if constexpr (prefer_repr) {
148
+ if constexpr (any_repr_capable<T>) {
149
+ _emit_to(sink, ::tpy::repr_of(std::any_cast<const T&>(a)));
150
+ return;
151
+ } else if constexpr (any_str_capable<T>) {
152
+ _emit_to(sink, ::tpy::__str__(std::any_cast<const T&>(a)));
153
+ return;
154
+ }
155
+ } else {
156
+ if constexpr (any_str_capable<T>) {
157
+ _emit_to(sink, ::tpy::__str__(std::any_cast<const T&>(a)));
158
+ return;
159
+ } else if constexpr (any_repr_capable<T>) {
160
+ _emit_to(sink, ::tpy::repr_of(std::any_cast<const T&>(a)));
161
+ return;
162
+ }
163
+ }
164
+ _emit_to(sink, fallback_object_repr(a));
165
+ }
166
+
167
+ template <typename T>
168
+ constexpr void (*str_slot_for() noexcept)(std::string&, const std::any&) {
169
+ return +[](std::string& buf, const std::any& a) {
170
+ _write_str_or_repr<T, /*prefer_repr=*/false>(buf, a);
171
+ };
172
+ }
173
+
174
+ template <typename T>
175
+ constexpr void (*print_slot_for() noexcept)(std::ostream&, const std::any&) {
176
+ return +[](std::ostream& os, const std::any& a) {
177
+ _write_str_or_repr<T, /*prefer_repr=*/false>(os, a);
178
+ };
179
+ }
180
+
181
+ template <typename T>
182
+ constexpr void (*repr_slot_for() noexcept)(std::string&, const std::any&) {
183
+ return +[](std::string& buf, const std::any& a) {
184
+ _write_str_or_repr<T, /*prefer_repr=*/true>(buf, a);
185
+ };
186
+ }
187
+
188
+ template <typename T>
189
+ constexpr bool (*to_bool_slot_for() noexcept)(const std::any&) {
190
+ if constexpr (any_to_bool_capable<T>) {
191
+ return +[](const std::any& a) -> bool {
192
+ return ::tpy::to_bool(std::any_cast<const T&>(a));
193
+ };
194
+ } else {
195
+ // Python default: objects without __bool__/__len__ are truthy.
196
+ return +[](const std::any&) -> bool { return true; };
197
+ }
198
+ }
199
+
200
+ template <typename T>
201
+ constexpr bool (*equals_slot_for() noexcept)(const std::any&, const std::any&) {
202
+ if constexpr (any_eq_capable<T>) {
203
+ return +[](const std::any& a, const std::any& b) -> bool {
204
+ return std::any_cast<const T&>(a) == std::any_cast<const T&>(b);
205
+ };
206
+ } else {
207
+ return nullptr;
208
+ }
209
+ }
210
+
211
+ template <typename T>
212
+ constexpr std::uint64_t (*hash_slot_for() noexcept)(const std::any&) {
213
+ if constexpr (any_hash_capable<T>) {
214
+ return +[](const std::any& a) -> std::uint64_t {
215
+ return ::tpy::__hash__(std::any_cast<const T&>(a));
216
+ };
217
+ } else {
218
+ return nullptr;
219
+ }
220
+ }
221
+
222
+ template <typename T>
223
+ constexpr std::string (*type_name_slot_for() noexcept)() {
224
+ return +[]() -> std::string { return ::tpy::type_name<T>(); };
225
+ }
226
+
227
+ } // namespace detail
228
+
229
+ // `inline constexpr` template variables guarantee a single instance per
230
+ // T across translation units in a single binary. Cross-shared-library
231
+ // identity is out of scope (TPy builds as one binary).
232
+ //
233
+ // Every slot is conditionally generated. Slots whose underlying op is
234
+ // missing fall back to a sensible default (Python-conformant where
235
+ // possible): str/print/repr render `<typeid object>`, to_bool returns
236
+ // true, equals/hash stay null and trigger the documented runtime
237
+ // behaviour (== returns False; hash() panics).
238
+ template <typename T>
239
+ inline constexpr AnyOps any_ops_for = {
240
+ /*print=*/detail::print_slot_for<T>(),
241
+ /*str=*/detail::str_slot_for<T>(),
242
+ /*repr=*/detail::repr_slot_for<T>(),
243
+ /*to_bool=*/detail::to_bool_slot_for<T>(),
244
+ /*equals=*/detail::equals_slot_for<T>(),
245
+ /*hash=*/detail::hash_slot_for<T>(),
246
+ /*type_name=*/detail::type_name_slot_for<T>(),
247
+ };
248
+
249
+ // ---------------------------------------------------------------------
250
+ // make_any<T>: factory that wires the value to its per-T ops table
251
+ // ---------------------------------------------------------------------
252
+ //
253
+ // Codegen emits `::tpy::make_any(value)` and lets argument deduction
254
+ // pick T -- so the source is `make_any(BigInt(42))` rather than the
255
+ // hand-spelled `Any{std::any{BigInt(42)}, &any_ops_for<BigInt>}`.
256
+ // Callers must build `value` so its decayed C++ type *is* the desired
257
+ // storage typeid (e.g. `BigInt(42)` not `42`, `std::string("hi")` not
258
+ // `"hi"`); the codegen layer's _any_storage_form ensures that.
259
+
260
+ template <typename T>
261
+ inline Any make_any(T value) {
262
+ return Any{std::any{std::move(value)}, &any_ops_for<T>};
263
+ }
264
+
265
+ // ---------------------------------------------------------------------
266
+ // any_cast_or_panic<T>: checked extraction
267
+ // ---------------------------------------------------------------------
268
+ //
269
+ // const-ref overload copies the contents out (auto-coerce paths use
270
+ // this). The rvalue overload moves out at last use.
271
+
272
+ namespace detail {
273
+
274
+ template <typename T>
275
+ inline void check_any_cast(const Any& a) {
276
+ if (a.empty()) {
277
+ ::tpy::tpy_panic("use of empty/moved-from Any");
278
+ }
279
+ if (a.value.type() != typeid(T)) {
280
+ ::tpy::raise_type_error("Any holds {}, cannot cast to {}",
281
+ a.ops->type_name(),
282
+ ::tpy::type_name<T>());
283
+ }
284
+ }
285
+
286
+ } // namespace detail
287
+
288
+ template <typename T>
289
+ T any_cast_or_panic(const Any& a) {
290
+ detail::check_any_cast<T>(a);
291
+ return std::any_cast<T>(a.value);
292
+ }
293
+
294
+ template <typename T>
295
+ T any_cast_or_panic(Any&& a) {
296
+ detail::check_any_cast<T>(a);
297
+ T moved = std::any_cast<T>(std::move(a.value));
298
+ // Clear the source so the documented "use of empty/moved-from Any"
299
+ // panic fires on subsequent access. std::any_cast<T>(rvalue) does
300
+ // not necessarily empty the source.
301
+ a.value.reset();
302
+ a.ops = nullptr;
303
+ return moved;
304
+ }
305
+
306
+ // ---------------------------------------------------------------------
307
+ // any_eq / any_eq_concrete / any_hash
308
+ // ---------------------------------------------------------------------
309
+ //
310
+ // `==` semantics: type-mismatch returns False (Python behaviour for
311
+ // non-promotable types). When the equals slot is null (T isn't Eq),
312
+ // also False -- the only honest answer when T has no notion of equality.
313
+ // Empty/moved-from Any is never equal to anything (also returns False).
314
+
315
+ inline bool any_eq(const Any& a, const Any& b) {
316
+ if (a.empty() || b.empty()) return false;
317
+ if (a.value.type() != b.value.type()) return false;
318
+ if (a.ops == nullptr || a.ops->equals == nullptr) return false;
319
+ return a.ops->equals(a.value, b.value);
320
+ }
321
+
322
+ template <typename U>
323
+ bool any_eq_concrete(const Any& a, const U& b) {
324
+ if (a.empty()) return false;
325
+ if (a.value.type() != typeid(U)) return false;
326
+ return std::any_cast<const U&>(a.value) == b;
327
+ }
328
+
329
+ template <typename U>
330
+ bool any_eq_concrete(const U& a, const Any& b) {
331
+ return any_eq_concrete<U>(b, a);
332
+ }
333
+
334
+ // Hashing: panics if the contained T is not Hashable, or if the cell
335
+ // is empty. Compile-time `hash(any_var)` cannot fail at type check
336
+ // because Any satisfies the Hashable concept at the type-system level
337
+ // -- the runtime check is the trade-off for accepting arbitrary T.
338
+ inline std::uint64_t any_hash(const Any& a) {
339
+ if (a.empty()) {
340
+ ::tpy::tpy_panic("use of empty/moved-from Any");
341
+ }
342
+ if (a.ops == nullptr || a.ops->hash == nullptr) {
343
+ std::string name = (a.ops != nullptr)
344
+ ? a.ops->type_name()
345
+ : ::tpy::demangle_type_name(a.value.type().name());
346
+ ::tpy::raise_type_error("unhashable type: '{}'", name);
347
+ }
348
+ return a.ops->hash(a.value);
349
+ }
350
+
351
+ // Container-element printing routes through `tpy::detail::print_element`,
352
+ // which renders strings as `'foo'` (repr-flavoured) so `print(d)` for
353
+ // `dict[str, str]` reads `{'k': 'v'}`. Any values inside containers
354
+ // follow the same convention -- route through the repr slot rather
355
+ // than the str slot used by top-level operator<<.
356
+ namespace detail {
357
+ inline void print_element(std::ostream& os, const ::tpy::Any& a) {
358
+ if (a.empty()) {
359
+ ::tpy::tpy_panic("use of empty/moved-from Any");
360
+ }
361
+ std::string buf;
362
+ a.ops->repr(buf, a.value);
363
+ os << buf;
364
+ }
365
+ } // namespace detail
366
+
367
+ // ---------------------------------------------------------------------
368
+ // Integration with TPy runtime primitives
369
+ // ---------------------------------------------------------------------
370
+ //
371
+ // `__str__(Any)` falls through to `operator<<` via dunder.hpp's
372
+ // generic-fallback chain -- defining `operator<<` is enough.
373
+ // `__repr__(Any)` needs an explicit definition because the fallback
374
+ // would route through `operator<<` (which renders via the str slot,
375
+ // not the repr slot) and silently produce the str representation.
376
+
377
+ inline std::ostream& operator<<(std::ostream& os, const Any& a) {
378
+ if (a.empty()) {
379
+ ::tpy::tpy_panic("use of empty/moved-from Any");
380
+ }
381
+ a.ops->print(os, a.value);
382
+ return os;
383
+ }
384
+
385
+ inline std::string __repr__(const Any& a) {
386
+ if (a.empty()) {
387
+ ::tpy::tpy_panic("use of empty/moved-from Any");
388
+ }
389
+ std::string buf;
390
+ a.ops->repr(buf, a.value);
391
+ return buf;
392
+ }
393
+
394
+ inline std::uint64_t __hash__(const Any& a) {
395
+ return any_hash(a);
396
+ }
397
+
398
+ // `to_bool(const T&)` in builtins.hpp tests `requires { x.empty(); }`
399
+ // before `__bool__()`, so Any's empty() helper would otherwise hijack
400
+ // truthiness. This explicit overload routes through the to_bool slot.
401
+ inline bool to_bool(const Any& a) {
402
+ if (a.empty()) {
403
+ ::tpy::tpy_panic("use of empty/moved-from Any");
404
+ }
405
+ return a.ops->to_bool(a.value);
406
+ }
407
+
408
+ // Equality: typeid-checked. Type mismatch returns False (Python
409
+ // behaviour for incomparable types); null equals slot also False.
410
+
411
+ inline bool operator==(const Any& a, const Any& b) {
412
+ return any_eq(a, b);
413
+ }
414
+
415
+ template <typename U>
416
+ requires (!std::same_as<U, Any>)
417
+ inline bool operator==(const Any& a, const U& b) {
418
+ return any_eq_concrete<U>(a, b);
419
+ }
420
+
421
+ template <typename U>
422
+ requires (!std::same_as<U, Any>)
423
+ inline bool operator==(const U& a, const Any& b) {
424
+ return any_eq_concrete<U>(b, a);
425
+ }
426
+
427
+ } // namespace tpy
428
+
429
+ // std::hash<tpy::Any> for use as a key in std::unordered_map / set
430
+ // based containers (TPy's ordered_map / ordered_set). Routes through
431
+ // the per-type hash slot; panics if the contained T isn't Hashable.
432
+ template <>
433
+ struct std::hash<::tpy::Any> {
434
+ std::size_t operator()(const ::tpy::Any& a) const {
435
+ return static_cast<std::size_t>(::tpy::any_hash(a));
436
+ }
437
+ };
438
+
439
+ // std::format / f-string support: route through the str slot. Format
440
+ // specs are not currently supported on Any (the design defers richer
441
+ // dispatch); only `{}` is accepted.
442
+ template <>
443
+ struct std::formatter<::tpy::Any> {
444
+ constexpr auto parse(std::format_parse_context& ctx) {
445
+ auto it = ctx.begin();
446
+ if (it != ctx.end() && *it != '}') {
447
+ throw std::format_error(
448
+ "format specs on Any are not supported -- narrow first");
449
+ }
450
+ return it;
451
+ }
452
+
453
+ auto format(const ::tpy::Any& a, std::format_context& ctx) const {
454
+ if (a.empty()) {
455
+ ::tpy::tpy_panic("use of empty/moved-from Any");
456
+ }
457
+ std::string buf;
458
+ a.ops->str(buf, a.value);
459
+ return std::format_to(ctx.out(), "{}", buf);
460
+ }
461
+ };
@@ -0,0 +1,117 @@
1
+ /**
2
+ * TurboPython Runtime - Output sink dispatch
3
+ *
4
+ * Resolves a print()-style file= target to a std::ostream& usable with
5
+ * the existing operator<< chain. Three concrete overloads bypass any
6
+ * adapter (cout/cerr via std::ostream&, sys.stdout/stderr via StdStream,
7
+ * open()-files via TextFile); a fallback template wraps any user type
8
+ * satisfying the Writable concept in a streambuf adapter.
9
+ */
10
+
11
+ #pragma once
12
+
13
+ #include <cstdint>
14
+ #include <ostream>
15
+ #include <streambuf>
16
+ #include <string_view>
17
+ #include <type_traits>
18
+
19
+ #include "file.hpp"
20
+ #include "system.hpp"
21
+
22
+ namespace tpy {
23
+
24
+ template <typename W>
25
+ concept WritableSink = requires(W& w, std::string_view sv) {
26
+ { w.write(sv) } -> std::convertible_to<int32_t>;
27
+ { w.flush() } -> std::same_as<void>;
28
+ };
29
+
30
+ namespace detail {
31
+
32
+ // Buffered streambuf forwarding to a Writable's write() / flush().
33
+ // sync() drains the buffer AND calls W::flush() (semantics for `<< std::flush`);
34
+ // the destructor only drains, matching std::ostream's no-flush-on-destroy.
35
+ template <typename W>
36
+ class WritableStreambuf final : public std::streambuf {
37
+ W* w_;
38
+ static constexpr std::size_t kBufSize = 256;
39
+ char buf_[kBufSize];
40
+
41
+ void drain() {
42
+ const auto n = pptr() - pbase();
43
+ if (n > 0) {
44
+ w_->write(std::string_view(pbase(), static_cast<std::size_t>(n)));
45
+ setp(buf_, buf_ + kBufSize);
46
+ }
47
+ }
48
+
49
+ protected:
50
+ std::streamsize xsputn(const char* s, std::streamsize n) override {
51
+ if (n <= 0) return 0;
52
+ if (pptr() != pbase()) drain();
53
+ // Mirrors Python's io.IOBase.write: short-write / error returns from
54
+ // the user's write() are not propagated as a streambuf failure.
55
+ w_->write(std::string_view(s, static_cast<std::size_t>(n)));
56
+ return n;
57
+ }
58
+
59
+ int_type overflow(int_type ch) override {
60
+ drain();
61
+ if (!traits_type::eq_int_type(ch, traits_type::eof())) {
62
+ *pptr() = traits_type::to_char_type(ch);
63
+ pbump(1);
64
+ }
65
+ return traits_type::not_eof(ch);
66
+ }
67
+
68
+ int sync() override {
69
+ drain();
70
+ w_->flush();
71
+ return 0;
72
+ }
73
+
74
+ public:
75
+ explicit WritableStreambuf(W& w) : w_(&w) {
76
+ setp(buf_, buf_ + kBufSize);
77
+ }
78
+
79
+ ~WritableStreambuf() override { drain(); }
80
+
81
+ WritableStreambuf(const WritableStreambuf&) = delete;
82
+ WritableStreambuf(WritableStreambuf&&) = delete;
83
+ WritableStreambuf& operator=(const WritableStreambuf&) = delete;
84
+ WritableStreambuf& operator=(WritableStreambuf&&) = delete;
85
+ };
86
+
87
+ template <typename W>
88
+ class WritableOstream final : public std::ostream {
89
+ WritableStreambuf<W> sb_;
90
+
91
+ public:
92
+ explicit WritableOstream(W& w) : std::ostream(nullptr), sb_(w) {
93
+ rdbuf(&sb_);
94
+ }
95
+
96
+ WritableOstream(const WritableOstream&) = delete;
97
+ WritableOstream(WritableOstream&&) = delete;
98
+ WritableOstream& operator=(const WritableOstream&) = delete;
99
+ WritableOstream& operator=(WritableOstream&&) = delete;
100
+ };
101
+
102
+ } // namespace detail
103
+
104
+ inline std::ostream& as_ostream(std::ostream& os) { return os; }
105
+ inline std::ostream& as_ostream(StdStream& s) { return s.sink(); }
106
+ inline std::ostream& as_ostream(TextFile& f) { return f.sink(); }
107
+
108
+ template <typename W>
109
+ requires WritableSink<W>
110
+ && (!std::is_base_of_v<std::ostream, W>)
111
+ && (!std::is_same_v<std::remove_cv_t<W>, StdStream>)
112
+ && (!std::is_same_v<std::remove_cv_t<W>, TextFile>)
113
+ detail::WritableOstream<W> as_ostream(W& w) {
114
+ return detail::WritableOstream<W>(w);
115
+ }
116
+
117
+ } // namespace tpy
@@ -0,0 +1,76 @@
1
+ /**
2
+ * TurboPython Runtime - Async primitives
3
+ *
4
+ * The async surface lives in TPy; see `lib/tpy/tpy/coro/__init__.py`
5
+ * (Waker, Awaker) and `lib/tpy/asyncio/_executor.py` (Executor,
6
+ * _ExecutorScope, _current_executor). The C++ side carries two pieces:
7
+ * `CancelledError` (thrown into a coroutine at the resumed-await
8
+ * position when its task is cancelled) and `poll_with_cancel`, the
9
+ * resume-case helper template every async-def coro frame uses to
10
+ * propagate outer cancellation through to the in-flight sub-coro
11
+ * before polling.
12
+ */
13
+
14
+ #pragma once
15
+
16
+ #include "core.hpp"
17
+
18
+ namespace tpy {
19
+
20
+ /**
21
+ * CancelledError -- thrown into a coroutine at the resumed-await position
22
+ * when its task is cancelled. Inherits BaseException (not Exception) so
23
+ * `except Exception:` does not silently swallow it.
24
+ */
25
+ struct CancelledError : BaseException {
26
+ CancelledError() : BaseException("CancelledError") {}
27
+ using BaseException::BaseException;
28
+ TPY_THROWABLE_VIRTUALS(CancelledError)
29
+ };
30
+
31
+ /**
32
+ * Resume-case helper: poll an async-def frame's sub-coroutine while
33
+ * propagating outer cancellation through to it.
34
+ *
35
+ * Called from every `S_AFTER_AWAIT_N` block emitted by the async-def
36
+ * codegen. If the outer's `__cancel_pending` flag is set on entry,
37
+ * the helper delivers the cancel by clearing the flag, calling
38
+ * `sub->cancel()`, then polling -- so the sub observes the cancel at
39
+ * its own next suspension point and can run `finally`-with-await
40
+ * cleanup. Three completion paths:
41
+ *
42
+ * - Sub returns Pending and cancel was being delivered: re-set the
43
+ * outer's flag so the cancel persists until the next poll attempt
44
+ * actually delivers it.
45
+ * - Sub raises (CancelledError or another exception): unwinds with
46
+ * a clean cancel_pending state -- nested `finally`-with-await
47
+ * bodies in the outer don't get re-cancelled at every new
48
+ * suspension.
49
+ * - Sub returns Ready synchronously while we were delivering cancel:
50
+ * the sub raced past the cancel signal. Outer cancel still wins;
51
+ * throw `CancelledError`. (The sub's Ready value is discarded as
52
+ * the returned Poll's storage unwinds.)
53
+ *
54
+ * `Sub` is duck-typed: an `std::optional<T>` or `T*` whose pointee
55
+ * provides `cancel()` and `__poll__(Waker) -> Poll<T>`. Both shapes
56
+ * use `->`, so the same template body works for INLINE/ERASED and
57
+ * BORROWED await modes. Inline so the compiler can fold the
58
+ * not-cancelling fast path back to a plain `sub->__poll__(waker)`.
59
+ */
60
+ template <typename Sub, typename W>
61
+ inline auto poll_with_cancel(Sub&& sub, bool& cancel_pending, W&& waker) {
62
+ bool was_canceling = cancel_pending;
63
+ if (was_canceling) {
64
+ cancel_pending = false;
65
+ sub->cancel();
66
+ }
67
+ auto r = sub->__poll__(waker);
68
+ if (r.is_pending()) {
69
+ if (was_canceling) cancel_pending = true;
70
+ return r;
71
+ }
72
+ if (was_canceling) throw CancelledError();
73
+ return r;
74
+ }
75
+
76
+ } // namespace tpy