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,337 @@
1
+ /**
2
+ * TurboPython Runtime - Ordered Set
3
+ *
4
+ * Hash set that preserves insertion order (matching Python's set implementation).
5
+ * Combines std::unordered_set for O(1) lookup with an intrusive doubly-linked
6
+ * list for insertion-order iteration.
7
+ */
8
+
9
+ #pragma once
10
+
11
+ #include <cstdint>
12
+ #include <expected>
13
+ #include <functional>
14
+ #include <initializer_list>
15
+ #include <unordered_map>
16
+ #include <utility>
17
+
18
+ #include "core.hpp"
19
+
20
+ namespace tpy {
21
+
22
+ template<typename T>
23
+ class ordered_set {
24
+ struct Node {
25
+ T value;
26
+ Node* prev = nullptr;
27
+ Node* next = nullptr;
28
+
29
+ template<typename U>
30
+ explicit Node(U&& v) : value(std::forward<U>(v)) {}
31
+ };
32
+
33
+ public:
34
+ // -- Iterator (insertion order) ------------------------------------------
35
+
36
+ template<bool IsConst>
37
+ class iterator_impl {
38
+ friend class ordered_set;
39
+ using NodePtr = std::conditional_t<IsConst, const Node*, Node*>;
40
+ NodePtr node_;
41
+
42
+ explicit iterator_impl(NodePtr n) : node_(n) {}
43
+
44
+ public:
45
+ iterator_impl() : node_(nullptr) {}
46
+
47
+ using iterator_category = std::forward_iterator_tag;
48
+ using difference_type = std::ptrdiff_t;
49
+ using value_type = T;
50
+ using reference = const T&;
51
+
52
+ const T& operator*() const { return node_->value; }
53
+
54
+ iterator_impl& operator++() { node_ = node_->next; return *this; }
55
+ iterator_impl operator++(int) { auto tmp = *this; node_ = node_->next; return tmp; }
56
+
57
+ bool operator==(const iterator_impl& o) const { return node_ == o.node_; }
58
+ bool operator!=(const iterator_impl& o) const { return node_ != o.node_; }
59
+ };
60
+
61
+ using iterator = iterator_impl<false>;
62
+ using const_iterator = iterator_impl<true>;
63
+
64
+ // -- Construction --------------------------------------------------------
65
+
66
+ ordered_set() = default;
67
+
68
+ ordered_set(std::initializer_list<T> init) {
69
+ for (auto& v : init) {
70
+ insert(v);
71
+ }
72
+ }
73
+
74
+ ordered_set(const ordered_set& other) {
75
+ for (auto* n = other.head_; n != nullptr; n = n->next) {
76
+ insert(n->value);
77
+ }
78
+ }
79
+
80
+ ordered_set(ordered_set&& other) noexcept
81
+ : table_(std::move(other.table_))
82
+ , head_(other.head_)
83
+ , tail_(other.tail_)
84
+ {
85
+ other.head_ = nullptr;
86
+ other.tail_ = nullptr;
87
+ }
88
+
89
+ ordered_set& operator=(const ordered_set& other) {
90
+ if (this != &other) {
91
+ clear();
92
+ for (auto* n = other.head_; n != nullptr; n = n->next) {
93
+ insert(n->value);
94
+ }
95
+ }
96
+ return *this;
97
+ }
98
+
99
+ ordered_set& operator=(ordered_set&& other) noexcept {
100
+ if (this != &other) {
101
+ clear();
102
+ table_ = std::move(other.table_);
103
+ head_ = other.head_;
104
+ tail_ = other.tail_;
105
+ other.head_ = nullptr;
106
+ other.tail_ = nullptr;
107
+ }
108
+ return *this;
109
+ }
110
+
111
+ ~ordered_set() {
112
+ clear();
113
+ }
114
+
115
+ // -- Capacity ------------------------------------------------------------
116
+
117
+ int32_t size() const { return static_cast<int32_t>(table_.size()); }
118
+ bool empty() const { return table_.empty(); }
119
+
120
+ // -- Modifiers -----------------------------------------------------------
121
+
122
+ bool insert(const T& value) {
123
+ auto it = table_.find(value);
124
+ if (it != table_.end()) return false;
125
+ auto* node = new Node(value);
126
+ link_back(node);
127
+ table_.emplace(value, node);
128
+ return true;
129
+ }
130
+
131
+ bool insert(T&& value) {
132
+ auto it = table_.find(value);
133
+ if (it != table_.end()) return false;
134
+ auto* node = new Node(std::move(value));
135
+ link_back(node);
136
+ table_.emplace(node->value, node);
137
+ return true;
138
+ }
139
+
140
+ bool erase(const T& value) {
141
+ auto it = table_.find(value);
142
+ if (it == table_.end()) return false;
143
+ Node* node = it->second;
144
+ table_.erase(it);
145
+ unlink(node);
146
+ delete node;
147
+ return true;
148
+ }
149
+
150
+ void clear() {
151
+ auto* n = head_;
152
+ while (n != nullptr) {
153
+ auto* next = n->next;
154
+ delete n;
155
+ n = next;
156
+ }
157
+ table_.clear();
158
+ head_ = nullptr;
159
+ tail_ = nullptr;
160
+ }
161
+
162
+ // -- Lookup --------------------------------------------------------------
163
+
164
+ bool contains(const T& value) const {
165
+ return table_.find(value) != table_.end();
166
+ }
167
+
168
+ // -- Iteration (insertion order) -----------------------------------------
169
+
170
+ iterator begin() { return iterator(head_); }
171
+ iterator end() { return iterator(nullptr); }
172
+ const_iterator begin() const { return const_iterator(head_); }
173
+ const_iterator end() const { return const_iterator(nullptr); }
174
+
175
+ // -- Python __iter__() support -------------------------------------------
176
+
177
+ // Defined in set_ops.hpp (needs native_iterator template)
178
+ inline auto __iter__() const;
179
+
180
+ // -- Comparison (order-independent, matching Python) ---------------------
181
+
182
+ bool operator==(const ordered_set& other) const {
183
+ if (table_.size() != other.table_.size()) return false;
184
+ for (auto* n = head_; n != nullptr; n = n->next) {
185
+ if (!other.contains(n->value)) return false;
186
+ }
187
+ return true;
188
+ }
189
+
190
+ bool operator!=(const ordered_set& other) const {
191
+ return !(*this == other);
192
+ }
193
+
194
+ // Python set comparison: <= means subset, < means strict subset, etc.
195
+ bool operator<=(const ordered_set& other) const {
196
+ if (table_.size() > other.table_.size()) return false;
197
+ for (auto* n = head_; n != nullptr; n = n->next) {
198
+ if (!other.contains(n->value)) return false;
199
+ }
200
+ return true;
201
+ }
202
+
203
+ bool operator<(const ordered_set& other) const {
204
+ return table_.size() < other.table_.size() && *this <= other;
205
+ }
206
+
207
+ bool operator>=(const ordered_set& other) const {
208
+ return other <= *this;
209
+ }
210
+
211
+ bool operator>(const ordered_set& other) const {
212
+ return other < *this;
213
+ }
214
+
215
+ // -- Front access (for pop) ----------------------------------------------
216
+
217
+ const T& front() const { return head_->value; }
218
+
219
+ void pop_front() {
220
+ Node* node = head_;
221
+ table_.erase(node->value);
222
+ unlink(node);
223
+ delete node;
224
+ }
225
+
226
+ private:
227
+ void link_back(Node* node) {
228
+ node->prev = tail_;
229
+ node->next = nullptr;
230
+ if (tail_) {
231
+ tail_->next = node;
232
+ } else {
233
+ head_ = node;
234
+ }
235
+ tail_ = node;
236
+ }
237
+
238
+ void unlink(Node* node) {
239
+ if (node->prev) {
240
+ node->prev->next = node->next;
241
+ } else {
242
+ head_ = node->next;
243
+ }
244
+ if (node->next) {
245
+ node->next->prev = node->prev;
246
+ } else {
247
+ tail_ = node->prev;
248
+ }
249
+ }
250
+
251
+ template<typename> friend struct OwnIterSet;
252
+
253
+ std::unordered_map<T, Node*, std::hash<T>> table_;
254
+ Node* head_ = nullptr;
255
+ Node* tail_ = nullptr;
256
+ };
257
+
258
+ // Construct an ordered_set from move-only T types. Mirrors make_vector /
259
+ // make_ordered_map: the initializer_list ctor stores elements as const,
260
+ // forcing a copy of T -- this helper forwards each element into insert
261
+ // so move-only values work in set literals once sema permits them.
262
+ template<typename T, typename... Args>
263
+ ordered_set<T> make_ordered_set(Args&&... args) {
264
+ ordered_set<T> s;
265
+ (s.insert(std::forward<Args>(args)), ...);
266
+ return s;
267
+ }
268
+
269
+ // ---------------------------------------------------------------------------
270
+ // OwnIterSet -- drain iterator for ordered_set
271
+ //
272
+ // Owns a moved ordered_set and yields elements by move. O(1) construction
273
+ // (hash table move is pointer swap). Implements both C++ range (begin/end
274
+ // with move iterators) and the TurboPython Iterator protocol (__next__).
275
+ // ---------------------------------------------------------------------------
276
+
277
+ template<typename T>
278
+ struct OwnIterSet {
279
+ ordered_set<T> data;
280
+ typename ordered_set<T>::Node* pos;
281
+
282
+ explicit OwnIterSet(ordered_set<T>&& s)
283
+ : data(std::move(s)), pos(data.head_) {}
284
+
285
+ OwnIterSet(const OwnIterSet&) = delete;
286
+ OwnIterSet& operator=(const OwnIterSet&) = delete;
287
+ OwnIterSet(OwnIterSet&&) = default;
288
+ OwnIterSet& operator=(OwnIterSet&&) = default;
289
+
290
+ // Move iterator: walks linked-list nodes, yields T&& (moved values).
291
+ // Single-pass: each dereference moves the value out of the node.
292
+ struct move_iter {
293
+ using Node = typename ordered_set<T>::Node;
294
+ Node* node_;
295
+
296
+ using iterator_category = std::input_iterator_tag;
297
+ using value_type = T;
298
+ using difference_type = std::ptrdiff_t;
299
+ using reference = T&&;
300
+
301
+ move_iter() : node_(nullptr) {}
302
+ explicit move_iter(Node* n) : node_(n) {}
303
+
304
+ T&& operator*() { return std::move(node_->value); }
305
+ move_iter& operator++() { node_ = node_->next; return *this; }
306
+ move_iter operator++(int) { auto tmp = *this; ++*this; return tmp; }
307
+ bool operator==(const move_iter& o) const { return node_ == o.node_; }
308
+ bool operator!=(const move_iter& o) const { return node_ != o.node_; }
309
+ };
310
+
311
+ // NativeIterable: range-based iteration with move semantics.
312
+ // Do not mix range-based (begin/end) and __next__-based iteration on the
313
+ // same instance -- both advance shared state and the result is undefined.
314
+ move_iter begin() { return move_iter(pos); }
315
+ move_iter end() { return move_iter(nullptr); }
316
+
317
+ // TPy Iterator protocol
318
+ std::expected<T, StopIteration> __next__() {
319
+ if (pos == nullptr) return tpy::make_unexpected(StopIteration{});
320
+ T value = std::move(pos->value);
321
+ pos = pos->next;
322
+ return value;
323
+ }
324
+
325
+ OwnIterSet& __iter__() { return *this; }
326
+
327
+ friend std::ostream& operator<<(std::ostream& os, const OwnIterSet&) {
328
+ return os << "<own_iter_set>";
329
+ }
330
+ };
331
+
332
+ template<typename T>
333
+ OwnIterSet<T> own_iter_set(ordered_set<T>&& s) {
334
+ return OwnIterSet<T>{std::move(s)};
335
+ }
336
+
337
+ } // namespace tpy
@@ -0,0 +1,54 @@
1
+ /**
2
+ * TurboPython Runtime - OwnIter
3
+ *
4
+ * Drain iterator for heap-backed containers (std::vector). Owns a moved
5
+ * vector and yields elements by move. O(1) construction (vector move is
6
+ * pointer swap). Unconsumed elements are destructed when OwnIter is dropped.
7
+ *
8
+ * Implements both C++ range (begin/end with move iterators) and the
9
+ * TurboPython Iterator protocol (__next__/__iter__).
10
+ */
11
+
12
+ #pragma once
13
+
14
+ #include "core.hpp"
15
+
16
+ #include <expected>
17
+ #include <iterator>
18
+ #include <vector>
19
+
20
+ namespace tpy {
21
+
22
+ template<typename T>
23
+ struct OwnIter {
24
+ std::vector<T> data;
25
+ std::size_t pos = 0;
26
+
27
+ explicit OwnIter(std::vector<T>&& v) : data(std::move(v)) {}
28
+
29
+ // NativeIterable: range-based iteration with move semantics.
30
+ // Do not mix range-based (begin/end) and __next__-based iteration on the
31
+ // same instance -- both advance shared state and the result is undefined.
32
+ auto begin() { return std::make_move_iterator(data.begin() + static_cast<std::ptrdiff_t>(pos)); }
33
+ auto end() { return std::make_move_iterator(data.end()); }
34
+
35
+ // Iterator protocol
36
+ std::expected<T, StopIteration> __next__() {
37
+ if (pos >= data.size()) return tpy::make_unexpected(StopIteration{});
38
+ return std::move(data[pos++]);
39
+ }
40
+
41
+ OwnIter& __iter__() { return *this; }
42
+
43
+ friend std::ostream& operator<<(std::ostream& os, const OwnIter&) {
44
+ return os << "<own_iter>";
45
+ }
46
+ };
47
+
48
+ // Factory: create OwnIter from an rvalue vector.
49
+ template<typename T>
50
+ OwnIter<T> own_iter(std::vector<T>&& v) {
51
+ return OwnIter<T>{std::move(v)};
52
+ }
53
+
54
+ } // namespace tpy
@@ -0,0 +1,192 @@
1
+ // Pascal Graph SDL2 display layer.
2
+ //
3
+ // Optional companion to the pure-TPy Pascal Graph unit. Compiled in when
4
+ // `--dsl-opt pascal.sdl=on` (or `auto` finds libsdl2-dev). The frontend
5
+ // plugin injects calls to the entry points below around the Pascal source
6
+ // (initgraph -> open, delay/setvisualpage -> present, closegraph ->
7
+ // show_blocking + closegraph + close_window) so animated TP7 programs
8
+ // render live in a window rather than as one final snapshot.
9
+ //
10
+ // The Pascal Graph runtime owns the pixel buffer + does all drawing
11
+ // (Tier A/B/C primitives are pure TPy). This file is a thin display
12
+ // adapter -- window/renderer/texture creation, pixel upload, event
13
+ // pumping, teardown.
14
+
15
+ #pragma once
16
+
17
+ #include <SDL2/SDL.h>
18
+
19
+ #include <cstdint>
20
+ #include <vector>
21
+
22
+
23
+ namespace tpy::pascal {
24
+
25
+ // Module-level SDL handles. Held in a function-local static so we can
26
+ // keep the API as free functions matching the TPy `@native` shape. The
27
+ // program is single-threaded at the Pascal level, so a single global
28
+ // is fine; nested initgraph/closegraph cycles work because
29
+ // `sdl_close_window` resets everything.
30
+ struct SdlGfxState {
31
+ SDL_Window* win = nullptr;
32
+ SDL_Renderer* ren = nullptr;
33
+ SDL_Texture* tex = nullptr;
34
+ int width = 0;
35
+ int height = 0;
36
+ bool user_quit = false;
37
+ };
38
+
39
+ inline SdlGfxState& sdl_gfx_state() {
40
+ static SdlGfxState s;
41
+ return s;
42
+ }
43
+
44
+ // Pump any pending SDL events so the OS keeps treating the window as
45
+ // responsive. Sets `user_quit` if the user has tried to close the
46
+ // window or pressed any key. Non-blocking; safe to call from any
47
+ // hook.
48
+ inline void sdl_pump_events() {
49
+ SdlGfxState& s = sdl_gfx_state();
50
+ SDL_Event ev;
51
+ while (SDL_PollEvent(&ev) != 0) {
52
+ if (ev.type == SDL_QUIT) {
53
+ s.user_quit = true;
54
+ } else if (ev.type == SDL_KEYDOWN) {
55
+ s.user_quit = true;
56
+ } else if (ev.type == SDL_WINDOWEVENT
57
+ && ev.window.event == SDL_WINDOWEVENT_CLOSE) {
58
+ s.user_quit = true;
59
+ }
60
+ }
61
+ }
62
+
63
+ // Open the SDL window for a `width`x`height` canvas. Idempotent --
64
+ // calling twice with the same dimensions is a no-op; calling with
65
+ // different dimensions reopens. Silent no-op on any SDL failure --
66
+ // the Pascal program's PPM snapshot fallback still gets written at
67
+ // CloseGraph, so users without a working SDL2 setup don't end up
68
+ // empty-handed.
69
+ inline void sdl_open_window(std::int32_t width, std::int32_t height) {
70
+ SdlGfxState& s = sdl_gfx_state();
71
+ if (width <= 0 || height <= 0) {
72
+ return;
73
+ }
74
+ if (s.win != nullptr && s.width == width && s.height == height) {
75
+ return;
76
+ }
77
+ // Different dimensions on a re-init -> tear down and reopen.
78
+ if (s.win != nullptr) {
79
+ if (s.tex != nullptr) { SDL_DestroyTexture(s.tex); }
80
+ if (s.ren != nullptr) { SDL_DestroyRenderer(s.ren); }
81
+ SDL_DestroyWindow(s.win);
82
+ s.tex = nullptr; s.ren = nullptr; s.win = nullptr;
83
+ }
84
+ if (SDL_WasInit(SDL_INIT_VIDEO) == 0) {
85
+ if (SDL_Init(SDL_INIT_VIDEO) != 0) {
86
+ return;
87
+ }
88
+ }
89
+ // Scale up by 2x so a 320x200 BGI canvas renders at 640x400
90
+ // (closer to readable on a modern display). The texture stays at
91
+ // the canvas size; SDL's RenderCopy stretches it to the window.
92
+ const int win_w = width * 2;
93
+ const int win_h = height * 2;
94
+ s.win = SDL_CreateWindow(
95
+ "TurboPython Pascal Graph",
96
+ SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
97
+ win_w, win_h, SDL_WINDOW_SHOWN);
98
+ if (s.win == nullptr) {
99
+ return;
100
+ }
101
+ s.ren = SDL_CreateRenderer(s.win, -1, 0);
102
+ if (s.ren == nullptr) {
103
+ SDL_DestroyWindow(s.win); s.win = nullptr;
104
+ return;
105
+ }
106
+ s.tex = SDL_CreateTexture(
107
+ s.ren, SDL_PIXELFORMAT_RGB888,
108
+ SDL_TEXTUREACCESS_STREAMING, width, height);
109
+ if (s.tex == nullptr) {
110
+ SDL_DestroyRenderer(s.ren); s.ren = nullptr;
111
+ SDL_DestroyWindow(s.win); s.win = nullptr;
112
+ return;
113
+ }
114
+ s.width = width;
115
+ s.height = height;
116
+ s.user_quit = false;
117
+ sdl_pump_events();
118
+ }
119
+
120
+ // Upload the current pixel buffer and present it. Pumps SDL events so
121
+ // the OS keeps the window responsive. Non-blocking. Auto-opens the
122
+ // window if it isn't open yet (lets a program call `sdl_present`
123
+ // without an explicit `sdl_open_window` -- the frontend injects the
124
+ // open call after initgraph but a malformed sequence shouldn't
125
+ // silently drop frames).
126
+ inline void sdl_present(std::int32_t width, std::int32_t height,
127
+ const std::vector<std::int32_t>& pixels) {
128
+ SdlGfxState& s = sdl_gfx_state();
129
+ if (width <= 0 || height <= 0) {
130
+ return;
131
+ }
132
+ if (static_cast<std::size_t>(width) * static_cast<std::size_t>(height)
133
+ != pixels.size()) {
134
+ return;
135
+ }
136
+ if (s.win == nullptr || s.width != width || s.height != height) {
137
+ sdl_open_window(width, height);
138
+ if (s.win == nullptr) {
139
+ return;
140
+ }
141
+ }
142
+ SDL_UpdateTexture(s.tex, nullptr, pixels.data(),
143
+ static_cast<int>(width * sizeof(std::int32_t)));
144
+ SDL_RenderClear(s.ren);
145
+ SDL_RenderCopy(s.ren, s.tex, nullptr, nullptr);
146
+ SDL_RenderPresent(s.ren);
147
+ sdl_pump_events();
148
+ }
149
+
150
+ // Present the final canvas and block until the user closes the
151
+ // window or presses any key. If the user already quit during an
152
+ // earlier present (`user_quit` set), returns immediately so the
153
+ // program can finish teardown without re-blocking.
154
+ inline void sdl_show_blocking(std::int32_t width, std::int32_t height,
155
+ const std::vector<std::int32_t>& pixels) {
156
+ sdl_present(width, height, pixels);
157
+ SdlGfxState& s = sdl_gfx_state();
158
+ if (s.win == nullptr) {
159
+ return;
160
+ }
161
+ if (s.user_quit) {
162
+ return;
163
+ }
164
+ SDL_Event ev;
165
+ while (SDL_WaitEvent(&ev) != 0) {
166
+ if (ev.type == SDL_QUIT
167
+ || ev.type == SDL_KEYDOWN
168
+ || (ev.type == SDL_WINDOWEVENT
169
+ && ev.window.event == SDL_WINDOWEVENT_CLOSE)) {
170
+ s.user_quit = true;
171
+ return;
172
+ }
173
+ }
174
+ }
175
+
176
+ // Destroy the window / renderer / texture and shut down SDL video.
177
+ // Idempotent -- safe to call from cleanup paths even when the window
178
+ // failed to open.
179
+ inline void sdl_close_window() {
180
+ SdlGfxState& s = sdl_gfx_state();
181
+ if (s.tex != nullptr) { SDL_DestroyTexture(s.tex); s.tex = nullptr; }
182
+ if (s.ren != nullptr) { SDL_DestroyRenderer(s.ren); s.ren = nullptr; }
183
+ if (s.win != nullptr) { SDL_DestroyWindow(s.win); s.win = nullptr; }
184
+ s.width = 0;
185
+ s.height = 0;
186
+ s.user_quit = false;
187
+ if (SDL_WasInit(SDL_INIT_VIDEO) != 0) {
188
+ SDL_Quit();
189
+ }
190
+ }
191
+
192
+ } // namespace tpy::pascal