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.
- package/README.md +77 -53
- package/__tests__/azd-plugin.test.js +109 -0
- package/__tests__/config.test.js +4 -3
- package/__tests__/discover.test.js +59 -0
- package/__tests__/goose-plugin.test.js +149 -0
- package/__tests__/help-json.test.js +2 -0
- package/__tests__/openhands-plugin.test.js +106 -0
- package/__tests__/plugin-cocoindex-code-uninstall.test.js +19 -0
- package/__tests__/plugin-cocoindex-code.test.js +37 -0
- package/__tests__/plugin-install-guidance.test.js +81 -0
- package/__tests__/plugins-registry.test.js +44 -0
- package/__tests__/plugins-store.test.js +40 -5
- package/__tests__/process-adapter.test.js +50 -1
- package/__tests__/server-app.test.js +1 -0
- package/__tests__/server-routes-commands.test.js +20 -2
- package/__tests__/server-routes-plugins.test.js +130 -0
- package/__tests__/skills.test.js +26 -0
- package/__tests__/squirrelscan-plugin.test.js +129 -0
- package/__tests__/uipath-plugin.test.js +104 -0
- package/__tests__/uipathcli-plugin.test.js +95 -0
- package/cli/adapters/mcp.js +2 -0
- package/cli/adapters/process.js +49 -2
- package/cli/config.js +240 -3
- package/cli/discover.js +157 -0
- package/cli/help-json.js +16 -1
- package/cli/plugin-install-guidance.js +92 -37
- package/cli/plugins-manager.js +1 -0
- package/cli/plugins-registry.js +74 -8
- package/cli/plugins-store.js +78 -17
- package/cli/skills-mcp.js +1 -1
- package/cli/skills.js +39 -2
- package/cli/supercli.js +87 -11
- package/docs/feature-gaps.md +8 -8
- package/docs/features/azd-uipath-plugins.md +43 -0
- package/docs/features/server-plugins.md +62 -0
- package/docs/features/skills.md +9 -5
- package/docs/{supported-harnesses.md → plugins-available.md} +4 -3
- package/docs/{plugin-harness-guide.md → plugins-how-to.md} +1 -1
- package/docs/plugins.md +26 -20
- package/docs/server-plugins-usage-guide.md +182 -0
- package/docs/skills-catalog.md +12 -10
- package/package.json +1 -1
- package/plugins/agent-browser/README.md +69 -0
- package/plugins/agent-browser/plugin.json +111 -0
- package/plugins/agent-browser/skills/quickstart/SKILL.md +66 -0
- package/plugins/aider/README.md +53 -0
- package/plugins/aider/plugin.json +105 -0
- package/plugins/aider/scripts/aider-wrapper.js +243 -0
- package/plugins/aider/scripts/setup-aider.js +37 -0
- package/plugins/aider/skills/dry-run-review.md +24 -0
- package/plugins/aider/skills/model-and-provider.md +24 -0
- package/plugins/aider/skills/one-shot-edits.md +30 -0
- package/plugins/aider/skills/quickstart/SKILL.md +51 -0
- package/plugins/azd/README.md +28 -0
- package/plugins/azd/plugin.json +87 -0
- package/plugins/azd/skills/quickstart/SKILL.md +41 -0
- package/plugins/blogwatcher/README.md +3 -3
- package/plugins/boxlite/Dockerfile +9 -0
- package/plugins/boxlite/README.md +62 -0
- package/plugins/boxlite/plugin.json +201 -0
- package/plugins/boxlite/scripts/run-boxlite.js +106 -0
- package/plugins/boxlite/skills/quickstart/SKILL.md +40 -0
- package/plugins/cass/plugin.json +150 -0
- package/plugins/cass/scripts/setup-cass.js +47 -0
- package/plugins/cass/skills/quickstart/SKILL.md +46 -0
- package/plugins/clever/README.md +46 -0
- package/plugins/clever/plugin.json +119 -0
- package/plugins/clever/scripts/setup-clever.js +28 -0
- package/plugins/clever/skills/auth-and-profile.md +29 -0
- package/plugins/clever/skills/passthrough-safety.md +21 -0
- package/plugins/clever/skills/quickstart/SKILL.md +45 -0
- package/plugins/clever/skills/resource-inventory.md +24 -0
- package/plugins/clix/README.md +4 -4
- package/plugins/cocoindex-code/README.md +64 -0
- package/plugins/cocoindex-code/plugin.json +81 -0
- package/plugins/cocoindex-code/scripts/__pycache__/query.cpython-310.pyc +0 -0
- package/plugins/cocoindex-code/scripts/__pycache__/query.cpython-311.pyc +0 -0
- package/plugins/cocoindex-code/scripts/post-install.js +61 -0
- package/plugins/cocoindex-code/scripts/post-uninstall.js +25 -0
- package/plugins/cocoindex-code/scripts/query.py +88 -0
- package/plugins/cocoindex-code/scripts/run-query.js +50 -0
- package/plugins/cocoindex-code/skills/quickstart/SKILL.md +73 -0
- package/plugins/copilot/README.md +24 -0
- package/plugins/copilot/plugin.json +80 -0
- package/plugins/copilot/skills/quickstart/SKILL.md +44 -0
- package/plugins/gemini/README.md +24 -0
- package/plugins/gemini/plugin.json +98 -0
- package/plugins/gemini/skills/quickstart/SKILL.md +44 -0
- package/plugins/gifcap/plugin.json +119 -0
- package/plugins/gifcap/scripts/setup-gifcap.js +44 -0
- package/plugins/gifcap/skills/quickstart/SKILL.md +34 -0
- package/plugins/gifcap/test-record-quiet.gif +0 -0
- package/plugins/gifcap/test-record.gif +0 -0
- package/plugins/goose/README.md +36 -0
- package/plugins/goose/plugin.json +183 -0
- package/plugins/goose/skills/quickstart/SKILL.md +44 -0
- package/plugins/json-server/README.md +58 -0
- package/plugins/json-server/plugin.json +113 -0
- package/plugins/json-server/skills/quickstart/SKILL.md +57 -0
- package/plugins/lightpanda/README.md +145 -0
- package/plugins/lightpanda/package-lock.json +1375 -0
- package/plugins/lightpanda/package.json +12 -0
- package/plugins/lightpanda/plugin.json +116 -0
- package/plugins/lightpanda/scripts/lightpanda-contacts.js +494 -0
- package/plugins/lightpanda/scripts/lightpanda-generic-extract.js +403 -0
- package/plugins/lightpanda/scripts/lightpanda-wrapper.js +480 -0
- package/plugins/lightpanda/scripts/setup-lightpanda.js +39 -0
- package/plugins/lightpanda/skills/contact-discovery.md +51 -0
- package/plugins/lightpanda/skills/generic-extraction.md +66 -0
- package/plugins/lightpanda/skills/quickstart/SKILL.md +103 -0
- package/plugins/lightpanda/skills/resilient-navigation.md +42 -0
- package/plugins/monty/README.md +2 -2
- package/plugins/nullclaw/README.md +3 -3
- package/plugins/offline-ai/README.md +23 -0
- package/plugins/offline-ai/plugin.json +82 -0
- package/plugins/offline-ai/skills/quickstart/SKILL.md +43 -0
- package/plugins/openhands/README.md +25 -0
- package/plugins/openhands/plugin.json +116 -0
- package/plugins/openhands/skills/quickstart/SKILL.md +26 -0
- package/plugins/plandex/README.md +25 -0
- package/plugins/plandex/plugin.json +130 -0
- package/plugins/plandex/skills/quickstart/SKILL.md +50 -0
- package/plugins/plugins.json +188 -0
- package/plugins/squirrelscan/Dockerfile +5 -0
- package/plugins/squirrelscan/README.md +47 -0
- package/plugins/squirrelscan/plugin.json +493 -0
- package/plugins/squirrelscan/scripts/post-install.js +33 -0
- package/plugins/squirrelscan/scripts/post-uninstall.js +25 -0
- package/plugins/squirrelscan/scripts/run-squirrel.js +73 -0
- package/plugins/squirrelscan/skills/audit-workflow/SKILL.md +33 -0
- package/plugins/squirrelscan/skills/publish-report/SKILL.md +33 -0
- package/plugins/squirrelscan/skills/quickstart/SKILL.md +41 -0
- package/plugins/uipath/README.md +27 -0
- package/plugins/uipath/plugin.json +86 -0
- package/plugins/uipath/skills/quickstart/SKILL.md +47 -0
- package/plugins/uipathcli/README.md +28 -0
- package/plugins/uipathcli/plugin.json +120 -0
- package/plugins/uipathcli/scripts/run-uipath-cli.js +49 -0
- package/plugins/uipathcli/skills/quickstart/SKILL.md +22 -0
- package/plugins/xurl/README.md +4 -4
- package/server/app.js +5 -2
- package/server/public/app.js +3 -0
- package/server/routes/commands.js +95 -12
- package/server/routes/plugins.js +262 -0
- package/server/services/pluginsService.js +303 -0
- package/server/views/command-edit.ejs +196 -14
- package/server/views/partials/head.ejs +1 -0
- package/server/views/plugins.ejs +264 -0
- package/tests/test-plugins-registry.js +30 -0
- package/.beads/.br_history/issues.20260308_200823_636718328.jsonl +0 -20
- package/.beads/.br_history/issues.20260308_200823_636718328.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_200827_033159453.jsonl +0 -21
- package/.beads/.br_history/issues.20260308_200827_033159453.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_200829_595900053.jsonl +0 -22
- package/.beads/.br_history/issues.20260308_200829_595900053.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_200834_079930100.jsonl +0 -23
- package/.beads/.br_history/issues.20260308_200834_079930100.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_200858_370924996.jsonl +0 -24
- package/.beads/.br_history/issues.20260308_200858_370924996.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_201031_019730855.jsonl +0 -24
- package/.beads/.br_history/issues.20260308_201031_019730855.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_201031_578974884.jsonl +0 -24
- package/.beads/.br_history/issues.20260308_201031_578974884.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_201054_780345548.jsonl +0 -24
- package/.beads/.br_history/issues.20260308_201054_780345548.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_201054_896980019.jsonl +0 -24
- package/.beads/.br_history/issues.20260308_201054_896980019.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_201128_599819688.jsonl +0 -24
- package/.beads/.br_history/issues.20260308_201128_599819688.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_201128_710221699.jsonl +0 -24
- package/.beads/.br_history/issues.20260308_201128_710221699.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_201204_745649213.jsonl +0 -24
- package/.beads/.br_history/issues.20260308_201204_745649213.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_201338_908436144.jsonl +0 -24
- package/.beads/.br_history/issues.20260308_201338_908436144.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_201344_734860714.jsonl +0 -25
- package/.beads/.br_history/issues.20260308_201344_734860714.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_201630_819282295.jsonl +0 -25
- package/.beads/.br_history/issues.20260308_201630_819282295.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_203538_054279699.jsonl +0 -25
- package/.beads/.br_history/issues.20260308_203538_054279699.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_203547_597113070.jsonl +0 -26
- package/.beads/.br_history/issues.20260308_203547_597113070.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_203547_775139216.jsonl +0 -27
- package/.beads/.br_history/issues.20260308_203547_775139216.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_203547_950724773.jsonl +0 -28
- package/.beads/.br_history/issues.20260308_203547_950724773.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_203548_107684523.jsonl +0 -29
- package/.beads/.br_history/issues.20260308_203548_107684523.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_203548_310389993.jsonl +0 -30
- package/.beads/.br_history/issues.20260308_203548_310389993.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_203825_953337320.jsonl +0 -31
- package/.beads/.br_history/issues.20260308_203825_953337320.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_204056_071377736.jsonl +0 -32
- package/.beads/.br_history/issues.20260308_204056_071377736.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_205141_517616844.jsonl +0 -32
- package/.beads/.br_history/issues.20260308_205141_517616844.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_205141_648994024.jsonl +0 -32
- package/.beads/.br_history/issues.20260308_205141_648994024.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_205141_867598036.jsonl +0 -32
- package/.beads/.br_history/issues.20260308_205141_867598036.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_205142_094157355.jsonl +0 -32
- package/.beads/.br_history/issues.20260308_205142_094157355.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_205142_327315677.jsonl +0 -32
- package/.beads/.br_history/issues.20260308_205142_327315677.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_205142_545563822.jsonl +0 -32
- package/.beads/.br_history/issues.20260308_205142_545563822.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_205213_061989333.jsonl +0 -32
- package/.beads/.br_history/issues.20260308_205213_061989333.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_205213_181103364.jsonl +0 -32
- package/.beads/.br_history/issues.20260308_205213_181103364.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_205213_408872234.jsonl +0 -32
- package/.beads/.br_history/issues.20260308_205213_408872234.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_205213_616681652.jsonl +0 -32
- package/.beads/.br_history/issues.20260308_205213_616681652.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_205213_821507069.jsonl +0 -32
- package/.beads/.br_history/issues.20260308_205213_821507069.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_205214_026661112.jsonl +0 -32
- package/.beads/.br_history/issues.20260308_205214_026661112.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_205454_955250554.jsonl +0 -32
- package/.beads/.br_history/issues.20260308_205454_955250554.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_205556_337800392.jsonl +0 -33
- package/.beads/.br_history/issues.20260308_205556_337800392.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_205824_274686694.jsonl +0 -33
- package/.beads/.br_history/issues.20260308_205824_274686694.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_210240_583768328.jsonl +0 -34
- package/.beads/.br_history/issues.20260308_210240_583768328.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_212223_641541494.jsonl +0 -34
- package/.beads/.br_history/issues.20260308_212223_641541494.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_212227_735550996.jsonl +0 -35
- package/.beads/.br_history/issues.20260308_212227_735550996.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_212232_547298548.jsonl +0 -36
- package/.beads/.br_history/issues.20260308_212232_547298548.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_212528_843628125.jsonl +0 -37
- package/.beads/.br_history/issues.20260308_212528_843628125.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_212529_094530502.jsonl +0 -38
- package/.beads/.br_history/issues.20260308_212529_094530502.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_212529_331000853.jsonl +0 -39
- package/.beads/.br_history/issues.20260308_212529_331000853.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_212529_587925652.jsonl +0 -40
- package/.beads/.br_history/issues.20260308_212529_587925652.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_212804_927764103.jsonl +0 -41
- package/.beads/.br_history/issues.20260308_212804_927764103.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_212805_153673453.jsonl +0 -42
- package/.beads/.br_history/issues.20260308_212805_153673453.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_212805_415982363.jsonl +0 -43
- package/.beads/.br_history/issues.20260308_212805_415982363.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_212805_657497741.jsonl +0 -44
- package/.beads/.br_history/issues.20260308_212805_657497741.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_212805_952838724.jsonl +0 -45
- package/.beads/.br_history/issues.20260308_212805_952838724.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_212806_325433779.jsonl +0 -46
- package/.beads/.br_history/issues.20260308_212806_325433779.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_212806_584685598.jsonl +0 -47
- package/.beads/.br_history/issues.20260308_212806_584685598.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_212806_827817208.jsonl +0 -48
- package/.beads/.br_history/issues.20260308_212806_827817208.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_212807_111320451.jsonl +0 -49
- package/.beads/.br_history/issues.20260308_212807_111320451.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_212807_409545536.jsonl +0 -50
- package/.beads/.br_history/issues.20260308_212807_409545536.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_212807_625063294.jsonl +0 -51
- package/.beads/.br_history/issues.20260308_212807_625063294.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_212807_843906551.jsonl +0 -52
- package/.beads/.br_history/issues.20260308_212807_843906551.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_212808_100304073.jsonl +0 -53
- package/.beads/.br_history/issues.20260308_212808_100304073.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_212808_324723976.jsonl +0 -54
- package/.beads/.br_history/issues.20260308_212808_324723976.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_212808_557513104.jsonl +0 -55
- package/.beads/.br_history/issues.20260308_212808_557513104.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_212808_788048322.jsonl +0 -56
- package/.beads/.br_history/issues.20260308_212808_788048322.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_213702_613249728.jsonl +0 -57
- package/.beads/.br_history/issues.20260308_213702_613249728.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_213715_115792063.jsonl +0 -57
- package/.beads/.br_history/issues.20260308_213715_115792063.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_213715_462220666.jsonl +0 -57
- package/.beads/.br_history/issues.20260308_213715_462220666.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_213727_191258923.jsonl +0 -57
- package/.beads/.br_history/issues.20260308_213727_191258923.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_213727_684383652.jsonl +0 -57
- package/.beads/.br_history/issues.20260308_213727_684383652.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_213735_751882991.jsonl +0 -57
- package/.beads/.br_history/issues.20260308_213735_751882991.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_222052_279844960.jsonl +0 -57
- package/.beads/.br_history/issues.20260308_222052_279844960.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_222056_873282114.jsonl +0 -57
- package/.beads/.br_history/issues.20260308_222056_873282114.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_222103_402410761.jsonl +0 -57
- package/.beads/.br_history/issues.20260308_222103_402410761.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_235202_180577215.jsonl +0 -57
- package/.beads/.br_history/issues.20260308_235202_180577215.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_235202_387414163.jsonl +0 -57
- package/.beads/.br_history/issues.20260308_235202_387414163.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_235202_564422794.jsonl +0 -57
- package/.beads/.br_history/issues.20260308_235202_564422794.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_235202_742600597.jsonl +0 -57
- package/.beads/.br_history/issues.20260308_235202_742600597.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_235208_133360069.jsonl +0 -57
- package/.beads/.br_history/issues.20260308_235208_133360069.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_235505_473406307.jsonl +0 -57
- package/.beads/.br_history/issues.20260308_235505_473406307.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_235505_662360489.jsonl +0 -57
- package/.beads/.br_history/issues.20260308_235505_662360489.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_235505_843935624.jsonl +0 -57
- package/.beads/.br_history/issues.20260308_235505_843935624.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260308_235506_044530221.jsonl +0 -57
- package/.beads/.br_history/issues.20260308_235506_044530221.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260309_002618_115728731.jsonl +0 -57
- package/.beads/.br_history/issues.20260309_002618_115728731.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260309_003748_878174586.jsonl +0 -57
- package/.beads/.br_history/issues.20260309_003748_878174586.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260309_004057_868755623.jsonl +0 -57
- package/.beads/.br_history/issues.20260309_004057_868755623.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260309_004058_512842163.jsonl +0 -57
- package/.beads/.br_history/issues.20260309_004058_512842163.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260309_004058_994445226.jsonl +0 -57
- package/.beads/.br_history/issues.20260309_004058_994445226.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260309_004059_475988596.jsonl +0 -57
- package/.beads/.br_history/issues.20260309_004059_475988596.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260309_161902_566857851.jsonl +0 -57
- package/.beads/.br_history/issues.20260309_161902_566857851.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260309_170512_277017739.jsonl +0 -57
- package/.beads/.br_history/issues.20260309_170512_277017739.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260309_170512_477876921.jsonl +0 -57
- package/.beads/.br_history/issues.20260309_170512_477876921.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260309_170512_664382701.jsonl +0 -57
- package/.beads/.br_history/issues.20260309_170512_664382701.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260309_170512_859400333.jsonl +0 -57
- package/.beads/.br_history/issues.20260309_170512_859400333.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260309_212326_082771164.jsonl +0 -57
- package/.beads/.br_history/issues.20260309_212326_082771164.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260309_212326_245619716.jsonl +0 -58
- package/.beads/.br_history/issues.20260309_212326_245619716.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260309_212326_403198317.jsonl +0 -59
- package/.beads/.br_history/issues.20260309_212326_403198317.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260309_212332_539197678.jsonl +0 -60
- package/.beads/.br_history/issues.20260309_212332_539197678.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260309_212332_731373599.jsonl +0 -60
- package/.beads/.br_history/issues.20260309_212332_731373599.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260309_212332_928710953.jsonl +0 -60
- package/.beads/.br_history/issues.20260309_212332_928710953.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260309_213021_341505240.jsonl +0 -60
- package/.beads/.br_history/issues.20260309_213021_341505240.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260309_213022_023136934.jsonl +0 -60
- package/.beads/.br_history/issues.20260309_213022_023136934.jsonl.meta.json +0 -1
- package/.beads/.br_history/issues.20260309_213022_400050719.jsonl +0 -60
- package/.beads/.br_history/issues.20260309_213022_400050719.jsonl.meta.json +0 -1
- package/.beads/config.yaml +0 -4
- package/.beads/issues.jsonl +0 -60
- package/.beads/metadata.json +0 -4
- package/docs/mcp-cheatsheet.md +0 -324
- package/docs/visual-overview.md +0 -21
- package/ref-monty/.cargo/config.toml +0 -3
- package/ref-monty/.claude/settings.json +0 -60
- package/ref-monty/.claude/skills/fastmod/SKILL.md +0 -22
- package/ref-monty/.claude/skills/python-playground/SKILL.md +0 -47
- package/ref-monty/.codecov.yml +0 -12
- package/ref-monty/.github/actions/build-pgo-wheel/action.yml +0 -72
- package/ref-monty/.github/workflows/ci.yml +0 -776
- package/ref-monty/.github/workflows/codspeed.yml +0 -45
- package/ref-monty/.github/workflows/init-npm-packages.yml +0 -82
- package/ref-monty/.pre-commit-config.yaml +0 -47
- package/ref-monty/.python-version +0 -1
- package/ref-monty/.rustfmt.toml +0 -4
- package/ref-monty/.zed/settings.json +0 -11
- package/ref-monty/CLAUDE.md +0 -535
- package/ref-monty/Cargo.lock +0 -3798
- package/ref-monty/Cargo.toml +0 -87
- package/ref-monty/LICENSE +0 -21
- package/ref-monty/Makefile +0 -216
- package/ref-monty/README.md +0 -430
- package/ref-monty/RELEASING.md +0 -47
- package/ref-monty/crates/fuzz/Cargo.toml +0 -30
- package/ref-monty/crates/fuzz/fuzz_targets/string_input_panic.rs +0 -37
- package/ref-monty/crates/fuzz/fuzz_targets/tokens_input_panic.rs +0 -552
- package/ref-monty/crates/monty/Cargo.toml +0 -68
- package/ref-monty/crates/monty/benches/main.rs +0 -247
- package/ref-monty/crates/monty/build.rs +0 -10
- package/ref-monty/crates/monty/src/args.rs +0 -733
- package/ref-monty/crates/monty/src/asyncio.rs +0 -179
- package/ref-monty/crates/monty/src/builtins/abs.rs +0 -55
- package/ref-monty/crates/monty/src/builtins/all.rs +0 -30
- package/ref-monty/crates/monty/src/builtins/any.rs +0 -30
- package/ref-monty/crates/monty/src/builtins/bin.rs +0 -59
- package/ref-monty/crates/monty/src/builtins/chr.rs +0 -46
- package/ref-monty/crates/monty/src/builtins/divmod.rs +0 -164
- package/ref-monty/crates/monty/src/builtins/enumerate.rs +0 -52
- package/ref-monty/crates/monty/src/builtins/filter.rs +0 -67
- package/ref-monty/crates/monty/src/builtins/getattr.rs +0 -65
- package/ref-monty/crates/monty/src/builtins/hash.rs +0 -28
- package/ref-monty/crates/monty/src/builtins/hex.rs +0 -58
- package/ref-monty/crates/monty/src/builtins/id.rs +0 -24
- package/ref-monty/crates/monty/src/builtins/isinstance.rs +0 -68
- package/ref-monty/crates/monty/src/builtins/len.rs +0 -25
- package/ref-monty/crates/monty/src/builtins/map.rs +0 -98
- package/ref-monty/crates/monty/src/builtins/min_max.rs +0 -113
- package/ref-monty/crates/monty/src/builtins/mod.rs +0 -246
- package/ref-monty/crates/monty/src/builtins/next.rs +0 -21
- package/ref-monty/crates/monty/src/builtins/oct.rs +0 -59
- package/ref-monty/crates/monty/src/builtins/ord.rs +0 -67
- package/ref-monty/crates/monty/src/builtins/pow.rs +0 -365
- package/ref-monty/crates/monty/src/builtins/print.rs +0 -141
- package/ref-monty/crates/monty/src/builtins/repr.rs +0 -16
- package/ref-monty/crates/monty/src/builtins/reversed.rs +0 -28
- package/ref-monty/crates/monty/src/builtins/round.rs +0 -174
- package/ref-monty/crates/monty/src/builtins/sorted.rs +0 -151
- package/ref-monty/crates/monty/src/builtins/sum.rs +0 -66
- package/ref-monty/crates/monty/src/builtins/type_.rs +0 -16
- package/ref-monty/crates/monty/src/builtins/zip.rs +0 -77
- package/ref-monty/crates/monty/src/bytecode/builder.rs +0 -699
- package/ref-monty/crates/monty/src/bytecode/code.rs +0 -310
- package/ref-monty/crates/monty/src/bytecode/compiler.rs +0 -3206
- package/ref-monty/crates/monty/src/bytecode/mod.rs +0 -24
- package/ref-monty/crates/monty/src/bytecode/op.rs +0 -617
- package/ref-monty/crates/monty/src/bytecode/vm/async_exec.rs +0 -1058
- package/ref-monty/crates/monty/src/bytecode/vm/attr.rs +0 -63
- package/ref-monty/crates/monty/src/bytecode/vm/binary.rs +0 -487
- package/ref-monty/crates/monty/src/bytecode/vm/call.rs +0 -767
- package/ref-monty/crates/monty/src/bytecode/vm/collections.rs +0 -741
- package/ref-monty/crates/monty/src/bytecode/vm/compare.rs +0 -147
- package/ref-monty/crates/monty/src/bytecode/vm/exceptions.rs +0 -297
- package/ref-monty/crates/monty/src/bytecode/vm/format.rs +0 -132
- package/ref-monty/crates/monty/src/bytecode/vm/mod.rs +0 -1958
- package/ref-monty/crates/monty/src/bytecode/vm/scheduler.rs +0 -620
- package/ref-monty/crates/monty/src/exception_private.rs +0 -1513
- package/ref-monty/crates/monty/src/exception_public.rs +0 -346
- package/ref-monty/crates/monty/src/expressions.rs +0 -694
- package/ref-monty/crates/monty/src/fstring.rs +0 -854
- package/ref-monty/crates/monty/src/function.rs +0 -119
- package/ref-monty/crates/monty/src/heap.rs +0 -1073
- package/ref-monty/crates/monty/src/heap_data.rs +0 -985
- package/ref-monty/crates/monty/src/heap_traits.rs +0 -312
- package/ref-monty/crates/monty/src/intern.rs +0 -837
- package/ref-monty/crates/monty/src/io.rs +0 -106
- package/ref-monty/crates/monty/src/lib.rs +0 -52
- package/ref-monty/crates/monty/src/modules/asyncio.rs +0 -144
- package/ref-monty/crates/monty/src/modules/math.rs +0 -1453
- package/ref-monty/crates/monty/src/modules/mod.rs +0 -120
- package/ref-monty/crates/monty/src/modules/os.rs +0 -116
- package/ref-monty/crates/monty/src/modules/pathlib.rs +0 -33
- package/ref-monty/crates/monty/src/modules/re.rs +0 -606
- package/ref-monty/crates/monty/src/modules/sys.rs +0 -60
- package/ref-monty/crates/monty/src/modules/typing.rs +0 -70
- package/ref-monty/crates/monty/src/namespace.rs +0 -21
- package/ref-monty/crates/monty/src/object.rs +0 -1040
- package/ref-monty/crates/monty/src/os.rs +0 -215
- package/ref-monty/crates/monty/src/parse.rs +0 -1730
- package/ref-monty/crates/monty/src/prepare.rs +0 -3015
- package/ref-monty/crates/monty/src/repl.rs +0 -1109
- package/ref-monty/crates/monty/src/resource.rs +0 -559
- package/ref-monty/crates/monty/src/run.rs +0 -457
- package/ref-monty/crates/monty/src/run_progress.rs +0 -821
- package/ref-monty/crates/monty/src/signature.rs +0 -651
- package/ref-monty/crates/monty/src/sorting.rs +0 -100
- package/ref-monty/crates/monty/src/types/bytes.rs +0 -2356
- package/ref-monty/crates/monty/src/types/dataclass.rs +0 -345
- package/ref-monty/crates/monty/src/types/dict.rs +0 -879
- package/ref-monty/crates/monty/src/types/dict_view.rs +0 -619
- package/ref-monty/crates/monty/src/types/iter.rs +0 -799
- package/ref-monty/crates/monty/src/types/list.rs +0 -929
- package/ref-monty/crates/monty/src/types/long_int.rs +0 -211
- package/ref-monty/crates/monty/src/types/mod.rs +0 -48
- package/ref-monty/crates/monty/src/types/module.rs +0 -146
- package/ref-monty/crates/monty/src/types/namedtuple.rs +0 -261
- package/ref-monty/crates/monty/src/types/path.rs +0 -596
- package/ref-monty/crates/monty/src/types/property.rs +0 -35
- package/ref-monty/crates/monty/src/types/py_trait.rs +0 -322
- package/ref-monty/crates/monty/src/types/range.rs +0 -285
- package/ref-monty/crates/monty/src/types/re_match.rs +0 -522
- package/ref-monty/crates/monty/src/types/re_pattern.rs +0 -726
- package/ref-monty/crates/monty/src/types/set.rs +0 -1373
- package/ref-monty/crates/monty/src/types/slice.rs +0 -257
- package/ref-monty/crates/monty/src/types/str.rs +0 -2051
- package/ref-monty/crates/monty/src/types/tuple.rs +0 -376
- package/ref-monty/crates/monty/src/types/type.rs +0 -407
- package/ref-monty/crates/monty/src/value.rs +0 -2558
- package/ref-monty/crates/monty/test_cases/args__dict_get_no_args.py +0 -3
- package/ref-monty/crates/monty/test_cases/args__dict_get_too_many.py +0 -3
- package/ref-monty/crates/monty/test_cases/args__dict_items_with_args.py +0 -3
- package/ref-monty/crates/monty/test_cases/args__dict_keys_with_args.py +0 -3
- package/ref-monty/crates/monty/test_cases/args__dict_pop_no_args.py +0 -3
- package/ref-monty/crates/monty/test_cases/args__dict_pop_too_many.py +0 -3
- package/ref-monty/crates/monty/test_cases/args__dict_values_with_args.py +0 -3
- package/ref-monty/crates/monty/test_cases/args__id_too_many.py +0 -2
- package/ref-monty/crates/monty/test_cases/args__len_no_args.py +0 -2
- package/ref-monty/crates/monty/test_cases/args__len_too_many.py +0 -2
- package/ref-monty/crates/monty/test_cases/args__len_type_error_int.py +0 -9
- package/ref-monty/crates/monty/test_cases/args__len_type_error_none.py +0 -9
- package/ref-monty/crates/monty/test_cases/args__list_append_no_args.py +0 -3
- package/ref-monty/crates/monty/test_cases/args__list_append_too_many.py +0 -3
- package/ref-monty/crates/monty/test_cases/args__list_insert_too_few.py +0 -3
- package/ref-monty/crates/monty/test_cases/args__list_insert_too_many.py +0 -3
- package/ref-monty/crates/monty/test_cases/args__repr_no_args.py +0 -2
- package/ref-monty/crates/monty/test_cases/arith__div_zero_float.py +0 -2
- package/ref-monty/crates/monty/test_cases/arith__div_zero_int.py +0 -2
- package/ref-monty/crates/monty/test_cases/arith__floordiv_zero_float.py +0 -2
- package/ref-monty/crates/monty/test_cases/arith__floordiv_zero_int.py +0 -2
- package/ref-monty/crates/monty/test_cases/arith__pow_zero_neg.py +0 -2
- package/ref-monty/crates/monty/test_cases/arith__pow_zero_neg_builtin.py +0 -9
- package/ref-monty/crates/monty/test_cases/assert__expr_fail.py +0 -2
- package/ref-monty/crates/monty/test_cases/assert__fail.py +0 -2
- package/ref-monty/crates/monty/test_cases/assert__fail_msg.py +0 -2
- package/ref-monty/crates/monty/test_cases/assert__fn_fail.py +0 -3
- package/ref-monty/crates/monty/test_cases/assert__ops.py +0 -11
- package/ref-monty/crates/monty/test_cases/async__asyncio_run.py +0 -47
- package/ref-monty/crates/monty/test_cases/async__basic.py +0 -10
- package/ref-monty/crates/monty/test_cases/async__closure.py +0 -14
- package/ref-monty/crates/monty/test_cases/async__double_await_coroutine.py +0 -16
- package/ref-monty/crates/monty/test_cases/async__exception.py +0 -10
- package/ref-monty/crates/monty/test_cases/async__ext_call.py +0 -73
- package/ref-monty/crates/monty/test_cases/async__gather_all.py +0 -85
- package/ref-monty/crates/monty/test_cases/async__nested_await.py +0 -15
- package/ref-monty/crates/monty/test_cases/async__nested_gather_ext.py +0 -37
- package/ref-monty/crates/monty/test_cases/async__not_awaitable.py +0 -10
- package/ref-monty/crates/monty/test_cases/async__not_imported.py +0 -14
- package/ref-monty/crates/monty/test_cases/async__recursion_depth_isolation.py +0 -27
- package/ref-monty/crates/monty/test_cases/async__return_types.py +0 -31
- package/ref-monty/crates/monty/test_cases/async__sequential.py +0 -16
- package/ref-monty/crates/monty/test_cases/async__traceback.py +0 -19
- package/ref-monty/crates/monty/test_cases/async__with_args.py +0 -14
- package/ref-monty/crates/monty/test_cases/attr__get_int_error.py +0 -9
- package/ref-monty/crates/monty/test_cases/attr__get_list_error.py +0 -9
- package/ref-monty/crates/monty/test_cases/attr__set_frozen_nonfield.py +0 -12
- package/ref-monty/crates/monty/test_cases/attr__set_int_error.py +0 -10
- package/ref-monty/crates/monty/test_cases/attr__set_list_error.py +0 -10
- package/ref-monty/crates/monty/test_cases/bench__kitchen_sink.py +0 -68
- package/ref-monty/crates/monty/test_cases/bool__ops.py +0 -20
- package/ref-monty/crates/monty/test_cases/builtin__add_type_error.py +0 -2
- package/ref-monty/crates/monty/test_cases/builtin__filter.py +0 -62
- package/ref-monty/crates/monty/test_cases/builtin__filter_not_iterable.py +0 -11
- package/ref-monty/crates/monty/test_cases/builtin__getattr.py +0 -84
- package/ref-monty/crates/monty/test_cases/builtin__iter_funcs.py +0 -42
- package/ref-monty/crates/monty/test_cases/builtin__iter_next.py +0 -66
- package/ref-monty/crates/monty/test_cases/builtin__map.py +0 -74
- package/ref-monty/crates/monty/test_cases/builtin__map_not_iterable.py +0 -11
- package/ref-monty/crates/monty/test_cases/builtin__math_funcs.py +0 -154
- package/ref-monty/crates/monty/test_cases/builtin__more_iter_funcs.py +0 -148
- package/ref-monty/crates/monty/test_cases/builtin__next_stop_iteration.py +0 -10
- package/ref-monty/crates/monty/test_cases/builtin__print_invalid_kwarg.py +0 -9
- package/ref-monty/crates/monty/test_cases/builtin__print_kwargs.py +0 -12
- package/ref-monty/crates/monty/test_cases/builtin__repr.py +0 -3
- package/ref-monty/crates/monty/test_cases/builtin__string_funcs.py +0 -73
- package/ref-monty/crates/monty/test_cases/bytes__decode_invalid_utf8.py +0 -18
- package/ref-monty/crates/monty/test_cases/bytes__endswith_str_error.py +0 -10
- package/ref-monty/crates/monty/test_cases/bytes__getitem_index_error.py +0 -10
- package/ref-monty/crates/monty/test_cases/bytes__index_start_gt_end.py +0 -10
- package/ref-monty/crates/monty/test_cases/bytes__methods.py +0 -394
- package/ref-monty/crates/monty/test_cases/bytes__negative_count.py +0 -9
- package/ref-monty/crates/monty/test_cases/bytes__ops.py +0 -90
- package/ref-monty/crates/monty/test_cases/bytes__startswith_str_error.py +0 -10
- package/ref-monty/crates/monty/test_cases/call_object.py +0 -3
- package/ref-monty/crates/monty/test_cases/chain_comparison__all.py +0 -79
- package/ref-monty/crates/monty/test_cases/closure__param_shadows_outer.py +0 -81
- package/ref-monty/crates/monty/test_cases/closure__pep448.py +0 -203
- package/ref-monty/crates/monty/test_cases/closure__undefined_nonlocal.py +0 -13
- package/ref-monty/crates/monty/test_cases/compare__mixed_types.py +0 -120
- package/ref-monty/crates/monty/test_cases/comprehension__all.py +0 -208
- package/ref-monty/crates/monty/test_cases/comprehension__scope.py +0 -7
- package/ref-monty/crates/monty/test_cases/comprehension__unbound_local.py +0 -14
- package/ref-monty/crates/monty/test_cases/dataclass__basic.py +0 -238
- package/ref-monty/crates/monty/test_cases/dataclass__call_field_error.py +0 -12
- package/ref-monty/crates/monty/test_cases/dataclass__frozen_set_error.py +0 -12
- package/ref-monty/crates/monty/test_cases/dataclass__get_missing_attr_error.py +0 -11
- package/ref-monty/crates/monty/test_cases/dict__get_unhashable_key.py +0 -3
- package/ref-monty/crates/monty/test_cases/dict__literal_unhashable_key.py +0 -2
- package/ref-monty/crates/monty/test_cases/dict__method_pop_missing_error.py +0 -3
- package/ref-monty/crates/monty/test_cases/dict__methods.py +0 -151
- package/ref-monty/crates/monty/test_cases/dict__ops.py +0 -133
- package/ref-monty/crates/monty/test_cases/dict__pop_unhashable_key.py +0 -4
- package/ref-monty/crates/monty/test_cases/dict__popitem_empty.py +0 -9
- package/ref-monty/crates/monty/test_cases/dict__subscript_missing_key.py +0 -3
- package/ref-monty/crates/monty/test_cases/dict__unhashable_dict_key.py +0 -2
- package/ref-monty/crates/monty/test_cases/dict__unhashable_list_key.py +0 -2
- package/ref-monty/crates/monty/test_cases/dict__unpack_type_error.py +0 -2
- package/ref-monty/crates/monty/test_cases/dict__views.py +0 -165
- package/ref-monty/crates/monty/test_cases/edge__all.py +0 -26
- package/ref-monty/crates/monty/test_cases/edge__float_int_mod.py +0 -2
- package/ref-monty/crates/monty/test_cases/edge__int_float_mod.py +0 -2
- package/ref-monty/crates/monty/test_cases/exc__args.py +0 -16
- package/ref-monty/crates/monty/test_cases/exc__str.py +0 -15
- package/ref-monty/crates/monty/test_cases/execute_ok__all.py +0 -54
- package/ref-monty/crates/monty/test_cases/execute_raise__error_instance_str.py +0 -2
- package/ref-monty/crates/monty/test_cases/execute_raise__error_no_args.py +0 -2
- package/ref-monty/crates/monty/test_cases/execute_raise__error_string_arg.py +0 -2
- package/ref-monty/crates/monty/test_cases/execute_raise__error_string_arg_quotes.py +0 -2
- package/ref-monty/crates/monty/test_cases/execute_raise__error_type.py +0 -2
- package/ref-monty/crates/monty/test_cases/execute_raise__raise_instance_via_var.py +0 -4
- package/ref-monty/crates/monty/test_cases/execute_raise__raise_list.py +0 -2
- package/ref-monty/crates/monty/test_cases/execute_raise__raise_number.py +0 -2
- package/ref-monty/crates/monty/test_cases/execute_raise__raise_type_call_via_var.py +0 -4
- package/ref-monty/crates/monty/test_cases/execute_raise__raise_type_direct.py +0 -3
- package/ref-monty/crates/monty/test_cases/execute_raise__raise_type_via_var.py +0 -4
- package/ref-monty/crates/monty/test_cases/ext_call__arg_side_effect_bug.py +0 -22
- package/ref-monty/crates/monty/test_cases/ext_call__augmented.py +0 -17
- package/ref-monty/crates/monty/test_cases/ext_call__augmented_refcount_bug.py +0 -7
- package/ref-monty/crates/monty/test_cases/ext_call__bare_raise_after_resume.py +0 -34
- package/ref-monty/crates/monty/test_cases/ext_call__basic.py +0 -99
- package/ref-monty/crates/monty/test_cases/ext_call__boolean.py +0 -37
- package/ref-monty/crates/monty/test_cases/ext_call__boolean_side_effect_hang.py +0 -17
- package/ref-monty/crates/monty/test_cases/ext_call__closure_bug.py +0 -16
- package/ref-monty/crates/monty/test_cases/ext_call__comparison.py +0 -26
- package/ref-monty/crates/monty/test_cases/ext_call__deep_call_stack.py +0 -18
- package/ref-monty/crates/monty/test_cases/ext_call__elif.py +0 -171
- package/ref-monty/crates/monty/test_cases/ext_call__exc.py +0 -4
- package/ref-monty/crates/monty/test_cases/ext_call__exc_deep_stack.py +0 -39
- package/ref-monty/crates/monty/test_cases/ext_call__exc_in_function.py +0 -17
- package/ref-monty/crates/monty/test_cases/ext_call__exc_nested_functions.py +0 -31
- package/ref-monty/crates/monty/test_cases/ext_call__ext_exc.py +0 -171
- package/ref-monty/crates/monty/test_cases/ext_call__for.py +0 -114
- package/ref-monty/crates/monty/test_cases/ext_call__fstring.py +0 -12
- package/ref-monty/crates/monty/test_cases/ext_call__if.py +0 -135
- package/ref-monty/crates/monty/test_cases/ext_call__if_condition.py +0 -37
- package/ref-monty/crates/monty/test_cases/ext_call__in_closure.py +0 -14
- package/ref-monty/crates/monty/test_cases/ext_call__in_function.py +0 -40
- package/ref-monty/crates/monty/test_cases/ext_call__in_function_simple.py +0 -7
- package/ref-monty/crates/monty/test_cases/ext_call__literals.py +0 -17
- package/ref-monty/crates/monty/test_cases/ext_call__multi_in_func.py +0 -32
- package/ref-monty/crates/monty/test_cases/ext_call__name_lookup.py +0 -69
- package/ref-monty/crates/monty/test_cases/ext_call__name_lookup_undefined.py +0 -4
- package/ref-monty/crates/monty/test_cases/ext_call__nested_calls.py +0 -14
- package/ref-monty/crates/monty/test_cases/ext_call__recursion_bug.py +0 -19
- package/ref-monty/crates/monty/test_cases/ext_call__return.py +0 -28
- package/ref-monty/crates/monty/test_cases/ext_call__side_effects.py +0 -25
- package/ref-monty/crates/monty/test_cases/ext_call__subscript.py +0 -7
- package/ref-monty/crates/monty/test_cases/ext_call__ternary.py +0 -28
- package/ref-monty/crates/monty/test_cases/ext_call__try.py +0 -280
- package/ref-monty/crates/monty/test_cases/ext_call__try_simple.py +0 -10
- package/ref-monty/crates/monty/test_cases/ext_call__unary.py +0 -13
- package/ref-monty/crates/monty/test_cases/frozenset__ops.py +0 -178
- package/ref-monty/crates/monty/test_cases/fstring__all.py +0 -236
- package/ref-monty/crates/monty/test_cases/fstring__error_eq_align_on_str.py +0 -3
- package/ref-monty/crates/monty/test_cases/fstring__error_float_f_on_str.py +0 -3
- package/ref-monty/crates/monty/test_cases/fstring__error_int_d_on_float.py +0 -3
- package/ref-monty/crates/monty/test_cases/fstring__error_int_d_on_str.py +0 -3
- package/ref-monty/crates/monty/test_cases/fstring__error_invalid_spec.py +0 -4
- package/ref-monty/crates/monty/test_cases/fstring__error_invalid_spec_dynamic.py +0 -4
- package/ref-monty/crates/monty/test_cases/fstring__error_invalid_spec_str.py +0 -4
- package/ref-monty/crates/monty/test_cases/fstring__error_str_s_on_int.py +0 -3
- package/ref-monty/crates/monty/test_cases/function__call_duplicate_kwargs.py +0 -6
- package/ref-monty/crates/monty/test_cases/function__call_unpack.py +0 -42
- package/ref-monty/crates/monty/test_cases/function__defaults.py +0 -117
- package/ref-monty/crates/monty/test_cases/function__err_duplicate_arg.py +0 -7
- package/ref-monty/crates/monty/test_cases/function__err_duplicate_first_arg.py +0 -7
- package/ref-monty/crates/monty/test_cases/function__err_duplicate_kwarg_cleanup.py +0 -9
- package/ref-monty/crates/monty/test_cases/function__err_kwonly_as_positional.py +0 -7
- package/ref-monty/crates/monty/test_cases/function__err_missing_all_posonly.py +0 -7
- package/ref-monty/crates/monty/test_cases/function__err_missing_heap_cleanup.py +0 -9
- package/ref-monty/crates/monty/test_cases/function__err_missing_kwonly.py +0 -7
- package/ref-monty/crates/monty/test_cases/function__err_missing_posonly_with_kwarg.py +0 -7
- package/ref-monty/crates/monty/test_cases/function__err_missing_with_posonly.py +0 -7
- package/ref-monty/crates/monty/test_cases/function__err_posonly_as_kwarg.py +0 -7
- package/ref-monty/crates/monty/test_cases/function__err_posonly_first_as_kwarg.py +0 -7
- package/ref-monty/crates/monty/test_cases/function__err_too_many_posonly.py +0 -7
- package/ref-monty/crates/monty/test_cases/function__err_too_many_with_kwonly.py +0 -7
- package/ref-monty/crates/monty/test_cases/function__err_unexpected_kwarg.py +0 -7
- package/ref-monty/crates/monty/test_cases/function__err_unexpected_kwarg_cleanup.py +0 -9
- package/ref-monty/crates/monty/test_cases/function__err_unexpected_kwarg_quote.py +0 -13
- package/ref-monty/crates/monty/test_cases/function__err_unexpected_kwarg_simple.py +0 -7
- package/ref-monty/crates/monty/test_cases/function__err_unpack_duplicate_arg.py +0 -6
- package/ref-monty/crates/monty/test_cases/function__err_unpack_duplicate_heap.py +0 -8
- package/ref-monty/crates/monty/test_cases/function__err_unpack_int.py +0 -6
- package/ref-monty/crates/monty/test_cases/function__err_unpack_nonstring_key.py +0 -6
- package/ref-monty/crates/monty/test_cases/function__err_unpack_not_mapping.py +0 -6
- package/ref-monty/crates/monty/test_cases/function__kwargs_unpacking.py +0 -173
- package/ref-monty/crates/monty/test_cases/function__ops.py +0 -294
- package/ref-monty/crates/monty/test_cases/function__return_none.py +0 -42
- package/ref-monty/crates/monty/test_cases/function__signatures.py +0 -47
- package/ref-monty/crates/monty/test_cases/function__too_few_args_all.py +0 -6
- package/ref-monty/crates/monty/test_cases/function__too_few_args_one.py +0 -6
- package/ref-monty/crates/monty/test_cases/function__too_few_args_two.py +0 -6
- package/ref-monty/crates/monty/test_cases/function__too_many_args_one.py +0 -6
- package/ref-monty/crates/monty/test_cases/function__too_many_args_two.py +0 -6
- package/ref-monty/crates/monty/test_cases/function__too_many_args_zero.py +0 -6
- package/ref-monty/crates/monty/test_cases/global__error_assigned_before.py +0 -7
- package/ref-monty/crates/monty/test_cases/global__ops.py +0 -163
- package/ref-monty/crates/monty/test_cases/hash__dict_unhashable.py +0 -2
- package/ref-monty/crates/monty/test_cases/hash__list_unhashable.py +0 -2
- package/ref-monty/crates/monty/test_cases/hash__ops.py +0 -153
- package/ref-monty/crates/monty/test_cases/id__bytes_literals_distinct.py +0 -3
- package/ref-monty/crates/monty/test_cases/id__int_copy_distinct.py +0 -5
- package/ref-monty/crates/monty/test_cases/id__is_number_is_number.py +0 -3
- package/ref-monty/crates/monty/test_cases/id__non_overlapping_lifetimes_distinct_types.py +0 -10
- package/ref-monty/crates/monty/test_cases/id__non_overlapping_lifetimes_same_types.py +0 -6
- package/ref-monty/crates/monty/test_cases/id__ops.py +0 -97
- package/ref-monty/crates/monty/test_cases/id__str_literals_same.py +0 -3
- package/ref-monty/crates/monty/test_cases/if__elif_else.py +0 -207
- package/ref-monty/crates/monty/test_cases/if__raise_elif.py +0 -11
- package/ref-monty/crates/monty/test_cases/if__raise_else.py +0 -13
- package/ref-monty/crates/monty/test_cases/if__raise_if.py +0 -9
- package/ref-monty/crates/monty/test_cases/if__raise_in_elif_condition.py +0 -18
- package/ref-monty/crates/monty/test_cases/if__raise_in_if_condition.py +0 -16
- package/ref-monty/crates/monty/test_cases/if_else_expr__all.py +0 -55
- package/ref-monty/crates/monty/test_cases/import__error_cannot_import.py +0 -9
- package/ref-monty/crates/monty/test_cases/import__error_module_not_found.py +0 -9
- package/ref-monty/crates/monty/test_cases/import__local_scope.py +0 -68
- package/ref-monty/crates/monty/test_cases/import__os.py +0 -25
- package/ref-monty/crates/monty/test_cases/import__relative_error.py +0 -9
- package/ref-monty/crates/monty/test_cases/import__relative_no_module_error.py +0 -9
- package/ref-monty/crates/monty/test_cases/import__runtime_error_when_executed.py +0 -14
- package/ref-monty/crates/monty/test_cases/import__star_error.py +0 -11
- package/ref-monty/crates/monty/test_cases/import__sys.py +0 -47
- package/ref-monty/crates/monty/test_cases/import__sys_monty.py +0 -28
- package/ref-monty/crates/monty/test_cases/import__type_checking_guard.py +0 -37
- package/ref-monty/crates/monty/test_cases/import__typing.py +0 -25
- package/ref-monty/crates/monty/test_cases/import__typing_type_ignore.py +0 -4
- package/ref-monty/crates/monty/test_cases/int__bigint.py +0 -467
- package/ref-monty/crates/monty/test_cases/int__bigint_errors.py +0 -260
- package/ref-monty/crates/monty/test_cases/int__ops.py +0 -219
- package/ref-monty/crates/monty/test_cases/int__overflow_division.py +0 -84
- package/ref-monty/crates/monty/test_cases/is_variant__all.py +0 -36
- package/ref-monty/crates/monty/test_cases/isinstance__arg2_list_error.py +0 -2
- package/ref-monty/crates/monty/test_cases/isinstance__arg2_type_error.py +0 -2
- package/ref-monty/crates/monty/test_cases/iter__dict_mutation.py +0 -4
- package/ref-monty/crates/monty/test_cases/iter__for.py +0 -243
- package/ref-monty/crates/monty/test_cases/iter__for_loop_unpacking.py +0 -66
- package/ref-monty/crates/monty/test_cases/iter__generator_expr.py +0 -20
- package/ref-monty/crates/monty/test_cases/iter__generator_expr_type.py +0 -7
- package/ref-monty/crates/monty/test_cases/iter__not_iterable.py +0 -3
- package/ref-monty/crates/monty/test_cases/lambda__all.py +0 -145
- package/ref-monty/crates/monty/test_cases/list__extend_not_iterable.py +0 -7
- package/ref-monty/crates/monty/test_cases/list__getitem_out_of_bounds.py +0 -3
- package/ref-monty/crates/monty/test_cases/list__index_not_found.py +0 -9
- package/ref-monty/crates/monty/test_cases/list__index_start_gt_end.py +0 -10
- package/ref-monty/crates/monty/test_cases/list__ops.py +0 -473
- package/ref-monty/crates/monty/test_cases/list__pop_empty.py +0 -9
- package/ref-monty/crates/monty/test_cases/list__pop_out_of_range.py +0 -9
- package/ref-monty/crates/monty/test_cases/list__pop_type_error.py +0 -9
- package/ref-monty/crates/monty/test_cases/list__remove_not_found.py +0 -9
- package/ref-monty/crates/monty/test_cases/list__setitem_dict_index.py +0 -13
- package/ref-monty/crates/monty/test_cases/list__setitem_huge_int_index.py +0 -13
- package/ref-monty/crates/monty/test_cases/list__setitem_index_error.py +0 -10
- package/ref-monty/crates/monty/test_cases/list__setitem_type_error.py +0 -10
- package/ref-monty/crates/monty/test_cases/list__unpack_type_error.py +0 -2
- package/ref-monty/crates/monty/test_cases/longint__index_error.py +0 -3
- package/ref-monty/crates/monty/test_cases/longint__repeat_error.py +0 -3
- package/ref-monty/crates/monty/test_cases/loop__break_continue.py +0 -113
- package/ref-monty/crates/monty/test_cases/loop__break_finally.py +0 -69
- package/ref-monty/crates/monty/test_cases/loop__break_in_function_error.py +0 -13
- package/ref-monty/crates/monty/test_cases/loop__break_in_if_error.py +0 -11
- package/ref-monty/crates/monty/test_cases/loop__break_nested_except_clears.py +0 -55
- package/ref-monty/crates/monty/test_cases/loop__break_outside_error.py +0 -9
- package/ref-monty/crates/monty/test_cases/loop__continue_finally.py +0 -81
- package/ref-monty/crates/monty/test_cases/loop__continue_in_function_error.py +0 -13
- package/ref-monty/crates/monty/test_cases/loop__continue_in_if_error.py +0 -11
- package/ref-monty/crates/monty/test_cases/loop__continue_nested_except_clears.py +0 -60
- package/ref-monty/crates/monty/test_cases/loop__continue_outside_error.py +0 -9
- package/ref-monty/crates/monty/test_cases/math__acos_domain_error.py +0 -11
- package/ref-monty/crates/monty/test_cases/math__acosh_domain_error.py +0 -11
- package/ref-monty/crates/monty/test_cases/math__asin_domain_error.py +0 -11
- package/ref-monty/crates/monty/test_cases/math__atanh_domain_error.py +0 -11
- package/ref-monty/crates/monty/test_cases/math__cos_inf_error.py +0 -11
- package/ref-monty/crates/monty/test_cases/math__cosh_overflow_error.py +0 -11
- package/ref-monty/crates/monty/test_cases/math__exp_overflow_error.py +0 -11
- package/ref-monty/crates/monty/test_cases/math__factorial_float_error.py +0 -11
- package/ref-monty/crates/monty/test_cases/math__factorial_negative_error.py +0 -11
- package/ref-monty/crates/monty/test_cases/math__floor_inf_error.py +0 -11
- package/ref-monty/crates/monty/test_cases/math__floor_nan_error.py +0 -11
- package/ref-monty/crates/monty/test_cases/math__floor_str_error.py +0 -11
- package/ref-monty/crates/monty/test_cases/math__fmod_inf_error.py +0 -11
- package/ref-monty/crates/monty/test_cases/math__gamma_neg_int_error.py +0 -11
- package/ref-monty/crates/monty/test_cases/math__gcd_float_error.py +0 -11
- package/ref-monty/crates/monty/test_cases/math__isqrt_negative_error.py +0 -11
- package/ref-monty/crates/monty/test_cases/math__ldexp_overflow_error.py +0 -11
- package/ref-monty/crates/monty/test_cases/math__log1p_domain_error.py +0 -11
- package/ref-monty/crates/monty/test_cases/math__log_base1_error.py +0 -11
- package/ref-monty/crates/monty/test_cases/math__log_zero_error.py +0 -11
- package/ref-monty/crates/monty/test_cases/math__module.py +0 -1432
- package/ref-monty/crates/monty/test_cases/math__pow_domain_error.py +0 -11
- package/ref-monty/crates/monty/test_cases/math__sin_inf_error.py +0 -11
- package/ref-monty/crates/monty/test_cases/math__sqrt_negative_error.py +0 -11
- package/ref-monty/crates/monty/test_cases/math__tan_inf_error.py +0 -11
- package/ref-monty/crates/monty/test_cases/math__trunc_str_error.py +0 -11
- package/ref-monty/crates/monty/test_cases/method__args_kwargs_unpacking.py +0 -259
- package/ref-monty/crates/monty/test_cases/name_error__unbound_local_func.py +0 -19
- package/ref-monty/crates/monty/test_cases/name_error__unbound_local_module.py +0 -12
- package/ref-monty/crates/monty/test_cases/name_error__undefined_call_chained.py +0 -9
- package/ref-monty/crates/monty/test_cases/name_error__undefined_call_in_expr.py +0 -9
- package/ref-monty/crates/monty/test_cases/name_error__undefined_call_in_function.py +0 -16
- package/ref-monty/crates/monty/test_cases/name_error__undefined_call_with_args.py +0 -9
- package/ref-monty/crates/monty/test_cases/name_error__undefined_global.py +0 -10
- package/ref-monty/crates/monty/test_cases/namedtuple__missing_attr.py +0 -11
- package/ref-monty/crates/monty/test_cases/namedtuple__ops.py +0 -34
- package/ref-monty/crates/monty/test_cases/nonlocal__error_module_level.py +0 -3
- package/ref-monty/crates/monty/test_cases/nonlocal__ops.py +0 -353
- package/ref-monty/crates/monty/test_cases/os__environ.py +0 -40
- package/ref-monty/crates/monty/test_cases/os__getenv_key_list_error.py +0 -5
- package/ref-monty/crates/monty/test_cases/os__getenv_key_type_error.py +0 -5
- package/ref-monty/crates/monty/test_cases/parse_error__complex.py +0 -3
- package/ref-monty/crates/monty/test_cases/pathlib__import.py +0 -11
- package/ref-monty/crates/monty/test_cases/pathlib__os.py +0 -136
- package/ref-monty/crates/monty/test_cases/pathlib__os_read_error.py +0 -12
- package/ref-monty/crates/monty/test_cases/pathlib__pure.py +0 -81
- package/ref-monty/crates/monty/test_cases/pyobject__cycle_dict_self.py +0 -5
- package/ref-monty/crates/monty/test_cases/pyobject__cycle_list_dict.py +0 -6
- package/ref-monty/crates/monty/test_cases/pyobject__cycle_list_self.py +0 -5
- package/ref-monty/crates/monty/test_cases/pyobject__cycle_multiple_refs.py +0 -6
- package/ref-monty/crates/monty/test_cases/range__error_no_args.py +0 -2
- package/ref-monty/crates/monty/test_cases/range__error_step_zero.py +0 -2
- package/ref-monty/crates/monty/test_cases/range__error_too_many_args.py +0 -2
- package/ref-monty/crates/monty/test_cases/range__getitem_index_error.py +0 -10
- package/ref-monty/crates/monty/test_cases/range__ops.py +0 -236
- package/ref-monty/crates/monty/test_cases/re__basic.py +0 -756
- package/ref-monty/crates/monty/test_cases/re__grouping.py +0 -241
- package/ref-monty/crates/monty/test_cases/re__match.py +0 -148
- package/ref-monty/crates/monty/test_cases/recursion__deep_drop.py +0 -26
- package/ref-monty/crates/monty/test_cases/recursion__deep_eq.py +0 -23
- package/ref-monty/crates/monty/test_cases/recursion__deep_hash.py +0 -46
- package/ref-monty/crates/monty/test_cases/recursion__deep_repr.py +0 -12
- package/ref-monty/crates/monty/test_cases/recursion__function_depth.py +0 -13
- package/ref-monty/crates/monty/test_cases/refcount__cycle_mutual_reference.py +0 -18
- package/ref-monty/crates/monty/test_cases/refcount__cycle_self_reference.py +0 -12
- package/ref-monty/crates/monty/test_cases/refcount__dict_basic.py +0 -5
- package/ref-monty/crates/monty/test_cases/refcount__dict_get.py +0 -5
- package/ref-monty/crates/monty/test_cases/refcount__dict_keys_and.py +0 -14
- package/ref-monty/crates/monty/test_cases/refcount__dict_overwrite.py +0 -6
- package/ref-monty/crates/monty/test_cases/refcount__gather_cleanup.py +0 -16
- package/ref-monty/crates/monty/test_cases/refcount__gather_exception.py +0 -18
- package/ref-monty/crates/monty/test_cases/refcount__gather_nested_cancel.py +0 -25
- package/ref-monty/crates/monty/test_cases/refcount__immediate_skipped.py +0 -4
- package/ref-monty/crates/monty/test_cases/refcount__kwargs_unpacking.py +0 -27
- package/ref-monty/crates/monty/test_cases/refcount__list_append_multiple.py +0 -6
- package/ref-monty/crates/monty/test_cases/refcount__list_append_ref.py +0 -5
- package/ref-monty/crates/monty/test_cases/refcount__list_concat.py +0 -5
- package/ref-monty/crates/monty/test_cases/refcount__list_getitem.py +0 -5
- package/ref-monty/crates/monty/test_cases/refcount__list_iadd.py +0 -5
- package/ref-monty/crates/monty/test_cases/refcount__nested_list.py +0 -4
- package/ref-monty/crates/monty/test_cases/refcount__re_pattern_sub_error_paths.py +0 -37
- package/ref-monty/crates/monty/test_cases/refcount__re_search_match.py +0 -34
- package/ref-monty/crates/monty/test_cases/refcount__re_sub_error_paths.py +0 -31
- package/ref-monty/crates/monty/test_cases/refcount__shared_reference.py +0 -4
- package/ref-monty/crates/monty/test_cases/refcount__single_list.py +0 -3
- package/ref-monty/crates/monty/test_cases/repr__cycle_detection.py +0 -24
- package/ref-monty/crates/monty/test_cases/set__ops.py +0 -191
- package/ref-monty/crates/monty/test_cases/set__review_bugs.py +0 -35
- package/ref-monty/crates/monty/test_cases/set__unpack_type_error.py +0 -2
- package/ref-monty/crates/monty/test_cases/slice__invalid_indices.py +0 -2
- package/ref-monty/crates/monty/test_cases/slice__kwargs.py +0 -9
- package/ref-monty/crates/monty/test_cases/slice__no_args.py +0 -9
- package/ref-monty/crates/monty/test_cases/slice__ops.py +0 -149
- package/ref-monty/crates/monty/test_cases/slice__step_zero.py +0 -9
- package/ref-monty/crates/monty/test_cases/slice__step_zero_bytes.py +0 -9
- package/ref-monty/crates/monty/test_cases/slice__step_zero_range.py +0 -9
- package/ref-monty/crates/monty/test_cases/slice__step_zero_str.py +0 -9
- package/ref-monty/crates/monty/test_cases/slice__step_zero_tuple.py +0 -9
- package/ref-monty/crates/monty/test_cases/slice__too_many_args.py +0 -9
- package/ref-monty/crates/monty/test_cases/str__getitem_index_error.py +0 -10
- package/ref-monty/crates/monty/test_cases/str__index_not_found.py +0 -9
- package/ref-monty/crates/monty/test_cases/str__join_no_args.py +0 -9
- package/ref-monty/crates/monty/test_cases/str__join_non_string.py +0 -9
- package/ref-monty/crates/monty/test_cases/str__join_not_iterable.py +0 -9
- package/ref-monty/crates/monty/test_cases/str__join_too_many_args.py +0 -9
- package/ref-monty/crates/monty/test_cases/str__methods.py +0 -327
- package/ref-monty/crates/monty/test_cases/str__ops.py +0 -162
- package/ref-monty/crates/monty/test_cases/str__partition_empty.py +0 -9
- package/ref-monty/crates/monty/test_cases/str__rsplit_empty_sep.py +0 -9
- package/ref-monty/crates/monty/test_cases/str__split_empty_sep.py +0 -9
- package/ref-monty/crates/monty/test_cases/sys__types.py +0 -7
- package/ref-monty/crates/monty/test_cases/traceback__division_error.py +0 -30
- package/ref-monty/crates/monty/test_cases/traceback__index_error.py +0 -17
- package/ref-monty/crates/monty/test_cases/traceback__insert_as_int.py +0 -10
- package/ref-monty/crates/monty/test_cases/traceback__nested_call.py +0 -29
- package/ref-monty/crates/monty/test_cases/traceback__nonlocal_module_scope.py +0 -10
- package/ref-monty/crates/monty/test_cases/traceback__nonlocal_unbound.py +0 -24
- package/ref-monty/crates/monty/test_cases/traceback__range_as_int.py +0 -9
- package/ref-monty/crates/monty/test_cases/traceback__recursion_error.py +0 -23
- package/ref-monty/crates/monty/test_cases/traceback__set_mutation.py +0 -11
- package/ref-monty/crates/monty/test_cases/traceback__undefined_attr_call.py +0 -16
- package/ref-monty/crates/monty/test_cases/traceback__undefined_call.py +0 -16
- package/ref-monty/crates/monty/test_cases/traceback__undefined_raise.py +0 -16
- package/ref-monty/crates/monty/test_cases/try_except__all.py +0 -472
- package/ref-monty/crates/monty/test_cases/try_except__bare_raise_no_context.py +0 -2
- package/ref-monty/crates/monty/test_cases/try_except__invalid_type.py +0 -5
- package/ref-monty/crates/monty/test_cases/tuple__getitem_out_of_bounds.py +0 -3
- package/ref-monty/crates/monty/test_cases/tuple__index_not_found.py +0 -9
- package/ref-monty/crates/monty/test_cases/tuple__index_start_gt_end.py +0 -10
- package/ref-monty/crates/monty/test_cases/tuple__methods.py +0 -19
- package/ref-monty/crates/monty/test_cases/tuple__ops.py +0 -133
- package/ref-monty/crates/monty/test_cases/tuple__unpack_type_error.py +0 -2
- package/ref-monty/crates/monty/test_cases/type__builtin_attr_error.py +0 -9
- package/ref-monty/crates/monty/test_cases/type__bytes_negative.py +0 -2
- package/ref-monty/crates/monty/test_cases/type__cell_not_builtin.py +0 -9
- package/ref-monty/crates/monty/test_cases/type__exception_attr_error.py +0 -11
- package/ref-monty/crates/monty/test_cases/type__float_conversion_error.py +0 -2
- package/ref-monty/crates/monty/test_cases/type__float_repr_both_quotes.py +0 -9
- package/ref-monty/crates/monty/test_cases/type__float_repr_newline.py +0 -9
- package/ref-monty/crates/monty/test_cases/type__float_repr_single_quote.py +0 -9
- package/ref-monty/crates/monty/test_cases/type__int_conversion_error.py +0 -2
- package/ref-monty/crates/monty/test_cases/type__list_not_iterable.py +0 -2
- package/ref-monty/crates/monty/test_cases/type__non_builtin_name_error.py +0 -9
- package/ref-monty/crates/monty/test_cases/type__ops.py +0 -200
- package/ref-monty/crates/monty/test_cases/type__shadow_exc.py +0 -3
- package/ref-monty/crates/monty/test_cases/type__shadow_int.py +0 -9
- package/ref-monty/crates/monty/test_cases/type__shadow_len.py +0 -3
- package/ref-monty/crates/monty/test_cases/type__tuple_not_iterable.py +0 -2
- package/ref-monty/crates/monty/test_cases/type_error__int_add_list.py +0 -2
- package/ref-monty/crates/monty/test_cases/type_error__int_div_str.py +0 -2
- package/ref-monty/crates/monty/test_cases/type_error__int_floordiv_str.py +0 -2
- package/ref-monty/crates/monty/test_cases/type_error__int_iadd_str.py +0 -3
- package/ref-monty/crates/monty/test_cases/type_error__int_mod_str.py +0 -2
- package/ref-monty/crates/monty/test_cases/type_error__int_pow_str.py +0 -2
- package/ref-monty/crates/monty/test_cases/type_error__int_sub_str.py +0 -2
- package/ref-monty/crates/monty/test_cases/type_error__list_add_int.py +0 -2
- package/ref-monty/crates/monty/test_cases/type_error__list_add_str.py +0 -2
- package/ref-monty/crates/monty/test_cases/type_error__list_iadd_int.py +0 -6
- package/ref-monty/crates/monty/test_cases/type_error__str_add_int.py +0 -2
- package/ref-monty/crates/monty/test_cases/type_error__str_iadd_int.py +0 -3
- package/ref-monty/crates/monty/test_cases/type_error__unary_invert_str.py +0 -3
- package/ref-monty/crates/monty/test_cases/type_error__unary_minus_str.py +0 -4
- package/ref-monty/crates/monty/test_cases/type_error__unary_neg_str.py +0 -3
- package/ref-monty/crates/monty/test_cases/type_error__unary_plus_str.py +0 -4
- package/ref-monty/crates/monty/test_cases/typing__types.py +0 -24
- package/ref-monty/crates/monty/test_cases/unpack__nested.py +0 -48
- package/ref-monty/crates/monty/test_cases/unpack__non_sequence.py +0 -9
- package/ref-monty/crates/monty/test_cases/unpack__not_enough.py +0 -9
- package/ref-monty/crates/monty/test_cases/unpack__ops.py +0 -153
- package/ref-monty/crates/monty/test_cases/unpack__star_not_enough.py +0 -9
- package/ref-monty/crates/monty/test_cases/unpack__too_many.py +0 -9
- package/ref-monty/crates/monty/test_cases/version__cpython.py +0 -4
- package/ref-monty/crates/monty/test_cases/walrus__all.py +0 -178
- package/ref-monty/crates/monty/test_cases/while__all.py +0 -206
- package/ref-monty/crates/monty/tests/asyncio.rs +0 -764
- package/ref-monty/crates/monty/tests/binary_serde.rs +0 -185
- package/ref-monty/crates/monty/tests/bytecode_limits.rs +0 -248
- package/ref-monty/crates/monty/tests/datatest_runner.rs +0 -2029
- package/ref-monty/crates/monty/tests/inputs.rs +0 -420
- package/ref-monty/crates/monty/tests/json_serde.rs +0 -250
- package/ref-monty/crates/monty/tests/main.rs +0 -71
- package/ref-monty/crates/monty/tests/math_module.rs +0 -114
- package/ref-monty/crates/monty/tests/name_lookup.rs +0 -482
- package/ref-monty/crates/monty/tests/os_tests.rs +0 -459
- package/ref-monty/crates/monty/tests/parse_errors.rs +0 -441
- package/ref-monty/crates/monty/tests/print_writer.rs +0 -238
- package/ref-monty/crates/monty/tests/py_object.rs +0 -121
- package/ref-monty/crates/monty/tests/regex.rs +0 -90
- package/ref-monty/crates/monty/tests/repl.rs +0 -344
- package/ref-monty/crates/monty/tests/resource_limits.rs +0 -1826
- package/ref-monty/crates/monty/tests/try_from.rs +0 -167
- package/ref-monty/crates/monty-cli/Cargo.toml +0 -25
- package/ref-monty/crates/monty-cli/src/main.rs +0 -541
- package/ref-monty/crates/monty-js/.cargo/config.toml +0 -2
- package/ref-monty/crates/monty-js/.prettierignore +0 -8
- package/ref-monty/crates/monty-js/Cargo.toml +0 -32
- package/ref-monty/crates/monty-js/README.md +0 -207
- package/ref-monty/crates/monty-js/__test__/async.spec.ts +0 -350
- package/ref-monty/crates/monty-js/__test__/basic.spec.ts +0 -114
- package/ref-monty/crates/monty-js/__test__/exceptions.spec.ts +0 -427
- package/ref-monty/crates/monty-js/__test__/external.spec.ts +0 -354
- package/ref-monty/crates/monty-js/__test__/inputs.spec.ts +0 -143
- package/ref-monty/crates/monty-js/__test__/limits.spec.ts +0 -162
- package/ref-monty/crates/monty-js/__test__/package.json +0 -3
- package/ref-monty/crates/monty-js/__test__/print.spec.ts +0 -229
- package/ref-monty/crates/monty-js/__test__/repl.spec.ts +0 -34
- package/ref-monty/crates/monty-js/__test__/serialize.spec.ts +0 -205
- package/ref-monty/crates/monty-js/__test__/start.spec.ts +0 -443
- package/ref-monty/crates/monty-js/__test__/type_check.spec.ts +0 -147
- package/ref-monty/crates/monty-js/__test__/types.spec.ts +0 -319
- package/ref-monty/crates/monty-js/build.rs +0 -61
- package/ref-monty/crates/monty-js/index-header.d.ts +0 -3
- package/ref-monty/crates/monty-js/package-lock.json +0 -4694
- package/ref-monty/crates/monty-js/package.json +0 -100
- package/ref-monty/crates/monty-js/scripts/smoke-test.sh +0 -69
- package/ref-monty/crates/monty-js/smoke-test/package.json +0 -17
- package/ref-monty/crates/monty-js/smoke-test/test.ts +0 -171
- package/ref-monty/crates/monty-js/smoke-test/tsconfig.json +0 -11
- package/ref-monty/crates/monty-js/src/convert.rs +0 -648
- package/ref-monty/crates/monty-js/src/exceptions.rs +0 -293
- package/ref-monty/crates/monty-js/src/lib.rs +0 -41
- package/ref-monty/crates/monty-js/src/limits.rs +0 -53
- package/ref-monty/crates/monty-js/src/monty_cls.rs +0 -1407
- package/ref-monty/crates/monty-js/tsconfig.json +0 -17
- package/ref-monty/crates/monty-js/wrapper.ts +0 -701
- package/ref-monty/crates/monty-python/Cargo.toml +0 -38
- package/ref-monty/crates/monty-python/README.md +0 -134
- package/ref-monty/crates/monty-python/build.rs +0 -4
- package/ref-monty/crates/monty-python/example.py +0 -40
- package/ref-monty/crates/monty-python/exercise.py +0 -46
- package/ref-monty/crates/monty-python/pyproject.toml +0 -57
- package/ref-monty/crates/monty-python/python/pydantic_monty/__init__.py +0 -281
- package/ref-monty/crates/monty-python/python/pydantic_monty/_monty.pyi +0 -677
- package/ref-monty/crates/monty-python/python/pydantic_monty/os_access.py +0 -933
- package/ref-monty/crates/monty-python/python/pydantic_monty/py.typed +0 -0
- package/ref-monty/crates/monty-python/src/convert.rs +0 -273
- package/ref-monty/crates/monty-python/src/dataclass.rs +0 -461
- package/ref-monty/crates/monty-python/src/exceptions.rs +0 -557
- package/ref-monty/crates/monty-python/src/external.rs +0 -165
- package/ref-monty/crates/monty-python/src/lib.rs +0 -77
- package/ref-monty/crates/monty-python/src/limits.rs +0 -142
- package/ref-monty/crates/monty-python/src/monty_cls.rs +0 -1650
- package/ref-monty/crates/monty-python/src/repl.rs +0 -470
- package/ref-monty/crates/monty-python/src/serialization.rs +0 -761
- package/ref-monty/crates/monty-python/tests/test_async.py +0 -1201
- package/ref-monty/crates/monty-python/tests/test_basic.py +0 -66
- package/ref-monty/crates/monty-python/tests/test_dataclasses.py +0 -971
- package/ref-monty/crates/monty-python/tests/test_exceptions.py +0 -361
- package/ref-monty/crates/monty-python/tests/test_external.py +0 -367
- package/ref-monty/crates/monty-python/tests/test_inputs.py +0 -126
- package/ref-monty/crates/monty-python/tests/test_limits.py +0 -257
- package/ref-monty/crates/monty-python/tests/test_os_access.py +0 -1286
- package/ref-monty/crates/monty-python/tests/test_os_access_compat.py +0 -731
- package/ref-monty/crates/monty-python/tests/test_os_access_raw.py +0 -483
- package/ref-monty/crates/monty-python/tests/test_os_calls.py +0 -819
- package/ref-monty/crates/monty-python/tests/test_print.py +0 -208
- package/ref-monty/crates/monty-python/tests/test_re.py +0 -170
- package/ref-monty/crates/monty-python/tests/test_readme_examples.py +0 -20
- package/ref-monty/crates/monty-python/tests/test_repl.py +0 -749
- package/ref-monty/crates/monty-python/tests/test_serialize.py +0 -284
- package/ref-monty/crates/monty-python/tests/test_start.py +0 -346
- package/ref-monty/crates/monty-python/tests/test_threading.py +0 -163
- package/ref-monty/crates/monty-python/tests/test_type_check.py +0 -344
- package/ref-monty/crates/monty-python/tests/test_types.py +0 -553
- package/ref-monty/crates/monty-type-checking/Cargo.toml +0 -32
- package/ref-monty/crates/monty-type-checking/src/db.rs +0 -116
- package/ref-monty/crates/monty-type-checking/src/lib.rs +0 -4
- package/ref-monty/crates/monty-type-checking/src/type_check.rs +0 -280
- package/ref-monty/crates/monty-type-checking/tests/bad_types.py +0 -109
- package/ref-monty/crates/monty-type-checking/tests/bad_types_output.txt +0 -21
- package/ref-monty/crates/monty-type-checking/tests/good_types.py +0 -475
- package/ref-monty/crates/monty-type-checking/tests/main.rs +0 -205
- package/ref-monty/crates/monty-type-checking/tests/reveal_types.py +0 -56
- package/ref-monty/crates/monty-type-checking/tests/reveal_types_output.txt +0 -41
- package/ref-monty/crates/monty-typeshed/Cargo.toml +0 -29
- package/ref-monty/crates/monty-typeshed/README.md +0 -11
- package/ref-monty/crates/monty-typeshed/build.rs +0 -101
- package/ref-monty/crates/monty-typeshed/custom/README.md +0 -1
- package/ref-monty/crates/monty-typeshed/custom/asyncio.pyi +0 -138
- package/ref-monty/crates/monty-typeshed/custom/os.pyi +0 -87
- package/ref-monty/crates/monty-typeshed/custom/sys.pyi +0 -33
- package/ref-monty/crates/monty-typeshed/src/lib.rs +0 -56
- package/ref-monty/crates/monty-typeshed/update.py +0 -321
- package/ref-monty/crates/monty-typeshed/vendor/typeshed/source_commit.txt +0 -1
- package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/VERSIONS +0 -20
- package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/_collections_abc.pyi +0 -105
- package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/_typeshed/__init__.pyi +0 -394
- package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/asyncio.pyi +0 -138
- package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/builtins.pyi +0 -1434
- package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/collections/__init__.pyi +0 -527
- package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/collections/abc.pyi +0 -2
- package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/dataclasses.pyi +0 -502
- package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/enum.pyi +0 -376
- package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/math.pyi +0 -149
- package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/os.pyi +0 -87
- package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/pathlib/__init__.pyi +0 -395
- package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/pathlib/types.pyi +0 -8
- package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/re.pyi +0 -337
- package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/sys.pyi +0 -33
- package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/types.pyi +0 -741
- package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/typing.pyi +0 -1217
- package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/typing_extensions.pyi +0 -716
- package/ref-monty/docs/usage-guide.md +0 -117
- package/ref-monty/examples/README.md +0 -3
- package/ref-monty/examples/expense_analysis/README.md +0 -3
- package/ref-monty/examples/expense_analysis/data.py +0 -124
- package/ref-monty/examples/expense_analysis/main.py +0 -115
- package/ref-monty/examples/sql_playground/README.md +0 -20
- package/ref-monty/examples/sql_playground/external_functions.py +0 -129
- package/ref-monty/examples/sql_playground/main.py +0 -81
- package/ref-monty/examples/sql_playground/sandbox_code.py +0 -82
- package/ref-monty/examples/sql_playground/type_stubs.pyi +0 -14
- package/ref-monty/examples/web_scraper/README.md +0 -15
- package/ref-monty/examples/web_scraper/browser.py +0 -56
- package/ref-monty/examples/web_scraper/example_code.py +0 -59
- package/ref-monty/examples/web_scraper/external_functions.py +0 -324
- package/ref-monty/examples/web_scraper/main.py +0 -193
- package/ref-monty/examples/web_scraper/sub_agent.py +0 -79
- package/ref-monty/monty-npm.md +0 -235
- package/ref-monty/pyproject.toml +0 -162
- package/ref-monty/scripts/check_imports.py +0 -91
- package/ref-monty/scripts/codecov_diff.py +0 -412
- package/ref-monty/scripts/complete_tests.py +0 -146
- package/ref-monty/scripts/flamegraph_to_text.py +0 -208
- package/ref-monty/scripts/iter_test_methods.py +0 -540
- package/ref-monty/scripts/run_traceback.py +0 -180
- package/ref-monty/scripts/startup_performance.py +0 -130
- package/ref-monty/uv.lock +0 -1779
- package/temp_resend_cli/repo/.github/scripts/pr-title-check.js +0 -34
- package/temp_resend_cli/repo/.github/workflows/ci.yml +0 -67
- package/temp_resend_cli/repo/.github/workflows/post-release.yml +0 -51
- package/temp_resend_cli/repo/.github/workflows/pr-title-check.yml +0 -13
- package/temp_resend_cli/repo/.github/workflows/release.yml +0 -175
- package/temp_resend_cli/repo/.github/workflows/test-install-unix.yml +0 -34
- package/temp_resend_cli/repo/.github/workflows/test-install-windows.yml +0 -48
- package/temp_resend_cli/repo/CHANGELOG.md +0 -31
- package/temp_resend_cli/repo/LICENSE +0 -21
- package/temp_resend_cli/repo/README.md +0 -450
- package/temp_resend_cli/repo/biome.json +0 -36
- package/temp_resend_cli/repo/install.ps1 +0 -141
- package/temp_resend_cli/repo/install.sh +0 -301
- package/temp_resend_cli/repo/package.json +0 -61
- package/temp_resend_cli/repo/pnpm-lock.yaml +0 -2439
- package/temp_resend_cli/repo/renovate.json +0 -4
- package/temp_resend_cli/repo/src/cli.ts +0 -98
- package/temp_resend_cli/repo/src/commands/api-keys/create.ts +0 -114
- package/temp_resend_cli/repo/src/commands/api-keys/delete.ts +0 -47
- package/temp_resend_cli/repo/src/commands/api-keys/index.ts +0 -26
- package/temp_resend_cli/repo/src/commands/api-keys/list.ts +0 -35
- package/temp_resend_cli/repo/src/commands/api-keys/utils.ts +0 -8
- package/temp_resend_cli/repo/src/commands/auth/index.ts +0 -20
- package/temp_resend_cli/repo/src/commands/auth/login.ts +0 -234
- package/temp_resend_cli/repo/src/commands/auth/logout.ts +0 -105
- package/temp_resend_cli/repo/src/commands/broadcasts/create.ts +0 -196
- package/temp_resend_cli/repo/src/commands/broadcasts/delete.ts +0 -46
- package/temp_resend_cli/repo/src/commands/broadcasts/get.ts +0 -59
- package/temp_resend_cli/repo/src/commands/broadcasts/index.ts +0 -43
- package/temp_resend_cli/repo/src/commands/broadcasts/list.ts +0 -60
- package/temp_resend_cli/repo/src/commands/broadcasts/send.ts +0 -56
- package/temp_resend_cli/repo/src/commands/broadcasts/update.ts +0 -95
- package/temp_resend_cli/repo/src/commands/broadcasts/utils.ts +0 -35
- package/temp_resend_cli/repo/src/commands/contact-properties/create.ts +0 -118
- package/temp_resend_cli/repo/src/commands/contact-properties/delete.ts +0 -48
- package/temp_resend_cli/repo/src/commands/contact-properties/get.ts +0 -46
- package/temp_resend_cli/repo/src/commands/contact-properties/index.ts +0 -48
- package/temp_resend_cli/repo/src/commands/contact-properties/list.ts +0 -68
- package/temp_resend_cli/repo/src/commands/contact-properties/update.ts +0 -88
- package/temp_resend_cli/repo/src/commands/contact-properties/utils.ts +0 -17
- package/temp_resend_cli/repo/src/commands/contacts/add-segment.ts +0 -78
- package/temp_resend_cli/repo/src/commands/contacts/create.ts +0 -122
- package/temp_resend_cli/repo/src/commands/contacts/delete.ts +0 -49
- package/temp_resend_cli/repo/src/commands/contacts/get.ts +0 -53
- package/temp_resend_cli/repo/src/commands/contacts/index.ts +0 -58
- package/temp_resend_cli/repo/src/commands/contacts/list.ts +0 -57
- package/temp_resend_cli/repo/src/commands/contacts/remove-segment.ts +0 -48
- package/temp_resend_cli/repo/src/commands/contacts/segments.ts +0 -39
- package/temp_resend_cli/repo/src/commands/contacts/topics.ts +0 -45
- package/temp_resend_cli/repo/src/commands/contacts/update-topics.ts +0 -90
- package/temp_resend_cli/repo/src/commands/contacts/update.ts +0 -77
- package/temp_resend_cli/repo/src/commands/contacts/utils.ts +0 -119
- package/temp_resend_cli/repo/src/commands/doctor.ts +0 -216
- package/temp_resend_cli/repo/src/commands/domains/create.ts +0 -83
- package/temp_resend_cli/repo/src/commands/domains/delete.ts +0 -42
- package/temp_resend_cli/repo/src/commands/domains/get.ts +0 -47
- package/temp_resend_cli/repo/src/commands/domains/index.ts +0 -35
- package/temp_resend_cli/repo/src/commands/domains/list.ts +0 -53
- package/temp_resend_cli/repo/src/commands/domains/update.ts +0 -75
- package/temp_resend_cli/repo/src/commands/domains/utils.ts +0 -44
- package/temp_resend_cli/repo/src/commands/domains/verify.ts +0 -38
- package/temp_resend_cli/repo/src/commands/emails/batch.ts +0 -140
- package/temp_resend_cli/repo/src/commands/emails/get.ts +0 -44
- package/temp_resend_cli/repo/src/commands/emails/index.ts +0 -30
- package/temp_resend_cli/repo/src/commands/emails/list.ts +0 -84
- package/temp_resend_cli/repo/src/commands/emails/receiving/attachment.ts +0 -55
- package/temp_resend_cli/repo/src/commands/emails/receiving/attachments.ts +0 -68
- package/temp_resend_cli/repo/src/commands/emails/receiving/get.ts +0 -58
- package/temp_resend_cli/repo/src/commands/emails/receiving/index.ts +0 -28
- package/temp_resend_cli/repo/src/commands/emails/receiving/list.ts +0 -59
- package/temp_resend_cli/repo/src/commands/emails/receiving/utils.ts +0 -38
- package/temp_resend_cli/repo/src/commands/emails/send.ts +0 -189
- package/temp_resend_cli/repo/src/commands/open.ts +0 -27
- package/temp_resend_cli/repo/src/commands/segments/create.ts +0 -50
- package/temp_resend_cli/repo/src/commands/segments/delete.ts +0 -47
- package/temp_resend_cli/repo/src/commands/segments/get.ts +0 -38
- package/temp_resend_cli/repo/src/commands/segments/index.ts +0 -36
- package/temp_resend_cli/repo/src/commands/segments/list.ts +0 -58
- package/temp_resend_cli/repo/src/commands/segments/utils.ts +0 -7
- package/temp_resend_cli/repo/src/commands/teams/index.ts +0 -10
- package/temp_resend_cli/repo/src/commands/teams/list.ts +0 -35
- package/temp_resend_cli/repo/src/commands/teams/remove.ts +0 -86
- package/temp_resend_cli/repo/src/commands/teams/switch.ts +0 -76
- package/temp_resend_cli/repo/src/commands/topics/create.ts +0 -73
- package/temp_resend_cli/repo/src/commands/topics/delete.ts +0 -47
- package/temp_resend_cli/repo/src/commands/topics/get.ts +0 -42
- package/temp_resend_cli/repo/src/commands/topics/index.ts +0 -42
- package/temp_resend_cli/repo/src/commands/topics/list.ts +0 -34
- package/temp_resend_cli/repo/src/commands/topics/update.ts +0 -59
- package/temp_resend_cli/repo/src/commands/topics/utils.ts +0 -16
- package/temp_resend_cli/repo/src/commands/webhooks/create.ts +0 -128
- package/temp_resend_cli/repo/src/commands/webhooks/delete.ts +0 -49
- package/temp_resend_cli/repo/src/commands/webhooks/get.ts +0 -42
- package/temp_resend_cli/repo/src/commands/webhooks/index.ts +0 -42
- package/temp_resend_cli/repo/src/commands/webhooks/list.ts +0 -55
- package/temp_resend_cli/repo/src/commands/webhooks/listen.ts +0 -379
- package/temp_resend_cli/repo/src/commands/webhooks/update.ts +0 -83
- package/temp_resend_cli/repo/src/commands/webhooks/utils.ts +0 -36
- package/temp_resend_cli/repo/src/commands/whoami.ts +0 -71
- package/temp_resend_cli/repo/src/lib/actions.ts +0 -157
- package/temp_resend_cli/repo/src/lib/client.ts +0 -37
- package/temp_resend_cli/repo/src/lib/config.ts +0 -217
- package/temp_resend_cli/repo/src/lib/files.ts +0 -15
- package/temp_resend_cli/repo/src/lib/help-text.ts +0 -38
- package/temp_resend_cli/repo/src/lib/output.ts +0 -56
- package/temp_resend_cli/repo/src/lib/pagination.ts +0 -36
- package/temp_resend_cli/repo/src/lib/prompts.ts +0 -149
- package/temp_resend_cli/repo/src/lib/spinner.ts +0 -100
- package/temp_resend_cli/repo/src/lib/table.ts +0 -57
- package/temp_resend_cli/repo/src/lib/tty.ts +0 -28
- package/temp_resend_cli/repo/src/lib/update-check.ts +0 -169
- package/temp_resend_cli/repo/src/lib/version.ts +0 -4
- package/temp_resend_cli/repo/tests/commands/api-keys/create.test.ts +0 -196
- package/temp_resend_cli/repo/tests/commands/api-keys/delete.test.ts +0 -157
- package/temp_resend_cli/repo/tests/commands/api-keys/list.test.ts +0 -134
- package/temp_resend_cli/repo/tests/commands/auth/login.test.ts +0 -153
- package/temp_resend_cli/repo/tests/commands/auth/logout.test.ts +0 -153
- package/temp_resend_cli/repo/tests/commands/broadcasts/create.test.ts +0 -454
- package/temp_resend_cli/repo/tests/commands/broadcasts/delete.test.ts +0 -183
- package/temp_resend_cli/repo/tests/commands/broadcasts/get.test.ts +0 -147
- package/temp_resend_cli/repo/tests/commands/broadcasts/list.test.ts +0 -199
- package/temp_resend_cli/repo/tests/commands/broadcasts/send.test.ts +0 -162
- package/temp_resend_cli/repo/tests/commands/broadcasts/update.test.ts +0 -288
- package/temp_resend_cli/repo/tests/commands/contact-properties/create.test.ts +0 -251
- package/temp_resend_cli/repo/tests/commands/contact-properties/delete.test.ts +0 -184
- package/temp_resend_cli/repo/tests/commands/contact-properties/get.test.ts +0 -145
- package/temp_resend_cli/repo/tests/commands/contact-properties/list.test.ts +0 -181
- package/temp_resend_cli/repo/tests/commands/contact-properties/update.test.ts +0 -217
- package/temp_resend_cli/repo/tests/commands/contacts/add-segment.test.ts +0 -189
- package/temp_resend_cli/repo/tests/commands/contacts/create.test.ts +0 -271
- package/temp_resend_cli/repo/tests/commands/contacts/delete.test.ts +0 -193
- package/temp_resend_cli/repo/tests/commands/contacts/get.test.ts +0 -149
- package/temp_resend_cli/repo/tests/commands/contacts/list.test.ts +0 -176
- package/temp_resend_cli/repo/tests/commands/contacts/remove-segment.test.ts +0 -167
- package/temp_resend_cli/repo/tests/commands/contacts/segments.test.ts +0 -168
- package/temp_resend_cli/repo/tests/commands/contacts/topics.test.ts +0 -164
- package/temp_resend_cli/repo/tests/commands/contacts/update-topics.test.ts +0 -248
- package/temp_resend_cli/repo/tests/commands/contacts/update.test.ts +0 -206
- package/temp_resend_cli/repo/tests/commands/doctor.test.ts +0 -164
- package/temp_resend_cli/repo/tests/commands/domains/create.test.ts +0 -193
- package/temp_resend_cli/repo/tests/commands/domains/delete.test.ts +0 -157
- package/temp_resend_cli/repo/tests/commands/domains/get.test.ts +0 -138
- package/temp_resend_cli/repo/tests/commands/domains/list.test.ts +0 -165
- package/temp_resend_cli/repo/tests/commands/domains/update.test.ts +0 -224
- package/temp_resend_cli/repo/tests/commands/domains/verify.test.ts +0 -118
- package/temp_resend_cli/repo/tests/commands/emails/batch.test.ts +0 -324
- package/temp_resend_cli/repo/tests/commands/emails/get.test.ts +0 -132
- package/temp_resend_cli/repo/tests/commands/emails/receiving/attachment.test.ts +0 -141
- package/temp_resend_cli/repo/tests/commands/emails/receiving/attachments.test.ts +0 -169
- package/temp_resend_cli/repo/tests/commands/emails/receiving/get.test.ts +0 -141
- package/temp_resend_cli/repo/tests/commands/emails/receiving/list.test.ts +0 -182
- package/temp_resend_cli/repo/tests/commands/emails/send.test.ts +0 -312
- package/temp_resend_cli/repo/tests/commands/segments/create.test.ts +0 -164
- package/temp_resend_cli/repo/tests/commands/segments/delete.test.ts +0 -183
- package/temp_resend_cli/repo/tests/commands/segments/get.test.ts +0 -138
- package/temp_resend_cli/repo/tests/commands/segments/list.test.ts +0 -174
- package/temp_resend_cli/repo/tests/commands/teams/list.test.ts +0 -62
- package/temp_resend_cli/repo/tests/commands/teams/remove.test.ts +0 -110
- package/temp_resend_cli/repo/tests/commands/teams/switch.test.ts +0 -103
- package/temp_resend_cli/repo/tests/commands/topics/create.test.ts +0 -192
- package/temp_resend_cli/repo/tests/commands/topics/delete.test.ts +0 -157
- package/temp_resend_cli/repo/tests/commands/topics/get.test.ts +0 -126
- package/temp_resend_cli/repo/tests/commands/topics/list.test.ts +0 -125
- package/temp_resend_cli/repo/tests/commands/topics/update.test.ts +0 -178
- package/temp_resend_cli/repo/tests/commands/webhooks/create.test.ts +0 -225
- package/temp_resend_cli/repo/tests/commands/webhooks/delete.test.ts +0 -157
- package/temp_resend_cli/repo/tests/commands/webhooks/get.test.ts +0 -126
- package/temp_resend_cli/repo/tests/commands/webhooks/list.test.ts +0 -178
- package/temp_resend_cli/repo/tests/commands/webhooks/update.test.ts +0 -207
- package/temp_resend_cli/repo/tests/commands/whoami.test.ts +0 -98
- package/temp_resend_cli/repo/tests/e2e/smoke.test.ts +0 -93
- package/temp_resend_cli/repo/tests/helpers.ts +0 -86
- package/temp_resend_cli/repo/tests/lib/client.test.ts +0 -71
- package/temp_resend_cli/repo/tests/lib/config.test.ts +0 -451
- package/temp_resend_cli/repo/tests/lib/files.test.ts +0 -73
- package/temp_resend_cli/repo/tests/lib/help-text.test.ts +0 -97
- package/temp_resend_cli/repo/tests/lib/output.test.ts +0 -136
- package/temp_resend_cli/repo/tests/lib/prompts.test.ts +0 -185
- package/temp_resend_cli/repo/tests/lib/spinner.test.ts +0 -166
- package/temp_resend_cli/repo/tests/lib/table.test.ts +0 -63
- package/temp_resend_cli/repo/tests/lib/tty.test.ts +0 -89
- package/temp_resend_cli/repo/tests/lib/update-check.test.ts +0 -179
- package/temp_resend_cli/repo/tsconfig.json +0 -14
- package/temp_resend_cli/repo/vitest.config.e2e.ts +0 -8
- package/temp_resend_cli/repo/vitest.config.ts +0 -10
- /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
|
-
}
|