superacli 1.1.6 → 1.1.8

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 (1268) hide show
  1. package/CONTRIBUTING.md +270 -0
  2. package/README.md +141 -54
  3. package/__tests__/adapter-schema.test.js +251 -86
  4. package/__tests__/azd-plugin.test.js +109 -0
  5. package/__tests__/config.test.js +4 -3
  6. package/__tests__/discover.test.js +59 -0
  7. package/__tests__/goose-plugin.test.js +149 -0
  8. package/__tests__/help-json.test.js +2 -0
  9. package/__tests__/openhands-plugin.test.js +106 -0
  10. package/__tests__/plugin-cocoindex-code-uninstall.test.js +19 -0
  11. package/__tests__/plugin-cocoindex-code.test.js +37 -0
  12. package/__tests__/plugin-install-guidance.test.js +81 -0
  13. package/__tests__/plugins-registry.test.js +44 -0
  14. package/__tests__/plugins-store.test.js +40 -5
  15. package/__tests__/process-adapter.test.js +50 -1
  16. package/__tests__/resend-plugin.test.js +109 -82
  17. package/__tests__/server-app.test.js +1 -0
  18. package/__tests__/server-routes-commands.test.js +20 -2
  19. package/__tests__/server-routes-plugins.test.js +130 -0
  20. package/__tests__/skills.test.js +26 -0
  21. package/__tests__/squirrelscan-plugin.test.js +129 -0
  22. package/__tests__/uipath-plugin.test.js +104 -0
  23. package/__tests__/uipathcli-plugin.test.js +95 -0
  24. package/cli/adapters/mcp.js +2 -0
  25. package/cli/adapters/process.js +50 -7
  26. package/cli/config.js +240 -3
  27. package/cli/discover.js +157 -0
  28. package/cli/help-json.js +16 -1
  29. package/cli/plugin-install-guidance.js +92 -37
  30. package/cli/plugins-manager.js +4 -3
  31. package/cli/plugins-registry.js +74 -8
  32. package/cli/plugins-store.js +78 -17
  33. package/cli/skills-mcp.js +1 -1
  34. package/cli/skills.js +39 -2
  35. package/cli/supercli.js +255 -63
  36. package/docs/feature-gaps.md +8 -8
  37. package/docs/features/azd-uipath-plugins.md +43 -0
  38. package/docs/features/server-plugins.md +62 -0
  39. package/docs/features/skills.md +9 -5
  40. package/docs/index.html +183 -123
  41. package/docs/{supported-harnesses.md → plugins-available.md} +4 -3
  42. package/docs/{plugin-harness-guide.md → plugins-how-to.md} +1 -1
  43. package/docs/plugins.md +26 -20
  44. package/docs/server-plugins-usage-guide.md +182 -0
  45. package/docs/skills-catalog.md +12 -10
  46. package/index.html +384 -0
  47. package/package.json +2 -2
  48. package/plugins/agent-browser/README.md +69 -0
  49. package/plugins/agent-browser/plugin.json +111 -0
  50. package/plugins/agent-browser/skills/quickstart/SKILL.md +66 -0
  51. package/plugins/aider/README.md +53 -0
  52. package/plugins/aider/plugin.json +105 -0
  53. package/plugins/aider/scripts/aider-wrapper.js +243 -0
  54. package/plugins/aider/scripts/setup-aider.js +37 -0
  55. package/plugins/aider/skills/dry-run-review.md +24 -0
  56. package/plugins/aider/skills/model-and-provider.md +24 -0
  57. package/plugins/aider/skills/one-shot-edits.md +30 -0
  58. package/plugins/aider/skills/quickstart/SKILL.md +51 -0
  59. package/plugins/azd/README.md +28 -0
  60. package/plugins/azd/plugin.json +87 -0
  61. package/plugins/azd/skills/quickstart/SKILL.md +41 -0
  62. package/plugins/blogwatcher/README.md +3 -3
  63. package/plugins/boxlite/Dockerfile +9 -0
  64. package/plugins/boxlite/README.md +62 -0
  65. package/plugins/boxlite/plugin.json +201 -0
  66. package/plugins/boxlite/scripts/run-boxlite.js +106 -0
  67. package/plugins/boxlite/skills/quickstart/SKILL.md +40 -0
  68. package/plugins/cass/plugin.json +150 -0
  69. package/plugins/cass/scripts/setup-cass.js +47 -0
  70. package/plugins/cass/skills/quickstart/SKILL.md +46 -0
  71. package/plugins/clever/README.md +46 -0
  72. package/plugins/clever/plugin.json +119 -0
  73. package/plugins/clever/scripts/setup-clever.js +28 -0
  74. package/plugins/clever/skills/auth-and-profile.md +29 -0
  75. package/plugins/clever/skills/passthrough-safety.md +21 -0
  76. package/plugins/clever/skills/quickstart/SKILL.md +45 -0
  77. package/plugins/clever/skills/resource-inventory.md +24 -0
  78. package/plugins/clix/README.md +4 -4
  79. package/plugins/cocoindex-code/README.md +64 -0
  80. package/plugins/cocoindex-code/plugin.json +81 -0
  81. package/plugins/cocoindex-code/scripts/__pycache__/query.cpython-310.pyc +0 -0
  82. package/plugins/cocoindex-code/scripts/__pycache__/query.cpython-311.pyc +0 -0
  83. package/plugins/cocoindex-code/scripts/post-install.js +61 -0
  84. package/plugins/cocoindex-code/scripts/post-uninstall.js +25 -0
  85. package/plugins/cocoindex-code/scripts/query.py +88 -0
  86. package/plugins/cocoindex-code/scripts/run-query.js +50 -0
  87. package/plugins/cocoindex-code/skills/quickstart/SKILL.md +73 -0
  88. package/plugins/copilot/README.md +24 -0
  89. package/plugins/copilot/plugin.json +80 -0
  90. package/plugins/copilot/skills/quickstart/SKILL.md +44 -0
  91. package/plugins/gemini/README.md +24 -0
  92. package/plugins/gemini/plugin.json +98 -0
  93. package/plugins/gemini/skills/quickstart/SKILL.md +44 -0
  94. package/plugins/gifcap/plugin.json +119 -0
  95. package/plugins/gifcap/scripts/setup-gifcap.js +44 -0
  96. package/plugins/gifcap/skills/quickstart/SKILL.md +34 -0
  97. package/plugins/gifcap/test-record-quiet.gif +0 -0
  98. package/plugins/gifcap/test-record.gif +0 -0
  99. package/plugins/goose/README.md +36 -0
  100. package/plugins/goose/plugin.json +183 -0
  101. package/plugins/goose/skills/quickstart/SKILL.md +44 -0
  102. package/plugins/json-server/README.md +58 -0
  103. package/plugins/json-server/plugin.json +113 -0
  104. package/plugins/json-server/skills/quickstart/SKILL.md +57 -0
  105. package/plugins/lightpanda/README.md +145 -0
  106. package/plugins/lightpanda/package-lock.json +1375 -0
  107. package/plugins/lightpanda/package.json +12 -0
  108. package/plugins/lightpanda/plugin.json +116 -0
  109. package/plugins/lightpanda/scripts/lightpanda-contacts.js +494 -0
  110. package/plugins/lightpanda/scripts/lightpanda-generic-extract.js +403 -0
  111. package/plugins/lightpanda/scripts/lightpanda-wrapper.js +480 -0
  112. package/plugins/lightpanda/scripts/setup-lightpanda.js +39 -0
  113. package/plugins/lightpanda/skills/contact-discovery.md +51 -0
  114. package/plugins/lightpanda/skills/generic-extraction.md +66 -0
  115. package/plugins/lightpanda/skills/quickstart/SKILL.md +103 -0
  116. package/plugins/lightpanda/skills/resilient-navigation.md +42 -0
  117. package/plugins/monty/README.md +2 -2
  118. package/plugins/nullclaw/README.md +3 -3
  119. package/plugins/offline-ai/README.md +23 -0
  120. package/plugins/offline-ai/plugin.json +82 -0
  121. package/plugins/offline-ai/skills/quickstart/SKILL.md +43 -0
  122. package/plugins/openhands/README.md +25 -0
  123. package/plugins/openhands/plugin.json +116 -0
  124. package/plugins/openhands/skills/quickstart/SKILL.md +26 -0
  125. package/plugins/plandex/README.md +25 -0
  126. package/plugins/plandex/plugin.json +130 -0
  127. package/plugins/plandex/skills/quickstart/SKILL.md +50 -0
  128. package/plugins/plugins.json +199 -0
  129. package/plugins/squirrelscan/Dockerfile +5 -0
  130. package/plugins/squirrelscan/README.md +47 -0
  131. package/plugins/squirrelscan/plugin.json +493 -0
  132. package/plugins/squirrelscan/scripts/post-install.js +33 -0
  133. package/plugins/squirrelscan/scripts/post-uninstall.js +25 -0
  134. package/plugins/squirrelscan/scripts/run-squirrel.js +73 -0
  135. package/plugins/squirrelscan/skills/audit-workflow/SKILL.md +33 -0
  136. package/plugins/squirrelscan/skills/publish-report/SKILL.md +33 -0
  137. package/plugins/squirrelscan/skills/quickstart/SKILL.md +41 -0
  138. package/plugins/uipath/README.md +27 -0
  139. package/plugins/uipath/plugin.json +86 -0
  140. package/plugins/uipath/skills/quickstart/SKILL.md +47 -0
  141. package/plugins/uipathcli/README.md +28 -0
  142. package/plugins/uipathcli/plugin.json +120 -0
  143. package/plugins/uipathcli/scripts/run-uipath-cli.js +49 -0
  144. package/plugins/uipathcli/skills/quickstart/SKILL.md +22 -0
  145. package/plugins/xurl/README.md +4 -4
  146. package/server/app.js +5 -2
  147. package/server/public/app.js +3 -0
  148. package/server/routes/commands.js +95 -12
  149. package/server/routes/plugins.js +262 -0
  150. package/server/services/pluginsService.js +303 -0
  151. package/server/views/command-edit.ejs +196 -14
  152. package/server/views/partials/head.ejs +1 -0
  153. package/server/views/plugins.ejs +264 -0
  154. package/tests/test-plugins-registry.js +30 -0
  155. package/.beads/.br_history/issues.20260308_200823_636718328.jsonl +0 -20
  156. package/.beads/.br_history/issues.20260308_200823_636718328.jsonl.meta.json +0 -1
  157. package/.beads/.br_history/issues.20260308_200827_033159453.jsonl +0 -21
  158. package/.beads/.br_history/issues.20260308_200827_033159453.jsonl.meta.json +0 -1
  159. package/.beads/.br_history/issues.20260308_200829_595900053.jsonl +0 -22
  160. package/.beads/.br_history/issues.20260308_200829_595900053.jsonl.meta.json +0 -1
  161. package/.beads/.br_history/issues.20260308_200834_079930100.jsonl +0 -23
  162. package/.beads/.br_history/issues.20260308_200834_079930100.jsonl.meta.json +0 -1
  163. package/.beads/.br_history/issues.20260308_200858_370924996.jsonl +0 -24
  164. package/.beads/.br_history/issues.20260308_200858_370924996.jsonl.meta.json +0 -1
  165. package/.beads/.br_history/issues.20260308_201031_019730855.jsonl +0 -24
  166. package/.beads/.br_history/issues.20260308_201031_019730855.jsonl.meta.json +0 -1
  167. package/.beads/.br_history/issues.20260308_201031_578974884.jsonl +0 -24
  168. package/.beads/.br_history/issues.20260308_201031_578974884.jsonl.meta.json +0 -1
  169. package/.beads/.br_history/issues.20260308_201054_780345548.jsonl +0 -24
  170. package/.beads/.br_history/issues.20260308_201054_780345548.jsonl.meta.json +0 -1
  171. package/.beads/.br_history/issues.20260308_201054_896980019.jsonl +0 -24
  172. package/.beads/.br_history/issues.20260308_201054_896980019.jsonl.meta.json +0 -1
  173. package/.beads/.br_history/issues.20260308_201128_599819688.jsonl +0 -24
  174. package/.beads/.br_history/issues.20260308_201128_599819688.jsonl.meta.json +0 -1
  175. package/.beads/.br_history/issues.20260308_201128_710221699.jsonl +0 -24
  176. package/.beads/.br_history/issues.20260308_201128_710221699.jsonl.meta.json +0 -1
  177. package/.beads/.br_history/issues.20260308_201204_745649213.jsonl +0 -24
  178. package/.beads/.br_history/issues.20260308_201204_745649213.jsonl.meta.json +0 -1
  179. package/.beads/.br_history/issues.20260308_201338_908436144.jsonl +0 -24
  180. package/.beads/.br_history/issues.20260308_201338_908436144.jsonl.meta.json +0 -1
  181. package/.beads/.br_history/issues.20260308_201344_734860714.jsonl +0 -25
  182. package/.beads/.br_history/issues.20260308_201344_734860714.jsonl.meta.json +0 -1
  183. package/.beads/.br_history/issues.20260308_201630_819282295.jsonl +0 -25
  184. package/.beads/.br_history/issues.20260308_201630_819282295.jsonl.meta.json +0 -1
  185. package/.beads/.br_history/issues.20260308_203538_054279699.jsonl +0 -25
  186. package/.beads/.br_history/issues.20260308_203538_054279699.jsonl.meta.json +0 -1
  187. package/.beads/.br_history/issues.20260308_203547_597113070.jsonl +0 -26
  188. package/.beads/.br_history/issues.20260308_203547_597113070.jsonl.meta.json +0 -1
  189. package/.beads/.br_history/issues.20260308_203547_775139216.jsonl +0 -27
  190. package/.beads/.br_history/issues.20260308_203547_775139216.jsonl.meta.json +0 -1
  191. package/.beads/.br_history/issues.20260308_203547_950724773.jsonl +0 -28
  192. package/.beads/.br_history/issues.20260308_203547_950724773.jsonl.meta.json +0 -1
  193. package/.beads/.br_history/issues.20260308_203548_107684523.jsonl +0 -29
  194. package/.beads/.br_history/issues.20260308_203548_107684523.jsonl.meta.json +0 -1
  195. package/.beads/.br_history/issues.20260308_203548_310389993.jsonl +0 -30
  196. package/.beads/.br_history/issues.20260308_203548_310389993.jsonl.meta.json +0 -1
  197. package/.beads/.br_history/issues.20260308_203825_953337320.jsonl +0 -31
  198. package/.beads/.br_history/issues.20260308_203825_953337320.jsonl.meta.json +0 -1
  199. package/.beads/.br_history/issues.20260308_204056_071377736.jsonl +0 -32
  200. package/.beads/.br_history/issues.20260308_204056_071377736.jsonl.meta.json +0 -1
  201. package/.beads/.br_history/issues.20260308_205141_517616844.jsonl +0 -32
  202. package/.beads/.br_history/issues.20260308_205141_517616844.jsonl.meta.json +0 -1
  203. package/.beads/.br_history/issues.20260308_205141_648994024.jsonl +0 -32
  204. package/.beads/.br_history/issues.20260308_205141_648994024.jsonl.meta.json +0 -1
  205. package/.beads/.br_history/issues.20260308_205141_867598036.jsonl +0 -32
  206. package/.beads/.br_history/issues.20260308_205141_867598036.jsonl.meta.json +0 -1
  207. package/.beads/.br_history/issues.20260308_205142_094157355.jsonl +0 -32
  208. package/.beads/.br_history/issues.20260308_205142_094157355.jsonl.meta.json +0 -1
  209. package/.beads/.br_history/issues.20260308_205142_327315677.jsonl +0 -32
  210. package/.beads/.br_history/issues.20260308_205142_327315677.jsonl.meta.json +0 -1
  211. package/.beads/.br_history/issues.20260308_205142_545563822.jsonl +0 -32
  212. package/.beads/.br_history/issues.20260308_205142_545563822.jsonl.meta.json +0 -1
  213. package/.beads/.br_history/issues.20260308_205213_061989333.jsonl +0 -32
  214. package/.beads/.br_history/issues.20260308_205213_061989333.jsonl.meta.json +0 -1
  215. package/.beads/.br_history/issues.20260308_205213_181103364.jsonl +0 -32
  216. package/.beads/.br_history/issues.20260308_205213_181103364.jsonl.meta.json +0 -1
  217. package/.beads/.br_history/issues.20260308_205213_408872234.jsonl +0 -32
  218. package/.beads/.br_history/issues.20260308_205213_408872234.jsonl.meta.json +0 -1
  219. package/.beads/.br_history/issues.20260308_205213_616681652.jsonl +0 -32
  220. package/.beads/.br_history/issues.20260308_205213_616681652.jsonl.meta.json +0 -1
  221. package/.beads/.br_history/issues.20260308_205213_821507069.jsonl +0 -32
  222. package/.beads/.br_history/issues.20260308_205213_821507069.jsonl.meta.json +0 -1
  223. package/.beads/.br_history/issues.20260308_205214_026661112.jsonl +0 -32
  224. package/.beads/.br_history/issues.20260308_205214_026661112.jsonl.meta.json +0 -1
  225. package/.beads/.br_history/issues.20260308_205454_955250554.jsonl +0 -32
  226. package/.beads/.br_history/issues.20260308_205454_955250554.jsonl.meta.json +0 -1
  227. package/.beads/.br_history/issues.20260308_205556_337800392.jsonl +0 -33
  228. package/.beads/.br_history/issues.20260308_205556_337800392.jsonl.meta.json +0 -1
  229. package/.beads/.br_history/issues.20260308_205824_274686694.jsonl +0 -33
  230. package/.beads/.br_history/issues.20260308_205824_274686694.jsonl.meta.json +0 -1
  231. package/.beads/.br_history/issues.20260308_210240_583768328.jsonl +0 -34
  232. package/.beads/.br_history/issues.20260308_210240_583768328.jsonl.meta.json +0 -1
  233. package/.beads/.br_history/issues.20260308_212223_641541494.jsonl +0 -34
  234. package/.beads/.br_history/issues.20260308_212223_641541494.jsonl.meta.json +0 -1
  235. package/.beads/.br_history/issues.20260308_212227_735550996.jsonl +0 -35
  236. package/.beads/.br_history/issues.20260308_212227_735550996.jsonl.meta.json +0 -1
  237. package/.beads/.br_history/issues.20260308_212232_547298548.jsonl +0 -36
  238. package/.beads/.br_history/issues.20260308_212232_547298548.jsonl.meta.json +0 -1
  239. package/.beads/.br_history/issues.20260308_212528_843628125.jsonl +0 -37
  240. package/.beads/.br_history/issues.20260308_212528_843628125.jsonl.meta.json +0 -1
  241. package/.beads/.br_history/issues.20260308_212529_094530502.jsonl +0 -38
  242. package/.beads/.br_history/issues.20260308_212529_094530502.jsonl.meta.json +0 -1
  243. package/.beads/.br_history/issues.20260308_212529_331000853.jsonl +0 -39
  244. package/.beads/.br_history/issues.20260308_212529_331000853.jsonl.meta.json +0 -1
  245. package/.beads/.br_history/issues.20260308_212529_587925652.jsonl +0 -40
  246. package/.beads/.br_history/issues.20260308_212529_587925652.jsonl.meta.json +0 -1
  247. package/.beads/.br_history/issues.20260308_212804_927764103.jsonl +0 -41
  248. package/.beads/.br_history/issues.20260308_212804_927764103.jsonl.meta.json +0 -1
  249. package/.beads/.br_history/issues.20260308_212805_153673453.jsonl +0 -42
  250. package/.beads/.br_history/issues.20260308_212805_153673453.jsonl.meta.json +0 -1
  251. package/.beads/.br_history/issues.20260308_212805_415982363.jsonl +0 -43
  252. package/.beads/.br_history/issues.20260308_212805_415982363.jsonl.meta.json +0 -1
  253. package/.beads/.br_history/issues.20260308_212805_657497741.jsonl +0 -44
  254. package/.beads/.br_history/issues.20260308_212805_657497741.jsonl.meta.json +0 -1
  255. package/.beads/.br_history/issues.20260308_212805_952838724.jsonl +0 -45
  256. package/.beads/.br_history/issues.20260308_212805_952838724.jsonl.meta.json +0 -1
  257. package/.beads/.br_history/issues.20260308_212806_325433779.jsonl +0 -46
  258. package/.beads/.br_history/issues.20260308_212806_325433779.jsonl.meta.json +0 -1
  259. package/.beads/.br_history/issues.20260308_212806_584685598.jsonl +0 -47
  260. package/.beads/.br_history/issues.20260308_212806_584685598.jsonl.meta.json +0 -1
  261. package/.beads/.br_history/issues.20260308_212806_827817208.jsonl +0 -48
  262. package/.beads/.br_history/issues.20260308_212806_827817208.jsonl.meta.json +0 -1
  263. package/.beads/.br_history/issues.20260308_212807_111320451.jsonl +0 -49
  264. package/.beads/.br_history/issues.20260308_212807_111320451.jsonl.meta.json +0 -1
  265. package/.beads/.br_history/issues.20260308_212807_409545536.jsonl +0 -50
  266. package/.beads/.br_history/issues.20260308_212807_409545536.jsonl.meta.json +0 -1
  267. package/.beads/.br_history/issues.20260308_212807_625063294.jsonl +0 -51
  268. package/.beads/.br_history/issues.20260308_212807_625063294.jsonl.meta.json +0 -1
  269. package/.beads/.br_history/issues.20260308_212807_843906551.jsonl +0 -52
  270. package/.beads/.br_history/issues.20260308_212807_843906551.jsonl.meta.json +0 -1
  271. package/.beads/.br_history/issues.20260308_212808_100304073.jsonl +0 -53
  272. package/.beads/.br_history/issues.20260308_212808_100304073.jsonl.meta.json +0 -1
  273. package/.beads/.br_history/issues.20260308_212808_324723976.jsonl +0 -54
  274. package/.beads/.br_history/issues.20260308_212808_324723976.jsonl.meta.json +0 -1
  275. package/.beads/.br_history/issues.20260308_212808_557513104.jsonl +0 -55
  276. package/.beads/.br_history/issues.20260308_212808_557513104.jsonl.meta.json +0 -1
  277. package/.beads/.br_history/issues.20260308_212808_788048322.jsonl +0 -56
  278. package/.beads/.br_history/issues.20260308_212808_788048322.jsonl.meta.json +0 -1
  279. package/.beads/.br_history/issues.20260308_213702_613249728.jsonl +0 -57
  280. package/.beads/.br_history/issues.20260308_213702_613249728.jsonl.meta.json +0 -1
  281. package/.beads/.br_history/issues.20260308_213715_115792063.jsonl +0 -57
  282. package/.beads/.br_history/issues.20260308_213715_115792063.jsonl.meta.json +0 -1
  283. package/.beads/.br_history/issues.20260308_213715_462220666.jsonl +0 -57
  284. package/.beads/.br_history/issues.20260308_213715_462220666.jsonl.meta.json +0 -1
  285. package/.beads/.br_history/issues.20260308_213727_191258923.jsonl +0 -57
  286. package/.beads/.br_history/issues.20260308_213727_191258923.jsonl.meta.json +0 -1
  287. package/.beads/.br_history/issues.20260308_213727_684383652.jsonl +0 -57
  288. package/.beads/.br_history/issues.20260308_213727_684383652.jsonl.meta.json +0 -1
  289. package/.beads/.br_history/issues.20260308_213735_751882991.jsonl +0 -57
  290. package/.beads/.br_history/issues.20260308_213735_751882991.jsonl.meta.json +0 -1
  291. package/.beads/.br_history/issues.20260308_222052_279844960.jsonl +0 -57
  292. package/.beads/.br_history/issues.20260308_222052_279844960.jsonl.meta.json +0 -1
  293. package/.beads/.br_history/issues.20260308_222056_873282114.jsonl +0 -57
  294. package/.beads/.br_history/issues.20260308_222056_873282114.jsonl.meta.json +0 -1
  295. package/.beads/.br_history/issues.20260308_222103_402410761.jsonl +0 -57
  296. package/.beads/.br_history/issues.20260308_222103_402410761.jsonl.meta.json +0 -1
  297. package/.beads/.br_history/issues.20260308_235202_180577215.jsonl +0 -57
  298. package/.beads/.br_history/issues.20260308_235202_180577215.jsonl.meta.json +0 -1
  299. package/.beads/.br_history/issues.20260308_235202_387414163.jsonl +0 -57
  300. package/.beads/.br_history/issues.20260308_235202_387414163.jsonl.meta.json +0 -1
  301. package/.beads/.br_history/issues.20260308_235202_564422794.jsonl +0 -57
  302. package/.beads/.br_history/issues.20260308_235202_564422794.jsonl.meta.json +0 -1
  303. package/.beads/.br_history/issues.20260308_235202_742600597.jsonl +0 -57
  304. package/.beads/.br_history/issues.20260308_235202_742600597.jsonl.meta.json +0 -1
  305. package/.beads/.br_history/issues.20260308_235208_133360069.jsonl +0 -57
  306. package/.beads/.br_history/issues.20260308_235208_133360069.jsonl.meta.json +0 -1
  307. package/.beads/.br_history/issues.20260308_235505_473406307.jsonl +0 -57
  308. package/.beads/.br_history/issues.20260308_235505_473406307.jsonl.meta.json +0 -1
  309. package/.beads/.br_history/issues.20260308_235505_662360489.jsonl +0 -57
  310. package/.beads/.br_history/issues.20260308_235505_662360489.jsonl.meta.json +0 -1
  311. package/.beads/.br_history/issues.20260308_235505_843935624.jsonl +0 -57
  312. package/.beads/.br_history/issues.20260308_235505_843935624.jsonl.meta.json +0 -1
  313. package/.beads/.br_history/issues.20260308_235506_044530221.jsonl +0 -57
  314. package/.beads/.br_history/issues.20260308_235506_044530221.jsonl.meta.json +0 -1
  315. package/.beads/.br_history/issues.20260309_002618_115728731.jsonl +0 -57
  316. package/.beads/.br_history/issues.20260309_002618_115728731.jsonl.meta.json +0 -1
  317. package/.beads/.br_history/issues.20260309_003748_878174586.jsonl +0 -57
  318. package/.beads/.br_history/issues.20260309_003748_878174586.jsonl.meta.json +0 -1
  319. package/.beads/.br_history/issues.20260309_004057_868755623.jsonl +0 -57
  320. package/.beads/.br_history/issues.20260309_004057_868755623.jsonl.meta.json +0 -1
  321. package/.beads/.br_history/issues.20260309_004058_512842163.jsonl +0 -57
  322. package/.beads/.br_history/issues.20260309_004058_512842163.jsonl.meta.json +0 -1
  323. package/.beads/.br_history/issues.20260309_004058_994445226.jsonl +0 -57
  324. package/.beads/.br_history/issues.20260309_004058_994445226.jsonl.meta.json +0 -1
  325. package/.beads/.br_history/issues.20260309_004059_475988596.jsonl +0 -57
  326. package/.beads/.br_history/issues.20260309_004059_475988596.jsonl.meta.json +0 -1
  327. package/.beads/.br_history/issues.20260309_161902_566857851.jsonl +0 -57
  328. package/.beads/.br_history/issues.20260309_161902_566857851.jsonl.meta.json +0 -1
  329. package/.beads/.br_history/issues.20260309_170512_277017739.jsonl +0 -57
  330. package/.beads/.br_history/issues.20260309_170512_277017739.jsonl.meta.json +0 -1
  331. package/.beads/.br_history/issues.20260309_170512_477876921.jsonl +0 -57
  332. package/.beads/.br_history/issues.20260309_170512_477876921.jsonl.meta.json +0 -1
  333. package/.beads/.br_history/issues.20260309_170512_664382701.jsonl +0 -57
  334. package/.beads/.br_history/issues.20260309_170512_664382701.jsonl.meta.json +0 -1
  335. package/.beads/.br_history/issues.20260309_170512_859400333.jsonl +0 -57
  336. package/.beads/.br_history/issues.20260309_170512_859400333.jsonl.meta.json +0 -1
  337. package/.beads/.br_history/issues.20260309_212326_082771164.jsonl +0 -57
  338. package/.beads/.br_history/issues.20260309_212326_082771164.jsonl.meta.json +0 -1
  339. package/.beads/.br_history/issues.20260309_212326_245619716.jsonl +0 -58
  340. package/.beads/.br_history/issues.20260309_212326_245619716.jsonl.meta.json +0 -1
  341. package/.beads/.br_history/issues.20260309_212326_403198317.jsonl +0 -59
  342. package/.beads/.br_history/issues.20260309_212326_403198317.jsonl.meta.json +0 -1
  343. package/.beads/.br_history/issues.20260309_212332_539197678.jsonl +0 -60
  344. package/.beads/.br_history/issues.20260309_212332_539197678.jsonl.meta.json +0 -1
  345. package/.beads/.br_history/issues.20260309_212332_731373599.jsonl +0 -60
  346. package/.beads/.br_history/issues.20260309_212332_731373599.jsonl.meta.json +0 -1
  347. package/.beads/.br_history/issues.20260309_212332_928710953.jsonl +0 -60
  348. package/.beads/.br_history/issues.20260309_212332_928710953.jsonl.meta.json +0 -1
  349. package/.beads/.br_history/issues.20260309_213021_341505240.jsonl +0 -60
  350. package/.beads/.br_history/issues.20260309_213021_341505240.jsonl.meta.json +0 -1
  351. package/.beads/.br_history/issues.20260309_213022_023136934.jsonl +0 -60
  352. package/.beads/.br_history/issues.20260309_213022_023136934.jsonl.meta.json +0 -1
  353. package/.beads/.br_history/issues.20260309_213022_400050719.jsonl +0 -60
  354. package/.beads/.br_history/issues.20260309_213022_400050719.jsonl.meta.json +0 -1
  355. package/.beads/config.yaml +0 -4
  356. package/.beads/issues.jsonl +0 -60
  357. package/.beads/metadata.json +0 -4
  358. package/docs/docs.html +0 -224
  359. package/docs/mcp-cheatsheet.md +0 -324
  360. package/docs/visual-overview.md +0 -21
  361. package/ref-monty/.cargo/config.toml +0 -3
  362. package/ref-monty/.claude/settings.json +0 -60
  363. package/ref-monty/.claude/skills/fastmod/SKILL.md +0 -22
  364. package/ref-monty/.claude/skills/python-playground/SKILL.md +0 -47
  365. package/ref-monty/.codecov.yml +0 -12
  366. package/ref-monty/.github/actions/build-pgo-wheel/action.yml +0 -72
  367. package/ref-monty/.github/workflows/ci.yml +0 -776
  368. package/ref-monty/.github/workflows/codspeed.yml +0 -45
  369. package/ref-monty/.github/workflows/init-npm-packages.yml +0 -82
  370. package/ref-monty/.pre-commit-config.yaml +0 -47
  371. package/ref-monty/.python-version +0 -1
  372. package/ref-monty/.rustfmt.toml +0 -4
  373. package/ref-monty/.zed/settings.json +0 -11
  374. package/ref-monty/CLAUDE.md +0 -535
  375. package/ref-monty/Cargo.lock +0 -3798
  376. package/ref-monty/Cargo.toml +0 -87
  377. package/ref-monty/LICENSE +0 -21
  378. package/ref-monty/Makefile +0 -216
  379. package/ref-monty/README.md +0 -430
  380. package/ref-monty/RELEASING.md +0 -47
  381. package/ref-monty/crates/fuzz/Cargo.toml +0 -30
  382. package/ref-monty/crates/fuzz/fuzz_targets/string_input_panic.rs +0 -37
  383. package/ref-monty/crates/fuzz/fuzz_targets/tokens_input_panic.rs +0 -552
  384. package/ref-monty/crates/monty/Cargo.toml +0 -68
  385. package/ref-monty/crates/monty/benches/main.rs +0 -247
  386. package/ref-monty/crates/monty/build.rs +0 -10
  387. package/ref-monty/crates/monty/src/args.rs +0 -733
  388. package/ref-monty/crates/monty/src/asyncio.rs +0 -179
  389. package/ref-monty/crates/monty/src/builtins/abs.rs +0 -55
  390. package/ref-monty/crates/monty/src/builtins/all.rs +0 -30
  391. package/ref-monty/crates/monty/src/builtins/any.rs +0 -30
  392. package/ref-monty/crates/monty/src/builtins/bin.rs +0 -59
  393. package/ref-monty/crates/monty/src/builtins/chr.rs +0 -46
  394. package/ref-monty/crates/monty/src/builtins/divmod.rs +0 -164
  395. package/ref-monty/crates/monty/src/builtins/enumerate.rs +0 -52
  396. package/ref-monty/crates/monty/src/builtins/filter.rs +0 -67
  397. package/ref-monty/crates/monty/src/builtins/getattr.rs +0 -65
  398. package/ref-monty/crates/monty/src/builtins/hash.rs +0 -28
  399. package/ref-monty/crates/monty/src/builtins/hex.rs +0 -58
  400. package/ref-monty/crates/monty/src/builtins/id.rs +0 -24
  401. package/ref-monty/crates/monty/src/builtins/isinstance.rs +0 -68
  402. package/ref-monty/crates/monty/src/builtins/len.rs +0 -25
  403. package/ref-monty/crates/monty/src/builtins/map.rs +0 -98
  404. package/ref-monty/crates/monty/src/builtins/min_max.rs +0 -113
  405. package/ref-monty/crates/monty/src/builtins/mod.rs +0 -246
  406. package/ref-monty/crates/monty/src/builtins/next.rs +0 -21
  407. package/ref-monty/crates/monty/src/builtins/oct.rs +0 -59
  408. package/ref-monty/crates/monty/src/builtins/ord.rs +0 -67
  409. package/ref-monty/crates/monty/src/builtins/pow.rs +0 -365
  410. package/ref-monty/crates/monty/src/builtins/print.rs +0 -141
  411. package/ref-monty/crates/monty/src/builtins/repr.rs +0 -16
  412. package/ref-monty/crates/monty/src/builtins/reversed.rs +0 -28
  413. package/ref-monty/crates/monty/src/builtins/round.rs +0 -174
  414. package/ref-monty/crates/monty/src/builtins/sorted.rs +0 -151
  415. package/ref-monty/crates/monty/src/builtins/sum.rs +0 -66
  416. package/ref-monty/crates/monty/src/builtins/type_.rs +0 -16
  417. package/ref-monty/crates/monty/src/builtins/zip.rs +0 -77
  418. package/ref-monty/crates/monty/src/bytecode/builder.rs +0 -699
  419. package/ref-monty/crates/monty/src/bytecode/code.rs +0 -310
  420. package/ref-monty/crates/monty/src/bytecode/compiler.rs +0 -3206
  421. package/ref-monty/crates/monty/src/bytecode/mod.rs +0 -24
  422. package/ref-monty/crates/monty/src/bytecode/op.rs +0 -617
  423. package/ref-monty/crates/monty/src/bytecode/vm/async_exec.rs +0 -1058
  424. package/ref-monty/crates/monty/src/bytecode/vm/attr.rs +0 -63
  425. package/ref-monty/crates/monty/src/bytecode/vm/binary.rs +0 -487
  426. package/ref-monty/crates/monty/src/bytecode/vm/call.rs +0 -767
  427. package/ref-monty/crates/monty/src/bytecode/vm/collections.rs +0 -741
  428. package/ref-monty/crates/monty/src/bytecode/vm/compare.rs +0 -147
  429. package/ref-monty/crates/monty/src/bytecode/vm/exceptions.rs +0 -297
  430. package/ref-monty/crates/monty/src/bytecode/vm/format.rs +0 -132
  431. package/ref-monty/crates/monty/src/bytecode/vm/mod.rs +0 -1958
  432. package/ref-monty/crates/monty/src/bytecode/vm/scheduler.rs +0 -620
  433. package/ref-monty/crates/monty/src/exception_private.rs +0 -1513
  434. package/ref-monty/crates/monty/src/exception_public.rs +0 -346
  435. package/ref-monty/crates/monty/src/expressions.rs +0 -694
  436. package/ref-monty/crates/monty/src/fstring.rs +0 -854
  437. package/ref-monty/crates/monty/src/function.rs +0 -119
  438. package/ref-monty/crates/monty/src/heap.rs +0 -1073
  439. package/ref-monty/crates/monty/src/heap_data.rs +0 -985
  440. package/ref-monty/crates/monty/src/heap_traits.rs +0 -312
  441. package/ref-monty/crates/monty/src/intern.rs +0 -837
  442. package/ref-monty/crates/monty/src/io.rs +0 -106
  443. package/ref-monty/crates/monty/src/lib.rs +0 -52
  444. package/ref-monty/crates/monty/src/modules/asyncio.rs +0 -144
  445. package/ref-monty/crates/monty/src/modules/math.rs +0 -1453
  446. package/ref-monty/crates/monty/src/modules/mod.rs +0 -120
  447. package/ref-monty/crates/monty/src/modules/os.rs +0 -116
  448. package/ref-monty/crates/monty/src/modules/pathlib.rs +0 -33
  449. package/ref-monty/crates/monty/src/modules/re.rs +0 -606
  450. package/ref-monty/crates/monty/src/modules/sys.rs +0 -60
  451. package/ref-monty/crates/monty/src/modules/typing.rs +0 -70
  452. package/ref-monty/crates/monty/src/namespace.rs +0 -21
  453. package/ref-monty/crates/monty/src/object.rs +0 -1040
  454. package/ref-monty/crates/monty/src/os.rs +0 -215
  455. package/ref-monty/crates/monty/src/parse.rs +0 -1730
  456. package/ref-monty/crates/monty/src/prepare.rs +0 -3015
  457. package/ref-monty/crates/monty/src/repl.rs +0 -1109
  458. package/ref-monty/crates/monty/src/resource.rs +0 -559
  459. package/ref-monty/crates/monty/src/run.rs +0 -457
  460. package/ref-monty/crates/monty/src/run_progress.rs +0 -821
  461. package/ref-monty/crates/monty/src/signature.rs +0 -651
  462. package/ref-monty/crates/monty/src/sorting.rs +0 -100
  463. package/ref-monty/crates/monty/src/types/bytes.rs +0 -2356
  464. package/ref-monty/crates/monty/src/types/dataclass.rs +0 -345
  465. package/ref-monty/crates/monty/src/types/dict.rs +0 -879
  466. package/ref-monty/crates/monty/src/types/dict_view.rs +0 -619
  467. package/ref-monty/crates/monty/src/types/iter.rs +0 -799
  468. package/ref-monty/crates/monty/src/types/list.rs +0 -929
  469. package/ref-monty/crates/monty/src/types/long_int.rs +0 -211
  470. package/ref-monty/crates/monty/src/types/mod.rs +0 -48
  471. package/ref-monty/crates/monty/src/types/module.rs +0 -146
  472. package/ref-monty/crates/monty/src/types/namedtuple.rs +0 -261
  473. package/ref-monty/crates/monty/src/types/path.rs +0 -596
  474. package/ref-monty/crates/monty/src/types/property.rs +0 -35
  475. package/ref-monty/crates/monty/src/types/py_trait.rs +0 -322
  476. package/ref-monty/crates/monty/src/types/range.rs +0 -285
  477. package/ref-monty/crates/monty/src/types/re_match.rs +0 -522
  478. package/ref-monty/crates/monty/src/types/re_pattern.rs +0 -726
  479. package/ref-monty/crates/monty/src/types/set.rs +0 -1373
  480. package/ref-monty/crates/monty/src/types/slice.rs +0 -257
  481. package/ref-monty/crates/monty/src/types/str.rs +0 -2051
  482. package/ref-monty/crates/monty/src/types/tuple.rs +0 -376
  483. package/ref-monty/crates/monty/src/types/type.rs +0 -407
  484. package/ref-monty/crates/monty/src/value.rs +0 -2558
  485. package/ref-monty/crates/monty/test_cases/args__dict_get_no_args.py +0 -3
  486. package/ref-monty/crates/monty/test_cases/args__dict_get_too_many.py +0 -3
  487. package/ref-monty/crates/monty/test_cases/args__dict_items_with_args.py +0 -3
  488. package/ref-monty/crates/monty/test_cases/args__dict_keys_with_args.py +0 -3
  489. package/ref-monty/crates/monty/test_cases/args__dict_pop_no_args.py +0 -3
  490. package/ref-monty/crates/monty/test_cases/args__dict_pop_too_many.py +0 -3
  491. package/ref-monty/crates/monty/test_cases/args__dict_values_with_args.py +0 -3
  492. package/ref-monty/crates/monty/test_cases/args__id_too_many.py +0 -2
  493. package/ref-monty/crates/monty/test_cases/args__len_no_args.py +0 -2
  494. package/ref-monty/crates/monty/test_cases/args__len_too_many.py +0 -2
  495. package/ref-monty/crates/monty/test_cases/args__len_type_error_int.py +0 -9
  496. package/ref-monty/crates/monty/test_cases/args__len_type_error_none.py +0 -9
  497. package/ref-monty/crates/monty/test_cases/args__list_append_no_args.py +0 -3
  498. package/ref-monty/crates/monty/test_cases/args__list_append_too_many.py +0 -3
  499. package/ref-monty/crates/monty/test_cases/args__list_insert_too_few.py +0 -3
  500. package/ref-monty/crates/monty/test_cases/args__list_insert_too_many.py +0 -3
  501. package/ref-monty/crates/monty/test_cases/args__repr_no_args.py +0 -2
  502. package/ref-monty/crates/monty/test_cases/arith__div_zero_float.py +0 -2
  503. package/ref-monty/crates/monty/test_cases/arith__div_zero_int.py +0 -2
  504. package/ref-monty/crates/monty/test_cases/arith__floordiv_zero_float.py +0 -2
  505. package/ref-monty/crates/monty/test_cases/arith__floordiv_zero_int.py +0 -2
  506. package/ref-monty/crates/monty/test_cases/arith__pow_zero_neg.py +0 -2
  507. package/ref-monty/crates/monty/test_cases/arith__pow_zero_neg_builtin.py +0 -9
  508. package/ref-monty/crates/monty/test_cases/assert__expr_fail.py +0 -2
  509. package/ref-monty/crates/monty/test_cases/assert__fail.py +0 -2
  510. package/ref-monty/crates/monty/test_cases/assert__fail_msg.py +0 -2
  511. package/ref-monty/crates/monty/test_cases/assert__fn_fail.py +0 -3
  512. package/ref-monty/crates/monty/test_cases/assert__ops.py +0 -11
  513. package/ref-monty/crates/monty/test_cases/async__asyncio_run.py +0 -47
  514. package/ref-monty/crates/monty/test_cases/async__basic.py +0 -10
  515. package/ref-monty/crates/monty/test_cases/async__closure.py +0 -14
  516. package/ref-monty/crates/monty/test_cases/async__double_await_coroutine.py +0 -16
  517. package/ref-monty/crates/monty/test_cases/async__exception.py +0 -10
  518. package/ref-monty/crates/monty/test_cases/async__ext_call.py +0 -73
  519. package/ref-monty/crates/monty/test_cases/async__gather_all.py +0 -85
  520. package/ref-monty/crates/monty/test_cases/async__nested_await.py +0 -15
  521. package/ref-monty/crates/monty/test_cases/async__nested_gather_ext.py +0 -37
  522. package/ref-monty/crates/monty/test_cases/async__not_awaitable.py +0 -10
  523. package/ref-monty/crates/monty/test_cases/async__not_imported.py +0 -14
  524. package/ref-monty/crates/monty/test_cases/async__recursion_depth_isolation.py +0 -27
  525. package/ref-monty/crates/monty/test_cases/async__return_types.py +0 -31
  526. package/ref-monty/crates/monty/test_cases/async__sequential.py +0 -16
  527. package/ref-monty/crates/monty/test_cases/async__traceback.py +0 -19
  528. package/ref-monty/crates/monty/test_cases/async__with_args.py +0 -14
  529. package/ref-monty/crates/monty/test_cases/attr__get_int_error.py +0 -9
  530. package/ref-monty/crates/monty/test_cases/attr__get_list_error.py +0 -9
  531. package/ref-monty/crates/monty/test_cases/attr__set_frozen_nonfield.py +0 -12
  532. package/ref-monty/crates/monty/test_cases/attr__set_int_error.py +0 -10
  533. package/ref-monty/crates/monty/test_cases/attr__set_list_error.py +0 -10
  534. package/ref-monty/crates/monty/test_cases/bench__kitchen_sink.py +0 -68
  535. package/ref-monty/crates/monty/test_cases/bool__ops.py +0 -20
  536. package/ref-monty/crates/monty/test_cases/builtin__add_type_error.py +0 -2
  537. package/ref-monty/crates/monty/test_cases/builtin__filter.py +0 -62
  538. package/ref-monty/crates/monty/test_cases/builtin__filter_not_iterable.py +0 -11
  539. package/ref-monty/crates/monty/test_cases/builtin__getattr.py +0 -84
  540. package/ref-monty/crates/monty/test_cases/builtin__iter_funcs.py +0 -42
  541. package/ref-monty/crates/monty/test_cases/builtin__iter_next.py +0 -66
  542. package/ref-monty/crates/monty/test_cases/builtin__map.py +0 -74
  543. package/ref-monty/crates/monty/test_cases/builtin__map_not_iterable.py +0 -11
  544. package/ref-monty/crates/monty/test_cases/builtin__math_funcs.py +0 -154
  545. package/ref-monty/crates/monty/test_cases/builtin__more_iter_funcs.py +0 -148
  546. package/ref-monty/crates/monty/test_cases/builtin__next_stop_iteration.py +0 -10
  547. package/ref-monty/crates/monty/test_cases/builtin__print_invalid_kwarg.py +0 -9
  548. package/ref-monty/crates/monty/test_cases/builtin__print_kwargs.py +0 -12
  549. package/ref-monty/crates/monty/test_cases/builtin__repr.py +0 -3
  550. package/ref-monty/crates/monty/test_cases/builtin__string_funcs.py +0 -73
  551. package/ref-monty/crates/monty/test_cases/bytes__decode_invalid_utf8.py +0 -18
  552. package/ref-monty/crates/monty/test_cases/bytes__endswith_str_error.py +0 -10
  553. package/ref-monty/crates/monty/test_cases/bytes__getitem_index_error.py +0 -10
  554. package/ref-monty/crates/monty/test_cases/bytes__index_start_gt_end.py +0 -10
  555. package/ref-monty/crates/monty/test_cases/bytes__methods.py +0 -394
  556. package/ref-monty/crates/monty/test_cases/bytes__negative_count.py +0 -9
  557. package/ref-monty/crates/monty/test_cases/bytes__ops.py +0 -90
  558. package/ref-monty/crates/monty/test_cases/bytes__startswith_str_error.py +0 -10
  559. package/ref-monty/crates/monty/test_cases/call_object.py +0 -3
  560. package/ref-monty/crates/monty/test_cases/chain_comparison__all.py +0 -79
  561. package/ref-monty/crates/monty/test_cases/closure__param_shadows_outer.py +0 -81
  562. package/ref-monty/crates/monty/test_cases/closure__pep448.py +0 -203
  563. package/ref-monty/crates/monty/test_cases/closure__undefined_nonlocal.py +0 -13
  564. package/ref-monty/crates/monty/test_cases/compare__mixed_types.py +0 -120
  565. package/ref-monty/crates/monty/test_cases/comprehension__all.py +0 -208
  566. package/ref-monty/crates/monty/test_cases/comprehension__scope.py +0 -7
  567. package/ref-monty/crates/monty/test_cases/comprehension__unbound_local.py +0 -14
  568. package/ref-monty/crates/monty/test_cases/dataclass__basic.py +0 -238
  569. package/ref-monty/crates/monty/test_cases/dataclass__call_field_error.py +0 -12
  570. package/ref-monty/crates/monty/test_cases/dataclass__frozen_set_error.py +0 -12
  571. package/ref-monty/crates/monty/test_cases/dataclass__get_missing_attr_error.py +0 -11
  572. package/ref-monty/crates/monty/test_cases/dict__get_unhashable_key.py +0 -3
  573. package/ref-monty/crates/monty/test_cases/dict__literal_unhashable_key.py +0 -2
  574. package/ref-monty/crates/monty/test_cases/dict__method_pop_missing_error.py +0 -3
  575. package/ref-monty/crates/monty/test_cases/dict__methods.py +0 -151
  576. package/ref-monty/crates/monty/test_cases/dict__ops.py +0 -133
  577. package/ref-monty/crates/monty/test_cases/dict__pop_unhashable_key.py +0 -4
  578. package/ref-monty/crates/monty/test_cases/dict__popitem_empty.py +0 -9
  579. package/ref-monty/crates/monty/test_cases/dict__subscript_missing_key.py +0 -3
  580. package/ref-monty/crates/monty/test_cases/dict__unhashable_dict_key.py +0 -2
  581. package/ref-monty/crates/monty/test_cases/dict__unhashable_list_key.py +0 -2
  582. package/ref-monty/crates/monty/test_cases/dict__unpack_type_error.py +0 -2
  583. package/ref-monty/crates/monty/test_cases/dict__views.py +0 -165
  584. package/ref-monty/crates/monty/test_cases/edge__all.py +0 -26
  585. package/ref-monty/crates/monty/test_cases/edge__float_int_mod.py +0 -2
  586. package/ref-monty/crates/monty/test_cases/edge__int_float_mod.py +0 -2
  587. package/ref-monty/crates/monty/test_cases/exc__args.py +0 -16
  588. package/ref-monty/crates/monty/test_cases/exc__str.py +0 -15
  589. package/ref-monty/crates/monty/test_cases/execute_ok__all.py +0 -54
  590. package/ref-monty/crates/monty/test_cases/execute_raise__error_instance_str.py +0 -2
  591. package/ref-monty/crates/monty/test_cases/execute_raise__error_no_args.py +0 -2
  592. package/ref-monty/crates/monty/test_cases/execute_raise__error_string_arg.py +0 -2
  593. package/ref-monty/crates/monty/test_cases/execute_raise__error_string_arg_quotes.py +0 -2
  594. package/ref-monty/crates/monty/test_cases/execute_raise__error_type.py +0 -2
  595. package/ref-monty/crates/monty/test_cases/execute_raise__raise_instance_via_var.py +0 -4
  596. package/ref-monty/crates/monty/test_cases/execute_raise__raise_list.py +0 -2
  597. package/ref-monty/crates/monty/test_cases/execute_raise__raise_number.py +0 -2
  598. package/ref-monty/crates/monty/test_cases/execute_raise__raise_type_call_via_var.py +0 -4
  599. package/ref-monty/crates/monty/test_cases/execute_raise__raise_type_direct.py +0 -3
  600. package/ref-monty/crates/monty/test_cases/execute_raise__raise_type_via_var.py +0 -4
  601. package/ref-monty/crates/monty/test_cases/ext_call__arg_side_effect_bug.py +0 -22
  602. package/ref-monty/crates/monty/test_cases/ext_call__augmented.py +0 -17
  603. package/ref-monty/crates/monty/test_cases/ext_call__augmented_refcount_bug.py +0 -7
  604. package/ref-monty/crates/monty/test_cases/ext_call__bare_raise_after_resume.py +0 -34
  605. package/ref-monty/crates/monty/test_cases/ext_call__basic.py +0 -99
  606. package/ref-monty/crates/monty/test_cases/ext_call__boolean.py +0 -37
  607. package/ref-monty/crates/monty/test_cases/ext_call__boolean_side_effect_hang.py +0 -17
  608. package/ref-monty/crates/monty/test_cases/ext_call__closure_bug.py +0 -16
  609. package/ref-monty/crates/monty/test_cases/ext_call__comparison.py +0 -26
  610. package/ref-monty/crates/monty/test_cases/ext_call__deep_call_stack.py +0 -18
  611. package/ref-monty/crates/monty/test_cases/ext_call__elif.py +0 -171
  612. package/ref-monty/crates/monty/test_cases/ext_call__exc.py +0 -4
  613. package/ref-monty/crates/monty/test_cases/ext_call__exc_deep_stack.py +0 -39
  614. package/ref-monty/crates/monty/test_cases/ext_call__exc_in_function.py +0 -17
  615. package/ref-monty/crates/monty/test_cases/ext_call__exc_nested_functions.py +0 -31
  616. package/ref-monty/crates/monty/test_cases/ext_call__ext_exc.py +0 -171
  617. package/ref-monty/crates/monty/test_cases/ext_call__for.py +0 -114
  618. package/ref-monty/crates/monty/test_cases/ext_call__fstring.py +0 -12
  619. package/ref-monty/crates/monty/test_cases/ext_call__if.py +0 -135
  620. package/ref-monty/crates/monty/test_cases/ext_call__if_condition.py +0 -37
  621. package/ref-monty/crates/monty/test_cases/ext_call__in_closure.py +0 -14
  622. package/ref-monty/crates/monty/test_cases/ext_call__in_function.py +0 -40
  623. package/ref-monty/crates/monty/test_cases/ext_call__in_function_simple.py +0 -7
  624. package/ref-monty/crates/monty/test_cases/ext_call__literals.py +0 -17
  625. package/ref-monty/crates/monty/test_cases/ext_call__multi_in_func.py +0 -32
  626. package/ref-monty/crates/monty/test_cases/ext_call__name_lookup.py +0 -69
  627. package/ref-monty/crates/monty/test_cases/ext_call__name_lookup_undefined.py +0 -4
  628. package/ref-monty/crates/monty/test_cases/ext_call__nested_calls.py +0 -14
  629. package/ref-monty/crates/monty/test_cases/ext_call__recursion_bug.py +0 -19
  630. package/ref-monty/crates/monty/test_cases/ext_call__return.py +0 -28
  631. package/ref-monty/crates/monty/test_cases/ext_call__side_effects.py +0 -25
  632. package/ref-monty/crates/monty/test_cases/ext_call__subscript.py +0 -7
  633. package/ref-monty/crates/monty/test_cases/ext_call__ternary.py +0 -28
  634. package/ref-monty/crates/monty/test_cases/ext_call__try.py +0 -280
  635. package/ref-monty/crates/monty/test_cases/ext_call__try_simple.py +0 -10
  636. package/ref-monty/crates/monty/test_cases/ext_call__unary.py +0 -13
  637. package/ref-monty/crates/monty/test_cases/frozenset__ops.py +0 -178
  638. package/ref-monty/crates/monty/test_cases/fstring__all.py +0 -236
  639. package/ref-monty/crates/monty/test_cases/fstring__error_eq_align_on_str.py +0 -3
  640. package/ref-monty/crates/monty/test_cases/fstring__error_float_f_on_str.py +0 -3
  641. package/ref-monty/crates/monty/test_cases/fstring__error_int_d_on_float.py +0 -3
  642. package/ref-monty/crates/monty/test_cases/fstring__error_int_d_on_str.py +0 -3
  643. package/ref-monty/crates/monty/test_cases/fstring__error_invalid_spec.py +0 -4
  644. package/ref-monty/crates/monty/test_cases/fstring__error_invalid_spec_dynamic.py +0 -4
  645. package/ref-monty/crates/monty/test_cases/fstring__error_invalid_spec_str.py +0 -4
  646. package/ref-monty/crates/monty/test_cases/fstring__error_str_s_on_int.py +0 -3
  647. package/ref-monty/crates/monty/test_cases/function__call_duplicate_kwargs.py +0 -6
  648. package/ref-monty/crates/monty/test_cases/function__call_unpack.py +0 -42
  649. package/ref-monty/crates/monty/test_cases/function__defaults.py +0 -117
  650. package/ref-monty/crates/monty/test_cases/function__err_duplicate_arg.py +0 -7
  651. package/ref-monty/crates/monty/test_cases/function__err_duplicate_first_arg.py +0 -7
  652. package/ref-monty/crates/monty/test_cases/function__err_duplicate_kwarg_cleanup.py +0 -9
  653. package/ref-monty/crates/monty/test_cases/function__err_kwonly_as_positional.py +0 -7
  654. package/ref-monty/crates/monty/test_cases/function__err_missing_all_posonly.py +0 -7
  655. package/ref-monty/crates/monty/test_cases/function__err_missing_heap_cleanup.py +0 -9
  656. package/ref-monty/crates/monty/test_cases/function__err_missing_kwonly.py +0 -7
  657. package/ref-monty/crates/monty/test_cases/function__err_missing_posonly_with_kwarg.py +0 -7
  658. package/ref-monty/crates/monty/test_cases/function__err_missing_with_posonly.py +0 -7
  659. package/ref-monty/crates/monty/test_cases/function__err_posonly_as_kwarg.py +0 -7
  660. package/ref-monty/crates/monty/test_cases/function__err_posonly_first_as_kwarg.py +0 -7
  661. package/ref-monty/crates/monty/test_cases/function__err_too_many_posonly.py +0 -7
  662. package/ref-monty/crates/monty/test_cases/function__err_too_many_with_kwonly.py +0 -7
  663. package/ref-monty/crates/monty/test_cases/function__err_unexpected_kwarg.py +0 -7
  664. package/ref-monty/crates/monty/test_cases/function__err_unexpected_kwarg_cleanup.py +0 -9
  665. package/ref-monty/crates/monty/test_cases/function__err_unexpected_kwarg_quote.py +0 -13
  666. package/ref-monty/crates/monty/test_cases/function__err_unexpected_kwarg_simple.py +0 -7
  667. package/ref-monty/crates/monty/test_cases/function__err_unpack_duplicate_arg.py +0 -6
  668. package/ref-monty/crates/monty/test_cases/function__err_unpack_duplicate_heap.py +0 -8
  669. package/ref-monty/crates/monty/test_cases/function__err_unpack_int.py +0 -6
  670. package/ref-monty/crates/monty/test_cases/function__err_unpack_nonstring_key.py +0 -6
  671. package/ref-monty/crates/monty/test_cases/function__err_unpack_not_mapping.py +0 -6
  672. package/ref-monty/crates/monty/test_cases/function__kwargs_unpacking.py +0 -173
  673. package/ref-monty/crates/monty/test_cases/function__ops.py +0 -294
  674. package/ref-monty/crates/monty/test_cases/function__return_none.py +0 -42
  675. package/ref-monty/crates/monty/test_cases/function__signatures.py +0 -47
  676. package/ref-monty/crates/monty/test_cases/function__too_few_args_all.py +0 -6
  677. package/ref-monty/crates/monty/test_cases/function__too_few_args_one.py +0 -6
  678. package/ref-monty/crates/monty/test_cases/function__too_few_args_two.py +0 -6
  679. package/ref-monty/crates/monty/test_cases/function__too_many_args_one.py +0 -6
  680. package/ref-monty/crates/monty/test_cases/function__too_many_args_two.py +0 -6
  681. package/ref-monty/crates/monty/test_cases/function__too_many_args_zero.py +0 -6
  682. package/ref-monty/crates/monty/test_cases/global__error_assigned_before.py +0 -7
  683. package/ref-monty/crates/monty/test_cases/global__ops.py +0 -163
  684. package/ref-monty/crates/monty/test_cases/hash__dict_unhashable.py +0 -2
  685. package/ref-monty/crates/monty/test_cases/hash__list_unhashable.py +0 -2
  686. package/ref-monty/crates/monty/test_cases/hash__ops.py +0 -153
  687. package/ref-monty/crates/monty/test_cases/id__bytes_literals_distinct.py +0 -3
  688. package/ref-monty/crates/monty/test_cases/id__int_copy_distinct.py +0 -5
  689. package/ref-monty/crates/monty/test_cases/id__is_number_is_number.py +0 -3
  690. package/ref-monty/crates/monty/test_cases/id__non_overlapping_lifetimes_distinct_types.py +0 -10
  691. package/ref-monty/crates/monty/test_cases/id__non_overlapping_lifetimes_same_types.py +0 -6
  692. package/ref-monty/crates/monty/test_cases/id__ops.py +0 -97
  693. package/ref-monty/crates/monty/test_cases/id__str_literals_same.py +0 -3
  694. package/ref-monty/crates/monty/test_cases/if__elif_else.py +0 -207
  695. package/ref-monty/crates/monty/test_cases/if__raise_elif.py +0 -11
  696. package/ref-monty/crates/monty/test_cases/if__raise_else.py +0 -13
  697. package/ref-monty/crates/monty/test_cases/if__raise_if.py +0 -9
  698. package/ref-monty/crates/monty/test_cases/if__raise_in_elif_condition.py +0 -18
  699. package/ref-monty/crates/monty/test_cases/if__raise_in_if_condition.py +0 -16
  700. package/ref-monty/crates/monty/test_cases/if_else_expr__all.py +0 -55
  701. package/ref-monty/crates/monty/test_cases/import__error_cannot_import.py +0 -9
  702. package/ref-monty/crates/monty/test_cases/import__error_module_not_found.py +0 -9
  703. package/ref-monty/crates/monty/test_cases/import__local_scope.py +0 -68
  704. package/ref-monty/crates/monty/test_cases/import__os.py +0 -25
  705. package/ref-monty/crates/monty/test_cases/import__relative_error.py +0 -9
  706. package/ref-monty/crates/monty/test_cases/import__relative_no_module_error.py +0 -9
  707. package/ref-monty/crates/monty/test_cases/import__runtime_error_when_executed.py +0 -14
  708. package/ref-monty/crates/monty/test_cases/import__star_error.py +0 -11
  709. package/ref-monty/crates/monty/test_cases/import__sys.py +0 -47
  710. package/ref-monty/crates/monty/test_cases/import__sys_monty.py +0 -28
  711. package/ref-monty/crates/monty/test_cases/import__type_checking_guard.py +0 -37
  712. package/ref-monty/crates/monty/test_cases/import__typing.py +0 -25
  713. package/ref-monty/crates/monty/test_cases/import__typing_type_ignore.py +0 -4
  714. package/ref-monty/crates/monty/test_cases/int__bigint.py +0 -467
  715. package/ref-monty/crates/monty/test_cases/int__bigint_errors.py +0 -260
  716. package/ref-monty/crates/monty/test_cases/int__ops.py +0 -219
  717. package/ref-monty/crates/monty/test_cases/int__overflow_division.py +0 -84
  718. package/ref-monty/crates/monty/test_cases/is_variant__all.py +0 -36
  719. package/ref-monty/crates/monty/test_cases/isinstance__arg2_list_error.py +0 -2
  720. package/ref-monty/crates/monty/test_cases/isinstance__arg2_type_error.py +0 -2
  721. package/ref-monty/crates/monty/test_cases/iter__dict_mutation.py +0 -4
  722. package/ref-monty/crates/monty/test_cases/iter__for.py +0 -243
  723. package/ref-monty/crates/monty/test_cases/iter__for_loop_unpacking.py +0 -66
  724. package/ref-monty/crates/monty/test_cases/iter__generator_expr.py +0 -20
  725. package/ref-monty/crates/monty/test_cases/iter__generator_expr_type.py +0 -7
  726. package/ref-monty/crates/monty/test_cases/iter__not_iterable.py +0 -3
  727. package/ref-monty/crates/monty/test_cases/lambda__all.py +0 -145
  728. package/ref-monty/crates/monty/test_cases/list__extend_not_iterable.py +0 -7
  729. package/ref-monty/crates/monty/test_cases/list__getitem_out_of_bounds.py +0 -3
  730. package/ref-monty/crates/monty/test_cases/list__index_not_found.py +0 -9
  731. package/ref-monty/crates/monty/test_cases/list__index_start_gt_end.py +0 -10
  732. package/ref-monty/crates/monty/test_cases/list__ops.py +0 -473
  733. package/ref-monty/crates/monty/test_cases/list__pop_empty.py +0 -9
  734. package/ref-monty/crates/monty/test_cases/list__pop_out_of_range.py +0 -9
  735. package/ref-monty/crates/monty/test_cases/list__pop_type_error.py +0 -9
  736. package/ref-monty/crates/monty/test_cases/list__remove_not_found.py +0 -9
  737. package/ref-monty/crates/monty/test_cases/list__setitem_dict_index.py +0 -13
  738. package/ref-monty/crates/monty/test_cases/list__setitem_huge_int_index.py +0 -13
  739. package/ref-monty/crates/monty/test_cases/list__setitem_index_error.py +0 -10
  740. package/ref-monty/crates/monty/test_cases/list__setitem_type_error.py +0 -10
  741. package/ref-monty/crates/monty/test_cases/list__unpack_type_error.py +0 -2
  742. package/ref-monty/crates/monty/test_cases/longint__index_error.py +0 -3
  743. package/ref-monty/crates/monty/test_cases/longint__repeat_error.py +0 -3
  744. package/ref-monty/crates/monty/test_cases/loop__break_continue.py +0 -113
  745. package/ref-monty/crates/monty/test_cases/loop__break_finally.py +0 -69
  746. package/ref-monty/crates/monty/test_cases/loop__break_in_function_error.py +0 -13
  747. package/ref-monty/crates/monty/test_cases/loop__break_in_if_error.py +0 -11
  748. package/ref-monty/crates/monty/test_cases/loop__break_nested_except_clears.py +0 -55
  749. package/ref-monty/crates/monty/test_cases/loop__break_outside_error.py +0 -9
  750. package/ref-monty/crates/monty/test_cases/loop__continue_finally.py +0 -81
  751. package/ref-monty/crates/monty/test_cases/loop__continue_in_function_error.py +0 -13
  752. package/ref-monty/crates/monty/test_cases/loop__continue_in_if_error.py +0 -11
  753. package/ref-monty/crates/monty/test_cases/loop__continue_nested_except_clears.py +0 -60
  754. package/ref-monty/crates/monty/test_cases/loop__continue_outside_error.py +0 -9
  755. package/ref-monty/crates/monty/test_cases/math__acos_domain_error.py +0 -11
  756. package/ref-monty/crates/monty/test_cases/math__acosh_domain_error.py +0 -11
  757. package/ref-monty/crates/monty/test_cases/math__asin_domain_error.py +0 -11
  758. package/ref-monty/crates/monty/test_cases/math__atanh_domain_error.py +0 -11
  759. package/ref-monty/crates/monty/test_cases/math__cos_inf_error.py +0 -11
  760. package/ref-monty/crates/monty/test_cases/math__cosh_overflow_error.py +0 -11
  761. package/ref-monty/crates/monty/test_cases/math__exp_overflow_error.py +0 -11
  762. package/ref-monty/crates/monty/test_cases/math__factorial_float_error.py +0 -11
  763. package/ref-monty/crates/monty/test_cases/math__factorial_negative_error.py +0 -11
  764. package/ref-monty/crates/monty/test_cases/math__floor_inf_error.py +0 -11
  765. package/ref-monty/crates/monty/test_cases/math__floor_nan_error.py +0 -11
  766. package/ref-monty/crates/monty/test_cases/math__floor_str_error.py +0 -11
  767. package/ref-monty/crates/monty/test_cases/math__fmod_inf_error.py +0 -11
  768. package/ref-monty/crates/monty/test_cases/math__gamma_neg_int_error.py +0 -11
  769. package/ref-monty/crates/monty/test_cases/math__gcd_float_error.py +0 -11
  770. package/ref-monty/crates/monty/test_cases/math__isqrt_negative_error.py +0 -11
  771. package/ref-monty/crates/monty/test_cases/math__ldexp_overflow_error.py +0 -11
  772. package/ref-monty/crates/monty/test_cases/math__log1p_domain_error.py +0 -11
  773. package/ref-monty/crates/monty/test_cases/math__log_base1_error.py +0 -11
  774. package/ref-monty/crates/monty/test_cases/math__log_zero_error.py +0 -11
  775. package/ref-monty/crates/monty/test_cases/math__module.py +0 -1432
  776. package/ref-monty/crates/monty/test_cases/math__pow_domain_error.py +0 -11
  777. package/ref-monty/crates/monty/test_cases/math__sin_inf_error.py +0 -11
  778. package/ref-monty/crates/monty/test_cases/math__sqrt_negative_error.py +0 -11
  779. package/ref-monty/crates/monty/test_cases/math__tan_inf_error.py +0 -11
  780. package/ref-monty/crates/monty/test_cases/math__trunc_str_error.py +0 -11
  781. package/ref-monty/crates/monty/test_cases/method__args_kwargs_unpacking.py +0 -259
  782. package/ref-monty/crates/monty/test_cases/name_error__unbound_local_func.py +0 -19
  783. package/ref-monty/crates/monty/test_cases/name_error__unbound_local_module.py +0 -12
  784. package/ref-monty/crates/monty/test_cases/name_error__undefined_call_chained.py +0 -9
  785. package/ref-monty/crates/monty/test_cases/name_error__undefined_call_in_expr.py +0 -9
  786. package/ref-monty/crates/monty/test_cases/name_error__undefined_call_in_function.py +0 -16
  787. package/ref-monty/crates/monty/test_cases/name_error__undefined_call_with_args.py +0 -9
  788. package/ref-monty/crates/monty/test_cases/name_error__undefined_global.py +0 -10
  789. package/ref-monty/crates/monty/test_cases/namedtuple__missing_attr.py +0 -11
  790. package/ref-monty/crates/monty/test_cases/namedtuple__ops.py +0 -34
  791. package/ref-monty/crates/monty/test_cases/nonlocal__error_module_level.py +0 -3
  792. package/ref-monty/crates/monty/test_cases/nonlocal__ops.py +0 -353
  793. package/ref-monty/crates/monty/test_cases/os__environ.py +0 -40
  794. package/ref-monty/crates/monty/test_cases/os__getenv_key_list_error.py +0 -5
  795. package/ref-monty/crates/monty/test_cases/os__getenv_key_type_error.py +0 -5
  796. package/ref-monty/crates/monty/test_cases/parse_error__complex.py +0 -3
  797. package/ref-monty/crates/monty/test_cases/pathlib__import.py +0 -11
  798. package/ref-monty/crates/monty/test_cases/pathlib__os.py +0 -136
  799. package/ref-monty/crates/monty/test_cases/pathlib__os_read_error.py +0 -12
  800. package/ref-monty/crates/monty/test_cases/pathlib__pure.py +0 -81
  801. package/ref-monty/crates/monty/test_cases/pyobject__cycle_dict_self.py +0 -5
  802. package/ref-monty/crates/monty/test_cases/pyobject__cycle_list_dict.py +0 -6
  803. package/ref-monty/crates/monty/test_cases/pyobject__cycle_list_self.py +0 -5
  804. package/ref-monty/crates/monty/test_cases/pyobject__cycle_multiple_refs.py +0 -6
  805. package/ref-monty/crates/monty/test_cases/range__error_no_args.py +0 -2
  806. package/ref-monty/crates/monty/test_cases/range__error_step_zero.py +0 -2
  807. package/ref-monty/crates/monty/test_cases/range__error_too_many_args.py +0 -2
  808. package/ref-monty/crates/monty/test_cases/range__getitem_index_error.py +0 -10
  809. package/ref-monty/crates/monty/test_cases/range__ops.py +0 -236
  810. package/ref-monty/crates/monty/test_cases/re__basic.py +0 -756
  811. package/ref-monty/crates/monty/test_cases/re__grouping.py +0 -241
  812. package/ref-monty/crates/monty/test_cases/re__match.py +0 -148
  813. package/ref-monty/crates/monty/test_cases/recursion__deep_drop.py +0 -26
  814. package/ref-monty/crates/monty/test_cases/recursion__deep_eq.py +0 -23
  815. package/ref-monty/crates/monty/test_cases/recursion__deep_hash.py +0 -46
  816. package/ref-monty/crates/monty/test_cases/recursion__deep_repr.py +0 -12
  817. package/ref-monty/crates/monty/test_cases/recursion__function_depth.py +0 -13
  818. package/ref-monty/crates/monty/test_cases/refcount__cycle_mutual_reference.py +0 -18
  819. package/ref-monty/crates/monty/test_cases/refcount__cycle_self_reference.py +0 -12
  820. package/ref-monty/crates/monty/test_cases/refcount__dict_basic.py +0 -5
  821. package/ref-monty/crates/monty/test_cases/refcount__dict_get.py +0 -5
  822. package/ref-monty/crates/monty/test_cases/refcount__dict_keys_and.py +0 -14
  823. package/ref-monty/crates/monty/test_cases/refcount__dict_overwrite.py +0 -6
  824. package/ref-monty/crates/monty/test_cases/refcount__gather_cleanup.py +0 -16
  825. package/ref-monty/crates/monty/test_cases/refcount__gather_exception.py +0 -18
  826. package/ref-monty/crates/monty/test_cases/refcount__gather_nested_cancel.py +0 -25
  827. package/ref-monty/crates/monty/test_cases/refcount__immediate_skipped.py +0 -4
  828. package/ref-monty/crates/monty/test_cases/refcount__kwargs_unpacking.py +0 -27
  829. package/ref-monty/crates/monty/test_cases/refcount__list_append_multiple.py +0 -6
  830. package/ref-monty/crates/monty/test_cases/refcount__list_append_ref.py +0 -5
  831. package/ref-monty/crates/monty/test_cases/refcount__list_concat.py +0 -5
  832. package/ref-monty/crates/monty/test_cases/refcount__list_getitem.py +0 -5
  833. package/ref-monty/crates/monty/test_cases/refcount__list_iadd.py +0 -5
  834. package/ref-monty/crates/monty/test_cases/refcount__nested_list.py +0 -4
  835. package/ref-monty/crates/monty/test_cases/refcount__re_pattern_sub_error_paths.py +0 -37
  836. package/ref-monty/crates/monty/test_cases/refcount__re_search_match.py +0 -34
  837. package/ref-monty/crates/monty/test_cases/refcount__re_sub_error_paths.py +0 -31
  838. package/ref-monty/crates/monty/test_cases/refcount__shared_reference.py +0 -4
  839. package/ref-monty/crates/monty/test_cases/refcount__single_list.py +0 -3
  840. package/ref-monty/crates/monty/test_cases/repr__cycle_detection.py +0 -24
  841. package/ref-monty/crates/monty/test_cases/set__ops.py +0 -191
  842. package/ref-monty/crates/monty/test_cases/set__review_bugs.py +0 -35
  843. package/ref-monty/crates/monty/test_cases/set__unpack_type_error.py +0 -2
  844. package/ref-monty/crates/monty/test_cases/slice__invalid_indices.py +0 -2
  845. package/ref-monty/crates/monty/test_cases/slice__kwargs.py +0 -9
  846. package/ref-monty/crates/monty/test_cases/slice__no_args.py +0 -9
  847. package/ref-monty/crates/monty/test_cases/slice__ops.py +0 -149
  848. package/ref-monty/crates/monty/test_cases/slice__step_zero.py +0 -9
  849. package/ref-monty/crates/monty/test_cases/slice__step_zero_bytes.py +0 -9
  850. package/ref-monty/crates/monty/test_cases/slice__step_zero_range.py +0 -9
  851. package/ref-monty/crates/monty/test_cases/slice__step_zero_str.py +0 -9
  852. package/ref-monty/crates/monty/test_cases/slice__step_zero_tuple.py +0 -9
  853. package/ref-monty/crates/monty/test_cases/slice__too_many_args.py +0 -9
  854. package/ref-monty/crates/monty/test_cases/str__getitem_index_error.py +0 -10
  855. package/ref-monty/crates/monty/test_cases/str__index_not_found.py +0 -9
  856. package/ref-monty/crates/monty/test_cases/str__join_no_args.py +0 -9
  857. package/ref-monty/crates/monty/test_cases/str__join_non_string.py +0 -9
  858. package/ref-monty/crates/monty/test_cases/str__join_not_iterable.py +0 -9
  859. package/ref-monty/crates/monty/test_cases/str__join_too_many_args.py +0 -9
  860. package/ref-monty/crates/monty/test_cases/str__methods.py +0 -327
  861. package/ref-monty/crates/monty/test_cases/str__ops.py +0 -162
  862. package/ref-monty/crates/monty/test_cases/str__partition_empty.py +0 -9
  863. package/ref-monty/crates/monty/test_cases/str__rsplit_empty_sep.py +0 -9
  864. package/ref-monty/crates/monty/test_cases/str__split_empty_sep.py +0 -9
  865. package/ref-monty/crates/monty/test_cases/sys__types.py +0 -7
  866. package/ref-monty/crates/monty/test_cases/traceback__division_error.py +0 -30
  867. package/ref-monty/crates/monty/test_cases/traceback__index_error.py +0 -17
  868. package/ref-monty/crates/monty/test_cases/traceback__insert_as_int.py +0 -10
  869. package/ref-monty/crates/monty/test_cases/traceback__nested_call.py +0 -29
  870. package/ref-monty/crates/monty/test_cases/traceback__nonlocal_module_scope.py +0 -10
  871. package/ref-monty/crates/monty/test_cases/traceback__nonlocal_unbound.py +0 -24
  872. package/ref-monty/crates/monty/test_cases/traceback__range_as_int.py +0 -9
  873. package/ref-monty/crates/monty/test_cases/traceback__recursion_error.py +0 -23
  874. package/ref-monty/crates/monty/test_cases/traceback__set_mutation.py +0 -11
  875. package/ref-monty/crates/monty/test_cases/traceback__undefined_attr_call.py +0 -16
  876. package/ref-monty/crates/monty/test_cases/traceback__undefined_call.py +0 -16
  877. package/ref-monty/crates/monty/test_cases/traceback__undefined_raise.py +0 -16
  878. package/ref-monty/crates/monty/test_cases/try_except__all.py +0 -472
  879. package/ref-monty/crates/monty/test_cases/try_except__bare_raise_no_context.py +0 -2
  880. package/ref-monty/crates/monty/test_cases/try_except__invalid_type.py +0 -5
  881. package/ref-monty/crates/monty/test_cases/tuple__getitem_out_of_bounds.py +0 -3
  882. package/ref-monty/crates/monty/test_cases/tuple__index_not_found.py +0 -9
  883. package/ref-monty/crates/monty/test_cases/tuple__index_start_gt_end.py +0 -10
  884. package/ref-monty/crates/monty/test_cases/tuple__methods.py +0 -19
  885. package/ref-monty/crates/monty/test_cases/tuple__ops.py +0 -133
  886. package/ref-monty/crates/monty/test_cases/tuple__unpack_type_error.py +0 -2
  887. package/ref-monty/crates/monty/test_cases/type__builtin_attr_error.py +0 -9
  888. package/ref-monty/crates/monty/test_cases/type__bytes_negative.py +0 -2
  889. package/ref-monty/crates/monty/test_cases/type__cell_not_builtin.py +0 -9
  890. package/ref-monty/crates/monty/test_cases/type__exception_attr_error.py +0 -11
  891. package/ref-monty/crates/monty/test_cases/type__float_conversion_error.py +0 -2
  892. package/ref-monty/crates/monty/test_cases/type__float_repr_both_quotes.py +0 -9
  893. package/ref-monty/crates/monty/test_cases/type__float_repr_newline.py +0 -9
  894. package/ref-monty/crates/monty/test_cases/type__float_repr_single_quote.py +0 -9
  895. package/ref-monty/crates/monty/test_cases/type__int_conversion_error.py +0 -2
  896. package/ref-monty/crates/monty/test_cases/type__list_not_iterable.py +0 -2
  897. package/ref-monty/crates/monty/test_cases/type__non_builtin_name_error.py +0 -9
  898. package/ref-monty/crates/monty/test_cases/type__ops.py +0 -200
  899. package/ref-monty/crates/monty/test_cases/type__shadow_exc.py +0 -3
  900. package/ref-monty/crates/monty/test_cases/type__shadow_int.py +0 -9
  901. package/ref-monty/crates/monty/test_cases/type__shadow_len.py +0 -3
  902. package/ref-monty/crates/monty/test_cases/type__tuple_not_iterable.py +0 -2
  903. package/ref-monty/crates/monty/test_cases/type_error__int_add_list.py +0 -2
  904. package/ref-monty/crates/monty/test_cases/type_error__int_div_str.py +0 -2
  905. package/ref-monty/crates/monty/test_cases/type_error__int_floordiv_str.py +0 -2
  906. package/ref-monty/crates/monty/test_cases/type_error__int_iadd_str.py +0 -3
  907. package/ref-monty/crates/monty/test_cases/type_error__int_mod_str.py +0 -2
  908. package/ref-monty/crates/monty/test_cases/type_error__int_pow_str.py +0 -2
  909. package/ref-monty/crates/monty/test_cases/type_error__int_sub_str.py +0 -2
  910. package/ref-monty/crates/monty/test_cases/type_error__list_add_int.py +0 -2
  911. package/ref-monty/crates/monty/test_cases/type_error__list_add_str.py +0 -2
  912. package/ref-monty/crates/monty/test_cases/type_error__list_iadd_int.py +0 -6
  913. package/ref-monty/crates/monty/test_cases/type_error__str_add_int.py +0 -2
  914. package/ref-monty/crates/monty/test_cases/type_error__str_iadd_int.py +0 -3
  915. package/ref-monty/crates/monty/test_cases/type_error__unary_invert_str.py +0 -3
  916. package/ref-monty/crates/monty/test_cases/type_error__unary_minus_str.py +0 -4
  917. package/ref-monty/crates/monty/test_cases/type_error__unary_neg_str.py +0 -3
  918. package/ref-monty/crates/monty/test_cases/type_error__unary_plus_str.py +0 -4
  919. package/ref-monty/crates/monty/test_cases/typing__types.py +0 -24
  920. package/ref-monty/crates/monty/test_cases/unpack__nested.py +0 -48
  921. package/ref-monty/crates/monty/test_cases/unpack__non_sequence.py +0 -9
  922. package/ref-monty/crates/monty/test_cases/unpack__not_enough.py +0 -9
  923. package/ref-monty/crates/monty/test_cases/unpack__ops.py +0 -153
  924. package/ref-monty/crates/monty/test_cases/unpack__star_not_enough.py +0 -9
  925. package/ref-monty/crates/monty/test_cases/unpack__too_many.py +0 -9
  926. package/ref-monty/crates/monty/test_cases/version__cpython.py +0 -4
  927. package/ref-monty/crates/monty/test_cases/walrus__all.py +0 -178
  928. package/ref-monty/crates/monty/test_cases/while__all.py +0 -206
  929. package/ref-monty/crates/monty/tests/asyncio.rs +0 -764
  930. package/ref-monty/crates/monty/tests/binary_serde.rs +0 -185
  931. package/ref-monty/crates/monty/tests/bytecode_limits.rs +0 -248
  932. package/ref-monty/crates/monty/tests/datatest_runner.rs +0 -2029
  933. package/ref-monty/crates/monty/tests/inputs.rs +0 -420
  934. package/ref-monty/crates/monty/tests/json_serde.rs +0 -250
  935. package/ref-monty/crates/monty/tests/main.rs +0 -71
  936. package/ref-monty/crates/monty/tests/math_module.rs +0 -114
  937. package/ref-monty/crates/monty/tests/name_lookup.rs +0 -482
  938. package/ref-monty/crates/monty/tests/os_tests.rs +0 -459
  939. package/ref-monty/crates/monty/tests/parse_errors.rs +0 -441
  940. package/ref-monty/crates/monty/tests/print_writer.rs +0 -238
  941. package/ref-monty/crates/monty/tests/py_object.rs +0 -121
  942. package/ref-monty/crates/monty/tests/regex.rs +0 -90
  943. package/ref-monty/crates/monty/tests/repl.rs +0 -344
  944. package/ref-monty/crates/monty/tests/resource_limits.rs +0 -1826
  945. package/ref-monty/crates/monty/tests/try_from.rs +0 -167
  946. package/ref-monty/crates/monty-cli/Cargo.toml +0 -25
  947. package/ref-monty/crates/monty-cli/src/main.rs +0 -541
  948. package/ref-monty/crates/monty-js/.cargo/config.toml +0 -2
  949. package/ref-monty/crates/monty-js/.prettierignore +0 -8
  950. package/ref-monty/crates/monty-js/Cargo.toml +0 -32
  951. package/ref-monty/crates/monty-js/README.md +0 -207
  952. package/ref-monty/crates/monty-js/__test__/async.spec.ts +0 -350
  953. package/ref-monty/crates/monty-js/__test__/basic.spec.ts +0 -114
  954. package/ref-monty/crates/monty-js/__test__/exceptions.spec.ts +0 -427
  955. package/ref-monty/crates/monty-js/__test__/external.spec.ts +0 -354
  956. package/ref-monty/crates/monty-js/__test__/inputs.spec.ts +0 -143
  957. package/ref-monty/crates/monty-js/__test__/limits.spec.ts +0 -162
  958. package/ref-monty/crates/monty-js/__test__/package.json +0 -3
  959. package/ref-monty/crates/monty-js/__test__/print.spec.ts +0 -229
  960. package/ref-monty/crates/monty-js/__test__/repl.spec.ts +0 -34
  961. package/ref-monty/crates/monty-js/__test__/serialize.spec.ts +0 -205
  962. package/ref-monty/crates/monty-js/__test__/start.spec.ts +0 -443
  963. package/ref-monty/crates/monty-js/__test__/type_check.spec.ts +0 -147
  964. package/ref-monty/crates/monty-js/__test__/types.spec.ts +0 -319
  965. package/ref-monty/crates/monty-js/build.rs +0 -61
  966. package/ref-monty/crates/monty-js/index-header.d.ts +0 -3
  967. package/ref-monty/crates/monty-js/package-lock.json +0 -4694
  968. package/ref-monty/crates/monty-js/package.json +0 -100
  969. package/ref-monty/crates/monty-js/scripts/smoke-test.sh +0 -69
  970. package/ref-monty/crates/monty-js/smoke-test/package.json +0 -17
  971. package/ref-monty/crates/monty-js/smoke-test/test.ts +0 -171
  972. package/ref-monty/crates/monty-js/smoke-test/tsconfig.json +0 -11
  973. package/ref-monty/crates/monty-js/src/convert.rs +0 -648
  974. package/ref-monty/crates/monty-js/src/exceptions.rs +0 -293
  975. package/ref-monty/crates/monty-js/src/lib.rs +0 -41
  976. package/ref-monty/crates/monty-js/src/limits.rs +0 -53
  977. package/ref-monty/crates/monty-js/src/monty_cls.rs +0 -1407
  978. package/ref-monty/crates/monty-js/tsconfig.json +0 -17
  979. package/ref-monty/crates/monty-js/wrapper.ts +0 -701
  980. package/ref-monty/crates/monty-python/Cargo.toml +0 -38
  981. package/ref-monty/crates/monty-python/README.md +0 -134
  982. package/ref-monty/crates/monty-python/build.rs +0 -4
  983. package/ref-monty/crates/monty-python/example.py +0 -40
  984. package/ref-monty/crates/monty-python/exercise.py +0 -46
  985. package/ref-monty/crates/monty-python/pyproject.toml +0 -57
  986. package/ref-monty/crates/monty-python/python/pydantic_monty/__init__.py +0 -281
  987. package/ref-monty/crates/monty-python/python/pydantic_monty/_monty.pyi +0 -677
  988. package/ref-monty/crates/monty-python/python/pydantic_monty/os_access.py +0 -933
  989. package/ref-monty/crates/monty-python/python/pydantic_monty/py.typed +0 -0
  990. package/ref-monty/crates/monty-python/src/convert.rs +0 -273
  991. package/ref-monty/crates/monty-python/src/dataclass.rs +0 -461
  992. package/ref-monty/crates/monty-python/src/exceptions.rs +0 -557
  993. package/ref-monty/crates/monty-python/src/external.rs +0 -165
  994. package/ref-monty/crates/monty-python/src/lib.rs +0 -77
  995. package/ref-monty/crates/monty-python/src/limits.rs +0 -142
  996. package/ref-monty/crates/monty-python/src/monty_cls.rs +0 -1650
  997. package/ref-monty/crates/monty-python/src/repl.rs +0 -470
  998. package/ref-monty/crates/monty-python/src/serialization.rs +0 -761
  999. package/ref-monty/crates/monty-python/tests/test_async.py +0 -1201
  1000. package/ref-monty/crates/monty-python/tests/test_basic.py +0 -66
  1001. package/ref-monty/crates/monty-python/tests/test_dataclasses.py +0 -971
  1002. package/ref-monty/crates/monty-python/tests/test_exceptions.py +0 -361
  1003. package/ref-monty/crates/monty-python/tests/test_external.py +0 -367
  1004. package/ref-monty/crates/monty-python/tests/test_inputs.py +0 -126
  1005. package/ref-monty/crates/monty-python/tests/test_limits.py +0 -257
  1006. package/ref-monty/crates/monty-python/tests/test_os_access.py +0 -1286
  1007. package/ref-monty/crates/monty-python/tests/test_os_access_compat.py +0 -731
  1008. package/ref-monty/crates/monty-python/tests/test_os_access_raw.py +0 -483
  1009. package/ref-monty/crates/monty-python/tests/test_os_calls.py +0 -819
  1010. package/ref-monty/crates/monty-python/tests/test_print.py +0 -208
  1011. package/ref-monty/crates/monty-python/tests/test_re.py +0 -170
  1012. package/ref-monty/crates/monty-python/tests/test_readme_examples.py +0 -20
  1013. package/ref-monty/crates/monty-python/tests/test_repl.py +0 -749
  1014. package/ref-monty/crates/monty-python/tests/test_serialize.py +0 -284
  1015. package/ref-monty/crates/monty-python/tests/test_start.py +0 -346
  1016. package/ref-monty/crates/monty-python/tests/test_threading.py +0 -163
  1017. package/ref-monty/crates/monty-python/tests/test_type_check.py +0 -344
  1018. package/ref-monty/crates/monty-python/tests/test_types.py +0 -553
  1019. package/ref-monty/crates/monty-type-checking/Cargo.toml +0 -32
  1020. package/ref-monty/crates/monty-type-checking/src/db.rs +0 -116
  1021. package/ref-monty/crates/monty-type-checking/src/lib.rs +0 -4
  1022. package/ref-monty/crates/monty-type-checking/src/type_check.rs +0 -280
  1023. package/ref-monty/crates/monty-type-checking/tests/bad_types.py +0 -109
  1024. package/ref-monty/crates/monty-type-checking/tests/bad_types_output.txt +0 -21
  1025. package/ref-monty/crates/monty-type-checking/tests/good_types.py +0 -475
  1026. package/ref-monty/crates/monty-type-checking/tests/main.rs +0 -205
  1027. package/ref-monty/crates/monty-type-checking/tests/reveal_types.py +0 -56
  1028. package/ref-monty/crates/monty-type-checking/tests/reveal_types_output.txt +0 -41
  1029. package/ref-monty/crates/monty-typeshed/Cargo.toml +0 -29
  1030. package/ref-monty/crates/monty-typeshed/README.md +0 -11
  1031. package/ref-monty/crates/monty-typeshed/build.rs +0 -101
  1032. package/ref-monty/crates/monty-typeshed/custom/README.md +0 -1
  1033. package/ref-monty/crates/monty-typeshed/custom/asyncio.pyi +0 -138
  1034. package/ref-monty/crates/monty-typeshed/custom/os.pyi +0 -87
  1035. package/ref-monty/crates/monty-typeshed/custom/sys.pyi +0 -33
  1036. package/ref-monty/crates/monty-typeshed/src/lib.rs +0 -56
  1037. package/ref-monty/crates/monty-typeshed/update.py +0 -321
  1038. package/ref-monty/crates/monty-typeshed/vendor/typeshed/source_commit.txt +0 -1
  1039. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/VERSIONS +0 -20
  1040. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/_collections_abc.pyi +0 -105
  1041. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/_typeshed/__init__.pyi +0 -394
  1042. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/asyncio.pyi +0 -138
  1043. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/builtins.pyi +0 -1434
  1044. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/collections/__init__.pyi +0 -527
  1045. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/collections/abc.pyi +0 -2
  1046. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/dataclasses.pyi +0 -502
  1047. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/enum.pyi +0 -376
  1048. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/math.pyi +0 -149
  1049. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/os.pyi +0 -87
  1050. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/pathlib/__init__.pyi +0 -395
  1051. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/pathlib/types.pyi +0 -8
  1052. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/re.pyi +0 -337
  1053. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/sys.pyi +0 -33
  1054. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/types.pyi +0 -741
  1055. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/typing.pyi +0 -1217
  1056. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/typing_extensions.pyi +0 -716
  1057. package/ref-monty/docs/usage-guide.md +0 -117
  1058. package/ref-monty/examples/README.md +0 -3
  1059. package/ref-monty/examples/expense_analysis/README.md +0 -3
  1060. package/ref-monty/examples/expense_analysis/data.py +0 -124
  1061. package/ref-monty/examples/expense_analysis/main.py +0 -115
  1062. package/ref-monty/examples/sql_playground/README.md +0 -20
  1063. package/ref-monty/examples/sql_playground/external_functions.py +0 -129
  1064. package/ref-monty/examples/sql_playground/main.py +0 -81
  1065. package/ref-monty/examples/sql_playground/sandbox_code.py +0 -82
  1066. package/ref-monty/examples/sql_playground/type_stubs.pyi +0 -14
  1067. package/ref-monty/examples/web_scraper/README.md +0 -15
  1068. package/ref-monty/examples/web_scraper/browser.py +0 -56
  1069. package/ref-monty/examples/web_scraper/example_code.py +0 -59
  1070. package/ref-monty/examples/web_scraper/external_functions.py +0 -324
  1071. package/ref-monty/examples/web_scraper/main.py +0 -193
  1072. package/ref-monty/examples/web_scraper/sub_agent.py +0 -79
  1073. package/ref-monty/monty-npm.md +0 -235
  1074. package/ref-monty/pyproject.toml +0 -162
  1075. package/ref-monty/scripts/check_imports.py +0 -91
  1076. package/ref-monty/scripts/codecov_diff.py +0 -412
  1077. package/ref-monty/scripts/complete_tests.py +0 -146
  1078. package/ref-monty/scripts/flamegraph_to_text.py +0 -208
  1079. package/ref-monty/scripts/iter_test_methods.py +0 -540
  1080. package/ref-monty/scripts/run_traceback.py +0 -180
  1081. package/ref-monty/scripts/startup_performance.py +0 -130
  1082. package/ref-monty/uv.lock +0 -1779
  1083. package/temp_resend_cli/repo/.github/scripts/pr-title-check.js +0 -34
  1084. package/temp_resend_cli/repo/.github/workflows/ci.yml +0 -67
  1085. package/temp_resend_cli/repo/.github/workflows/post-release.yml +0 -51
  1086. package/temp_resend_cli/repo/.github/workflows/pr-title-check.yml +0 -13
  1087. package/temp_resend_cli/repo/.github/workflows/release.yml +0 -175
  1088. package/temp_resend_cli/repo/.github/workflows/test-install-unix.yml +0 -34
  1089. package/temp_resend_cli/repo/.github/workflows/test-install-windows.yml +0 -48
  1090. package/temp_resend_cli/repo/CHANGELOG.md +0 -31
  1091. package/temp_resend_cli/repo/LICENSE +0 -21
  1092. package/temp_resend_cli/repo/README.md +0 -450
  1093. package/temp_resend_cli/repo/biome.json +0 -36
  1094. package/temp_resend_cli/repo/install.ps1 +0 -141
  1095. package/temp_resend_cli/repo/install.sh +0 -301
  1096. package/temp_resend_cli/repo/package.json +0 -61
  1097. package/temp_resend_cli/repo/pnpm-lock.yaml +0 -2439
  1098. package/temp_resend_cli/repo/renovate.json +0 -4
  1099. package/temp_resend_cli/repo/src/cli.ts +0 -98
  1100. package/temp_resend_cli/repo/src/commands/api-keys/create.ts +0 -114
  1101. package/temp_resend_cli/repo/src/commands/api-keys/delete.ts +0 -47
  1102. package/temp_resend_cli/repo/src/commands/api-keys/index.ts +0 -26
  1103. package/temp_resend_cli/repo/src/commands/api-keys/list.ts +0 -35
  1104. package/temp_resend_cli/repo/src/commands/api-keys/utils.ts +0 -8
  1105. package/temp_resend_cli/repo/src/commands/auth/index.ts +0 -20
  1106. package/temp_resend_cli/repo/src/commands/auth/login.ts +0 -234
  1107. package/temp_resend_cli/repo/src/commands/auth/logout.ts +0 -105
  1108. package/temp_resend_cli/repo/src/commands/broadcasts/create.ts +0 -196
  1109. package/temp_resend_cli/repo/src/commands/broadcasts/delete.ts +0 -46
  1110. package/temp_resend_cli/repo/src/commands/broadcasts/get.ts +0 -59
  1111. package/temp_resend_cli/repo/src/commands/broadcasts/index.ts +0 -43
  1112. package/temp_resend_cli/repo/src/commands/broadcasts/list.ts +0 -60
  1113. package/temp_resend_cli/repo/src/commands/broadcasts/send.ts +0 -56
  1114. package/temp_resend_cli/repo/src/commands/broadcasts/update.ts +0 -95
  1115. package/temp_resend_cli/repo/src/commands/broadcasts/utils.ts +0 -35
  1116. package/temp_resend_cli/repo/src/commands/contact-properties/create.ts +0 -118
  1117. package/temp_resend_cli/repo/src/commands/contact-properties/delete.ts +0 -48
  1118. package/temp_resend_cli/repo/src/commands/contact-properties/get.ts +0 -46
  1119. package/temp_resend_cli/repo/src/commands/contact-properties/index.ts +0 -48
  1120. package/temp_resend_cli/repo/src/commands/contact-properties/list.ts +0 -68
  1121. package/temp_resend_cli/repo/src/commands/contact-properties/update.ts +0 -88
  1122. package/temp_resend_cli/repo/src/commands/contact-properties/utils.ts +0 -17
  1123. package/temp_resend_cli/repo/src/commands/contacts/add-segment.ts +0 -78
  1124. package/temp_resend_cli/repo/src/commands/contacts/create.ts +0 -122
  1125. package/temp_resend_cli/repo/src/commands/contacts/delete.ts +0 -49
  1126. package/temp_resend_cli/repo/src/commands/contacts/get.ts +0 -53
  1127. package/temp_resend_cli/repo/src/commands/contacts/index.ts +0 -58
  1128. package/temp_resend_cli/repo/src/commands/contacts/list.ts +0 -57
  1129. package/temp_resend_cli/repo/src/commands/contacts/remove-segment.ts +0 -48
  1130. package/temp_resend_cli/repo/src/commands/contacts/segments.ts +0 -39
  1131. package/temp_resend_cli/repo/src/commands/contacts/topics.ts +0 -45
  1132. package/temp_resend_cli/repo/src/commands/contacts/update-topics.ts +0 -90
  1133. package/temp_resend_cli/repo/src/commands/contacts/update.ts +0 -77
  1134. package/temp_resend_cli/repo/src/commands/contacts/utils.ts +0 -119
  1135. package/temp_resend_cli/repo/src/commands/doctor.ts +0 -216
  1136. package/temp_resend_cli/repo/src/commands/domains/create.ts +0 -83
  1137. package/temp_resend_cli/repo/src/commands/domains/delete.ts +0 -42
  1138. package/temp_resend_cli/repo/src/commands/domains/get.ts +0 -47
  1139. package/temp_resend_cli/repo/src/commands/domains/index.ts +0 -35
  1140. package/temp_resend_cli/repo/src/commands/domains/list.ts +0 -53
  1141. package/temp_resend_cli/repo/src/commands/domains/update.ts +0 -75
  1142. package/temp_resend_cli/repo/src/commands/domains/utils.ts +0 -44
  1143. package/temp_resend_cli/repo/src/commands/domains/verify.ts +0 -38
  1144. package/temp_resend_cli/repo/src/commands/emails/batch.ts +0 -140
  1145. package/temp_resend_cli/repo/src/commands/emails/get.ts +0 -44
  1146. package/temp_resend_cli/repo/src/commands/emails/index.ts +0 -30
  1147. package/temp_resend_cli/repo/src/commands/emails/list.ts +0 -84
  1148. package/temp_resend_cli/repo/src/commands/emails/receiving/attachment.ts +0 -55
  1149. package/temp_resend_cli/repo/src/commands/emails/receiving/attachments.ts +0 -68
  1150. package/temp_resend_cli/repo/src/commands/emails/receiving/get.ts +0 -58
  1151. package/temp_resend_cli/repo/src/commands/emails/receiving/index.ts +0 -28
  1152. package/temp_resend_cli/repo/src/commands/emails/receiving/list.ts +0 -59
  1153. package/temp_resend_cli/repo/src/commands/emails/receiving/utils.ts +0 -38
  1154. package/temp_resend_cli/repo/src/commands/emails/send.ts +0 -189
  1155. package/temp_resend_cli/repo/src/commands/open.ts +0 -27
  1156. package/temp_resend_cli/repo/src/commands/segments/create.ts +0 -50
  1157. package/temp_resend_cli/repo/src/commands/segments/delete.ts +0 -47
  1158. package/temp_resend_cli/repo/src/commands/segments/get.ts +0 -38
  1159. package/temp_resend_cli/repo/src/commands/segments/index.ts +0 -36
  1160. package/temp_resend_cli/repo/src/commands/segments/list.ts +0 -58
  1161. package/temp_resend_cli/repo/src/commands/segments/utils.ts +0 -7
  1162. package/temp_resend_cli/repo/src/commands/teams/index.ts +0 -10
  1163. package/temp_resend_cli/repo/src/commands/teams/list.ts +0 -35
  1164. package/temp_resend_cli/repo/src/commands/teams/remove.ts +0 -86
  1165. package/temp_resend_cli/repo/src/commands/teams/switch.ts +0 -76
  1166. package/temp_resend_cli/repo/src/commands/topics/create.ts +0 -73
  1167. package/temp_resend_cli/repo/src/commands/topics/delete.ts +0 -47
  1168. package/temp_resend_cli/repo/src/commands/topics/get.ts +0 -42
  1169. package/temp_resend_cli/repo/src/commands/topics/index.ts +0 -42
  1170. package/temp_resend_cli/repo/src/commands/topics/list.ts +0 -34
  1171. package/temp_resend_cli/repo/src/commands/topics/update.ts +0 -59
  1172. package/temp_resend_cli/repo/src/commands/topics/utils.ts +0 -16
  1173. package/temp_resend_cli/repo/src/commands/webhooks/create.ts +0 -128
  1174. package/temp_resend_cli/repo/src/commands/webhooks/delete.ts +0 -49
  1175. package/temp_resend_cli/repo/src/commands/webhooks/get.ts +0 -42
  1176. package/temp_resend_cli/repo/src/commands/webhooks/index.ts +0 -42
  1177. package/temp_resend_cli/repo/src/commands/webhooks/list.ts +0 -55
  1178. package/temp_resend_cli/repo/src/commands/webhooks/listen.ts +0 -379
  1179. package/temp_resend_cli/repo/src/commands/webhooks/update.ts +0 -83
  1180. package/temp_resend_cli/repo/src/commands/webhooks/utils.ts +0 -36
  1181. package/temp_resend_cli/repo/src/commands/whoami.ts +0 -71
  1182. package/temp_resend_cli/repo/src/lib/actions.ts +0 -157
  1183. package/temp_resend_cli/repo/src/lib/client.ts +0 -37
  1184. package/temp_resend_cli/repo/src/lib/config.ts +0 -217
  1185. package/temp_resend_cli/repo/src/lib/files.ts +0 -15
  1186. package/temp_resend_cli/repo/src/lib/help-text.ts +0 -38
  1187. package/temp_resend_cli/repo/src/lib/output.ts +0 -56
  1188. package/temp_resend_cli/repo/src/lib/pagination.ts +0 -36
  1189. package/temp_resend_cli/repo/src/lib/prompts.ts +0 -149
  1190. package/temp_resend_cli/repo/src/lib/spinner.ts +0 -100
  1191. package/temp_resend_cli/repo/src/lib/table.ts +0 -57
  1192. package/temp_resend_cli/repo/src/lib/tty.ts +0 -28
  1193. package/temp_resend_cli/repo/src/lib/update-check.ts +0 -169
  1194. package/temp_resend_cli/repo/src/lib/version.ts +0 -4
  1195. package/temp_resend_cli/repo/tests/commands/api-keys/create.test.ts +0 -196
  1196. package/temp_resend_cli/repo/tests/commands/api-keys/delete.test.ts +0 -157
  1197. package/temp_resend_cli/repo/tests/commands/api-keys/list.test.ts +0 -134
  1198. package/temp_resend_cli/repo/tests/commands/auth/login.test.ts +0 -153
  1199. package/temp_resend_cli/repo/tests/commands/auth/logout.test.ts +0 -153
  1200. package/temp_resend_cli/repo/tests/commands/broadcasts/create.test.ts +0 -454
  1201. package/temp_resend_cli/repo/tests/commands/broadcasts/delete.test.ts +0 -183
  1202. package/temp_resend_cli/repo/tests/commands/broadcasts/get.test.ts +0 -147
  1203. package/temp_resend_cli/repo/tests/commands/broadcasts/list.test.ts +0 -199
  1204. package/temp_resend_cli/repo/tests/commands/broadcasts/send.test.ts +0 -162
  1205. package/temp_resend_cli/repo/tests/commands/broadcasts/update.test.ts +0 -288
  1206. package/temp_resend_cli/repo/tests/commands/contact-properties/create.test.ts +0 -251
  1207. package/temp_resend_cli/repo/tests/commands/contact-properties/delete.test.ts +0 -184
  1208. package/temp_resend_cli/repo/tests/commands/contact-properties/get.test.ts +0 -145
  1209. package/temp_resend_cli/repo/tests/commands/contact-properties/list.test.ts +0 -181
  1210. package/temp_resend_cli/repo/tests/commands/contact-properties/update.test.ts +0 -217
  1211. package/temp_resend_cli/repo/tests/commands/contacts/add-segment.test.ts +0 -189
  1212. package/temp_resend_cli/repo/tests/commands/contacts/create.test.ts +0 -271
  1213. package/temp_resend_cli/repo/tests/commands/contacts/delete.test.ts +0 -193
  1214. package/temp_resend_cli/repo/tests/commands/contacts/get.test.ts +0 -149
  1215. package/temp_resend_cli/repo/tests/commands/contacts/list.test.ts +0 -176
  1216. package/temp_resend_cli/repo/tests/commands/contacts/remove-segment.test.ts +0 -167
  1217. package/temp_resend_cli/repo/tests/commands/contacts/segments.test.ts +0 -168
  1218. package/temp_resend_cli/repo/tests/commands/contacts/topics.test.ts +0 -164
  1219. package/temp_resend_cli/repo/tests/commands/contacts/update-topics.test.ts +0 -248
  1220. package/temp_resend_cli/repo/tests/commands/contacts/update.test.ts +0 -206
  1221. package/temp_resend_cli/repo/tests/commands/doctor.test.ts +0 -164
  1222. package/temp_resend_cli/repo/tests/commands/domains/create.test.ts +0 -193
  1223. package/temp_resend_cli/repo/tests/commands/domains/delete.test.ts +0 -157
  1224. package/temp_resend_cli/repo/tests/commands/domains/get.test.ts +0 -138
  1225. package/temp_resend_cli/repo/tests/commands/domains/list.test.ts +0 -165
  1226. package/temp_resend_cli/repo/tests/commands/domains/update.test.ts +0 -224
  1227. package/temp_resend_cli/repo/tests/commands/domains/verify.test.ts +0 -118
  1228. package/temp_resend_cli/repo/tests/commands/emails/batch.test.ts +0 -324
  1229. package/temp_resend_cli/repo/tests/commands/emails/get.test.ts +0 -132
  1230. package/temp_resend_cli/repo/tests/commands/emails/receiving/attachment.test.ts +0 -141
  1231. package/temp_resend_cli/repo/tests/commands/emails/receiving/attachments.test.ts +0 -169
  1232. package/temp_resend_cli/repo/tests/commands/emails/receiving/get.test.ts +0 -141
  1233. package/temp_resend_cli/repo/tests/commands/emails/receiving/list.test.ts +0 -182
  1234. package/temp_resend_cli/repo/tests/commands/emails/send.test.ts +0 -312
  1235. package/temp_resend_cli/repo/tests/commands/segments/create.test.ts +0 -164
  1236. package/temp_resend_cli/repo/tests/commands/segments/delete.test.ts +0 -183
  1237. package/temp_resend_cli/repo/tests/commands/segments/get.test.ts +0 -138
  1238. package/temp_resend_cli/repo/tests/commands/segments/list.test.ts +0 -174
  1239. package/temp_resend_cli/repo/tests/commands/teams/list.test.ts +0 -62
  1240. package/temp_resend_cli/repo/tests/commands/teams/remove.test.ts +0 -110
  1241. package/temp_resend_cli/repo/tests/commands/teams/switch.test.ts +0 -103
  1242. package/temp_resend_cli/repo/tests/commands/topics/create.test.ts +0 -192
  1243. package/temp_resend_cli/repo/tests/commands/topics/delete.test.ts +0 -157
  1244. package/temp_resend_cli/repo/tests/commands/topics/get.test.ts +0 -126
  1245. package/temp_resend_cli/repo/tests/commands/topics/list.test.ts +0 -125
  1246. package/temp_resend_cli/repo/tests/commands/topics/update.test.ts +0 -178
  1247. package/temp_resend_cli/repo/tests/commands/webhooks/create.test.ts +0 -225
  1248. package/temp_resend_cli/repo/tests/commands/webhooks/delete.test.ts +0 -157
  1249. package/temp_resend_cli/repo/tests/commands/webhooks/get.test.ts +0 -126
  1250. package/temp_resend_cli/repo/tests/commands/webhooks/list.test.ts +0 -178
  1251. package/temp_resend_cli/repo/tests/commands/webhooks/update.test.ts +0 -207
  1252. package/temp_resend_cli/repo/tests/commands/whoami.test.ts +0 -98
  1253. package/temp_resend_cli/repo/tests/e2e/smoke.test.ts +0 -93
  1254. package/temp_resend_cli/repo/tests/helpers.ts +0 -86
  1255. package/temp_resend_cli/repo/tests/lib/client.test.ts +0 -71
  1256. package/temp_resend_cli/repo/tests/lib/config.test.ts +0 -451
  1257. package/temp_resend_cli/repo/tests/lib/files.test.ts +0 -73
  1258. package/temp_resend_cli/repo/tests/lib/help-text.test.ts +0 -97
  1259. package/temp_resend_cli/repo/tests/lib/output.test.ts +0 -136
  1260. package/temp_resend_cli/repo/tests/lib/prompts.test.ts +0 -185
  1261. package/temp_resend_cli/repo/tests/lib/spinner.test.ts +0 -166
  1262. package/temp_resend_cli/repo/tests/lib/table.test.ts +0 -63
  1263. package/temp_resend_cli/repo/tests/lib/tty.test.ts +0 -89
  1264. package/temp_resend_cli/repo/tests/lib/update-check.test.ts +0 -179
  1265. package/temp_resend_cli/repo/tsconfig.json +0 -14
  1266. package/temp_resend_cli/repo/vitest.config.e2e.ts +0 -8
  1267. package/temp_resend_cli/repo/vitest.config.ts +0 -10
  1268. /package/docs/{plugin-examples.md → plugins-examples.md} +0 -0
