superacli 1.1.6 → 1.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONTRIBUTING.md +270 -0
- package/README.md +141 -54
- package/__tests__/adapter-schema.test.js +251 -86
- 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__/resend-plugin.test.js +109 -82
- 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 +50 -7
- 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 +4 -3
- 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 +255 -63
- 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/index.html +183 -123
- 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/index.html +384 -0
- package/package.json +2 -2
- 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 +199 -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/docs.html +0 -224
- 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,3015 +0,0 @@
|
|
|
1
|
-
use std::collections::hash_map::Entry;
|
|
2
|
-
|
|
3
|
-
use ahash::{AHashMap, AHashSet};
|
|
4
|
-
|
|
5
|
-
use crate::{
|
|
6
|
-
args::{ArgExprs, CallArg, CallKwarg},
|
|
7
|
-
builtins::Builtins,
|
|
8
|
-
expressions::{
|
|
9
|
-
Callable, CmpOperator, Comprehension, DictItem, Expr, ExprLoc, Identifier, Literal, NameScope, Node, Operator,
|
|
10
|
-
PreparedFunctionDef, PreparedNode, SequenceItem, UnpackTarget,
|
|
11
|
-
},
|
|
12
|
-
fstring::{FStringPart, FormatSpec},
|
|
13
|
-
intern::{InternerBuilder, StringId},
|
|
14
|
-
namespace::NamespaceId,
|
|
15
|
-
parse::{CodeRange, ExceptHandler, ParseError, ParseNode, ParseResult, ParsedSignature, RawFunctionDef, Try},
|
|
16
|
-
signature::Signature,
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
/// Result of the prepare phase, containing everything needed to compile and execute code.
|
|
20
|
-
///
|
|
21
|
-
/// This struct holds the outputs of name resolution and AST transformation:
|
|
22
|
-
/// - The namespace size (number of slots needed at module level)
|
|
23
|
-
/// - A mapping from variable names to their namespace indices (for ref-count testing)
|
|
24
|
-
/// - The transformed AST nodes with all names resolved, ready for compilation
|
|
25
|
-
/// - The string interner containing all interned identifiers and filenames
|
|
26
|
-
pub struct PrepareResult {
|
|
27
|
-
/// Number of items in the namespace (at module level, this IS the global namespace)
|
|
28
|
-
pub namespace_size: usize,
|
|
29
|
-
/// Maps variable names to their indices in the namespace.
|
|
30
|
-
///
|
|
31
|
-
/// This map is used by:
|
|
32
|
-
/// - ref-count tests for looking up variables by name
|
|
33
|
-
/// - REPL incremental compilation to preserve stable global slot IDs across snippets
|
|
34
|
-
pub name_map: AHashMap<String, NamespaceId>,
|
|
35
|
-
/// The prepared AST nodes with all names resolved to namespace indices.
|
|
36
|
-
/// Function definitions are inline as `PreparedFunctionDef` variants.
|
|
37
|
-
pub nodes: Vec<PreparedNode>,
|
|
38
|
-
/// The string interner containing all interned identifiers and filenames.
|
|
39
|
-
pub interner: InternerBuilder,
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/// Prepares parsed nodes for compilation by resolving names and building the initial namespace.
|
|
43
|
-
///
|
|
44
|
-
/// The namespace will be converted to runtime Objects when execution begins and the heap is available.
|
|
45
|
-
/// At module level, the local namespace IS the global namespace.
|
|
46
|
-
pub(crate) fn prepare(parse_result: ParseResult, input_names: Vec<String>) -> Result<PrepareResult, ParseError> {
|
|
47
|
-
let ParseResult { nodes, interner } = parse_result;
|
|
48
|
-
let mut p = Prepare::new_module(input_names, &interner);
|
|
49
|
-
let mut prepared_nodes = p.prepare_nodes(nodes)?;
|
|
50
|
-
|
|
51
|
-
// In the root frame, the last expression is implicitly returned
|
|
52
|
-
// if it's not None. This matches Python REPL behavior where the last expression
|
|
53
|
-
// value is displayed/returned.
|
|
54
|
-
if let Some(Node::Expr(expr_loc)) = prepared_nodes.last()
|
|
55
|
-
&& !expr_loc.expr.is_none()
|
|
56
|
-
{
|
|
57
|
-
let new_expr_loc = expr_loc.clone();
|
|
58
|
-
prepared_nodes.pop();
|
|
59
|
-
prepared_nodes.push(Node::Return(new_expr_loc));
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
Ok(PrepareResult {
|
|
63
|
-
namespace_size: p.namespace_size,
|
|
64
|
-
name_map: p.name_map,
|
|
65
|
-
nodes: prepared_nodes,
|
|
66
|
-
interner,
|
|
67
|
-
})
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/// Prepares parsed nodes for REPL-style incremental compilation using an existing global namespace map.
|
|
71
|
-
///
|
|
72
|
-
/// Existing bindings keep their original namespace slots; any new names are appended with new slots.
|
|
73
|
-
/// This ensures snippets can be compiled independently while sharing one persistent global namespace.
|
|
74
|
-
pub(crate) fn prepare_with_existing_names(
|
|
75
|
-
parse_result: ParseResult,
|
|
76
|
-
existing_name_map: AHashMap<String, NamespaceId>,
|
|
77
|
-
) -> Result<PrepareResult, ParseError> {
|
|
78
|
-
let ParseResult { nodes, interner } = parse_result;
|
|
79
|
-
let mut p = Prepare::new_module_with_name_map(existing_name_map, &interner);
|
|
80
|
-
let mut prepared_nodes = p.prepare_nodes(nodes)?;
|
|
81
|
-
|
|
82
|
-
// In the root frame, the last expression is implicitly returned to match REPL behavior.
|
|
83
|
-
if let Some(Node::Expr(expr_loc)) = prepared_nodes.last()
|
|
84
|
-
&& !expr_loc.expr.is_none()
|
|
85
|
-
{
|
|
86
|
-
let new_expr_loc = expr_loc.clone();
|
|
87
|
-
prepared_nodes.pop();
|
|
88
|
-
prepared_nodes.push(Node::Return(new_expr_loc));
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
Ok(PrepareResult {
|
|
92
|
-
namespace_size: p.namespace_size,
|
|
93
|
-
name_map: p.name_map,
|
|
94
|
-
nodes: prepared_nodes,
|
|
95
|
-
interner,
|
|
96
|
-
})
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/// State machine for the preparation phase that transforms parsed AST nodes into a prepared form.
|
|
100
|
-
///
|
|
101
|
-
/// This struct maintains the mapping between variable names and their namespace indices,
|
|
102
|
-
/// and handles scope resolution. The preparation phase is crucial for converting string-based
|
|
103
|
-
/// name lookups into efficient integer-indexed namespace access during compilation and execution.
|
|
104
|
-
///
|
|
105
|
-
/// For functions, this struct also tracks:
|
|
106
|
-
/// - Which variables are declared `global` (should resolve to module namespace)
|
|
107
|
-
/// - Which variables are declared `nonlocal` (should resolve to enclosing scope via cells)
|
|
108
|
-
/// - Which variables are assigned locally (determines local vs global scope)
|
|
109
|
-
/// - Reference to the global name map for resolving global variable references
|
|
110
|
-
/// - Enclosing scope information for closure analysis
|
|
111
|
-
struct Prepare<'i> {
|
|
112
|
-
/// Reference to the string interner for looking up names in error messages.
|
|
113
|
-
interner: &'i InternerBuilder,
|
|
114
|
-
/// Maps variable names to their indices in this scope's namespace vector
|
|
115
|
-
name_map: AHashMap<String, NamespaceId>,
|
|
116
|
-
/// Number of items in the namespace
|
|
117
|
-
pub namespace_size: usize,
|
|
118
|
-
/// Whether this is the module-level scope.
|
|
119
|
-
/// At module level, all variables are global and `global` keyword is a no-op.
|
|
120
|
-
is_module_scope: bool,
|
|
121
|
-
/// Names declared as `global` in this scope.
|
|
122
|
-
/// These names will resolve to the global namespace instead of local.
|
|
123
|
-
global_names: AHashSet<String>,
|
|
124
|
-
/// Names that are assigned in this scope (from first-pass scan).
|
|
125
|
-
/// Used in functions to determine if a variable is local (assigned) or global (only read).
|
|
126
|
-
assigned_names: AHashSet<String>,
|
|
127
|
-
/// Names that have been assigned so far during the second pass (in order).
|
|
128
|
-
/// Used to produce the correct error message for `global x` when x was assigned before.
|
|
129
|
-
names_assigned_in_order: AHashSet<String>,
|
|
130
|
-
/// Copy of the module-level global name map.
|
|
131
|
-
/// Used by functions to resolve global variable references.
|
|
132
|
-
/// None at module level (not needed since all names are global there).
|
|
133
|
-
global_name_map: Option<AHashMap<String, NamespaceId>>,
|
|
134
|
-
/// Names that exist as locals in the enclosing function scope.
|
|
135
|
-
/// Used to validate `nonlocal` declarations and resolve captured variables.
|
|
136
|
-
/// None at module level or when there's no enclosing function.
|
|
137
|
-
enclosing_locals: Option<AHashSet<String>>,
|
|
138
|
-
/// Maps free variable names (from nonlocal declarations and implicit captures) to their
|
|
139
|
-
/// index in the free_vars vector. Pre-populated with nonlocal names at initialization,
|
|
140
|
-
/// then extended with implicit captures discovered during preparation.
|
|
141
|
-
free_var_map: AHashMap<String, NamespaceId>,
|
|
142
|
-
/// Maps cell variable names to their index in the owned_cells vector.
|
|
143
|
-
/// Pre-populated with cell_var names at initialization (excluding pass-through variables
|
|
144
|
-
/// that are both nonlocal and captured by nested functions), then extended as new
|
|
145
|
-
/// captures are discovered during nested function preparation.
|
|
146
|
-
cell_var_map: AHashMap<String, NamespaceId>,
|
|
147
|
-
/// Names that were resolved as `LocalUnassigned` in step 8 of `get_id`.
|
|
148
|
-
///
|
|
149
|
-
/// These names are never assigned and not parameters - they were only referenced
|
|
150
|
-
/// (e.g., external function names). Tracking them prevents step 6 from incorrectly
|
|
151
|
-
/// classifying subsequent references as `Local` (like parameters) when the name
|
|
152
|
-
/// appears in `name_map` from a previous `get_id` call.
|
|
153
|
-
unassigned_ref_names: AHashSet<String>,
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
impl<'i> Prepare<'i> {
|
|
157
|
-
/// Creates a new Prepare instance for module-level code.
|
|
158
|
-
///
|
|
159
|
-
/// At module level, all variables are global. The `global` keyword is a no-op
|
|
160
|
-
/// since all variables are already in the global namespace.
|
|
161
|
-
///
|
|
162
|
-
/// # Arguments
|
|
163
|
-
/// * `input_names` - Names that should be pre-registered in the namespace (e.g., input variables)
|
|
164
|
-
/// * `interner` - Reference to the string interner for looking up names
|
|
165
|
-
fn new_module(input_names: Vec<String>, interner: &'i InternerBuilder) -> Self {
|
|
166
|
-
let mut name_map = AHashMap::with_capacity(input_names.len());
|
|
167
|
-
for (index, name) in input_names.into_iter().enumerate() {
|
|
168
|
-
name_map.insert(name, NamespaceId::new(index));
|
|
169
|
-
}
|
|
170
|
-
let namespace_size = name_map.len();
|
|
171
|
-
Self {
|
|
172
|
-
interner,
|
|
173
|
-
name_map,
|
|
174
|
-
namespace_size,
|
|
175
|
-
is_module_scope: true,
|
|
176
|
-
global_names: AHashSet::new(),
|
|
177
|
-
assigned_names: AHashSet::new(),
|
|
178
|
-
names_assigned_in_order: AHashSet::new(),
|
|
179
|
-
global_name_map: None,
|
|
180
|
-
enclosing_locals: None,
|
|
181
|
-
free_var_map: AHashMap::new(),
|
|
182
|
-
cell_var_map: AHashMap::new(),
|
|
183
|
-
unassigned_ref_names: AHashSet::new(),
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
/// Creates a module-scope Prepare instance from an existing global name map.
|
|
188
|
-
///
|
|
189
|
-
/// Used by incremental REPL compilation to keep stable slot assignments across snippets.
|
|
190
|
-
fn new_module_with_name_map(name_map: AHashMap<String, NamespaceId>, interner: &'i InternerBuilder) -> Self {
|
|
191
|
-
let namespace_size = name_map
|
|
192
|
-
.values()
|
|
193
|
-
.map(|id| id.index())
|
|
194
|
-
.max()
|
|
195
|
-
.map_or(0, |max_idx| max_idx + 1);
|
|
196
|
-
|
|
197
|
-
Self {
|
|
198
|
-
interner,
|
|
199
|
-
name_map,
|
|
200
|
-
namespace_size,
|
|
201
|
-
is_module_scope: true,
|
|
202
|
-
global_names: AHashSet::new(),
|
|
203
|
-
assigned_names: AHashSet::new(),
|
|
204
|
-
names_assigned_in_order: AHashSet::new(),
|
|
205
|
-
global_name_map: None,
|
|
206
|
-
enclosing_locals: None,
|
|
207
|
-
free_var_map: AHashMap::new(),
|
|
208
|
-
cell_var_map: AHashMap::new(),
|
|
209
|
-
unassigned_ref_names: AHashSet::new(),
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
/// Creates a new Prepare instance for function-level code.
|
|
214
|
-
///
|
|
215
|
-
/// Pre-populates `free_var_map` with nonlocal declarations and implicit captures,
|
|
216
|
-
/// and `cell_var_map` with cell variables (excluding pass-through variables).
|
|
217
|
-
///
|
|
218
|
-
/// # Arguments
|
|
219
|
-
/// * `capacity` - Expected number of nodes
|
|
220
|
-
/// * `params` - Function parameter StringIds (pre-registered in namespace)
|
|
221
|
-
/// * `assigned_names` - Names that are assigned in this function (from first-pass scan)
|
|
222
|
-
/// * `global_names` - Names declared as `global` in this function
|
|
223
|
-
/// * `nonlocal_names` - Names declared as `nonlocal` in this function
|
|
224
|
-
/// * `implicit_captures` - Names captured from enclosing scope without explicit nonlocal
|
|
225
|
-
/// * `global_name_map` - Copy of the module-level name map for global resolution
|
|
226
|
-
/// * `enclosing_locals` - Names that exist as locals in the enclosing function (for nonlocal resolution)
|
|
227
|
-
/// * `cell_var_names` - Names that are captured by nested functions (must be stored in cells)
|
|
228
|
-
/// * `interner` - Reference to the string interner for looking up names
|
|
229
|
-
#[expect(clippy::too_many_arguments)]
|
|
230
|
-
fn new_function(
|
|
231
|
-
capacity: usize,
|
|
232
|
-
params: &[StringId],
|
|
233
|
-
assigned_names: AHashSet<String>,
|
|
234
|
-
global_names: AHashSet<String>,
|
|
235
|
-
nonlocal_names: AHashSet<String>,
|
|
236
|
-
implicit_captures: AHashSet<String>,
|
|
237
|
-
global_name_map: AHashMap<String, NamespaceId>,
|
|
238
|
-
enclosing_locals: Option<AHashSet<String>>,
|
|
239
|
-
cell_var_names: AHashSet<String>,
|
|
240
|
-
interner: &'i InternerBuilder,
|
|
241
|
-
) -> Self {
|
|
242
|
-
let mut name_map = AHashMap::with_capacity(capacity);
|
|
243
|
-
for (index, string_id) in params.iter().enumerate() {
|
|
244
|
-
name_map.insert(interner.get_str(*string_id).to_string(), NamespaceId::new(index));
|
|
245
|
-
}
|
|
246
|
-
let namespace_size = name_map.len();
|
|
247
|
-
|
|
248
|
-
// Namespace layout: [params][cell_vars][free_vars][locals]
|
|
249
|
-
// This predictable layout allows sequential namespace construction at runtime.
|
|
250
|
-
|
|
251
|
-
// Pre-populate cell_var_map with cell variables FIRST (right after params).
|
|
252
|
-
// Excludes pass-through variables (names that are both nonlocal and captured by
|
|
253
|
-
// nested functions - these stay in free_var_map since we receive the cell, not create it).
|
|
254
|
-
// NOTE: We intentionally do NOT add these to name_map here, because the scope
|
|
255
|
-
// validation checks name_map to detect "used before declaration" errors
|
|
256
|
-
let mut cell_var_map = AHashMap::with_capacity(cell_var_names.len());
|
|
257
|
-
let mut namespace_size = namespace_size;
|
|
258
|
-
for name in cell_var_names {
|
|
259
|
-
if !nonlocal_names.contains(&name) && !implicit_captures.contains(&name) {
|
|
260
|
-
let slot = namespace_size;
|
|
261
|
-
namespace_size += 1;
|
|
262
|
-
cell_var_map.insert(name, NamespaceId::new(slot));
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
// Pre-populate free_var_map with nonlocal declarations AND implicit captures SECOND (after cell_vars).
|
|
267
|
-
// Each entry maps name -> namespace slot index where the cell reference will be stored.
|
|
268
|
-
// NOTE: We intentionally do NOT add these to name_map here, because the nonlocal
|
|
269
|
-
// validation in prepare_nodes checks name_map to detect "used before nonlocal declaration"
|
|
270
|
-
let free_var_capacity = nonlocal_names.len() + implicit_captures.len();
|
|
271
|
-
let mut free_var_map = AHashMap::with_capacity(free_var_capacity);
|
|
272
|
-
for name in nonlocal_names {
|
|
273
|
-
let slot = namespace_size;
|
|
274
|
-
namespace_size += 1;
|
|
275
|
-
free_var_map.insert(name, NamespaceId::new(slot));
|
|
276
|
-
}
|
|
277
|
-
// Implicit captures (variables accessed from enclosing scope without explicit nonlocal)
|
|
278
|
-
for name in implicit_captures {
|
|
279
|
-
let slot = namespace_size;
|
|
280
|
-
namespace_size += 1;
|
|
281
|
-
free_var_map.insert(name, NamespaceId::new(slot));
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
Self {
|
|
285
|
-
interner,
|
|
286
|
-
name_map,
|
|
287
|
-
namespace_size,
|
|
288
|
-
is_module_scope: false,
|
|
289
|
-
global_names,
|
|
290
|
-
assigned_names,
|
|
291
|
-
names_assigned_in_order: AHashSet::new(),
|
|
292
|
-
global_name_map: Some(global_name_map),
|
|
293
|
-
enclosing_locals,
|
|
294
|
-
free_var_map,
|
|
295
|
-
cell_var_map,
|
|
296
|
-
unassigned_ref_names: AHashSet::new(),
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
/// Recursively prepares a sequence of AST nodes by resolving names and transforming expressions.
|
|
301
|
-
///
|
|
302
|
-
/// This method processes each node type differently:
|
|
303
|
-
/// - Resolves variable names to namespace indices
|
|
304
|
-
/// - Transforms function calls from identifier-based to builtin type-based
|
|
305
|
-
/// - Handles special cases like implicit returns in root frames
|
|
306
|
-
/// - Validates that names used in attribute calls are already defined
|
|
307
|
-
///
|
|
308
|
-
/// # Returns
|
|
309
|
-
/// A vector of prepared nodes ready for compilation
|
|
310
|
-
fn prepare_nodes(&mut self, nodes: Vec<ParseNode>) -> Result<Vec<PreparedNode>, ParseError> {
|
|
311
|
-
let nodes_len = nodes.len();
|
|
312
|
-
let mut new_nodes = Vec::with_capacity(nodes_len);
|
|
313
|
-
for node in nodes {
|
|
314
|
-
match node {
|
|
315
|
-
Node::Pass => (),
|
|
316
|
-
Node::Expr(expr) => new_nodes.push(Node::Expr(self.prepare_expression(expr)?)),
|
|
317
|
-
Node::Return(expr) => new_nodes.push(Node::Return(self.prepare_expression(expr)?)),
|
|
318
|
-
Node::ReturnNone => new_nodes.push(Node::ReturnNone),
|
|
319
|
-
Node::Raise(exc) => {
|
|
320
|
-
let expr = match exc {
|
|
321
|
-
Some(expr) => {
|
|
322
|
-
let prepared = self.prepare_expression(expr)?;
|
|
323
|
-
match prepared.expr {
|
|
324
|
-
// Handle raising a builtin exception type without instantiation,
|
|
325
|
-
// e.g. `raise TypeError`. Transform into `raise TypeError()`
|
|
326
|
-
// so the exception is properly instantiated before being raised.
|
|
327
|
-
Expr::Builtin(b) => {
|
|
328
|
-
let call_expr = Expr::Call {
|
|
329
|
-
callable: Callable::Builtin(b),
|
|
330
|
-
args: Box::new(ArgExprs::Empty),
|
|
331
|
-
};
|
|
332
|
-
Some(ExprLoc::new(prepared.position, call_expr))
|
|
333
|
-
}
|
|
334
|
-
_ => Some(prepared),
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
None => None,
|
|
338
|
-
};
|
|
339
|
-
new_nodes.push(Node::Raise(expr));
|
|
340
|
-
}
|
|
341
|
-
Node::Assert { test, msg } => {
|
|
342
|
-
let test = self.prepare_expression(test)?;
|
|
343
|
-
let msg = match msg {
|
|
344
|
-
Some(m) => Some(self.prepare_expression(m)?),
|
|
345
|
-
None => None,
|
|
346
|
-
};
|
|
347
|
-
new_nodes.push(Node::Assert { test, msg });
|
|
348
|
-
}
|
|
349
|
-
Node::Assign { target, object } => {
|
|
350
|
-
let object = self.prepare_expression(object)?;
|
|
351
|
-
// Track that this name was assigned before we call get_id
|
|
352
|
-
self.names_assigned_in_order
|
|
353
|
-
.insert(self.interner.get_str(target.name_id).to_string());
|
|
354
|
-
let (target, _) = self.get_id(target);
|
|
355
|
-
new_nodes.push(Node::Assign { target, object });
|
|
356
|
-
}
|
|
357
|
-
Node::UnpackAssign {
|
|
358
|
-
targets,
|
|
359
|
-
targets_position,
|
|
360
|
-
object,
|
|
361
|
-
} => {
|
|
362
|
-
let object = self.prepare_expression(object)?;
|
|
363
|
-
// Recursively resolve all targets (supports nested tuples)
|
|
364
|
-
let targets = targets
|
|
365
|
-
.into_iter()
|
|
366
|
-
.map(|target| self.prepare_unpack_target(target))
|
|
367
|
-
.collect();
|
|
368
|
-
new_nodes.push(Node::UnpackAssign {
|
|
369
|
-
targets,
|
|
370
|
-
targets_position,
|
|
371
|
-
object,
|
|
372
|
-
});
|
|
373
|
-
}
|
|
374
|
-
Node::OpAssign { target, op, object } => {
|
|
375
|
-
// Track that this name was assigned
|
|
376
|
-
self.names_assigned_in_order
|
|
377
|
-
.insert(self.interner.get_str(target.name_id).to_string());
|
|
378
|
-
let target = self.get_id(target).0;
|
|
379
|
-
let object = self.prepare_expression(object)?;
|
|
380
|
-
new_nodes.push(Node::OpAssign { target, op, object });
|
|
381
|
-
}
|
|
382
|
-
Node::SubscriptOpAssign {
|
|
383
|
-
target,
|
|
384
|
-
index,
|
|
385
|
-
op,
|
|
386
|
-
object,
|
|
387
|
-
target_position,
|
|
388
|
-
} => {
|
|
389
|
-
let target = self.get_id(target).0;
|
|
390
|
-
let index = self.prepare_expression(index)?;
|
|
391
|
-
let object = self.prepare_expression(object)?;
|
|
392
|
-
new_nodes.push(Node::SubscriptOpAssign {
|
|
393
|
-
target,
|
|
394
|
-
index,
|
|
395
|
-
op,
|
|
396
|
-
object,
|
|
397
|
-
target_position,
|
|
398
|
-
});
|
|
399
|
-
}
|
|
400
|
-
Node::SubscriptAssign {
|
|
401
|
-
target,
|
|
402
|
-
index,
|
|
403
|
-
value,
|
|
404
|
-
target_position,
|
|
405
|
-
} => {
|
|
406
|
-
// SubscriptAssign doesn't assign to the target itself, just modifies it
|
|
407
|
-
let target = self.get_id(target).0;
|
|
408
|
-
let index = self.prepare_expression(index)?;
|
|
409
|
-
let value = self.prepare_expression(value)?;
|
|
410
|
-
new_nodes.push(Node::SubscriptAssign {
|
|
411
|
-
target,
|
|
412
|
-
index,
|
|
413
|
-
value,
|
|
414
|
-
target_position,
|
|
415
|
-
});
|
|
416
|
-
}
|
|
417
|
-
Node::AttrAssign {
|
|
418
|
-
object,
|
|
419
|
-
attr,
|
|
420
|
-
target_position,
|
|
421
|
-
value,
|
|
422
|
-
} => {
|
|
423
|
-
// AttrAssign doesn't assign to the object itself, just modifies its attribute
|
|
424
|
-
let object = self.prepare_expression(object)?;
|
|
425
|
-
let value = self.prepare_expression(value)?;
|
|
426
|
-
new_nodes.push(Node::AttrAssign {
|
|
427
|
-
object,
|
|
428
|
-
attr,
|
|
429
|
-
target_position,
|
|
430
|
-
value,
|
|
431
|
-
});
|
|
432
|
-
}
|
|
433
|
-
Node::For {
|
|
434
|
-
target,
|
|
435
|
-
iter,
|
|
436
|
-
body,
|
|
437
|
-
or_else,
|
|
438
|
-
} => {
|
|
439
|
-
// Prepare target with normal scoping (not comprehension isolation)
|
|
440
|
-
let target = self.prepare_unpack_target(target);
|
|
441
|
-
new_nodes.push(Node::For {
|
|
442
|
-
target,
|
|
443
|
-
iter: self.prepare_expression(iter)?,
|
|
444
|
-
body: self.prepare_nodes(body)?,
|
|
445
|
-
or_else: self.prepare_nodes(or_else)?,
|
|
446
|
-
});
|
|
447
|
-
}
|
|
448
|
-
Node::Break { position } => {
|
|
449
|
-
new_nodes.push(Node::Break { position });
|
|
450
|
-
}
|
|
451
|
-
Node::Continue { position } => {
|
|
452
|
-
new_nodes.push(Node::Continue { position });
|
|
453
|
-
}
|
|
454
|
-
Node::While { test, body, or_else } => {
|
|
455
|
-
new_nodes.push(Node::While {
|
|
456
|
-
test: self.prepare_expression(test)?,
|
|
457
|
-
body: self.prepare_nodes(body)?,
|
|
458
|
-
or_else: self.prepare_nodes(or_else)?,
|
|
459
|
-
});
|
|
460
|
-
}
|
|
461
|
-
Node::If { test, body, or_else } => {
|
|
462
|
-
let test = self.prepare_expression(test)?;
|
|
463
|
-
let body = self.prepare_nodes(body)?;
|
|
464
|
-
let or_else = self.prepare_nodes(or_else)?;
|
|
465
|
-
new_nodes.push(Node::If { test, body, or_else });
|
|
466
|
-
}
|
|
467
|
-
Node::FunctionDef(RawFunctionDef {
|
|
468
|
-
name,
|
|
469
|
-
signature,
|
|
470
|
-
body,
|
|
471
|
-
is_async,
|
|
472
|
-
}) => {
|
|
473
|
-
let func_node = self.prepare_function_def(name, &signature, body, is_async)?;
|
|
474
|
-
new_nodes.push(func_node);
|
|
475
|
-
}
|
|
476
|
-
Node::Global { names, position } => {
|
|
477
|
-
// At module level, `global` is a no-op since all variables are already global.
|
|
478
|
-
// In functions, the global declarations are already collected in the first pass
|
|
479
|
-
// (see prepare_function_def), so this is also a no-op at this point.
|
|
480
|
-
// The actual effect happens in get_id where we check global_names.
|
|
481
|
-
if !self.is_module_scope {
|
|
482
|
-
// Validate that names weren't already used/assigned before `global` declaration
|
|
483
|
-
for string_id in names {
|
|
484
|
-
let name_str = self.interner.get_str(string_id);
|
|
485
|
-
if self.names_assigned_in_order.contains(name_str) {
|
|
486
|
-
// Name was assigned before the global declaration
|
|
487
|
-
return Err(ParseError::syntax(
|
|
488
|
-
format!("name '{name_str}' is assigned to before global declaration"),
|
|
489
|
-
position,
|
|
490
|
-
));
|
|
491
|
-
} else if self.name_map.contains_key(name_str) {
|
|
492
|
-
// Name was used (but not assigned) before the global declaration
|
|
493
|
-
return Err(ParseError::syntax(
|
|
494
|
-
format!("name '{name_str}' is used prior to global declaration"),
|
|
495
|
-
position,
|
|
496
|
-
));
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
// Global statements don't produce any runtime nodes
|
|
501
|
-
}
|
|
502
|
-
Node::Nonlocal { names, position } => {
|
|
503
|
-
// Nonlocal can only be used inside a function, not at module level
|
|
504
|
-
if self.is_module_scope {
|
|
505
|
-
return Err(ParseError::syntax(
|
|
506
|
-
"nonlocal declaration not allowed at module level",
|
|
507
|
-
position,
|
|
508
|
-
));
|
|
509
|
-
}
|
|
510
|
-
// Validate that names weren't already used/assigned before `nonlocal` declaration
|
|
511
|
-
// and that the binding exists in an enclosing scope
|
|
512
|
-
for string_id in names {
|
|
513
|
-
let name_str = self.interner.get_str(string_id);
|
|
514
|
-
if self.names_assigned_in_order.contains(name_str) {
|
|
515
|
-
// Name was assigned before the nonlocal declaration
|
|
516
|
-
return Err(ParseError::syntax(
|
|
517
|
-
format!("name '{name_str}' is assigned to before nonlocal declaration"),
|
|
518
|
-
position,
|
|
519
|
-
));
|
|
520
|
-
} else if self.name_map.contains_key(name_str) {
|
|
521
|
-
// Name was used (but not assigned) before the nonlocal declaration
|
|
522
|
-
return Err(ParseError::syntax(
|
|
523
|
-
format!("name '{name_str}' is used prior to nonlocal declaration"),
|
|
524
|
-
position,
|
|
525
|
-
));
|
|
526
|
-
}
|
|
527
|
-
// Validate that the binding exists in an enclosing scope
|
|
528
|
-
if let Some(ref enclosing) = self.enclosing_locals {
|
|
529
|
-
if !enclosing.contains(name_str) {
|
|
530
|
-
return Err(ParseError::syntax(
|
|
531
|
-
format!("no binding for nonlocal '{name_str}' found"),
|
|
532
|
-
position,
|
|
533
|
-
));
|
|
534
|
-
}
|
|
535
|
-
} else {
|
|
536
|
-
// No enclosing scope (function defined at module level)
|
|
537
|
-
// The nonlocal must reference something in an enclosing function
|
|
538
|
-
return Err(ParseError::syntax(
|
|
539
|
-
format!("no binding for nonlocal '{name_str}' found"),
|
|
540
|
-
position,
|
|
541
|
-
));
|
|
542
|
-
}
|
|
543
|
-
}
|
|
544
|
-
// Nonlocal statements don't produce any runtime nodes
|
|
545
|
-
}
|
|
546
|
-
Node::Try(Try {
|
|
547
|
-
body,
|
|
548
|
-
handlers,
|
|
549
|
-
or_else,
|
|
550
|
-
finally,
|
|
551
|
-
}) => {
|
|
552
|
-
let body = self.prepare_nodes(body)?;
|
|
553
|
-
let handlers = handlers
|
|
554
|
-
.into_iter()
|
|
555
|
-
.map(|h| self.prepare_except_handler(h))
|
|
556
|
-
.collect::<Result<Vec<_>, _>>()?;
|
|
557
|
-
let or_else = self.prepare_nodes(or_else)?;
|
|
558
|
-
let finally = self.prepare_nodes(finally)?;
|
|
559
|
-
new_nodes.push(Node::Try(Try {
|
|
560
|
-
body,
|
|
561
|
-
handlers,
|
|
562
|
-
or_else,
|
|
563
|
-
finally,
|
|
564
|
-
}));
|
|
565
|
-
}
|
|
566
|
-
Node::Import { module_name, binding } => {
|
|
567
|
-
// Resolve the binding identifier to get the namespace slot
|
|
568
|
-
let (resolved_binding, _) = self.get_id(binding);
|
|
569
|
-
new_nodes.push(Node::Import {
|
|
570
|
-
module_name,
|
|
571
|
-
binding: resolved_binding,
|
|
572
|
-
});
|
|
573
|
-
}
|
|
574
|
-
Node::ImportFrom {
|
|
575
|
-
module_name,
|
|
576
|
-
names,
|
|
577
|
-
position,
|
|
578
|
-
} => {
|
|
579
|
-
// Resolve each binding identifier to get namespace slots
|
|
580
|
-
let resolved_names = names
|
|
581
|
-
.into_iter()
|
|
582
|
-
.map(|(import_name, binding)| {
|
|
583
|
-
let (resolved_binding, _) = self.get_id(binding);
|
|
584
|
-
(import_name, resolved_binding)
|
|
585
|
-
})
|
|
586
|
-
.collect();
|
|
587
|
-
new_nodes.push(Node::ImportFrom {
|
|
588
|
-
module_name,
|
|
589
|
-
names: resolved_names,
|
|
590
|
-
position,
|
|
591
|
-
});
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
Ok(new_nodes)
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
/// Prepares an exception handler by resolving names in the exception type and body.
|
|
599
|
-
///
|
|
600
|
-
/// The exception variable (if present) is treated as an assigned name in the current scope.
|
|
601
|
-
fn prepare_except_handler(
|
|
602
|
-
&mut self,
|
|
603
|
-
handler: ExceptHandler<ParseNode>,
|
|
604
|
-
) -> Result<ExceptHandler<PreparedNode>, ParseError> {
|
|
605
|
-
let exc_type = match handler.exc_type {
|
|
606
|
-
Some(expr) => Some(self.prepare_expression(expr)?),
|
|
607
|
-
None => None,
|
|
608
|
-
};
|
|
609
|
-
// The exception variable binding (e.g., `as e:`) is an assignment
|
|
610
|
-
let name = match handler.name {
|
|
611
|
-
Some(ident) => {
|
|
612
|
-
// Track that this name was assigned
|
|
613
|
-
self.names_assigned_in_order
|
|
614
|
-
.insert(self.interner.get_str(ident.name_id).to_string());
|
|
615
|
-
Some(self.get_id(ident).0)
|
|
616
|
-
}
|
|
617
|
-
None => None,
|
|
618
|
-
};
|
|
619
|
-
let body = self.prepare_nodes(handler.body)?;
|
|
620
|
-
Ok(ExceptHandler { exc_type, name, body })
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
/// Prepares an expression by resolving names, transforming calls, and applying optimizations.
|
|
624
|
-
///
|
|
625
|
-
/// Key transformations performed:
|
|
626
|
-
/// - Name lookups are resolved to namespace indices via `get_id`
|
|
627
|
-
/// - Function calls are resolved from identifiers to builtin types
|
|
628
|
-
/// - Attribute calls validate that the object is already defined (not a new name)
|
|
629
|
-
/// - Lists and tuples are recursively prepared
|
|
630
|
-
/// - Modulo equality patterns like `x % n == k` (constant right-hand side) are optimized to
|
|
631
|
-
/// `CmpOperator::ModEq`
|
|
632
|
-
///
|
|
633
|
-
/// # Errors
|
|
634
|
-
/// Returns a NameError if an attribute call references an undefined variable
|
|
635
|
-
fn prepare_expression(&mut self, loc_expr: ExprLoc) -> Result<ExprLoc, ParseError> {
|
|
636
|
-
let ExprLoc { position, expr } = loc_expr;
|
|
637
|
-
let expr = match expr {
|
|
638
|
-
Expr::Literal(object) => Expr::Literal(object),
|
|
639
|
-
Expr::Builtin(callable) => Expr::Builtin(callable),
|
|
640
|
-
Expr::Name(name) => self.resolve_name_or_builtin(name),
|
|
641
|
-
Expr::Op { left, op, right } => Expr::Op {
|
|
642
|
-
left: Box::new(self.prepare_expression(*left)?),
|
|
643
|
-
op,
|
|
644
|
-
right: Box::new(self.prepare_expression(*right)?),
|
|
645
|
-
},
|
|
646
|
-
Expr::CmpOp { left, op, right } => Expr::CmpOp {
|
|
647
|
-
left: Box::new(self.prepare_expression(*left)?),
|
|
648
|
-
op,
|
|
649
|
-
right: Box::new(self.prepare_expression(*right)?),
|
|
650
|
-
},
|
|
651
|
-
Expr::ChainCmp { left, comparisons } => Expr::ChainCmp {
|
|
652
|
-
left: Box::new(self.prepare_expression(*left)?),
|
|
653
|
-
comparisons: comparisons
|
|
654
|
-
.into_iter()
|
|
655
|
-
.map(|(op, expr)| Ok((op, self.prepare_expression(expr)?)))
|
|
656
|
-
.collect::<Result<Vec<_>, _>>()?,
|
|
657
|
-
},
|
|
658
|
-
Expr::Call { callable, mut args } => {
|
|
659
|
-
// Prepare the arguments
|
|
660
|
-
args.prepare_args(|expr| self.prepare_expression(expr))?;
|
|
661
|
-
// For Name callables, resolve the identifier in the namespace
|
|
662
|
-
// Don't error here if undefined - let runtime raise NameError with proper traceback
|
|
663
|
-
let callable = match callable {
|
|
664
|
-
Callable::Name(ident) => match self.resolve_name_or_builtin(ident) {
|
|
665
|
-
Expr::Builtin(b) => Callable::Builtin(b),
|
|
666
|
-
Expr::Name(resolved) => Callable::Name(resolved),
|
|
667
|
-
_ => unreachable!("resolve_name_or_builtin returns Name or Builtin"),
|
|
668
|
-
},
|
|
669
|
-
other @ Callable::Builtin(_) => other,
|
|
670
|
-
};
|
|
671
|
-
Expr::Call { callable, args }
|
|
672
|
-
}
|
|
673
|
-
Expr::AttrCall { object, attr, mut args } => {
|
|
674
|
-
// Prepare the object expression (supports chained access like a.b.c.method())
|
|
675
|
-
let object = Box::new(self.prepare_expression(*object)?);
|
|
676
|
-
args.prepare_args(|expr| self.prepare_expression(expr))?;
|
|
677
|
-
Expr::AttrCall { object, attr, args }
|
|
678
|
-
}
|
|
679
|
-
Expr::IndirectCall { callable, mut args } => {
|
|
680
|
-
// Prepare the callable expression (e.g., lambda or any expression returning a callable)
|
|
681
|
-
let callable = Box::new(self.prepare_expression(*callable)?);
|
|
682
|
-
args.prepare_args(|expr| self.prepare_expression(expr))?;
|
|
683
|
-
Expr::IndirectCall { callable, args }
|
|
684
|
-
}
|
|
685
|
-
Expr::AttrGet { object, attr } => {
|
|
686
|
-
// Prepare the object expression (supports chained access like a.b.c)
|
|
687
|
-
let object = Box::new(self.prepare_expression(*object)?);
|
|
688
|
-
Expr::AttrGet { object, attr }
|
|
689
|
-
}
|
|
690
|
-
Expr::List(elements) => {
|
|
691
|
-
let items = elements
|
|
692
|
-
.into_iter()
|
|
693
|
-
.map(|item| self.prepare_sequence_item(item))
|
|
694
|
-
.collect::<Result<_, ParseError>>()?;
|
|
695
|
-
Expr::List(items)
|
|
696
|
-
}
|
|
697
|
-
Expr::Tuple(elements) => {
|
|
698
|
-
let items = elements
|
|
699
|
-
.into_iter()
|
|
700
|
-
.map(|item| self.prepare_sequence_item(item))
|
|
701
|
-
.collect::<Result<_, ParseError>>()?;
|
|
702
|
-
Expr::Tuple(items)
|
|
703
|
-
}
|
|
704
|
-
Expr::Subscript { object, index } => Expr::Subscript {
|
|
705
|
-
object: Box::new(self.prepare_expression(*object)?),
|
|
706
|
-
index: Box::new(self.prepare_expression(*index)?),
|
|
707
|
-
},
|
|
708
|
-
Expr::Dict(dict_items) => {
|
|
709
|
-
let prepared = dict_items
|
|
710
|
-
.into_iter()
|
|
711
|
-
.map(|item| match item {
|
|
712
|
-
DictItem::Pair(k, v) => {
|
|
713
|
-
Ok(DictItem::Pair(self.prepare_expression(k)?, self.prepare_expression(v)?))
|
|
714
|
-
}
|
|
715
|
-
DictItem::Unpack(e) => Ok(DictItem::Unpack(self.prepare_expression(e)?)),
|
|
716
|
-
})
|
|
717
|
-
.collect::<Result<_, ParseError>>()?;
|
|
718
|
-
Expr::Dict(prepared)
|
|
719
|
-
}
|
|
720
|
-
Expr::Set(elements) => {
|
|
721
|
-
let items = elements
|
|
722
|
-
.into_iter()
|
|
723
|
-
.map(|item| self.prepare_sequence_item(item))
|
|
724
|
-
.collect::<Result<_, ParseError>>()?;
|
|
725
|
-
Expr::Set(items)
|
|
726
|
-
}
|
|
727
|
-
Expr::Not(operand) => Expr::Not(Box::new(self.prepare_expression(*operand)?)),
|
|
728
|
-
Expr::UnaryMinus(operand) => Expr::UnaryMinus(Box::new(self.prepare_expression(*operand)?)),
|
|
729
|
-
Expr::UnaryPlus(operand) => Expr::UnaryPlus(Box::new(self.prepare_expression(*operand)?)),
|
|
730
|
-
Expr::UnaryInvert(operand) => Expr::UnaryInvert(Box::new(self.prepare_expression(*operand)?)),
|
|
731
|
-
Expr::FString(parts) => {
|
|
732
|
-
let prepared_parts = parts
|
|
733
|
-
.into_iter()
|
|
734
|
-
.map(|part| self.prepare_fstring_part(part))
|
|
735
|
-
.collect::<Result<Vec<_>, ParseError>>()?;
|
|
736
|
-
Expr::FString(prepared_parts)
|
|
737
|
-
}
|
|
738
|
-
Expr::IfElse { test, body, orelse } => Expr::IfElse {
|
|
739
|
-
test: Box::new(self.prepare_expression(*test)?),
|
|
740
|
-
body: Box::new(self.prepare_expression(*body)?),
|
|
741
|
-
orelse: Box::new(self.prepare_expression(*orelse)?),
|
|
742
|
-
},
|
|
743
|
-
Expr::ListComp { elt, generators } => {
|
|
744
|
-
let (generators, elt, _) = self.prepare_comprehension(generators, Some(*elt), None)?;
|
|
745
|
-
Expr::ListComp {
|
|
746
|
-
elt: Box::new(elt.expect("list comp must have elt")),
|
|
747
|
-
generators,
|
|
748
|
-
}
|
|
749
|
-
}
|
|
750
|
-
Expr::SetComp { elt, generators } => {
|
|
751
|
-
let (generators, elt, _) = self.prepare_comprehension(generators, Some(*elt), None)?;
|
|
752
|
-
Expr::SetComp {
|
|
753
|
-
elt: Box::new(elt.expect("set comp must have elt")),
|
|
754
|
-
generators,
|
|
755
|
-
}
|
|
756
|
-
}
|
|
757
|
-
Expr::DictComp { key, value, generators } => {
|
|
758
|
-
let (generators, _, key_value) = self.prepare_comprehension(generators, None, Some((*key, *value)))?;
|
|
759
|
-
let (key, value) = key_value.expect("dict comp must have key/value");
|
|
760
|
-
Expr::DictComp {
|
|
761
|
-
key: Box::new(key),
|
|
762
|
-
value: Box::new(value),
|
|
763
|
-
generators,
|
|
764
|
-
}
|
|
765
|
-
}
|
|
766
|
-
Expr::LambdaRaw {
|
|
767
|
-
name_id,
|
|
768
|
-
signature,
|
|
769
|
-
body,
|
|
770
|
-
} => {
|
|
771
|
-
// Convert the raw lambda into a prepared lambda expression
|
|
772
|
-
return self.prepare_lambda(name_id, &signature, &body, position);
|
|
773
|
-
}
|
|
774
|
-
Expr::Lambda { .. } => {
|
|
775
|
-
// Lambda should only be created during prepare, never during parsing
|
|
776
|
-
unreachable!("Expr::Lambda should not exist before prepare phase")
|
|
777
|
-
}
|
|
778
|
-
Expr::Slice { lower, upper, step } => Expr::Slice {
|
|
779
|
-
lower: lower.map(|e| self.prepare_expression(*e)).transpose()?.map(Box::new),
|
|
780
|
-
upper: upper.map(|e| self.prepare_expression(*e)).transpose()?.map(Box::new),
|
|
781
|
-
step: step.map(|e| self.prepare_expression(*e)).transpose()?.map(Box::new),
|
|
782
|
-
},
|
|
783
|
-
Expr::Named { target, value } => {
|
|
784
|
-
let value = Box::new(self.prepare_expression(*value)?);
|
|
785
|
-
// Register the target as assigned in this scope
|
|
786
|
-
self.names_assigned_in_order
|
|
787
|
-
.insert(self.interner.get_str(target.name_id).to_string());
|
|
788
|
-
let (resolved_target, _) = self.get_id(target);
|
|
789
|
-
Expr::Named {
|
|
790
|
-
target: resolved_target,
|
|
791
|
-
value,
|
|
792
|
-
}
|
|
793
|
-
}
|
|
794
|
-
Expr::Await(value) => Expr::Await(Box::new(self.prepare_expression(*value)?)),
|
|
795
|
-
};
|
|
796
|
-
|
|
797
|
-
// Optimization: Transform `(x % n) == value` with any constant right-hand side into a
|
|
798
|
-
// specialized ModEq operator.
|
|
799
|
-
// This is a common pattern in competitive programming (e.g., FizzBuzz checks like `i % 3 == 0`)
|
|
800
|
-
// and can be executed more efficiently with a single modulo operation + comparison
|
|
801
|
-
// instead of separate modulo, then equality check.
|
|
802
|
-
if let Expr::CmpOp { left, op, right } = &expr
|
|
803
|
-
&& op == &CmpOperator::Eq
|
|
804
|
-
&& let Expr::Literal(Literal::Int(value)) = right.expr
|
|
805
|
-
&& let Expr::Op {
|
|
806
|
-
left: left2,
|
|
807
|
-
op,
|
|
808
|
-
right: right2,
|
|
809
|
-
} = &left.expr
|
|
810
|
-
&& op == &Operator::Mod
|
|
811
|
-
{
|
|
812
|
-
let new_expr = Expr::CmpOp {
|
|
813
|
-
left: left2.clone(),
|
|
814
|
-
op: CmpOperator::ModEq(value),
|
|
815
|
-
right: right2.clone(),
|
|
816
|
-
};
|
|
817
|
-
return Ok(ExprLoc {
|
|
818
|
-
position: left.position,
|
|
819
|
-
expr: new_expr,
|
|
820
|
-
});
|
|
821
|
-
}
|
|
822
|
-
|
|
823
|
-
Ok(ExprLoc { position, expr })
|
|
824
|
-
}
|
|
825
|
-
|
|
826
|
-
/// Resolves a name to either `Expr::Builtin` or `Expr::Name` with scope-aware builtin detection.
|
|
827
|
-
///
|
|
828
|
-
/// Python's name resolution follows LEGB order (Local, Enclosing, Global, Builtin).
|
|
829
|
-
/// Builtins are only used when the name is not found in any other scope. This method
|
|
830
|
-
/// ensures that local assignments (e.g., `int = 42`) properly shadow builtin names.
|
|
831
|
-
///
|
|
832
|
-
/// We check before calling `get_id` to avoid allocating unnecessary namespace slots.
|
|
833
|
-
/// At module level, a slot allocated for an unassigned builtin would leak into
|
|
834
|
-
/// `global_name_map` for nested functions, causing incorrect resolution.
|
|
835
|
-
fn resolve_name_or_builtin(&mut self, name: Identifier) -> Expr {
|
|
836
|
-
let name_str = self.interner.get_str(name.name_id);
|
|
837
|
-
|
|
838
|
-
// Check if the name is assigned in the current scope. If so, it shadows
|
|
839
|
-
// any builtin with the same name.
|
|
840
|
-
let is_locally_assigned = if self.is_module_scope {
|
|
841
|
-
// Module scope: sequential — only names assigned SO FAR shadow builtins
|
|
842
|
-
self.names_assigned_in_order.contains(name_str)
|
|
843
|
-
} else {
|
|
844
|
-
// Function scope: lexical — ANY assignment in the function body makes
|
|
845
|
-
// the name local for the entire function
|
|
846
|
-
self.assigned_names.contains(name_str)
|
|
847
|
-
};
|
|
848
|
-
|
|
849
|
-
if !is_locally_assigned {
|
|
850
|
-
// In function scope, also check if the name is bound by other mechanisms
|
|
851
|
-
// (global declaration, parameter, closure capture, enclosing/global scope).
|
|
852
|
-
// Only fall back to builtins if the name is truly unresolved.
|
|
853
|
-
let is_otherwise_bound = !self.is_module_scope
|
|
854
|
-
&& (self.global_names.contains(name_str)
|
|
855
|
-
|| self.free_var_map.contains_key(name_str)
|
|
856
|
-
|| self.cell_var_map.contains_key(name_str)
|
|
857
|
-
|| self.name_map.contains_key(name_str)
|
|
858
|
-
|| self.enclosing_locals.as_ref().is_some_and(|l| l.contains(name_str))
|
|
859
|
-
|| self.global_name_map.as_ref().is_some_and(|m| m.contains_key(name_str)));
|
|
860
|
-
|
|
861
|
-
if !is_otherwise_bound && let Ok(builtin) = name_str.parse::<Builtins>() {
|
|
862
|
-
return Expr::Builtin(builtin);
|
|
863
|
-
}
|
|
864
|
-
}
|
|
865
|
-
|
|
866
|
-
Expr::Name(self.get_id(name).0)
|
|
867
|
-
}
|
|
868
|
-
|
|
869
|
-
/// Prepares a `SequenceItem` by recursively preparing its inner expression.
|
|
870
|
-
///
|
|
871
|
-
/// Both `Value` and `Unpack` variants need their expressions prepared
|
|
872
|
-
/// (name resolution, scope analysis, builtin detection, etc.).
|
|
873
|
-
fn prepare_sequence_item(&mut self, item: SequenceItem) -> Result<SequenceItem, ParseError> {
|
|
874
|
-
match item {
|
|
875
|
-
SequenceItem::Value(e) => Ok(SequenceItem::Value(self.prepare_expression(e)?)),
|
|
876
|
-
SequenceItem::Unpack(e) => Ok(SequenceItem::Unpack(self.prepare_expression(e)?)),
|
|
877
|
-
}
|
|
878
|
-
}
|
|
879
|
-
|
|
880
|
-
/// Prepares a comprehension with scope isolation for loop variables.
|
|
881
|
-
///
|
|
882
|
-
/// Comprehension loop variables are isolated from the enclosing scope - they do not
|
|
883
|
-
/// leak after the comprehension completes. CPython scoping rules require:
|
|
884
|
-
///
|
|
885
|
-
/// 1. The FIRST generator's iter is evaluated in the enclosing scope
|
|
886
|
-
/// 2. ALL loop variables from ALL generators are then shadowed as local
|
|
887
|
-
/// 3. Subsequent generators' iters see all loop vars as local (even if unassigned)
|
|
888
|
-
///
|
|
889
|
-
/// This means `[y for x in [1] for y in z for z in [[2]]]` raises UnboundLocalError
|
|
890
|
-
/// because `z` is treated as local (it's a loop var in generator 3) when evaluating
|
|
891
|
-
/// generator 2's iter.
|
|
892
|
-
///
|
|
893
|
-
/// For list/set comprehensions, pass `elt` as Some and `key_value` as None.
|
|
894
|
-
/// For dict comprehensions, pass `elt` as None and `key_value` as Some((key, value)).
|
|
895
|
-
#[expect(clippy::type_complexity)]
|
|
896
|
-
fn prepare_comprehension(
|
|
897
|
-
&mut self,
|
|
898
|
-
generators: Vec<Comprehension>,
|
|
899
|
-
elt: Option<ExprLoc>,
|
|
900
|
-
key_value: Option<(ExprLoc, ExprLoc)>,
|
|
901
|
-
) -> Result<(Vec<Comprehension>, Option<ExprLoc>, Option<(ExprLoc, ExprLoc)>), ParseError> {
|
|
902
|
-
// Per PEP 572, walrus operators inside comprehensions bind in the ENCLOSING scope.
|
|
903
|
-
// Pre-register walrus targets before saving scope state, so they persist after restore.
|
|
904
|
-
let mut walrus_targets: AHashSet<String> = AHashSet::new();
|
|
905
|
-
if let Some(ref e) = elt {
|
|
906
|
-
collect_assigned_names_from_expr(e, &mut walrus_targets, self.interner);
|
|
907
|
-
}
|
|
908
|
-
if let Some((ref k, ref v)) = key_value {
|
|
909
|
-
collect_assigned_names_from_expr(k, &mut walrus_targets, self.interner);
|
|
910
|
-
collect_assigned_names_from_expr(v, &mut walrus_targets, self.interner);
|
|
911
|
-
}
|
|
912
|
-
for generator in &generators {
|
|
913
|
-
// Note: we don't scan iter expressions here because walrus in iterable is not allowed
|
|
914
|
-
for cond in &generator.ifs {
|
|
915
|
-
collect_assigned_names_from_expr(cond, &mut walrus_targets, self.interner);
|
|
916
|
-
}
|
|
917
|
-
}
|
|
918
|
-
// Pre-allocate slots for walrus targets in the enclosing scope
|
|
919
|
-
for name in &walrus_targets {
|
|
920
|
-
if !self.name_map.contains_key(name) {
|
|
921
|
-
let slot = NamespaceId::new(self.namespace_size);
|
|
922
|
-
self.namespace_size += 1;
|
|
923
|
-
self.name_map.insert(name.clone(), slot);
|
|
924
|
-
self.names_assigned_in_order.insert(name.clone());
|
|
925
|
-
}
|
|
926
|
-
}
|
|
927
|
-
|
|
928
|
-
// Save current scope state for isolation
|
|
929
|
-
let saved_name_map = self.name_map.clone();
|
|
930
|
-
let saved_assigned_names = self.names_assigned_in_order.clone();
|
|
931
|
-
let saved_free_var_map = self.free_var_map.clone();
|
|
932
|
-
let saved_cell_var_map = self.cell_var_map.clone();
|
|
933
|
-
let saved_enclosing_locals = self.enclosing_locals.clone();
|
|
934
|
-
let saved_unassigned_ref_names = self.unassigned_ref_names.clone();
|
|
935
|
-
|
|
936
|
-
// Step 1: Prepare first generator's iter in enclosing scope (before any shadowing)
|
|
937
|
-
let mut generators_iter = generators.into_iter();
|
|
938
|
-
let first_gen = generators_iter
|
|
939
|
-
.next()
|
|
940
|
-
.expect("comprehension must have at least one generator");
|
|
941
|
-
let first_iter = self.prepare_expression(first_gen.iter)?;
|
|
942
|
-
|
|
943
|
-
// Step 2: Collect and shadow ALL loop variable names from ALL generators.
|
|
944
|
-
// This must happen BEFORE evaluating any subsequent generator's iter expression.
|
|
945
|
-
// We allocate slots but don't mark them as "assigned" yet - this causes
|
|
946
|
-
// UnboundLocalError if a later generator's iter references an earlier-declared
|
|
947
|
-
// but not-yet-assigned loop variable.
|
|
948
|
-
let first_target = self.prepare_unpack_target_for_comprehension(first_gen.target);
|
|
949
|
-
|
|
950
|
-
// Collect remaining generators so we can pre-shadow their targets
|
|
951
|
-
let remaining_gens: Vec<Comprehension> = generators_iter.collect();
|
|
952
|
-
|
|
953
|
-
// Pre-shadow ALL remaining loop variables before evaluating their iters.
|
|
954
|
-
// This is the key CPython behavior: all loop vars are local to the comprehension,
|
|
955
|
-
// so referencing a later loop var in an earlier iter raises UnboundLocalError.
|
|
956
|
-
let mut preshadowed_targets: Vec<UnpackTarget> = Vec::with_capacity(remaining_gens.len());
|
|
957
|
-
for generator in &remaining_gens {
|
|
958
|
-
preshadowed_targets.push(self.prepare_unpack_target_shadow_only(generator.target.clone()));
|
|
959
|
-
}
|
|
960
|
-
|
|
961
|
-
// Prepare first generator's filters (can see first loop variable)
|
|
962
|
-
let first_ifs = first_gen
|
|
963
|
-
.ifs
|
|
964
|
-
.into_iter()
|
|
965
|
-
.map(|cond| self.prepare_expression(cond))
|
|
966
|
-
.collect::<Result<Vec<_>, _>>()?;
|
|
967
|
-
|
|
968
|
-
let mut prepared_generators = Vec::with_capacity(1 + remaining_gens.len());
|
|
969
|
-
prepared_generators.push(Comprehension {
|
|
970
|
-
target: first_target,
|
|
971
|
-
iter: first_iter,
|
|
972
|
-
ifs: first_ifs,
|
|
973
|
-
});
|
|
974
|
-
|
|
975
|
-
// Step 3: Process remaining generators - their iters now see all loop vars as local
|
|
976
|
-
for (generator, preshadowed_target) in remaining_gens.into_iter().zip(preshadowed_targets) {
|
|
977
|
-
let iter = self.prepare_expression(generator.iter)?;
|
|
978
|
-
let ifs = generator
|
|
979
|
-
.ifs
|
|
980
|
-
.into_iter()
|
|
981
|
-
.map(|cond| self.prepare_expression(cond))
|
|
982
|
-
.collect::<Result<Vec<_>, _>>()?;
|
|
983
|
-
|
|
984
|
-
prepared_generators.push(Comprehension {
|
|
985
|
-
target: preshadowed_target,
|
|
986
|
-
iter,
|
|
987
|
-
ifs,
|
|
988
|
-
});
|
|
989
|
-
}
|
|
990
|
-
|
|
991
|
-
// Prepare the element expression(s) - can see all loop variables
|
|
992
|
-
let prepared_elt = match elt {
|
|
993
|
-
Some(e) => Some(self.prepare_expression(e)?),
|
|
994
|
-
None => None,
|
|
995
|
-
};
|
|
996
|
-
let prepared_key_value = match key_value {
|
|
997
|
-
Some((k, v)) => Some((self.prepare_expression(k)?, self.prepare_expression(v)?)),
|
|
998
|
-
None => None,
|
|
999
|
-
};
|
|
1000
|
-
|
|
1001
|
-
// Restore scope state - loop variables do not leak to enclosing scope
|
|
1002
|
-
self.name_map = saved_name_map;
|
|
1003
|
-
self.names_assigned_in_order = saved_assigned_names;
|
|
1004
|
-
self.free_var_map = saved_free_var_map;
|
|
1005
|
-
self.cell_var_map = saved_cell_var_map;
|
|
1006
|
-
self.enclosing_locals = saved_enclosing_locals;
|
|
1007
|
-
self.unassigned_ref_names = saved_unassigned_ref_names;
|
|
1008
|
-
|
|
1009
|
-
Ok((prepared_generators, prepared_elt, prepared_key_value))
|
|
1010
|
-
}
|
|
1011
|
-
|
|
1012
|
-
/// Prepares an unpack target by resolving identifiers recursively.
|
|
1013
|
-
///
|
|
1014
|
-
/// Handles both single identifiers and nested tuples like `(a, b), c`.
|
|
1015
|
-
fn prepare_unpack_target(&mut self, target: UnpackTarget) -> UnpackTarget {
|
|
1016
|
-
match target {
|
|
1017
|
-
UnpackTarget::Name(ident) => {
|
|
1018
|
-
self.names_assigned_in_order
|
|
1019
|
-
.insert(self.interner.get_str(ident.name_id).to_string());
|
|
1020
|
-
UnpackTarget::Name(self.get_id(ident).0)
|
|
1021
|
-
}
|
|
1022
|
-
UnpackTarget::Starred(ident) => {
|
|
1023
|
-
self.names_assigned_in_order
|
|
1024
|
-
.insert(self.interner.get_str(ident.name_id).to_string());
|
|
1025
|
-
UnpackTarget::Starred(self.get_id(ident).0)
|
|
1026
|
-
}
|
|
1027
|
-
UnpackTarget::Tuple { targets, position } => {
|
|
1028
|
-
let resolved_targets: Vec<UnpackTarget> = targets
|
|
1029
|
-
.into_iter()
|
|
1030
|
-
.map(|t| self.prepare_unpack_target(t)) // Recursive call
|
|
1031
|
-
.collect();
|
|
1032
|
-
UnpackTarget::Tuple {
|
|
1033
|
-
targets: resolved_targets,
|
|
1034
|
-
position,
|
|
1035
|
-
}
|
|
1036
|
-
}
|
|
1037
|
-
}
|
|
1038
|
-
}
|
|
1039
|
-
|
|
1040
|
-
/// Prepares an unpack target for comprehension by allocating fresh namespace slots.
|
|
1041
|
-
///
|
|
1042
|
-
/// Unlike regular unpack targets, comprehension targets need new slots to shadow
|
|
1043
|
-
/// any existing bindings with the same name.
|
|
1044
|
-
fn prepare_unpack_target_for_comprehension(&mut self, target: UnpackTarget) -> UnpackTarget {
|
|
1045
|
-
match target {
|
|
1046
|
-
UnpackTarget::Name(ident) => {
|
|
1047
|
-
let name_str = self.interner.get_str(ident.name_id).to_string();
|
|
1048
|
-
let comp_var_id = NamespaceId::new(self.namespace_size);
|
|
1049
|
-
self.namespace_size += 1;
|
|
1050
|
-
|
|
1051
|
-
// Shadow any existing binding
|
|
1052
|
-
self.shadow_for_comprehension(&name_str, comp_var_id);
|
|
1053
|
-
|
|
1054
|
-
UnpackTarget::Name(Identifier::new_with_scope(
|
|
1055
|
-
ident.name_id,
|
|
1056
|
-
ident.position,
|
|
1057
|
-
comp_var_id,
|
|
1058
|
-
NameScope::Local,
|
|
1059
|
-
))
|
|
1060
|
-
}
|
|
1061
|
-
UnpackTarget::Starred(ident) => {
|
|
1062
|
-
let name_str = self.interner.get_str(ident.name_id).to_string();
|
|
1063
|
-
let comp_var_id = NamespaceId::new(self.namespace_size);
|
|
1064
|
-
self.namespace_size += 1;
|
|
1065
|
-
|
|
1066
|
-
// Shadow any existing binding
|
|
1067
|
-
self.shadow_for_comprehension(&name_str, comp_var_id);
|
|
1068
|
-
|
|
1069
|
-
UnpackTarget::Starred(Identifier::new_with_scope(
|
|
1070
|
-
ident.name_id,
|
|
1071
|
-
ident.position,
|
|
1072
|
-
comp_var_id,
|
|
1073
|
-
NameScope::Local,
|
|
1074
|
-
))
|
|
1075
|
-
}
|
|
1076
|
-
UnpackTarget::Tuple { targets, position } => {
|
|
1077
|
-
let resolved_targets: Vec<UnpackTarget> = targets
|
|
1078
|
-
.into_iter()
|
|
1079
|
-
.map(|t| self.prepare_unpack_target_for_comprehension(t)) // Recursive call
|
|
1080
|
-
.collect();
|
|
1081
|
-
UnpackTarget::Tuple {
|
|
1082
|
-
targets: resolved_targets,
|
|
1083
|
-
position,
|
|
1084
|
-
}
|
|
1085
|
-
}
|
|
1086
|
-
}
|
|
1087
|
-
}
|
|
1088
|
-
|
|
1089
|
-
/// Pre-shadows an unpack target for comprehension scoping.
|
|
1090
|
-
///
|
|
1091
|
-
/// Allocates namespace slots without marking as assigned, causing UnboundLocalError
|
|
1092
|
-
/// if accessed before assignment.
|
|
1093
|
-
fn prepare_unpack_target_shadow_only(&mut self, target: UnpackTarget) -> UnpackTarget {
|
|
1094
|
-
match target {
|
|
1095
|
-
UnpackTarget::Name(ident) => {
|
|
1096
|
-
let name_str = self.interner.get_str(ident.name_id).to_string();
|
|
1097
|
-
let comp_var_id = NamespaceId::new(self.namespace_size);
|
|
1098
|
-
self.namespace_size += 1;
|
|
1099
|
-
|
|
1100
|
-
// Shadow but do NOT add to names_assigned_in_order yet
|
|
1101
|
-
self.name_map.insert(name_str.clone(), comp_var_id);
|
|
1102
|
-
self.free_var_map.remove(&name_str);
|
|
1103
|
-
self.cell_var_map.remove(&name_str);
|
|
1104
|
-
if let Some(ref mut enclosing) = self.enclosing_locals {
|
|
1105
|
-
enclosing.remove(&name_str);
|
|
1106
|
-
}
|
|
1107
|
-
|
|
1108
|
-
UnpackTarget::Name(Identifier::new_with_scope(
|
|
1109
|
-
ident.name_id,
|
|
1110
|
-
ident.position,
|
|
1111
|
-
comp_var_id,
|
|
1112
|
-
NameScope::Local,
|
|
1113
|
-
))
|
|
1114
|
-
}
|
|
1115
|
-
UnpackTarget::Starred(ident) => {
|
|
1116
|
-
let name_str = self.interner.get_str(ident.name_id).to_string();
|
|
1117
|
-
let comp_var_id = NamespaceId::new(self.namespace_size);
|
|
1118
|
-
self.namespace_size += 1;
|
|
1119
|
-
|
|
1120
|
-
// Shadow but do NOT add to names_assigned_in_order yet
|
|
1121
|
-
self.name_map.insert(name_str.clone(), comp_var_id);
|
|
1122
|
-
self.free_var_map.remove(&name_str);
|
|
1123
|
-
self.cell_var_map.remove(&name_str);
|
|
1124
|
-
if let Some(ref mut enclosing) = self.enclosing_locals {
|
|
1125
|
-
enclosing.remove(&name_str);
|
|
1126
|
-
}
|
|
1127
|
-
|
|
1128
|
-
UnpackTarget::Starred(Identifier::new_with_scope(
|
|
1129
|
-
ident.name_id,
|
|
1130
|
-
ident.position,
|
|
1131
|
-
comp_var_id,
|
|
1132
|
-
NameScope::Local,
|
|
1133
|
-
))
|
|
1134
|
-
}
|
|
1135
|
-
UnpackTarget::Tuple { targets, position } => {
|
|
1136
|
-
let resolved_targets: Vec<UnpackTarget> = targets
|
|
1137
|
-
.into_iter()
|
|
1138
|
-
.map(|t| self.prepare_unpack_target_shadow_only(t)) // Recursive call
|
|
1139
|
-
.collect();
|
|
1140
|
-
UnpackTarget::Tuple {
|
|
1141
|
-
targets: resolved_targets,
|
|
1142
|
-
position,
|
|
1143
|
-
}
|
|
1144
|
-
}
|
|
1145
|
-
}
|
|
1146
|
-
}
|
|
1147
|
-
|
|
1148
|
-
/// Shadows a name in all scope maps for comprehension isolation.
|
|
1149
|
-
///
|
|
1150
|
-
/// This ensures the comprehension loop variable takes precedence over any
|
|
1151
|
-
/// variable with the same name from enclosing scopes.
|
|
1152
|
-
fn shadow_for_comprehension(&mut self, name_str: &str, comp_var_id: NamespaceId) {
|
|
1153
|
-
// The lookup order in get_id is: global_declarations, free_var_map, cell_var_map,
|
|
1154
|
-
// assigned_names, enclosing_locals, then name_map. So we must update/remove from all maps
|
|
1155
|
-
// checked before name_map to ensure the comprehension variable shadows any captured
|
|
1156
|
-
// variable with the same name.
|
|
1157
|
-
self.name_map.insert(name_str.to_string(), comp_var_id);
|
|
1158
|
-
self.names_assigned_in_order.insert(name_str.to_string());
|
|
1159
|
-
self.free_var_map.remove(name_str);
|
|
1160
|
-
self.cell_var_map.remove(name_str);
|
|
1161
|
-
// Also remove from enclosing_locals to prevent get_id from re-capturing the variable
|
|
1162
|
-
if let Some(ref mut enclosing) = self.enclosing_locals {
|
|
1163
|
-
enclosing.remove(name_str);
|
|
1164
|
-
}
|
|
1165
|
-
}
|
|
1166
|
-
|
|
1167
|
-
/// Prepares a function definition using a two-pass approach for correct scope resolution.
|
|
1168
|
-
///
|
|
1169
|
-
/// Pass 1: Scan the function body to collect:
|
|
1170
|
-
/// - Names declared as `global`
|
|
1171
|
-
/// - Names declared as `nonlocal`
|
|
1172
|
-
/// - Names that are assigned (these are local unless declared global/nonlocal)
|
|
1173
|
-
///
|
|
1174
|
-
/// Pass 2: Prepare the function body with the scope information from pass 1.
|
|
1175
|
-
///
|
|
1176
|
-
/// # Closure Analysis
|
|
1177
|
-
///
|
|
1178
|
-
/// When the nested function uses `nonlocal` declarations, those names must exist
|
|
1179
|
-
/// in an enclosing scope. The enclosing scope's variable becomes a cell_var
|
|
1180
|
-
/// (stored in a heap cell), and the nested function captures it as a free_var.
|
|
1181
|
-
fn prepare_function_def(
|
|
1182
|
-
&mut self,
|
|
1183
|
-
name: Identifier,
|
|
1184
|
-
parsed_sig: &ParsedSignature,
|
|
1185
|
-
body: Vec<ParseNode>,
|
|
1186
|
-
is_async: bool,
|
|
1187
|
-
) -> Result<PreparedNode, ParseError> {
|
|
1188
|
-
// Register the function name in the current scope
|
|
1189
|
-
let (name, _) = self.get_id(name);
|
|
1190
|
-
|
|
1191
|
-
// Extract param names from the parsed signature for scope analysis
|
|
1192
|
-
let param_names: Vec<StringId> = parsed_sig.param_names().collect();
|
|
1193
|
-
|
|
1194
|
-
// Pass 1: Collect scope information from the function body
|
|
1195
|
-
let scope_info = collect_function_scope_info(&body, ¶m_names, self.interner);
|
|
1196
|
-
|
|
1197
|
-
// Get the global name map to pass to the function preparer
|
|
1198
|
-
// At module level, use our own name_map; otherwise use the inherited global_name_map
|
|
1199
|
-
let global_name_map = if self.is_module_scope {
|
|
1200
|
-
self.name_map.clone()
|
|
1201
|
-
} else {
|
|
1202
|
-
self.global_name_map.clone().unwrap_or_default()
|
|
1203
|
-
};
|
|
1204
|
-
|
|
1205
|
-
// Build enclosing_locals: names that are local to this scope (including params)
|
|
1206
|
-
// These are available for `nonlocal` declarations in nested functions
|
|
1207
|
-
let enclosing_locals: AHashSet<String> = if self.is_module_scope {
|
|
1208
|
-
// At module level, there are no enclosing locals for nonlocal
|
|
1209
|
-
// (module-level variables are accessed via `global`, not `nonlocal`)
|
|
1210
|
-
AHashSet::new()
|
|
1211
|
-
} else {
|
|
1212
|
-
// In a function: our params + assigned_names + existing name_map keys
|
|
1213
|
-
// are all potentially available as enclosing locals
|
|
1214
|
-
let mut locals = self.assigned_names.clone();
|
|
1215
|
-
for key in self.name_map.keys() {
|
|
1216
|
-
locals.insert(key.clone());
|
|
1217
|
-
}
|
|
1218
|
-
locals
|
|
1219
|
-
};
|
|
1220
|
-
|
|
1221
|
-
// Filter potential_captures to get actual implicit captures.
|
|
1222
|
-
// Only names that are ALSO in enclosing_locals are true implicit captures.
|
|
1223
|
-
// Names NOT in enclosing_locals are either builtins or globals (handled at runtime).
|
|
1224
|
-
let implicit_captures: AHashSet<String> = scope_info
|
|
1225
|
-
.potential_captures
|
|
1226
|
-
.into_iter()
|
|
1227
|
-
.filter(|name| enclosing_locals.contains(name))
|
|
1228
|
-
.collect();
|
|
1229
|
-
|
|
1230
|
-
// Pass 2: Create child preparer for function body with scope info
|
|
1231
|
-
let mut inner_prepare = Prepare::new_function(
|
|
1232
|
-
body.len(),
|
|
1233
|
-
¶m_names,
|
|
1234
|
-
scope_info.assigned_names,
|
|
1235
|
-
scope_info.global_names,
|
|
1236
|
-
scope_info.nonlocal_names,
|
|
1237
|
-
implicit_captures,
|
|
1238
|
-
global_name_map,
|
|
1239
|
-
Some(enclosing_locals),
|
|
1240
|
-
scope_info.cell_var_names,
|
|
1241
|
-
self.interner,
|
|
1242
|
-
);
|
|
1243
|
-
|
|
1244
|
-
// Prepare the function body
|
|
1245
|
-
let prepared_body = inner_prepare.prepare_nodes(body)?;
|
|
1246
|
-
|
|
1247
|
-
// Mark variables that the inner function captures as our cell_vars
|
|
1248
|
-
// These are the names that appear in inner_prepare.free_var_map
|
|
1249
|
-
// Add to cell_var_map if not already present (may have been pre-populated or added earlier)
|
|
1250
|
-
for captured_name in inner_prepare.free_var_map.keys() {
|
|
1251
|
-
if !self.cell_var_map.contains_key(captured_name) && !self.free_var_map.contains_key(captured_name) {
|
|
1252
|
-
// Only add to cell_var_map if not already a free_var (pass-through case)
|
|
1253
|
-
// Allocate a namespace slot for the cell reference
|
|
1254
|
-
let slot = match self.name_map.entry(captured_name.clone()) {
|
|
1255
|
-
Entry::Occupied(e) => *e.get(),
|
|
1256
|
-
Entry::Vacant(e) => {
|
|
1257
|
-
let slot = NamespaceId::new(self.namespace_size);
|
|
1258
|
-
self.namespace_size += 1;
|
|
1259
|
-
e.insert(slot);
|
|
1260
|
-
slot
|
|
1261
|
-
}
|
|
1262
|
-
};
|
|
1263
|
-
self.cell_var_map.insert(captured_name.clone(), slot);
|
|
1264
|
-
}
|
|
1265
|
-
}
|
|
1266
|
-
|
|
1267
|
-
// Build free_var_enclosing_slots: enclosing namespace slots for captured variables
|
|
1268
|
-
// At call time, cells are pushed sequentially, so we only need the enclosing slots.
|
|
1269
|
-
// Sort by our slot index to ensure consistent ordering (matches namespace layout).
|
|
1270
|
-
let mut free_var_entries: Vec<_> = inner_prepare.free_var_map.into_iter().collect();
|
|
1271
|
-
free_var_entries.sort_by_key(|(_, our_slot)| *our_slot);
|
|
1272
|
-
|
|
1273
|
-
let free_var_enclosing_slots: Vec<NamespaceId> = free_var_entries
|
|
1274
|
-
.into_iter()
|
|
1275
|
-
.map(|(var_name, _our_slot)| {
|
|
1276
|
-
// Determine the namespace slot in the enclosing scope where the cell reference lives:
|
|
1277
|
-
// - If it's in cell_var_map, it's a cell we own (allocated in this scope)
|
|
1278
|
-
// - If it's in free_var_map, it's a cell we captured from further up
|
|
1279
|
-
// - Otherwise, this is a prepare-time bug
|
|
1280
|
-
if let Some(&slot) = self.cell_var_map.get(&var_name) {
|
|
1281
|
-
slot
|
|
1282
|
-
} else if let Some(&slot) = self.free_var_map.get(&var_name) {
|
|
1283
|
-
slot
|
|
1284
|
-
} else {
|
|
1285
|
-
panic!("free_var '{var_name}' not found in enclosing scope's cell_var_map or free_var_map");
|
|
1286
|
-
}
|
|
1287
|
-
})
|
|
1288
|
-
.collect();
|
|
1289
|
-
|
|
1290
|
-
// cell_var_count: number of cells to create at call time for variables captured by nested functions
|
|
1291
|
-
// Slots are implicitly params.len()..params.len()+cell_var_count in the namespace layout
|
|
1292
|
-
let cell_var_count = inner_prepare.cell_var_map.len();
|
|
1293
|
-
let namespace_size = inner_prepare.namespace_size;
|
|
1294
|
-
|
|
1295
|
-
// Build cell_param_indices: maps cell indices to parameter indices for captured parameters.
|
|
1296
|
-
// When a parameter is captured by a nested function, we need to copy its value into the cell.
|
|
1297
|
-
let cell_param_indices: Vec<Option<usize>> = if cell_var_count == 0 {
|
|
1298
|
-
Vec::new()
|
|
1299
|
-
} else {
|
|
1300
|
-
// Build a map from param name (String) to param index
|
|
1301
|
-
let param_name_to_index: AHashMap<String, usize> = param_names
|
|
1302
|
-
.iter()
|
|
1303
|
-
.enumerate()
|
|
1304
|
-
.map(|(idx, &name_id)| (self.interner.get_str(name_id).to_string(), idx))
|
|
1305
|
-
.collect();
|
|
1306
|
-
|
|
1307
|
-
// Sort cell_var_map entries by slot to get cells in order
|
|
1308
|
-
let mut cell_entries: Vec<_> = inner_prepare.cell_var_map.iter().collect();
|
|
1309
|
-
cell_entries.sort_by_key(|&(_, slot)| slot);
|
|
1310
|
-
|
|
1311
|
-
// For each cell (in slot order), check if it's a parameter
|
|
1312
|
-
cell_entries
|
|
1313
|
-
.into_iter()
|
|
1314
|
-
.map(|(name, _slot)| param_name_to_index.get(name).copied())
|
|
1315
|
-
.collect()
|
|
1316
|
-
};
|
|
1317
|
-
|
|
1318
|
-
// Build the runtime Signature from the parsed signature
|
|
1319
|
-
let pos_args: Vec<StringId> = parsed_sig.pos_args.iter().map(|p| p.name).collect();
|
|
1320
|
-
let pos_defaults_count = parsed_sig.pos_args.iter().filter(|p| p.default.is_some()).count();
|
|
1321
|
-
let args: Vec<StringId> = parsed_sig.args.iter().map(|p| p.name).collect();
|
|
1322
|
-
let arg_defaults_count = parsed_sig.args.iter().filter(|p| p.default.is_some()).count();
|
|
1323
|
-
let mut kwargs: Vec<StringId> = Vec::with_capacity(parsed_sig.kwargs.len());
|
|
1324
|
-
let mut kwarg_default_map: Vec<Option<usize>> = Vec::with_capacity(parsed_sig.kwargs.len());
|
|
1325
|
-
let mut kwarg_default_index = 0;
|
|
1326
|
-
for param in &parsed_sig.kwargs {
|
|
1327
|
-
kwargs.push(param.name);
|
|
1328
|
-
if param.default.is_some() {
|
|
1329
|
-
kwarg_default_map.push(Some(kwarg_default_index));
|
|
1330
|
-
kwarg_default_index += 1;
|
|
1331
|
-
} else {
|
|
1332
|
-
kwarg_default_map.push(None);
|
|
1333
|
-
}
|
|
1334
|
-
}
|
|
1335
|
-
|
|
1336
|
-
let signature = Signature::new(
|
|
1337
|
-
pos_args,
|
|
1338
|
-
pos_defaults_count,
|
|
1339
|
-
args,
|
|
1340
|
-
arg_defaults_count,
|
|
1341
|
-
parsed_sig.var_args,
|
|
1342
|
-
kwargs,
|
|
1343
|
-
kwarg_default_map,
|
|
1344
|
-
parsed_sig.var_kwargs,
|
|
1345
|
-
);
|
|
1346
|
-
|
|
1347
|
-
// Collect and prepare default expressions in order: pos_args -> args -> kwargs
|
|
1348
|
-
// Only includes parameters that actually have defaults.
|
|
1349
|
-
let mut default_exprs = Vec::with_capacity(signature.total_defaults_count());
|
|
1350
|
-
for param in &parsed_sig.pos_args {
|
|
1351
|
-
if let Some(ref expr) = param.default {
|
|
1352
|
-
default_exprs.push(self.prepare_expression(expr.clone())?);
|
|
1353
|
-
}
|
|
1354
|
-
}
|
|
1355
|
-
for param in &parsed_sig.args {
|
|
1356
|
-
if let Some(ref expr) = param.default {
|
|
1357
|
-
default_exprs.push(self.prepare_expression(expr.clone())?);
|
|
1358
|
-
}
|
|
1359
|
-
}
|
|
1360
|
-
for param in &parsed_sig.kwargs {
|
|
1361
|
-
if let Some(ref expr) = param.default {
|
|
1362
|
-
default_exprs.push(self.prepare_expression(expr.clone())?);
|
|
1363
|
-
}
|
|
1364
|
-
}
|
|
1365
|
-
|
|
1366
|
-
// Return the prepared function definition inline in the AST
|
|
1367
|
-
Ok(Node::FunctionDef(PreparedFunctionDef {
|
|
1368
|
-
name,
|
|
1369
|
-
signature,
|
|
1370
|
-
body: prepared_body,
|
|
1371
|
-
namespace_size,
|
|
1372
|
-
free_var_enclosing_slots,
|
|
1373
|
-
cell_var_count,
|
|
1374
|
-
cell_param_indices,
|
|
1375
|
-
default_exprs,
|
|
1376
|
-
is_async,
|
|
1377
|
-
}))
|
|
1378
|
-
}
|
|
1379
|
-
|
|
1380
|
-
/// Prepares a lambda expression, converting it into a prepared function definition.
|
|
1381
|
-
///
|
|
1382
|
-
/// Lambdas are essentially anonymous functions with an implicit return of their body
|
|
1383
|
-
/// expression. This method follows the same preparation logic as `prepare_function_def`
|
|
1384
|
-
/// but:
|
|
1385
|
-
/// - Uses `<lambda>` as the function name (not registered in scope)
|
|
1386
|
-
/// - Wraps the body expression as `Node::Return(body)`
|
|
1387
|
-
/// - Returns `ExprLoc` with `Expr::Lambda` instead of `PreparedNode`
|
|
1388
|
-
fn prepare_lambda(
|
|
1389
|
-
&mut self,
|
|
1390
|
-
lambda_name_id: StringId,
|
|
1391
|
-
parsed_sig: &ParsedSignature,
|
|
1392
|
-
body: &ExprLoc,
|
|
1393
|
-
position: CodeRange,
|
|
1394
|
-
) -> Result<ExprLoc, ParseError> {
|
|
1395
|
-
// Create a synthetic <lambda> name identifier (not registered in scope)
|
|
1396
|
-
let lambda_name = Identifier::new_with_scope(
|
|
1397
|
-
lambda_name_id,
|
|
1398
|
-
position,
|
|
1399
|
-
NamespaceId::new(0), // Placeholder, not actually used for storage
|
|
1400
|
-
NameScope::Local,
|
|
1401
|
-
);
|
|
1402
|
-
|
|
1403
|
-
// Wrap the body expression as a return statement for scope analysis
|
|
1404
|
-
let body_as_node: ParseNode = Node::Return(body.clone());
|
|
1405
|
-
let body_nodes = vec![body_as_node];
|
|
1406
|
-
|
|
1407
|
-
// Extract param names from the parsed signature for scope analysis
|
|
1408
|
-
let param_names: Vec<StringId> = parsed_sig.param_names().collect();
|
|
1409
|
-
|
|
1410
|
-
// Pass 1: Collect scope information from the lambda body
|
|
1411
|
-
// (Lambdas can't have global/nonlocal declarations, but can have nested functions)
|
|
1412
|
-
let scope_info = collect_function_scope_info(&body_nodes, ¶m_names, self.interner);
|
|
1413
|
-
|
|
1414
|
-
// Get the global name map to pass to the function preparer
|
|
1415
|
-
let global_name_map = if self.is_module_scope {
|
|
1416
|
-
self.name_map.clone()
|
|
1417
|
-
} else {
|
|
1418
|
-
self.global_name_map.clone().unwrap_or_default()
|
|
1419
|
-
};
|
|
1420
|
-
|
|
1421
|
-
// Build enclosing_locals: names that are local to this scope or captured from enclosing scope.
|
|
1422
|
-
// This includes free_vars so that nested lambdas can capture pass-through variables.
|
|
1423
|
-
let enclosing_locals: AHashSet<String> = if self.is_module_scope {
|
|
1424
|
-
AHashSet::new()
|
|
1425
|
-
} else {
|
|
1426
|
-
let mut locals = self.assigned_names.clone();
|
|
1427
|
-
for key in self.name_map.keys() {
|
|
1428
|
-
locals.insert(key.clone());
|
|
1429
|
-
}
|
|
1430
|
-
// Include free_vars so nested functions/lambdas can capture pass-through variables
|
|
1431
|
-
for key in self.free_var_map.keys() {
|
|
1432
|
-
locals.insert(key.clone());
|
|
1433
|
-
}
|
|
1434
|
-
locals
|
|
1435
|
-
};
|
|
1436
|
-
|
|
1437
|
-
// Filter potential_captures to get actual implicit captures
|
|
1438
|
-
let implicit_captures: AHashSet<String> = scope_info
|
|
1439
|
-
.potential_captures
|
|
1440
|
-
.into_iter()
|
|
1441
|
-
.filter(|name| enclosing_locals.contains(name))
|
|
1442
|
-
.collect();
|
|
1443
|
-
|
|
1444
|
-
// Pass 2: Create child preparer for lambda body with scope info
|
|
1445
|
-
let mut inner_prepare = Prepare::new_function(
|
|
1446
|
-
body_nodes.len(),
|
|
1447
|
-
¶m_names,
|
|
1448
|
-
scope_info.assigned_names,
|
|
1449
|
-
scope_info.global_names,
|
|
1450
|
-
scope_info.nonlocal_names,
|
|
1451
|
-
implicit_captures,
|
|
1452
|
-
global_name_map,
|
|
1453
|
-
Some(enclosing_locals),
|
|
1454
|
-
scope_info.cell_var_names,
|
|
1455
|
-
self.interner,
|
|
1456
|
-
);
|
|
1457
|
-
|
|
1458
|
-
// Prepare the lambda body
|
|
1459
|
-
let prepared_body = inner_prepare.prepare_nodes(body_nodes)?;
|
|
1460
|
-
|
|
1461
|
-
// Mark variables that the inner function captures as our cell_vars
|
|
1462
|
-
for captured_name in inner_prepare.free_var_map.keys() {
|
|
1463
|
-
if !self.cell_var_map.contains_key(captured_name) && !self.free_var_map.contains_key(captured_name) {
|
|
1464
|
-
let slot = match self.name_map.entry(captured_name.clone()) {
|
|
1465
|
-
Entry::Occupied(e) => *e.get(),
|
|
1466
|
-
Entry::Vacant(e) => {
|
|
1467
|
-
let slot = NamespaceId::new(self.namespace_size);
|
|
1468
|
-
self.namespace_size += 1;
|
|
1469
|
-
e.insert(slot);
|
|
1470
|
-
slot
|
|
1471
|
-
}
|
|
1472
|
-
};
|
|
1473
|
-
self.cell_var_map.insert(captured_name.clone(), slot);
|
|
1474
|
-
}
|
|
1475
|
-
}
|
|
1476
|
-
|
|
1477
|
-
// Build free_var_enclosing_slots
|
|
1478
|
-
let mut free_var_entries: Vec<_> = inner_prepare.free_var_map.into_iter().collect();
|
|
1479
|
-
free_var_entries.sort_by_key(|(_, our_slot)| *our_slot);
|
|
1480
|
-
|
|
1481
|
-
let free_var_enclosing_slots: Vec<NamespaceId> = free_var_entries
|
|
1482
|
-
.into_iter()
|
|
1483
|
-
.map(|(var_name, _our_slot)| {
|
|
1484
|
-
if let Some(&slot) = self.cell_var_map.get(&var_name) {
|
|
1485
|
-
slot
|
|
1486
|
-
} else if let Some(&slot) = self.free_var_map.get(&var_name) {
|
|
1487
|
-
slot
|
|
1488
|
-
} else {
|
|
1489
|
-
panic!("free_var '{var_name}' not found in enclosing scope's cell_var_map or free_var_map");
|
|
1490
|
-
}
|
|
1491
|
-
})
|
|
1492
|
-
.collect();
|
|
1493
|
-
|
|
1494
|
-
// Build cell_param_indices
|
|
1495
|
-
let cell_var_count = inner_prepare.cell_var_map.len();
|
|
1496
|
-
let namespace_size = inner_prepare.namespace_size;
|
|
1497
|
-
|
|
1498
|
-
let cell_param_indices: Vec<Option<usize>> = if cell_var_count == 0 {
|
|
1499
|
-
Vec::new()
|
|
1500
|
-
} else {
|
|
1501
|
-
let param_name_to_index: AHashMap<String, usize> = param_names
|
|
1502
|
-
.iter()
|
|
1503
|
-
.enumerate()
|
|
1504
|
-
.map(|(idx, &name_id)| (self.interner.get_str(name_id).to_string(), idx))
|
|
1505
|
-
.collect();
|
|
1506
|
-
|
|
1507
|
-
let mut cell_entries: Vec<_> = inner_prepare.cell_var_map.iter().collect();
|
|
1508
|
-
cell_entries.sort_by_key(|&(_, slot)| slot);
|
|
1509
|
-
|
|
1510
|
-
cell_entries
|
|
1511
|
-
.into_iter()
|
|
1512
|
-
.map(|(name, _slot)| param_name_to_index.get(name).copied())
|
|
1513
|
-
.collect()
|
|
1514
|
-
};
|
|
1515
|
-
|
|
1516
|
-
// Build the runtime Signature from the parsed signature
|
|
1517
|
-
let pos_args: Vec<StringId> = parsed_sig.pos_args.iter().map(|p| p.name).collect();
|
|
1518
|
-
let pos_defaults_count = parsed_sig.pos_args.iter().filter(|p| p.default.is_some()).count();
|
|
1519
|
-
let args: Vec<StringId> = parsed_sig.args.iter().map(|p| p.name).collect();
|
|
1520
|
-
let arg_defaults_count = parsed_sig.args.iter().filter(|p| p.default.is_some()).count();
|
|
1521
|
-
let mut kwargs: Vec<StringId> = Vec::with_capacity(parsed_sig.kwargs.len());
|
|
1522
|
-
let mut kwarg_default_map: Vec<Option<usize>> = Vec::with_capacity(parsed_sig.kwargs.len());
|
|
1523
|
-
let mut kwarg_default_index = 0;
|
|
1524
|
-
for param in &parsed_sig.kwargs {
|
|
1525
|
-
kwargs.push(param.name);
|
|
1526
|
-
if param.default.is_some() {
|
|
1527
|
-
kwarg_default_map.push(Some(kwarg_default_index));
|
|
1528
|
-
kwarg_default_index += 1;
|
|
1529
|
-
} else {
|
|
1530
|
-
kwarg_default_map.push(None);
|
|
1531
|
-
}
|
|
1532
|
-
}
|
|
1533
|
-
|
|
1534
|
-
let signature = Signature::new(
|
|
1535
|
-
pos_args,
|
|
1536
|
-
pos_defaults_count,
|
|
1537
|
-
args,
|
|
1538
|
-
arg_defaults_count,
|
|
1539
|
-
parsed_sig.var_args,
|
|
1540
|
-
kwargs,
|
|
1541
|
-
kwarg_default_map,
|
|
1542
|
-
parsed_sig.var_kwargs,
|
|
1543
|
-
);
|
|
1544
|
-
|
|
1545
|
-
// Collect and prepare default expressions (evaluated in enclosing scope)
|
|
1546
|
-
let mut default_exprs = Vec::with_capacity(signature.total_defaults_count());
|
|
1547
|
-
for param in &parsed_sig.pos_args {
|
|
1548
|
-
if let Some(ref expr) = param.default {
|
|
1549
|
-
default_exprs.push(self.prepare_expression(expr.clone())?);
|
|
1550
|
-
}
|
|
1551
|
-
}
|
|
1552
|
-
for param in &parsed_sig.args {
|
|
1553
|
-
if let Some(ref expr) = param.default {
|
|
1554
|
-
default_exprs.push(self.prepare_expression(expr.clone())?);
|
|
1555
|
-
}
|
|
1556
|
-
}
|
|
1557
|
-
for param in &parsed_sig.kwargs {
|
|
1558
|
-
if let Some(ref expr) = param.default {
|
|
1559
|
-
default_exprs.push(self.prepare_expression(expr.clone())?);
|
|
1560
|
-
}
|
|
1561
|
-
}
|
|
1562
|
-
|
|
1563
|
-
// Create the prepared function definition (lambdas are never async)
|
|
1564
|
-
let func_def = PreparedFunctionDef {
|
|
1565
|
-
name: lambda_name,
|
|
1566
|
-
signature,
|
|
1567
|
-
body: prepared_body,
|
|
1568
|
-
namespace_size,
|
|
1569
|
-
free_var_enclosing_slots,
|
|
1570
|
-
cell_var_count,
|
|
1571
|
-
cell_param_indices,
|
|
1572
|
-
default_exprs,
|
|
1573
|
-
is_async: false,
|
|
1574
|
-
};
|
|
1575
|
-
|
|
1576
|
-
Ok(ExprLoc::new(
|
|
1577
|
-
position,
|
|
1578
|
-
Expr::Lambda {
|
|
1579
|
-
func_def: Box::new(func_def),
|
|
1580
|
-
},
|
|
1581
|
-
))
|
|
1582
|
-
}
|
|
1583
|
-
|
|
1584
|
-
/// Resolves an identifier to its namespace index and scope, creating a new entry if needed.
|
|
1585
|
-
///
|
|
1586
|
-
/// TODO This whole implementation seems ugly at best.
|
|
1587
|
-
///
|
|
1588
|
-
/// This is the core name resolution mechanism with scope-aware resolution:
|
|
1589
|
-
///
|
|
1590
|
-
/// **At module level:** All names go to the local namespace (which IS the global namespace).
|
|
1591
|
-
///
|
|
1592
|
-
/// **In functions:**
|
|
1593
|
-
/// - If name is declared `global` → resolve to global namespace
|
|
1594
|
-
/// - If name is declared `nonlocal` → resolve to enclosing scope via Cell
|
|
1595
|
-
/// - If name is assigned in this function → resolve to local namespace
|
|
1596
|
-
/// - If name exists in global namespace (read-only access) → resolve to global namespace
|
|
1597
|
-
/// - Otherwise → resolve to local namespace (will be NameError at runtime)
|
|
1598
|
-
///
|
|
1599
|
-
/// # Returns
|
|
1600
|
-
/// A tuple of (resolved Identifier with id and scope set, whether this is a new local name).
|
|
1601
|
-
fn get_id(&mut self, ident: Identifier) -> (Identifier, bool) {
|
|
1602
|
-
let name_str = self.interner.get_str(ident.name_id);
|
|
1603
|
-
|
|
1604
|
-
// At module level, all names are local (which is also the global namespace).
|
|
1605
|
-
// The compiler emits global opcodes for these, so the VM reads/writes
|
|
1606
|
-
// directly from the globals array rather than the stack.
|
|
1607
|
-
if self.is_module_scope {
|
|
1608
|
-
return match self.name_map.entry(name_str.to_string()) {
|
|
1609
|
-
Entry::Occupied(e) => {
|
|
1610
|
-
// Name already exists (from prior reference or pre-registered).
|
|
1611
|
-
// Determine scope the same way as for vacant entries: if the name
|
|
1612
|
-
// has been assigned so far, it's a true local; otherwise it's an
|
|
1613
|
-
// unassigned reference that should yield NameLookup at runtime.
|
|
1614
|
-
let scope = if self.names_assigned_in_order.contains(name_str) {
|
|
1615
|
-
NameScope::Local
|
|
1616
|
-
} else {
|
|
1617
|
-
NameScope::LocalUnassigned
|
|
1618
|
-
};
|
|
1619
|
-
(
|
|
1620
|
-
Identifier::new_with_scope(ident.name_id, ident.position, *e.get(), scope),
|
|
1621
|
-
false,
|
|
1622
|
-
)
|
|
1623
|
-
}
|
|
1624
|
-
Entry::Vacant(e) => {
|
|
1625
|
-
let id = NamespaceId::new(self.namespace_size);
|
|
1626
|
-
self.namespace_size += 1;
|
|
1627
|
-
e.insert(id);
|
|
1628
|
-
// Determine scope: if the name is assigned somewhere (even later in the file),
|
|
1629
|
-
// it's a true local that will raise UnboundLocalError if accessed before assignment.
|
|
1630
|
-
// If the name is never assigned, it's an undefined reference that raises NameError.
|
|
1631
|
-
let scope = if self.names_assigned_in_order.contains(name_str) {
|
|
1632
|
-
NameScope::Local
|
|
1633
|
-
} else {
|
|
1634
|
-
NameScope::LocalUnassigned
|
|
1635
|
-
};
|
|
1636
|
-
(
|
|
1637
|
-
Identifier::new_with_scope(ident.name_id, ident.position, id, scope),
|
|
1638
|
-
true,
|
|
1639
|
-
)
|
|
1640
|
-
}
|
|
1641
|
-
};
|
|
1642
|
-
}
|
|
1643
|
-
|
|
1644
|
-
// In a function: determine scope based on global_names, nonlocal_names, assigned_names, global_name_map
|
|
1645
|
-
|
|
1646
|
-
// 1. Check if declared `global`
|
|
1647
|
-
if self.global_names.contains(name_str) {
|
|
1648
|
-
if let Some(ref global_map) = self.global_name_map
|
|
1649
|
-
&& let Some(&global_id) = global_map.get(name_str)
|
|
1650
|
-
{
|
|
1651
|
-
// Name exists in global namespace
|
|
1652
|
-
return (
|
|
1653
|
-
Identifier::new_with_scope(ident.name_id, ident.position, global_id, NameScope::Global),
|
|
1654
|
-
false,
|
|
1655
|
-
);
|
|
1656
|
-
}
|
|
1657
|
-
// Declared global but doesn't exist yet - it will be created when assigned
|
|
1658
|
-
// For now, we still need a global index. We'll use a placeholder approach:
|
|
1659
|
-
// allocate in global namespace (this is a simplification - in real Python,
|
|
1660
|
-
// the global would be created at module level when first assigned)
|
|
1661
|
-
// For our implementation, we'll resolve to global but the variable won't exist until assigned.
|
|
1662
|
-
// Return a "new" global - but we can't modify global_name_map here.
|
|
1663
|
-
// For simplicity, we'll resolve to local with Global scope - runtime will handle the lookup.
|
|
1664
|
-
let (id, is_new) = match self.name_map.entry(name_str.to_string()) {
|
|
1665
|
-
Entry::Occupied(e) => (*e.get(), false),
|
|
1666
|
-
Entry::Vacant(e) => {
|
|
1667
|
-
let id = NamespaceId::new(self.namespace_size);
|
|
1668
|
-
self.namespace_size += 1;
|
|
1669
|
-
e.insert(id);
|
|
1670
|
-
(id, true)
|
|
1671
|
-
}
|
|
1672
|
-
};
|
|
1673
|
-
// Mark as Global scope - runtime will need to handle this specially
|
|
1674
|
-
return (
|
|
1675
|
-
Identifier::new_with_scope(ident.name_id, ident.position, id, NameScope::Global),
|
|
1676
|
-
is_new,
|
|
1677
|
-
);
|
|
1678
|
-
}
|
|
1679
|
-
|
|
1680
|
-
// 2. Check if captured from enclosing scope (nonlocal declaration or implicit capture)
|
|
1681
|
-
// free_var_map stores namespace slot indices where the cell reference will be stored
|
|
1682
|
-
if let Some(&slot) = self.free_var_map.get(name_str) {
|
|
1683
|
-
// At runtime, the cell reference is in namespace[slot] as Value::Ref(cell_id)
|
|
1684
|
-
return (
|
|
1685
|
-
Identifier::new_with_scope(ident.name_id, ident.position, slot, NameScope::Cell),
|
|
1686
|
-
false, // Not a new local - it's captured from enclosing scope
|
|
1687
|
-
);
|
|
1688
|
-
}
|
|
1689
|
-
|
|
1690
|
-
// 3. Check if this is a cell variable (captured by nested functions)
|
|
1691
|
-
// cell_var_map stores namespace slot indices where the cell reference will be stored
|
|
1692
|
-
// At call time, a cell is created and stored as Value::Ref(cell_id) at this slot
|
|
1693
|
-
if let Some(&slot) = self.cell_var_map.get(name_str) {
|
|
1694
|
-
// The namespace slot was already allocated when cell_var_map was populated
|
|
1695
|
-
return (
|
|
1696
|
-
Identifier::new_with_scope(ident.name_id, ident.position, slot, NameScope::Cell),
|
|
1697
|
-
false, // Not a "new" local - it's a cell variable
|
|
1698
|
-
);
|
|
1699
|
-
}
|
|
1700
|
-
|
|
1701
|
-
// 4. Check if assigned in this function (local variable)
|
|
1702
|
-
if self.assigned_names.contains(name_str) {
|
|
1703
|
-
let (id, is_new) = match self.name_map.entry(name_str.to_string()) {
|
|
1704
|
-
Entry::Occupied(e) => (*e.get(), false),
|
|
1705
|
-
Entry::Vacant(e) => {
|
|
1706
|
-
let id = NamespaceId::new(self.namespace_size);
|
|
1707
|
-
self.namespace_size += 1;
|
|
1708
|
-
e.insert(id);
|
|
1709
|
-
(id, true)
|
|
1710
|
-
}
|
|
1711
|
-
};
|
|
1712
|
-
return (
|
|
1713
|
-
Identifier::new_with_scope(ident.name_id, ident.position, id, NameScope::Local),
|
|
1714
|
-
is_new,
|
|
1715
|
-
);
|
|
1716
|
-
}
|
|
1717
|
-
|
|
1718
|
-
// 5. Check if name was pre-populated in name_map (from function parameters)
|
|
1719
|
-
// This ensures parameters shadow both enclosing locals and global variables
|
|
1720
|
-
// with the same name. Parameters are added to name_map during
|
|
1721
|
-
// FunctionScope::new_function() but are NOT in assigned_names (since they're
|
|
1722
|
-
// not assigned in the function body). This MUST be checked before
|
|
1723
|
-
// enclosing_locals, otherwise a parameter like `def inner(x)` would be
|
|
1724
|
-
// incorrectly resolved as a closure capture when an outer scope also has `x`.
|
|
1725
|
-
// Excludes names tracked in `unassigned_ref_names` — those were added to
|
|
1726
|
-
// `name_map` by step 8 as `LocalUnassigned` references and must stay that way
|
|
1727
|
-
// to trigger NameLookup at runtime (e.g., for external function resolution).
|
|
1728
|
-
if !self.unassigned_ref_names.contains(name_str)
|
|
1729
|
-
&& let Some(&id) = self.name_map.get(name_str)
|
|
1730
|
-
{
|
|
1731
|
-
return (
|
|
1732
|
-
Identifier::new_with_scope(ident.name_id, ident.position, id, NameScope::Local),
|
|
1733
|
-
false, // Not new - was pre-populated from parameters
|
|
1734
|
-
);
|
|
1735
|
-
}
|
|
1736
|
-
|
|
1737
|
-
// 6. Check if exists in enclosing scope (implicit closure capture)
|
|
1738
|
-
// This handles reading variables from enclosing functions without explicit `nonlocal`
|
|
1739
|
-
if let Some(ref enclosing) = self.enclosing_locals
|
|
1740
|
-
&& enclosing.contains(name_str)
|
|
1741
|
-
{
|
|
1742
|
-
// This is an implicit capture - add to free_var_map with a namespace slot
|
|
1743
|
-
let slot = if let Some(&existing_slot) = self.free_var_map.get(name_str) {
|
|
1744
|
-
existing_slot
|
|
1745
|
-
} else {
|
|
1746
|
-
// Allocate a namespace slot for this free variable
|
|
1747
|
-
let slot = NamespaceId::new(self.namespace_size);
|
|
1748
|
-
self.namespace_size += 1;
|
|
1749
|
-
self.name_map.insert(name_str.to_string(), slot);
|
|
1750
|
-
self.free_var_map.insert(name_str.to_string(), slot);
|
|
1751
|
-
slot
|
|
1752
|
-
};
|
|
1753
|
-
return (
|
|
1754
|
-
Identifier::new_with_scope(ident.name_id, ident.position, slot, NameScope::Cell),
|
|
1755
|
-
false, // Not a new local - it's captured from enclosing scope
|
|
1756
|
-
);
|
|
1757
|
-
}
|
|
1758
|
-
|
|
1759
|
-
// 7. Check if exists in global namespace (implicit global read)
|
|
1760
|
-
if let Some(ref global_map) = self.global_name_map
|
|
1761
|
-
&& let Some(&global_id) = global_map.get(name_str)
|
|
1762
|
-
{
|
|
1763
|
-
return (
|
|
1764
|
-
Identifier::new_with_scope(ident.name_id, ident.position, global_id, NameScope::Global),
|
|
1765
|
-
false,
|
|
1766
|
-
);
|
|
1767
|
-
}
|
|
1768
|
-
|
|
1769
|
-
// 8. Name not found anywhere - allocate a local slot (will be NameError at runtime)
|
|
1770
|
-
// This handles names that are only read (never assigned) and don't exist globally.
|
|
1771
|
-
// We allocate a local slot that will never be written to.
|
|
1772
|
-
// Mark as LocalUnassigned so runtime raises NameError (not UnboundLocalError).
|
|
1773
|
-
// Track in `unassigned_ref_names` so step 6 doesn't treat subsequent references
|
|
1774
|
-
// as `Local` (parameters).
|
|
1775
|
-
self.unassigned_ref_names.insert(name_str.to_string());
|
|
1776
|
-
let (id, is_new) = match self.name_map.entry(name_str.to_string()) {
|
|
1777
|
-
Entry::Occupied(e) => (*e.get(), false),
|
|
1778
|
-
Entry::Vacant(e) => {
|
|
1779
|
-
let id = NamespaceId::new(self.namespace_size);
|
|
1780
|
-
self.namespace_size += 1;
|
|
1781
|
-
e.insert(id);
|
|
1782
|
-
(id, true)
|
|
1783
|
-
}
|
|
1784
|
-
};
|
|
1785
|
-
(
|
|
1786
|
-
Identifier::new_with_scope(ident.name_id, ident.position, id, NameScope::LocalUnassigned),
|
|
1787
|
-
is_new,
|
|
1788
|
-
)
|
|
1789
|
-
}
|
|
1790
|
-
|
|
1791
|
-
/// Prepares an f-string part by resolving names in interpolated expressions.
|
|
1792
|
-
fn prepare_fstring_part(&mut self, part: FStringPart) -> Result<FStringPart, ParseError> {
|
|
1793
|
-
match part {
|
|
1794
|
-
FStringPart::Literal(s) => Ok(FStringPart::Literal(s)),
|
|
1795
|
-
FStringPart::Interpolation {
|
|
1796
|
-
expr,
|
|
1797
|
-
conversion,
|
|
1798
|
-
format_spec,
|
|
1799
|
-
debug_prefix,
|
|
1800
|
-
} => {
|
|
1801
|
-
let prepared_expr = Box::new(self.prepare_expression(*expr)?);
|
|
1802
|
-
let prepared_spec = match format_spec {
|
|
1803
|
-
Some(FormatSpec::Static(s)) => Some(FormatSpec::Static(s)),
|
|
1804
|
-
Some(FormatSpec::Dynamic(parts)) => {
|
|
1805
|
-
let prepared = parts
|
|
1806
|
-
.into_iter()
|
|
1807
|
-
.map(|p| self.prepare_fstring_part(p))
|
|
1808
|
-
.collect::<Result<Vec<_>, _>>()?;
|
|
1809
|
-
Some(FormatSpec::Dynamic(prepared))
|
|
1810
|
-
}
|
|
1811
|
-
None => None,
|
|
1812
|
-
};
|
|
1813
|
-
Ok(FStringPart::Interpolation {
|
|
1814
|
-
expr: prepared_expr,
|
|
1815
|
-
conversion,
|
|
1816
|
-
format_spec: prepared_spec,
|
|
1817
|
-
debug_prefix,
|
|
1818
|
-
})
|
|
1819
|
-
}
|
|
1820
|
-
}
|
|
1821
|
-
}
|
|
1822
|
-
}
|
|
1823
|
-
|
|
1824
|
-
/// Information collected from first-pass scan of a function body.
|
|
1825
|
-
///
|
|
1826
|
-
/// This struct holds the scope-related information needed for the second pass
|
|
1827
|
-
/// of function preparation and for closure analysis.
|
|
1828
|
-
struct FunctionScopeInfo {
|
|
1829
|
-
/// Names declared as `global`
|
|
1830
|
-
global_names: AHashSet<String>,
|
|
1831
|
-
/// Names declared as `nonlocal`
|
|
1832
|
-
nonlocal_names: AHashSet<String>,
|
|
1833
|
-
/// Names that are assigned in this scope
|
|
1834
|
-
assigned_names: AHashSet<String>,
|
|
1835
|
-
/// Names that are captured by nested functions (must be stored in cells)
|
|
1836
|
-
cell_var_names: AHashSet<String>,
|
|
1837
|
-
/// Names that are referenced but not local, global, or nonlocal.
|
|
1838
|
-
/// These are POTENTIAL implicit captures - they may be captures from an enclosing function
|
|
1839
|
-
/// OR they may be builtin/global reads. The actual implicit captures are determined
|
|
1840
|
-
/// by filtering against enclosing_locals in new_function.
|
|
1841
|
-
potential_captures: AHashSet<String>,
|
|
1842
|
-
}
|
|
1843
|
-
|
|
1844
|
-
/// Scans a function body to collect scope information (first phase of preparation).
|
|
1845
|
-
///
|
|
1846
|
-
/// This function performs three passes over the AST:
|
|
1847
|
-
/// 1. Collect global, nonlocal, and assigned names
|
|
1848
|
-
/// 2. Identify cell_vars (names captured by nested functions)
|
|
1849
|
-
/// 3. Collect potential implicit captures (referenced but not local/global/nonlocal)
|
|
1850
|
-
///
|
|
1851
|
-
/// The collected information includes:
|
|
1852
|
-
/// - Names declared as `global` (from Global statements)
|
|
1853
|
-
/// - Names declared as `nonlocal` (from Nonlocal statements)
|
|
1854
|
-
/// - Names that are assigned (from Assign, OpAssign, For targets, etc.)
|
|
1855
|
-
/// - Names that are captured by nested functions (cell_var_names)
|
|
1856
|
-
/// - Names that might be captured from enclosing scope (potential_captures)
|
|
1857
|
-
///
|
|
1858
|
-
/// This information is used to determine whether each name reference should resolve
|
|
1859
|
-
/// to the local namespace, global namespace, or an enclosing scope via cells.
|
|
1860
|
-
fn collect_function_scope_info(
|
|
1861
|
-
nodes: &[ParseNode],
|
|
1862
|
-
params: &[StringId],
|
|
1863
|
-
interner: &InternerBuilder,
|
|
1864
|
-
) -> FunctionScopeInfo {
|
|
1865
|
-
let mut global_names = AHashSet::new();
|
|
1866
|
-
let mut nonlocal_names = AHashSet::new();
|
|
1867
|
-
let mut assigned_names = AHashSet::new();
|
|
1868
|
-
let mut cell_var_names = AHashSet::new();
|
|
1869
|
-
let mut referenced_names = AHashSet::new();
|
|
1870
|
-
|
|
1871
|
-
// First pass: collect global, nonlocal, and assigned names
|
|
1872
|
-
for node in nodes {
|
|
1873
|
-
collect_scope_info_from_node(
|
|
1874
|
-
node,
|
|
1875
|
-
&mut global_names,
|
|
1876
|
-
&mut nonlocal_names,
|
|
1877
|
-
&mut assigned_names,
|
|
1878
|
-
interner,
|
|
1879
|
-
);
|
|
1880
|
-
}
|
|
1881
|
-
|
|
1882
|
-
// Build the set of our locals: params + assigned_names (excluding globals)
|
|
1883
|
-
let param_names: AHashSet<String> = params
|
|
1884
|
-
.iter()
|
|
1885
|
-
.map(|string_id| interner.get_str(*string_id).to_string())
|
|
1886
|
-
.collect();
|
|
1887
|
-
|
|
1888
|
-
let our_locals: AHashSet<String> = param_names
|
|
1889
|
-
.iter()
|
|
1890
|
-
.cloned()
|
|
1891
|
-
.chain(assigned_names.iter().cloned())
|
|
1892
|
-
.filter(|name| !global_names.contains(name))
|
|
1893
|
-
.collect();
|
|
1894
|
-
|
|
1895
|
-
// Second pass: find what nested functions capture from us
|
|
1896
|
-
for node in nodes {
|
|
1897
|
-
collect_cell_vars_from_node(node, &our_locals, &mut cell_var_names, interner);
|
|
1898
|
-
}
|
|
1899
|
-
|
|
1900
|
-
// Third pass: collect all referenced names to identify potential implicit captures.
|
|
1901
|
-
// These are names that might be captured from an enclosing function scope.
|
|
1902
|
-
// We can't fully determine implicit captures here because we don't know yet what
|
|
1903
|
-
// the enclosing scope's locals are - that's determined later when we call new_function.
|
|
1904
|
-
for node in nodes {
|
|
1905
|
-
collect_referenced_names_from_node(node, &mut referenced_names, interner);
|
|
1906
|
-
}
|
|
1907
|
-
|
|
1908
|
-
// Potential implicit captures are names that are:
|
|
1909
|
-
// - Referenced in the function body
|
|
1910
|
-
// - Not local (not params, not assigned)
|
|
1911
|
-
// - Not declared global
|
|
1912
|
-
// - Not declared nonlocal (those are handled separately)
|
|
1913
|
-
// The actual implicit captures will be filtered against enclosing_locals in new_function.
|
|
1914
|
-
let potential_captures: AHashSet<String> = referenced_names
|
|
1915
|
-
.into_iter()
|
|
1916
|
-
.filter(|name| !our_locals.contains(name) && !global_names.contains(name) && !nonlocal_names.contains(name))
|
|
1917
|
-
.collect();
|
|
1918
|
-
|
|
1919
|
-
FunctionScopeInfo {
|
|
1920
|
-
global_names,
|
|
1921
|
-
nonlocal_names,
|
|
1922
|
-
assigned_names,
|
|
1923
|
-
cell_var_names,
|
|
1924
|
-
potential_captures,
|
|
1925
|
-
}
|
|
1926
|
-
}
|
|
1927
|
-
|
|
1928
|
-
/// Helper to collect scope info from a single node.
|
|
1929
|
-
fn collect_scope_info_from_node(
|
|
1930
|
-
node: &ParseNode,
|
|
1931
|
-
global_names: &mut AHashSet<String>,
|
|
1932
|
-
nonlocal_names: &mut AHashSet<String>,
|
|
1933
|
-
assigned_names: &mut AHashSet<String>,
|
|
1934
|
-
interner: &InternerBuilder,
|
|
1935
|
-
) {
|
|
1936
|
-
match node {
|
|
1937
|
-
Node::Global { names, .. } => {
|
|
1938
|
-
for string_id in names {
|
|
1939
|
-
global_names.insert(interner.get_str(*string_id).to_string());
|
|
1940
|
-
}
|
|
1941
|
-
}
|
|
1942
|
-
Node::Nonlocal { names, .. } => {
|
|
1943
|
-
for string_id in names {
|
|
1944
|
-
nonlocal_names.insert(interner.get_str(*string_id).to_string());
|
|
1945
|
-
}
|
|
1946
|
-
}
|
|
1947
|
-
Node::Assign { target, object } => {
|
|
1948
|
-
assigned_names.insert(interner.get_str(target.name_id).to_string());
|
|
1949
|
-
// Scan value expression for walrus operators
|
|
1950
|
-
collect_assigned_names_from_expr(object, assigned_names, interner);
|
|
1951
|
-
}
|
|
1952
|
-
Node::UnpackAssign { targets, object, .. } => {
|
|
1953
|
-
// Recursively collect all names from nested unpack targets
|
|
1954
|
-
for target in targets {
|
|
1955
|
-
collect_names_from_unpack_target(target, assigned_names, interner);
|
|
1956
|
-
}
|
|
1957
|
-
// Scan value expression for walrus operators
|
|
1958
|
-
collect_assigned_names_from_expr(object, assigned_names, interner);
|
|
1959
|
-
}
|
|
1960
|
-
Node::OpAssign { target, object, .. } => {
|
|
1961
|
-
assigned_names.insert(interner.get_str(target.name_id).to_string());
|
|
1962
|
-
// Scan value expression for walrus operators
|
|
1963
|
-
collect_assigned_names_from_expr(object, assigned_names, interner);
|
|
1964
|
-
}
|
|
1965
|
-
Node::SubscriptOpAssign { index, object, .. } => {
|
|
1966
|
-
collect_assigned_names_from_expr(index, assigned_names, interner);
|
|
1967
|
-
collect_assigned_names_from_expr(object, assigned_names, interner);
|
|
1968
|
-
}
|
|
1969
|
-
Node::SubscriptAssign { index, value, .. } => {
|
|
1970
|
-
// Subscript assignment doesn't create a new name, it modifies existing container
|
|
1971
|
-
// But scan expressions for walrus operators
|
|
1972
|
-
collect_assigned_names_from_expr(index, assigned_names, interner);
|
|
1973
|
-
collect_assigned_names_from_expr(value, assigned_names, interner);
|
|
1974
|
-
}
|
|
1975
|
-
Node::AttrAssign { object, value, .. } => {
|
|
1976
|
-
// Attribute assignment doesn't create a new name, it modifies existing object
|
|
1977
|
-
// But scan expressions for walrus operators
|
|
1978
|
-
collect_assigned_names_from_expr(object, assigned_names, interner);
|
|
1979
|
-
collect_assigned_names_from_expr(value, assigned_names, interner);
|
|
1980
|
-
}
|
|
1981
|
-
Node::For {
|
|
1982
|
-
target,
|
|
1983
|
-
iter,
|
|
1984
|
-
body,
|
|
1985
|
-
or_else,
|
|
1986
|
-
} => {
|
|
1987
|
-
// For loop target is assigned - collect all names from the target
|
|
1988
|
-
collect_names_from_unpack_target(target, assigned_names, interner);
|
|
1989
|
-
// Scan iter expression for walrus operators
|
|
1990
|
-
collect_assigned_names_from_expr(iter, assigned_names, interner);
|
|
1991
|
-
// Recurse into body and else
|
|
1992
|
-
for n in body {
|
|
1993
|
-
collect_scope_info_from_node(n, global_names, nonlocal_names, assigned_names, interner);
|
|
1994
|
-
}
|
|
1995
|
-
for n in or_else {
|
|
1996
|
-
collect_scope_info_from_node(n, global_names, nonlocal_names, assigned_names, interner);
|
|
1997
|
-
}
|
|
1998
|
-
}
|
|
1999
|
-
Node::While { test, body, or_else } => {
|
|
2000
|
-
// Scan test expression for walrus operators
|
|
2001
|
-
collect_assigned_names_from_expr(test, assigned_names, interner);
|
|
2002
|
-
// Recurse into body and else blocks
|
|
2003
|
-
for n in body {
|
|
2004
|
-
collect_scope_info_from_node(n, global_names, nonlocal_names, assigned_names, interner);
|
|
2005
|
-
}
|
|
2006
|
-
for n in or_else {
|
|
2007
|
-
collect_scope_info_from_node(n, global_names, nonlocal_names, assigned_names, interner);
|
|
2008
|
-
}
|
|
2009
|
-
}
|
|
2010
|
-
Node::If { test, body, or_else } => {
|
|
2011
|
-
// Scan test expression for walrus operators
|
|
2012
|
-
collect_assigned_names_from_expr(test, assigned_names, interner);
|
|
2013
|
-
// Recurse into branches
|
|
2014
|
-
for n in body {
|
|
2015
|
-
collect_scope_info_from_node(n, global_names, nonlocal_names, assigned_names, interner);
|
|
2016
|
-
}
|
|
2017
|
-
for n in or_else {
|
|
2018
|
-
collect_scope_info_from_node(n, global_names, nonlocal_names, assigned_names, interner);
|
|
2019
|
-
}
|
|
2020
|
-
}
|
|
2021
|
-
Node::FunctionDef(RawFunctionDef { name, .. }) => {
|
|
2022
|
-
// Function definition creates a local binding for the function name
|
|
2023
|
-
// But we don't recurse into the function body - that's a separate scope
|
|
2024
|
-
assigned_names.insert(interner.get_str(name.name_id).to_string());
|
|
2025
|
-
}
|
|
2026
|
-
Node::Try(Try {
|
|
2027
|
-
body,
|
|
2028
|
-
handlers,
|
|
2029
|
-
or_else,
|
|
2030
|
-
finally,
|
|
2031
|
-
}) => {
|
|
2032
|
-
// Recurse into all blocks
|
|
2033
|
-
for n in body {
|
|
2034
|
-
collect_scope_info_from_node(n, global_names, nonlocal_names, assigned_names, interner);
|
|
2035
|
-
}
|
|
2036
|
-
for handler in handlers {
|
|
2037
|
-
// Exception variable name is assigned
|
|
2038
|
-
if let Some(ref name) = handler.name {
|
|
2039
|
-
assigned_names.insert(interner.get_str(name.name_id).to_string());
|
|
2040
|
-
}
|
|
2041
|
-
for n in &handler.body {
|
|
2042
|
-
collect_scope_info_from_node(n, global_names, nonlocal_names, assigned_names, interner);
|
|
2043
|
-
}
|
|
2044
|
-
}
|
|
2045
|
-
for n in or_else {
|
|
2046
|
-
collect_scope_info_from_node(n, global_names, nonlocal_names, assigned_names, interner);
|
|
2047
|
-
}
|
|
2048
|
-
for n in finally {
|
|
2049
|
-
collect_scope_info_from_node(n, global_names, nonlocal_names, assigned_names, interner);
|
|
2050
|
-
}
|
|
2051
|
-
}
|
|
2052
|
-
// Import creates a binding for the module name (or alias)
|
|
2053
|
-
Node::Import { binding, .. } => {
|
|
2054
|
-
assigned_names.insert(interner.get_str(binding.name_id).to_string());
|
|
2055
|
-
}
|
|
2056
|
-
// ImportFrom creates bindings for each imported name (or alias)
|
|
2057
|
-
Node::ImportFrom { names, .. } => {
|
|
2058
|
-
for (_import_name, binding) in names {
|
|
2059
|
-
assigned_names.insert(interner.get_str(binding.name_id).to_string());
|
|
2060
|
-
}
|
|
2061
|
-
}
|
|
2062
|
-
// Statements with expressions that may contain walrus operators
|
|
2063
|
-
Node::Expr(expr) | Node::Return(expr) => {
|
|
2064
|
-
collect_assigned_names_from_expr(expr, assigned_names, interner);
|
|
2065
|
-
}
|
|
2066
|
-
Node::Raise(Some(expr)) => {
|
|
2067
|
-
collect_assigned_names_from_expr(expr, assigned_names, interner);
|
|
2068
|
-
}
|
|
2069
|
-
Node::Assert { test, msg } => {
|
|
2070
|
-
collect_assigned_names_from_expr(test, assigned_names, interner);
|
|
2071
|
-
if let Some(m) = msg {
|
|
2072
|
-
collect_assigned_names_from_expr(m, assigned_names, interner);
|
|
2073
|
-
}
|
|
2074
|
-
}
|
|
2075
|
-
// These don't create new names
|
|
2076
|
-
Node::Pass | Node::ReturnNone | Node::Raise(None) | Node::Break { .. } | Node::Continue { .. } => {}
|
|
2077
|
-
}
|
|
2078
|
-
}
|
|
2079
|
-
|
|
2080
|
-
/// Collects names assigned by walrus operators (`:=`) within an expression.
|
|
2081
|
-
///
|
|
2082
|
-
/// Per PEP 572, walrus operator targets are assignments in the enclosing scope.
|
|
2083
|
-
/// This function recursively scans expressions to find all `Named` expression targets.
|
|
2084
|
-
/// It does NOT recurse into lambda bodies as those have their own scope.
|
|
2085
|
-
fn collect_assigned_names_from_expr(expr: &ExprLoc, assigned_names: &mut AHashSet<String>, interner: &InternerBuilder) {
|
|
2086
|
-
match &expr.expr {
|
|
2087
|
-
Expr::Named { target, value } => {
|
|
2088
|
-
// The target of a walrus operator is assigned in this scope
|
|
2089
|
-
assigned_names.insert(interner.get_str(target.name_id).to_string());
|
|
2090
|
-
// Also scan the value expression
|
|
2091
|
-
collect_assigned_names_from_expr(value, assigned_names, interner);
|
|
2092
|
-
}
|
|
2093
|
-
// Recurse into sub-expressions
|
|
2094
|
-
Expr::List(items) | Expr::Tuple(items) | Expr::Set(items) => {
|
|
2095
|
-
for item in items {
|
|
2096
|
-
let expr = match item {
|
|
2097
|
-
SequenceItem::Value(e) | SequenceItem::Unpack(e) => e,
|
|
2098
|
-
};
|
|
2099
|
-
collect_assigned_names_from_expr(expr, assigned_names, interner);
|
|
2100
|
-
}
|
|
2101
|
-
}
|
|
2102
|
-
Expr::Dict(dict_items) => {
|
|
2103
|
-
for item in dict_items {
|
|
2104
|
-
match item {
|
|
2105
|
-
DictItem::Pair(key, value) => {
|
|
2106
|
-
collect_assigned_names_from_expr(key, assigned_names, interner);
|
|
2107
|
-
collect_assigned_names_from_expr(value, assigned_names, interner);
|
|
2108
|
-
}
|
|
2109
|
-
DictItem::Unpack(e) => collect_assigned_names_from_expr(e, assigned_names, interner),
|
|
2110
|
-
}
|
|
2111
|
-
}
|
|
2112
|
-
}
|
|
2113
|
-
Expr::Op { left, right, .. } | Expr::CmpOp { left, right, .. } => {
|
|
2114
|
-
collect_assigned_names_from_expr(left, assigned_names, interner);
|
|
2115
|
-
collect_assigned_names_from_expr(right, assigned_names, interner);
|
|
2116
|
-
}
|
|
2117
|
-
Expr::ChainCmp { left, comparisons } => {
|
|
2118
|
-
collect_assigned_names_from_expr(left, assigned_names, interner);
|
|
2119
|
-
for (_, expr) in comparisons {
|
|
2120
|
-
collect_assigned_names_from_expr(expr, assigned_names, interner);
|
|
2121
|
-
}
|
|
2122
|
-
}
|
|
2123
|
-
Expr::Not(operand)
|
|
2124
|
-
| Expr::UnaryMinus(operand)
|
|
2125
|
-
| Expr::UnaryPlus(operand)
|
|
2126
|
-
| Expr::UnaryInvert(operand)
|
|
2127
|
-
| Expr::Await(operand) => {
|
|
2128
|
-
collect_assigned_names_from_expr(operand, assigned_names, interner);
|
|
2129
|
-
}
|
|
2130
|
-
Expr::Subscript { object, index } => {
|
|
2131
|
-
collect_assigned_names_from_expr(object, assigned_names, interner);
|
|
2132
|
-
collect_assigned_names_from_expr(index, assigned_names, interner);
|
|
2133
|
-
}
|
|
2134
|
-
Expr::Call { args, .. } => {
|
|
2135
|
-
collect_assigned_names_from_args(args, assigned_names, interner);
|
|
2136
|
-
}
|
|
2137
|
-
Expr::AttrCall { object, args, .. } => {
|
|
2138
|
-
collect_assigned_names_from_expr(object, assigned_names, interner);
|
|
2139
|
-
collect_assigned_names_from_args(args, assigned_names, interner);
|
|
2140
|
-
}
|
|
2141
|
-
Expr::IndirectCall { callable, args } => {
|
|
2142
|
-
collect_assigned_names_from_expr(callable, assigned_names, interner);
|
|
2143
|
-
collect_assigned_names_from_args(args, assigned_names, interner);
|
|
2144
|
-
}
|
|
2145
|
-
Expr::AttrGet { object, .. } => {
|
|
2146
|
-
collect_assigned_names_from_expr(object, assigned_names, interner);
|
|
2147
|
-
}
|
|
2148
|
-
Expr::IfElse { test, body, orelse } => {
|
|
2149
|
-
collect_assigned_names_from_expr(test, assigned_names, interner);
|
|
2150
|
-
collect_assigned_names_from_expr(body, assigned_names, interner);
|
|
2151
|
-
collect_assigned_names_from_expr(orelse, assigned_names, interner);
|
|
2152
|
-
}
|
|
2153
|
-
// Per PEP 572, walrus in comprehensions assigns to the ENCLOSING scope
|
|
2154
|
-
Expr::ListComp { elt, generators } | Expr::SetComp { elt, generators } => {
|
|
2155
|
-
collect_assigned_names_from_expr(elt, assigned_names, interner);
|
|
2156
|
-
for generator in generators {
|
|
2157
|
-
collect_assigned_names_from_expr(&generator.iter, assigned_names, interner);
|
|
2158
|
-
for cond in &generator.ifs {
|
|
2159
|
-
collect_assigned_names_from_expr(cond, assigned_names, interner);
|
|
2160
|
-
}
|
|
2161
|
-
}
|
|
2162
|
-
}
|
|
2163
|
-
Expr::DictComp { key, value, generators } => {
|
|
2164
|
-
collect_assigned_names_from_expr(key, assigned_names, interner);
|
|
2165
|
-
collect_assigned_names_from_expr(value, assigned_names, interner);
|
|
2166
|
-
for generator in generators {
|
|
2167
|
-
collect_assigned_names_from_expr(&generator.iter, assigned_names, interner);
|
|
2168
|
-
for cond in &generator.ifs {
|
|
2169
|
-
collect_assigned_names_from_expr(cond, assigned_names, interner);
|
|
2170
|
-
}
|
|
2171
|
-
}
|
|
2172
|
-
}
|
|
2173
|
-
Expr::FString(parts) => {
|
|
2174
|
-
for part in parts {
|
|
2175
|
-
if let FStringPart::Interpolation { expr, .. } = part {
|
|
2176
|
-
collect_assigned_names_from_expr(expr, assigned_names, interner);
|
|
2177
|
-
}
|
|
2178
|
-
}
|
|
2179
|
-
}
|
|
2180
|
-
Expr::Slice { lower, upper, step } => {
|
|
2181
|
-
if let Some(e) = lower {
|
|
2182
|
-
collect_assigned_names_from_expr(e, assigned_names, interner);
|
|
2183
|
-
}
|
|
2184
|
-
if let Some(e) = upper {
|
|
2185
|
-
collect_assigned_names_from_expr(e, assigned_names, interner);
|
|
2186
|
-
}
|
|
2187
|
-
if let Some(e) = step {
|
|
2188
|
-
collect_assigned_names_from_expr(e, assigned_names, interner);
|
|
2189
|
-
}
|
|
2190
|
-
}
|
|
2191
|
-
// Lambda bodies have their own scope - walrus inside them doesn't affect us
|
|
2192
|
-
Expr::LambdaRaw { .. } | Expr::Lambda { .. } => {}
|
|
2193
|
-
// Leaf expressions don't contain walrus operators
|
|
2194
|
-
Expr::Literal(_) | Expr::Builtin(_) | Expr::Name(_) => {}
|
|
2195
|
-
}
|
|
2196
|
-
}
|
|
2197
|
-
|
|
2198
|
-
/// Helper to collect assigned names from argument expressions.
|
|
2199
|
-
fn collect_assigned_names_from_args(
|
|
2200
|
-
args: &ArgExprs,
|
|
2201
|
-
assigned_names: &mut AHashSet<String>,
|
|
2202
|
-
interner: &InternerBuilder,
|
|
2203
|
-
) {
|
|
2204
|
-
match args {
|
|
2205
|
-
ArgExprs::Empty => {}
|
|
2206
|
-
ArgExprs::One(arg) => collect_assigned_names_from_expr(arg, assigned_names, interner),
|
|
2207
|
-
ArgExprs::Two(arg1, arg2) => {
|
|
2208
|
-
collect_assigned_names_from_expr(arg1, assigned_names, interner);
|
|
2209
|
-
collect_assigned_names_from_expr(arg2, assigned_names, interner);
|
|
2210
|
-
}
|
|
2211
|
-
ArgExprs::Args(args) => {
|
|
2212
|
-
for arg in args {
|
|
2213
|
-
collect_assigned_names_from_expr(arg, assigned_names, interner);
|
|
2214
|
-
}
|
|
2215
|
-
}
|
|
2216
|
-
ArgExprs::Kwargs(kwargs) => {
|
|
2217
|
-
for kwarg in kwargs {
|
|
2218
|
-
collect_assigned_names_from_expr(&kwarg.value, assigned_names, interner);
|
|
2219
|
-
}
|
|
2220
|
-
}
|
|
2221
|
-
ArgExprs::ArgsKargs {
|
|
2222
|
-
args,
|
|
2223
|
-
kwargs,
|
|
2224
|
-
var_args,
|
|
2225
|
-
var_kwargs,
|
|
2226
|
-
} => {
|
|
2227
|
-
if let Some(args) = args {
|
|
2228
|
-
for arg in args {
|
|
2229
|
-
collect_assigned_names_from_expr(arg, assigned_names, interner);
|
|
2230
|
-
}
|
|
2231
|
-
}
|
|
2232
|
-
if let Some(kwargs) = kwargs {
|
|
2233
|
-
for kwarg in kwargs {
|
|
2234
|
-
collect_assigned_names_from_expr(&kwarg.value, assigned_names, interner);
|
|
2235
|
-
}
|
|
2236
|
-
}
|
|
2237
|
-
if let Some(var_args) = var_args {
|
|
2238
|
-
collect_assigned_names_from_expr(var_args, assigned_names, interner);
|
|
2239
|
-
}
|
|
2240
|
-
if let Some(var_kwargs) = var_kwargs {
|
|
2241
|
-
collect_assigned_names_from_expr(var_kwargs, assigned_names, interner);
|
|
2242
|
-
}
|
|
2243
|
-
}
|
|
2244
|
-
ArgExprs::GeneralizedCall { args, kwargs } => {
|
|
2245
|
-
for arg in args {
|
|
2246
|
-
match arg {
|
|
2247
|
-
CallArg::Value(e) | CallArg::Unpack(e) => {
|
|
2248
|
-
collect_assigned_names_from_expr(e, assigned_names, interner);
|
|
2249
|
-
}
|
|
2250
|
-
}
|
|
2251
|
-
}
|
|
2252
|
-
for kwarg in kwargs {
|
|
2253
|
-
match kwarg {
|
|
2254
|
-
CallKwarg::Named(kw) => {
|
|
2255
|
-
collect_assigned_names_from_expr(&kw.value, assigned_names, interner);
|
|
2256
|
-
}
|
|
2257
|
-
CallKwarg::Unpack(e) => {
|
|
2258
|
-
collect_assigned_names_from_expr(e, assigned_names, interner);
|
|
2259
|
-
}
|
|
2260
|
-
}
|
|
2261
|
-
}
|
|
2262
|
-
}
|
|
2263
|
-
}
|
|
2264
|
-
}
|
|
2265
|
-
|
|
2266
|
-
/// Collects cell_vars by analyzing what nested functions capture from our scope.
|
|
2267
|
-
///
|
|
2268
|
-
/// For each FunctionDef node, we recursively analyze its body to find what names it
|
|
2269
|
-
/// references. Any name that is in `our_locals` and referenced by the nested function
|
|
2270
|
-
/// (not as a local of the nested function) becomes a cell_var.
|
|
2271
|
-
fn collect_cell_vars_from_node(
|
|
2272
|
-
node: &ParseNode,
|
|
2273
|
-
our_locals: &AHashSet<String>,
|
|
2274
|
-
cell_vars: &mut AHashSet<String>,
|
|
2275
|
-
interner: &InternerBuilder,
|
|
2276
|
-
) {
|
|
2277
|
-
match node {
|
|
2278
|
-
Node::FunctionDef(RawFunctionDef { signature, body, .. }) => {
|
|
2279
|
-
// Find what names are referenced inside this nested function
|
|
2280
|
-
let mut referenced = AHashSet::new();
|
|
2281
|
-
for n in body {
|
|
2282
|
-
collect_referenced_names_from_node(n, &mut referenced, interner);
|
|
2283
|
-
}
|
|
2284
|
-
|
|
2285
|
-
// Extract param names from signature for scope analysis
|
|
2286
|
-
let param_names: Vec<StringId> = signature.param_names().collect();
|
|
2287
|
-
|
|
2288
|
-
// Collect the nested function's own locals (params + assigned)
|
|
2289
|
-
let nested_scope = collect_function_scope_info(body, ¶m_names, interner);
|
|
2290
|
-
|
|
2291
|
-
// Any name that is:
|
|
2292
|
-
// - Referenced by the nested function
|
|
2293
|
-
// - Not a local of the nested function
|
|
2294
|
-
// - Not declared global in the nested function
|
|
2295
|
-
// - In our locals
|
|
2296
|
-
// becomes a cell_var
|
|
2297
|
-
for name in &referenced {
|
|
2298
|
-
if !nested_scope.assigned_names.contains(name)
|
|
2299
|
-
&& !param_names.iter().any(|p| interner.get_str(*p) == name)
|
|
2300
|
-
&& !nested_scope.global_names.contains(name)
|
|
2301
|
-
&& our_locals.contains(name)
|
|
2302
|
-
{
|
|
2303
|
-
cell_vars.insert(name.clone());
|
|
2304
|
-
}
|
|
2305
|
-
}
|
|
2306
|
-
|
|
2307
|
-
// Also check what the nested function explicitly declares as nonlocal
|
|
2308
|
-
for name in &nested_scope.nonlocal_names {
|
|
2309
|
-
if our_locals.contains(name) {
|
|
2310
|
-
cell_vars.insert(name.clone());
|
|
2311
|
-
}
|
|
2312
|
-
}
|
|
2313
|
-
}
|
|
2314
|
-
// Recurse into control flow structures
|
|
2315
|
-
Node::For { body, or_else, .. } => {
|
|
2316
|
-
for n in body {
|
|
2317
|
-
collect_cell_vars_from_node(n, our_locals, cell_vars, interner);
|
|
2318
|
-
}
|
|
2319
|
-
for n in or_else {
|
|
2320
|
-
collect_cell_vars_from_node(n, our_locals, cell_vars, interner);
|
|
2321
|
-
}
|
|
2322
|
-
}
|
|
2323
|
-
Node::While { body, or_else, .. } => {
|
|
2324
|
-
for n in body {
|
|
2325
|
-
collect_cell_vars_from_node(n, our_locals, cell_vars, interner);
|
|
2326
|
-
}
|
|
2327
|
-
for n in or_else {
|
|
2328
|
-
collect_cell_vars_from_node(n, our_locals, cell_vars, interner);
|
|
2329
|
-
}
|
|
2330
|
-
}
|
|
2331
|
-
Node::If { body, or_else, .. } => {
|
|
2332
|
-
for n in body {
|
|
2333
|
-
collect_cell_vars_from_node(n, our_locals, cell_vars, interner);
|
|
2334
|
-
}
|
|
2335
|
-
for n in or_else {
|
|
2336
|
-
collect_cell_vars_from_node(n, our_locals, cell_vars, interner);
|
|
2337
|
-
}
|
|
2338
|
-
}
|
|
2339
|
-
Node::Try(Try {
|
|
2340
|
-
body,
|
|
2341
|
-
handlers,
|
|
2342
|
-
or_else,
|
|
2343
|
-
finally,
|
|
2344
|
-
}) => {
|
|
2345
|
-
for n in body {
|
|
2346
|
-
collect_cell_vars_from_node(n, our_locals, cell_vars, interner);
|
|
2347
|
-
}
|
|
2348
|
-
for handler in handlers {
|
|
2349
|
-
for n in &handler.body {
|
|
2350
|
-
collect_cell_vars_from_node(n, our_locals, cell_vars, interner);
|
|
2351
|
-
}
|
|
2352
|
-
}
|
|
2353
|
-
for n in or_else {
|
|
2354
|
-
collect_cell_vars_from_node(n, our_locals, cell_vars, interner);
|
|
2355
|
-
}
|
|
2356
|
-
for n in finally {
|
|
2357
|
-
collect_cell_vars_from_node(n, our_locals, cell_vars, interner);
|
|
2358
|
-
}
|
|
2359
|
-
}
|
|
2360
|
-
// Handle expressions that may contain lambdas
|
|
2361
|
-
Node::Expr(expr) | Node::Return(expr) => {
|
|
2362
|
-
collect_cell_vars_from_expr(expr, our_locals, cell_vars, interner);
|
|
2363
|
-
}
|
|
2364
|
-
Node::Assign { object, .. } | Node::UnpackAssign { object, .. } => {
|
|
2365
|
-
collect_cell_vars_from_expr(object, our_locals, cell_vars, interner);
|
|
2366
|
-
}
|
|
2367
|
-
Node::OpAssign { object, .. } => {
|
|
2368
|
-
collect_cell_vars_from_expr(object, our_locals, cell_vars, interner);
|
|
2369
|
-
}
|
|
2370
|
-
Node::SubscriptOpAssign { index, object, .. } => {
|
|
2371
|
-
collect_cell_vars_from_expr(index, our_locals, cell_vars, interner);
|
|
2372
|
-
collect_cell_vars_from_expr(object, our_locals, cell_vars, interner);
|
|
2373
|
-
}
|
|
2374
|
-
Node::SubscriptAssign { index, value, .. } => {
|
|
2375
|
-
collect_cell_vars_from_expr(index, our_locals, cell_vars, interner);
|
|
2376
|
-
collect_cell_vars_from_expr(value, our_locals, cell_vars, interner);
|
|
2377
|
-
}
|
|
2378
|
-
Node::AttrAssign { object, value, .. } => {
|
|
2379
|
-
collect_cell_vars_from_expr(object, our_locals, cell_vars, interner);
|
|
2380
|
-
collect_cell_vars_from_expr(value, our_locals, cell_vars, interner);
|
|
2381
|
-
}
|
|
2382
|
-
// Other nodes don't contain nested function definitions or lambdas
|
|
2383
|
-
_ => {}
|
|
2384
|
-
}
|
|
2385
|
-
}
|
|
2386
|
-
|
|
2387
|
-
/// Collects cell_vars from lambda expressions within an expression.
|
|
2388
|
-
///
|
|
2389
|
-
/// Recursively searches through an expression tree to find lambda expressions
|
|
2390
|
-
/// that capture variables from the enclosing scope.
|
|
2391
|
-
fn collect_cell_vars_from_expr(
|
|
2392
|
-
expr: &ExprLoc,
|
|
2393
|
-
our_locals: &AHashSet<String>,
|
|
2394
|
-
cell_vars: &mut AHashSet<String>,
|
|
2395
|
-
interner: &InternerBuilder,
|
|
2396
|
-
) {
|
|
2397
|
-
use crate::expressions::Expr;
|
|
2398
|
-
match &expr.expr {
|
|
2399
|
-
Expr::LambdaRaw { signature, body, .. } => {
|
|
2400
|
-
// This lambda captures variables from our scope
|
|
2401
|
-
// Find what names are referenced in the lambda body
|
|
2402
|
-
let mut referenced = AHashSet::new();
|
|
2403
|
-
collect_referenced_names_from_expr(body, &mut referenced, interner);
|
|
2404
|
-
// Also collect from default expressions
|
|
2405
|
-
for param in &signature.pos_args {
|
|
2406
|
-
if let Some(ref default) = param.default {
|
|
2407
|
-
collect_referenced_names_from_expr(default, &mut referenced, interner);
|
|
2408
|
-
}
|
|
2409
|
-
}
|
|
2410
|
-
for param in &signature.args {
|
|
2411
|
-
if let Some(ref default) = param.default {
|
|
2412
|
-
collect_referenced_names_from_expr(default, &mut referenced, interner);
|
|
2413
|
-
}
|
|
2414
|
-
}
|
|
2415
|
-
for param in &signature.kwargs {
|
|
2416
|
-
if let Some(ref default) = param.default {
|
|
2417
|
-
collect_referenced_names_from_expr(default, &mut referenced, interner);
|
|
2418
|
-
}
|
|
2419
|
-
}
|
|
2420
|
-
|
|
2421
|
-
// Extract param names from signature
|
|
2422
|
-
let param_names: Vec<StringId> = signature.param_names().collect();
|
|
2423
|
-
|
|
2424
|
-
// Any name that is:
|
|
2425
|
-
// - Referenced by the lambda
|
|
2426
|
-
// - Not a param of the lambda
|
|
2427
|
-
// - In our locals
|
|
2428
|
-
// becomes a cell_var
|
|
2429
|
-
for name in &referenced {
|
|
2430
|
-
if !param_names.iter().any(|p| interner.get_str(*p) == name) && our_locals.contains(name) {
|
|
2431
|
-
cell_vars.insert(name.clone());
|
|
2432
|
-
}
|
|
2433
|
-
}
|
|
2434
|
-
|
|
2435
|
-
// Recursively check the lambda body for nested lambdas.
|
|
2436
|
-
// For nested lambdas, extend our_locals to include this lambda's parameters
|
|
2437
|
-
// so that inner lambdas can find them for closure capture.
|
|
2438
|
-
let mut extended_locals = our_locals.clone();
|
|
2439
|
-
for param_id in ¶m_names {
|
|
2440
|
-
extended_locals.insert(interner.get_str(*param_id).to_string());
|
|
2441
|
-
}
|
|
2442
|
-
collect_cell_vars_from_expr(body, &extended_locals, cell_vars, interner);
|
|
2443
|
-
}
|
|
2444
|
-
// Recurse into sub-expressions
|
|
2445
|
-
Expr::List(items) | Expr::Tuple(items) | Expr::Set(items) => {
|
|
2446
|
-
for item in items {
|
|
2447
|
-
let expr = match item {
|
|
2448
|
-
SequenceItem::Value(e) | SequenceItem::Unpack(e) => e,
|
|
2449
|
-
};
|
|
2450
|
-
collect_cell_vars_from_expr(expr, our_locals, cell_vars, interner);
|
|
2451
|
-
}
|
|
2452
|
-
}
|
|
2453
|
-
Expr::Dict(dict_items) => {
|
|
2454
|
-
for item in dict_items {
|
|
2455
|
-
match item {
|
|
2456
|
-
DictItem::Pair(key, value) => {
|
|
2457
|
-
collect_cell_vars_from_expr(key, our_locals, cell_vars, interner);
|
|
2458
|
-
collect_cell_vars_from_expr(value, our_locals, cell_vars, interner);
|
|
2459
|
-
}
|
|
2460
|
-
DictItem::Unpack(e) => collect_cell_vars_from_expr(e, our_locals, cell_vars, interner),
|
|
2461
|
-
}
|
|
2462
|
-
}
|
|
2463
|
-
}
|
|
2464
|
-
Expr::Op { left, right, .. } | Expr::CmpOp { left, right, .. } => {
|
|
2465
|
-
collect_cell_vars_from_expr(left, our_locals, cell_vars, interner);
|
|
2466
|
-
collect_cell_vars_from_expr(right, our_locals, cell_vars, interner);
|
|
2467
|
-
}
|
|
2468
|
-
Expr::ChainCmp { left, comparisons } => {
|
|
2469
|
-
collect_cell_vars_from_expr(left, our_locals, cell_vars, interner);
|
|
2470
|
-
for (_, expr) in comparisons {
|
|
2471
|
-
collect_cell_vars_from_expr(expr, our_locals, cell_vars, interner);
|
|
2472
|
-
}
|
|
2473
|
-
}
|
|
2474
|
-
Expr::Not(operand) | Expr::UnaryMinus(operand) | Expr::UnaryPlus(operand) | Expr::UnaryInvert(operand) => {
|
|
2475
|
-
collect_cell_vars_from_expr(operand, our_locals, cell_vars, interner);
|
|
2476
|
-
}
|
|
2477
|
-
Expr::Subscript { object, index } => {
|
|
2478
|
-
collect_cell_vars_from_expr(object, our_locals, cell_vars, interner);
|
|
2479
|
-
collect_cell_vars_from_expr(index, our_locals, cell_vars, interner);
|
|
2480
|
-
}
|
|
2481
|
-
Expr::Call { args, .. } => {
|
|
2482
|
-
collect_cell_vars_from_args(args, our_locals, cell_vars, interner);
|
|
2483
|
-
}
|
|
2484
|
-
Expr::AttrCall { object, args, .. } => {
|
|
2485
|
-
collect_cell_vars_from_expr(object, our_locals, cell_vars, interner);
|
|
2486
|
-
collect_cell_vars_from_args(args, our_locals, cell_vars, interner);
|
|
2487
|
-
}
|
|
2488
|
-
Expr::IndirectCall { callable, args } => {
|
|
2489
|
-
collect_cell_vars_from_expr(callable, our_locals, cell_vars, interner);
|
|
2490
|
-
collect_cell_vars_from_args(args, our_locals, cell_vars, interner);
|
|
2491
|
-
}
|
|
2492
|
-
Expr::AttrGet { object, .. } => {
|
|
2493
|
-
collect_cell_vars_from_expr(object, our_locals, cell_vars, interner);
|
|
2494
|
-
}
|
|
2495
|
-
Expr::IfElse { test, body, orelse } => {
|
|
2496
|
-
collect_cell_vars_from_expr(test, our_locals, cell_vars, interner);
|
|
2497
|
-
collect_cell_vars_from_expr(body, our_locals, cell_vars, interner);
|
|
2498
|
-
collect_cell_vars_from_expr(orelse, our_locals, cell_vars, interner);
|
|
2499
|
-
}
|
|
2500
|
-
Expr::ListComp { elt, generators } | Expr::SetComp { elt, generators } => {
|
|
2501
|
-
collect_cell_vars_from_expr(elt, our_locals, cell_vars, interner);
|
|
2502
|
-
for generator in generators {
|
|
2503
|
-
collect_cell_vars_from_expr(&generator.iter, our_locals, cell_vars, interner);
|
|
2504
|
-
for cond in &generator.ifs {
|
|
2505
|
-
collect_cell_vars_from_expr(cond, our_locals, cell_vars, interner);
|
|
2506
|
-
}
|
|
2507
|
-
}
|
|
2508
|
-
}
|
|
2509
|
-
Expr::DictComp { key, value, generators } => {
|
|
2510
|
-
collect_cell_vars_from_expr(key, our_locals, cell_vars, interner);
|
|
2511
|
-
collect_cell_vars_from_expr(value, our_locals, cell_vars, interner);
|
|
2512
|
-
for generator in generators {
|
|
2513
|
-
collect_cell_vars_from_expr(&generator.iter, our_locals, cell_vars, interner);
|
|
2514
|
-
for cond in &generator.ifs {
|
|
2515
|
-
collect_cell_vars_from_expr(cond, our_locals, cell_vars, interner);
|
|
2516
|
-
}
|
|
2517
|
-
}
|
|
2518
|
-
}
|
|
2519
|
-
Expr::FString(parts) => {
|
|
2520
|
-
for part in parts {
|
|
2521
|
-
if let crate::fstring::FStringPart::Interpolation { expr, .. } = part {
|
|
2522
|
-
collect_cell_vars_from_expr(expr, our_locals, cell_vars, interner);
|
|
2523
|
-
}
|
|
2524
|
-
}
|
|
2525
|
-
}
|
|
2526
|
-
Expr::Named { value, .. } => {
|
|
2527
|
-
// Only scan the value expression for cell vars
|
|
2528
|
-
collect_cell_vars_from_expr(value, our_locals, cell_vars, interner);
|
|
2529
|
-
}
|
|
2530
|
-
Expr::Await(value) => {
|
|
2531
|
-
collect_cell_vars_from_expr(value, our_locals, cell_vars, interner);
|
|
2532
|
-
}
|
|
2533
|
-
// Leaf expressions
|
|
2534
|
-
Expr::Literal(_) | Expr::Builtin(_) | Expr::Name(_) | Expr::Lambda { .. } | Expr::Slice { .. } => {}
|
|
2535
|
-
}
|
|
2536
|
-
}
|
|
2537
|
-
|
|
2538
|
-
/// Helper to collect cell vars from argument expressions.
|
|
2539
|
-
fn collect_cell_vars_from_args(
|
|
2540
|
-
args: &ArgExprs,
|
|
2541
|
-
our_locals: &AHashSet<String>,
|
|
2542
|
-
cell_vars: &mut AHashSet<String>,
|
|
2543
|
-
interner: &InternerBuilder,
|
|
2544
|
-
) {
|
|
2545
|
-
match args {
|
|
2546
|
-
ArgExprs::Empty => {}
|
|
2547
|
-
ArgExprs::One(arg) => collect_cell_vars_from_expr(arg, our_locals, cell_vars, interner),
|
|
2548
|
-
ArgExprs::Two(arg1, arg2) => {
|
|
2549
|
-
collect_cell_vars_from_expr(arg1, our_locals, cell_vars, interner);
|
|
2550
|
-
collect_cell_vars_from_expr(arg2, our_locals, cell_vars, interner);
|
|
2551
|
-
}
|
|
2552
|
-
ArgExprs::Args(args) => {
|
|
2553
|
-
for arg in args {
|
|
2554
|
-
collect_cell_vars_from_expr(arg, our_locals, cell_vars, interner);
|
|
2555
|
-
}
|
|
2556
|
-
}
|
|
2557
|
-
ArgExprs::Kwargs(kwargs) => {
|
|
2558
|
-
for kwarg in kwargs {
|
|
2559
|
-
collect_cell_vars_from_expr(&kwarg.value, our_locals, cell_vars, interner);
|
|
2560
|
-
}
|
|
2561
|
-
}
|
|
2562
|
-
ArgExprs::ArgsKargs {
|
|
2563
|
-
args,
|
|
2564
|
-
kwargs,
|
|
2565
|
-
var_args,
|
|
2566
|
-
var_kwargs,
|
|
2567
|
-
} => {
|
|
2568
|
-
if let Some(args) = args {
|
|
2569
|
-
for arg in args {
|
|
2570
|
-
collect_cell_vars_from_expr(arg, our_locals, cell_vars, interner);
|
|
2571
|
-
}
|
|
2572
|
-
}
|
|
2573
|
-
if let Some(kwargs) = kwargs {
|
|
2574
|
-
for kwarg in kwargs {
|
|
2575
|
-
collect_cell_vars_from_expr(&kwarg.value, our_locals, cell_vars, interner);
|
|
2576
|
-
}
|
|
2577
|
-
}
|
|
2578
|
-
if let Some(var_args) = var_args {
|
|
2579
|
-
collect_cell_vars_from_expr(var_args, our_locals, cell_vars, interner);
|
|
2580
|
-
}
|
|
2581
|
-
if let Some(var_kwargs) = var_kwargs {
|
|
2582
|
-
collect_cell_vars_from_expr(var_kwargs, our_locals, cell_vars, interner);
|
|
2583
|
-
}
|
|
2584
|
-
}
|
|
2585
|
-
ArgExprs::GeneralizedCall { args, kwargs } => {
|
|
2586
|
-
for arg in args {
|
|
2587
|
-
match arg {
|
|
2588
|
-
CallArg::Value(e) | CallArg::Unpack(e) => {
|
|
2589
|
-
collect_cell_vars_from_expr(e, our_locals, cell_vars, interner);
|
|
2590
|
-
}
|
|
2591
|
-
}
|
|
2592
|
-
}
|
|
2593
|
-
for kwarg in kwargs {
|
|
2594
|
-
match kwarg {
|
|
2595
|
-
CallKwarg::Named(kw) => {
|
|
2596
|
-
collect_cell_vars_from_expr(&kw.value, our_locals, cell_vars, interner);
|
|
2597
|
-
}
|
|
2598
|
-
CallKwarg::Unpack(e) => {
|
|
2599
|
-
collect_cell_vars_from_expr(e, our_locals, cell_vars, interner);
|
|
2600
|
-
}
|
|
2601
|
-
}
|
|
2602
|
-
}
|
|
2603
|
-
}
|
|
2604
|
-
}
|
|
2605
|
-
}
|
|
2606
|
-
|
|
2607
|
-
/// Collects all names referenced (read) in a node and its descendants.
|
|
2608
|
-
///
|
|
2609
|
-
/// This is used to find what names a nested function references from enclosing scopes.
|
|
2610
|
-
fn collect_referenced_names_from_node(node: &ParseNode, referenced: &mut AHashSet<String>, interner: &InternerBuilder) {
|
|
2611
|
-
match node {
|
|
2612
|
-
Node::Expr(expr) => collect_referenced_names_from_expr(expr, referenced, interner),
|
|
2613
|
-
Node::Return(expr) => collect_referenced_names_from_expr(expr, referenced, interner),
|
|
2614
|
-
Node::Raise(Some(expr)) => collect_referenced_names_from_expr(expr, referenced, interner),
|
|
2615
|
-
Node::Raise(None) => {}
|
|
2616
|
-
Node::Assert { test, msg } => {
|
|
2617
|
-
collect_referenced_names_from_expr(test, referenced, interner);
|
|
2618
|
-
if let Some(m) = msg {
|
|
2619
|
-
collect_referenced_names_from_expr(m, referenced, interner);
|
|
2620
|
-
}
|
|
2621
|
-
}
|
|
2622
|
-
Node::Assign { object, .. } => {
|
|
2623
|
-
collect_referenced_names_from_expr(object, referenced, interner);
|
|
2624
|
-
}
|
|
2625
|
-
Node::UnpackAssign { object, .. } => {
|
|
2626
|
-
collect_referenced_names_from_expr(object, referenced, interner);
|
|
2627
|
-
}
|
|
2628
|
-
Node::OpAssign { target, object, .. } => {
|
|
2629
|
-
// OpAssign reads the target before writing
|
|
2630
|
-
referenced.insert(interner.get_str(target.name_id).to_string());
|
|
2631
|
-
collect_referenced_names_from_expr(object, referenced, interner);
|
|
2632
|
-
}
|
|
2633
|
-
Node::SubscriptOpAssign {
|
|
2634
|
-
target, index, object, ..
|
|
2635
|
-
} => {
|
|
2636
|
-
referenced.insert(interner.get_str(target.name_id).to_string());
|
|
2637
|
-
collect_referenced_names_from_expr(index, referenced, interner);
|
|
2638
|
-
collect_referenced_names_from_expr(object, referenced, interner);
|
|
2639
|
-
}
|
|
2640
|
-
Node::SubscriptAssign {
|
|
2641
|
-
target, index, value, ..
|
|
2642
|
-
} => {
|
|
2643
|
-
referenced.insert(interner.get_str(target.name_id).to_string());
|
|
2644
|
-
collect_referenced_names_from_expr(index, referenced, interner);
|
|
2645
|
-
collect_referenced_names_from_expr(value, referenced, interner);
|
|
2646
|
-
}
|
|
2647
|
-
Node::AttrAssign { object, value, .. } => {
|
|
2648
|
-
collect_referenced_names_from_expr(object, referenced, interner);
|
|
2649
|
-
collect_referenced_names_from_expr(value, referenced, interner);
|
|
2650
|
-
}
|
|
2651
|
-
Node::For {
|
|
2652
|
-
iter, body, or_else, ..
|
|
2653
|
-
} => {
|
|
2654
|
-
collect_referenced_names_from_expr(iter, referenced, interner);
|
|
2655
|
-
for n in body {
|
|
2656
|
-
collect_referenced_names_from_node(n, referenced, interner);
|
|
2657
|
-
}
|
|
2658
|
-
for n in or_else {
|
|
2659
|
-
collect_referenced_names_from_node(n, referenced, interner);
|
|
2660
|
-
}
|
|
2661
|
-
}
|
|
2662
|
-
Node::While { test, body, or_else } => {
|
|
2663
|
-
collect_referenced_names_from_expr(test, referenced, interner);
|
|
2664
|
-
for n in body {
|
|
2665
|
-
collect_referenced_names_from_node(n, referenced, interner);
|
|
2666
|
-
}
|
|
2667
|
-
for n in or_else {
|
|
2668
|
-
collect_referenced_names_from_node(n, referenced, interner);
|
|
2669
|
-
}
|
|
2670
|
-
}
|
|
2671
|
-
Node::If { test, body, or_else } => {
|
|
2672
|
-
collect_referenced_names_from_expr(test, referenced, interner);
|
|
2673
|
-
for n in body {
|
|
2674
|
-
collect_referenced_names_from_node(n, referenced, interner);
|
|
2675
|
-
}
|
|
2676
|
-
for n in or_else {
|
|
2677
|
-
collect_referenced_names_from_node(n, referenced, interner);
|
|
2678
|
-
}
|
|
2679
|
-
}
|
|
2680
|
-
Node::FunctionDef(_) => {
|
|
2681
|
-
// Don't recurse into nested function bodies - they have their own scope
|
|
2682
|
-
}
|
|
2683
|
-
Node::Try(Try {
|
|
2684
|
-
body,
|
|
2685
|
-
handlers,
|
|
2686
|
-
or_else,
|
|
2687
|
-
finally,
|
|
2688
|
-
}) => {
|
|
2689
|
-
for n in body {
|
|
2690
|
-
collect_referenced_names_from_node(n, referenced, interner);
|
|
2691
|
-
}
|
|
2692
|
-
for handler in handlers {
|
|
2693
|
-
// Exception type expression may reference names
|
|
2694
|
-
if let Some(ref exc_type) = handler.exc_type {
|
|
2695
|
-
collect_referenced_names_from_expr(exc_type, referenced, interner);
|
|
2696
|
-
}
|
|
2697
|
-
for n in &handler.body {
|
|
2698
|
-
collect_referenced_names_from_node(n, referenced, interner);
|
|
2699
|
-
}
|
|
2700
|
-
}
|
|
2701
|
-
for n in or_else {
|
|
2702
|
-
collect_referenced_names_from_node(n, referenced, interner);
|
|
2703
|
-
}
|
|
2704
|
-
for n in finally {
|
|
2705
|
-
collect_referenced_names_from_node(n, referenced, interner);
|
|
2706
|
-
}
|
|
2707
|
-
}
|
|
2708
|
-
// Imports create bindings but don't reference names
|
|
2709
|
-
Node::Import { .. } | Node::ImportFrom { .. } => {}
|
|
2710
|
-
Node::Pass
|
|
2711
|
-
| Node::ReturnNone
|
|
2712
|
-
| Node::Global { .. }
|
|
2713
|
-
| Node::Nonlocal { .. }
|
|
2714
|
-
| Node::Break { .. }
|
|
2715
|
-
| Node::Continue { .. } => {}
|
|
2716
|
-
}
|
|
2717
|
-
}
|
|
2718
|
-
|
|
2719
|
-
/// Collects all names referenced in an expression.
|
|
2720
|
-
fn collect_referenced_names_from_expr(
|
|
2721
|
-
expr: &crate::expressions::ExprLoc,
|
|
2722
|
-
referenced: &mut AHashSet<String>,
|
|
2723
|
-
interner: &InternerBuilder,
|
|
2724
|
-
) {
|
|
2725
|
-
use crate::expressions::Expr;
|
|
2726
|
-
match &expr.expr {
|
|
2727
|
-
Expr::Name(ident) => {
|
|
2728
|
-
referenced.insert(interner.get_str(ident.name_id).to_string());
|
|
2729
|
-
}
|
|
2730
|
-
Expr::Literal(_) => {}
|
|
2731
|
-
Expr::Builtin(_) => {}
|
|
2732
|
-
Expr::List(items) | Expr::Tuple(items) | Expr::Set(items) => {
|
|
2733
|
-
for item in items {
|
|
2734
|
-
let expr = match item {
|
|
2735
|
-
SequenceItem::Value(e) | SequenceItem::Unpack(e) => e,
|
|
2736
|
-
};
|
|
2737
|
-
collect_referenced_names_from_expr(expr, referenced, interner);
|
|
2738
|
-
}
|
|
2739
|
-
}
|
|
2740
|
-
Expr::Dict(dict_items) => {
|
|
2741
|
-
for item in dict_items {
|
|
2742
|
-
match item {
|
|
2743
|
-
DictItem::Pair(key, value) => {
|
|
2744
|
-
collect_referenced_names_from_expr(key, referenced, interner);
|
|
2745
|
-
collect_referenced_names_from_expr(value, referenced, interner);
|
|
2746
|
-
}
|
|
2747
|
-
DictItem::Unpack(e) => collect_referenced_names_from_expr(e, referenced, interner),
|
|
2748
|
-
}
|
|
2749
|
-
}
|
|
2750
|
-
}
|
|
2751
|
-
Expr::Op { left, right, .. } | Expr::CmpOp { left, right, .. } => {
|
|
2752
|
-
collect_referenced_names_from_expr(left, referenced, interner);
|
|
2753
|
-
collect_referenced_names_from_expr(right, referenced, interner);
|
|
2754
|
-
}
|
|
2755
|
-
Expr::ChainCmp { left, comparisons } => {
|
|
2756
|
-
collect_referenced_names_from_expr(left, referenced, interner);
|
|
2757
|
-
for (_, expr) in comparisons {
|
|
2758
|
-
collect_referenced_names_from_expr(expr, referenced, interner);
|
|
2759
|
-
}
|
|
2760
|
-
}
|
|
2761
|
-
Expr::Not(operand) | Expr::UnaryMinus(operand) | Expr::UnaryPlus(operand) | Expr::UnaryInvert(operand) => {
|
|
2762
|
-
collect_referenced_names_from_expr(operand, referenced, interner);
|
|
2763
|
-
}
|
|
2764
|
-
Expr::FString(parts) => {
|
|
2765
|
-
collect_referenced_names_from_fstring_parts(parts, referenced, interner);
|
|
2766
|
-
}
|
|
2767
|
-
Expr::Subscript { object, index } => {
|
|
2768
|
-
collect_referenced_names_from_expr(object, referenced, interner);
|
|
2769
|
-
collect_referenced_names_from_expr(index, referenced, interner);
|
|
2770
|
-
}
|
|
2771
|
-
Expr::Call { callable, args } => {
|
|
2772
|
-
// Check if the callable is a Name reference
|
|
2773
|
-
if let Callable::Name(ident) = callable {
|
|
2774
|
-
referenced.insert(interner.get_str(ident.name_id).to_string());
|
|
2775
|
-
}
|
|
2776
|
-
collect_referenced_names_from_args(args, referenced, interner);
|
|
2777
|
-
}
|
|
2778
|
-
Expr::AttrCall { object, args, .. } => {
|
|
2779
|
-
collect_referenced_names_from_expr(object, referenced, interner);
|
|
2780
|
-
collect_referenced_names_from_args(args, referenced, interner);
|
|
2781
|
-
}
|
|
2782
|
-
Expr::AttrGet { object, .. } => {
|
|
2783
|
-
collect_referenced_names_from_expr(object, referenced, interner);
|
|
2784
|
-
}
|
|
2785
|
-
Expr::IndirectCall { callable, args } => {
|
|
2786
|
-
// Collect references from the callable expression and arguments
|
|
2787
|
-
collect_referenced_names_from_expr(callable, referenced, interner);
|
|
2788
|
-
collect_referenced_names_from_args(args, referenced, interner);
|
|
2789
|
-
}
|
|
2790
|
-
Expr::IfElse { test, body, orelse } => {
|
|
2791
|
-
collect_referenced_names_from_expr(test, referenced, interner);
|
|
2792
|
-
collect_referenced_names_from_expr(body, referenced, interner);
|
|
2793
|
-
collect_referenced_names_from_expr(orelse, referenced, interner);
|
|
2794
|
-
}
|
|
2795
|
-
Expr::ListComp { elt, generators } | Expr::SetComp { elt, generators } => {
|
|
2796
|
-
collect_referenced_names_from_comprehension(generators, Some(elt), None, referenced, interner);
|
|
2797
|
-
}
|
|
2798
|
-
Expr::DictComp { key, value, generators } => {
|
|
2799
|
-
collect_referenced_names_from_comprehension(generators, None, Some((key, value)), referenced, interner);
|
|
2800
|
-
}
|
|
2801
|
-
Expr::LambdaRaw { signature, body, .. } => {
|
|
2802
|
-
// Build set of parameter names (these are local to the lambda, not free variables)
|
|
2803
|
-
let lambda_params: AHashSet<String> = signature
|
|
2804
|
-
.param_names()
|
|
2805
|
-
.map(|s| interner.get_str(s).to_string())
|
|
2806
|
-
.collect();
|
|
2807
|
-
|
|
2808
|
-
// Collect references from the body expression into a temporary set
|
|
2809
|
-
let mut body_refs: AHashSet<String> = AHashSet::new();
|
|
2810
|
-
collect_referenced_names_from_expr(body, &mut body_refs, interner);
|
|
2811
|
-
|
|
2812
|
-
// Filter out the lambda's own parameters before adding to referenced set.
|
|
2813
|
-
// The lambda's parameters are bound by the lambda, not free from outer scope.
|
|
2814
|
-
for name in body_refs {
|
|
2815
|
-
if !lambda_params.contains(&name) {
|
|
2816
|
-
referenced.insert(name);
|
|
2817
|
-
}
|
|
2818
|
-
}
|
|
2819
|
-
|
|
2820
|
-
// Default value expressions are evaluated in the enclosing scope, not the lambda's
|
|
2821
|
-
// scope, so they can reference outer scope without filtering.
|
|
2822
|
-
for param in &signature.pos_args {
|
|
2823
|
-
if let Some(ref default) = param.default {
|
|
2824
|
-
collect_referenced_names_from_expr(default, referenced, interner);
|
|
2825
|
-
}
|
|
2826
|
-
}
|
|
2827
|
-
for param in &signature.args {
|
|
2828
|
-
if let Some(ref default) = param.default {
|
|
2829
|
-
collect_referenced_names_from_expr(default, referenced, interner);
|
|
2830
|
-
}
|
|
2831
|
-
}
|
|
2832
|
-
for param in &signature.kwargs {
|
|
2833
|
-
if let Some(ref default) = param.default {
|
|
2834
|
-
collect_referenced_names_from_expr(default, referenced, interner);
|
|
2835
|
-
}
|
|
2836
|
-
}
|
|
2837
|
-
}
|
|
2838
|
-
Expr::Lambda { .. } => {
|
|
2839
|
-
// Lambda should only exist after preparation; this function operates on raw expressions
|
|
2840
|
-
unreachable!("Expr::Lambda should not exist during scope analysis")
|
|
2841
|
-
}
|
|
2842
|
-
Expr::Named { value, .. } => {
|
|
2843
|
-
// Only the value is referenced; target is being assigned, not read
|
|
2844
|
-
collect_referenced_names_from_expr(value, referenced, interner);
|
|
2845
|
-
}
|
|
2846
|
-
Expr::Slice { lower, upper, step } => {
|
|
2847
|
-
if let Some(expr) = lower {
|
|
2848
|
-
collect_referenced_names_from_expr(expr, referenced, interner);
|
|
2849
|
-
}
|
|
2850
|
-
if let Some(expr) = upper {
|
|
2851
|
-
collect_referenced_names_from_expr(expr, referenced, interner);
|
|
2852
|
-
}
|
|
2853
|
-
if let Some(expr) = step {
|
|
2854
|
-
collect_referenced_names_from_expr(expr, referenced, interner);
|
|
2855
|
-
}
|
|
2856
|
-
}
|
|
2857
|
-
Expr::Await(value) => {
|
|
2858
|
-
collect_referenced_names_from_expr(value, referenced, interner);
|
|
2859
|
-
}
|
|
2860
|
-
}
|
|
2861
|
-
}
|
|
2862
|
-
|
|
2863
|
-
/// Collects referenced names from comprehension expressions.
|
|
2864
|
-
///
|
|
2865
|
-
/// Handles the special scoping rules: loop variables are local to the comprehension,
|
|
2866
|
-
/// so we collect references from iterators and conditions but exclude loop variable names.
|
|
2867
|
-
fn collect_referenced_names_from_comprehension(
|
|
2868
|
-
generators: &[Comprehension],
|
|
2869
|
-
elt: Option<&ExprLoc>,
|
|
2870
|
-
key_value: Option<(&ExprLoc, &ExprLoc)>,
|
|
2871
|
-
referenced: &mut AHashSet<String>,
|
|
2872
|
-
interner: &InternerBuilder,
|
|
2873
|
-
) {
|
|
2874
|
-
// Track loop variable names (these are local to the comprehension)
|
|
2875
|
-
let mut comp_locals: AHashSet<String> = AHashSet::new();
|
|
2876
|
-
|
|
2877
|
-
// Collect references from expressions that can see prior loop variables.
|
|
2878
|
-
// These need to be filtered against comp_locals before adding to referenced.
|
|
2879
|
-
let mut inner_refs: AHashSet<String> = AHashSet::new();
|
|
2880
|
-
|
|
2881
|
-
for (i, comp) in generators.iter().enumerate() {
|
|
2882
|
-
if i == 0 {
|
|
2883
|
-
// FIRST generator's iter expression truly references enclosing scope
|
|
2884
|
-
// (evaluated before any loop variable is defined).
|
|
2885
|
-
collect_referenced_names_from_expr(&comp.iter, referenced, interner);
|
|
2886
|
-
} else {
|
|
2887
|
-
// SUBSEQUENT generators' iter expressions can reference prior loop variables.
|
|
2888
|
-
// For example, in `[y for x in xs for y in x]`, the `x` in the second
|
|
2889
|
-
// generator's iter is the first generator's loop variable, not outer scope.
|
|
2890
|
-
collect_referenced_names_from_expr(&comp.iter, &mut inner_refs, interner);
|
|
2891
|
-
}
|
|
2892
|
-
|
|
2893
|
-
// Add this generator's target(s) to local set
|
|
2894
|
-
collect_names_from_unpack_target(&comp.target, &mut comp_locals, interner);
|
|
2895
|
-
|
|
2896
|
-
// Filter conditions can see prior loop variables - collect separately
|
|
2897
|
-
for cond in &comp.ifs {
|
|
2898
|
-
collect_referenced_names_from_expr(cond, &mut inner_refs, interner);
|
|
2899
|
-
}
|
|
2900
|
-
}
|
|
2901
|
-
|
|
2902
|
-
// Element expression(s) can see all loop variables - collect separately
|
|
2903
|
-
if let Some(e) = elt {
|
|
2904
|
-
collect_referenced_names_from_expr(e, &mut inner_refs, interner);
|
|
2905
|
-
}
|
|
2906
|
-
if let Some((k, v)) = key_value {
|
|
2907
|
-
collect_referenced_names_from_expr(k, &mut inner_refs, interner);
|
|
2908
|
-
collect_referenced_names_from_expr(v, &mut inner_refs, interner);
|
|
2909
|
-
}
|
|
2910
|
-
|
|
2911
|
-
// Add inner references that are NOT comprehension-locals to the outer referenced set.
|
|
2912
|
-
// Names that ARE comp_locals refer to the comprehension's loop variable, not enclosing scope.
|
|
2913
|
-
for name in inner_refs {
|
|
2914
|
-
if !comp_locals.contains(&name) {
|
|
2915
|
-
referenced.insert(name);
|
|
2916
|
-
}
|
|
2917
|
-
}
|
|
2918
|
-
}
|
|
2919
|
-
|
|
2920
|
-
/// Collects referenced names from argument expressions.
|
|
2921
|
-
fn collect_referenced_names_from_args(args: &ArgExprs, referenced: &mut AHashSet<String>, interner: &InternerBuilder) {
|
|
2922
|
-
match args {
|
|
2923
|
-
ArgExprs::Empty => {}
|
|
2924
|
-
ArgExprs::One(e) => collect_referenced_names_from_expr(e, referenced, interner),
|
|
2925
|
-
ArgExprs::Two(e1, e2) => {
|
|
2926
|
-
collect_referenced_names_from_expr(e1, referenced, interner);
|
|
2927
|
-
collect_referenced_names_from_expr(e2, referenced, interner);
|
|
2928
|
-
}
|
|
2929
|
-
ArgExprs::Args(exprs) => {
|
|
2930
|
-
for e in exprs {
|
|
2931
|
-
collect_referenced_names_from_expr(e, referenced, interner);
|
|
2932
|
-
}
|
|
2933
|
-
}
|
|
2934
|
-
ArgExprs::Kwargs(kwargs) => {
|
|
2935
|
-
for kwarg in kwargs {
|
|
2936
|
-
collect_referenced_names_from_expr(&kwarg.value, referenced, interner);
|
|
2937
|
-
}
|
|
2938
|
-
}
|
|
2939
|
-
ArgExprs::ArgsKargs {
|
|
2940
|
-
args,
|
|
2941
|
-
kwargs,
|
|
2942
|
-
var_args,
|
|
2943
|
-
var_kwargs,
|
|
2944
|
-
} => {
|
|
2945
|
-
if let Some(args) = args {
|
|
2946
|
-
for e in args {
|
|
2947
|
-
collect_referenced_names_from_expr(e, referenced, interner);
|
|
2948
|
-
}
|
|
2949
|
-
}
|
|
2950
|
-
if let Some(kwargs) = kwargs {
|
|
2951
|
-
for kwarg in kwargs {
|
|
2952
|
-
collect_referenced_names_from_expr(&kwarg.value, referenced, interner);
|
|
2953
|
-
}
|
|
2954
|
-
}
|
|
2955
|
-
if let Some(e) = var_args {
|
|
2956
|
-
collect_referenced_names_from_expr(e, referenced, interner);
|
|
2957
|
-
}
|
|
2958
|
-
if let Some(e) = var_kwargs {
|
|
2959
|
-
collect_referenced_names_from_expr(e, referenced, interner);
|
|
2960
|
-
}
|
|
2961
|
-
}
|
|
2962
|
-
ArgExprs::GeneralizedCall { args, kwargs } => {
|
|
2963
|
-
for arg in args {
|
|
2964
|
-
match arg {
|
|
2965
|
-
CallArg::Value(e) | CallArg::Unpack(e) => {
|
|
2966
|
-
collect_referenced_names_from_expr(e, referenced, interner);
|
|
2967
|
-
}
|
|
2968
|
-
}
|
|
2969
|
-
}
|
|
2970
|
-
for kwarg in kwargs {
|
|
2971
|
-
match kwarg {
|
|
2972
|
-
CallKwarg::Named(kw) => {
|
|
2973
|
-
collect_referenced_names_from_expr(&kw.value, referenced, interner);
|
|
2974
|
-
}
|
|
2975
|
-
CallKwarg::Unpack(e) => {
|
|
2976
|
-
collect_referenced_names_from_expr(e, referenced, interner);
|
|
2977
|
-
}
|
|
2978
|
-
}
|
|
2979
|
-
}
|
|
2980
|
-
}
|
|
2981
|
-
}
|
|
2982
|
-
}
|
|
2983
|
-
|
|
2984
|
-
/// Collects referenced names from f-string parts (both expressions and dynamic format specs).
|
|
2985
|
-
fn collect_referenced_names_from_fstring_parts(
|
|
2986
|
-
parts: &[FStringPart],
|
|
2987
|
-
referenced: &mut AHashSet<String>,
|
|
2988
|
-
interner: &InternerBuilder,
|
|
2989
|
-
) {
|
|
2990
|
-
for part in parts {
|
|
2991
|
-
if let FStringPart::Interpolation { expr, format_spec, .. } = part {
|
|
2992
|
-
collect_referenced_names_from_expr(expr, referenced, interner);
|
|
2993
|
-
// Also check dynamic format specs which can contain interpolated expressions
|
|
2994
|
-
if let Some(FormatSpec::Dynamic(spec_parts)) = format_spec {
|
|
2995
|
-
collect_referenced_names_from_fstring_parts(spec_parts, referenced, interner);
|
|
2996
|
-
}
|
|
2997
|
-
}
|
|
2998
|
-
}
|
|
2999
|
-
}
|
|
3000
|
-
|
|
3001
|
-
/// Collects all names from an unpack target into the given set.
|
|
3002
|
-
///
|
|
3003
|
-
/// Recursively traverses nested tuples to find all identifier names.
|
|
3004
|
-
fn collect_names_from_unpack_target(target: &UnpackTarget, names: &mut AHashSet<String>, interner: &InternerBuilder) {
|
|
3005
|
-
match target {
|
|
3006
|
-
UnpackTarget::Name(ident) | UnpackTarget::Starred(ident) => {
|
|
3007
|
-
names.insert(interner.get_str(ident.name_id).to_string());
|
|
3008
|
-
}
|
|
3009
|
-
UnpackTarget::Tuple { targets, .. } => {
|
|
3010
|
-
for t in targets {
|
|
3011
|
-
collect_names_from_unpack_target(t, names, interner);
|
|
3012
|
-
}
|
|
3013
|
-
}
|
|
3014
|
-
}
|
|
3015
|
-
}
|