superacli 1.1.6 → 1.1.7

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 (1262) hide show
  1. package/README.md +77 -53
  2. package/__tests__/azd-plugin.test.js +109 -0
  3. package/__tests__/config.test.js +4 -3
  4. package/__tests__/discover.test.js +59 -0
  5. package/__tests__/goose-plugin.test.js +149 -0
  6. package/__tests__/help-json.test.js +2 -0
  7. package/__tests__/openhands-plugin.test.js +106 -0
  8. package/__tests__/plugin-cocoindex-code-uninstall.test.js +19 -0
  9. package/__tests__/plugin-cocoindex-code.test.js +37 -0
  10. package/__tests__/plugin-install-guidance.test.js +81 -0
  11. package/__tests__/plugins-registry.test.js +44 -0
  12. package/__tests__/plugins-store.test.js +40 -5
  13. package/__tests__/process-adapter.test.js +50 -1
  14. package/__tests__/server-app.test.js +1 -0
  15. package/__tests__/server-routes-commands.test.js +20 -2
  16. package/__tests__/server-routes-plugins.test.js +130 -0
  17. package/__tests__/skills.test.js +26 -0
  18. package/__tests__/squirrelscan-plugin.test.js +129 -0
  19. package/__tests__/uipath-plugin.test.js +104 -0
  20. package/__tests__/uipathcli-plugin.test.js +95 -0
  21. package/cli/adapters/mcp.js +2 -0
  22. package/cli/adapters/process.js +49 -2
  23. package/cli/config.js +240 -3
  24. package/cli/discover.js +157 -0
  25. package/cli/help-json.js +16 -1
  26. package/cli/plugin-install-guidance.js +92 -37
  27. package/cli/plugins-manager.js +1 -0
  28. package/cli/plugins-registry.js +74 -8
  29. package/cli/plugins-store.js +78 -17
  30. package/cli/skills-mcp.js +1 -1
  31. package/cli/skills.js +39 -2
  32. package/cli/supercli.js +87 -11
  33. package/docs/feature-gaps.md +8 -8
  34. package/docs/features/azd-uipath-plugins.md +43 -0
  35. package/docs/features/server-plugins.md +62 -0
  36. package/docs/features/skills.md +9 -5
  37. package/docs/{supported-harnesses.md → plugins-available.md} +4 -3
  38. package/docs/{plugin-harness-guide.md → plugins-how-to.md} +1 -1
  39. package/docs/plugins.md +26 -20
  40. package/docs/server-plugins-usage-guide.md +182 -0
  41. package/docs/skills-catalog.md +12 -10
  42. package/package.json +1 -1
  43. package/plugins/agent-browser/README.md +69 -0
  44. package/plugins/agent-browser/plugin.json +111 -0
  45. package/plugins/agent-browser/skills/quickstart/SKILL.md +66 -0
  46. package/plugins/aider/README.md +53 -0
  47. package/plugins/aider/plugin.json +105 -0
  48. package/plugins/aider/scripts/aider-wrapper.js +243 -0
  49. package/plugins/aider/scripts/setup-aider.js +37 -0
  50. package/plugins/aider/skills/dry-run-review.md +24 -0
  51. package/plugins/aider/skills/model-and-provider.md +24 -0
  52. package/plugins/aider/skills/one-shot-edits.md +30 -0
  53. package/plugins/aider/skills/quickstart/SKILL.md +51 -0
  54. package/plugins/azd/README.md +28 -0
  55. package/plugins/azd/plugin.json +87 -0
  56. package/plugins/azd/skills/quickstart/SKILL.md +41 -0
  57. package/plugins/blogwatcher/README.md +3 -3
  58. package/plugins/boxlite/Dockerfile +9 -0
  59. package/plugins/boxlite/README.md +62 -0
  60. package/plugins/boxlite/plugin.json +201 -0
  61. package/plugins/boxlite/scripts/run-boxlite.js +106 -0
  62. package/plugins/boxlite/skills/quickstart/SKILL.md +40 -0
  63. package/plugins/cass/plugin.json +150 -0
  64. package/plugins/cass/scripts/setup-cass.js +47 -0
  65. package/plugins/cass/skills/quickstart/SKILL.md +46 -0
  66. package/plugins/clever/README.md +46 -0
  67. package/plugins/clever/plugin.json +119 -0
  68. package/plugins/clever/scripts/setup-clever.js +28 -0
  69. package/plugins/clever/skills/auth-and-profile.md +29 -0
  70. package/plugins/clever/skills/passthrough-safety.md +21 -0
  71. package/plugins/clever/skills/quickstart/SKILL.md +45 -0
  72. package/plugins/clever/skills/resource-inventory.md +24 -0
  73. package/plugins/clix/README.md +4 -4
  74. package/plugins/cocoindex-code/README.md +64 -0
  75. package/plugins/cocoindex-code/plugin.json +81 -0
  76. package/plugins/cocoindex-code/scripts/__pycache__/query.cpython-310.pyc +0 -0
  77. package/plugins/cocoindex-code/scripts/__pycache__/query.cpython-311.pyc +0 -0
  78. package/plugins/cocoindex-code/scripts/post-install.js +61 -0
  79. package/plugins/cocoindex-code/scripts/post-uninstall.js +25 -0
  80. package/plugins/cocoindex-code/scripts/query.py +88 -0
  81. package/plugins/cocoindex-code/scripts/run-query.js +50 -0
  82. package/plugins/cocoindex-code/skills/quickstart/SKILL.md +73 -0
  83. package/plugins/copilot/README.md +24 -0
  84. package/plugins/copilot/plugin.json +80 -0
  85. package/plugins/copilot/skills/quickstart/SKILL.md +44 -0
  86. package/plugins/gemini/README.md +24 -0
  87. package/plugins/gemini/plugin.json +98 -0
  88. package/plugins/gemini/skills/quickstart/SKILL.md +44 -0
  89. package/plugins/gifcap/plugin.json +119 -0
  90. package/plugins/gifcap/scripts/setup-gifcap.js +44 -0
  91. package/plugins/gifcap/skills/quickstart/SKILL.md +34 -0
  92. package/plugins/gifcap/test-record-quiet.gif +0 -0
  93. package/plugins/gifcap/test-record.gif +0 -0
  94. package/plugins/goose/README.md +36 -0
  95. package/plugins/goose/plugin.json +183 -0
  96. package/plugins/goose/skills/quickstart/SKILL.md +44 -0
  97. package/plugins/json-server/README.md +58 -0
  98. package/plugins/json-server/plugin.json +113 -0
  99. package/plugins/json-server/skills/quickstart/SKILL.md +57 -0
  100. package/plugins/lightpanda/README.md +145 -0
  101. package/plugins/lightpanda/package-lock.json +1375 -0
  102. package/plugins/lightpanda/package.json +12 -0
  103. package/plugins/lightpanda/plugin.json +116 -0
  104. package/plugins/lightpanda/scripts/lightpanda-contacts.js +494 -0
  105. package/plugins/lightpanda/scripts/lightpanda-generic-extract.js +403 -0
  106. package/plugins/lightpanda/scripts/lightpanda-wrapper.js +480 -0
  107. package/plugins/lightpanda/scripts/setup-lightpanda.js +39 -0
  108. package/plugins/lightpanda/skills/contact-discovery.md +51 -0
  109. package/plugins/lightpanda/skills/generic-extraction.md +66 -0
  110. package/plugins/lightpanda/skills/quickstart/SKILL.md +103 -0
  111. package/plugins/lightpanda/skills/resilient-navigation.md +42 -0
  112. package/plugins/monty/README.md +2 -2
  113. package/plugins/nullclaw/README.md +3 -3
  114. package/plugins/offline-ai/README.md +23 -0
  115. package/plugins/offline-ai/plugin.json +82 -0
  116. package/plugins/offline-ai/skills/quickstart/SKILL.md +43 -0
  117. package/plugins/openhands/README.md +25 -0
  118. package/plugins/openhands/plugin.json +116 -0
  119. package/plugins/openhands/skills/quickstart/SKILL.md +26 -0
  120. package/plugins/plandex/README.md +25 -0
  121. package/plugins/plandex/plugin.json +130 -0
  122. package/plugins/plandex/skills/quickstart/SKILL.md +50 -0
  123. package/plugins/plugins.json +188 -0
  124. package/plugins/squirrelscan/Dockerfile +5 -0
  125. package/plugins/squirrelscan/README.md +47 -0
  126. package/plugins/squirrelscan/plugin.json +493 -0
  127. package/plugins/squirrelscan/scripts/post-install.js +33 -0
  128. package/plugins/squirrelscan/scripts/post-uninstall.js +25 -0
  129. package/plugins/squirrelscan/scripts/run-squirrel.js +73 -0
  130. package/plugins/squirrelscan/skills/audit-workflow/SKILL.md +33 -0
  131. package/plugins/squirrelscan/skills/publish-report/SKILL.md +33 -0
  132. package/plugins/squirrelscan/skills/quickstart/SKILL.md +41 -0
  133. package/plugins/uipath/README.md +27 -0
  134. package/plugins/uipath/plugin.json +86 -0
  135. package/plugins/uipath/skills/quickstart/SKILL.md +47 -0
  136. package/plugins/uipathcli/README.md +28 -0
  137. package/plugins/uipathcli/plugin.json +120 -0
  138. package/plugins/uipathcli/scripts/run-uipath-cli.js +49 -0
  139. package/plugins/uipathcli/skills/quickstart/SKILL.md +22 -0
  140. package/plugins/xurl/README.md +4 -4
  141. package/server/app.js +5 -2
  142. package/server/public/app.js +3 -0
  143. package/server/routes/commands.js +95 -12
  144. package/server/routes/plugins.js +262 -0
  145. package/server/services/pluginsService.js +303 -0
  146. package/server/views/command-edit.ejs +196 -14
  147. package/server/views/partials/head.ejs +1 -0
  148. package/server/views/plugins.ejs +264 -0
  149. package/tests/test-plugins-registry.js +30 -0
  150. package/.beads/.br_history/issues.20260308_200823_636718328.jsonl +0 -20
  151. package/.beads/.br_history/issues.20260308_200823_636718328.jsonl.meta.json +0 -1
  152. package/.beads/.br_history/issues.20260308_200827_033159453.jsonl +0 -21
  153. package/.beads/.br_history/issues.20260308_200827_033159453.jsonl.meta.json +0 -1
  154. package/.beads/.br_history/issues.20260308_200829_595900053.jsonl +0 -22
  155. package/.beads/.br_history/issues.20260308_200829_595900053.jsonl.meta.json +0 -1
  156. package/.beads/.br_history/issues.20260308_200834_079930100.jsonl +0 -23
  157. package/.beads/.br_history/issues.20260308_200834_079930100.jsonl.meta.json +0 -1
  158. package/.beads/.br_history/issues.20260308_200858_370924996.jsonl +0 -24
  159. package/.beads/.br_history/issues.20260308_200858_370924996.jsonl.meta.json +0 -1
  160. package/.beads/.br_history/issues.20260308_201031_019730855.jsonl +0 -24
  161. package/.beads/.br_history/issues.20260308_201031_019730855.jsonl.meta.json +0 -1
  162. package/.beads/.br_history/issues.20260308_201031_578974884.jsonl +0 -24
  163. package/.beads/.br_history/issues.20260308_201031_578974884.jsonl.meta.json +0 -1
  164. package/.beads/.br_history/issues.20260308_201054_780345548.jsonl +0 -24
  165. package/.beads/.br_history/issues.20260308_201054_780345548.jsonl.meta.json +0 -1
  166. package/.beads/.br_history/issues.20260308_201054_896980019.jsonl +0 -24
  167. package/.beads/.br_history/issues.20260308_201054_896980019.jsonl.meta.json +0 -1
  168. package/.beads/.br_history/issues.20260308_201128_599819688.jsonl +0 -24
  169. package/.beads/.br_history/issues.20260308_201128_599819688.jsonl.meta.json +0 -1
  170. package/.beads/.br_history/issues.20260308_201128_710221699.jsonl +0 -24
  171. package/.beads/.br_history/issues.20260308_201128_710221699.jsonl.meta.json +0 -1
  172. package/.beads/.br_history/issues.20260308_201204_745649213.jsonl +0 -24
  173. package/.beads/.br_history/issues.20260308_201204_745649213.jsonl.meta.json +0 -1
  174. package/.beads/.br_history/issues.20260308_201338_908436144.jsonl +0 -24
  175. package/.beads/.br_history/issues.20260308_201338_908436144.jsonl.meta.json +0 -1
  176. package/.beads/.br_history/issues.20260308_201344_734860714.jsonl +0 -25
  177. package/.beads/.br_history/issues.20260308_201344_734860714.jsonl.meta.json +0 -1
  178. package/.beads/.br_history/issues.20260308_201630_819282295.jsonl +0 -25
  179. package/.beads/.br_history/issues.20260308_201630_819282295.jsonl.meta.json +0 -1
  180. package/.beads/.br_history/issues.20260308_203538_054279699.jsonl +0 -25
  181. package/.beads/.br_history/issues.20260308_203538_054279699.jsonl.meta.json +0 -1
  182. package/.beads/.br_history/issues.20260308_203547_597113070.jsonl +0 -26
  183. package/.beads/.br_history/issues.20260308_203547_597113070.jsonl.meta.json +0 -1
  184. package/.beads/.br_history/issues.20260308_203547_775139216.jsonl +0 -27
  185. package/.beads/.br_history/issues.20260308_203547_775139216.jsonl.meta.json +0 -1
  186. package/.beads/.br_history/issues.20260308_203547_950724773.jsonl +0 -28
  187. package/.beads/.br_history/issues.20260308_203547_950724773.jsonl.meta.json +0 -1
  188. package/.beads/.br_history/issues.20260308_203548_107684523.jsonl +0 -29
  189. package/.beads/.br_history/issues.20260308_203548_107684523.jsonl.meta.json +0 -1
  190. package/.beads/.br_history/issues.20260308_203548_310389993.jsonl +0 -30
  191. package/.beads/.br_history/issues.20260308_203548_310389993.jsonl.meta.json +0 -1
  192. package/.beads/.br_history/issues.20260308_203825_953337320.jsonl +0 -31
  193. package/.beads/.br_history/issues.20260308_203825_953337320.jsonl.meta.json +0 -1
  194. package/.beads/.br_history/issues.20260308_204056_071377736.jsonl +0 -32
  195. package/.beads/.br_history/issues.20260308_204056_071377736.jsonl.meta.json +0 -1
  196. package/.beads/.br_history/issues.20260308_205141_517616844.jsonl +0 -32
  197. package/.beads/.br_history/issues.20260308_205141_517616844.jsonl.meta.json +0 -1
  198. package/.beads/.br_history/issues.20260308_205141_648994024.jsonl +0 -32
  199. package/.beads/.br_history/issues.20260308_205141_648994024.jsonl.meta.json +0 -1
  200. package/.beads/.br_history/issues.20260308_205141_867598036.jsonl +0 -32
  201. package/.beads/.br_history/issues.20260308_205141_867598036.jsonl.meta.json +0 -1
  202. package/.beads/.br_history/issues.20260308_205142_094157355.jsonl +0 -32
  203. package/.beads/.br_history/issues.20260308_205142_094157355.jsonl.meta.json +0 -1
  204. package/.beads/.br_history/issues.20260308_205142_327315677.jsonl +0 -32
  205. package/.beads/.br_history/issues.20260308_205142_327315677.jsonl.meta.json +0 -1
  206. package/.beads/.br_history/issues.20260308_205142_545563822.jsonl +0 -32
  207. package/.beads/.br_history/issues.20260308_205142_545563822.jsonl.meta.json +0 -1
  208. package/.beads/.br_history/issues.20260308_205213_061989333.jsonl +0 -32
  209. package/.beads/.br_history/issues.20260308_205213_061989333.jsonl.meta.json +0 -1
  210. package/.beads/.br_history/issues.20260308_205213_181103364.jsonl +0 -32
  211. package/.beads/.br_history/issues.20260308_205213_181103364.jsonl.meta.json +0 -1
  212. package/.beads/.br_history/issues.20260308_205213_408872234.jsonl +0 -32
  213. package/.beads/.br_history/issues.20260308_205213_408872234.jsonl.meta.json +0 -1
  214. package/.beads/.br_history/issues.20260308_205213_616681652.jsonl +0 -32
  215. package/.beads/.br_history/issues.20260308_205213_616681652.jsonl.meta.json +0 -1
  216. package/.beads/.br_history/issues.20260308_205213_821507069.jsonl +0 -32
  217. package/.beads/.br_history/issues.20260308_205213_821507069.jsonl.meta.json +0 -1
  218. package/.beads/.br_history/issues.20260308_205214_026661112.jsonl +0 -32
  219. package/.beads/.br_history/issues.20260308_205214_026661112.jsonl.meta.json +0 -1
  220. package/.beads/.br_history/issues.20260308_205454_955250554.jsonl +0 -32
  221. package/.beads/.br_history/issues.20260308_205454_955250554.jsonl.meta.json +0 -1
  222. package/.beads/.br_history/issues.20260308_205556_337800392.jsonl +0 -33
  223. package/.beads/.br_history/issues.20260308_205556_337800392.jsonl.meta.json +0 -1
  224. package/.beads/.br_history/issues.20260308_205824_274686694.jsonl +0 -33
  225. package/.beads/.br_history/issues.20260308_205824_274686694.jsonl.meta.json +0 -1
  226. package/.beads/.br_history/issues.20260308_210240_583768328.jsonl +0 -34
  227. package/.beads/.br_history/issues.20260308_210240_583768328.jsonl.meta.json +0 -1
  228. package/.beads/.br_history/issues.20260308_212223_641541494.jsonl +0 -34
  229. package/.beads/.br_history/issues.20260308_212223_641541494.jsonl.meta.json +0 -1
  230. package/.beads/.br_history/issues.20260308_212227_735550996.jsonl +0 -35
  231. package/.beads/.br_history/issues.20260308_212227_735550996.jsonl.meta.json +0 -1
  232. package/.beads/.br_history/issues.20260308_212232_547298548.jsonl +0 -36
  233. package/.beads/.br_history/issues.20260308_212232_547298548.jsonl.meta.json +0 -1
  234. package/.beads/.br_history/issues.20260308_212528_843628125.jsonl +0 -37
  235. package/.beads/.br_history/issues.20260308_212528_843628125.jsonl.meta.json +0 -1
  236. package/.beads/.br_history/issues.20260308_212529_094530502.jsonl +0 -38
  237. package/.beads/.br_history/issues.20260308_212529_094530502.jsonl.meta.json +0 -1
  238. package/.beads/.br_history/issues.20260308_212529_331000853.jsonl +0 -39
  239. package/.beads/.br_history/issues.20260308_212529_331000853.jsonl.meta.json +0 -1
  240. package/.beads/.br_history/issues.20260308_212529_587925652.jsonl +0 -40
  241. package/.beads/.br_history/issues.20260308_212529_587925652.jsonl.meta.json +0 -1
  242. package/.beads/.br_history/issues.20260308_212804_927764103.jsonl +0 -41
  243. package/.beads/.br_history/issues.20260308_212804_927764103.jsonl.meta.json +0 -1
  244. package/.beads/.br_history/issues.20260308_212805_153673453.jsonl +0 -42
  245. package/.beads/.br_history/issues.20260308_212805_153673453.jsonl.meta.json +0 -1
  246. package/.beads/.br_history/issues.20260308_212805_415982363.jsonl +0 -43
  247. package/.beads/.br_history/issues.20260308_212805_415982363.jsonl.meta.json +0 -1
  248. package/.beads/.br_history/issues.20260308_212805_657497741.jsonl +0 -44
  249. package/.beads/.br_history/issues.20260308_212805_657497741.jsonl.meta.json +0 -1
  250. package/.beads/.br_history/issues.20260308_212805_952838724.jsonl +0 -45
  251. package/.beads/.br_history/issues.20260308_212805_952838724.jsonl.meta.json +0 -1
  252. package/.beads/.br_history/issues.20260308_212806_325433779.jsonl +0 -46
  253. package/.beads/.br_history/issues.20260308_212806_325433779.jsonl.meta.json +0 -1
  254. package/.beads/.br_history/issues.20260308_212806_584685598.jsonl +0 -47
  255. package/.beads/.br_history/issues.20260308_212806_584685598.jsonl.meta.json +0 -1
  256. package/.beads/.br_history/issues.20260308_212806_827817208.jsonl +0 -48
  257. package/.beads/.br_history/issues.20260308_212806_827817208.jsonl.meta.json +0 -1
  258. package/.beads/.br_history/issues.20260308_212807_111320451.jsonl +0 -49
  259. package/.beads/.br_history/issues.20260308_212807_111320451.jsonl.meta.json +0 -1
  260. package/.beads/.br_history/issues.20260308_212807_409545536.jsonl +0 -50
  261. package/.beads/.br_history/issues.20260308_212807_409545536.jsonl.meta.json +0 -1
  262. package/.beads/.br_history/issues.20260308_212807_625063294.jsonl +0 -51
  263. package/.beads/.br_history/issues.20260308_212807_625063294.jsonl.meta.json +0 -1
  264. package/.beads/.br_history/issues.20260308_212807_843906551.jsonl +0 -52
  265. package/.beads/.br_history/issues.20260308_212807_843906551.jsonl.meta.json +0 -1
  266. package/.beads/.br_history/issues.20260308_212808_100304073.jsonl +0 -53
  267. package/.beads/.br_history/issues.20260308_212808_100304073.jsonl.meta.json +0 -1
  268. package/.beads/.br_history/issues.20260308_212808_324723976.jsonl +0 -54
  269. package/.beads/.br_history/issues.20260308_212808_324723976.jsonl.meta.json +0 -1
  270. package/.beads/.br_history/issues.20260308_212808_557513104.jsonl +0 -55
  271. package/.beads/.br_history/issues.20260308_212808_557513104.jsonl.meta.json +0 -1
  272. package/.beads/.br_history/issues.20260308_212808_788048322.jsonl +0 -56
  273. package/.beads/.br_history/issues.20260308_212808_788048322.jsonl.meta.json +0 -1
  274. package/.beads/.br_history/issues.20260308_213702_613249728.jsonl +0 -57
  275. package/.beads/.br_history/issues.20260308_213702_613249728.jsonl.meta.json +0 -1
  276. package/.beads/.br_history/issues.20260308_213715_115792063.jsonl +0 -57
  277. package/.beads/.br_history/issues.20260308_213715_115792063.jsonl.meta.json +0 -1
  278. package/.beads/.br_history/issues.20260308_213715_462220666.jsonl +0 -57
  279. package/.beads/.br_history/issues.20260308_213715_462220666.jsonl.meta.json +0 -1
  280. package/.beads/.br_history/issues.20260308_213727_191258923.jsonl +0 -57
  281. package/.beads/.br_history/issues.20260308_213727_191258923.jsonl.meta.json +0 -1
  282. package/.beads/.br_history/issues.20260308_213727_684383652.jsonl +0 -57
  283. package/.beads/.br_history/issues.20260308_213727_684383652.jsonl.meta.json +0 -1
  284. package/.beads/.br_history/issues.20260308_213735_751882991.jsonl +0 -57
  285. package/.beads/.br_history/issues.20260308_213735_751882991.jsonl.meta.json +0 -1
  286. package/.beads/.br_history/issues.20260308_222052_279844960.jsonl +0 -57
  287. package/.beads/.br_history/issues.20260308_222052_279844960.jsonl.meta.json +0 -1
  288. package/.beads/.br_history/issues.20260308_222056_873282114.jsonl +0 -57
  289. package/.beads/.br_history/issues.20260308_222056_873282114.jsonl.meta.json +0 -1
  290. package/.beads/.br_history/issues.20260308_222103_402410761.jsonl +0 -57
  291. package/.beads/.br_history/issues.20260308_222103_402410761.jsonl.meta.json +0 -1
  292. package/.beads/.br_history/issues.20260308_235202_180577215.jsonl +0 -57
  293. package/.beads/.br_history/issues.20260308_235202_180577215.jsonl.meta.json +0 -1
  294. package/.beads/.br_history/issues.20260308_235202_387414163.jsonl +0 -57
  295. package/.beads/.br_history/issues.20260308_235202_387414163.jsonl.meta.json +0 -1
  296. package/.beads/.br_history/issues.20260308_235202_564422794.jsonl +0 -57
  297. package/.beads/.br_history/issues.20260308_235202_564422794.jsonl.meta.json +0 -1
  298. package/.beads/.br_history/issues.20260308_235202_742600597.jsonl +0 -57
  299. package/.beads/.br_history/issues.20260308_235202_742600597.jsonl.meta.json +0 -1
  300. package/.beads/.br_history/issues.20260308_235208_133360069.jsonl +0 -57
  301. package/.beads/.br_history/issues.20260308_235208_133360069.jsonl.meta.json +0 -1
  302. package/.beads/.br_history/issues.20260308_235505_473406307.jsonl +0 -57
  303. package/.beads/.br_history/issues.20260308_235505_473406307.jsonl.meta.json +0 -1
  304. package/.beads/.br_history/issues.20260308_235505_662360489.jsonl +0 -57
  305. package/.beads/.br_history/issues.20260308_235505_662360489.jsonl.meta.json +0 -1
  306. package/.beads/.br_history/issues.20260308_235505_843935624.jsonl +0 -57
  307. package/.beads/.br_history/issues.20260308_235505_843935624.jsonl.meta.json +0 -1
  308. package/.beads/.br_history/issues.20260308_235506_044530221.jsonl +0 -57
  309. package/.beads/.br_history/issues.20260308_235506_044530221.jsonl.meta.json +0 -1
  310. package/.beads/.br_history/issues.20260309_002618_115728731.jsonl +0 -57
  311. package/.beads/.br_history/issues.20260309_002618_115728731.jsonl.meta.json +0 -1
  312. package/.beads/.br_history/issues.20260309_003748_878174586.jsonl +0 -57
  313. package/.beads/.br_history/issues.20260309_003748_878174586.jsonl.meta.json +0 -1
  314. package/.beads/.br_history/issues.20260309_004057_868755623.jsonl +0 -57
  315. package/.beads/.br_history/issues.20260309_004057_868755623.jsonl.meta.json +0 -1
  316. package/.beads/.br_history/issues.20260309_004058_512842163.jsonl +0 -57
  317. package/.beads/.br_history/issues.20260309_004058_512842163.jsonl.meta.json +0 -1
  318. package/.beads/.br_history/issues.20260309_004058_994445226.jsonl +0 -57
  319. package/.beads/.br_history/issues.20260309_004058_994445226.jsonl.meta.json +0 -1
  320. package/.beads/.br_history/issues.20260309_004059_475988596.jsonl +0 -57
  321. package/.beads/.br_history/issues.20260309_004059_475988596.jsonl.meta.json +0 -1
  322. package/.beads/.br_history/issues.20260309_161902_566857851.jsonl +0 -57
  323. package/.beads/.br_history/issues.20260309_161902_566857851.jsonl.meta.json +0 -1
  324. package/.beads/.br_history/issues.20260309_170512_277017739.jsonl +0 -57
  325. package/.beads/.br_history/issues.20260309_170512_277017739.jsonl.meta.json +0 -1
  326. package/.beads/.br_history/issues.20260309_170512_477876921.jsonl +0 -57
  327. package/.beads/.br_history/issues.20260309_170512_477876921.jsonl.meta.json +0 -1
  328. package/.beads/.br_history/issues.20260309_170512_664382701.jsonl +0 -57
  329. package/.beads/.br_history/issues.20260309_170512_664382701.jsonl.meta.json +0 -1
  330. package/.beads/.br_history/issues.20260309_170512_859400333.jsonl +0 -57
  331. package/.beads/.br_history/issues.20260309_170512_859400333.jsonl.meta.json +0 -1
  332. package/.beads/.br_history/issues.20260309_212326_082771164.jsonl +0 -57
  333. package/.beads/.br_history/issues.20260309_212326_082771164.jsonl.meta.json +0 -1
  334. package/.beads/.br_history/issues.20260309_212326_245619716.jsonl +0 -58
  335. package/.beads/.br_history/issues.20260309_212326_245619716.jsonl.meta.json +0 -1
  336. package/.beads/.br_history/issues.20260309_212326_403198317.jsonl +0 -59
  337. package/.beads/.br_history/issues.20260309_212326_403198317.jsonl.meta.json +0 -1
  338. package/.beads/.br_history/issues.20260309_212332_539197678.jsonl +0 -60
  339. package/.beads/.br_history/issues.20260309_212332_539197678.jsonl.meta.json +0 -1
  340. package/.beads/.br_history/issues.20260309_212332_731373599.jsonl +0 -60
  341. package/.beads/.br_history/issues.20260309_212332_731373599.jsonl.meta.json +0 -1
  342. package/.beads/.br_history/issues.20260309_212332_928710953.jsonl +0 -60
  343. package/.beads/.br_history/issues.20260309_212332_928710953.jsonl.meta.json +0 -1
  344. package/.beads/.br_history/issues.20260309_213021_341505240.jsonl +0 -60
  345. package/.beads/.br_history/issues.20260309_213021_341505240.jsonl.meta.json +0 -1
  346. package/.beads/.br_history/issues.20260309_213022_023136934.jsonl +0 -60
  347. package/.beads/.br_history/issues.20260309_213022_023136934.jsonl.meta.json +0 -1
  348. package/.beads/.br_history/issues.20260309_213022_400050719.jsonl +0 -60
  349. package/.beads/.br_history/issues.20260309_213022_400050719.jsonl.meta.json +0 -1
  350. package/.beads/config.yaml +0 -4
  351. package/.beads/issues.jsonl +0 -60
  352. package/.beads/metadata.json +0 -4
  353. package/docs/mcp-cheatsheet.md +0 -324
  354. package/docs/visual-overview.md +0 -21
  355. package/ref-monty/.cargo/config.toml +0 -3
  356. package/ref-monty/.claude/settings.json +0 -60
  357. package/ref-monty/.claude/skills/fastmod/SKILL.md +0 -22
  358. package/ref-monty/.claude/skills/python-playground/SKILL.md +0 -47
  359. package/ref-monty/.codecov.yml +0 -12
  360. package/ref-monty/.github/actions/build-pgo-wheel/action.yml +0 -72
  361. package/ref-monty/.github/workflows/ci.yml +0 -776
  362. package/ref-monty/.github/workflows/codspeed.yml +0 -45
  363. package/ref-monty/.github/workflows/init-npm-packages.yml +0 -82
  364. package/ref-monty/.pre-commit-config.yaml +0 -47
  365. package/ref-monty/.python-version +0 -1
  366. package/ref-monty/.rustfmt.toml +0 -4
  367. package/ref-monty/.zed/settings.json +0 -11
  368. package/ref-monty/CLAUDE.md +0 -535
  369. package/ref-monty/Cargo.lock +0 -3798
  370. package/ref-monty/Cargo.toml +0 -87
  371. package/ref-monty/LICENSE +0 -21
  372. package/ref-monty/Makefile +0 -216
  373. package/ref-monty/README.md +0 -430
  374. package/ref-monty/RELEASING.md +0 -47
  375. package/ref-monty/crates/fuzz/Cargo.toml +0 -30
  376. package/ref-monty/crates/fuzz/fuzz_targets/string_input_panic.rs +0 -37
  377. package/ref-monty/crates/fuzz/fuzz_targets/tokens_input_panic.rs +0 -552
  378. package/ref-monty/crates/monty/Cargo.toml +0 -68
  379. package/ref-monty/crates/monty/benches/main.rs +0 -247
  380. package/ref-monty/crates/monty/build.rs +0 -10
  381. package/ref-monty/crates/monty/src/args.rs +0 -733
  382. package/ref-monty/crates/monty/src/asyncio.rs +0 -179
  383. package/ref-monty/crates/monty/src/builtins/abs.rs +0 -55
  384. package/ref-monty/crates/monty/src/builtins/all.rs +0 -30
  385. package/ref-monty/crates/monty/src/builtins/any.rs +0 -30
  386. package/ref-monty/crates/monty/src/builtins/bin.rs +0 -59
  387. package/ref-monty/crates/monty/src/builtins/chr.rs +0 -46
  388. package/ref-monty/crates/monty/src/builtins/divmod.rs +0 -164
  389. package/ref-monty/crates/monty/src/builtins/enumerate.rs +0 -52
  390. package/ref-monty/crates/monty/src/builtins/filter.rs +0 -67
  391. package/ref-monty/crates/monty/src/builtins/getattr.rs +0 -65
  392. package/ref-monty/crates/monty/src/builtins/hash.rs +0 -28
  393. package/ref-monty/crates/monty/src/builtins/hex.rs +0 -58
  394. package/ref-monty/crates/monty/src/builtins/id.rs +0 -24
  395. package/ref-monty/crates/monty/src/builtins/isinstance.rs +0 -68
  396. package/ref-monty/crates/monty/src/builtins/len.rs +0 -25
  397. package/ref-monty/crates/monty/src/builtins/map.rs +0 -98
  398. package/ref-monty/crates/monty/src/builtins/min_max.rs +0 -113
  399. package/ref-monty/crates/monty/src/builtins/mod.rs +0 -246
  400. package/ref-monty/crates/monty/src/builtins/next.rs +0 -21
  401. package/ref-monty/crates/monty/src/builtins/oct.rs +0 -59
  402. package/ref-monty/crates/monty/src/builtins/ord.rs +0 -67
  403. package/ref-monty/crates/monty/src/builtins/pow.rs +0 -365
  404. package/ref-monty/crates/monty/src/builtins/print.rs +0 -141
  405. package/ref-monty/crates/monty/src/builtins/repr.rs +0 -16
  406. package/ref-monty/crates/monty/src/builtins/reversed.rs +0 -28
  407. package/ref-monty/crates/monty/src/builtins/round.rs +0 -174
  408. package/ref-monty/crates/monty/src/builtins/sorted.rs +0 -151
  409. package/ref-monty/crates/monty/src/builtins/sum.rs +0 -66
  410. package/ref-monty/crates/monty/src/builtins/type_.rs +0 -16
  411. package/ref-monty/crates/monty/src/builtins/zip.rs +0 -77
  412. package/ref-monty/crates/monty/src/bytecode/builder.rs +0 -699
  413. package/ref-monty/crates/monty/src/bytecode/code.rs +0 -310
  414. package/ref-monty/crates/monty/src/bytecode/compiler.rs +0 -3206
  415. package/ref-monty/crates/monty/src/bytecode/mod.rs +0 -24
  416. package/ref-monty/crates/monty/src/bytecode/op.rs +0 -617
  417. package/ref-monty/crates/monty/src/bytecode/vm/async_exec.rs +0 -1058
  418. package/ref-monty/crates/monty/src/bytecode/vm/attr.rs +0 -63
  419. package/ref-monty/crates/monty/src/bytecode/vm/binary.rs +0 -487
  420. package/ref-monty/crates/monty/src/bytecode/vm/call.rs +0 -767
  421. package/ref-monty/crates/monty/src/bytecode/vm/collections.rs +0 -741
  422. package/ref-monty/crates/monty/src/bytecode/vm/compare.rs +0 -147
  423. package/ref-monty/crates/monty/src/bytecode/vm/exceptions.rs +0 -297
  424. package/ref-monty/crates/monty/src/bytecode/vm/format.rs +0 -132
  425. package/ref-monty/crates/monty/src/bytecode/vm/mod.rs +0 -1958
  426. package/ref-monty/crates/monty/src/bytecode/vm/scheduler.rs +0 -620
  427. package/ref-monty/crates/monty/src/exception_private.rs +0 -1513
  428. package/ref-monty/crates/monty/src/exception_public.rs +0 -346
  429. package/ref-monty/crates/monty/src/expressions.rs +0 -694
  430. package/ref-monty/crates/monty/src/fstring.rs +0 -854
  431. package/ref-monty/crates/monty/src/function.rs +0 -119
  432. package/ref-monty/crates/monty/src/heap.rs +0 -1073
  433. package/ref-monty/crates/monty/src/heap_data.rs +0 -985
  434. package/ref-monty/crates/monty/src/heap_traits.rs +0 -312
  435. package/ref-monty/crates/monty/src/intern.rs +0 -837
  436. package/ref-monty/crates/monty/src/io.rs +0 -106
  437. package/ref-monty/crates/monty/src/lib.rs +0 -52
  438. package/ref-monty/crates/monty/src/modules/asyncio.rs +0 -144
  439. package/ref-monty/crates/monty/src/modules/math.rs +0 -1453
  440. package/ref-monty/crates/monty/src/modules/mod.rs +0 -120
  441. package/ref-monty/crates/monty/src/modules/os.rs +0 -116
  442. package/ref-monty/crates/monty/src/modules/pathlib.rs +0 -33
  443. package/ref-monty/crates/monty/src/modules/re.rs +0 -606
  444. package/ref-monty/crates/monty/src/modules/sys.rs +0 -60
  445. package/ref-monty/crates/monty/src/modules/typing.rs +0 -70
  446. package/ref-monty/crates/monty/src/namespace.rs +0 -21
  447. package/ref-monty/crates/monty/src/object.rs +0 -1040
  448. package/ref-monty/crates/monty/src/os.rs +0 -215
  449. package/ref-monty/crates/monty/src/parse.rs +0 -1730
  450. package/ref-monty/crates/monty/src/prepare.rs +0 -3015
  451. package/ref-monty/crates/monty/src/repl.rs +0 -1109
  452. package/ref-monty/crates/monty/src/resource.rs +0 -559
  453. package/ref-monty/crates/monty/src/run.rs +0 -457
  454. package/ref-monty/crates/monty/src/run_progress.rs +0 -821
  455. package/ref-monty/crates/monty/src/signature.rs +0 -651
  456. package/ref-monty/crates/monty/src/sorting.rs +0 -100
  457. package/ref-monty/crates/monty/src/types/bytes.rs +0 -2356
  458. package/ref-monty/crates/monty/src/types/dataclass.rs +0 -345
  459. package/ref-monty/crates/monty/src/types/dict.rs +0 -879
  460. package/ref-monty/crates/monty/src/types/dict_view.rs +0 -619
  461. package/ref-monty/crates/monty/src/types/iter.rs +0 -799
  462. package/ref-monty/crates/monty/src/types/list.rs +0 -929
  463. package/ref-monty/crates/monty/src/types/long_int.rs +0 -211
  464. package/ref-monty/crates/monty/src/types/mod.rs +0 -48
  465. package/ref-monty/crates/monty/src/types/module.rs +0 -146
  466. package/ref-monty/crates/monty/src/types/namedtuple.rs +0 -261
  467. package/ref-monty/crates/monty/src/types/path.rs +0 -596
  468. package/ref-monty/crates/monty/src/types/property.rs +0 -35
  469. package/ref-monty/crates/monty/src/types/py_trait.rs +0 -322
  470. package/ref-monty/crates/monty/src/types/range.rs +0 -285
  471. package/ref-monty/crates/monty/src/types/re_match.rs +0 -522
  472. package/ref-monty/crates/monty/src/types/re_pattern.rs +0 -726
  473. package/ref-monty/crates/monty/src/types/set.rs +0 -1373
  474. package/ref-monty/crates/monty/src/types/slice.rs +0 -257
  475. package/ref-monty/crates/monty/src/types/str.rs +0 -2051
  476. package/ref-monty/crates/monty/src/types/tuple.rs +0 -376
  477. package/ref-monty/crates/monty/src/types/type.rs +0 -407
  478. package/ref-monty/crates/monty/src/value.rs +0 -2558
  479. package/ref-monty/crates/monty/test_cases/args__dict_get_no_args.py +0 -3
  480. package/ref-monty/crates/monty/test_cases/args__dict_get_too_many.py +0 -3
  481. package/ref-monty/crates/monty/test_cases/args__dict_items_with_args.py +0 -3
  482. package/ref-monty/crates/monty/test_cases/args__dict_keys_with_args.py +0 -3
  483. package/ref-monty/crates/monty/test_cases/args__dict_pop_no_args.py +0 -3
  484. package/ref-monty/crates/monty/test_cases/args__dict_pop_too_many.py +0 -3
  485. package/ref-monty/crates/monty/test_cases/args__dict_values_with_args.py +0 -3
  486. package/ref-monty/crates/monty/test_cases/args__id_too_many.py +0 -2
  487. package/ref-monty/crates/monty/test_cases/args__len_no_args.py +0 -2
  488. package/ref-monty/crates/monty/test_cases/args__len_too_many.py +0 -2
  489. package/ref-monty/crates/monty/test_cases/args__len_type_error_int.py +0 -9
  490. package/ref-monty/crates/monty/test_cases/args__len_type_error_none.py +0 -9
  491. package/ref-monty/crates/monty/test_cases/args__list_append_no_args.py +0 -3
  492. package/ref-monty/crates/monty/test_cases/args__list_append_too_many.py +0 -3
  493. package/ref-monty/crates/monty/test_cases/args__list_insert_too_few.py +0 -3
  494. package/ref-monty/crates/monty/test_cases/args__list_insert_too_many.py +0 -3
  495. package/ref-monty/crates/monty/test_cases/args__repr_no_args.py +0 -2
  496. package/ref-monty/crates/monty/test_cases/arith__div_zero_float.py +0 -2
  497. package/ref-monty/crates/monty/test_cases/arith__div_zero_int.py +0 -2
  498. package/ref-monty/crates/monty/test_cases/arith__floordiv_zero_float.py +0 -2
  499. package/ref-monty/crates/monty/test_cases/arith__floordiv_zero_int.py +0 -2
  500. package/ref-monty/crates/monty/test_cases/arith__pow_zero_neg.py +0 -2
  501. package/ref-monty/crates/monty/test_cases/arith__pow_zero_neg_builtin.py +0 -9
  502. package/ref-monty/crates/monty/test_cases/assert__expr_fail.py +0 -2
  503. package/ref-monty/crates/monty/test_cases/assert__fail.py +0 -2
  504. package/ref-monty/crates/monty/test_cases/assert__fail_msg.py +0 -2
  505. package/ref-monty/crates/monty/test_cases/assert__fn_fail.py +0 -3
  506. package/ref-monty/crates/monty/test_cases/assert__ops.py +0 -11
  507. package/ref-monty/crates/monty/test_cases/async__asyncio_run.py +0 -47
  508. package/ref-monty/crates/monty/test_cases/async__basic.py +0 -10
  509. package/ref-monty/crates/monty/test_cases/async__closure.py +0 -14
  510. package/ref-monty/crates/monty/test_cases/async__double_await_coroutine.py +0 -16
  511. package/ref-monty/crates/monty/test_cases/async__exception.py +0 -10
  512. package/ref-monty/crates/monty/test_cases/async__ext_call.py +0 -73
  513. package/ref-monty/crates/monty/test_cases/async__gather_all.py +0 -85
  514. package/ref-monty/crates/monty/test_cases/async__nested_await.py +0 -15
  515. package/ref-monty/crates/monty/test_cases/async__nested_gather_ext.py +0 -37
  516. package/ref-monty/crates/monty/test_cases/async__not_awaitable.py +0 -10
  517. package/ref-monty/crates/monty/test_cases/async__not_imported.py +0 -14
  518. package/ref-monty/crates/monty/test_cases/async__recursion_depth_isolation.py +0 -27
  519. package/ref-monty/crates/monty/test_cases/async__return_types.py +0 -31
  520. package/ref-monty/crates/monty/test_cases/async__sequential.py +0 -16
  521. package/ref-monty/crates/monty/test_cases/async__traceback.py +0 -19
  522. package/ref-monty/crates/monty/test_cases/async__with_args.py +0 -14
  523. package/ref-monty/crates/monty/test_cases/attr__get_int_error.py +0 -9
  524. package/ref-monty/crates/monty/test_cases/attr__get_list_error.py +0 -9
  525. package/ref-monty/crates/monty/test_cases/attr__set_frozen_nonfield.py +0 -12
  526. package/ref-monty/crates/monty/test_cases/attr__set_int_error.py +0 -10
  527. package/ref-monty/crates/monty/test_cases/attr__set_list_error.py +0 -10
  528. package/ref-monty/crates/monty/test_cases/bench__kitchen_sink.py +0 -68
  529. package/ref-monty/crates/monty/test_cases/bool__ops.py +0 -20
  530. package/ref-monty/crates/monty/test_cases/builtin__add_type_error.py +0 -2
  531. package/ref-monty/crates/monty/test_cases/builtin__filter.py +0 -62
  532. package/ref-monty/crates/monty/test_cases/builtin__filter_not_iterable.py +0 -11
  533. package/ref-monty/crates/monty/test_cases/builtin__getattr.py +0 -84
  534. package/ref-monty/crates/monty/test_cases/builtin__iter_funcs.py +0 -42
  535. package/ref-monty/crates/monty/test_cases/builtin__iter_next.py +0 -66
  536. package/ref-monty/crates/monty/test_cases/builtin__map.py +0 -74
  537. package/ref-monty/crates/monty/test_cases/builtin__map_not_iterable.py +0 -11
  538. package/ref-monty/crates/monty/test_cases/builtin__math_funcs.py +0 -154
  539. package/ref-monty/crates/monty/test_cases/builtin__more_iter_funcs.py +0 -148
  540. package/ref-monty/crates/monty/test_cases/builtin__next_stop_iteration.py +0 -10
  541. package/ref-monty/crates/monty/test_cases/builtin__print_invalid_kwarg.py +0 -9
  542. package/ref-monty/crates/monty/test_cases/builtin__print_kwargs.py +0 -12
  543. package/ref-monty/crates/monty/test_cases/builtin__repr.py +0 -3
  544. package/ref-monty/crates/monty/test_cases/builtin__string_funcs.py +0 -73
  545. package/ref-monty/crates/monty/test_cases/bytes__decode_invalid_utf8.py +0 -18
  546. package/ref-monty/crates/monty/test_cases/bytes__endswith_str_error.py +0 -10
  547. package/ref-monty/crates/monty/test_cases/bytes__getitem_index_error.py +0 -10
  548. package/ref-monty/crates/monty/test_cases/bytes__index_start_gt_end.py +0 -10
  549. package/ref-monty/crates/monty/test_cases/bytes__methods.py +0 -394
  550. package/ref-monty/crates/monty/test_cases/bytes__negative_count.py +0 -9
  551. package/ref-monty/crates/monty/test_cases/bytes__ops.py +0 -90
  552. package/ref-monty/crates/monty/test_cases/bytes__startswith_str_error.py +0 -10
  553. package/ref-monty/crates/monty/test_cases/call_object.py +0 -3
  554. package/ref-monty/crates/monty/test_cases/chain_comparison__all.py +0 -79
  555. package/ref-monty/crates/monty/test_cases/closure__param_shadows_outer.py +0 -81
  556. package/ref-monty/crates/monty/test_cases/closure__pep448.py +0 -203
  557. package/ref-monty/crates/monty/test_cases/closure__undefined_nonlocal.py +0 -13
  558. package/ref-monty/crates/monty/test_cases/compare__mixed_types.py +0 -120
  559. package/ref-monty/crates/monty/test_cases/comprehension__all.py +0 -208
  560. package/ref-monty/crates/monty/test_cases/comprehension__scope.py +0 -7
  561. package/ref-monty/crates/monty/test_cases/comprehension__unbound_local.py +0 -14
  562. package/ref-monty/crates/monty/test_cases/dataclass__basic.py +0 -238
  563. package/ref-monty/crates/monty/test_cases/dataclass__call_field_error.py +0 -12
  564. package/ref-monty/crates/monty/test_cases/dataclass__frozen_set_error.py +0 -12
  565. package/ref-monty/crates/monty/test_cases/dataclass__get_missing_attr_error.py +0 -11
  566. package/ref-monty/crates/monty/test_cases/dict__get_unhashable_key.py +0 -3
  567. package/ref-monty/crates/monty/test_cases/dict__literal_unhashable_key.py +0 -2
  568. package/ref-monty/crates/monty/test_cases/dict__method_pop_missing_error.py +0 -3
  569. package/ref-monty/crates/monty/test_cases/dict__methods.py +0 -151
  570. package/ref-monty/crates/monty/test_cases/dict__ops.py +0 -133
  571. package/ref-monty/crates/monty/test_cases/dict__pop_unhashable_key.py +0 -4
  572. package/ref-monty/crates/monty/test_cases/dict__popitem_empty.py +0 -9
  573. package/ref-monty/crates/monty/test_cases/dict__subscript_missing_key.py +0 -3
  574. package/ref-monty/crates/monty/test_cases/dict__unhashable_dict_key.py +0 -2
  575. package/ref-monty/crates/monty/test_cases/dict__unhashable_list_key.py +0 -2
  576. package/ref-monty/crates/monty/test_cases/dict__unpack_type_error.py +0 -2
  577. package/ref-monty/crates/monty/test_cases/dict__views.py +0 -165
  578. package/ref-monty/crates/monty/test_cases/edge__all.py +0 -26
  579. package/ref-monty/crates/monty/test_cases/edge__float_int_mod.py +0 -2
  580. package/ref-monty/crates/monty/test_cases/edge__int_float_mod.py +0 -2
  581. package/ref-monty/crates/monty/test_cases/exc__args.py +0 -16
  582. package/ref-monty/crates/monty/test_cases/exc__str.py +0 -15
  583. package/ref-monty/crates/monty/test_cases/execute_ok__all.py +0 -54
  584. package/ref-monty/crates/monty/test_cases/execute_raise__error_instance_str.py +0 -2
  585. package/ref-monty/crates/monty/test_cases/execute_raise__error_no_args.py +0 -2
  586. package/ref-monty/crates/monty/test_cases/execute_raise__error_string_arg.py +0 -2
  587. package/ref-monty/crates/monty/test_cases/execute_raise__error_string_arg_quotes.py +0 -2
  588. package/ref-monty/crates/monty/test_cases/execute_raise__error_type.py +0 -2
  589. package/ref-monty/crates/monty/test_cases/execute_raise__raise_instance_via_var.py +0 -4
  590. package/ref-monty/crates/monty/test_cases/execute_raise__raise_list.py +0 -2
  591. package/ref-monty/crates/monty/test_cases/execute_raise__raise_number.py +0 -2
  592. package/ref-monty/crates/monty/test_cases/execute_raise__raise_type_call_via_var.py +0 -4
  593. package/ref-monty/crates/monty/test_cases/execute_raise__raise_type_direct.py +0 -3
  594. package/ref-monty/crates/monty/test_cases/execute_raise__raise_type_via_var.py +0 -4
  595. package/ref-monty/crates/monty/test_cases/ext_call__arg_side_effect_bug.py +0 -22
  596. package/ref-monty/crates/monty/test_cases/ext_call__augmented.py +0 -17
  597. package/ref-monty/crates/monty/test_cases/ext_call__augmented_refcount_bug.py +0 -7
  598. package/ref-monty/crates/monty/test_cases/ext_call__bare_raise_after_resume.py +0 -34
  599. package/ref-monty/crates/monty/test_cases/ext_call__basic.py +0 -99
  600. package/ref-monty/crates/monty/test_cases/ext_call__boolean.py +0 -37
  601. package/ref-monty/crates/monty/test_cases/ext_call__boolean_side_effect_hang.py +0 -17
  602. package/ref-monty/crates/monty/test_cases/ext_call__closure_bug.py +0 -16
  603. package/ref-monty/crates/monty/test_cases/ext_call__comparison.py +0 -26
  604. package/ref-monty/crates/monty/test_cases/ext_call__deep_call_stack.py +0 -18
  605. package/ref-monty/crates/monty/test_cases/ext_call__elif.py +0 -171
  606. package/ref-monty/crates/monty/test_cases/ext_call__exc.py +0 -4
  607. package/ref-monty/crates/monty/test_cases/ext_call__exc_deep_stack.py +0 -39
  608. package/ref-monty/crates/monty/test_cases/ext_call__exc_in_function.py +0 -17
  609. package/ref-monty/crates/monty/test_cases/ext_call__exc_nested_functions.py +0 -31
  610. package/ref-monty/crates/monty/test_cases/ext_call__ext_exc.py +0 -171
  611. package/ref-monty/crates/monty/test_cases/ext_call__for.py +0 -114
  612. package/ref-monty/crates/monty/test_cases/ext_call__fstring.py +0 -12
  613. package/ref-monty/crates/monty/test_cases/ext_call__if.py +0 -135
  614. package/ref-monty/crates/monty/test_cases/ext_call__if_condition.py +0 -37
  615. package/ref-monty/crates/monty/test_cases/ext_call__in_closure.py +0 -14
  616. package/ref-monty/crates/monty/test_cases/ext_call__in_function.py +0 -40
  617. package/ref-monty/crates/monty/test_cases/ext_call__in_function_simple.py +0 -7
  618. package/ref-monty/crates/monty/test_cases/ext_call__literals.py +0 -17
  619. package/ref-monty/crates/monty/test_cases/ext_call__multi_in_func.py +0 -32
  620. package/ref-monty/crates/monty/test_cases/ext_call__name_lookup.py +0 -69
  621. package/ref-monty/crates/monty/test_cases/ext_call__name_lookup_undefined.py +0 -4
  622. package/ref-monty/crates/monty/test_cases/ext_call__nested_calls.py +0 -14
  623. package/ref-monty/crates/monty/test_cases/ext_call__recursion_bug.py +0 -19
  624. package/ref-monty/crates/monty/test_cases/ext_call__return.py +0 -28
  625. package/ref-monty/crates/monty/test_cases/ext_call__side_effects.py +0 -25
  626. package/ref-monty/crates/monty/test_cases/ext_call__subscript.py +0 -7
  627. package/ref-monty/crates/monty/test_cases/ext_call__ternary.py +0 -28
  628. package/ref-monty/crates/monty/test_cases/ext_call__try.py +0 -280
  629. package/ref-monty/crates/monty/test_cases/ext_call__try_simple.py +0 -10
  630. package/ref-monty/crates/monty/test_cases/ext_call__unary.py +0 -13
  631. package/ref-monty/crates/monty/test_cases/frozenset__ops.py +0 -178
  632. package/ref-monty/crates/monty/test_cases/fstring__all.py +0 -236
  633. package/ref-monty/crates/monty/test_cases/fstring__error_eq_align_on_str.py +0 -3
  634. package/ref-monty/crates/monty/test_cases/fstring__error_float_f_on_str.py +0 -3
  635. package/ref-monty/crates/monty/test_cases/fstring__error_int_d_on_float.py +0 -3
  636. package/ref-monty/crates/monty/test_cases/fstring__error_int_d_on_str.py +0 -3
  637. package/ref-monty/crates/monty/test_cases/fstring__error_invalid_spec.py +0 -4
  638. package/ref-monty/crates/monty/test_cases/fstring__error_invalid_spec_dynamic.py +0 -4
  639. package/ref-monty/crates/monty/test_cases/fstring__error_invalid_spec_str.py +0 -4
  640. package/ref-monty/crates/monty/test_cases/fstring__error_str_s_on_int.py +0 -3
  641. package/ref-monty/crates/monty/test_cases/function__call_duplicate_kwargs.py +0 -6
  642. package/ref-monty/crates/monty/test_cases/function__call_unpack.py +0 -42
  643. package/ref-monty/crates/monty/test_cases/function__defaults.py +0 -117
  644. package/ref-monty/crates/monty/test_cases/function__err_duplicate_arg.py +0 -7
  645. package/ref-monty/crates/monty/test_cases/function__err_duplicate_first_arg.py +0 -7
  646. package/ref-monty/crates/monty/test_cases/function__err_duplicate_kwarg_cleanup.py +0 -9
  647. package/ref-monty/crates/monty/test_cases/function__err_kwonly_as_positional.py +0 -7
  648. package/ref-monty/crates/monty/test_cases/function__err_missing_all_posonly.py +0 -7
  649. package/ref-monty/crates/monty/test_cases/function__err_missing_heap_cleanup.py +0 -9
  650. package/ref-monty/crates/monty/test_cases/function__err_missing_kwonly.py +0 -7
  651. package/ref-monty/crates/monty/test_cases/function__err_missing_posonly_with_kwarg.py +0 -7
  652. package/ref-monty/crates/monty/test_cases/function__err_missing_with_posonly.py +0 -7
  653. package/ref-monty/crates/monty/test_cases/function__err_posonly_as_kwarg.py +0 -7
  654. package/ref-monty/crates/monty/test_cases/function__err_posonly_first_as_kwarg.py +0 -7
  655. package/ref-monty/crates/monty/test_cases/function__err_too_many_posonly.py +0 -7
  656. package/ref-monty/crates/monty/test_cases/function__err_too_many_with_kwonly.py +0 -7
  657. package/ref-monty/crates/monty/test_cases/function__err_unexpected_kwarg.py +0 -7
  658. package/ref-monty/crates/monty/test_cases/function__err_unexpected_kwarg_cleanup.py +0 -9
  659. package/ref-monty/crates/monty/test_cases/function__err_unexpected_kwarg_quote.py +0 -13
  660. package/ref-monty/crates/monty/test_cases/function__err_unexpected_kwarg_simple.py +0 -7
  661. package/ref-monty/crates/monty/test_cases/function__err_unpack_duplicate_arg.py +0 -6
  662. package/ref-monty/crates/monty/test_cases/function__err_unpack_duplicate_heap.py +0 -8
  663. package/ref-monty/crates/monty/test_cases/function__err_unpack_int.py +0 -6
  664. package/ref-monty/crates/monty/test_cases/function__err_unpack_nonstring_key.py +0 -6
  665. package/ref-monty/crates/monty/test_cases/function__err_unpack_not_mapping.py +0 -6
  666. package/ref-monty/crates/monty/test_cases/function__kwargs_unpacking.py +0 -173
  667. package/ref-monty/crates/monty/test_cases/function__ops.py +0 -294
  668. package/ref-monty/crates/monty/test_cases/function__return_none.py +0 -42
  669. package/ref-monty/crates/monty/test_cases/function__signatures.py +0 -47
  670. package/ref-monty/crates/monty/test_cases/function__too_few_args_all.py +0 -6
  671. package/ref-monty/crates/monty/test_cases/function__too_few_args_one.py +0 -6
  672. package/ref-monty/crates/monty/test_cases/function__too_few_args_two.py +0 -6
  673. package/ref-monty/crates/monty/test_cases/function__too_many_args_one.py +0 -6
  674. package/ref-monty/crates/monty/test_cases/function__too_many_args_two.py +0 -6
  675. package/ref-monty/crates/monty/test_cases/function__too_many_args_zero.py +0 -6
  676. package/ref-monty/crates/monty/test_cases/global__error_assigned_before.py +0 -7
  677. package/ref-monty/crates/monty/test_cases/global__ops.py +0 -163
  678. package/ref-monty/crates/monty/test_cases/hash__dict_unhashable.py +0 -2
  679. package/ref-monty/crates/monty/test_cases/hash__list_unhashable.py +0 -2
  680. package/ref-monty/crates/monty/test_cases/hash__ops.py +0 -153
  681. package/ref-monty/crates/monty/test_cases/id__bytes_literals_distinct.py +0 -3
  682. package/ref-monty/crates/monty/test_cases/id__int_copy_distinct.py +0 -5
  683. package/ref-monty/crates/monty/test_cases/id__is_number_is_number.py +0 -3
  684. package/ref-monty/crates/monty/test_cases/id__non_overlapping_lifetimes_distinct_types.py +0 -10
  685. package/ref-monty/crates/monty/test_cases/id__non_overlapping_lifetimes_same_types.py +0 -6
  686. package/ref-monty/crates/monty/test_cases/id__ops.py +0 -97
  687. package/ref-monty/crates/monty/test_cases/id__str_literals_same.py +0 -3
  688. package/ref-monty/crates/monty/test_cases/if__elif_else.py +0 -207
  689. package/ref-monty/crates/monty/test_cases/if__raise_elif.py +0 -11
  690. package/ref-monty/crates/monty/test_cases/if__raise_else.py +0 -13
  691. package/ref-monty/crates/monty/test_cases/if__raise_if.py +0 -9
  692. package/ref-monty/crates/monty/test_cases/if__raise_in_elif_condition.py +0 -18
  693. package/ref-monty/crates/monty/test_cases/if__raise_in_if_condition.py +0 -16
  694. package/ref-monty/crates/monty/test_cases/if_else_expr__all.py +0 -55
  695. package/ref-monty/crates/monty/test_cases/import__error_cannot_import.py +0 -9
  696. package/ref-monty/crates/monty/test_cases/import__error_module_not_found.py +0 -9
  697. package/ref-monty/crates/monty/test_cases/import__local_scope.py +0 -68
  698. package/ref-monty/crates/monty/test_cases/import__os.py +0 -25
  699. package/ref-monty/crates/monty/test_cases/import__relative_error.py +0 -9
  700. package/ref-monty/crates/monty/test_cases/import__relative_no_module_error.py +0 -9
  701. package/ref-monty/crates/monty/test_cases/import__runtime_error_when_executed.py +0 -14
  702. package/ref-monty/crates/monty/test_cases/import__star_error.py +0 -11
  703. package/ref-monty/crates/monty/test_cases/import__sys.py +0 -47
  704. package/ref-monty/crates/monty/test_cases/import__sys_monty.py +0 -28
  705. package/ref-monty/crates/monty/test_cases/import__type_checking_guard.py +0 -37
  706. package/ref-monty/crates/monty/test_cases/import__typing.py +0 -25
  707. package/ref-monty/crates/monty/test_cases/import__typing_type_ignore.py +0 -4
  708. package/ref-monty/crates/monty/test_cases/int__bigint.py +0 -467
  709. package/ref-monty/crates/monty/test_cases/int__bigint_errors.py +0 -260
  710. package/ref-monty/crates/monty/test_cases/int__ops.py +0 -219
  711. package/ref-monty/crates/monty/test_cases/int__overflow_division.py +0 -84
  712. package/ref-monty/crates/monty/test_cases/is_variant__all.py +0 -36
  713. package/ref-monty/crates/monty/test_cases/isinstance__arg2_list_error.py +0 -2
  714. package/ref-monty/crates/monty/test_cases/isinstance__arg2_type_error.py +0 -2
  715. package/ref-monty/crates/monty/test_cases/iter__dict_mutation.py +0 -4
  716. package/ref-monty/crates/monty/test_cases/iter__for.py +0 -243
  717. package/ref-monty/crates/monty/test_cases/iter__for_loop_unpacking.py +0 -66
  718. package/ref-monty/crates/monty/test_cases/iter__generator_expr.py +0 -20
  719. package/ref-monty/crates/monty/test_cases/iter__generator_expr_type.py +0 -7
  720. package/ref-monty/crates/monty/test_cases/iter__not_iterable.py +0 -3
  721. package/ref-monty/crates/monty/test_cases/lambda__all.py +0 -145
  722. package/ref-monty/crates/monty/test_cases/list__extend_not_iterable.py +0 -7
  723. package/ref-monty/crates/monty/test_cases/list__getitem_out_of_bounds.py +0 -3
  724. package/ref-monty/crates/monty/test_cases/list__index_not_found.py +0 -9
  725. package/ref-monty/crates/monty/test_cases/list__index_start_gt_end.py +0 -10
  726. package/ref-monty/crates/monty/test_cases/list__ops.py +0 -473
  727. package/ref-monty/crates/monty/test_cases/list__pop_empty.py +0 -9
  728. package/ref-monty/crates/monty/test_cases/list__pop_out_of_range.py +0 -9
  729. package/ref-monty/crates/monty/test_cases/list__pop_type_error.py +0 -9
  730. package/ref-monty/crates/monty/test_cases/list__remove_not_found.py +0 -9
  731. package/ref-monty/crates/monty/test_cases/list__setitem_dict_index.py +0 -13
  732. package/ref-monty/crates/monty/test_cases/list__setitem_huge_int_index.py +0 -13
  733. package/ref-monty/crates/monty/test_cases/list__setitem_index_error.py +0 -10
  734. package/ref-monty/crates/monty/test_cases/list__setitem_type_error.py +0 -10
  735. package/ref-monty/crates/monty/test_cases/list__unpack_type_error.py +0 -2
  736. package/ref-monty/crates/monty/test_cases/longint__index_error.py +0 -3
  737. package/ref-monty/crates/monty/test_cases/longint__repeat_error.py +0 -3
  738. package/ref-monty/crates/monty/test_cases/loop__break_continue.py +0 -113
  739. package/ref-monty/crates/monty/test_cases/loop__break_finally.py +0 -69
  740. package/ref-monty/crates/monty/test_cases/loop__break_in_function_error.py +0 -13
  741. package/ref-monty/crates/monty/test_cases/loop__break_in_if_error.py +0 -11
  742. package/ref-monty/crates/monty/test_cases/loop__break_nested_except_clears.py +0 -55
  743. package/ref-monty/crates/monty/test_cases/loop__break_outside_error.py +0 -9
  744. package/ref-monty/crates/monty/test_cases/loop__continue_finally.py +0 -81
  745. package/ref-monty/crates/monty/test_cases/loop__continue_in_function_error.py +0 -13
  746. package/ref-monty/crates/monty/test_cases/loop__continue_in_if_error.py +0 -11
  747. package/ref-monty/crates/monty/test_cases/loop__continue_nested_except_clears.py +0 -60
  748. package/ref-monty/crates/monty/test_cases/loop__continue_outside_error.py +0 -9
  749. package/ref-monty/crates/monty/test_cases/math__acos_domain_error.py +0 -11
  750. package/ref-monty/crates/monty/test_cases/math__acosh_domain_error.py +0 -11
  751. package/ref-monty/crates/monty/test_cases/math__asin_domain_error.py +0 -11
  752. package/ref-monty/crates/monty/test_cases/math__atanh_domain_error.py +0 -11
  753. package/ref-monty/crates/monty/test_cases/math__cos_inf_error.py +0 -11
  754. package/ref-monty/crates/monty/test_cases/math__cosh_overflow_error.py +0 -11
  755. package/ref-monty/crates/monty/test_cases/math__exp_overflow_error.py +0 -11
  756. package/ref-monty/crates/monty/test_cases/math__factorial_float_error.py +0 -11
  757. package/ref-monty/crates/monty/test_cases/math__factorial_negative_error.py +0 -11
  758. package/ref-monty/crates/monty/test_cases/math__floor_inf_error.py +0 -11
  759. package/ref-monty/crates/monty/test_cases/math__floor_nan_error.py +0 -11
  760. package/ref-monty/crates/monty/test_cases/math__floor_str_error.py +0 -11
  761. package/ref-monty/crates/monty/test_cases/math__fmod_inf_error.py +0 -11
  762. package/ref-monty/crates/monty/test_cases/math__gamma_neg_int_error.py +0 -11
  763. package/ref-monty/crates/monty/test_cases/math__gcd_float_error.py +0 -11
  764. package/ref-monty/crates/monty/test_cases/math__isqrt_negative_error.py +0 -11
  765. package/ref-monty/crates/monty/test_cases/math__ldexp_overflow_error.py +0 -11
  766. package/ref-monty/crates/monty/test_cases/math__log1p_domain_error.py +0 -11
  767. package/ref-monty/crates/monty/test_cases/math__log_base1_error.py +0 -11
  768. package/ref-monty/crates/monty/test_cases/math__log_zero_error.py +0 -11
  769. package/ref-monty/crates/monty/test_cases/math__module.py +0 -1432
  770. package/ref-monty/crates/monty/test_cases/math__pow_domain_error.py +0 -11
  771. package/ref-monty/crates/monty/test_cases/math__sin_inf_error.py +0 -11
  772. package/ref-monty/crates/monty/test_cases/math__sqrt_negative_error.py +0 -11
  773. package/ref-monty/crates/monty/test_cases/math__tan_inf_error.py +0 -11
  774. package/ref-monty/crates/monty/test_cases/math__trunc_str_error.py +0 -11
  775. package/ref-monty/crates/monty/test_cases/method__args_kwargs_unpacking.py +0 -259
  776. package/ref-monty/crates/monty/test_cases/name_error__unbound_local_func.py +0 -19
  777. package/ref-monty/crates/monty/test_cases/name_error__unbound_local_module.py +0 -12
  778. package/ref-monty/crates/monty/test_cases/name_error__undefined_call_chained.py +0 -9
  779. package/ref-monty/crates/monty/test_cases/name_error__undefined_call_in_expr.py +0 -9
  780. package/ref-monty/crates/monty/test_cases/name_error__undefined_call_in_function.py +0 -16
  781. package/ref-monty/crates/monty/test_cases/name_error__undefined_call_with_args.py +0 -9
  782. package/ref-monty/crates/monty/test_cases/name_error__undefined_global.py +0 -10
  783. package/ref-monty/crates/monty/test_cases/namedtuple__missing_attr.py +0 -11
  784. package/ref-monty/crates/monty/test_cases/namedtuple__ops.py +0 -34
  785. package/ref-monty/crates/monty/test_cases/nonlocal__error_module_level.py +0 -3
  786. package/ref-monty/crates/monty/test_cases/nonlocal__ops.py +0 -353
  787. package/ref-monty/crates/monty/test_cases/os__environ.py +0 -40
  788. package/ref-monty/crates/monty/test_cases/os__getenv_key_list_error.py +0 -5
  789. package/ref-monty/crates/monty/test_cases/os__getenv_key_type_error.py +0 -5
  790. package/ref-monty/crates/monty/test_cases/parse_error__complex.py +0 -3
  791. package/ref-monty/crates/monty/test_cases/pathlib__import.py +0 -11
  792. package/ref-monty/crates/monty/test_cases/pathlib__os.py +0 -136
  793. package/ref-monty/crates/monty/test_cases/pathlib__os_read_error.py +0 -12
  794. package/ref-monty/crates/monty/test_cases/pathlib__pure.py +0 -81
  795. package/ref-monty/crates/monty/test_cases/pyobject__cycle_dict_self.py +0 -5
  796. package/ref-monty/crates/monty/test_cases/pyobject__cycle_list_dict.py +0 -6
  797. package/ref-monty/crates/monty/test_cases/pyobject__cycle_list_self.py +0 -5
  798. package/ref-monty/crates/monty/test_cases/pyobject__cycle_multiple_refs.py +0 -6
  799. package/ref-monty/crates/monty/test_cases/range__error_no_args.py +0 -2
  800. package/ref-monty/crates/monty/test_cases/range__error_step_zero.py +0 -2
  801. package/ref-monty/crates/monty/test_cases/range__error_too_many_args.py +0 -2
  802. package/ref-monty/crates/monty/test_cases/range__getitem_index_error.py +0 -10
  803. package/ref-monty/crates/monty/test_cases/range__ops.py +0 -236
  804. package/ref-monty/crates/monty/test_cases/re__basic.py +0 -756
  805. package/ref-monty/crates/monty/test_cases/re__grouping.py +0 -241
  806. package/ref-monty/crates/monty/test_cases/re__match.py +0 -148
  807. package/ref-monty/crates/monty/test_cases/recursion__deep_drop.py +0 -26
  808. package/ref-monty/crates/monty/test_cases/recursion__deep_eq.py +0 -23
  809. package/ref-monty/crates/monty/test_cases/recursion__deep_hash.py +0 -46
  810. package/ref-monty/crates/monty/test_cases/recursion__deep_repr.py +0 -12
  811. package/ref-monty/crates/monty/test_cases/recursion__function_depth.py +0 -13
  812. package/ref-monty/crates/monty/test_cases/refcount__cycle_mutual_reference.py +0 -18
  813. package/ref-monty/crates/monty/test_cases/refcount__cycle_self_reference.py +0 -12
  814. package/ref-monty/crates/monty/test_cases/refcount__dict_basic.py +0 -5
  815. package/ref-monty/crates/monty/test_cases/refcount__dict_get.py +0 -5
  816. package/ref-monty/crates/monty/test_cases/refcount__dict_keys_and.py +0 -14
  817. package/ref-monty/crates/monty/test_cases/refcount__dict_overwrite.py +0 -6
  818. package/ref-monty/crates/monty/test_cases/refcount__gather_cleanup.py +0 -16
  819. package/ref-monty/crates/monty/test_cases/refcount__gather_exception.py +0 -18
  820. package/ref-monty/crates/monty/test_cases/refcount__gather_nested_cancel.py +0 -25
  821. package/ref-monty/crates/monty/test_cases/refcount__immediate_skipped.py +0 -4
  822. package/ref-monty/crates/monty/test_cases/refcount__kwargs_unpacking.py +0 -27
  823. package/ref-monty/crates/monty/test_cases/refcount__list_append_multiple.py +0 -6
  824. package/ref-monty/crates/monty/test_cases/refcount__list_append_ref.py +0 -5
  825. package/ref-monty/crates/monty/test_cases/refcount__list_concat.py +0 -5
  826. package/ref-monty/crates/monty/test_cases/refcount__list_getitem.py +0 -5
  827. package/ref-monty/crates/monty/test_cases/refcount__list_iadd.py +0 -5
  828. package/ref-monty/crates/monty/test_cases/refcount__nested_list.py +0 -4
  829. package/ref-monty/crates/monty/test_cases/refcount__re_pattern_sub_error_paths.py +0 -37
  830. package/ref-monty/crates/monty/test_cases/refcount__re_search_match.py +0 -34
  831. package/ref-monty/crates/monty/test_cases/refcount__re_sub_error_paths.py +0 -31
  832. package/ref-monty/crates/monty/test_cases/refcount__shared_reference.py +0 -4
  833. package/ref-monty/crates/monty/test_cases/refcount__single_list.py +0 -3
  834. package/ref-monty/crates/monty/test_cases/repr__cycle_detection.py +0 -24
  835. package/ref-monty/crates/monty/test_cases/set__ops.py +0 -191
  836. package/ref-monty/crates/monty/test_cases/set__review_bugs.py +0 -35
  837. package/ref-monty/crates/monty/test_cases/set__unpack_type_error.py +0 -2
  838. package/ref-monty/crates/monty/test_cases/slice__invalid_indices.py +0 -2
  839. package/ref-monty/crates/monty/test_cases/slice__kwargs.py +0 -9
  840. package/ref-monty/crates/monty/test_cases/slice__no_args.py +0 -9
  841. package/ref-monty/crates/monty/test_cases/slice__ops.py +0 -149
  842. package/ref-monty/crates/monty/test_cases/slice__step_zero.py +0 -9
  843. package/ref-monty/crates/monty/test_cases/slice__step_zero_bytes.py +0 -9
  844. package/ref-monty/crates/monty/test_cases/slice__step_zero_range.py +0 -9
  845. package/ref-monty/crates/monty/test_cases/slice__step_zero_str.py +0 -9
  846. package/ref-monty/crates/monty/test_cases/slice__step_zero_tuple.py +0 -9
  847. package/ref-monty/crates/monty/test_cases/slice__too_many_args.py +0 -9
  848. package/ref-monty/crates/monty/test_cases/str__getitem_index_error.py +0 -10
  849. package/ref-monty/crates/monty/test_cases/str__index_not_found.py +0 -9
  850. package/ref-monty/crates/monty/test_cases/str__join_no_args.py +0 -9
  851. package/ref-monty/crates/monty/test_cases/str__join_non_string.py +0 -9
  852. package/ref-monty/crates/monty/test_cases/str__join_not_iterable.py +0 -9
  853. package/ref-monty/crates/monty/test_cases/str__join_too_many_args.py +0 -9
  854. package/ref-monty/crates/monty/test_cases/str__methods.py +0 -327
  855. package/ref-monty/crates/monty/test_cases/str__ops.py +0 -162
  856. package/ref-monty/crates/monty/test_cases/str__partition_empty.py +0 -9
  857. package/ref-monty/crates/monty/test_cases/str__rsplit_empty_sep.py +0 -9
  858. package/ref-monty/crates/monty/test_cases/str__split_empty_sep.py +0 -9
  859. package/ref-monty/crates/monty/test_cases/sys__types.py +0 -7
  860. package/ref-monty/crates/monty/test_cases/traceback__division_error.py +0 -30
  861. package/ref-monty/crates/monty/test_cases/traceback__index_error.py +0 -17
  862. package/ref-monty/crates/monty/test_cases/traceback__insert_as_int.py +0 -10
  863. package/ref-monty/crates/monty/test_cases/traceback__nested_call.py +0 -29
  864. package/ref-monty/crates/monty/test_cases/traceback__nonlocal_module_scope.py +0 -10
  865. package/ref-monty/crates/monty/test_cases/traceback__nonlocal_unbound.py +0 -24
  866. package/ref-monty/crates/monty/test_cases/traceback__range_as_int.py +0 -9
  867. package/ref-monty/crates/monty/test_cases/traceback__recursion_error.py +0 -23
  868. package/ref-monty/crates/monty/test_cases/traceback__set_mutation.py +0 -11
  869. package/ref-monty/crates/monty/test_cases/traceback__undefined_attr_call.py +0 -16
  870. package/ref-monty/crates/monty/test_cases/traceback__undefined_call.py +0 -16
  871. package/ref-monty/crates/monty/test_cases/traceback__undefined_raise.py +0 -16
  872. package/ref-monty/crates/monty/test_cases/try_except__all.py +0 -472
  873. package/ref-monty/crates/monty/test_cases/try_except__bare_raise_no_context.py +0 -2
  874. package/ref-monty/crates/monty/test_cases/try_except__invalid_type.py +0 -5
  875. package/ref-monty/crates/monty/test_cases/tuple__getitem_out_of_bounds.py +0 -3
  876. package/ref-monty/crates/monty/test_cases/tuple__index_not_found.py +0 -9
  877. package/ref-monty/crates/monty/test_cases/tuple__index_start_gt_end.py +0 -10
  878. package/ref-monty/crates/monty/test_cases/tuple__methods.py +0 -19
  879. package/ref-monty/crates/monty/test_cases/tuple__ops.py +0 -133
  880. package/ref-monty/crates/monty/test_cases/tuple__unpack_type_error.py +0 -2
  881. package/ref-monty/crates/monty/test_cases/type__builtin_attr_error.py +0 -9
  882. package/ref-monty/crates/monty/test_cases/type__bytes_negative.py +0 -2
  883. package/ref-monty/crates/monty/test_cases/type__cell_not_builtin.py +0 -9
  884. package/ref-monty/crates/monty/test_cases/type__exception_attr_error.py +0 -11
  885. package/ref-monty/crates/monty/test_cases/type__float_conversion_error.py +0 -2
  886. package/ref-monty/crates/monty/test_cases/type__float_repr_both_quotes.py +0 -9
  887. package/ref-monty/crates/monty/test_cases/type__float_repr_newline.py +0 -9
  888. package/ref-monty/crates/monty/test_cases/type__float_repr_single_quote.py +0 -9
  889. package/ref-monty/crates/monty/test_cases/type__int_conversion_error.py +0 -2
  890. package/ref-monty/crates/monty/test_cases/type__list_not_iterable.py +0 -2
  891. package/ref-monty/crates/monty/test_cases/type__non_builtin_name_error.py +0 -9
  892. package/ref-monty/crates/monty/test_cases/type__ops.py +0 -200
  893. package/ref-monty/crates/monty/test_cases/type__shadow_exc.py +0 -3
  894. package/ref-monty/crates/monty/test_cases/type__shadow_int.py +0 -9
  895. package/ref-monty/crates/monty/test_cases/type__shadow_len.py +0 -3
  896. package/ref-monty/crates/monty/test_cases/type__tuple_not_iterable.py +0 -2
  897. package/ref-monty/crates/monty/test_cases/type_error__int_add_list.py +0 -2
  898. package/ref-monty/crates/monty/test_cases/type_error__int_div_str.py +0 -2
  899. package/ref-monty/crates/monty/test_cases/type_error__int_floordiv_str.py +0 -2
  900. package/ref-monty/crates/monty/test_cases/type_error__int_iadd_str.py +0 -3
  901. package/ref-monty/crates/monty/test_cases/type_error__int_mod_str.py +0 -2
  902. package/ref-monty/crates/monty/test_cases/type_error__int_pow_str.py +0 -2
  903. package/ref-monty/crates/monty/test_cases/type_error__int_sub_str.py +0 -2
  904. package/ref-monty/crates/monty/test_cases/type_error__list_add_int.py +0 -2
  905. package/ref-monty/crates/monty/test_cases/type_error__list_add_str.py +0 -2
  906. package/ref-monty/crates/monty/test_cases/type_error__list_iadd_int.py +0 -6
  907. package/ref-monty/crates/monty/test_cases/type_error__str_add_int.py +0 -2
  908. package/ref-monty/crates/monty/test_cases/type_error__str_iadd_int.py +0 -3
  909. package/ref-monty/crates/monty/test_cases/type_error__unary_invert_str.py +0 -3
  910. package/ref-monty/crates/monty/test_cases/type_error__unary_minus_str.py +0 -4
  911. package/ref-monty/crates/monty/test_cases/type_error__unary_neg_str.py +0 -3
  912. package/ref-monty/crates/monty/test_cases/type_error__unary_plus_str.py +0 -4
  913. package/ref-monty/crates/monty/test_cases/typing__types.py +0 -24
  914. package/ref-monty/crates/monty/test_cases/unpack__nested.py +0 -48
  915. package/ref-monty/crates/monty/test_cases/unpack__non_sequence.py +0 -9
  916. package/ref-monty/crates/monty/test_cases/unpack__not_enough.py +0 -9
  917. package/ref-monty/crates/monty/test_cases/unpack__ops.py +0 -153
  918. package/ref-monty/crates/monty/test_cases/unpack__star_not_enough.py +0 -9
  919. package/ref-monty/crates/monty/test_cases/unpack__too_many.py +0 -9
  920. package/ref-monty/crates/monty/test_cases/version__cpython.py +0 -4
  921. package/ref-monty/crates/monty/test_cases/walrus__all.py +0 -178
  922. package/ref-monty/crates/monty/test_cases/while__all.py +0 -206
  923. package/ref-monty/crates/monty/tests/asyncio.rs +0 -764
  924. package/ref-monty/crates/monty/tests/binary_serde.rs +0 -185
  925. package/ref-monty/crates/monty/tests/bytecode_limits.rs +0 -248
  926. package/ref-monty/crates/monty/tests/datatest_runner.rs +0 -2029
  927. package/ref-monty/crates/monty/tests/inputs.rs +0 -420
  928. package/ref-monty/crates/monty/tests/json_serde.rs +0 -250
  929. package/ref-monty/crates/monty/tests/main.rs +0 -71
  930. package/ref-monty/crates/monty/tests/math_module.rs +0 -114
  931. package/ref-monty/crates/monty/tests/name_lookup.rs +0 -482
  932. package/ref-monty/crates/monty/tests/os_tests.rs +0 -459
  933. package/ref-monty/crates/monty/tests/parse_errors.rs +0 -441
  934. package/ref-monty/crates/monty/tests/print_writer.rs +0 -238
  935. package/ref-monty/crates/monty/tests/py_object.rs +0 -121
  936. package/ref-monty/crates/monty/tests/regex.rs +0 -90
  937. package/ref-monty/crates/monty/tests/repl.rs +0 -344
  938. package/ref-monty/crates/monty/tests/resource_limits.rs +0 -1826
  939. package/ref-monty/crates/monty/tests/try_from.rs +0 -167
  940. package/ref-monty/crates/monty-cli/Cargo.toml +0 -25
  941. package/ref-monty/crates/monty-cli/src/main.rs +0 -541
  942. package/ref-monty/crates/monty-js/.cargo/config.toml +0 -2
  943. package/ref-monty/crates/monty-js/.prettierignore +0 -8
  944. package/ref-monty/crates/monty-js/Cargo.toml +0 -32
  945. package/ref-monty/crates/monty-js/README.md +0 -207
  946. package/ref-monty/crates/monty-js/__test__/async.spec.ts +0 -350
  947. package/ref-monty/crates/monty-js/__test__/basic.spec.ts +0 -114
  948. package/ref-monty/crates/monty-js/__test__/exceptions.spec.ts +0 -427
  949. package/ref-monty/crates/monty-js/__test__/external.spec.ts +0 -354
  950. package/ref-monty/crates/monty-js/__test__/inputs.spec.ts +0 -143
  951. package/ref-monty/crates/monty-js/__test__/limits.spec.ts +0 -162
  952. package/ref-monty/crates/monty-js/__test__/package.json +0 -3
  953. package/ref-monty/crates/monty-js/__test__/print.spec.ts +0 -229
  954. package/ref-monty/crates/monty-js/__test__/repl.spec.ts +0 -34
  955. package/ref-monty/crates/monty-js/__test__/serialize.spec.ts +0 -205
  956. package/ref-monty/crates/monty-js/__test__/start.spec.ts +0 -443
  957. package/ref-monty/crates/monty-js/__test__/type_check.spec.ts +0 -147
  958. package/ref-monty/crates/monty-js/__test__/types.spec.ts +0 -319
  959. package/ref-monty/crates/monty-js/build.rs +0 -61
  960. package/ref-monty/crates/monty-js/index-header.d.ts +0 -3
  961. package/ref-monty/crates/monty-js/package-lock.json +0 -4694
  962. package/ref-monty/crates/monty-js/package.json +0 -100
  963. package/ref-monty/crates/monty-js/scripts/smoke-test.sh +0 -69
  964. package/ref-monty/crates/monty-js/smoke-test/package.json +0 -17
  965. package/ref-monty/crates/monty-js/smoke-test/test.ts +0 -171
  966. package/ref-monty/crates/monty-js/smoke-test/tsconfig.json +0 -11
  967. package/ref-monty/crates/monty-js/src/convert.rs +0 -648
  968. package/ref-monty/crates/monty-js/src/exceptions.rs +0 -293
  969. package/ref-monty/crates/monty-js/src/lib.rs +0 -41
  970. package/ref-monty/crates/monty-js/src/limits.rs +0 -53
  971. package/ref-monty/crates/monty-js/src/monty_cls.rs +0 -1407
  972. package/ref-monty/crates/monty-js/tsconfig.json +0 -17
  973. package/ref-monty/crates/monty-js/wrapper.ts +0 -701
  974. package/ref-monty/crates/monty-python/Cargo.toml +0 -38
  975. package/ref-monty/crates/monty-python/README.md +0 -134
  976. package/ref-monty/crates/monty-python/build.rs +0 -4
  977. package/ref-monty/crates/monty-python/example.py +0 -40
  978. package/ref-monty/crates/monty-python/exercise.py +0 -46
  979. package/ref-monty/crates/monty-python/pyproject.toml +0 -57
  980. package/ref-monty/crates/monty-python/python/pydantic_monty/__init__.py +0 -281
  981. package/ref-monty/crates/monty-python/python/pydantic_monty/_monty.pyi +0 -677
  982. package/ref-monty/crates/monty-python/python/pydantic_monty/os_access.py +0 -933
  983. package/ref-monty/crates/monty-python/python/pydantic_monty/py.typed +0 -0
  984. package/ref-monty/crates/monty-python/src/convert.rs +0 -273
  985. package/ref-monty/crates/monty-python/src/dataclass.rs +0 -461
  986. package/ref-monty/crates/monty-python/src/exceptions.rs +0 -557
  987. package/ref-monty/crates/monty-python/src/external.rs +0 -165
  988. package/ref-monty/crates/monty-python/src/lib.rs +0 -77
  989. package/ref-monty/crates/monty-python/src/limits.rs +0 -142
  990. package/ref-monty/crates/monty-python/src/monty_cls.rs +0 -1650
  991. package/ref-monty/crates/monty-python/src/repl.rs +0 -470
  992. package/ref-monty/crates/monty-python/src/serialization.rs +0 -761
  993. package/ref-monty/crates/monty-python/tests/test_async.py +0 -1201
  994. package/ref-monty/crates/monty-python/tests/test_basic.py +0 -66
  995. package/ref-monty/crates/monty-python/tests/test_dataclasses.py +0 -971
  996. package/ref-monty/crates/monty-python/tests/test_exceptions.py +0 -361
  997. package/ref-monty/crates/monty-python/tests/test_external.py +0 -367
  998. package/ref-monty/crates/monty-python/tests/test_inputs.py +0 -126
  999. package/ref-monty/crates/monty-python/tests/test_limits.py +0 -257
  1000. package/ref-monty/crates/monty-python/tests/test_os_access.py +0 -1286
  1001. package/ref-monty/crates/monty-python/tests/test_os_access_compat.py +0 -731
  1002. package/ref-monty/crates/monty-python/tests/test_os_access_raw.py +0 -483
  1003. package/ref-monty/crates/monty-python/tests/test_os_calls.py +0 -819
  1004. package/ref-monty/crates/monty-python/tests/test_print.py +0 -208
  1005. package/ref-monty/crates/monty-python/tests/test_re.py +0 -170
  1006. package/ref-monty/crates/monty-python/tests/test_readme_examples.py +0 -20
  1007. package/ref-monty/crates/monty-python/tests/test_repl.py +0 -749
  1008. package/ref-monty/crates/monty-python/tests/test_serialize.py +0 -284
  1009. package/ref-monty/crates/monty-python/tests/test_start.py +0 -346
  1010. package/ref-monty/crates/monty-python/tests/test_threading.py +0 -163
  1011. package/ref-monty/crates/monty-python/tests/test_type_check.py +0 -344
  1012. package/ref-monty/crates/monty-python/tests/test_types.py +0 -553
  1013. package/ref-monty/crates/monty-type-checking/Cargo.toml +0 -32
  1014. package/ref-monty/crates/monty-type-checking/src/db.rs +0 -116
  1015. package/ref-monty/crates/monty-type-checking/src/lib.rs +0 -4
  1016. package/ref-monty/crates/monty-type-checking/src/type_check.rs +0 -280
  1017. package/ref-monty/crates/monty-type-checking/tests/bad_types.py +0 -109
  1018. package/ref-monty/crates/monty-type-checking/tests/bad_types_output.txt +0 -21
  1019. package/ref-monty/crates/monty-type-checking/tests/good_types.py +0 -475
  1020. package/ref-monty/crates/monty-type-checking/tests/main.rs +0 -205
  1021. package/ref-monty/crates/monty-type-checking/tests/reveal_types.py +0 -56
  1022. package/ref-monty/crates/monty-type-checking/tests/reveal_types_output.txt +0 -41
  1023. package/ref-monty/crates/monty-typeshed/Cargo.toml +0 -29
  1024. package/ref-monty/crates/monty-typeshed/README.md +0 -11
  1025. package/ref-monty/crates/monty-typeshed/build.rs +0 -101
  1026. package/ref-monty/crates/monty-typeshed/custom/README.md +0 -1
  1027. package/ref-monty/crates/monty-typeshed/custom/asyncio.pyi +0 -138
  1028. package/ref-monty/crates/monty-typeshed/custom/os.pyi +0 -87
  1029. package/ref-monty/crates/monty-typeshed/custom/sys.pyi +0 -33
  1030. package/ref-monty/crates/monty-typeshed/src/lib.rs +0 -56
  1031. package/ref-monty/crates/monty-typeshed/update.py +0 -321
  1032. package/ref-monty/crates/monty-typeshed/vendor/typeshed/source_commit.txt +0 -1
  1033. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/VERSIONS +0 -20
  1034. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/_collections_abc.pyi +0 -105
  1035. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/_typeshed/__init__.pyi +0 -394
  1036. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/asyncio.pyi +0 -138
  1037. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/builtins.pyi +0 -1434
  1038. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/collections/__init__.pyi +0 -527
  1039. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/collections/abc.pyi +0 -2
  1040. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/dataclasses.pyi +0 -502
  1041. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/enum.pyi +0 -376
  1042. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/math.pyi +0 -149
  1043. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/os.pyi +0 -87
  1044. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/pathlib/__init__.pyi +0 -395
  1045. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/pathlib/types.pyi +0 -8
  1046. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/re.pyi +0 -337
  1047. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/sys.pyi +0 -33
  1048. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/types.pyi +0 -741
  1049. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/typing.pyi +0 -1217
  1050. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/typing_extensions.pyi +0 -716
  1051. package/ref-monty/docs/usage-guide.md +0 -117
  1052. package/ref-monty/examples/README.md +0 -3
  1053. package/ref-monty/examples/expense_analysis/README.md +0 -3
  1054. package/ref-monty/examples/expense_analysis/data.py +0 -124
  1055. package/ref-monty/examples/expense_analysis/main.py +0 -115
  1056. package/ref-monty/examples/sql_playground/README.md +0 -20
  1057. package/ref-monty/examples/sql_playground/external_functions.py +0 -129
  1058. package/ref-monty/examples/sql_playground/main.py +0 -81
  1059. package/ref-monty/examples/sql_playground/sandbox_code.py +0 -82
  1060. package/ref-monty/examples/sql_playground/type_stubs.pyi +0 -14
  1061. package/ref-monty/examples/web_scraper/README.md +0 -15
  1062. package/ref-monty/examples/web_scraper/browser.py +0 -56
  1063. package/ref-monty/examples/web_scraper/example_code.py +0 -59
  1064. package/ref-monty/examples/web_scraper/external_functions.py +0 -324
  1065. package/ref-monty/examples/web_scraper/main.py +0 -193
  1066. package/ref-monty/examples/web_scraper/sub_agent.py +0 -79
  1067. package/ref-monty/monty-npm.md +0 -235
  1068. package/ref-monty/pyproject.toml +0 -162
  1069. package/ref-monty/scripts/check_imports.py +0 -91
  1070. package/ref-monty/scripts/codecov_diff.py +0 -412
  1071. package/ref-monty/scripts/complete_tests.py +0 -146
  1072. package/ref-monty/scripts/flamegraph_to_text.py +0 -208
  1073. package/ref-monty/scripts/iter_test_methods.py +0 -540
  1074. package/ref-monty/scripts/run_traceback.py +0 -180
  1075. package/ref-monty/scripts/startup_performance.py +0 -130
  1076. package/ref-monty/uv.lock +0 -1779
  1077. package/temp_resend_cli/repo/.github/scripts/pr-title-check.js +0 -34
  1078. package/temp_resend_cli/repo/.github/workflows/ci.yml +0 -67
  1079. package/temp_resend_cli/repo/.github/workflows/post-release.yml +0 -51
  1080. package/temp_resend_cli/repo/.github/workflows/pr-title-check.yml +0 -13
  1081. package/temp_resend_cli/repo/.github/workflows/release.yml +0 -175
  1082. package/temp_resend_cli/repo/.github/workflows/test-install-unix.yml +0 -34
  1083. package/temp_resend_cli/repo/.github/workflows/test-install-windows.yml +0 -48
  1084. package/temp_resend_cli/repo/CHANGELOG.md +0 -31
  1085. package/temp_resend_cli/repo/LICENSE +0 -21
  1086. package/temp_resend_cli/repo/README.md +0 -450
  1087. package/temp_resend_cli/repo/biome.json +0 -36
  1088. package/temp_resend_cli/repo/install.ps1 +0 -141
  1089. package/temp_resend_cli/repo/install.sh +0 -301
  1090. package/temp_resend_cli/repo/package.json +0 -61
  1091. package/temp_resend_cli/repo/pnpm-lock.yaml +0 -2439
  1092. package/temp_resend_cli/repo/renovate.json +0 -4
  1093. package/temp_resend_cli/repo/src/cli.ts +0 -98
  1094. package/temp_resend_cli/repo/src/commands/api-keys/create.ts +0 -114
  1095. package/temp_resend_cli/repo/src/commands/api-keys/delete.ts +0 -47
  1096. package/temp_resend_cli/repo/src/commands/api-keys/index.ts +0 -26
  1097. package/temp_resend_cli/repo/src/commands/api-keys/list.ts +0 -35
  1098. package/temp_resend_cli/repo/src/commands/api-keys/utils.ts +0 -8
  1099. package/temp_resend_cli/repo/src/commands/auth/index.ts +0 -20
  1100. package/temp_resend_cli/repo/src/commands/auth/login.ts +0 -234
  1101. package/temp_resend_cli/repo/src/commands/auth/logout.ts +0 -105
  1102. package/temp_resend_cli/repo/src/commands/broadcasts/create.ts +0 -196
  1103. package/temp_resend_cli/repo/src/commands/broadcasts/delete.ts +0 -46
  1104. package/temp_resend_cli/repo/src/commands/broadcasts/get.ts +0 -59
  1105. package/temp_resend_cli/repo/src/commands/broadcasts/index.ts +0 -43
  1106. package/temp_resend_cli/repo/src/commands/broadcasts/list.ts +0 -60
  1107. package/temp_resend_cli/repo/src/commands/broadcasts/send.ts +0 -56
  1108. package/temp_resend_cli/repo/src/commands/broadcasts/update.ts +0 -95
  1109. package/temp_resend_cli/repo/src/commands/broadcasts/utils.ts +0 -35
  1110. package/temp_resend_cli/repo/src/commands/contact-properties/create.ts +0 -118
  1111. package/temp_resend_cli/repo/src/commands/contact-properties/delete.ts +0 -48
  1112. package/temp_resend_cli/repo/src/commands/contact-properties/get.ts +0 -46
  1113. package/temp_resend_cli/repo/src/commands/contact-properties/index.ts +0 -48
  1114. package/temp_resend_cli/repo/src/commands/contact-properties/list.ts +0 -68
  1115. package/temp_resend_cli/repo/src/commands/contact-properties/update.ts +0 -88
  1116. package/temp_resend_cli/repo/src/commands/contact-properties/utils.ts +0 -17
  1117. package/temp_resend_cli/repo/src/commands/contacts/add-segment.ts +0 -78
  1118. package/temp_resend_cli/repo/src/commands/contacts/create.ts +0 -122
  1119. package/temp_resend_cli/repo/src/commands/contacts/delete.ts +0 -49
  1120. package/temp_resend_cli/repo/src/commands/contacts/get.ts +0 -53
  1121. package/temp_resend_cli/repo/src/commands/contacts/index.ts +0 -58
  1122. package/temp_resend_cli/repo/src/commands/contacts/list.ts +0 -57
  1123. package/temp_resend_cli/repo/src/commands/contacts/remove-segment.ts +0 -48
  1124. package/temp_resend_cli/repo/src/commands/contacts/segments.ts +0 -39
  1125. package/temp_resend_cli/repo/src/commands/contacts/topics.ts +0 -45
  1126. package/temp_resend_cli/repo/src/commands/contacts/update-topics.ts +0 -90
  1127. package/temp_resend_cli/repo/src/commands/contacts/update.ts +0 -77
  1128. package/temp_resend_cli/repo/src/commands/contacts/utils.ts +0 -119
  1129. package/temp_resend_cli/repo/src/commands/doctor.ts +0 -216
  1130. package/temp_resend_cli/repo/src/commands/domains/create.ts +0 -83
  1131. package/temp_resend_cli/repo/src/commands/domains/delete.ts +0 -42
  1132. package/temp_resend_cli/repo/src/commands/domains/get.ts +0 -47
  1133. package/temp_resend_cli/repo/src/commands/domains/index.ts +0 -35
  1134. package/temp_resend_cli/repo/src/commands/domains/list.ts +0 -53
  1135. package/temp_resend_cli/repo/src/commands/domains/update.ts +0 -75
  1136. package/temp_resend_cli/repo/src/commands/domains/utils.ts +0 -44
  1137. package/temp_resend_cli/repo/src/commands/domains/verify.ts +0 -38
  1138. package/temp_resend_cli/repo/src/commands/emails/batch.ts +0 -140
  1139. package/temp_resend_cli/repo/src/commands/emails/get.ts +0 -44
  1140. package/temp_resend_cli/repo/src/commands/emails/index.ts +0 -30
  1141. package/temp_resend_cli/repo/src/commands/emails/list.ts +0 -84
  1142. package/temp_resend_cli/repo/src/commands/emails/receiving/attachment.ts +0 -55
  1143. package/temp_resend_cli/repo/src/commands/emails/receiving/attachments.ts +0 -68
  1144. package/temp_resend_cli/repo/src/commands/emails/receiving/get.ts +0 -58
  1145. package/temp_resend_cli/repo/src/commands/emails/receiving/index.ts +0 -28
  1146. package/temp_resend_cli/repo/src/commands/emails/receiving/list.ts +0 -59
  1147. package/temp_resend_cli/repo/src/commands/emails/receiving/utils.ts +0 -38
  1148. package/temp_resend_cli/repo/src/commands/emails/send.ts +0 -189
  1149. package/temp_resend_cli/repo/src/commands/open.ts +0 -27
  1150. package/temp_resend_cli/repo/src/commands/segments/create.ts +0 -50
  1151. package/temp_resend_cli/repo/src/commands/segments/delete.ts +0 -47
  1152. package/temp_resend_cli/repo/src/commands/segments/get.ts +0 -38
  1153. package/temp_resend_cli/repo/src/commands/segments/index.ts +0 -36
  1154. package/temp_resend_cli/repo/src/commands/segments/list.ts +0 -58
  1155. package/temp_resend_cli/repo/src/commands/segments/utils.ts +0 -7
  1156. package/temp_resend_cli/repo/src/commands/teams/index.ts +0 -10
  1157. package/temp_resend_cli/repo/src/commands/teams/list.ts +0 -35
  1158. package/temp_resend_cli/repo/src/commands/teams/remove.ts +0 -86
  1159. package/temp_resend_cli/repo/src/commands/teams/switch.ts +0 -76
  1160. package/temp_resend_cli/repo/src/commands/topics/create.ts +0 -73
  1161. package/temp_resend_cli/repo/src/commands/topics/delete.ts +0 -47
  1162. package/temp_resend_cli/repo/src/commands/topics/get.ts +0 -42
  1163. package/temp_resend_cli/repo/src/commands/topics/index.ts +0 -42
  1164. package/temp_resend_cli/repo/src/commands/topics/list.ts +0 -34
  1165. package/temp_resend_cli/repo/src/commands/topics/update.ts +0 -59
  1166. package/temp_resend_cli/repo/src/commands/topics/utils.ts +0 -16
  1167. package/temp_resend_cli/repo/src/commands/webhooks/create.ts +0 -128
  1168. package/temp_resend_cli/repo/src/commands/webhooks/delete.ts +0 -49
  1169. package/temp_resend_cli/repo/src/commands/webhooks/get.ts +0 -42
  1170. package/temp_resend_cli/repo/src/commands/webhooks/index.ts +0 -42
  1171. package/temp_resend_cli/repo/src/commands/webhooks/list.ts +0 -55
  1172. package/temp_resend_cli/repo/src/commands/webhooks/listen.ts +0 -379
  1173. package/temp_resend_cli/repo/src/commands/webhooks/update.ts +0 -83
  1174. package/temp_resend_cli/repo/src/commands/webhooks/utils.ts +0 -36
  1175. package/temp_resend_cli/repo/src/commands/whoami.ts +0 -71
  1176. package/temp_resend_cli/repo/src/lib/actions.ts +0 -157
  1177. package/temp_resend_cli/repo/src/lib/client.ts +0 -37
  1178. package/temp_resend_cli/repo/src/lib/config.ts +0 -217
  1179. package/temp_resend_cli/repo/src/lib/files.ts +0 -15
  1180. package/temp_resend_cli/repo/src/lib/help-text.ts +0 -38
  1181. package/temp_resend_cli/repo/src/lib/output.ts +0 -56
  1182. package/temp_resend_cli/repo/src/lib/pagination.ts +0 -36
  1183. package/temp_resend_cli/repo/src/lib/prompts.ts +0 -149
  1184. package/temp_resend_cli/repo/src/lib/spinner.ts +0 -100
  1185. package/temp_resend_cli/repo/src/lib/table.ts +0 -57
  1186. package/temp_resend_cli/repo/src/lib/tty.ts +0 -28
  1187. package/temp_resend_cli/repo/src/lib/update-check.ts +0 -169
  1188. package/temp_resend_cli/repo/src/lib/version.ts +0 -4
  1189. package/temp_resend_cli/repo/tests/commands/api-keys/create.test.ts +0 -196
  1190. package/temp_resend_cli/repo/tests/commands/api-keys/delete.test.ts +0 -157
  1191. package/temp_resend_cli/repo/tests/commands/api-keys/list.test.ts +0 -134
  1192. package/temp_resend_cli/repo/tests/commands/auth/login.test.ts +0 -153
  1193. package/temp_resend_cli/repo/tests/commands/auth/logout.test.ts +0 -153
  1194. package/temp_resend_cli/repo/tests/commands/broadcasts/create.test.ts +0 -454
  1195. package/temp_resend_cli/repo/tests/commands/broadcasts/delete.test.ts +0 -183
  1196. package/temp_resend_cli/repo/tests/commands/broadcasts/get.test.ts +0 -147
  1197. package/temp_resend_cli/repo/tests/commands/broadcasts/list.test.ts +0 -199
  1198. package/temp_resend_cli/repo/tests/commands/broadcasts/send.test.ts +0 -162
  1199. package/temp_resend_cli/repo/tests/commands/broadcasts/update.test.ts +0 -288
  1200. package/temp_resend_cli/repo/tests/commands/contact-properties/create.test.ts +0 -251
  1201. package/temp_resend_cli/repo/tests/commands/contact-properties/delete.test.ts +0 -184
  1202. package/temp_resend_cli/repo/tests/commands/contact-properties/get.test.ts +0 -145
  1203. package/temp_resend_cli/repo/tests/commands/contact-properties/list.test.ts +0 -181
  1204. package/temp_resend_cli/repo/tests/commands/contact-properties/update.test.ts +0 -217
  1205. package/temp_resend_cli/repo/tests/commands/contacts/add-segment.test.ts +0 -189
  1206. package/temp_resend_cli/repo/tests/commands/contacts/create.test.ts +0 -271
  1207. package/temp_resend_cli/repo/tests/commands/contacts/delete.test.ts +0 -193
  1208. package/temp_resend_cli/repo/tests/commands/contacts/get.test.ts +0 -149
  1209. package/temp_resend_cli/repo/tests/commands/contacts/list.test.ts +0 -176
  1210. package/temp_resend_cli/repo/tests/commands/contacts/remove-segment.test.ts +0 -167
  1211. package/temp_resend_cli/repo/tests/commands/contacts/segments.test.ts +0 -168
  1212. package/temp_resend_cli/repo/tests/commands/contacts/topics.test.ts +0 -164
  1213. package/temp_resend_cli/repo/tests/commands/contacts/update-topics.test.ts +0 -248
  1214. package/temp_resend_cli/repo/tests/commands/contacts/update.test.ts +0 -206
  1215. package/temp_resend_cli/repo/tests/commands/doctor.test.ts +0 -164
  1216. package/temp_resend_cli/repo/tests/commands/domains/create.test.ts +0 -193
  1217. package/temp_resend_cli/repo/tests/commands/domains/delete.test.ts +0 -157
  1218. package/temp_resend_cli/repo/tests/commands/domains/get.test.ts +0 -138
  1219. package/temp_resend_cli/repo/tests/commands/domains/list.test.ts +0 -165
  1220. package/temp_resend_cli/repo/tests/commands/domains/update.test.ts +0 -224
  1221. package/temp_resend_cli/repo/tests/commands/domains/verify.test.ts +0 -118
  1222. package/temp_resend_cli/repo/tests/commands/emails/batch.test.ts +0 -324
  1223. package/temp_resend_cli/repo/tests/commands/emails/get.test.ts +0 -132
  1224. package/temp_resend_cli/repo/tests/commands/emails/receiving/attachment.test.ts +0 -141
  1225. package/temp_resend_cli/repo/tests/commands/emails/receiving/attachments.test.ts +0 -169
  1226. package/temp_resend_cli/repo/tests/commands/emails/receiving/get.test.ts +0 -141
  1227. package/temp_resend_cli/repo/tests/commands/emails/receiving/list.test.ts +0 -182
  1228. package/temp_resend_cli/repo/tests/commands/emails/send.test.ts +0 -312
  1229. package/temp_resend_cli/repo/tests/commands/segments/create.test.ts +0 -164
  1230. package/temp_resend_cli/repo/tests/commands/segments/delete.test.ts +0 -183
  1231. package/temp_resend_cli/repo/tests/commands/segments/get.test.ts +0 -138
  1232. package/temp_resend_cli/repo/tests/commands/segments/list.test.ts +0 -174
  1233. package/temp_resend_cli/repo/tests/commands/teams/list.test.ts +0 -62
  1234. package/temp_resend_cli/repo/tests/commands/teams/remove.test.ts +0 -110
  1235. package/temp_resend_cli/repo/tests/commands/teams/switch.test.ts +0 -103
  1236. package/temp_resend_cli/repo/tests/commands/topics/create.test.ts +0 -192
  1237. package/temp_resend_cli/repo/tests/commands/topics/delete.test.ts +0 -157
  1238. package/temp_resend_cli/repo/tests/commands/topics/get.test.ts +0 -126
  1239. package/temp_resend_cli/repo/tests/commands/topics/list.test.ts +0 -125
  1240. package/temp_resend_cli/repo/tests/commands/topics/update.test.ts +0 -178
  1241. package/temp_resend_cli/repo/tests/commands/webhooks/create.test.ts +0 -225
  1242. package/temp_resend_cli/repo/tests/commands/webhooks/delete.test.ts +0 -157
  1243. package/temp_resend_cli/repo/tests/commands/webhooks/get.test.ts +0 -126
  1244. package/temp_resend_cli/repo/tests/commands/webhooks/list.test.ts +0 -178
  1245. package/temp_resend_cli/repo/tests/commands/webhooks/update.test.ts +0 -207
  1246. package/temp_resend_cli/repo/tests/commands/whoami.test.ts +0 -98
  1247. package/temp_resend_cli/repo/tests/e2e/smoke.test.ts +0 -93
  1248. package/temp_resend_cli/repo/tests/helpers.ts +0 -86
  1249. package/temp_resend_cli/repo/tests/lib/client.test.ts +0 -71
  1250. package/temp_resend_cli/repo/tests/lib/config.test.ts +0 -451
  1251. package/temp_resend_cli/repo/tests/lib/files.test.ts +0 -73
  1252. package/temp_resend_cli/repo/tests/lib/help-text.test.ts +0 -97
  1253. package/temp_resend_cli/repo/tests/lib/output.test.ts +0 -136
  1254. package/temp_resend_cli/repo/tests/lib/prompts.test.ts +0 -185
  1255. package/temp_resend_cli/repo/tests/lib/spinner.test.ts +0 -166
  1256. package/temp_resend_cli/repo/tests/lib/table.test.ts +0 -63
  1257. package/temp_resend_cli/repo/tests/lib/tty.test.ts +0 -89
  1258. package/temp_resend_cli/repo/tests/lib/update-check.test.ts +0 -179
  1259. package/temp_resend_cli/repo/tsconfig.json +0 -14
  1260. package/temp_resend_cli/repo/vitest.config.e2e.ts +0 -8
  1261. package/temp_resend_cli/repo/vitest.config.ts +0 -10
  1262. /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
- }