@@ -1,2558 +0,0 @@
1
- use std::{
2
- borrow::Cow,
3
- cmp::Ordering,
4
- collections::hash_map::DefaultHasher,
5
- fmt::{self, Write},
6
- hash::{Hash, Hasher},
7
- mem::discriminant,
8
- str::FromStr,
9
- };
10
-
11
- use ahash::AHashSet;
12
- use num_bigint::BigInt;
13
- use num_integer::Integer;
14
- use num_traits::{ToPrimitive, Zero};
15
-
16
- use crate::{
17
- asyncio::CallId,
18
- builtins::Builtins,
19
- bytecode::{CallResult, VM},
20
- exception_private::{ExcType, RunError, RunResult, SimpleException},
21
- heap::{ContainsHeap, Heap, HeapData, HeapGuard, HeapId},
22
- heap_data::HeapDataMut,
23
- intern::{BytesId, FunctionId, Interns, LongIntId, StaticStrings, StringId},
24
- modules::ModuleFunctions,
25
- resource::{ResourceError, ResourceTracker, check_div_size, check_lshift_size, check_pow_size, check_repeat_size},
26
- types::{
27
- LongInt, Property, PyTrait, Str, Type,
28
- bytes::{bytes_repr_fmt, get_byte_at_index, get_bytes_slice},
29
- path,
30
- str::{allocate_char, get_char_at_index, get_str_slice, string_repr_fmt},
31
- },
32
- };
33
-
34
- /// Primary value type representing Python objects at runtime.
35
- ///
36
- /// This enum uses a hybrid design: small immediate values (Int, Bool, None) are stored
37
- /// inline, while heap-allocated values (List, Str, Dict, etc.) are stored in the arena
38
- /// and referenced via `Ref(HeapId)`.
39
- ///
40
- /// NOTE: `Clone` is intentionally NOT derived. Use `clone_with_heap()` for heap values
41
- /// or `clone_immediate()` for immediate values only. Direct cloning via `.clone()` would
42
- /// bypass reference counting and cause memory leaks.
43
- ///
44
- /// NOTE: it's important to keep this size small to minimize memory overhead!
45
- #[derive(Debug, serde::Serialize, serde::Deserialize)]
46
- pub(crate) enum Value {
47
- // Immediate values (stored inline, no heap allocation)
48
- Undefined,
49
- Ellipsis,
50
- None,
51
- Bool(bool),
52
- Int(i64),
53
- Float(f64),
54
- /// An interned string literal. The StringId references the string in the Interns table.
55
- /// To get the actual string content, use `interns.get(string_id)`.
56
- InternString(StringId),
57
- /// An interned bytes literal. The BytesId references the bytes in the Interns table.
58
- /// To get the actual bytes content, use `interns.get_bytes(bytes_id)`.
59
- InternBytes(BytesId),
60
- /// An interned long integer literal. The `LongIntId` references the `BigInt` in the Interns table.
61
- /// Used for integer literals exceeding i64 range. Converted to heap-allocated `LongInt` on load.
62
- InternLongInt(LongIntId),
63
- /// A builtin function or exception type
64
- Builtin(Builtins),
65
- /// A function from a module (not a global builtin).
66
- /// Module functions require importing a module to access (e.g., `asyncio.gather`).
67
- ModuleFunction(ModuleFunctions),
68
- /// A function defined in the module (not a closure, doesn't capture any variables)
69
- DefFunction(FunctionId),
70
- /// Reference to an external function defined on the host.
71
- ///
72
- /// The `StringId` stores the interned function name. When called, the VM yields
73
- /// a `FrameExit::ExternalCall` with this `StringId` so the host can look up and
74
- /// execute the function by name.
75
- ExtFunction(StringId),
76
- /// A marker value representing special objects like sys.stdout/stderr.
77
- /// These exist but have minimal functionality in the sandboxed environment.
78
- Marker(Marker),
79
- /// A property descriptor that computes its value when accessed.
80
- /// When retrieved via `py_getattr`, the property's getter is invoked.
81
- Property(Property),
82
- /// A pending external function call result.
83
- ///
84
- /// Created when the host calls `run_pending()` instead of `run(result)` for an
85
- /// external function call. The CallId correlates with the call that created it.
86
- /// When awaited, blocks the task until the host provides a result via `resume()`.
87
- ///
88
- /// ExternalFutures follow single-shot semantics like coroutines - awaiting an
89
- /// already-awaited ExternalFuture raises RuntimeError.
90
- ExternalFuture(CallId),
91
-
92
- // Heap-allocated values (stored in arena)
93
- Ref(HeapId),
94
-
95
- /// Sentinel value indicating this Value was properly cleaned up via `drop_with_heap`.
96
- /// Only exists when `ref-count-panic` feature is enabled. Used to verify reference counting
97
- /// correctness - if a `Ref` variant is dropped without calling `drop_with_heap`, the
98
- /// Drop impl will panic.
99
- #[cfg(feature = "ref-count-panic")]
100
- Dereferenced,
101
- }
102
-
103
- /// Drop implementation that panics if a `Ref` variant is dropped without calling `drop_with_heap`.
104
- /// This helps catch reference counting bugs during development/testing.
105
- /// Only enabled when the `ref-count-panic` feature is active.
106
- #[cfg(feature = "ref-count-panic")]
107
- impl Drop for Value {
108
- fn drop(&mut self) {
109
- if let Self::Ref(id) = self {
110
- panic!("Value::Ref({id:?}) dropped without calling drop_with_heap() - this is a reference counting bug");
111
- }
112
- }
113
- }
114
-
115
- impl From<bool> for Value {
116
- fn from(v: bool) -> Self {
117
- Self::Bool(v)
118
- }
119
- }
120
-
121
- impl PyTrait for Value {
122
- fn py_type(&self, heap: &Heap<impl ResourceTracker>) -> Type {
123
- match self {
124
- Self::Undefined => panic!("Cannot get type of undefined value"),
125
- Self::Ellipsis => Type::Ellipsis,
126
- Self::None => Type::NoneType,
127
- Self::Bool(_) => Type::Bool,
128
- Self::Int(_) | Self::InternLongInt(_) => Type::Int,
129
- Self::Float(_) => Type::Float,
130
- Self::InternString(_) => Type::Str,
131
- Self::InternBytes(_) => Type::Bytes,
132
- Self::Builtin(c) => c.py_type(),
133
- Self::ModuleFunction(_) => Type::BuiltinFunction,
134
- Self::DefFunction(_) | Self::ExtFunction(_) => Type::Function,
135
- Self::Marker(m) => m.py_type(),
136
- Self::Property(_) => Type::Property,
137
- Self::ExternalFuture(_) => Type::Coroutine,
138
- Self::Ref(id) => heap.get(*id).py_type(heap),
139
- #[cfg(feature = "ref-count-panic")]
140
- Self::Dereferenced => panic!("Cannot access Dereferenced object"),
141
- }
142
- }
143
-
144
- /// Returns 0 for Value since immediate values are stack-allocated.
145
- ///
146
- /// Heap-allocated values (Ref variants) have their size tracked when
147
- /// the HeapData is allocated, not here.
148
- fn py_estimate_size(&self) -> usize {
149
- // Value is stack-allocated; heap data is sized separately when allocated
150
- 0
151
- }
152
-
153
- fn py_len(&self, vm: &VM<'_, '_, impl ResourceTracker>) -> Option<usize> {
154
- match self {
155
- // Count Unicode characters, not bytes, to match Python semantics
156
- Self::InternString(string_id) => Some(vm.interns.get_str(*string_id).chars().count()),
157
- Self::InternBytes(bytes_id) => Some(vm.interns.get_bytes(*bytes_id).len()),
158
- Self::Ref(id) => vm.heap.get(*id).py_len(vm),
159
- _ => None,
160
- }
161
- }
162
-
163
- fn py_eq(&self, other: &Self, vm: &mut VM<'_, '_, impl ResourceTracker>) -> Result<bool, ResourceError> {
164
- let interns = vm.interns;
165
- match (self, other) {
166
- (Self::Undefined, _) => Ok(false),
167
- (_, Self::Undefined) => Ok(false),
168
- (Self::Int(v1), Self::Int(v2)) => Ok(v1 == v2),
169
- (Self::Bool(v1), Self::Bool(v2)) => Ok(v1 == v2),
170
- (Self::Bool(v1), Self::Int(v2)) => Ok(i64::from(*v1) == *v2),
171
- (Self::Int(v1), Self::Bool(v2)) => Ok(*v1 == i64::from(*v2)),
172
- (Self::Float(v1), Self::Float(v2)) => Ok(v1 == v2),
173
- (Self::Int(v1), Self::Float(v2)) => Ok((*v1 as f64) == *v2),
174
- (Self::Float(v1), Self::Int(v2)) => Ok(*v1 == (*v2 as f64)),
175
- (Self::Bool(v1), Self::Float(v2)) => Ok((i64::from(*v1) as f64) == *v2),
176
- (Self::Float(v1), Self::Bool(v2)) => Ok(*v1 == (i64::from(*v2) as f64)),
177
- (Self::None, Self::None) => Ok(true),
178
-
179
- // Int == LongInt comparison
180
- (Self::Int(a), Self::Ref(id)) => {
181
- if let HeapData::LongInt(li) = vm.heap.get(*id) {
182
- Ok(BigInt::from(*a) == *li.inner())
183
- } else {
184
- Ok(false)
185
- }
186
- }
187
- // LongInt == Int comparison
188
- (Self::Ref(id), Self::Int(b)) => {
189
- if let HeapData::LongInt(li) = vm.heap.get(*id) {
190
- Ok(*li.inner() == BigInt::from(*b))
191
- } else {
192
- Ok(false)
193
- }
194
- }
195
-
196
- // For interned interns, compare by StringId first (fast path for same interned string)
197
- (Self::InternString(s1), Self::InternString(s2)) => Ok(s1 == s2),
198
- // for strings we need to account for the fact they might be either interned or not
199
- (Self::InternString(string_id), Self::Ref(id2)) => {
200
- if let HeapData::Str(s2) = vm.heap.get(*id2) {
201
- Ok(interns.get_str(*string_id) == s2.as_str())
202
- } else {
203
- Ok(false)
204
- }
205
- }
206
- (Self::Ref(id1), Self::InternString(string_id)) => {
207
- if let HeapData::Str(s1) = vm.heap.get(*id1) {
208
- Ok(s1.as_str() == interns.get_str(*string_id))
209
- } else {
210
- Ok(false)
211
- }
212
- }
213
-
214
- // For interned bytes, compare by content (bytes are not deduplicated unlike interns)
215
- (Self::InternBytes(b1), Self::InternBytes(b2)) => {
216
- // Fast path: same BytesId means same content
217
- Ok(b1 == b2 || interns.get_bytes(*b1) == interns.get_bytes(*b2))
218
- }
219
- // same for bytes
220
- (Self::InternBytes(bytes_id), Self::Ref(id2)) => {
221
- if let HeapData::Bytes(b2) = vm.heap.get(*id2) {
222
- Ok(interns.get_bytes(*bytes_id) == b2.as_slice())
223
- } else {
224
- Ok(false)
225
- }
226
- }
227
- (Self::Ref(id1), Self::InternBytes(bytes_id)) => {
228
- if let HeapData::Bytes(b1) = vm.heap.get(*id1) {
229
- Ok(b1.as_slice() == interns.get_bytes(*bytes_id))
230
- } else {
231
- Ok(false)
232
- }
233
- }
234
-
235
- (Self::Ref(id1), Self::Ref(id2)) => {
236
- if *id1 == *id2 {
237
- return Ok(true);
238
- }
239
- Heap::with_two(vm, *id1, *id2, |vm, left, right| left.py_eq(right, vm))
240
- }
241
-
242
- // Builtins equality - just check the enums are equal
243
- (Self::Builtin(b1), Self::Builtin(b2)) => Ok(b1 == b2),
244
- // Module functions equality
245
- (Self::ModuleFunction(mf1), Self::ModuleFunction(mf2)) => Ok(mf1 == mf2),
246
- (Self::DefFunction(f1), Self::DefFunction(f2)) => Ok(f1 == f2),
247
- // Markers compare equal if they're the same variant
248
- (Self::Marker(m1), Self::Marker(m2)) => Ok(m1 == m2),
249
- // Properties compare equal if they're the same variant
250
- (Self::Property(p1), Self::Property(p2)) => Ok(p1 == p2),
251
-
252
- _ => Ok(false),
253
- }
254
- }
255
-
256
- fn py_cmp(
257
- &self,
258
- other: &Self,
259
- vm: &mut VM<'_, '_, impl ResourceTracker>,
260
- ) -> Result<Option<Ordering>, ResourceError> {
261
- let interns = vm.interns;
262
- // py_cmp handles numbers, strings, bytes, and tuples.
263
- // Recursion depth tracking for tuples is handled in Tuple::py_cmp.
264
- match (self, other) {
265
- (Self::Int(s), Self::Int(o)) => Ok(s.partial_cmp(o)),
266
- (Self::Float(s), Self::Float(o)) => Ok(s.partial_cmp(o)),
267
- (Self::Int(s), Self::Float(o)) => Ok((*s as f64).partial_cmp(o)),
268
- (Self::Float(s), Self::Int(o)) => Ok(s.partial_cmp(&(*o as f64))),
269
- // Bool promotion: convert to Int and re-dispatch. Recursion is bounded
270
- // to at most 2 levels (Bool→Int, then Int matches directly above).
271
- (Self::Bool(s), _) => Self::Int(i64::from(*s)).py_cmp(other, vm),
272
- (_, Self::Bool(s)) => self.py_cmp(&Self::Int(i64::from(*s)), vm),
273
- // Int vs LongInt comparison
274
- (Self::Int(a), Self::Ref(id)) => {
275
- if let HeapData::LongInt(li) = vm.heap.get(*id) {
276
- Ok(BigInt::from(*a).partial_cmp(li.inner()))
277
- } else {
278
- Ok(None)
279
- }
280
- }
281
- // LongInt vs Int comparison
282
- (Self::Ref(id), Self::Int(b)) => {
283
- if let HeapData::LongInt(li) = vm.heap.get(*id) {
284
- Ok(li.inner().partial_cmp(&BigInt::from(*b)))
285
- } else {
286
- Ok(None)
287
- }
288
- }
289
- // Ref vs Ref comparison: handles LongInt, Str, and Tuple
290
- (Self::Ref(id1), Self::Ref(id2)) => match (vm.heap.get(*id1), vm.heap.get(*id2)) {
291
- (HeapData::LongInt(a), HeapData::LongInt(b)) => Ok(a.inner().partial_cmp(b.inner())),
292
- (HeapData::Str(a), HeapData::Str(b)) => Ok(a.as_str().partial_cmp(b.as_str())),
293
- (HeapData::Tuple(_), HeapData::Tuple(_)) => {
294
- Heap::with_two(vm, *id1, *id2, |vm, left, right| left.py_cmp(right, vm))
295
- }
296
- _ => Ok(None),
297
- },
298
- // Interned string comparisons
299
- (Self::InternString(s1), Self::InternString(s2)) => {
300
- Ok(interns.get_str(*s1).partial_cmp(interns.get_str(*s2)))
301
- }
302
- // Cross-type string comparisons: interned vs heap-allocated
303
- (Self::InternString(s1), Self::Ref(id2)) => {
304
- if let HeapData::Str(s2) = vm.heap.get(*id2) {
305
- Ok(interns.get_str(*s1).partial_cmp(s2.as_str()))
306
- } else {
307
- Ok(None)
308
- }
309
- }
310
- (Self::Ref(id1), Self::InternString(s2)) => {
311
- if let HeapData::Str(s1) = vm.heap.get(*id1) {
312
- Ok(s1.as_str().partial_cmp(interns.get_str(*s2)))
313
- } else {
314
- Ok(None)
315
- }
316
- }
317
- (Self::InternBytes(b1), Self::InternBytes(b2)) => {
318
- Ok(interns.get_bytes(*b1).partial_cmp(interns.get_bytes(*b2)))
319
- }
320
- _ => Ok(None),
321
- }
322
- }
323
-
324
- fn py_dec_ref_ids(&mut self, stack: &mut Vec<HeapId>) {
325
- if let Self::Ref(id) = self {
326
- stack.push(*id);
327
- // Mark as Dereferenced to prevent Drop panic
328
- #[cfg(feature = "ref-count-panic")]
329
- self.dec_ref_forget();
330
- }
331
- }
332
-
333
- fn py_bool(&self, vm: &VM<'_, '_, impl ResourceTracker>) -> bool {
334
- match self {
335
- Self::Undefined => false,
336
- Self::Ellipsis => true,
337
- Self::None => false,
338
- Self::Bool(b) => *b,
339
- Self::Int(v) => *v != 0,
340
- Self::Float(f) => *f != 0.0,
341
- // InternLongInt is always truthy (if it were zero, it would fit in i64)
342
- Self::InternLongInt(_) => true,
343
- Self::Builtin(_) | Self::ModuleFunction(_) => true, // Builtins are always truthy
344
- Self::DefFunction(_) | Self::ExtFunction(_) => true, // Functions are always truthy
345
- Self::Marker(_) => true, // Markers are always truthy
346
- Self::Property(_) => true, // Properties are always truthy
347
- Self::ExternalFuture(_) => true, // ExternalFutures are always truthy
348
- Self::InternString(string_id) => !vm.interns.get_str(*string_id).is_empty(),
349
- Self::InternBytes(bytes_id) => !vm.interns.get_bytes(*bytes_id).is_empty(),
350
- Self::Ref(id) => vm.heap.get(*id).py_bool(vm),
351
- #[cfg(feature = "ref-count-panic")]
352
- Self::Dereferenced => panic!("Cannot access Dereferenced object"),
353
- }
354
- }
355
-
356
- fn py_repr_fmt(
357
- &self,
358
- f: &mut impl Write,
359
- vm: &VM<'_, '_, impl ResourceTracker>,
360
- heap_ids: &mut AHashSet<HeapId>,
361
- ) -> std::fmt::Result {
362
- let interns = vm.interns;
363
- match self {
364
- Self::Undefined => f.write_str("Undefined"),
365
- Self::Ellipsis => f.write_str("Ellipsis"),
366
- Self::None => f.write_str("None"),
367
- Self::Bool(true) => f.write_str("True"),
368
- Self::Bool(false) => f.write_str("False"),
369
- Self::Int(v) => write!(f, "{v}"),
370
- Self::InternLongInt(long_int_id) => write!(f, "{}", interns.get_long_int(*long_int_id)),
371
- Self::Float(v) => {
372
- let s = v.to_string();
373
- if s.contains('.') {
374
- f.write_str(&s)
375
- } else {
376
- write!(f, "{s}.0")
377
- }
378
- }
379
- Self::Builtin(b) => b.py_repr_fmt(f),
380
- Self::ModuleFunction(mf) => mf.py_repr_fmt(f, self.id()),
381
- Self::DefFunction(f_id) => interns.get_function(*f_id).py_repr_fmt(f, interns, self.id()),
382
- Self::ExtFunction(name_id) => {
383
- write!(f, "<function '{}' external>", interns.get_str(*name_id))
384
- }
385
- Self::InternString(string_id) => string_repr_fmt(interns.get_str(*string_id), f),
386
- Self::InternBytes(bytes_id) => bytes_repr_fmt(interns.get_bytes(*bytes_id), f),
387
- Self::Marker(m) => m.py_repr_fmt(f),
388
- Self::Property(p) => write!(f, "<property {p:?}>"),
389
- Self::ExternalFuture(call_id) => write!(f, "<coroutine external_future({})>", call_id.raw()),
390
- Self::Ref(id) => {
391
- if heap_ids.contains(id) {
392
- // Cycle detected - write type-specific placeholder following Python semantics
393
- match vm.heap.get(*id) {
394
- HeapData::List(_) => f.write_str("[...]"),
395
- HeapData::Tuple(_) => f.write_str("(...)"),
396
- HeapData::Dict(_) => f.write_str("{...}"),
397
- // Other types don't typically have cycles, but handle gracefully
398
- _ => f.write_str("..."),
399
- }
400
- } else {
401
- heap_ids.insert(*id);
402
- let result = vm.heap.get(*id).py_repr_fmt(f, vm, heap_ids);
403
- heap_ids.remove(id);
404
- result
405
- }
406
- }
407
- #[cfg(feature = "ref-count-panic")]
408
- Self::Dereferenced => panic!("Cannot access Dereferenced object"),
409
- }
410
- }
411
-
412
- fn py_str(&self, vm: &VM<'_, '_, impl ResourceTracker>) -> Cow<'static, str> {
413
- match self {
414
- Self::InternString(string_id) => vm.interns.get_str(*string_id).to_owned().into(),
415
- Self::Ref(id) => vm.heap.get(*id).py_str(vm),
416
- _ => self.py_repr(vm),
417
- }
418
- }
419
-
420
- fn py_add(
421
- &self,
422
- other: &Self,
423
- vm: &mut VM<'_, '_, impl ResourceTracker>,
424
- ) -> Result<Option<Value>, crate::resource::ResourceError> {
425
- let interns = vm.interns;
426
- match (self, other) {
427
- // Int + Int with overflow detection
428
- (Self::Int(a), Self::Int(b)) => {
429
- if let Some(result) = a.checked_add(*b) {
430
- Ok(Some(Self::Int(result)))
431
- } else {
432
- // Overflow - promote to LongInt
433
- let li = LongInt::from(*a) + LongInt::from(*b);
434
- li.into_value(vm.heap).map(Some)
435
- }
436
- }
437
- // Int + LongInt
438
- (Self::Int(i), Self::Ref(id)) | (Self::Ref(id), Self::Int(i)) => {
439
- if let HeapData::LongInt(li) = vm.heap.get(*id) {
440
- let result = LongInt::new(li.inner() + i);
441
- result.into_value(vm.heap).map(Some)
442
- } else {
443
- Ok(None)
444
- }
445
- }
446
- (Self::Float(v1), Self::Float(v2)) => Ok(Some(Self::Float(v1 + v2))),
447
- // Int + Float and Float + Int
448
- (Self::Int(a), Self::Float(b)) => Ok(Some(Self::Float(*a as f64 + b))),
449
- (Self::Float(a), Self::Int(b)) => Ok(Some(Self::Float(a + *b as f64))),
450
- (Self::Ref(id1), Self::Ref(id2)) => {
451
- Heap::with_two(vm, *id1, *id2, |vm, left, right| left.py_add(right, vm))
452
- }
453
- (Self::InternString(s1), Self::InternString(s2)) => {
454
- let concat = format!("{}{}", interns.get_str(*s1), interns.get_str(*s2));
455
- Ok(Some(Self::Ref(vm.heap.allocate(HeapData::Str(concat.into()))?)))
456
- }
457
- // for strings we need to account for the fact they might be either interned or not
458
- (Self::InternString(string_id), Self::Ref(id2)) => {
459
- if let HeapData::Str(s2) = vm.heap.get(*id2) {
460
- let concat = format!("{}{}", interns.get_str(*string_id), s2.as_str());
461
- Ok(Some(Self::Ref(vm.heap.allocate(HeapData::Str(concat.into()))?)))
462
- } else {
463
- Ok(None)
464
- }
465
- }
466
- (Self::Ref(id1), Self::InternString(string_id)) => {
467
- if let HeapData::Str(s1) = vm.heap.get(*id1) {
468
- let concat = format!("{}{}", s1.as_str(), interns.get_str(*string_id));
469
- Ok(Some(Self::Ref(vm.heap.allocate(HeapData::Str(concat.into()))?)))
470
- } else {
471
- Ok(None)
472
- }
473
- }
474
- // same for bytes
475
- (Self::InternBytes(b1), Self::InternBytes(b2)) => {
476
- let bytes1 = interns.get_bytes(*b1);
477
- let bytes2 = interns.get_bytes(*b2);
478
- let mut b = Vec::with_capacity(bytes1.len() + bytes2.len());
479
- b.extend_from_slice(bytes1);
480
- b.extend_from_slice(bytes2);
481
- Ok(Some(Self::Ref(vm.heap.allocate(HeapData::Bytes(b.into()))?)))
482
- }
483
- (Self::InternBytes(bytes_id), Self::Ref(id2)) => {
484
- if let HeapData::Bytes(b2) = vm.heap.get(*id2) {
485
- let bytes1 = interns.get_bytes(*bytes_id);
486
- let mut b = Vec::with_capacity(bytes1.len() + b2.len());
487
- b.extend_from_slice(bytes1);
488
- b.extend_from_slice(b2);
489
- Ok(Some(Self::Ref(vm.heap.allocate(HeapData::Bytes(b.into()))?)))
490
- } else {
491
- Ok(None)
492
- }
493
- }
494
- (Self::Ref(id1), Self::InternBytes(bytes_id)) => {
495
- if let HeapData::Bytes(b1) = vm.heap.get(*id1) {
496
- let bytes2 = interns.get_bytes(*bytes_id);
497
- let mut b = Vec::with_capacity(b1.len() + bytes2.len());
498
- b.extend_from_slice(b1);
499
- b.extend_from_slice(bytes2);
500
- Ok(Some(Self::Ref(vm.heap.allocate(HeapData::Bytes(b.into()))?)))
501
- } else {
502
- Ok(None)
503
- }
504
- }
505
- _ => Ok(None),
506
- }
507
- }
508
-
509
- fn py_sub(
510
- &self,
511
- other: &Self,
512
- vm: &mut VM<'_, '_, impl ResourceTracker>,
513
- ) -> Result<Option<Self>, crate::resource::ResourceError> {
514
- match (self, other) {
515
- // Int - Int with overflow detection
516
- (Self::Int(a), Self::Int(b)) => {
517
- if let Some(result) = a.checked_sub(*b) {
518
- Ok(Some(Self::Int(result)))
519
- } else {
520
- // Overflow - promote to LongInt
521
- let li = LongInt::from(*a) - LongInt::from(*b);
522
- li.into_value(vm.heap).map(Some)
523
- }
524
- }
525
- // Int - LongInt
526
- (Self::Int(a), Self::Ref(id)) => {
527
- if let HeapData::LongInt(li) = vm.heap.get(*id) {
528
- let result = LongInt::from(*a) - LongInt::new(li.inner().clone());
529
- result.into_value(vm.heap).map(Some)
530
- } else {
531
- Ok(None)
532
- }
533
- }
534
- // LongInt - Int
535
- (Self::Ref(id), Self::Int(b)) => {
536
- if let HeapData::LongInt(li) = vm.heap.get(*id) {
537
- let result = LongInt::new(li.inner().clone()) - LongInt::from(*b);
538
- result.into_value(vm.heap).map(Some)
539
- } else {
540
- Ok(None)
541
- }
542
- }
543
- // LongInt - LongInt
544
- (Self::Ref(id1), Self::Ref(id2)) => {
545
- Heap::with_two(vm, *id1, *id2, |vm, left, right| left.py_sub(right, vm))
546
- }
547
- // Float - Float
548
- (Self::Float(a), Self::Float(b)) => Ok(Some(Self::Float(a - b))),
549
- // Int - Float and Float - Int
550
- (Self::Int(a), Self::Float(b)) => Ok(Some(Self::Float(*a as f64 - b))),
551
- (Self::Float(a), Self::Int(b)) => Ok(Some(Self::Float(a - *b as f64))),
552
- _ => Ok(None),
553
- }
554
- }
555
-
556
- fn py_mod(&self, other: &Self, vm: &mut VM<'_, '_, impl ResourceTracker>) -> RunResult<Option<Self>> {
557
- match (self, other) {
558
- (Self::Int(a), Self::Int(b)) => {
559
- if *b == 0 {
560
- Err(ExcType::zero_division().into())
561
- } else if let Some(r) = a.checked_rem(*b) {
562
- // Python modulo: result has the same sign as divisor (b)
563
- let result = if r != 0 && (*a < 0) != (*b < 0) { r + *b } else { r };
564
- Ok(Some(Self::Int(result)))
565
- } else {
566
- // Overflow - i64::MIN % -1 is 0
567
- Ok(Some(Self::Int(0)))
568
- }
569
- }
570
- // Int % LongInt
571
- (Self::Int(a), Self::Ref(id)) => {
572
- // Clone to avoid borrow conflict with heap mutation
573
- let b_clone = if let HeapData::LongInt(li) = vm.heap.get(*id) {
574
- if li.is_zero() {
575
- return Err(ExcType::zero_division().into());
576
- }
577
- li.inner().clone()
578
- } else {
579
- return Ok(None);
580
- };
581
- let bi = BigInt::from(*a).mod_floor(&b_clone);
582
- Ok(Some(LongInt::new(bi).into_value(vm.heap)?))
583
- }
584
- // LongInt % Int
585
- (Self::Ref(id), Self::Int(b)) => {
586
- if *b == 0 {
587
- return Err(ExcType::zero_division().into());
588
- }
589
- // Clone to avoid borrow conflict with heap mutation
590
- let a_clone = if let HeapData::LongInt(li) = vm.heap.get(*id) {
591
- li.inner().clone()
592
- } else {
593
- return Ok(None);
594
- };
595
- let bi = a_clone.mod_floor(&BigInt::from(*b));
596
- Ok(Some(LongInt::new(bi).into_value(vm.heap)?))
597
- }
598
- // LongInt % LongInt
599
- (Self::Ref(id1), Self::Ref(id2)) => {
600
- Heap::with_two(vm, *id1, *id2, |vm, left, right| left.py_mod(right, vm))
601
- }
602
- (Self::Float(v1), Self::Float(v2)) => {
603
- if *v2 == 0.0 {
604
- Err(ExcType::zero_division().into())
605
- } else {
606
- Ok(Some(Self::Float(v1 % v2)))
607
- }
608
- }
609
- (Self::Float(v1), Self::Int(v2)) => {
610
- if *v2 == 0 {
611
- Err(ExcType::zero_division().into())
612
- } else {
613
- Ok(Some(Self::Float(v1 % (*v2 as f64))))
614
- }
615
- }
616
- (Self::Int(v1), Self::Float(v2)) => {
617
- if *v2 == 0.0 {
618
- Err(ExcType::zero_division().into())
619
- } else {
620
- Ok(Some(Self::Float((*v1 as f64) % v2)))
621
- }
622
- }
623
- _ => Ok(None),
624
- }
625
- }
626
-
627
- fn py_mod_eq(&self, other: &Self, right_value: i64) -> Option<bool> {
628
- match (self, other) {
629
- (Self::Int(v1), Self::Int(v2)) => {
630
- if let Some(r) = v1.checked_rem(*v2) {
631
- // Python modulo: result has same sign as divisor
632
- let result = if r != 0 && (*v1 < 0) != (*v2 < 0) { r + *v2 } else { r };
633
- Some(result == right_value)
634
- } else {
635
- // checked_rem returns None for overflow (i64::MIN % -1) or zero division
636
- (*v2 != 0).then_some(0 == right_value)
637
- }
638
- }
639
- (Self::Float(v1), Self::Float(v2)) => Some(v1 % v2 == right_value as f64),
640
- (Self::Float(v1), Self::Int(v2)) => Some(v1 % (*v2 as f64) == right_value as f64),
641
- (Self::Int(v1), Self::Float(v2)) => Some((*v1 as f64) % v2 == right_value as f64),
642
- _ => None,
643
- }
644
- }
645
-
646
- fn py_iadd(
647
- &mut self,
648
- other: &Self,
649
- vm: &mut VM<'_, '_, impl ResourceTracker>,
650
- _self_id: Option<HeapId>,
651
- ) -> Result<bool, crate::resource::ResourceError> {
652
- let interns = vm.interns;
653
- match (&self, other) {
654
- (Self::Int(v1), Self::Int(v2)) => {
655
- if let Some(result) = v1.checked_add(*v2) {
656
- *self = Self::Int(result);
657
- } else {
658
- // Overflow - promote to LongInt
659
- let li = LongInt::from(*v1) + LongInt::from(*v2);
660
- *self = li.into_value(vm.heap)?;
661
- }
662
- Ok(true)
663
- }
664
- (Self::Float(v1), Self::Float(v2)) => {
665
- *self = Self::Float(*v1 + *v2);
666
- Ok(true)
667
- }
668
- (Self::InternString(s1), Self::InternString(s2)) => {
669
- let concat = format!("{}{}", interns.get_str(*s1), interns.get_str(*s2));
670
- *self = Self::Ref(vm.heap.allocate(HeapData::Str(concat.into()))?);
671
- Ok(true)
672
- }
673
- (Self::InternString(string_id), Self::Ref(id2)) => {
674
- let result = if let HeapData::Str(s2) = vm.heap.get(*id2) {
675
- let concat = format!("{}{}", interns.get_str(*string_id), s2.as_str());
676
- *self = Self::Ref(vm.heap.allocate(HeapData::Str(concat.into()))?);
677
- true
678
- } else {
679
- false
680
- };
681
- Ok(result)
682
- }
683
- // same for bytes
684
- (Self::InternBytes(b1), Self::InternBytes(b2)) => {
685
- let bytes1 = interns.get_bytes(*b1);
686
- let bytes2 = interns.get_bytes(*b2);
687
- let mut b = Vec::with_capacity(bytes1.len() + bytes2.len());
688
- b.extend_from_slice(bytes1);
689
- b.extend_from_slice(bytes2);
690
- *self = Self::Ref(vm.heap.allocate(HeapData::Bytes(b.into()))?);
691
- Ok(true)
692
- }
693
- (Self::InternBytes(bytes_id), Self::Ref(id2)) => {
694
- let result = if let HeapData::Bytes(b2) = vm.heap.get(*id2) {
695
- let bytes1 = interns.get_bytes(*bytes_id);
696
- let mut b = Vec::with_capacity(bytes1.len() + b2.len());
697
- b.extend_from_slice(bytes1);
698
- b.extend_from_slice(b2);
699
- *self = Self::Ref(vm.heap.allocate(HeapData::Bytes(b.into()))?);
700
- true
701
- } else {
702
- false
703
- };
704
- Ok(result)
705
- }
706
- (Self::Ref(id), Self::Ref(_)) => {
707
- Heap::with_entry_mut(vm, *id, |vm, mut data| data.py_iadd(other, vm, Some(*id)))
708
- }
709
- _ => Ok(false),
710
- }
711
- }
712
-
713
- fn py_mult(&self, other: &Self, vm: &mut VM<'_, '_, impl ResourceTracker>) -> RunResult<Option<Value>> {
714
- let interns = vm.interns;
715
- match (self, other) {
716
- // Numeric multiplication with overflow promotion to LongInt
717
- (Self::Int(a), Self::Int(b)) => {
718
- if let Some(result) = a.checked_mul(*b) {
719
- Ok(Some(Self::Int(result)))
720
- } else {
721
- // Overflow - promote to LongInt
722
- let li = LongInt::from(*a) * LongInt::from(*b);
723
- Ok(Some(li.into_value(vm.heap)?))
724
- }
725
- }
726
- // Int * Ref (LongInt or sequence)
727
- (Self::Int(a), Self::Ref(id)) => vm.heap.mult_ref_by_i64(*id, *a),
728
- // Ref * Int (LongInt or sequence)
729
- (Self::Ref(id), Self::Int(b)) => vm.heap.mult_ref_by_i64(*id, *b),
730
- // Ref * Ref (LongInt * LongInt, sequence * LongInt, etc.)
731
- (Self::Ref(id1), Self::Ref(id2)) => vm.heap.mult_heap_values(*id1, *id2),
732
- (Self::Float(a), Self::Float(b)) => Ok(Some(Self::Float(a * b))),
733
- (Self::Int(a), Self::Float(b)) => Ok(Some(Self::Float(*a as f64 * b))),
734
- (Self::Float(a), Self::Int(b)) => Ok(Some(Self::Float(a * *b as f64))),
735
-
736
- // Bool numeric multiplication (True=1, False=0)
737
- (Self::Bool(a), Self::Int(b)) => {
738
- let a_int = i64::from(*a);
739
- Ok(Some(Self::Int(a_int * b)))
740
- }
741
- (Self::Int(a), Self::Bool(b)) => {
742
- let b_int = i64::from(*b);
743
- Ok(Some(Self::Int(a * b_int)))
744
- }
745
- (Self::Bool(a), Self::Float(b)) => {
746
- let a_float = if *a { 1.0 } else { 0.0 };
747
- Ok(Some(Self::Float(a_float * b)))
748
- }
749
- (Self::Float(a), Self::Bool(b)) => {
750
- let b_float = if *b { 1.0 } else { 0.0 };
751
- Ok(Some(Self::Float(a * b_float)))
752
- }
753
- (Self::Bool(a), Self::Bool(b)) => {
754
- let result = i64::from(*a) * i64::from(*b);
755
- Ok(Some(Self::Int(result)))
756
- }
757
-
758
- // String repetition: "ab" * 3 or 3 * "ab"
759
- (Self::InternString(s), Self::Int(n)) | (Self::Int(n), Self::InternString(s)) => {
760
- let count = i64_to_repeat_count(*n)?;
761
- let str_ref = interns.get_str(*s);
762
- check_repeat_size(str_ref.len(), count, vm.heap.tracker())?;
763
- let result = str_ref.repeat(count);
764
- Ok(Some(Self::Ref(vm.heap.allocate(HeapData::Str(result.into()))?)))
765
- }
766
-
767
- // Bytes repetition: b"ab" * 3 or 3 * b"ab"
768
- (Self::InternBytes(b), Self::Int(n)) | (Self::Int(n), Self::InternBytes(b)) => {
769
- let count = i64_to_repeat_count(*n)?;
770
- let bytes_ref = interns.get_bytes(*b);
771
- check_repeat_size(bytes_ref.len(), count, vm.heap.tracker())?;
772
- let result: Vec<u8> = bytes_ref.repeat(count);
773
- Ok(Some(Self::Ref(vm.heap.allocate(HeapData::Bytes(result.into()))?)))
774
- }
775
-
776
- // String repetition with LongInt: "ab" * bigint or bigint * "ab"
777
- (Self::InternString(s), Self::Ref(id)) | (Self::Ref(id), Self::InternString(s)) => {
778
- if let HeapData::LongInt(li) = vm.heap.get(*id) {
779
- let count = longint_to_repeat_count(li)?;
780
- let str_ref = interns.get_str(*s);
781
- check_repeat_size(str_ref.len(), count, vm.heap.tracker())?;
782
- let result = str_ref.repeat(count);
783
- Ok(Some(Self::Ref(vm.heap.allocate(HeapData::Str(result.into()))?)))
784
- } else {
785
- Ok(None)
786
- }
787
- }
788
-
789
- // Bytes repetition with LongInt: b"ab" * bigint or bigint * b"ab"
790
- (Self::InternBytes(b), Self::Ref(id)) | (Self::Ref(id), Self::InternBytes(b)) => {
791
- if let HeapData::LongInt(li) = vm.heap.get(*id) {
792
- let count = longint_to_repeat_count(li)?;
793
- let bytes_ref = interns.get_bytes(*b);
794
- check_repeat_size(bytes_ref.len(), count, vm.heap.tracker())?;
795
- let result: Vec<u8> = bytes_ref.repeat(count);
796
- Ok(Some(Self::Ref(vm.heap.allocate(HeapData::Bytes(result.into()))?)))
797
- } else {
798
- Ok(None)
799
- }
800
- }
801
-
802
- _ => Ok(None),
803
- }
804
- }
805
-
806
- fn py_div(&self, other: &Self, vm: &mut VM<'_, '_, impl ResourceTracker>) -> RunResult<Option<Value>> {
807
- let interns = vm.interns;
808
- match (self, other) {
809
- // True division always returns float
810
- (Self::Int(a), Self::Int(b)) => {
811
- if *b == 0 {
812
- Err(ExcType::zero_division().into())
813
- } else {
814
- Ok(Some(Self::Float(*a as f64 / *b as f64)))
815
- }
816
- }
817
- // Int / LongInt
818
- (Self::Int(a), Self::Ref(id)) => {
819
- if let HeapData::LongInt(li) = vm.heap.get(*id) {
820
- if li.is_zero() {
821
- Err(ExcType::zero_division().into())
822
- } else {
823
- // Convert both to f64 for division
824
- let a_f64 = *a as f64;
825
- let b_f64 = li.to_f64().unwrap_or(f64::INFINITY);
826
- Ok(Some(Self::Float(a_f64 / b_f64)))
827
- }
828
- } else {
829
- Ok(None)
830
- }
831
- }
832
- // LongInt / Int
833
- (Self::Ref(id), Self::Int(b)) => {
834
- if let HeapData::LongInt(li) = vm.heap.get(*id) {
835
- if *b == 0 {
836
- Err(ExcType::zero_division().into())
837
- } else {
838
- // Convert both to f64 for division
839
- let a_f64 = li.to_f64().unwrap_or(f64::INFINITY);
840
- let b_f64 = *b as f64;
841
- Ok(Some(Self::Float(a_f64 / b_f64)))
842
- }
843
- } else {
844
- Ok(None)
845
- }
846
- }
847
- // LongInt / LongInt
848
- (Self::Ref(id1), Self::Ref(id2)) => match (vm.heap.get(*id1), vm.heap.get(*id2)) {
849
- (HeapData::LongInt(li1), HeapData::LongInt(li2)) => {
850
- if li2.is_zero() {
851
- Err(ExcType::zero_division().into())
852
- } else {
853
- let a_f64 = li1.to_f64().unwrap_or(f64::INFINITY);
854
- let b_f64 = li2.to_f64().unwrap_or(f64::INFINITY);
855
- Ok(Some(Self::Float(a_f64 / b_f64)))
856
- }
857
- }
858
- _ => Ok(None),
859
- },
860
- // LongInt / Float
861
- (Self::Ref(id), Self::Float(b)) => {
862
- if let HeapData::LongInt(li) = vm.heap.get(*id) {
863
- if *b == 0.0 {
864
- Err(ExcType::zero_division().into())
865
- } else {
866
- let a_f64 = li.to_f64().unwrap_or(f64::INFINITY);
867
- Ok(Some(Self::Float(a_f64 / b)))
868
- }
869
- } else {
870
- Ok(None)
871
- }
872
- }
873
- // Float / LongInt
874
- (Self::Float(a), Self::Ref(id)) => {
875
- if let HeapData::LongInt(li) = vm.heap.get(*id) {
876
- if li.is_zero() {
877
- Err(ExcType::zero_division().into())
878
- } else {
879
- let b_f64 = li.to_f64().unwrap_or(f64::INFINITY);
880
- Ok(Some(Self::Float(a / b_f64)))
881
- }
882
- } else {
883
- Ok(None)
884
- }
885
- }
886
- (Self::Float(a), Self::Float(b)) => {
887
- if *b == 0.0 {
888
- Err(ExcType::zero_division().into())
889
- } else {
890
- Ok(Some(Self::Float(a / b)))
891
- }
892
- }
893
- (Self::Int(a), Self::Float(b)) => {
894
- if *b == 0.0 {
895
- Err(ExcType::zero_division().into())
896
- } else {
897
- Ok(Some(Self::Float(*a as f64 / b)))
898
- }
899
- }
900
- (Self::Float(a), Self::Int(b)) => {
901
- if *b == 0 {
902
- Err(ExcType::zero_division().into())
903
- } else {
904
- Ok(Some(Self::Float(a / *b as f64)))
905
- }
906
- }
907
- // Bool division (True=1, False=0)
908
- (Self::Bool(a), Self::Int(b)) => {
909
- if *b == 0 {
910
- Err(ExcType::zero_division().into())
911
- } else {
912
- Ok(Some(Self::Float(f64::from(*a) / *b as f64)))
913
- }
914
- }
915
- (Self::Int(a), Self::Bool(b)) => {
916
- if *b {
917
- Ok(Some(Self::Float(*a as f64))) // a / 1 = a
918
- } else {
919
- Err(ExcType::zero_division().into())
920
- }
921
- }
922
- (Self::Bool(a), Self::Float(b)) => {
923
- if *b == 0.0 {
924
- Err(ExcType::zero_division().into())
925
- } else {
926
- Ok(Some(Self::Float(f64::from(*a) / b)))
927
- }
928
- }
929
- (Self::Float(a), Self::Bool(b)) => {
930
- if *b {
931
- Ok(Some(Self::Float(*a))) // a / 1.0 = a
932
- } else {
933
- Err(ExcType::zero_division().into())
934
- }
935
- }
936
- (Self::Bool(a), Self::Bool(b)) => {
937
- if *b {
938
- Ok(Some(Self::Float(f64::from(*a)))) // a / 1 = a
939
- } else {
940
- Err(ExcType::zero_division().into())
941
- }
942
- }
943
- _ => {
944
- // Check for Path / (str or Path) - path concatenation
945
- if let Self::Ref(id) = self
946
- && matches!(vm.heap.get(*id), HeapData::Path(_))
947
- {
948
- return path::path_div(*id, other, vm.heap, interns);
949
- }
950
- Ok(None)
951
- }
952
- }
953
- }
954
-
955
- fn py_floordiv(&self, other: &Self, vm: &mut VM<'_, '_, impl ResourceTracker>) -> RunResult<Option<Value>> {
956
- match (self, other) {
957
- // Floor division: int // int returns int
958
- (Self::Int(a), Self::Int(b)) => {
959
- if *b == 0 {
960
- Err(ExcType::zero_division().into())
961
- } else if let Some((d, _)) = floor_divmod(*a, *b) {
962
- Ok(Some(Self::Int(d)))
963
- } else {
964
- // Overflow - promote to LongInt
965
- check_div_size(i64_bits(*a), vm.heap.tracker())?;
966
- let bi = BigInt::from(*a).div_floor(&BigInt::from(*b));
967
- Ok(Some(LongInt::new(bi).into_value(vm.heap)?))
968
- }
969
- }
970
- // Int // LongInt
971
- (Self::Int(a), Self::Ref(id)) => {
972
- if let HeapData::LongInt(li) = vm.heap.get(*id) {
973
- if li.is_zero() {
974
- Err(ExcType::zero_division().into())
975
- } else {
976
- let bi = BigInt::from(*a).div_floor(li.inner());
977
- Ok(Some(LongInt::new(bi).into_value(vm.heap)?))
978
- }
979
- } else {
980
- Ok(None)
981
- }
982
- }
983
- // LongInt // Int
984
- (Self::Ref(id), Self::Int(b)) => {
985
- if let HeapData::LongInt(li) = vm.heap.get(*id) {
986
- if *b == 0 {
987
- Err(ExcType::zero_division().into())
988
- } else {
989
- let bi = li.inner().div_floor(&BigInt::from(*b));
990
- Ok(Some(LongInt::new(bi).into_value(vm.heap)?))
991
- }
992
- } else {
993
- Ok(None)
994
- }
995
- }
996
- // LongInt // LongInt
997
- (Self::Ref(id1), Self::Ref(id2)) => match (vm.heap.get(*id1), vm.heap.get(*id2)) {
998
- (HeapData::LongInt(li1), HeapData::LongInt(li2)) => {
999
- if li2.is_zero() {
1000
- Err(ExcType::zero_division().into())
1001
- } else {
1002
- let bi = li1.inner().div_floor(li2.inner());
1003
- Ok(Some(LongInt::new(bi).into_value(vm.heap)?))
1004
- }
1005
- }
1006
- _ => Ok(None),
1007
- },
1008
- // Float floor division returns float
1009
- (Self::Float(a), Self::Float(b)) => {
1010
- if *b == 0.0 {
1011
- Err(ExcType::zero_division().into())
1012
- } else {
1013
- Ok(Some(Self::Float((a / b).floor())))
1014
- }
1015
- }
1016
- (Self::Int(a), Self::Float(b)) => {
1017
- if *b == 0.0 {
1018
- Err(ExcType::zero_division().into())
1019
- } else {
1020
- Ok(Some(Self::Float((*a as f64 / b).floor())))
1021
- }
1022
- }
1023
- (Self::Float(a), Self::Int(b)) => {
1024
- if *b == 0 {
1025
- Err(ExcType::zero_division().into())
1026
- } else {
1027
- Ok(Some(Self::Float((a / *b as f64).floor())))
1028
- }
1029
- }
1030
- // Bool floor division (True=1, False=0)
1031
- (Self::Bool(a), Self::Int(b)) => {
1032
- if *b == 0 {
1033
- Err(ExcType::zero_division().into())
1034
- } else {
1035
- let a_int = i64::from(*a);
1036
- // Use same floor division logic as Int // Int
1037
- let d = a_int / b;
1038
- let r = a_int % b;
1039
- let result = if r != 0 && (a_int < 0) != (*b < 0) { d - 1 } else { d };
1040
- Ok(Some(Self::Int(result)))
1041
- }
1042
- }
1043
- (Self::Int(a), Self::Bool(b)) => {
1044
- if *b {
1045
- Ok(Some(Self::Int(*a))) // a // 1 = a
1046
- } else {
1047
- Err(ExcType::zero_division().into())
1048
- }
1049
- }
1050
- (Self::Bool(a), Self::Float(b)) => {
1051
- if *b == 0.0 {
1052
- Err(ExcType::zero_division().into())
1053
- } else {
1054
- Ok(Some(Self::Float((f64::from(*a) / b).floor())))
1055
- }
1056
- }
1057
- (Self::Float(a), Self::Bool(b)) => {
1058
- if *b {
1059
- Ok(Some(Self::Float(a.floor()))) // a // 1.0 = floor(a)
1060
- } else {
1061
- Err(ExcType::zero_division().into())
1062
- }
1063
- }
1064
- (Self::Bool(a), Self::Bool(b)) => {
1065
- if *b {
1066
- Ok(Some(Self::Int(i64::from(*a)))) // a // 1 = a
1067
- } else {
1068
- Err(ExcType::zero_division().into())
1069
- }
1070
- }
1071
- _ => Ok(None),
1072
- }
1073
- }
1074
-
1075
- fn py_pow(&self, other: &Self, vm: &mut VM<'_, '_, impl ResourceTracker>) -> RunResult<Option<Value>> {
1076
- match (self, other) {
1077
- (Self::Int(base), Self::Int(exp)) => {
1078
- if *base == 0 && *exp < 0 {
1079
- Err(ExcType::zero_negative_power())
1080
- } else if *exp >= 0 {
1081
- // Positive exponent: try to return int, promote to LongInt on overflow
1082
- if let Ok(exp_u32) = u32::try_from(*exp) {
1083
- if let Some(result) = base.checked_pow(exp_u32) {
1084
- Ok(Some(Self::Int(result)))
1085
- } else {
1086
- // Overflow - promote to LongInt
1087
- // Check size before computing to prevent DoS
1088
- check_pow_size(i64_bits(*base), u64::from(exp_u32), vm.heap.tracker())?;
1089
- let bi = BigInt::from(*base).pow(exp_u32);
1090
- Ok(Some(LongInt::new(bi).into_value(vm.heap)?))
1091
- }
1092
- } else {
1093
- // exp > u32::MAX - use BigInt with modpow-style exponentiation
1094
- // For very large exponents, we still need LongInt
1095
- // Safety: exp >= 0 is guaranteed by the outer if condition
1096
- #[expect(clippy::cast_sign_loss)]
1097
- let exp_u64 = *exp as u64;
1098
- // Check size before computing to prevent DoS
1099
- check_pow_size(i64_bits(*base), exp_u64, vm.heap.tracker())?;
1100
- let bi = bigint_pow(BigInt::from(*base), exp_u64);
1101
- Ok(Some(LongInt::new(bi).into_value(vm.heap)?))
1102
- }
1103
- } else {
1104
- // Negative exponent: return float
1105
- // Use powi if exp fits in i32, otherwise use powf
1106
- if let Ok(exp_i32) = i32::try_from(*exp) {
1107
- Ok(Some(Self::Float((*base as f64).powi(exp_i32))))
1108
- } else {
1109
- Ok(Some(Self::Float((*base as f64).powf(*exp as f64))))
1110
- }
1111
- }
1112
- }
1113
- // LongInt ** Int
1114
- (Self::Ref(id), Self::Int(exp)) => {
1115
- if let HeapData::LongInt(li) = vm.heap.get(*id) {
1116
- if li.is_zero() && *exp < 0 {
1117
- Err(ExcType::zero_negative_power())
1118
- } else if *exp >= 0 {
1119
- // Use BigInt pow for positive exponents
1120
- if let Ok(exp_u32) = u32::try_from(*exp) {
1121
- // Check size before computing to prevent DoS
1122
- check_pow_size(li.bits(), u64::from(exp_u32), vm.heap.tracker())?;
1123
- let bi = li.inner().pow(exp_u32);
1124
- Ok(Some(LongInt::new(bi).into_value(vm.heap)?))
1125
- } else {
1126
- // Safety: exp >= 0 is guaranteed by the outer if condition
1127
- #[expect(clippy::cast_sign_loss)]
1128
- let exp_u64 = *exp as u64;
1129
- // Check size before computing to prevent DoS
1130
- check_pow_size(li.bits(), exp_u64, vm.heap.tracker())?;
1131
- let bi = bigint_pow(li.inner().clone(), exp_u64);
1132
- Ok(Some(LongInt::new(bi).into_value(vm.heap)?))
1133
- }
1134
- } else {
1135
- // Negative exponent: return float (LongInt base becomes 0.0 for large values)
1136
- if let Some(base_f64) = li.to_f64() {
1137
- if let Ok(exp_i32) = i32::try_from(*exp) {
1138
- Ok(Some(Self::Float(base_f64.powi(exp_i32))))
1139
- } else {
1140
- Ok(Some(Self::Float(base_f64.powf(*exp as f64))))
1141
- }
1142
- } else {
1143
- // Base too large for f64, result approaches 0
1144
- Ok(Some(Self::Float(0.0)))
1145
- }
1146
- }
1147
- } else {
1148
- Ok(None)
1149
- }
1150
- }
1151
- // Int ** LongInt (only small positive exponents make sense)
1152
- (Self::Int(base), Self::Ref(id)) => {
1153
- if let HeapData::LongInt(li) = vm.heap.get(*id) {
1154
- if *base == 0 && li.is_negative() {
1155
- Err(ExcType::zero_negative_power())
1156
- } else if !li.is_negative() {
1157
- // For very large exponents, most results are huge or 0/1
1158
- // Check for x ** 0 = 1 first (including 0 ** 0 = 1)
1159
- if li.is_zero() {
1160
- Ok(Some(Self::Int(1)))
1161
- } else if *base == 0 {
1162
- Ok(Some(Self::Int(0)))
1163
- } else if *base == 1 {
1164
- Ok(Some(Self::Int(1)))
1165
- } else if *base == -1 {
1166
- // (-1) ** n = 1 if n is even, -1 if n is odd
1167
- let is_even = (li.inner() % 2i32).is_zero();
1168
- Ok(Some(Self::Int(if is_even { 1 } else { -1 })))
1169
- } else if let Some(exp_u32) = li.to_u32() {
1170
- // Reasonable exponent size
1171
- if let Some(result) = base.checked_pow(exp_u32) {
1172
- Ok(Some(Self::Int(result)))
1173
- } else {
1174
- // Check size before computing to prevent DoS
1175
- check_pow_size(i64_bits(*base), u64::from(exp_u32), vm.heap.tracker())?;
1176
- let bi = BigInt::from(*base).pow(exp_u32);
1177
- Ok(Some(LongInt::new(bi).into_value(vm.heap)?))
1178
- }
1179
- } else {
1180
- // Exponent too large - result would be astronomically large
1181
- // Python handles this, but it would take forever. Use OverflowError
1182
- Err(SimpleException::new_msg(ExcType::OverflowError, "exponent too large").into())
1183
- }
1184
- } else {
1185
- // Negative LongInt exponent: return float
1186
- if let (Some(base_f64), Some(exp_f64)) = (Some(*base as f64), li.to_f64()) {
1187
- Ok(Some(Self::Float(base_f64.powf(exp_f64))))
1188
- } else {
1189
- Ok(Some(Self::Float(0.0)))
1190
- }
1191
- }
1192
- } else {
1193
- Ok(None)
1194
- }
1195
- }
1196
- (Self::Float(base), Self::Float(exp)) => {
1197
- if *base == 0.0 && *exp < 0.0 {
1198
- Err(ExcType::zero_negative_power())
1199
- } else {
1200
- Ok(Some(Self::Float(base.powf(*exp))))
1201
- }
1202
- }
1203
- (Self::Int(base), Self::Float(exp)) => {
1204
- if *base == 0 && *exp < 0.0 {
1205
- Err(ExcType::zero_negative_power())
1206
- } else {
1207
- Ok(Some(Self::Float((*base as f64).powf(*exp))))
1208
- }
1209
- }
1210
- (Self::Float(base), Self::Int(exp)) => {
1211
- if *base == 0.0 && *exp < 0 {
1212
- Err(ExcType::zero_negative_power())
1213
- } else if let Ok(exp_i32) = i32::try_from(*exp) {
1214
- // Use powi if exp fits in i32
1215
- Ok(Some(Self::Float(base.powi(exp_i32))))
1216
- } else {
1217
- // Fall back to powf for exponents outside i32 range
1218
- Ok(Some(Self::Float(base.powf(*exp as f64))))
1219
- }
1220
- }
1221
- // Bool power operations (True=1, False=0)
1222
- (Self::Bool(base), Self::Int(exp)) => {
1223
- let base_int = i64::from(*base);
1224
- if base_int == 0 && *exp < 0 {
1225
- Err(ExcType::zero_negative_power())
1226
- } else if *exp >= 0 {
1227
- // Positive exponent: 1**n=1, 0**n=0 (for n>0), 0**0=1
1228
- if let Ok(exp_u32) = u32::try_from(*exp) {
1229
- match base_int.checked_pow(exp_u32) {
1230
- Some(result) => Ok(Some(Self::Int(result))),
1231
- None => Ok(Some(Self::Float((base_int as f64).powf(*exp as f64)))),
1232
- }
1233
- } else {
1234
- Ok(Some(Self::Float((base_int as f64).powf(*exp as f64))))
1235
- }
1236
- } else {
1237
- // Negative exponent: return float (1**-n=1.0)
1238
- if let Ok(exp_i32) = i32::try_from(*exp) {
1239
- Ok(Some(Self::Float((base_int as f64).powi(exp_i32))))
1240
- } else {
1241
- Ok(Some(Self::Float((base_int as f64).powf(*exp as f64))))
1242
- }
1243
- }
1244
- }
1245
- (Self::Int(base), Self::Bool(exp)) => {
1246
- // n ** True = n, n ** False = 1
1247
- if *exp {
1248
- Ok(Some(Self::Int(*base)))
1249
- } else {
1250
- Ok(Some(Self::Int(1)))
1251
- }
1252
- }
1253
- (Self::Bool(base), Self::Float(exp)) => {
1254
- let base_float = f64::from(*base);
1255
- if base_float == 0.0 && *exp < 0.0 {
1256
- Err(ExcType::zero_negative_power())
1257
- } else {
1258
- Ok(Some(Self::Float(base_float.powf(*exp))))
1259
- }
1260
- }
1261
- (Self::Float(base), Self::Bool(exp)) => {
1262
- // base ** True = base, base ** False = 1.0
1263
- if *exp {
1264
- Ok(Some(Self::Float(*base)))
1265
- } else {
1266
- Ok(Some(Self::Float(1.0)))
1267
- }
1268
- }
1269
- (Self::Bool(base), Self::Bool(exp)) => {
1270
- // True ** True = 1, True ** False = 1, False ** True = 0, False ** False = 1
1271
- let base_int = i64::from(*base);
1272
- let exp_int = i64::from(*exp);
1273
- if exp_int == 0 {
1274
- Ok(Some(Self::Int(1))) // anything ** 0 = 1
1275
- } else {
1276
- Ok(Some(Self::Int(base_int))) // base ** 1 = base
1277
- }
1278
- }
1279
- _ => Ok(None),
1280
- }
1281
- }
1282
-
1283
- fn py_getitem(&self, key: &Self, vm: &mut VM<'_, '_, impl ResourceTracker>) -> RunResult<Self> {
1284
- let interns = vm.interns;
1285
- match self {
1286
- Self::Ref(id) => Heap::with_entry_mut(vm, *id, |vm, data| data.py_getitem(key, vm)),
1287
- Self::InternString(string_id) => {
1288
- // Check for slice first
1289
- if let Self::Ref(key_id) = key
1290
- && let HeapData::Slice(slice_obj) = vm.heap.get(*key_id)
1291
- {
1292
- let s = interns.get_str(*string_id);
1293
- let char_count = s.chars().count();
1294
- let (start, stop, step) = slice_obj
1295
- .indices(char_count)
1296
- .map_err(|()| ExcType::value_error_slice_step_zero())?;
1297
- let result_str = get_str_slice(s, start, stop, step);
1298
- let heap_id = vm.heap.allocate(HeapData::Str(Str::from(result_str)))?;
1299
- return Ok(Self::Ref(heap_id));
1300
- }
1301
-
1302
- // Handle interned string indexing, accepting Int and Bool
1303
- let index = match key {
1304
- Self::Int(i) => *i,
1305
- Self::Bool(b) => i64::from(*b),
1306
- _ => return Err(ExcType::type_error_indices(Type::Str, key.py_type(vm.heap))),
1307
- };
1308
-
1309
- let s = interns.get_str(*string_id);
1310
- let c = get_char_at_index(s, index).ok_or_else(ExcType::str_index_error)?;
1311
- Ok(allocate_char(c, vm.heap)?)
1312
- }
1313
- Self::InternBytes(bytes_id) => {
1314
- // Check for slice first
1315
- if let Self::Ref(key_id) = key
1316
- && let HeapData::Slice(slice_obj) = vm.heap.get(*key_id)
1317
- {
1318
- let bytes = interns.get_bytes(*bytes_id);
1319
- let (start, stop, step) = slice_obj
1320
- .indices(bytes.len())
1321
- .map_err(|()| ExcType::value_error_slice_step_zero())?;
1322
- let result_bytes = get_bytes_slice(bytes, start, stop, step);
1323
- let heap_id = vm
1324
- .heap
1325
- .allocate(HeapData::Bytes(crate::types::Bytes::new(result_bytes)))?;
1326
- return Ok(Self::Ref(heap_id));
1327
- }
1328
-
1329
- // Handle interned bytes indexing - returns integer byte value
1330
- let index = match key {
1331
- Self::Int(i) => *i,
1332
- Self::Bool(b) => i64::from(*b),
1333
- _ => return Err(ExcType::type_error_indices(Type::Bytes, key.py_type(vm.heap))),
1334
- };
1335
-
1336
- let bytes = interns.get_bytes(*bytes_id);
1337
- let byte = get_byte_at_index(bytes, index).ok_or_else(ExcType::bytes_index_error)?;
1338
- Ok(Self::Int(i64::from(byte)))
1339
- }
1340
- _ => Err(ExcType::type_error_not_sub(self.py_type(vm.heap))),
1341
- }
1342
- }
1343
-
1344
- fn py_setitem(&mut self, key: Self, value: Self, vm: &mut VM<'_, '_, impl ResourceTracker>) -> RunResult<()> {
1345
- match self {
1346
- Self::Ref(id) => Heap::with_entry_mut(vm, *id, |vm, mut data| data.py_setitem(key, value, vm)),
1347
- _ => Err(ExcType::type_error(format!(
1348
- "'{}' object does not support item assignment",
1349
- self.py_type(vm.heap)
1350
- ))),
1351
- }
1352
- }
1353
- }
1354
-
1355
- impl Value {
1356
- /// Returns a stable, unique identifier for this value.
1357
- ///
1358
- /// Should match Python's `id()` function conceptually.
1359
- ///
1360
- /// For immediate values (Int, Float, Builtins), this computes a deterministic ID
1361
- /// based on the value's hash, avoiding heap allocation. This means `id(5) == id(5)` will
1362
- /// return True (unlike CPython for large integers outside the interning range).
1363
- ///
1364
- /// Singletons (None, True, False, etc.) return IDs from a dedicated tagged range.
1365
- /// Interned strings/bytes use their interner index for stable identity.
1366
- /// Heap-allocated values (Ref) reuse their `HeapId` inside the heap-tagged range.
1367
- pub fn id(&self) -> usize {
1368
- match self {
1369
- // Singletons have fixed tagged IDs
1370
- Self::Undefined => singleton_id(SingletonSlot::Undefined),
1371
- Self::Ellipsis => singleton_id(SingletonSlot::Ellipsis),
1372
- Self::None => singleton_id(SingletonSlot::None),
1373
- Self::Bool(b) => {
1374
- if *b {
1375
- singleton_id(SingletonSlot::True)
1376
- } else {
1377
- singleton_id(SingletonSlot::False)
1378
- }
1379
- }
1380
- // Interned strings/bytes/bigints use their index directly - the index is the stable identifier
1381
- Self::InternString(string_id) => INTERN_STR_ID_TAG | (string_id.index() & INTERN_STR_ID_MASK),
1382
- Self::InternBytes(bytes_id) => INTERN_BYTES_ID_TAG | (bytes_id.index() & INTERN_BYTES_ID_MASK),
1383
- Self::InternLongInt(long_int_id) => {
1384
- INTERN_LONG_INT_ID_TAG | (long_int_id.index() & INTERN_LONG_INT_ID_MASK)
1385
- }
1386
- // Already heap-allocated (includes Range and Exception), return id within a dedicated tag range
1387
- Self::Ref(id) => heap_tagged_id(*id),
1388
- // Value-based IDs for immediate types (no heap allocation!)
1389
- Self::Int(v) => int_value_id(*v),
1390
- Self::Float(v) => float_value_id(*v),
1391
- Self::Builtin(c) => builtin_value_id(*c),
1392
- Self::ModuleFunction(mf) => module_function_value_id(*mf),
1393
- Self::DefFunction(f_id) => function_value_id(*f_id),
1394
- Self::ExtFunction(name_id) => ext_function_value_id(*name_id),
1395
- // Markers get deterministic IDs based on discriminant
1396
- Self::Marker(m) => marker_value_id(*m),
1397
- // Properties get deterministic IDs based on discriminant
1398
- Self::Property(p) => property_value_id(*p),
1399
- // ExternalFutures get IDs based on their call_id
1400
- Self::ExternalFuture(call_id) => external_future_value_id(*call_id),
1401
- #[cfg(feature = "ref-count-panic")]
1402
- Self::Dereferenced => panic!("Cannot get id of Dereferenced object"),
1403
- }
1404
- }
1405
-
1406
- /// Returns the Ref ID if this value is a reference, otherwise returns None.
1407
- pub fn ref_id(&self) -> Option<HeapId> {
1408
- match self {
1409
- Self::Ref(id) => Some(*id),
1410
- _ => None,
1411
- }
1412
- }
1413
-
1414
- /// Returns the module name if this value is a module, otherwise returns "<unknown>".
1415
- ///
1416
- /// Used for error messages in `from module import name` when the name doesn't exist.
1417
- pub fn module_name(&self, heap: &Heap<impl ResourceTracker>, interns: &Interns) -> String {
1418
- match self {
1419
- Self::Ref(id) => match heap.get(*id) {
1420
- HeapData::Module(module) => interns.get_str(module.name()).to_string(),
1421
- _ => "<unknown>".to_string(),
1422
- },
1423
- _ => "<unknown>".to_string(),
1424
- }
1425
- }
1426
-
1427
- /// Equivalent of Python's `is` operator.
1428
- ///
1429
- /// Compares value identity by comparing their IDs.
1430
- pub fn is(&self, other: &Self) -> bool {
1431
- self.id() == other.id()
1432
- }
1433
-
1434
- /// Computes the hash value for this value, used for dict keys.
1435
- ///
1436
- /// Returns `Ok(Some(hash))` for hashable types (immediate values and immutable heap types).
1437
- /// Returns `Ok(None)` for unhashable types (list, dict).
1438
- /// Returns `Err(ResourceError::Recursion)` if the recursion limit is exceeded
1439
- /// while hashing deeply nested containers (e.g., tuples of tuples).
1440
- ///
1441
- /// For heap-allocated values (Ref variant), this computes the hash lazily
1442
- /// on first use and caches it for subsequent calls.
1443
- ///
1444
- /// The `interns` parameter is needed for InternString/InternBytes to look up
1445
- /// their actual content and hash it consistently with equivalent heap Str/Bytes.
1446
- pub fn py_hash(
1447
- &self,
1448
- heap: &mut Heap<impl ResourceTracker>,
1449
- interns: &Interns,
1450
- ) -> Result<Option<u64>, ResourceError> {
1451
- // strings bytes bigints and heap allocated values have their own hashing logic
1452
- match self {
1453
- // Hash just the actual string or bytes content for consistency with heap Str/Bytes
1454
- // hence we don't include the discriminant
1455
- Self::InternString(string_id) => {
1456
- let mut hasher = DefaultHasher::new();
1457
- interns.get_str(*string_id).hash(&mut hasher);
1458
- return Ok(Some(hasher.finish()));
1459
- }
1460
- Self::InternBytes(bytes_id) => {
1461
- let mut hasher = DefaultHasher::new();
1462
- interns.get_bytes(*bytes_id).hash(&mut hasher);
1463
- return Ok(Some(hasher.finish()));
1464
- }
1465
- // Hash BigInt consistently with LongInt (using sign and bytes for large values)
1466
- Self::InternLongInt(long_int_id) => {
1467
- let bi = interns.get_long_int(*long_int_id);
1468
- let mut hasher = DefaultHasher::new();
1469
- let (sign, bytes) = bi.to_bytes_le();
1470
- sign.hash(&mut hasher);
1471
- bytes.hash(&mut hasher);
1472
- return Ok(Some(hasher.finish()));
1473
- }
1474
- // For heap-allocated values (includes Range and Exception), compute hash lazily and cache it
1475
- Self::Ref(id) => return heap.get_or_compute_hash(*id, interns),
1476
- _ => {}
1477
- }
1478
-
1479
- let mut hasher = DefaultHasher::new();
1480
- // hash based on discriminant to avoid collisions with different types
1481
- discriminant(self).hash(&mut hasher);
1482
- match self {
1483
- // Immediate values can be hashed directly
1484
- Self::Undefined | Self::Ellipsis | Self::None => {}
1485
- Self::Bool(b) => b.hash(&mut hasher),
1486
- Self::Int(i) => i.hash(&mut hasher),
1487
- // Hash the bit representation of float for consistency
1488
- Self::Float(f) => f.to_bits().hash(&mut hasher),
1489
- Self::Builtin(b) => b.hash(&mut hasher),
1490
- Self::ModuleFunction(mf) => mf.hash(&mut hasher),
1491
- // Hash functions based on function ID
1492
- Self::DefFunction(f_id) => f_id.hash(&mut hasher),
1493
- Self::ExtFunction(name_id) => name_id.hash(&mut hasher),
1494
- // Markers are hashable based on their discriminant (already included above)
1495
- Self::Marker(m) => m.hash(&mut hasher),
1496
- // Properties are hashable based on their OS function discriminant
1497
- Self::Property(p) => p.hash(&mut hasher),
1498
- // ExternalFutures are hashable based on their call ID
1499
- Self::ExternalFuture(call_id) => call_id.raw().hash(&mut hasher),
1500
- Self::InternString(_) | Self::InternBytes(_) | Self::InternLongInt(_) | Self::Ref(_) => {
1501
- unreachable!("covered above")
1502
- }
1503
- #[cfg(feature = "ref-count-panic")]
1504
- Self::Dereferenced => panic!("Cannot access Dereferenced object"),
1505
- }
1506
- Ok(Some(hasher.finish()))
1507
- }
1508
-
1509
- /// TODO this doesn't have many tests!!! also doesn't cover bytes
1510
- /// Checks if `item` is contained in `self` (the container).
1511
- ///
1512
- /// Implements Python's `in` operator for various container types:
1513
- /// - List/Tuple: linear search with equality
1514
- /// - Dict: key lookup
1515
- /// - Set/FrozenSet: element lookup
1516
- /// - Str: substring search
1517
- pub fn py_contains(&self, item: &Self, vm: &mut VM<'_, '_, impl ResourceTracker>) -> RunResult<bool> {
1518
- match self {
1519
- Self::Ref(heap_id) => Heap::with_entry_mut(vm, *heap_id, |vm, data| match data {
1520
- HeapDataMut::List(list) => {
1521
- for el in list.as_slice() {
1522
- if item.py_eq(el, vm)? {
1523
- return Ok(true);
1524
- }
1525
- }
1526
- Ok(false)
1527
- }
1528
- HeapDataMut::Tuple(tuple) => {
1529
- for el in tuple.as_slice() {
1530
- if item.py_eq(el, vm)? {
1531
- return Ok(true);
1532
- }
1533
- }
1534
- Ok(false)
1535
- }
1536
- HeapDataMut::Dict(dict) => dict.get(item, vm).map(|m| m.is_some()),
1537
- HeapDataMut::DictKeysView(view) => Heap::with_entry_mut(vm, view.dict_id(), |vm, dict_data| {
1538
- let HeapDataMut::Dict(dict) = dict_data else {
1539
- panic!("dict_keys view must reference a dict");
1540
- };
1541
- dict.get(item, vm).map(|m| m.is_some())
1542
- }),
1543
- HeapDataMut::DictItemsView(view) => {
1544
- let Some((key, value)) = cloned_items_view_candidate(item, vm) else {
1545
- return Ok(false);
1546
- };
1547
- let mut key_guard = HeapGuard::new(key, vm);
1548
- let (key, vm) = key_guard.as_parts_mut();
1549
- let mut value_guard = HeapGuard::new(value, vm);
1550
- let (value, vm) = value_guard.as_parts_mut();
1551
- Heap::with_entry_mut(vm, view.dict_id(), |vm, dict_data| {
1552
- let HeapDataMut::Dict(dict) = dict_data else {
1553
- panic!("dict_items view must reference a dict");
1554
- };
1555
- match dict.get(key, vm) {
1556
- Ok(Some(existing_value)) => value.py_eq(existing_value, vm).map_err(RunError::from),
1557
- Ok(None) => Ok(false),
1558
- Err(e) => Err(e),
1559
- }
1560
- })
1561
- }
1562
- HeapDataMut::DictValuesView(view) => Heap::with_entry_mut(vm, view.dict_id(), |vm, dict_data| {
1563
- let HeapDataMut::Dict(dict) = dict_data else {
1564
- panic!("dict_values view must reference a dict");
1565
- };
1566
- for (_, value) in dict.iter() {
1567
- if item.py_eq(value, vm)? {
1568
- return Ok(true);
1569
- }
1570
- }
1571
- Ok(false)
1572
- }),
1573
- HeapDataMut::Set(set) => set.contains(item, vm),
1574
- HeapDataMut::FrozenSet(fset) => fset.contains(item, vm),
1575
- HeapDataMut::Str(s) => str_contains(s.as_str(), item, vm.heap, vm.interns),
1576
- HeapDataMut::Range(range) => {
1577
- // Range containment is O(1) - check bounds and step alignment
1578
- let n = match item {
1579
- Self::Int(i) => *i,
1580
- Self::Bool(b) => i64::from(*b),
1581
- Self::Float(f) => {
1582
- // Floats are contained if they equal an integer in the range
1583
- // e.g., 3.0 in range(5) is True, but 3.5 in range(5) is False
1584
- if f.fract() != 0.0 {
1585
- return Ok(false);
1586
- }
1587
- // Check if float is within i64 range and convert safely
1588
- // f64 can represent integers up to 2^53 exactly
1589
- let int_val = f.trunc();
1590
- if int_val < i64::MIN as f64 || int_val > i64::MAX as f64 {
1591
- return Ok(false);
1592
- }
1593
- // Safe conversion: we've verified it's a whole number in i64 range
1594
- #[expect(clippy::cast_possible_truncation)]
1595
- let n = int_val as i64;
1596
- n
1597
- }
1598
- _ => return Ok(false),
1599
- };
1600
- Ok(range.contains(n))
1601
- }
1602
- other => {
1603
- let type_name = other.py_type(vm.heap);
1604
- Err(ExcType::type_error(format!(
1605
- "argument of type '{type_name}' is not iterable"
1606
- )))
1607
- }
1608
- }),
1609
- Self::InternString(string_id) => {
1610
- let container_str = vm.interns.get_str(*string_id);
1611
- str_contains(container_str, item, vm.heap, vm.interns)
1612
- }
1613
- _ => {
1614
- let type_name = self.py_type(vm.heap);
1615
- Err(ExcType::type_error(format!(
1616
- "argument of type '{type_name}' is not iterable"
1617
- )))
1618
- }
1619
- }
1620
- }
1621
-
1622
- /// Gets an attribute from this value.
1623
- ///
1624
- /// Dispatches to `py_getattr` on the underlying types where appropriate.
1625
- /// Accepts `EitherStr` to support both interned and heap-allocated attribute names.
1626
- ///
1627
- /// Returns `AttributeError` for other types or unknown attributes.
1628
- pub fn py_getattr(&self, attr: &EitherStr, vm: &mut VM<'_, '_, impl ResourceTracker>) -> RunResult<CallResult> {
1629
- match self {
1630
- Self::Ref(heap_id) => {
1631
- // Use with_entry_mut to get access to both data and heap without borrow conflicts.
1632
- // This allows py_getattr to allocate (for computed attributes) while we hold the data.
1633
- let opt_result = Heap::with_entry_mut(vm, *heap_id, |vm, data| data.py_getattr(attr, vm))?;
1634
- if let Some(call_result) = opt_result {
1635
- return Ok(call_result);
1636
- }
1637
- }
1638
- Self::Builtin(Builtins::Type(t)) => {
1639
- // Handle type object attributes like __name__
1640
- let is_dunder_name = attr.static_string().map_or_else(
1641
- || attr.as_str(vm.interns) == "__name__",
1642
- |ss| ss == StaticStrings::DunderName,
1643
- );
1644
- if is_dunder_name {
1645
- let name_str = t.to_string();
1646
- let str_id = vm.heap.allocate(HeapData::Str(Str::from(name_str)))?;
1647
- return Ok(CallResult::Value(Self::Ref(str_id)));
1648
- }
1649
- }
1650
- _ => {}
1651
- }
1652
- let type_name = self.py_type(vm.heap);
1653
- Err(ExcType::attribute_error(type_name, attr.as_str(vm.interns)))
1654
- }
1655
-
1656
- /// Sets an attribute on this value.
1657
- ///
1658
- /// Currently only Dataclass objects support attribute setting.
1659
- /// Returns AttributeError for other types.
1660
- ///
1661
- /// Takes ownership of `value` and drops it on error.
1662
- /// On success, drops the old attribute value if one existed.
1663
- pub fn py_set_attr(
1664
- &self,
1665
- name_id: StringId,
1666
- value: Self,
1667
- vm: &mut VM<'_, '_, impl ResourceTracker>,
1668
- ) -> RunResult<()> {
1669
- let attr_name = vm.interns.get_str(name_id);
1670
-
1671
- if let Self::Ref(heap_id) = self {
1672
- let heap_id = *heap_id;
1673
- let is_dataclass = matches!(vm.heap.get(heap_id), HeapData::Dataclass(_));
1674
-
1675
- if is_dataclass {
1676
- let name_value = Self::InternString(name_id);
1677
- Heap::with_entry_mut(vm, heap_id, |vm, data| {
1678
- if let HeapDataMut::Dataclass(dc) = data {
1679
- match dc.set_attr(name_value, value, vm) {
1680
- Ok(old_value) => {
1681
- if let Some(old) = old_value {
1682
- old.drop_with_heap(vm.heap);
1683
- }
1684
- Ok(())
1685
- }
1686
- Err(e) => Err(e),
1687
- }
1688
- } else {
1689
- unreachable!("type changed during borrow")
1690
- }
1691
- })
1692
- } else {
1693
- let type_name = vm.heap.get(heap_id).py_type(vm.heap);
1694
- value.drop_with_heap(vm.heap);
1695
- Err(ExcType::attribute_error_no_setattr(type_name, attr_name))
1696
- }
1697
- } else {
1698
- let type_name = self.py_type(vm.heap);
1699
- value.drop_with_heap(vm.heap);
1700
- Err(ExcType::attribute_error_no_setattr(type_name, attr_name))
1701
- }
1702
- }
1703
-
1704
- /// Extracts an integer value from the Value.
1705
- ///
1706
- /// Accepts `Int` and `LongInt` (if it fits in i64). Returns a `TypeError` for other types
1707
- /// and an `OverflowError` if the `LongInt` value is too large.
1708
- ///
1709
- /// Note: The LongInt-to-i64 conversion path is defensive code. In normal execution,
1710
- /// heap-allocated `LongInt` values always exceed i64 range because `LongInt::into_value()`
1711
- /// automatically demotes i64-fitting values to `Value::Int`. However, this path could be
1712
- /// reached via deserialization of crafted snapshot data.
1713
- pub fn as_int(&self, heap: &Heap<impl ResourceTracker>) -> RunResult<i64> {
1714
- match self {
1715
- Self::Int(i) => Ok(*i),
1716
- Self::Ref(heap_id) => {
1717
- if let HeapData::LongInt(li) = heap.get(*heap_id) {
1718
- li.to_i64().ok_or_else(ExcType::overflow_shift_count)
1719
- } else {
1720
- let msg = format!("'{}' object cannot be interpreted as an integer", self.py_type(heap));
1721
- Err(SimpleException::new_msg(ExcType::TypeError, msg).into())
1722
- }
1723
- }
1724
- _ => {
1725
- let msg = format!("'{}' object cannot be interpreted as an integer", self.py_type(heap));
1726
- Err(SimpleException::new_msg(ExcType::TypeError, msg).into())
1727
- }
1728
- }
1729
- }
1730
-
1731
- /// Extracts an index value for sequence operations.
1732
- ///
1733
- /// Accepts `Int`, `Bool` (True=1, False=0), and `LongInt` (if it fits in i64).
1734
- /// Returns a `TypeError` for other types with the container type name included.
1735
- /// Returns an `IndexError` if the `LongInt` value is too large to use as an index.
1736
- ///
1737
- /// Note: The LongInt-to-i64 conversion path is defensive code. In normal execution,
1738
- /// heap-allocated `LongInt` values always exceed i64 range because `LongInt::into_value()`
1739
- /// automatically demotes i64-fitting values to `Value::Int`. However, this path could be
1740
- /// reached via deserialization of crafted snapshot data.
1741
- pub fn as_index(&self, heap: &Heap<impl ResourceTracker>, container_type: Type) -> RunResult<i64> {
1742
- match self {
1743
- Self::Int(i) => Ok(*i),
1744
- Self::Bool(b) => Ok(i64::from(*b)),
1745
- Self::Ref(heap_id) => {
1746
- if let HeapData::LongInt(li) = heap.get(*heap_id) {
1747
- li.to_i64().ok_or_else(ExcType::index_error_int_too_large)
1748
- } else {
1749
- Err(ExcType::type_error_indices(container_type, self.py_type(heap)))
1750
- }
1751
- }
1752
- _ => Err(ExcType::type_error_indices(container_type, self.py_type(heap))),
1753
- }
1754
- }
1755
-
1756
- /// Performs a binary bitwise operation on two values.
1757
- ///
1758
- /// Python only supports bitwise operations on integers (and bools, which coerce to int).
1759
- /// Returns a `TypeError` if either operand is not an integer, bool, or LongInt.
1760
- ///
1761
- /// For shift operations:
1762
- /// - Negative shift counts raise `ValueError`
1763
- /// - Left shifts may produce LongInt results for large shifts
1764
- /// - Right shifts with large counts return 0 (or -1 for negative numbers)
1765
- pub fn py_bitwise(
1766
- &self,
1767
- other: &Self,
1768
- op: BitwiseOp,
1769
- heap: &mut Heap<impl ResourceTracker>,
1770
- ) -> Result<Self, RunError> {
1771
- // Capture types for error messages
1772
- let lhs_type = self.py_type(heap);
1773
- let rhs_type = other.py_type(heap);
1774
-
1775
- // Extract BigInt from all numeric types
1776
- let lhs_bigint = extract_bigint(self, heap);
1777
- let rhs_bigint = extract_bigint(other, heap);
1778
-
1779
- if let (Some(l), Some(r)) = (lhs_bigint, rhs_bigint) {
1780
- let result = match op {
1781
- BitwiseOp::And => l & r,
1782
- BitwiseOp::Or => l | r,
1783
- BitwiseOp::Xor => l ^ r,
1784
- BitwiseOp::LShift => {
1785
- // Get shift amount as i64 for validation
1786
- let shift_amount = r.to_i64();
1787
- if let Some(shift) = shift_amount {
1788
- if shift < 0 {
1789
- return Err(ExcType::value_error_negative_shift_count());
1790
- }
1791
- // Python allows arbitrarily large left shifts - use BigInt's shift
1792
- // Safety: shift >= 0 is guaranteed by the check above
1793
- #[expect(clippy::cast_sign_loss)]
1794
- let shift_u64 = shift as u64;
1795
- // Check size before computing to prevent DoS
1796
- check_lshift_size(l.bits(), shift_u64, heap.tracker())?;
1797
- l << shift_u64
1798
- } else if r.sign() == num_bigint::Sign::Minus {
1799
- return Err(ExcType::value_error_negative_shift_count());
1800
- } else {
1801
- // Shift amount too large to fit in i64 - this would be astronomically large
1802
- return Err(ExcType::overflow_shift_count());
1803
- }
1804
- }
1805
- BitwiseOp::RShift => {
1806
- // Get shift amount as i64 for validation
1807
- let shift_amount = r.to_i64();
1808
- if let Some(shift) = shift_amount {
1809
- if shift < 0 {
1810
- return Err(ExcType::value_error_negative_shift_count());
1811
- }
1812
- // Safety: shift >= 0 is guaranteed by the check above
1813
- #[expect(clippy::cast_sign_loss)]
1814
- let shift_u64 = shift as u64;
1815
- l >> shift_u64
1816
- } else if r.sign() == num_bigint::Sign::Minus {
1817
- return Err(ExcType::value_error_negative_shift_count());
1818
- } else {
1819
- // Shift amount too large - result is 0 or -1 depending on sign
1820
- if l.sign() == num_bigint::Sign::Minus {
1821
- BigInt::from(-1)
1822
- } else {
1823
- BigInt::from(0)
1824
- }
1825
- }
1826
- }
1827
- };
1828
- // Convert result back to Value, demoting to i64 if it fits
1829
- LongInt::new(result).into_value(heap).map_err(Into::into)
1830
- } else {
1831
- Err(ExcType::binary_type_error(op.as_str(), lhs_type, rhs_type))
1832
- }
1833
- }
1834
-
1835
- /// Clones an value with proper heap reference counting.
1836
- ///
1837
- /// For immediate values (Int, Bool, None, etc.), this performs a simple copy.
1838
- /// For heap-allocated values (Ref variant), this increments the reference count
1839
- /// and returns a new reference to the same heap value.
1840
- ///
1841
- /// Takes `ContainsHeap` to allow directly passing the `VM` in many contexts. Where
1842
- /// borrow checking creates conflicts, it may be preferred to pass `&Heap` directly
1843
- /// (e.g. as `vm.heap` / `self.heap` etc.).
1844
- ///
1845
- /// # Important
1846
- /// This method MUST be used instead of the derived `Clone` implementation to ensure
1847
- /// proper reference counting. Using `.clone()` directly will bypass reference counting
1848
- /// and cause memory leaks or double-frees.
1849
- #[must_use]
1850
- pub fn clone_with_heap(&self, heap: &impl ContainsHeap) -> Self {
1851
- match self {
1852
- Self::Ref(id) => {
1853
- heap.heap().inc_ref(*id);
1854
- Self::Ref(*id)
1855
- }
1856
- // Immediate values can be copied without heap interaction
1857
- other => other.clone_immediate(),
1858
- }
1859
- }
1860
-
1861
- /// Drops an value, decrementing its heap reference count if applicable.
1862
- ///
1863
- /// For immediate values, this is a no-op. For heap-allocated values (Ref variant),
1864
- /// this decrements the reference count and frees the value (and any children) when
1865
- /// the count reaches zero. For Closure variants, this decrements ref counts on all
1866
- /// captured cells.
1867
- ///
1868
- /// Takes `ContainsHeap` to allow directly passing the `VM` in many contexts. Where
1869
- /// borrow checking creates conflicts, it may be preferred to pass `&mut Heap` directly
1870
- /// (e.g. as `vm.heap` / `self.heap` etc.).
1871
- ///
1872
- /// # Important
1873
- /// This method MUST be called before overwriting a namespace slot or discarding
1874
- /// a value to prevent memory leaks.
1875
- #[cfg(not(feature = "ref-count-panic"))]
1876
- #[inline]
1877
- pub fn drop_with_heap(self, heap: &mut impl ContainsHeap) {
1878
- if let Self::Ref(id) = self {
1879
- heap.heap_mut().dec_ref(id);
1880
- }
1881
- }
1882
- /// With `ref-count-panic` enabled, `Ref` variants are replaced with `Dereferenced` and
1883
- /// the original is forgotten to prevent the Drop impl from panicking. Non-Ref variants
1884
- /// are left unchanged since they don't trigger the Drop panic.
1885
- #[cfg(feature = "ref-count-panic")]
1886
- pub fn drop_with_heap(mut self, heap: &mut impl ContainsHeap) {
1887
- let old = std::mem::replace(&mut self, Self::Dereferenced);
1888
- if let Self::Ref(id) = &old {
1889
- heap.heap_mut().dec_ref(*id);
1890
- std::mem::forget(old);
1891
- }
1892
- }
1893
-
1894
- /// Internal helper for copying immediate values without heap interaction.
1895
- ///
1896
- /// This method should only be called by `clone_with_heap()` for immediate values.
1897
- /// Attempting to clone a Ref variant will panic.
1898
- pub fn clone_immediate(&self) -> Self {
1899
- match self {
1900
- Self::Undefined => Self::Undefined,
1901
- Self::Ellipsis => Self::Ellipsis,
1902
- Self::None => Self::None,
1903
- Self::Bool(b) => Self::Bool(*b),
1904
- Self::Int(v) => Self::Int(*v),
1905
- Self::Float(v) => Self::Float(*v),
1906
- Self::Builtin(b) => Self::Builtin(*b),
1907
- Self::ModuleFunction(mf) => Self::ModuleFunction(*mf),
1908
- Self::DefFunction(f) => Self::DefFunction(*f),
1909
- Self::ExtFunction(f) => Self::ExtFunction(*f),
1910
- Self::InternString(s) => Self::InternString(*s),
1911
- Self::InternBytes(b) => Self::InternBytes(*b),
1912
- Self::InternLongInt(bi) => Self::InternLongInt(*bi),
1913
- Self::Marker(m) => Self::Marker(*m),
1914
- Self::Property(p) => Self::Property(*p),
1915
- Self::ExternalFuture(call_id) => Self::ExternalFuture(*call_id),
1916
- Self::Ref(_) => panic!("Ref clones must go through clone_with_heap to maintain refcounts"),
1917
- #[cfg(feature = "ref-count-panic")]
1918
- Self::Dereferenced => panic!("Cannot copy Dereferenced object"),
1919
- }
1920
- }
1921
-
1922
- /// Mark as Dereferenced to prevent Drop panic
1923
- ///
1924
- /// This should be called from `py_dec_ref_ids` methods only
1925
- #[cfg(feature = "ref-count-panic")]
1926
- pub fn dec_ref_forget(&mut self) {
1927
- let old = std::mem::replace(self, Self::Dereferenced);
1928
- std::mem::forget(old);
1929
- }
1930
-
1931
- /// Converts the value into a keyword string representation if possible.
1932
- ///
1933
- /// Returns `Some(KeywordStr)` for `InternString` values or heap `str`
1934
- /// objects, otherwise returns `None`.
1935
- pub fn as_either_str(&self, heap: &Heap<impl ResourceTracker>) -> Option<EitherStr> {
1936
- match self {
1937
- Self::InternString(id) => Some(EitherStr::Interned(*id)),
1938
- Self::Ref(heap_id) => match heap.get(*heap_id) {
1939
- HeapData::Str(s) => Some(EitherStr::Heap(s.as_str().to_owned())),
1940
- _ => None,
1941
- },
1942
- _ => None,
1943
- }
1944
- }
1945
-
1946
- /// check if the value is a string.
1947
- pub fn is_str(&self, heap: &Heap<impl ResourceTracker>) -> bool {
1948
- match self {
1949
- Self::InternString(_) => true,
1950
- Self::Ref(heap_id) => matches!(heap.get(*heap_id), HeapData::Str(_)),
1951
- _ => false,
1952
- }
1953
- }
1954
- }
1955
-
1956
- /// Interned or heap-owned string identifier.
1957
- ///
1958
- /// Used when a string value can come from either the intern table (for known
1959
- /// static strings and keywords) or from a heap-allocated Python string object.
1960
- #[derive(Debug, Clone, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize)]
1961
- pub(crate) enum EitherStr {
1962
- /// Interned string identifier (cheap comparisons and no allocation).
1963
- Interned(StringId),
1964
- /// Heap-owned string extracted from a `str` object.
1965
- Heap(String),
1966
- }
1967
-
1968
- impl From<StringId> for EitherStr {
1969
- fn from(id: StringId) -> Self {
1970
- Self::Interned(id)
1971
- }
1972
- }
1973
-
1974
- impl From<StaticStrings> for EitherStr {
1975
- fn from(s: StaticStrings) -> Self {
1976
- Self::Interned(s.into())
1977
- }
1978
- }
1979
-
1980
- /// Convert String to EitherStr: use Interned for known static strings,
1981
- /// otherwise use Heap for user-defined field names.
1982
- impl From<String> for EitherStr {
1983
- fn from(s: String) -> Self {
1984
- match StaticStrings::from_str(&s) {
1985
- Ok(s) => s.into(),
1986
- Err(_) => Self::Heap(s),
1987
- }
1988
- }
1989
- }
1990
-
1991
- impl EitherStr {
1992
- /// Returns the keyword as a str slice for error messages or comparisons.
1993
- pub fn as_str<'a>(&'a self, interns: &'a Interns) -> &'a str {
1994
- match self {
1995
- Self::Interned(id) => interns.get_str(*id),
1996
- Self::Heap(s) => s.as_str(),
1997
- }
1998
- }
1999
-
2000
- /// Checks whether this keyword matches the given interned identifier.
2001
- pub fn matches(&self, target: StringId, interns: &Interns) -> bool {
2002
- match self {
2003
- Self::Interned(id) => *id == target,
2004
- Self::Heap(s) => s == interns.get_str(target),
2005
- }
2006
- }
2007
-
2008
- /// Returns the `StringId` if this is an interned attribute.
2009
- #[inline]
2010
- pub fn string_id(&self) -> Option<StringId> {
2011
- match self {
2012
- Self::Interned(id) => Some(*id),
2013
- Self::Heap(_) => None,
2014
- }
2015
- }
2016
-
2017
- /// Returns the `StaticStrings` if this is an interned attribute from `StaticStrings`s.
2018
- #[inline]
2019
- pub fn static_string(&self) -> Option<StaticStrings> {
2020
- match self {
2021
- Self::Interned(id) => StaticStrings::from_string_id(*id),
2022
- Self::Heap(_) => None,
2023
- }
2024
- }
2025
-
2026
- /// Converts this `EitherStr` into an owned `String`.
2027
- ///
2028
- /// For interned strings, looks up and clones the string content.
2029
- /// For heap strings, returns the owned string directly.
2030
- pub fn into_string(self, interns: &Interns) -> String {
2031
- match self {
2032
- Self::Interned(id) => interns.get_str(id).to_owned(),
2033
- Self::Heap(s) => s,
2034
- }
2035
- }
2036
-
2037
- pub fn py_estimate_size(&self) -> usize {
2038
- match self {
2039
- Self::Interned(_) => 0,
2040
- Self::Heap(s) => s.capacity(),
2041
- }
2042
- }
2043
- }
2044
-
2045
- /// Bitwise operation type for `py_bitwise`.
2046
- #[derive(Debug, Clone, Copy)]
2047
- pub enum BitwiseOp {
2048
- And,
2049
- Or,
2050
- Xor,
2051
- LShift,
2052
- RShift,
2053
- }
2054
-
2055
- impl BitwiseOp {
2056
- /// Returns the operator symbol for error messages.
2057
- pub fn as_str(self) -> &'static str {
2058
- match self {
2059
- Self::And => "&",
2060
- Self::Or => "|",
2061
- Self::Xor => "^",
2062
- Self::LShift => "<<",
2063
- Self::RShift => ">>",
2064
- }
2065
- }
2066
- }
2067
-
2068
- /// Marker values for special objects that exist but have minimal functionality.
2069
- ///
2070
- /// These are used for:
2071
- /// - System objects like `sys.stdout` and `sys.stderr` that need to exist but don't
2072
- /// provide functionality in the sandboxed environment
2073
- /// - Typing constructs from the `typing` module that are imported for type hints but
2074
- /// don't need runtime functionality
2075
- ///
2076
- /// Wraps a `StaticStrings` variant to leverage its string conversion capabilities.
2077
- #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
2078
- pub(crate) struct Marker(pub StaticStrings);
2079
-
2080
- impl Marker {
2081
- /// Returns the Python type of this marker.
2082
- ///
2083
- /// System markers (stdout, stderr) are `TextIOWrapper`.
2084
- /// `typing.Union` has type `type` (matching CPython).
2085
- /// Other typing markers (Any, Optional, etc.) are `_SpecialForm`.
2086
- pub(crate) fn py_type(self) -> Type {
2087
- match self.0 {
2088
- StaticStrings::Stdout | StaticStrings::Stderr => Type::TextIOWrapper,
2089
- StaticStrings::UnionType => Type::Type,
2090
- _ => Type::SpecialForm,
2091
- }
2092
- }
2093
-
2094
- /// Writes the Python repr for this marker.
2095
- ///
2096
- /// System markers have special repr formats ("<stdout>", "<stderr>").
2097
- /// `typing.Union` uses `<class 'typing.Union'>` format (matching CPython).
2098
- /// Other typing markers are prefixed with "typing." (e.g., "typing.Any").
2099
- fn py_repr_fmt(self, f: &mut impl Write) -> fmt::Result {
2100
- let s: &'static str = self.0.into();
2101
- match self.0 {
2102
- StaticStrings::Stdout => f.write_str("<stdout>")?,
2103
- StaticStrings::Stderr => f.write_str("<stderr>")?,
2104
- StaticStrings::UnionType => f.write_str("<class 'typing.Union'>")?,
2105
- _ => write!(f, "typing.{s}")?,
2106
- }
2107
- Ok(())
2108
- }
2109
- }
2110
-
2111
- /// High-bit tag reserved for literal singletons (None, Ellipsis, booleans).
2112
- const SINGLETON_ID_TAG: usize = 1usize << (usize::BITS - 1);
2113
- /// High-bit tag reserved for interned string `id()` values.
2114
- const INTERN_STR_ID_TAG: usize = 1usize << (usize::BITS - 2);
2115
- /// High-bit tag reserved for interned bytes `id()` values to avoid colliding with any other space.
2116
- const INTERN_BYTES_ID_TAG: usize = 1usize << (usize::BITS - 3);
2117
- /// High-bit tag reserved for heap-backed `HeapId`s.
2118
- const HEAP_ID_TAG: usize = 1usize << (usize::BITS - 4);
2119
-
2120
- /// Mask that keeps pointer-derived bits below the bytes tag bit.
2121
- const INTERN_BYTES_ID_MASK: usize = INTERN_BYTES_ID_TAG - 1;
2122
- /// Mask that keeps pointer-derived bits below the string tag bit.
2123
- const INTERN_STR_ID_MASK: usize = INTERN_STR_ID_TAG - 1;
2124
- /// Mask that keeps per-singleton offsets below the singleton tag bit.
2125
- const SINGLETON_ID_MASK: usize = SINGLETON_ID_TAG - 1;
2126
- /// Mask that keeps heap value IDs below the heap tag bit.
2127
- const HEAP_ID_MASK: usize = HEAP_ID_TAG - 1;
2128
-
2129
- /// High-bit tag for Int value-based IDs (no heap allocation needed).
2130
- const INT_ID_TAG: usize = 1usize << (usize::BITS - 5);
2131
- /// High-bit tag for Float value-based IDs.
2132
- const FLOAT_ID_TAG: usize = 1usize << (usize::BITS - 6);
2133
- /// High-bit tag for Callable value-based IDs.
2134
- const BUILTIN_ID_TAG: usize = 1usize << (usize::BITS - 7);
2135
- /// High-bit tag for Function value-based IDs.
2136
- const FUNCTION_ID_TAG: usize = 1usize << (usize::BITS - 8);
2137
- /// High-bit tag for External Function value-based IDs.
2138
- const EXTFUNCTION_ID_TAG: usize = 1usize << (usize::BITS - 9);
2139
- /// High-bit tag for Marker value-based IDs (stdout, stderr, etc.).
2140
- const MARKER_ID_TAG: usize = 1usize << (usize::BITS - 10);
2141
- /// High-bit tag for ExternalFuture value-based IDs.
2142
- const EXTERNAL_FUTURE_ID_TAG: usize = 1usize << (usize::BITS - 11);
2143
- /// High-bit tag for ModuleFunction value-based IDs.
2144
- const MODULE_FUNCTION_ID_TAG: usize = 1usize << (usize::BITS - 12);
2145
- /// High-bit tag for interned LongInt `id()` values.
2146
- const INTERN_LONG_INT_ID_TAG: usize = 1usize << (usize::BITS - 13);
2147
- /// High-bit tag for Property value-based IDs.
2148
- const PROPERTY_ID_TAG: usize = 1usize << (usize::BITS - 14);
2149
-
2150
- /// Masks for value-based ID tags (keep bits below the tag bit).
2151
- const INT_ID_MASK: usize = INT_ID_TAG - 1;
2152
- const FLOAT_ID_MASK: usize = FLOAT_ID_TAG - 1;
2153
- const BUILTIN_ID_MASK: usize = BUILTIN_ID_TAG - 1;
2154
- const FUNCTION_ID_MASK: usize = FUNCTION_ID_TAG - 1;
2155
- const EXTFUNCTION_ID_MASK: usize = EXTFUNCTION_ID_TAG - 1;
2156
- const MARKER_ID_MASK: usize = MARKER_ID_TAG - 1;
2157
- const EXTERNAL_FUTURE_ID_MASK: usize = EXTERNAL_FUTURE_ID_TAG - 1;
2158
- const MODULE_FUNCTION_ID_MASK: usize = MODULE_FUNCTION_ID_TAG - 1;
2159
- const INTERN_LONG_INT_ID_MASK: usize = INTERN_LONG_INT_ID_TAG - 1;
2160
- const PROPERTY_ID_MASK: usize = PROPERTY_ID_TAG - 1;
2161
-
2162
- /// Enumerates singleton literal slots so we can issue stable `id()` values without heap allocation.
2163
- #[repr(usize)]
2164
- #[derive(Copy, Clone)]
2165
- enum SingletonSlot {
2166
- Undefined = 0,
2167
- Ellipsis = 1,
2168
- None = 2,
2169
- False = 3,
2170
- True = 4,
2171
- }
2172
-
2173
- /// Returns the fully tagged `id()` value for the requested singleton literal.
2174
- #[inline]
2175
- const fn singleton_id(slot: SingletonSlot) -> usize {
2176
- SINGLETON_ID_TAG | ((slot as usize) & SINGLETON_ID_MASK)
2177
- }
2178
-
2179
- /// Computes Python-style floor division and modulo.
2180
- ///
2181
- /// Python's division rounds toward negative infinity (floor division),
2182
- /// and the remainder has the same sign as the divisor.
2183
- /// This differs from Rust's truncating division.
2184
- ///
2185
- /// Returns `None` on overflow (i64::MIN / -1 doesn't fit in i64).
2186
- pub(crate) fn floor_divmod(a: i64, b: i64) -> Option<(i64, i64)> {
2187
- let quot = a.checked_div(b)?;
2188
- let rem = a.checked_rem(b)?;
2189
-
2190
- if rem != 0 && (rem < 0) != (b < 0) {
2191
- Some((quot - 1, rem + b))
2192
- } else {
2193
- Some((quot, rem))
2194
- }
2195
- }
2196
-
2197
- /// Converts a heap `HeapId` into its tagged `id()` value, ensuring it never collides with other spaces.
2198
- #[inline]
2199
- pub fn heap_tagged_id(heap_id: HeapId) -> usize {
2200
- HEAP_ID_TAG | (heap_id.index() & HEAP_ID_MASK)
2201
- }
2202
-
2203
- /// Computes a deterministic ID for an i64 integer value.
2204
- /// Uses the value's hash combined with a type tag to ensure uniqueness across types.
2205
- #[inline]
2206
- fn int_value_id(value: i64) -> usize {
2207
- let mut hasher = DefaultHasher::new();
2208
- value.hash(&mut hasher);
2209
- let hash_u64 = hasher.finish();
2210
- // Mask to usize range before conversion to handle 32-bit platforms
2211
- let masked = hash_u64 & (usize::MAX as u64);
2212
- let hash_usize = usize::try_from(masked).expect("masked value fits in usize");
2213
- INT_ID_TAG | (hash_usize & INT_ID_MASK)
2214
- }
2215
-
2216
- /// Computes a deterministic ID for an f64 float value.
2217
- /// Uses the bit representation's hash for consistency (handles NaN, infinities, etc.).
2218
- #[inline]
2219
- fn float_value_id(value: f64) -> usize {
2220
- let mut hasher = DefaultHasher::new();
2221
- value.to_bits().hash(&mut hasher);
2222
- let hash_u64 = hasher.finish();
2223
- // Mask to usize range before conversion to handle 32-bit platforms
2224
- let masked = hash_u64 & (usize::MAX as u64);
2225
- let hash_usize = usize::try_from(masked).expect("masked value fits in usize");
2226
- FLOAT_ID_TAG | (hash_usize & FLOAT_ID_MASK)
2227
- }
2228
-
2229
- /// Computes a deterministic ID for a builtin based on its discriminant.
2230
- #[inline]
2231
- fn builtin_value_id(b: Builtins) -> usize {
2232
- let mut hasher = DefaultHasher::new();
2233
- b.hash(&mut hasher);
2234
- let hash_u64 = hasher.finish();
2235
- // wrapping here is fine
2236
- #[expect(clippy::cast_possible_truncation)]
2237
- let hash_usize = hash_u64 as usize;
2238
- BUILTIN_ID_TAG | (hash_usize & BUILTIN_ID_MASK)
2239
- }
2240
-
2241
- /// Computes a deterministic ID for a function based on its id.
2242
- #[inline]
2243
- fn function_value_id(f_id: FunctionId) -> usize {
2244
- FUNCTION_ID_TAG | (f_id.index() & FUNCTION_ID_MASK)
2245
- }
2246
-
2247
- /// Computes a deterministic ID for an external function based on its interned name.
2248
- #[inline]
2249
- fn ext_function_value_id(name_id: StringId) -> usize {
2250
- EXTFUNCTION_ID_TAG | (name_id.index() & EXTFUNCTION_ID_MASK)
2251
- }
2252
-
2253
- /// Computes a deterministic ID for a marker value based on its discriminant.
2254
- #[inline]
2255
- fn marker_value_id(m: Marker) -> usize {
2256
- MARKER_ID_TAG | ((m.0 as usize) & MARKER_ID_MASK)
2257
- }
2258
-
2259
- /// Computes a deterministic ID for a property value based on its discriminant.
2260
- #[inline]
2261
- fn property_value_id(p: Property) -> usize {
2262
- let discriminant = match p {
2263
- Property::Os(os_fn) => os_fn as usize,
2264
- };
2265
- PROPERTY_ID_TAG | (discriminant & PROPERTY_ID_MASK)
2266
- }
2267
-
2268
- /// Computes a deterministic ID for an external future based on its call ID.
2269
- #[inline]
2270
- fn external_future_value_id(call_id: CallId) -> usize {
2271
- EXTERNAL_FUTURE_ID_TAG | ((call_id.raw() as usize) & EXTERNAL_FUTURE_ID_MASK)
2272
- }
2273
-
2274
- /// Computes a deterministic ID for a module function based on its discriminant.
2275
- #[inline]
2276
- fn module_function_value_id(mf: ModuleFunctions) -> usize {
2277
- let mut hasher = DefaultHasher::new();
2278
- mf.hash(&mut hasher);
2279
- let hash_u64 = hasher.finish();
2280
- // wrapping here is fine
2281
- #[expect(clippy::cast_possible_truncation)]
2282
- let hash_usize = hash_u64 as usize;
2283
- MODULE_FUNCTION_ID_TAG | (hash_usize & MODULE_FUNCTION_ID_MASK)
2284
- }
2285
-
2286
- /// Converts an i64 repeat count to usize, handling negative values and overflow.
2287
- ///
2288
- /// Returns 0 for negative values (Python treats negative repeat counts as 0).
2289
- /// Returns `OverflowError` if the value exceeds `usize::MAX`.
2290
- #[inline]
2291
- fn i64_to_repeat_count(n: i64) -> RunResult<usize> {
2292
- if n <= 0 {
2293
- Ok(0)
2294
- } else {
2295
- usize::try_from(n).map_err(|_| ExcType::overflow_repeat_count().into())
2296
- }
2297
- }
2298
-
2299
- /// Converts a LongInt repeat count to usize, handling negative values and overflow.
2300
- ///
2301
- /// Returns 0 for negative values (Python treats negative repeat counts as 0).
2302
- /// Returns `OverflowError` if the value exceeds `usize::MAX`.
2303
- #[inline]
2304
- fn longint_to_repeat_count(li: &LongInt) -> RunResult<usize> {
2305
- if li.is_negative() {
2306
- Ok(0)
2307
- } else if let Some(count) = li.to_usize() {
2308
- Ok(count)
2309
- } else {
2310
- Err(ExcType::overflow_repeat_count().into())
2311
- }
2312
- }
2313
-
2314
- /// Extracts a BigInt from a Value for bitwise operations.
2315
- ///
2316
- /// Returns `Some(BigInt)` for Int, Bool, and LongInt values.
2317
- /// Returns `None` for other types (Float, Str, etc.).
2318
- fn extract_bigint(value: &Value, heap: &Heap<impl ResourceTracker>) -> Option<BigInt> {
2319
- match value {
2320
- Value::Int(i) => Some(BigInt::from(*i)),
2321
- Value::Bool(b) => Some(BigInt::from(i64::from(*b))),
2322
- Value::Ref(id) => {
2323
- if let HeapData::LongInt(li) = heap.get(*id) {
2324
- Some(li.inner().clone())
2325
- } else {
2326
- None
2327
- }
2328
- }
2329
- _ => None,
2330
- }
2331
- }
2332
-
2333
- /// Extracts and clones the `(key, value)` probe accepted by `dict_items.__contains__`.
2334
- ///
2335
- /// CPython treats only 2-tuples as valid probes for items-view membership. Monty
2336
- /// also accepts namedtuples of length two so tuple-like runtime values behave
2337
- /// sensibly even though namedtuples are not modeled as a true tuple subclass.
2338
- fn cloned_items_view_candidate(item: &Value, heap: &impl ContainsHeap) -> Option<(Value, Value)> {
2339
- let Value::Ref(heap_id) = item else {
2340
- return None;
2341
- };
2342
-
2343
- match heap.heap().get(*heap_id) {
2344
- HeapData::Tuple(tuple) => {
2345
- let items = tuple.as_slice();
2346
- if items.len() == 2 {
2347
- Some((items[0].clone_with_heap(heap), items[1].clone_with_heap(heap)))
2348
- } else {
2349
- None
2350
- }
2351
- }
2352
- HeapData::NamedTuple(namedtuple) => {
2353
- let items = namedtuple.as_vec();
2354
- if items.len() == 2 {
2355
- Some((items[0].clone_with_heap(heap), items[1].clone_with_heap(heap)))
2356
- } else {
2357
- None
2358
- }
2359
- }
2360
- _ => None,
2361
- }
2362
- }
2363
-
2364
- /// Helper for substring containment check in strings.
2365
- ///
2366
- /// Called by `py_contains` when the container is a string.
2367
- /// The item must also be a string (either interned or heap-allocated).
2368
- fn str_contains(
2369
- container_str: &str,
2370
- item: &Value,
2371
- heap: &mut Heap<impl ResourceTracker>,
2372
- interns: &Interns,
2373
- ) -> RunResult<bool> {
2374
- match item {
2375
- Value::InternString(item_id) => {
2376
- let item_str = interns.get_str(*item_id);
2377
- Ok(container_str.contains(item_str))
2378
- }
2379
- Value::Ref(item_heap_id) => {
2380
- if let HeapData::Str(item_str) = heap.get(*item_heap_id) {
2381
- Ok(container_str.contains(item_str.as_str()))
2382
- } else {
2383
- Err(ExcType::type_error("'in <str>' requires string as left operand"))
2384
- }
2385
- }
2386
- _ => Err(ExcType::type_error("'in <str>' requires string as left operand")),
2387
- }
2388
- }
2389
-
2390
- /// Computes the number of significant bits in an i64.
2391
- ///
2392
- /// Returns 0 for 0, otherwise returns ceil(log2(|value|)) + 1 (accounting for sign).
2393
- /// For example: 0 -> 0, 1 -> 1, 2 -> 2, 255 -> 8, 256 -> 9.
2394
- fn i64_bits(value: i64) -> u64 {
2395
- if value == 0 {
2396
- 0
2397
- } else {
2398
- // For negative numbers, use unsigned_abs to get magnitude
2399
- u64::from(64 - value.unsigned_abs().leading_zeros())
2400
- }
2401
- }
2402
-
2403
- /// Computes BigInt exponentiation for exponents larger than u32::MAX.
2404
- ///
2405
- /// Uses repeated squaring for efficiency. This is needed when the exponent
2406
- /// doesn't fit in a u32, which is required by the `num-bigint` pow method.
2407
- fn bigint_pow(base: BigInt, exp: u64) -> BigInt {
2408
- if exp == 0 {
2409
- return BigInt::from(1);
2410
- }
2411
- if exp == 1 {
2412
- return base;
2413
- }
2414
-
2415
- // Use repeated squaring
2416
- let mut result = BigInt::from(1);
2417
- let mut b = base;
2418
- let mut e = exp;
2419
-
2420
- while e > 0 {
2421
- if e & 1 == 1 {
2422
- result *= &b;
2423
- }
2424
- b = &b * &b;
2425
- e >>= 1;
2426
- }
2427
-
2428
- result
2429
- }
2430
-
2431
- #[cfg(test)]
2432
- mod tests {
2433
- use num_bigint::BigInt;
2434
-
2435
- use super::*;
2436
- use crate::resource::NoLimitTracker;
2437
-
2438
- /// Creates a heap and directly allocates a LongInt with the given BigInt value.
2439
- ///
2440
- /// This bypasses `LongInt::into_value()` which would demote i64-fitting values.
2441
- /// Used to test defensive code paths that handle LongInt-as-index scenarios.
2442
- fn create_heap_with_longint(value: BigInt) -> (Heap<NoLimitTracker>, HeapId) {
2443
- let mut heap = Heap::new(16, NoLimitTracker);
2444
- let long_int = LongInt::new(value);
2445
- let heap_id = heap.allocate(HeapData::LongInt(long_int)).unwrap();
2446
- (heap, heap_id)
2447
- }
2448
-
2449
- /// Tests that `as_index()` correctly handles a LongInt containing an i64-fitting value.
2450
- ///
2451
- /// This tests a defensive code path that's normally unreachable because
2452
- /// `LongInt::into_value()` demotes i64-fitting values to `Value::Int`.
2453
- /// However, this path could be reached via deserialization of crafted data.
2454
- #[test]
2455
- fn as_index_longint_fits_in_i64() {
2456
- let (mut heap, heap_id) = create_heap_with_longint(BigInt::from(42));
2457
- let value = Value::Ref(heap_id);
2458
-
2459
- let result = value.as_index(&heap, Type::List);
2460
- assert_eq!(result.unwrap(), 42);
2461
- value.drop_with_heap(&mut heap);
2462
- }
2463
-
2464
- /// Tests that `as_index()` correctly handles a negative LongInt that fits in i64.
2465
- #[test]
2466
- fn as_index_longint_negative_fits_in_i64() {
2467
- let (mut heap, heap_id) = create_heap_with_longint(BigInt::from(-100));
2468
- let value = Value::Ref(heap_id);
2469
-
2470
- let result = value.as_index(&heap, Type::List);
2471
- assert_eq!(result.unwrap(), -100);
2472
- value.drop_with_heap(&mut heap);
2473
- }
2474
-
2475
- /// Tests that `as_index()` returns IndexError for LongInt values too large for i64.
2476
- #[test]
2477
- fn as_index_longint_too_large() {
2478
- // 2^100 is way larger than i64::MAX
2479
- let big_value = BigInt::from(2).pow(100);
2480
- let (mut heap, heap_id) = create_heap_with_longint(big_value);
2481
- let value = Value::Ref(heap_id);
2482
-
2483
- let result = value.as_index(&heap, Type::List);
2484
- assert!(result.is_err());
2485
- value.drop_with_heap(&mut heap);
2486
- }
2487
-
2488
- /// Tests that `as_int()` correctly handles a LongInt containing an i64-fitting value.
2489
- ///
2490
- /// Similar to `as_index`, this tests a defensive code path normally unreachable.
2491
- #[test]
2492
- fn as_int_longint_fits_in_i64() {
2493
- let (mut heap, heap_id) = create_heap_with_longint(BigInt::from(12345));
2494
- let value = Value::Ref(heap_id);
2495
-
2496
- let result = value.as_int(&heap);
2497
- assert_eq!(result.unwrap(), 12345);
2498
- value.drop_with_heap(&mut heap);
2499
- }
2500
-
2501
- /// Tests that `as_int()` returns an error for LongInt values too large for i64.
2502
- #[test]
2503
- fn as_int_longint_too_large() {
2504
- let big_value = BigInt::from(2).pow(100);
2505
- let (mut heap, heap_id) = create_heap_with_longint(big_value);
2506
- let value = Value::Ref(heap_id);
2507
-
2508
- let result = value.as_int(&heap);
2509
- assert!(result.is_err());
2510
- value.drop_with_heap(&mut heap);
2511
- }
2512
-
2513
- /// Tests boundary values: i64::MAX as a LongInt.
2514
- #[test]
2515
- fn as_index_longint_at_i64_max() {
2516
- let (mut heap, heap_id) = create_heap_with_longint(BigInt::from(i64::MAX));
2517
- let value = Value::Ref(heap_id);
2518
-
2519
- let result = value.as_index(&heap, Type::List);
2520
- assert_eq!(result.unwrap(), i64::MAX);
2521
- value.drop_with_heap(&mut heap);
2522
- }
2523
-
2524
- /// Tests boundary values: i64::MIN as a LongInt.
2525
- #[test]
2526
- fn as_index_longint_at_i64_min() {
2527
- let (mut heap, heap_id) = create_heap_with_longint(BigInt::from(i64::MIN));
2528
- let value = Value::Ref(heap_id);
2529
-
2530
- let result = value.as_index(&heap, Type::List);
2531
- assert_eq!(result.unwrap(), i64::MIN);
2532
- value.drop_with_heap(&mut heap);
2533
- }
2534
-
2535
- /// Tests boundary values: i64::MAX + 1 as a LongInt (should fail).
2536
- #[test]
2537
- fn as_index_longint_just_over_i64_max() {
2538
- let big_value = BigInt::from(i64::MAX) + BigInt::from(1);
2539
- let (mut heap, heap_id) = create_heap_with_longint(big_value);
2540
- let value = Value::Ref(heap_id);
2541
-
2542
- let result = value.as_index(&heap, Type::List);
2543
- assert!(result.is_err());
2544
- value.drop_with_heap(&mut heap);
2545
- }
2546
-
2547
- /// Tests boundary values: i64::MIN - 1 as a LongInt (should fail).
2548
- #[test]
2549
- fn as_index_longint_just_under_i64_min() {
2550
- let big_value = BigInt::from(i64::MIN) - BigInt::from(1);
2551
- let (mut heap, heap_id) = create_heap_with_longint(big_value);
2552
- let value = Value::Ref(heap_id);
2553
-
2554
- let result = value.as_index(&heap, Type::List);
2555
- assert!(result.is_err());
2556
- value.drop_with_heap(&mut heap);
2557
- }
2558
- }