superacli 1.1.4 → 1.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (961) hide show
  1. package/__tests__/adapter-schema.test.js +2 -0
  2. package/__tests__/config.test.js +62 -1
  3. package/__tests__/help-json.test.js +2 -0
  4. package/__tests__/mcp-adapter.test.js +14 -4
  5. package/__tests__/mcp-local.test.js +159 -0
  6. package/__tests__/mcp-stdio-jsonrpc.test.js +105 -0
  7. package/__tests__/monty-plugin.test.js +121 -0
  8. package/__tests__/plugin-browser-use-uninstall.test.js +23 -0
  9. package/__tests__/plugin-browser-use.test.js +77 -0
  10. package/__tests__/plugins-command.test.js +92 -1
  11. package/__tests__/plugins-learn.test.js +62 -0
  12. package/__tests__/plugins-registry.test.js +3 -1
  13. package/__tests__/resend-plugin.test.js +122 -0
  14. package/__tests__/skills.test.js +4 -0
  15. package/cli/adapter-schema.js +3 -2
  16. package/cli/adapters/mcp.js +22 -3
  17. package/cli/adapters/process.js +34 -7
  18. package/cli/config.js +27 -1
  19. package/cli/help-json.js +2 -2
  20. package/cli/mcp-diagnostics.js +152 -0
  21. package/cli/mcp-discovery.js +221 -0
  22. package/cli/mcp-local.js +267 -25
  23. package/cli/mcp-stdio-jsonrpc.js +246 -0
  24. package/cli/plugin-install-guidance.js +25 -0
  25. package/cli/plugins-command.js +86 -3
  26. package/cli/plugins-learn.js +177 -0
  27. package/cli/plugins-manager.js +3 -0
  28. package/cli/plugins-registry.js +2 -1
  29. package/cli/skills-mcp.js +102 -0
  30. package/cli/skills.js +6 -40
  31. package/cli/supercli.js +7 -2
  32. package/docs/initial/mcp-local-mode.md +35 -0
  33. package/docs/mcp-cheatsheet.md +324 -0
  34. package/docs/plugins.md +7 -0
  35. package/package.json +1 -1
  36. package/plugins/browser-use/plugin.json +23 -0
  37. package/plugins/browser-use/scripts/post-install.js +146 -0
  38. package/plugins/browser-use/scripts/post-uninstall.js +28 -0
  39. package/plugins/browser-use/skills/quickstart/SKILL.md +47 -0
  40. package/plugins/monty/README.md +49 -0
  41. package/plugins/monty/plugin.json +69 -0
  42. package/plugins/monty/scripts/post-install.js +73 -0
  43. package/plugins/monty/scripts/post-uninstall.js +23 -0
  44. package/plugins/monty/scripts/run-python.js +140 -0
  45. package/plugins/monty/scripts/setup-monty.js +27 -0
  46. package/plugins/plugins.json +29 -0
  47. package/plugins/resend/plugin.json +371 -0
  48. package/plugins/resend/scripts/post-install.js +59 -0
  49. package/plugins/resend/scripts/post-uninstall.js +23 -0
  50. package/plugins/resend/scripts/setup-resend.js +27 -0
  51. package/plugins/resend/skills/quickstart/SKILL.md +80 -0
  52. package/ref-monty/.cargo/config.toml +3 -0
  53. package/ref-monty/.claude/settings.json +60 -0
  54. package/ref-monty/.claude/skills/fastmod/SKILL.md +22 -0
  55. package/ref-monty/.claude/skills/python-playground/SKILL.md +47 -0
  56. package/ref-monty/.codecov.yml +12 -0
  57. package/ref-monty/.github/actions/build-pgo-wheel/action.yml +72 -0
  58. package/ref-monty/.github/workflows/ci.yml +776 -0
  59. package/ref-monty/.github/workflows/codspeed.yml +45 -0
  60. package/ref-monty/.github/workflows/init-npm-packages.yml +82 -0
  61. package/ref-monty/.pre-commit-config.yaml +47 -0
  62. package/ref-monty/.python-version +1 -0
  63. package/ref-monty/.rustfmt.toml +4 -0
  64. package/ref-monty/.zed/settings.json +11 -0
  65. package/ref-monty/CLAUDE.md +535 -0
  66. package/ref-monty/Cargo.lock +3798 -0
  67. package/ref-monty/Cargo.toml +87 -0
  68. package/ref-monty/LICENSE +21 -0
  69. package/ref-monty/Makefile +216 -0
  70. package/ref-monty/README.md +430 -0
  71. package/ref-monty/RELEASING.md +47 -0
  72. package/ref-monty/crates/fuzz/Cargo.toml +30 -0
  73. package/ref-monty/crates/fuzz/fuzz_targets/string_input_panic.rs +37 -0
  74. package/ref-monty/crates/fuzz/fuzz_targets/tokens_input_panic.rs +552 -0
  75. package/ref-monty/crates/monty/Cargo.toml +68 -0
  76. package/ref-monty/crates/monty/benches/main.rs +247 -0
  77. package/ref-monty/crates/monty/build.rs +10 -0
  78. package/ref-monty/crates/monty/src/args.rs +733 -0
  79. package/ref-monty/crates/monty/src/asyncio.rs +179 -0
  80. package/ref-monty/crates/monty/src/builtins/abs.rs +55 -0
  81. package/ref-monty/crates/monty/src/builtins/all.rs +30 -0
  82. package/ref-monty/crates/monty/src/builtins/any.rs +30 -0
  83. package/ref-monty/crates/monty/src/builtins/bin.rs +59 -0
  84. package/ref-monty/crates/monty/src/builtins/chr.rs +46 -0
  85. package/ref-monty/crates/monty/src/builtins/divmod.rs +164 -0
  86. package/ref-monty/crates/monty/src/builtins/enumerate.rs +52 -0
  87. package/ref-monty/crates/monty/src/builtins/filter.rs +67 -0
  88. package/ref-monty/crates/monty/src/builtins/getattr.rs +65 -0
  89. package/ref-monty/crates/monty/src/builtins/hash.rs +28 -0
  90. package/ref-monty/crates/monty/src/builtins/hex.rs +58 -0
  91. package/ref-monty/crates/monty/src/builtins/id.rs +24 -0
  92. package/ref-monty/crates/monty/src/builtins/isinstance.rs +68 -0
  93. package/ref-monty/crates/monty/src/builtins/len.rs +25 -0
  94. package/ref-monty/crates/monty/src/builtins/map.rs +98 -0
  95. package/ref-monty/crates/monty/src/builtins/min_max.rs +113 -0
  96. package/ref-monty/crates/monty/src/builtins/mod.rs +246 -0
  97. package/ref-monty/crates/monty/src/builtins/next.rs +21 -0
  98. package/ref-monty/crates/monty/src/builtins/oct.rs +59 -0
  99. package/ref-monty/crates/monty/src/builtins/ord.rs +67 -0
  100. package/ref-monty/crates/monty/src/builtins/pow.rs +365 -0
  101. package/ref-monty/crates/monty/src/builtins/print.rs +141 -0
  102. package/ref-monty/crates/monty/src/builtins/repr.rs +16 -0
  103. package/ref-monty/crates/monty/src/builtins/reversed.rs +28 -0
  104. package/ref-monty/crates/monty/src/builtins/round.rs +174 -0
  105. package/ref-monty/crates/monty/src/builtins/sorted.rs +151 -0
  106. package/ref-monty/crates/monty/src/builtins/sum.rs +66 -0
  107. package/ref-monty/crates/monty/src/builtins/type_.rs +16 -0
  108. package/ref-monty/crates/monty/src/builtins/zip.rs +77 -0
  109. package/ref-monty/crates/monty/src/bytecode/builder.rs +699 -0
  110. package/ref-monty/crates/monty/src/bytecode/code.rs +310 -0
  111. package/ref-monty/crates/monty/src/bytecode/compiler.rs +3206 -0
  112. package/ref-monty/crates/monty/src/bytecode/mod.rs +24 -0
  113. package/ref-monty/crates/monty/src/bytecode/op.rs +617 -0
  114. package/ref-monty/crates/monty/src/bytecode/vm/async_exec.rs +1058 -0
  115. package/ref-monty/crates/monty/src/bytecode/vm/attr.rs +63 -0
  116. package/ref-monty/crates/monty/src/bytecode/vm/binary.rs +487 -0
  117. package/ref-monty/crates/monty/src/bytecode/vm/call.rs +767 -0
  118. package/ref-monty/crates/monty/src/bytecode/vm/collections.rs +741 -0
  119. package/ref-monty/crates/monty/src/bytecode/vm/compare.rs +147 -0
  120. package/ref-monty/crates/monty/src/bytecode/vm/exceptions.rs +297 -0
  121. package/ref-monty/crates/monty/src/bytecode/vm/format.rs +132 -0
  122. package/ref-monty/crates/monty/src/bytecode/vm/mod.rs +1958 -0
  123. package/ref-monty/crates/monty/src/bytecode/vm/scheduler.rs +620 -0
  124. package/ref-monty/crates/monty/src/exception_private.rs +1513 -0
  125. package/ref-monty/crates/monty/src/exception_public.rs +346 -0
  126. package/ref-monty/crates/monty/src/expressions.rs +694 -0
  127. package/ref-monty/crates/monty/src/fstring.rs +854 -0
  128. package/ref-monty/crates/monty/src/function.rs +119 -0
  129. package/ref-monty/crates/monty/src/heap.rs +1073 -0
  130. package/ref-monty/crates/monty/src/heap_data.rs +985 -0
  131. package/ref-monty/crates/monty/src/heap_traits.rs +312 -0
  132. package/ref-monty/crates/monty/src/intern.rs +837 -0
  133. package/ref-monty/crates/monty/src/io.rs +106 -0
  134. package/ref-monty/crates/monty/src/lib.rs +52 -0
  135. package/ref-monty/crates/monty/src/modules/asyncio.rs +144 -0
  136. package/ref-monty/crates/monty/src/modules/math.rs +1453 -0
  137. package/ref-monty/crates/monty/src/modules/mod.rs +120 -0
  138. package/ref-monty/crates/monty/src/modules/os.rs +116 -0
  139. package/ref-monty/crates/monty/src/modules/pathlib.rs +33 -0
  140. package/ref-monty/crates/monty/src/modules/re.rs +606 -0
  141. package/ref-monty/crates/monty/src/modules/sys.rs +60 -0
  142. package/ref-monty/crates/monty/src/modules/typing.rs +70 -0
  143. package/ref-monty/crates/monty/src/namespace.rs +21 -0
  144. package/ref-monty/crates/monty/src/object.rs +1040 -0
  145. package/ref-monty/crates/monty/src/os.rs +215 -0
  146. package/ref-monty/crates/monty/src/parse.rs +1730 -0
  147. package/ref-monty/crates/monty/src/prepare.rs +3015 -0
  148. package/ref-monty/crates/monty/src/repl.rs +1109 -0
  149. package/ref-monty/crates/monty/src/resource.rs +559 -0
  150. package/ref-monty/crates/monty/src/run.rs +457 -0
  151. package/ref-monty/crates/monty/src/run_progress.rs +821 -0
  152. package/ref-monty/crates/monty/src/signature.rs +651 -0
  153. package/ref-monty/crates/monty/src/sorting.rs +100 -0
  154. package/ref-monty/crates/monty/src/types/bytes.rs +2356 -0
  155. package/ref-monty/crates/monty/src/types/dataclass.rs +345 -0
  156. package/ref-monty/crates/monty/src/types/dict.rs +879 -0
  157. package/ref-monty/crates/monty/src/types/dict_view.rs +619 -0
  158. package/ref-monty/crates/monty/src/types/iter.rs +799 -0
  159. package/ref-monty/crates/monty/src/types/list.rs +929 -0
  160. package/ref-monty/crates/monty/src/types/long_int.rs +211 -0
  161. package/ref-monty/crates/monty/src/types/mod.rs +48 -0
  162. package/ref-monty/crates/monty/src/types/module.rs +146 -0
  163. package/ref-monty/crates/monty/src/types/namedtuple.rs +261 -0
  164. package/ref-monty/crates/monty/src/types/path.rs +596 -0
  165. package/ref-monty/crates/monty/src/types/property.rs +35 -0
  166. package/ref-monty/crates/monty/src/types/py_trait.rs +322 -0
  167. package/ref-monty/crates/monty/src/types/range.rs +285 -0
  168. package/ref-monty/crates/monty/src/types/re_match.rs +522 -0
  169. package/ref-monty/crates/monty/src/types/re_pattern.rs +726 -0
  170. package/ref-monty/crates/monty/src/types/set.rs +1373 -0
  171. package/ref-monty/crates/monty/src/types/slice.rs +257 -0
  172. package/ref-monty/crates/monty/src/types/str.rs +2051 -0
  173. package/ref-monty/crates/monty/src/types/tuple.rs +376 -0
  174. package/ref-monty/crates/monty/src/types/type.rs +407 -0
  175. package/ref-monty/crates/monty/src/value.rs +2558 -0
  176. package/ref-monty/crates/monty/test_cases/args__dict_get_no_args.py +3 -0
  177. package/ref-monty/crates/monty/test_cases/args__dict_get_too_many.py +3 -0
  178. package/ref-monty/crates/monty/test_cases/args__dict_items_with_args.py +3 -0
  179. package/ref-monty/crates/monty/test_cases/args__dict_keys_with_args.py +3 -0
  180. package/ref-monty/crates/monty/test_cases/args__dict_pop_no_args.py +3 -0
  181. package/ref-monty/crates/monty/test_cases/args__dict_pop_too_many.py +3 -0
  182. package/ref-monty/crates/monty/test_cases/args__dict_values_with_args.py +3 -0
  183. package/ref-monty/crates/monty/test_cases/args__id_too_many.py +2 -0
  184. package/ref-monty/crates/monty/test_cases/args__len_no_args.py +2 -0
  185. package/ref-monty/crates/monty/test_cases/args__len_too_many.py +2 -0
  186. package/ref-monty/crates/monty/test_cases/args__len_type_error_int.py +9 -0
  187. package/ref-monty/crates/monty/test_cases/args__len_type_error_none.py +9 -0
  188. package/ref-monty/crates/monty/test_cases/args__list_append_no_args.py +3 -0
  189. package/ref-monty/crates/monty/test_cases/args__list_append_too_many.py +3 -0
  190. package/ref-monty/crates/monty/test_cases/args__list_insert_too_few.py +3 -0
  191. package/ref-monty/crates/monty/test_cases/args__list_insert_too_many.py +3 -0
  192. package/ref-monty/crates/monty/test_cases/args__repr_no_args.py +2 -0
  193. package/ref-monty/crates/monty/test_cases/arith__div_zero_float.py +2 -0
  194. package/ref-monty/crates/monty/test_cases/arith__div_zero_int.py +2 -0
  195. package/ref-monty/crates/monty/test_cases/arith__floordiv_zero_float.py +2 -0
  196. package/ref-monty/crates/monty/test_cases/arith__floordiv_zero_int.py +2 -0
  197. package/ref-monty/crates/monty/test_cases/arith__pow_zero_neg.py +2 -0
  198. package/ref-monty/crates/monty/test_cases/arith__pow_zero_neg_builtin.py +9 -0
  199. package/ref-monty/crates/monty/test_cases/assert__expr_fail.py +2 -0
  200. package/ref-monty/crates/monty/test_cases/assert__fail.py +2 -0
  201. package/ref-monty/crates/monty/test_cases/assert__fail_msg.py +2 -0
  202. package/ref-monty/crates/monty/test_cases/assert__fn_fail.py +3 -0
  203. package/ref-monty/crates/monty/test_cases/assert__ops.py +11 -0
  204. package/ref-monty/crates/monty/test_cases/async__asyncio_run.py +47 -0
  205. package/ref-monty/crates/monty/test_cases/async__basic.py +10 -0
  206. package/ref-monty/crates/monty/test_cases/async__closure.py +14 -0
  207. package/ref-monty/crates/monty/test_cases/async__double_await_coroutine.py +16 -0
  208. package/ref-monty/crates/monty/test_cases/async__exception.py +10 -0
  209. package/ref-monty/crates/monty/test_cases/async__ext_call.py +73 -0
  210. package/ref-monty/crates/monty/test_cases/async__gather_all.py +85 -0
  211. package/ref-monty/crates/monty/test_cases/async__nested_await.py +15 -0
  212. package/ref-monty/crates/monty/test_cases/async__nested_gather_ext.py +37 -0
  213. package/ref-monty/crates/monty/test_cases/async__not_awaitable.py +10 -0
  214. package/ref-monty/crates/monty/test_cases/async__not_imported.py +14 -0
  215. package/ref-monty/crates/monty/test_cases/async__recursion_depth_isolation.py +27 -0
  216. package/ref-monty/crates/monty/test_cases/async__return_types.py +31 -0
  217. package/ref-monty/crates/monty/test_cases/async__sequential.py +16 -0
  218. package/ref-monty/crates/monty/test_cases/async__traceback.py +19 -0
  219. package/ref-monty/crates/monty/test_cases/async__with_args.py +14 -0
  220. package/ref-monty/crates/monty/test_cases/attr__get_int_error.py +9 -0
  221. package/ref-monty/crates/monty/test_cases/attr__get_list_error.py +9 -0
  222. package/ref-monty/crates/monty/test_cases/attr__set_frozen_nonfield.py +12 -0
  223. package/ref-monty/crates/monty/test_cases/attr__set_int_error.py +10 -0
  224. package/ref-monty/crates/monty/test_cases/attr__set_list_error.py +10 -0
  225. package/ref-monty/crates/monty/test_cases/bench__kitchen_sink.py +68 -0
  226. package/ref-monty/crates/monty/test_cases/bool__ops.py +20 -0
  227. package/ref-monty/crates/monty/test_cases/builtin__add_type_error.py +2 -0
  228. package/ref-monty/crates/monty/test_cases/builtin__filter.py +62 -0
  229. package/ref-monty/crates/monty/test_cases/builtin__filter_not_iterable.py +11 -0
  230. package/ref-monty/crates/monty/test_cases/builtin__getattr.py +84 -0
  231. package/ref-monty/crates/monty/test_cases/builtin__iter_funcs.py +42 -0
  232. package/ref-monty/crates/monty/test_cases/builtin__iter_next.py +66 -0
  233. package/ref-monty/crates/monty/test_cases/builtin__map.py +74 -0
  234. package/ref-monty/crates/monty/test_cases/builtin__map_not_iterable.py +11 -0
  235. package/ref-monty/crates/monty/test_cases/builtin__math_funcs.py +154 -0
  236. package/ref-monty/crates/monty/test_cases/builtin__more_iter_funcs.py +148 -0
  237. package/ref-monty/crates/monty/test_cases/builtin__next_stop_iteration.py +10 -0
  238. package/ref-monty/crates/monty/test_cases/builtin__print_invalid_kwarg.py +9 -0
  239. package/ref-monty/crates/monty/test_cases/builtin__print_kwargs.py +12 -0
  240. package/ref-monty/crates/monty/test_cases/builtin__repr.py +3 -0
  241. package/ref-monty/crates/monty/test_cases/builtin__string_funcs.py +73 -0
  242. package/ref-monty/crates/monty/test_cases/bytes__decode_invalid_utf8.py +18 -0
  243. package/ref-monty/crates/monty/test_cases/bytes__endswith_str_error.py +10 -0
  244. package/ref-monty/crates/monty/test_cases/bytes__getitem_index_error.py +10 -0
  245. package/ref-monty/crates/monty/test_cases/bytes__index_start_gt_end.py +10 -0
  246. package/ref-monty/crates/monty/test_cases/bytes__methods.py +394 -0
  247. package/ref-monty/crates/monty/test_cases/bytes__negative_count.py +9 -0
  248. package/ref-monty/crates/monty/test_cases/bytes__ops.py +90 -0
  249. package/ref-monty/crates/monty/test_cases/bytes__startswith_str_error.py +10 -0
  250. package/ref-monty/crates/monty/test_cases/call_object.py +3 -0
  251. package/ref-monty/crates/monty/test_cases/chain_comparison__all.py +79 -0
  252. package/ref-monty/crates/monty/test_cases/closure__param_shadows_outer.py +81 -0
  253. package/ref-monty/crates/monty/test_cases/closure__pep448.py +203 -0
  254. package/ref-monty/crates/monty/test_cases/closure__undefined_nonlocal.py +13 -0
  255. package/ref-monty/crates/monty/test_cases/compare__mixed_types.py +120 -0
  256. package/ref-monty/crates/monty/test_cases/comprehension__all.py +208 -0
  257. package/ref-monty/crates/monty/test_cases/comprehension__scope.py +7 -0
  258. package/ref-monty/crates/monty/test_cases/comprehension__unbound_local.py +14 -0
  259. package/ref-monty/crates/monty/test_cases/dataclass__basic.py +238 -0
  260. package/ref-monty/crates/monty/test_cases/dataclass__call_field_error.py +12 -0
  261. package/ref-monty/crates/monty/test_cases/dataclass__frozen_set_error.py +12 -0
  262. package/ref-monty/crates/monty/test_cases/dataclass__get_missing_attr_error.py +11 -0
  263. package/ref-monty/crates/monty/test_cases/dict__get_unhashable_key.py +3 -0
  264. package/ref-monty/crates/monty/test_cases/dict__literal_unhashable_key.py +2 -0
  265. package/ref-monty/crates/monty/test_cases/dict__method_pop_missing_error.py +3 -0
  266. package/ref-monty/crates/monty/test_cases/dict__methods.py +151 -0
  267. package/ref-monty/crates/monty/test_cases/dict__ops.py +133 -0
  268. package/ref-monty/crates/monty/test_cases/dict__pop_unhashable_key.py +4 -0
  269. package/ref-monty/crates/monty/test_cases/dict__popitem_empty.py +9 -0
  270. package/ref-monty/crates/monty/test_cases/dict__subscript_missing_key.py +3 -0
  271. package/ref-monty/crates/monty/test_cases/dict__unhashable_dict_key.py +2 -0
  272. package/ref-monty/crates/monty/test_cases/dict__unhashable_list_key.py +2 -0
  273. package/ref-monty/crates/monty/test_cases/dict__unpack_type_error.py +2 -0
  274. package/ref-monty/crates/monty/test_cases/dict__views.py +165 -0
  275. package/ref-monty/crates/monty/test_cases/edge__all.py +26 -0
  276. package/ref-monty/crates/monty/test_cases/edge__float_int_mod.py +2 -0
  277. package/ref-monty/crates/monty/test_cases/edge__int_float_mod.py +2 -0
  278. package/ref-monty/crates/monty/test_cases/exc__args.py +16 -0
  279. package/ref-monty/crates/monty/test_cases/exc__str.py +15 -0
  280. package/ref-monty/crates/monty/test_cases/execute_ok__all.py +54 -0
  281. package/ref-monty/crates/monty/test_cases/execute_raise__error_instance_str.py +2 -0
  282. package/ref-monty/crates/monty/test_cases/execute_raise__error_no_args.py +2 -0
  283. package/ref-monty/crates/monty/test_cases/execute_raise__error_string_arg.py +2 -0
  284. package/ref-monty/crates/monty/test_cases/execute_raise__error_string_arg_quotes.py +2 -0
  285. package/ref-monty/crates/monty/test_cases/execute_raise__error_type.py +2 -0
  286. package/ref-monty/crates/monty/test_cases/execute_raise__raise_instance_via_var.py +4 -0
  287. package/ref-monty/crates/monty/test_cases/execute_raise__raise_list.py +2 -0
  288. package/ref-monty/crates/monty/test_cases/execute_raise__raise_number.py +2 -0
  289. package/ref-monty/crates/monty/test_cases/execute_raise__raise_type_call_via_var.py +4 -0
  290. package/ref-monty/crates/monty/test_cases/execute_raise__raise_type_direct.py +3 -0
  291. package/ref-monty/crates/monty/test_cases/execute_raise__raise_type_via_var.py +4 -0
  292. package/ref-monty/crates/monty/test_cases/ext_call__arg_side_effect_bug.py +22 -0
  293. package/ref-monty/crates/monty/test_cases/ext_call__augmented.py +17 -0
  294. package/ref-monty/crates/monty/test_cases/ext_call__augmented_refcount_bug.py +7 -0
  295. package/ref-monty/crates/monty/test_cases/ext_call__bare_raise_after_resume.py +34 -0
  296. package/ref-monty/crates/monty/test_cases/ext_call__basic.py +99 -0
  297. package/ref-monty/crates/monty/test_cases/ext_call__boolean.py +37 -0
  298. package/ref-monty/crates/monty/test_cases/ext_call__boolean_side_effect_hang.py +17 -0
  299. package/ref-monty/crates/monty/test_cases/ext_call__closure_bug.py +16 -0
  300. package/ref-monty/crates/monty/test_cases/ext_call__comparison.py +26 -0
  301. package/ref-monty/crates/monty/test_cases/ext_call__deep_call_stack.py +18 -0
  302. package/ref-monty/crates/monty/test_cases/ext_call__elif.py +171 -0
  303. package/ref-monty/crates/monty/test_cases/ext_call__exc.py +4 -0
  304. package/ref-monty/crates/monty/test_cases/ext_call__exc_deep_stack.py +39 -0
  305. package/ref-monty/crates/monty/test_cases/ext_call__exc_in_function.py +17 -0
  306. package/ref-monty/crates/monty/test_cases/ext_call__exc_nested_functions.py +31 -0
  307. package/ref-monty/crates/monty/test_cases/ext_call__ext_exc.py +171 -0
  308. package/ref-monty/crates/monty/test_cases/ext_call__for.py +114 -0
  309. package/ref-monty/crates/monty/test_cases/ext_call__fstring.py +12 -0
  310. package/ref-monty/crates/monty/test_cases/ext_call__if.py +135 -0
  311. package/ref-monty/crates/monty/test_cases/ext_call__if_condition.py +37 -0
  312. package/ref-monty/crates/monty/test_cases/ext_call__in_closure.py +14 -0
  313. package/ref-monty/crates/monty/test_cases/ext_call__in_function.py +40 -0
  314. package/ref-monty/crates/monty/test_cases/ext_call__in_function_simple.py +7 -0
  315. package/ref-monty/crates/monty/test_cases/ext_call__literals.py +17 -0
  316. package/ref-monty/crates/monty/test_cases/ext_call__multi_in_func.py +32 -0
  317. package/ref-monty/crates/monty/test_cases/ext_call__name_lookup.py +69 -0
  318. package/ref-monty/crates/monty/test_cases/ext_call__name_lookup_undefined.py +4 -0
  319. package/ref-monty/crates/monty/test_cases/ext_call__nested_calls.py +14 -0
  320. package/ref-monty/crates/monty/test_cases/ext_call__recursion_bug.py +19 -0
  321. package/ref-monty/crates/monty/test_cases/ext_call__return.py +28 -0
  322. package/ref-monty/crates/monty/test_cases/ext_call__side_effects.py +25 -0
  323. package/ref-monty/crates/monty/test_cases/ext_call__subscript.py +7 -0
  324. package/ref-monty/crates/monty/test_cases/ext_call__ternary.py +28 -0
  325. package/ref-monty/crates/monty/test_cases/ext_call__try.py +280 -0
  326. package/ref-monty/crates/monty/test_cases/ext_call__try_simple.py +10 -0
  327. package/ref-monty/crates/monty/test_cases/ext_call__unary.py +13 -0
  328. package/ref-monty/crates/monty/test_cases/frozenset__ops.py +178 -0
  329. package/ref-monty/crates/monty/test_cases/fstring__all.py +236 -0
  330. package/ref-monty/crates/monty/test_cases/fstring__error_eq_align_on_str.py +3 -0
  331. package/ref-monty/crates/monty/test_cases/fstring__error_float_f_on_str.py +3 -0
  332. package/ref-monty/crates/monty/test_cases/fstring__error_int_d_on_float.py +3 -0
  333. package/ref-monty/crates/monty/test_cases/fstring__error_int_d_on_str.py +3 -0
  334. package/ref-monty/crates/monty/test_cases/fstring__error_invalid_spec.py +4 -0
  335. package/ref-monty/crates/monty/test_cases/fstring__error_invalid_spec_dynamic.py +4 -0
  336. package/ref-monty/crates/monty/test_cases/fstring__error_invalid_spec_str.py +4 -0
  337. package/ref-monty/crates/monty/test_cases/fstring__error_str_s_on_int.py +3 -0
  338. package/ref-monty/crates/monty/test_cases/function__call_duplicate_kwargs.py +6 -0
  339. package/ref-monty/crates/monty/test_cases/function__call_unpack.py +42 -0
  340. package/ref-monty/crates/monty/test_cases/function__defaults.py +117 -0
  341. package/ref-monty/crates/monty/test_cases/function__err_duplicate_arg.py +7 -0
  342. package/ref-monty/crates/monty/test_cases/function__err_duplicate_first_arg.py +7 -0
  343. package/ref-monty/crates/monty/test_cases/function__err_duplicate_kwarg_cleanup.py +9 -0
  344. package/ref-monty/crates/monty/test_cases/function__err_kwonly_as_positional.py +7 -0
  345. package/ref-monty/crates/monty/test_cases/function__err_missing_all_posonly.py +7 -0
  346. package/ref-monty/crates/monty/test_cases/function__err_missing_heap_cleanup.py +9 -0
  347. package/ref-monty/crates/monty/test_cases/function__err_missing_kwonly.py +7 -0
  348. package/ref-monty/crates/monty/test_cases/function__err_missing_posonly_with_kwarg.py +7 -0
  349. package/ref-monty/crates/monty/test_cases/function__err_missing_with_posonly.py +7 -0
  350. package/ref-monty/crates/monty/test_cases/function__err_posonly_as_kwarg.py +7 -0
  351. package/ref-monty/crates/monty/test_cases/function__err_posonly_first_as_kwarg.py +7 -0
  352. package/ref-monty/crates/monty/test_cases/function__err_too_many_posonly.py +7 -0
  353. package/ref-monty/crates/monty/test_cases/function__err_too_many_with_kwonly.py +7 -0
  354. package/ref-monty/crates/monty/test_cases/function__err_unexpected_kwarg.py +7 -0
  355. package/ref-monty/crates/monty/test_cases/function__err_unexpected_kwarg_cleanup.py +9 -0
  356. package/ref-monty/crates/monty/test_cases/function__err_unexpected_kwarg_quote.py +13 -0
  357. package/ref-monty/crates/monty/test_cases/function__err_unexpected_kwarg_simple.py +7 -0
  358. package/ref-monty/crates/monty/test_cases/function__err_unpack_duplicate_arg.py +6 -0
  359. package/ref-monty/crates/monty/test_cases/function__err_unpack_duplicate_heap.py +8 -0
  360. package/ref-monty/crates/monty/test_cases/function__err_unpack_int.py +6 -0
  361. package/ref-monty/crates/monty/test_cases/function__err_unpack_nonstring_key.py +6 -0
  362. package/ref-monty/crates/monty/test_cases/function__err_unpack_not_mapping.py +6 -0
  363. package/ref-monty/crates/monty/test_cases/function__kwargs_unpacking.py +173 -0
  364. package/ref-monty/crates/monty/test_cases/function__ops.py +294 -0
  365. package/ref-monty/crates/monty/test_cases/function__return_none.py +42 -0
  366. package/ref-monty/crates/monty/test_cases/function__signatures.py +47 -0
  367. package/ref-monty/crates/monty/test_cases/function__too_few_args_all.py +6 -0
  368. package/ref-monty/crates/monty/test_cases/function__too_few_args_one.py +6 -0
  369. package/ref-monty/crates/monty/test_cases/function__too_few_args_two.py +6 -0
  370. package/ref-monty/crates/monty/test_cases/function__too_many_args_one.py +6 -0
  371. package/ref-monty/crates/monty/test_cases/function__too_many_args_two.py +6 -0
  372. package/ref-monty/crates/monty/test_cases/function__too_many_args_zero.py +6 -0
  373. package/ref-monty/crates/monty/test_cases/global__error_assigned_before.py +7 -0
  374. package/ref-monty/crates/monty/test_cases/global__ops.py +163 -0
  375. package/ref-monty/crates/monty/test_cases/hash__dict_unhashable.py +2 -0
  376. package/ref-monty/crates/monty/test_cases/hash__list_unhashable.py +2 -0
  377. package/ref-monty/crates/monty/test_cases/hash__ops.py +153 -0
  378. package/ref-monty/crates/monty/test_cases/id__bytes_literals_distinct.py +3 -0
  379. package/ref-monty/crates/monty/test_cases/id__int_copy_distinct.py +5 -0
  380. package/ref-monty/crates/monty/test_cases/id__is_number_is_number.py +3 -0
  381. package/ref-monty/crates/monty/test_cases/id__non_overlapping_lifetimes_distinct_types.py +10 -0
  382. package/ref-monty/crates/monty/test_cases/id__non_overlapping_lifetimes_same_types.py +6 -0
  383. package/ref-monty/crates/monty/test_cases/id__ops.py +97 -0
  384. package/ref-monty/crates/monty/test_cases/id__str_literals_same.py +3 -0
  385. package/ref-monty/crates/monty/test_cases/if__elif_else.py +207 -0
  386. package/ref-monty/crates/monty/test_cases/if__raise_elif.py +11 -0
  387. package/ref-monty/crates/monty/test_cases/if__raise_else.py +13 -0
  388. package/ref-monty/crates/monty/test_cases/if__raise_if.py +9 -0
  389. package/ref-monty/crates/monty/test_cases/if__raise_in_elif_condition.py +18 -0
  390. package/ref-monty/crates/monty/test_cases/if__raise_in_if_condition.py +16 -0
  391. package/ref-monty/crates/monty/test_cases/if_else_expr__all.py +55 -0
  392. package/ref-monty/crates/monty/test_cases/import__error_cannot_import.py +9 -0
  393. package/ref-monty/crates/monty/test_cases/import__error_module_not_found.py +9 -0
  394. package/ref-monty/crates/monty/test_cases/import__local_scope.py +68 -0
  395. package/ref-monty/crates/monty/test_cases/import__os.py +25 -0
  396. package/ref-monty/crates/monty/test_cases/import__relative_error.py +9 -0
  397. package/ref-monty/crates/monty/test_cases/import__relative_no_module_error.py +9 -0
  398. package/ref-monty/crates/monty/test_cases/import__runtime_error_when_executed.py +14 -0
  399. package/ref-monty/crates/monty/test_cases/import__star_error.py +11 -0
  400. package/ref-monty/crates/monty/test_cases/import__sys.py +47 -0
  401. package/ref-monty/crates/monty/test_cases/import__sys_monty.py +28 -0
  402. package/ref-monty/crates/monty/test_cases/import__type_checking_guard.py +37 -0
  403. package/ref-monty/crates/monty/test_cases/import__typing.py +25 -0
  404. package/ref-monty/crates/monty/test_cases/import__typing_type_ignore.py +4 -0
  405. package/ref-monty/crates/monty/test_cases/int__bigint.py +467 -0
  406. package/ref-monty/crates/monty/test_cases/int__bigint_errors.py +260 -0
  407. package/ref-monty/crates/monty/test_cases/int__ops.py +219 -0
  408. package/ref-monty/crates/monty/test_cases/int__overflow_division.py +84 -0
  409. package/ref-monty/crates/monty/test_cases/is_variant__all.py +36 -0
  410. package/ref-monty/crates/monty/test_cases/isinstance__arg2_list_error.py +2 -0
  411. package/ref-monty/crates/monty/test_cases/isinstance__arg2_type_error.py +2 -0
  412. package/ref-monty/crates/monty/test_cases/iter__dict_mutation.py +4 -0
  413. package/ref-monty/crates/monty/test_cases/iter__for.py +243 -0
  414. package/ref-monty/crates/monty/test_cases/iter__for_loop_unpacking.py +66 -0
  415. package/ref-monty/crates/monty/test_cases/iter__generator_expr.py +20 -0
  416. package/ref-monty/crates/monty/test_cases/iter__generator_expr_type.py +7 -0
  417. package/ref-monty/crates/monty/test_cases/iter__not_iterable.py +3 -0
  418. package/ref-monty/crates/monty/test_cases/lambda__all.py +145 -0
  419. package/ref-monty/crates/monty/test_cases/list__extend_not_iterable.py +7 -0
  420. package/ref-monty/crates/monty/test_cases/list__getitem_out_of_bounds.py +3 -0
  421. package/ref-monty/crates/monty/test_cases/list__index_not_found.py +9 -0
  422. package/ref-monty/crates/monty/test_cases/list__index_start_gt_end.py +10 -0
  423. package/ref-monty/crates/monty/test_cases/list__ops.py +473 -0
  424. package/ref-monty/crates/monty/test_cases/list__pop_empty.py +9 -0
  425. package/ref-monty/crates/monty/test_cases/list__pop_out_of_range.py +9 -0
  426. package/ref-monty/crates/monty/test_cases/list__pop_type_error.py +9 -0
  427. package/ref-monty/crates/monty/test_cases/list__remove_not_found.py +9 -0
  428. package/ref-monty/crates/monty/test_cases/list__setitem_dict_index.py +13 -0
  429. package/ref-monty/crates/monty/test_cases/list__setitem_huge_int_index.py +13 -0
  430. package/ref-monty/crates/monty/test_cases/list__setitem_index_error.py +10 -0
  431. package/ref-monty/crates/monty/test_cases/list__setitem_type_error.py +10 -0
  432. package/ref-monty/crates/monty/test_cases/list__unpack_type_error.py +2 -0
  433. package/ref-monty/crates/monty/test_cases/longint__index_error.py +3 -0
  434. package/ref-monty/crates/monty/test_cases/longint__repeat_error.py +3 -0
  435. package/ref-monty/crates/monty/test_cases/loop__break_continue.py +113 -0
  436. package/ref-monty/crates/monty/test_cases/loop__break_finally.py +69 -0
  437. package/ref-monty/crates/monty/test_cases/loop__break_in_function_error.py +13 -0
  438. package/ref-monty/crates/monty/test_cases/loop__break_in_if_error.py +11 -0
  439. package/ref-monty/crates/monty/test_cases/loop__break_nested_except_clears.py +55 -0
  440. package/ref-monty/crates/monty/test_cases/loop__break_outside_error.py +9 -0
  441. package/ref-monty/crates/monty/test_cases/loop__continue_finally.py +81 -0
  442. package/ref-monty/crates/monty/test_cases/loop__continue_in_function_error.py +13 -0
  443. package/ref-monty/crates/monty/test_cases/loop__continue_in_if_error.py +11 -0
  444. package/ref-monty/crates/monty/test_cases/loop__continue_nested_except_clears.py +60 -0
  445. package/ref-monty/crates/monty/test_cases/loop__continue_outside_error.py +9 -0
  446. package/ref-monty/crates/monty/test_cases/math__acos_domain_error.py +11 -0
  447. package/ref-monty/crates/monty/test_cases/math__acosh_domain_error.py +11 -0
  448. package/ref-monty/crates/monty/test_cases/math__asin_domain_error.py +11 -0
  449. package/ref-monty/crates/monty/test_cases/math__atanh_domain_error.py +11 -0
  450. package/ref-monty/crates/monty/test_cases/math__cos_inf_error.py +11 -0
  451. package/ref-monty/crates/monty/test_cases/math__cosh_overflow_error.py +11 -0
  452. package/ref-monty/crates/monty/test_cases/math__exp_overflow_error.py +11 -0
  453. package/ref-monty/crates/monty/test_cases/math__factorial_float_error.py +11 -0
  454. package/ref-monty/crates/monty/test_cases/math__factorial_negative_error.py +11 -0
  455. package/ref-monty/crates/monty/test_cases/math__floor_inf_error.py +11 -0
  456. package/ref-monty/crates/monty/test_cases/math__floor_nan_error.py +11 -0
  457. package/ref-monty/crates/monty/test_cases/math__floor_str_error.py +11 -0
  458. package/ref-monty/crates/monty/test_cases/math__fmod_inf_error.py +11 -0
  459. package/ref-monty/crates/monty/test_cases/math__gamma_neg_int_error.py +11 -0
  460. package/ref-monty/crates/monty/test_cases/math__gcd_float_error.py +11 -0
  461. package/ref-monty/crates/monty/test_cases/math__isqrt_negative_error.py +11 -0
  462. package/ref-monty/crates/monty/test_cases/math__ldexp_overflow_error.py +11 -0
  463. package/ref-monty/crates/monty/test_cases/math__log1p_domain_error.py +11 -0
  464. package/ref-monty/crates/monty/test_cases/math__log_base1_error.py +11 -0
  465. package/ref-monty/crates/monty/test_cases/math__log_zero_error.py +11 -0
  466. package/ref-monty/crates/monty/test_cases/math__module.py +1432 -0
  467. package/ref-monty/crates/monty/test_cases/math__pow_domain_error.py +11 -0
  468. package/ref-monty/crates/monty/test_cases/math__sin_inf_error.py +11 -0
  469. package/ref-monty/crates/monty/test_cases/math__sqrt_negative_error.py +11 -0
  470. package/ref-monty/crates/monty/test_cases/math__tan_inf_error.py +11 -0
  471. package/ref-monty/crates/monty/test_cases/math__trunc_str_error.py +11 -0
  472. package/ref-monty/crates/monty/test_cases/method__args_kwargs_unpacking.py +259 -0
  473. package/ref-monty/crates/monty/test_cases/name_error__unbound_local_func.py +19 -0
  474. package/ref-monty/crates/monty/test_cases/name_error__unbound_local_module.py +12 -0
  475. package/ref-monty/crates/monty/test_cases/name_error__undefined_call_chained.py +9 -0
  476. package/ref-monty/crates/monty/test_cases/name_error__undefined_call_in_expr.py +9 -0
  477. package/ref-monty/crates/monty/test_cases/name_error__undefined_call_in_function.py +16 -0
  478. package/ref-monty/crates/monty/test_cases/name_error__undefined_call_with_args.py +9 -0
  479. package/ref-monty/crates/monty/test_cases/name_error__undefined_global.py +10 -0
  480. package/ref-monty/crates/monty/test_cases/namedtuple__missing_attr.py +11 -0
  481. package/ref-monty/crates/monty/test_cases/namedtuple__ops.py +34 -0
  482. package/ref-monty/crates/monty/test_cases/nonlocal__error_module_level.py +3 -0
  483. package/ref-monty/crates/monty/test_cases/nonlocal__ops.py +353 -0
  484. package/ref-monty/crates/monty/test_cases/os__environ.py +40 -0
  485. package/ref-monty/crates/monty/test_cases/os__getenv_key_list_error.py +5 -0
  486. package/ref-monty/crates/monty/test_cases/os__getenv_key_type_error.py +5 -0
  487. package/ref-monty/crates/monty/test_cases/parse_error__complex.py +3 -0
  488. package/ref-monty/crates/monty/test_cases/pathlib__import.py +11 -0
  489. package/ref-monty/crates/monty/test_cases/pathlib__os.py +136 -0
  490. package/ref-monty/crates/monty/test_cases/pathlib__os_read_error.py +12 -0
  491. package/ref-monty/crates/monty/test_cases/pathlib__pure.py +81 -0
  492. package/ref-monty/crates/monty/test_cases/pyobject__cycle_dict_self.py +5 -0
  493. package/ref-monty/crates/monty/test_cases/pyobject__cycle_list_dict.py +6 -0
  494. package/ref-monty/crates/monty/test_cases/pyobject__cycle_list_self.py +5 -0
  495. package/ref-monty/crates/monty/test_cases/pyobject__cycle_multiple_refs.py +6 -0
  496. package/ref-monty/crates/monty/test_cases/range__error_no_args.py +2 -0
  497. package/ref-monty/crates/monty/test_cases/range__error_step_zero.py +2 -0
  498. package/ref-monty/crates/monty/test_cases/range__error_too_many_args.py +2 -0
  499. package/ref-monty/crates/monty/test_cases/range__getitem_index_error.py +10 -0
  500. package/ref-monty/crates/monty/test_cases/range__ops.py +236 -0
  501. package/ref-monty/crates/monty/test_cases/re__basic.py +756 -0
  502. package/ref-monty/crates/monty/test_cases/re__grouping.py +241 -0
  503. package/ref-monty/crates/monty/test_cases/re__match.py +148 -0
  504. package/ref-monty/crates/monty/test_cases/recursion__deep_drop.py +26 -0
  505. package/ref-monty/crates/monty/test_cases/recursion__deep_eq.py +23 -0
  506. package/ref-monty/crates/monty/test_cases/recursion__deep_hash.py +46 -0
  507. package/ref-monty/crates/monty/test_cases/recursion__deep_repr.py +12 -0
  508. package/ref-monty/crates/monty/test_cases/recursion__function_depth.py +13 -0
  509. package/ref-monty/crates/monty/test_cases/refcount__cycle_mutual_reference.py +18 -0
  510. package/ref-monty/crates/monty/test_cases/refcount__cycle_self_reference.py +12 -0
  511. package/ref-monty/crates/monty/test_cases/refcount__dict_basic.py +5 -0
  512. package/ref-monty/crates/monty/test_cases/refcount__dict_get.py +5 -0
  513. package/ref-monty/crates/monty/test_cases/refcount__dict_keys_and.py +14 -0
  514. package/ref-monty/crates/monty/test_cases/refcount__dict_overwrite.py +6 -0
  515. package/ref-monty/crates/monty/test_cases/refcount__gather_cleanup.py +16 -0
  516. package/ref-monty/crates/monty/test_cases/refcount__gather_exception.py +18 -0
  517. package/ref-monty/crates/monty/test_cases/refcount__gather_nested_cancel.py +25 -0
  518. package/ref-monty/crates/monty/test_cases/refcount__immediate_skipped.py +4 -0
  519. package/ref-monty/crates/monty/test_cases/refcount__kwargs_unpacking.py +27 -0
  520. package/ref-monty/crates/monty/test_cases/refcount__list_append_multiple.py +6 -0
  521. package/ref-monty/crates/monty/test_cases/refcount__list_append_ref.py +5 -0
  522. package/ref-monty/crates/monty/test_cases/refcount__list_concat.py +5 -0
  523. package/ref-monty/crates/monty/test_cases/refcount__list_getitem.py +5 -0
  524. package/ref-monty/crates/monty/test_cases/refcount__list_iadd.py +5 -0
  525. package/ref-monty/crates/monty/test_cases/refcount__nested_list.py +4 -0
  526. package/ref-monty/crates/monty/test_cases/refcount__re_pattern_sub_error_paths.py +37 -0
  527. package/ref-monty/crates/monty/test_cases/refcount__re_search_match.py +34 -0
  528. package/ref-monty/crates/monty/test_cases/refcount__re_sub_error_paths.py +31 -0
  529. package/ref-monty/crates/monty/test_cases/refcount__shared_reference.py +4 -0
  530. package/ref-monty/crates/monty/test_cases/refcount__single_list.py +3 -0
  531. package/ref-monty/crates/monty/test_cases/repr__cycle_detection.py +24 -0
  532. package/ref-monty/crates/monty/test_cases/set__ops.py +191 -0
  533. package/ref-monty/crates/monty/test_cases/set__review_bugs.py +35 -0
  534. package/ref-monty/crates/monty/test_cases/set__unpack_type_error.py +2 -0
  535. package/ref-monty/crates/monty/test_cases/slice__invalid_indices.py +2 -0
  536. package/ref-monty/crates/monty/test_cases/slice__kwargs.py +9 -0
  537. package/ref-monty/crates/monty/test_cases/slice__no_args.py +9 -0
  538. package/ref-monty/crates/monty/test_cases/slice__ops.py +149 -0
  539. package/ref-monty/crates/monty/test_cases/slice__step_zero.py +9 -0
  540. package/ref-monty/crates/monty/test_cases/slice__step_zero_bytes.py +9 -0
  541. package/ref-monty/crates/monty/test_cases/slice__step_zero_range.py +9 -0
  542. package/ref-monty/crates/monty/test_cases/slice__step_zero_str.py +9 -0
  543. package/ref-monty/crates/monty/test_cases/slice__step_zero_tuple.py +9 -0
  544. package/ref-monty/crates/monty/test_cases/slice__too_many_args.py +9 -0
  545. package/ref-monty/crates/monty/test_cases/str__getitem_index_error.py +10 -0
  546. package/ref-monty/crates/monty/test_cases/str__index_not_found.py +9 -0
  547. package/ref-monty/crates/monty/test_cases/str__join_no_args.py +9 -0
  548. package/ref-monty/crates/monty/test_cases/str__join_non_string.py +9 -0
  549. package/ref-monty/crates/monty/test_cases/str__join_not_iterable.py +9 -0
  550. package/ref-monty/crates/monty/test_cases/str__join_too_many_args.py +9 -0
  551. package/ref-monty/crates/monty/test_cases/str__methods.py +327 -0
  552. package/ref-monty/crates/monty/test_cases/str__ops.py +162 -0
  553. package/ref-monty/crates/monty/test_cases/str__partition_empty.py +9 -0
  554. package/ref-monty/crates/monty/test_cases/str__rsplit_empty_sep.py +9 -0
  555. package/ref-monty/crates/monty/test_cases/str__split_empty_sep.py +9 -0
  556. package/ref-monty/crates/monty/test_cases/sys__types.py +7 -0
  557. package/ref-monty/crates/monty/test_cases/traceback__division_error.py +30 -0
  558. package/ref-monty/crates/monty/test_cases/traceback__index_error.py +17 -0
  559. package/ref-monty/crates/monty/test_cases/traceback__insert_as_int.py +10 -0
  560. package/ref-monty/crates/monty/test_cases/traceback__nested_call.py +29 -0
  561. package/ref-monty/crates/monty/test_cases/traceback__nonlocal_module_scope.py +10 -0
  562. package/ref-monty/crates/monty/test_cases/traceback__nonlocal_unbound.py +24 -0
  563. package/ref-monty/crates/monty/test_cases/traceback__range_as_int.py +9 -0
  564. package/ref-monty/crates/monty/test_cases/traceback__recursion_error.py +23 -0
  565. package/ref-monty/crates/monty/test_cases/traceback__set_mutation.py +11 -0
  566. package/ref-monty/crates/monty/test_cases/traceback__undefined_attr_call.py +16 -0
  567. package/ref-monty/crates/monty/test_cases/traceback__undefined_call.py +16 -0
  568. package/ref-monty/crates/monty/test_cases/traceback__undefined_raise.py +16 -0
  569. package/ref-monty/crates/monty/test_cases/try_except__all.py +472 -0
  570. package/ref-monty/crates/monty/test_cases/try_except__bare_raise_no_context.py +2 -0
  571. package/ref-monty/crates/monty/test_cases/try_except__invalid_type.py +5 -0
  572. package/ref-monty/crates/monty/test_cases/tuple__getitem_out_of_bounds.py +3 -0
  573. package/ref-monty/crates/monty/test_cases/tuple__index_not_found.py +9 -0
  574. package/ref-monty/crates/monty/test_cases/tuple__index_start_gt_end.py +10 -0
  575. package/ref-monty/crates/monty/test_cases/tuple__methods.py +19 -0
  576. package/ref-monty/crates/monty/test_cases/tuple__ops.py +133 -0
  577. package/ref-monty/crates/monty/test_cases/tuple__unpack_type_error.py +2 -0
  578. package/ref-monty/crates/monty/test_cases/type__builtin_attr_error.py +9 -0
  579. package/ref-monty/crates/monty/test_cases/type__bytes_negative.py +2 -0
  580. package/ref-monty/crates/monty/test_cases/type__cell_not_builtin.py +9 -0
  581. package/ref-monty/crates/monty/test_cases/type__exception_attr_error.py +11 -0
  582. package/ref-monty/crates/monty/test_cases/type__float_conversion_error.py +2 -0
  583. package/ref-monty/crates/monty/test_cases/type__float_repr_both_quotes.py +9 -0
  584. package/ref-monty/crates/monty/test_cases/type__float_repr_newline.py +9 -0
  585. package/ref-monty/crates/monty/test_cases/type__float_repr_single_quote.py +9 -0
  586. package/ref-monty/crates/monty/test_cases/type__int_conversion_error.py +2 -0
  587. package/ref-monty/crates/monty/test_cases/type__list_not_iterable.py +2 -0
  588. package/ref-monty/crates/monty/test_cases/type__non_builtin_name_error.py +9 -0
  589. package/ref-monty/crates/monty/test_cases/type__ops.py +200 -0
  590. package/ref-monty/crates/monty/test_cases/type__shadow_exc.py +3 -0
  591. package/ref-monty/crates/monty/test_cases/type__shadow_int.py +9 -0
  592. package/ref-monty/crates/monty/test_cases/type__shadow_len.py +3 -0
  593. package/ref-monty/crates/monty/test_cases/type__tuple_not_iterable.py +2 -0
  594. package/ref-monty/crates/monty/test_cases/type_error__int_add_list.py +2 -0
  595. package/ref-monty/crates/monty/test_cases/type_error__int_div_str.py +2 -0
  596. package/ref-monty/crates/monty/test_cases/type_error__int_floordiv_str.py +2 -0
  597. package/ref-monty/crates/monty/test_cases/type_error__int_iadd_str.py +3 -0
  598. package/ref-monty/crates/monty/test_cases/type_error__int_mod_str.py +2 -0
  599. package/ref-monty/crates/monty/test_cases/type_error__int_pow_str.py +2 -0
  600. package/ref-monty/crates/monty/test_cases/type_error__int_sub_str.py +2 -0
  601. package/ref-monty/crates/monty/test_cases/type_error__list_add_int.py +2 -0
  602. package/ref-monty/crates/monty/test_cases/type_error__list_add_str.py +2 -0
  603. package/ref-monty/crates/monty/test_cases/type_error__list_iadd_int.py +6 -0
  604. package/ref-monty/crates/monty/test_cases/type_error__str_add_int.py +2 -0
  605. package/ref-monty/crates/monty/test_cases/type_error__str_iadd_int.py +3 -0
  606. package/ref-monty/crates/monty/test_cases/type_error__unary_invert_str.py +3 -0
  607. package/ref-monty/crates/monty/test_cases/type_error__unary_minus_str.py +4 -0
  608. package/ref-monty/crates/monty/test_cases/type_error__unary_neg_str.py +3 -0
  609. package/ref-monty/crates/monty/test_cases/type_error__unary_plus_str.py +4 -0
  610. package/ref-monty/crates/monty/test_cases/typing__types.py +24 -0
  611. package/ref-monty/crates/monty/test_cases/unpack__nested.py +48 -0
  612. package/ref-monty/crates/monty/test_cases/unpack__non_sequence.py +9 -0
  613. package/ref-monty/crates/monty/test_cases/unpack__not_enough.py +9 -0
  614. package/ref-monty/crates/monty/test_cases/unpack__ops.py +153 -0
  615. package/ref-monty/crates/monty/test_cases/unpack__star_not_enough.py +9 -0
  616. package/ref-monty/crates/monty/test_cases/unpack__too_many.py +9 -0
  617. package/ref-monty/crates/monty/test_cases/version__cpython.py +4 -0
  618. package/ref-monty/crates/monty/test_cases/walrus__all.py +178 -0
  619. package/ref-monty/crates/monty/test_cases/while__all.py +206 -0
  620. package/ref-monty/crates/monty/tests/asyncio.rs +764 -0
  621. package/ref-monty/crates/monty/tests/binary_serde.rs +185 -0
  622. package/ref-monty/crates/monty/tests/bytecode_limits.rs +248 -0
  623. package/ref-monty/crates/monty/tests/datatest_runner.rs +2029 -0
  624. package/ref-monty/crates/monty/tests/inputs.rs +420 -0
  625. package/ref-monty/crates/monty/tests/json_serde.rs +250 -0
  626. package/ref-monty/crates/monty/tests/main.rs +71 -0
  627. package/ref-monty/crates/monty/tests/math_module.rs +114 -0
  628. package/ref-monty/crates/monty/tests/name_lookup.rs +482 -0
  629. package/ref-monty/crates/monty/tests/os_tests.rs +459 -0
  630. package/ref-monty/crates/monty/tests/parse_errors.rs +441 -0
  631. package/ref-monty/crates/monty/tests/print_writer.rs +238 -0
  632. package/ref-monty/crates/monty/tests/py_object.rs +121 -0
  633. package/ref-monty/crates/monty/tests/regex.rs +90 -0
  634. package/ref-monty/crates/monty/tests/repl.rs +344 -0
  635. package/ref-monty/crates/monty/tests/resource_limits.rs +1826 -0
  636. package/ref-monty/crates/monty/tests/try_from.rs +167 -0
  637. package/ref-monty/crates/monty-cli/Cargo.toml +25 -0
  638. package/ref-monty/crates/monty-cli/src/main.rs +541 -0
  639. package/ref-monty/crates/monty-js/.cargo/config.toml +2 -0
  640. package/ref-monty/crates/monty-js/.prettierignore +8 -0
  641. package/ref-monty/crates/monty-js/Cargo.toml +32 -0
  642. package/ref-monty/crates/monty-js/README.md +207 -0
  643. package/ref-monty/crates/monty-js/__test__/async.spec.ts +350 -0
  644. package/ref-monty/crates/monty-js/__test__/basic.spec.ts +114 -0
  645. package/ref-monty/crates/monty-js/__test__/exceptions.spec.ts +427 -0
  646. package/ref-monty/crates/monty-js/__test__/external.spec.ts +354 -0
  647. package/ref-monty/crates/monty-js/__test__/inputs.spec.ts +143 -0
  648. package/ref-monty/crates/monty-js/__test__/limits.spec.ts +162 -0
  649. package/ref-monty/crates/monty-js/__test__/package.json +3 -0
  650. package/ref-monty/crates/monty-js/__test__/print.spec.ts +229 -0
  651. package/ref-monty/crates/monty-js/__test__/repl.spec.ts +34 -0
  652. package/ref-monty/crates/monty-js/__test__/serialize.spec.ts +205 -0
  653. package/ref-monty/crates/monty-js/__test__/start.spec.ts +443 -0
  654. package/ref-monty/crates/monty-js/__test__/type_check.spec.ts +147 -0
  655. package/ref-monty/crates/monty-js/__test__/types.spec.ts +319 -0
  656. package/ref-monty/crates/monty-js/build.rs +61 -0
  657. package/ref-monty/crates/monty-js/index-header.d.ts +3 -0
  658. package/ref-monty/crates/monty-js/package-lock.json +4694 -0
  659. package/ref-monty/crates/monty-js/package.json +100 -0
  660. package/ref-monty/crates/monty-js/scripts/smoke-test.sh +69 -0
  661. package/ref-monty/crates/monty-js/smoke-test/package.json +17 -0
  662. package/ref-monty/crates/monty-js/smoke-test/test.ts +171 -0
  663. package/ref-monty/crates/monty-js/smoke-test/tsconfig.json +11 -0
  664. package/ref-monty/crates/monty-js/src/convert.rs +648 -0
  665. package/ref-monty/crates/monty-js/src/exceptions.rs +293 -0
  666. package/ref-monty/crates/monty-js/src/lib.rs +41 -0
  667. package/ref-monty/crates/monty-js/src/limits.rs +53 -0
  668. package/ref-monty/crates/monty-js/src/monty_cls.rs +1407 -0
  669. package/ref-monty/crates/monty-js/tsconfig.json +17 -0
  670. package/ref-monty/crates/monty-js/wrapper.ts +701 -0
  671. package/ref-monty/crates/monty-python/Cargo.toml +38 -0
  672. package/ref-monty/crates/monty-python/README.md +134 -0
  673. package/ref-monty/crates/monty-python/build.rs +4 -0
  674. package/ref-monty/crates/monty-python/example.py +40 -0
  675. package/ref-monty/crates/monty-python/exercise.py +46 -0
  676. package/ref-monty/crates/monty-python/pyproject.toml +57 -0
  677. package/ref-monty/crates/monty-python/python/pydantic_monty/__init__.py +281 -0
  678. package/ref-monty/crates/monty-python/python/pydantic_monty/_monty.pyi +677 -0
  679. package/ref-monty/crates/monty-python/python/pydantic_monty/os_access.py +933 -0
  680. package/ref-monty/crates/monty-python/python/pydantic_monty/py.typed +0 -0
  681. package/ref-monty/crates/monty-python/src/convert.rs +273 -0
  682. package/ref-monty/crates/monty-python/src/dataclass.rs +461 -0
  683. package/ref-monty/crates/monty-python/src/exceptions.rs +557 -0
  684. package/ref-monty/crates/monty-python/src/external.rs +165 -0
  685. package/ref-monty/crates/monty-python/src/lib.rs +77 -0
  686. package/ref-monty/crates/monty-python/src/limits.rs +142 -0
  687. package/ref-monty/crates/monty-python/src/monty_cls.rs +1650 -0
  688. package/ref-monty/crates/monty-python/src/repl.rs +470 -0
  689. package/ref-monty/crates/monty-python/src/serialization.rs +761 -0
  690. package/ref-monty/crates/monty-python/tests/test_async.py +1201 -0
  691. package/ref-monty/crates/monty-python/tests/test_basic.py +66 -0
  692. package/ref-monty/crates/monty-python/tests/test_dataclasses.py +971 -0
  693. package/ref-monty/crates/monty-python/tests/test_exceptions.py +361 -0
  694. package/ref-monty/crates/monty-python/tests/test_external.py +367 -0
  695. package/ref-monty/crates/monty-python/tests/test_inputs.py +126 -0
  696. package/ref-monty/crates/monty-python/tests/test_limits.py +257 -0
  697. package/ref-monty/crates/monty-python/tests/test_os_access.py +1286 -0
  698. package/ref-monty/crates/monty-python/tests/test_os_access_compat.py +731 -0
  699. package/ref-monty/crates/monty-python/tests/test_os_access_raw.py +483 -0
  700. package/ref-monty/crates/monty-python/tests/test_os_calls.py +819 -0
  701. package/ref-monty/crates/monty-python/tests/test_print.py +208 -0
  702. package/ref-monty/crates/monty-python/tests/test_re.py +170 -0
  703. package/ref-monty/crates/monty-python/tests/test_readme_examples.py +20 -0
  704. package/ref-monty/crates/monty-python/tests/test_repl.py +749 -0
  705. package/ref-monty/crates/monty-python/tests/test_serialize.py +284 -0
  706. package/ref-monty/crates/monty-python/tests/test_start.py +346 -0
  707. package/ref-monty/crates/monty-python/tests/test_threading.py +163 -0
  708. package/ref-monty/crates/monty-python/tests/test_type_check.py +344 -0
  709. package/ref-monty/crates/monty-python/tests/test_types.py +553 -0
  710. package/ref-monty/crates/monty-type-checking/Cargo.toml +32 -0
  711. package/ref-monty/crates/monty-type-checking/src/db.rs +116 -0
  712. package/ref-monty/crates/monty-type-checking/src/lib.rs +4 -0
  713. package/ref-monty/crates/monty-type-checking/src/type_check.rs +280 -0
  714. package/ref-monty/crates/monty-type-checking/tests/bad_types.py +109 -0
  715. package/ref-monty/crates/monty-type-checking/tests/bad_types_output.txt +21 -0
  716. package/ref-monty/crates/monty-type-checking/tests/good_types.py +475 -0
  717. package/ref-monty/crates/monty-type-checking/tests/main.rs +205 -0
  718. package/ref-monty/crates/monty-type-checking/tests/reveal_types.py +56 -0
  719. package/ref-monty/crates/monty-type-checking/tests/reveal_types_output.txt +41 -0
  720. package/ref-monty/crates/monty-typeshed/Cargo.toml +29 -0
  721. package/ref-monty/crates/monty-typeshed/README.md +11 -0
  722. package/ref-monty/crates/monty-typeshed/build.rs +101 -0
  723. package/ref-monty/crates/monty-typeshed/custom/README.md +1 -0
  724. package/ref-monty/crates/monty-typeshed/custom/asyncio.pyi +138 -0
  725. package/ref-monty/crates/monty-typeshed/custom/os.pyi +87 -0
  726. package/ref-monty/crates/monty-typeshed/custom/sys.pyi +33 -0
  727. package/ref-monty/crates/monty-typeshed/src/lib.rs +56 -0
  728. package/ref-monty/crates/monty-typeshed/update.py +321 -0
  729. package/ref-monty/crates/monty-typeshed/vendor/typeshed/source_commit.txt +1 -0
  730. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/VERSIONS +20 -0
  731. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/_collections_abc.pyi +105 -0
  732. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/_typeshed/__init__.pyi +394 -0
  733. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/asyncio.pyi +138 -0
  734. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/builtins.pyi +1434 -0
  735. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/collections/__init__.pyi +527 -0
  736. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/collections/abc.pyi +2 -0
  737. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/dataclasses.pyi +502 -0
  738. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/enum.pyi +376 -0
  739. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/math.pyi +149 -0
  740. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/os.pyi +87 -0
  741. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/pathlib/__init__.pyi +395 -0
  742. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/pathlib/types.pyi +8 -0
  743. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/re.pyi +337 -0
  744. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/sys.pyi +33 -0
  745. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/types.pyi +741 -0
  746. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/typing.pyi +1217 -0
  747. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/typing_extensions.pyi +716 -0
  748. package/ref-monty/docs/usage-guide.md +117 -0
  749. package/ref-monty/examples/README.md +3 -0
  750. package/ref-monty/examples/expense_analysis/README.md +3 -0
  751. package/ref-monty/examples/expense_analysis/data.py +124 -0
  752. package/ref-monty/examples/expense_analysis/main.py +115 -0
  753. package/ref-monty/examples/sql_playground/README.md +20 -0
  754. package/ref-monty/examples/sql_playground/external_functions.py +129 -0
  755. package/ref-monty/examples/sql_playground/main.py +81 -0
  756. package/ref-monty/examples/sql_playground/sandbox_code.py +82 -0
  757. package/ref-monty/examples/sql_playground/type_stubs.pyi +14 -0
  758. package/ref-monty/examples/web_scraper/README.md +15 -0
  759. package/ref-monty/examples/web_scraper/browser.py +56 -0
  760. package/ref-monty/examples/web_scraper/example_code.py +59 -0
  761. package/ref-monty/examples/web_scraper/external_functions.py +324 -0
  762. package/ref-monty/examples/web_scraper/main.py +193 -0
  763. package/ref-monty/examples/web_scraper/sub_agent.py +79 -0
  764. package/ref-monty/monty-npm.md +235 -0
  765. package/ref-monty/pyproject.toml +162 -0
  766. package/ref-monty/scripts/check_imports.py +91 -0
  767. package/ref-monty/scripts/codecov_diff.py +412 -0
  768. package/ref-monty/scripts/complete_tests.py +146 -0
  769. package/ref-monty/scripts/flamegraph_to_text.py +208 -0
  770. package/ref-monty/scripts/iter_test_methods.py +540 -0
  771. package/ref-monty/scripts/run_traceback.py +180 -0
  772. package/ref-monty/scripts/startup_performance.py +130 -0
  773. package/ref-monty/uv.lock +1779 -0
  774. package/temp_resend_cli/repo/.github/scripts/pr-title-check.js +34 -0
  775. package/temp_resend_cli/repo/.github/workflows/ci.yml +67 -0
  776. package/temp_resend_cli/repo/.github/workflows/post-release.yml +51 -0
  777. package/temp_resend_cli/repo/.github/workflows/pr-title-check.yml +13 -0
  778. package/temp_resend_cli/repo/.github/workflows/release.yml +175 -0
  779. package/temp_resend_cli/repo/.github/workflows/test-install-unix.yml +34 -0
  780. package/temp_resend_cli/repo/.github/workflows/test-install-windows.yml +48 -0
  781. package/temp_resend_cli/repo/CHANGELOG.md +31 -0
  782. package/temp_resend_cli/repo/LICENSE +21 -0
  783. package/temp_resend_cli/repo/README.md +450 -0
  784. package/temp_resend_cli/repo/biome.json +36 -0
  785. package/temp_resend_cli/repo/install.ps1 +141 -0
  786. package/temp_resend_cli/repo/install.sh +301 -0
  787. package/temp_resend_cli/repo/package.json +61 -0
  788. package/temp_resend_cli/repo/pnpm-lock.yaml +2439 -0
  789. package/temp_resend_cli/repo/renovate.json +4 -0
  790. package/temp_resend_cli/repo/src/cli.ts +98 -0
  791. package/temp_resend_cli/repo/src/commands/api-keys/create.ts +114 -0
  792. package/temp_resend_cli/repo/src/commands/api-keys/delete.ts +47 -0
  793. package/temp_resend_cli/repo/src/commands/api-keys/index.ts +26 -0
  794. package/temp_resend_cli/repo/src/commands/api-keys/list.ts +35 -0
  795. package/temp_resend_cli/repo/src/commands/api-keys/utils.ts +8 -0
  796. package/temp_resend_cli/repo/src/commands/auth/index.ts +20 -0
  797. package/temp_resend_cli/repo/src/commands/auth/login.ts +234 -0
  798. package/temp_resend_cli/repo/src/commands/auth/logout.ts +105 -0
  799. package/temp_resend_cli/repo/src/commands/broadcasts/create.ts +196 -0
  800. package/temp_resend_cli/repo/src/commands/broadcasts/delete.ts +46 -0
  801. package/temp_resend_cli/repo/src/commands/broadcasts/get.ts +59 -0
  802. package/temp_resend_cli/repo/src/commands/broadcasts/index.ts +43 -0
  803. package/temp_resend_cli/repo/src/commands/broadcasts/list.ts +60 -0
  804. package/temp_resend_cli/repo/src/commands/broadcasts/send.ts +56 -0
  805. package/temp_resend_cli/repo/src/commands/broadcasts/update.ts +95 -0
  806. package/temp_resend_cli/repo/src/commands/broadcasts/utils.ts +35 -0
  807. package/temp_resend_cli/repo/src/commands/contact-properties/create.ts +118 -0
  808. package/temp_resend_cli/repo/src/commands/contact-properties/delete.ts +48 -0
  809. package/temp_resend_cli/repo/src/commands/contact-properties/get.ts +46 -0
  810. package/temp_resend_cli/repo/src/commands/contact-properties/index.ts +48 -0
  811. package/temp_resend_cli/repo/src/commands/contact-properties/list.ts +68 -0
  812. package/temp_resend_cli/repo/src/commands/contact-properties/update.ts +88 -0
  813. package/temp_resend_cli/repo/src/commands/contact-properties/utils.ts +17 -0
  814. package/temp_resend_cli/repo/src/commands/contacts/add-segment.ts +78 -0
  815. package/temp_resend_cli/repo/src/commands/contacts/create.ts +122 -0
  816. package/temp_resend_cli/repo/src/commands/contacts/delete.ts +49 -0
  817. package/temp_resend_cli/repo/src/commands/contacts/get.ts +53 -0
  818. package/temp_resend_cli/repo/src/commands/contacts/index.ts +58 -0
  819. package/temp_resend_cli/repo/src/commands/contacts/list.ts +57 -0
  820. package/temp_resend_cli/repo/src/commands/contacts/remove-segment.ts +48 -0
  821. package/temp_resend_cli/repo/src/commands/contacts/segments.ts +39 -0
  822. package/temp_resend_cli/repo/src/commands/contacts/topics.ts +45 -0
  823. package/temp_resend_cli/repo/src/commands/contacts/update-topics.ts +90 -0
  824. package/temp_resend_cli/repo/src/commands/contacts/update.ts +77 -0
  825. package/temp_resend_cli/repo/src/commands/contacts/utils.ts +119 -0
  826. package/temp_resend_cli/repo/src/commands/doctor.ts +216 -0
  827. package/temp_resend_cli/repo/src/commands/domains/create.ts +83 -0
  828. package/temp_resend_cli/repo/src/commands/domains/delete.ts +42 -0
  829. package/temp_resend_cli/repo/src/commands/domains/get.ts +47 -0
  830. package/temp_resend_cli/repo/src/commands/domains/index.ts +35 -0
  831. package/temp_resend_cli/repo/src/commands/domains/list.ts +53 -0
  832. package/temp_resend_cli/repo/src/commands/domains/update.ts +75 -0
  833. package/temp_resend_cli/repo/src/commands/domains/utils.ts +44 -0
  834. package/temp_resend_cli/repo/src/commands/domains/verify.ts +38 -0
  835. package/temp_resend_cli/repo/src/commands/emails/batch.ts +140 -0
  836. package/temp_resend_cli/repo/src/commands/emails/get.ts +44 -0
  837. package/temp_resend_cli/repo/src/commands/emails/index.ts +30 -0
  838. package/temp_resend_cli/repo/src/commands/emails/list.ts +84 -0
  839. package/temp_resend_cli/repo/src/commands/emails/receiving/attachment.ts +55 -0
  840. package/temp_resend_cli/repo/src/commands/emails/receiving/attachments.ts +68 -0
  841. package/temp_resend_cli/repo/src/commands/emails/receiving/get.ts +58 -0
  842. package/temp_resend_cli/repo/src/commands/emails/receiving/index.ts +28 -0
  843. package/temp_resend_cli/repo/src/commands/emails/receiving/list.ts +59 -0
  844. package/temp_resend_cli/repo/src/commands/emails/receiving/utils.ts +38 -0
  845. package/temp_resend_cli/repo/src/commands/emails/send.ts +189 -0
  846. package/temp_resend_cli/repo/src/commands/open.ts +27 -0
  847. package/temp_resend_cli/repo/src/commands/segments/create.ts +50 -0
  848. package/temp_resend_cli/repo/src/commands/segments/delete.ts +47 -0
  849. package/temp_resend_cli/repo/src/commands/segments/get.ts +38 -0
  850. package/temp_resend_cli/repo/src/commands/segments/index.ts +36 -0
  851. package/temp_resend_cli/repo/src/commands/segments/list.ts +58 -0
  852. package/temp_resend_cli/repo/src/commands/segments/utils.ts +7 -0
  853. package/temp_resend_cli/repo/src/commands/teams/index.ts +10 -0
  854. package/temp_resend_cli/repo/src/commands/teams/list.ts +35 -0
  855. package/temp_resend_cli/repo/src/commands/teams/remove.ts +86 -0
  856. package/temp_resend_cli/repo/src/commands/teams/switch.ts +76 -0
  857. package/temp_resend_cli/repo/src/commands/topics/create.ts +73 -0
  858. package/temp_resend_cli/repo/src/commands/topics/delete.ts +47 -0
  859. package/temp_resend_cli/repo/src/commands/topics/get.ts +42 -0
  860. package/temp_resend_cli/repo/src/commands/topics/index.ts +42 -0
  861. package/temp_resend_cli/repo/src/commands/topics/list.ts +34 -0
  862. package/temp_resend_cli/repo/src/commands/topics/update.ts +59 -0
  863. package/temp_resend_cli/repo/src/commands/topics/utils.ts +16 -0
  864. package/temp_resend_cli/repo/src/commands/webhooks/create.ts +128 -0
  865. package/temp_resend_cli/repo/src/commands/webhooks/delete.ts +49 -0
  866. package/temp_resend_cli/repo/src/commands/webhooks/get.ts +42 -0
  867. package/temp_resend_cli/repo/src/commands/webhooks/index.ts +42 -0
  868. package/temp_resend_cli/repo/src/commands/webhooks/list.ts +55 -0
  869. package/temp_resend_cli/repo/src/commands/webhooks/listen.ts +379 -0
  870. package/temp_resend_cli/repo/src/commands/webhooks/update.ts +83 -0
  871. package/temp_resend_cli/repo/src/commands/webhooks/utils.ts +36 -0
  872. package/temp_resend_cli/repo/src/commands/whoami.ts +71 -0
  873. package/temp_resend_cli/repo/src/lib/actions.ts +157 -0
  874. package/temp_resend_cli/repo/src/lib/client.ts +37 -0
  875. package/temp_resend_cli/repo/src/lib/config.ts +217 -0
  876. package/temp_resend_cli/repo/src/lib/files.ts +15 -0
  877. package/temp_resend_cli/repo/src/lib/help-text.ts +38 -0
  878. package/temp_resend_cli/repo/src/lib/output.ts +56 -0
  879. package/temp_resend_cli/repo/src/lib/pagination.ts +36 -0
  880. package/temp_resend_cli/repo/src/lib/prompts.ts +149 -0
  881. package/temp_resend_cli/repo/src/lib/spinner.ts +100 -0
  882. package/temp_resend_cli/repo/src/lib/table.ts +57 -0
  883. package/temp_resend_cli/repo/src/lib/tty.ts +28 -0
  884. package/temp_resend_cli/repo/src/lib/update-check.ts +169 -0
  885. package/temp_resend_cli/repo/src/lib/version.ts +4 -0
  886. package/temp_resend_cli/repo/tests/commands/api-keys/create.test.ts +196 -0
  887. package/temp_resend_cli/repo/tests/commands/api-keys/delete.test.ts +157 -0
  888. package/temp_resend_cli/repo/tests/commands/api-keys/list.test.ts +134 -0
  889. package/temp_resend_cli/repo/tests/commands/auth/login.test.ts +153 -0
  890. package/temp_resend_cli/repo/tests/commands/auth/logout.test.ts +153 -0
  891. package/temp_resend_cli/repo/tests/commands/broadcasts/create.test.ts +454 -0
  892. package/temp_resend_cli/repo/tests/commands/broadcasts/delete.test.ts +183 -0
  893. package/temp_resend_cli/repo/tests/commands/broadcasts/get.test.ts +147 -0
  894. package/temp_resend_cli/repo/tests/commands/broadcasts/list.test.ts +199 -0
  895. package/temp_resend_cli/repo/tests/commands/broadcasts/send.test.ts +162 -0
  896. package/temp_resend_cli/repo/tests/commands/broadcasts/update.test.ts +288 -0
  897. package/temp_resend_cli/repo/tests/commands/contact-properties/create.test.ts +251 -0
  898. package/temp_resend_cli/repo/tests/commands/contact-properties/delete.test.ts +184 -0
  899. package/temp_resend_cli/repo/tests/commands/contact-properties/get.test.ts +145 -0
  900. package/temp_resend_cli/repo/tests/commands/contact-properties/list.test.ts +181 -0
  901. package/temp_resend_cli/repo/tests/commands/contact-properties/update.test.ts +217 -0
  902. package/temp_resend_cli/repo/tests/commands/contacts/add-segment.test.ts +189 -0
  903. package/temp_resend_cli/repo/tests/commands/contacts/create.test.ts +271 -0
  904. package/temp_resend_cli/repo/tests/commands/contacts/delete.test.ts +193 -0
  905. package/temp_resend_cli/repo/tests/commands/contacts/get.test.ts +149 -0
  906. package/temp_resend_cli/repo/tests/commands/contacts/list.test.ts +176 -0
  907. package/temp_resend_cli/repo/tests/commands/contacts/remove-segment.test.ts +167 -0
  908. package/temp_resend_cli/repo/tests/commands/contacts/segments.test.ts +168 -0
  909. package/temp_resend_cli/repo/tests/commands/contacts/topics.test.ts +164 -0
  910. package/temp_resend_cli/repo/tests/commands/contacts/update-topics.test.ts +248 -0
  911. package/temp_resend_cli/repo/tests/commands/contacts/update.test.ts +206 -0
  912. package/temp_resend_cli/repo/tests/commands/doctor.test.ts +164 -0
  913. package/temp_resend_cli/repo/tests/commands/domains/create.test.ts +193 -0
  914. package/temp_resend_cli/repo/tests/commands/domains/delete.test.ts +157 -0
  915. package/temp_resend_cli/repo/tests/commands/domains/get.test.ts +138 -0
  916. package/temp_resend_cli/repo/tests/commands/domains/list.test.ts +165 -0
  917. package/temp_resend_cli/repo/tests/commands/domains/update.test.ts +224 -0
  918. package/temp_resend_cli/repo/tests/commands/domains/verify.test.ts +118 -0
  919. package/temp_resend_cli/repo/tests/commands/emails/batch.test.ts +324 -0
  920. package/temp_resend_cli/repo/tests/commands/emails/get.test.ts +132 -0
  921. package/temp_resend_cli/repo/tests/commands/emails/receiving/attachment.test.ts +141 -0
  922. package/temp_resend_cli/repo/tests/commands/emails/receiving/attachments.test.ts +169 -0
  923. package/temp_resend_cli/repo/tests/commands/emails/receiving/get.test.ts +141 -0
  924. package/temp_resend_cli/repo/tests/commands/emails/receiving/list.test.ts +182 -0
  925. package/temp_resend_cli/repo/tests/commands/emails/send.test.ts +312 -0
  926. package/temp_resend_cli/repo/tests/commands/segments/create.test.ts +164 -0
  927. package/temp_resend_cli/repo/tests/commands/segments/delete.test.ts +183 -0
  928. package/temp_resend_cli/repo/tests/commands/segments/get.test.ts +138 -0
  929. package/temp_resend_cli/repo/tests/commands/segments/list.test.ts +174 -0
  930. package/temp_resend_cli/repo/tests/commands/teams/list.test.ts +62 -0
  931. package/temp_resend_cli/repo/tests/commands/teams/remove.test.ts +110 -0
  932. package/temp_resend_cli/repo/tests/commands/teams/switch.test.ts +103 -0
  933. package/temp_resend_cli/repo/tests/commands/topics/create.test.ts +192 -0
  934. package/temp_resend_cli/repo/tests/commands/topics/delete.test.ts +157 -0
  935. package/temp_resend_cli/repo/tests/commands/topics/get.test.ts +126 -0
  936. package/temp_resend_cli/repo/tests/commands/topics/list.test.ts +125 -0
  937. package/temp_resend_cli/repo/tests/commands/topics/update.test.ts +178 -0
  938. package/temp_resend_cli/repo/tests/commands/webhooks/create.test.ts +225 -0
  939. package/temp_resend_cli/repo/tests/commands/webhooks/delete.test.ts +157 -0
  940. package/temp_resend_cli/repo/tests/commands/webhooks/get.test.ts +126 -0
  941. package/temp_resend_cli/repo/tests/commands/webhooks/list.test.ts +178 -0
  942. package/temp_resend_cli/repo/tests/commands/webhooks/update.test.ts +207 -0
  943. package/temp_resend_cli/repo/tests/commands/whoami.test.ts +98 -0
  944. package/temp_resend_cli/repo/tests/e2e/smoke.test.ts +93 -0
  945. package/temp_resend_cli/repo/tests/helpers.ts +86 -0
  946. package/temp_resend_cli/repo/tests/lib/client.test.ts +71 -0
  947. package/temp_resend_cli/repo/tests/lib/config.test.ts +451 -0
  948. package/temp_resend_cli/repo/tests/lib/files.test.ts +73 -0
  949. package/temp_resend_cli/repo/tests/lib/help-text.test.ts +97 -0
  950. package/temp_resend_cli/repo/tests/lib/output.test.ts +136 -0
  951. package/temp_resend_cli/repo/tests/lib/prompts.test.ts +185 -0
  952. package/temp_resend_cli/repo/tests/lib/spinner.test.ts +166 -0
  953. package/temp_resend_cli/repo/tests/lib/table.test.ts +63 -0
  954. package/temp_resend_cli/repo/tests/lib/tty.test.ts +89 -0
  955. package/temp_resend_cli/repo/tests/lib/update-check.test.ts +179 -0
  956. package/temp_resend_cli/repo/tsconfig.json +14 -0
  957. package/temp_resend_cli/repo/vitest.config.e2e.ts +8 -0
  958. package/temp_resend_cli/repo/vitest.config.ts +10 -0
  959. package/tests/test-mcp-browser-use-smoke.sh +28 -56
  960. package/tests/test-monty-smoke.sh +32 -0
  961. package/tests/test-resend-smoke.sh +36 -0
@@ -0,0 +1,1958 @@
1
+ //! Bytecode virtual machine for executing compiled Python code.
2
+ //!
3
+ //! The VM uses a stack-based execution model with an operand stack for computation
4
+ //! and a call stack for function frames. Each frame owns its instruction pointer (IP).
5
+
6
+ mod async_exec;
7
+ mod attr;
8
+ mod binary;
9
+ mod call;
10
+ mod collections;
11
+ mod compare;
12
+ mod exceptions;
13
+ mod format;
14
+ mod scheduler;
15
+
16
+ use std::cmp::Ordering;
17
+
18
+ pub(crate) use call::CallResult;
19
+ use scheduler::Scheduler;
20
+
21
+ use crate::{
22
+ MontyObject,
23
+ args::ArgValues,
24
+ asyncio::{CallId, TaskId},
25
+ bytecode::{code::Code, op::Opcode},
26
+ exception_private::{ExcType, RunError, RunResult, SimpleException},
27
+ heap::{ContainsHeap, DropWithHeap, Heap, HeapData, HeapGuard, HeapId},
28
+ heap_data::{Closure, FunctionDefaults, HeapDataMut},
29
+ intern::{FunctionId, Interns, StringId},
30
+ io::PrintWriter,
31
+ modules::BuiltinModule,
32
+ os::OsFunction,
33
+ parse::CodeRange,
34
+ resource::ResourceTracker,
35
+ types::{LongInt, MontyIter, PyTrait, iter::advance_on_heap},
36
+ value::{BitwiseOp, EitherStr, Value},
37
+ };
38
+
39
+ /// Result of executing Await opcode.
40
+ ///
41
+ /// Indicates what the VM should do after awaiting a value:
42
+ /// - `ValueReady`: the awaited value resolved immediately, push it
43
+ /// - `FramePushed`: a new frame was pushed for coroutine execution
44
+ /// - `Yield`: all tasks blocked, yield to caller with pending futures
45
+ enum AwaitResult {
46
+ /// The awaited value resolved immediately (e.g., resolved ExternalFuture).
47
+ ValueReady(Value),
48
+ /// A new frame was pushed to execute a coroutine.
49
+ FramePushed,
50
+ /// All tasks are blocked - yield to caller with pending futures.
51
+ Yield(Vec<CallId>),
52
+ }
53
+
54
+ /// Tries an operation and handles exceptions, reloading cached frame state.
55
+ ///
56
+ /// Use this in the main run loop where `cached_frame`
57
+ /// are used. After catching an exception, reloads the cache since the handler
58
+ /// may be in a different frame.
59
+ macro_rules! try_catch_sync {
60
+ ($self:expr, $cached_frame:ident, $expr:expr) => {
61
+ if let Err(e) = $expr {
62
+ if let Some(result) = $self.handle_exception(e) {
63
+ return Err(result);
64
+ }
65
+ // Exception was caught - handler may be in different frame, reload cache
66
+ reload_cache!($self, $cached_frame);
67
+ }
68
+ };
69
+ }
70
+
71
+ /// Handles an exception and reloads cached frame state if caught.
72
+ ///
73
+ /// Use this in the main run loop where `cached_frame`
74
+ /// are used. After catching an exception, reloads the cache since the handler
75
+ /// may be in a different frame.
76
+ ///
77
+ /// Wrapped in a block to allow use in match arm expressions.
78
+ macro_rules! catch_sync {
79
+ ($self:expr, $cached_frame:ident, $err:expr) => {{
80
+ if let Some(result) = $self.handle_exception($err) {
81
+ return Err(result);
82
+ }
83
+ // Exception was caught - handler may be in different frame, reload cache
84
+ reload_cache!($self, $cached_frame);
85
+ }};
86
+ }
87
+
88
+ /// Fetches a byte from bytecode using cached code/ip, advancing ip.
89
+ ///
90
+ /// Used in the run loop for fast operand fetching without frame access.
91
+ macro_rules! fetch_byte {
92
+ ($cached_frame:expr) => {{
93
+ let byte = $cached_frame.code.bytecode()[$cached_frame.ip];
94
+ $cached_frame.ip += 1;
95
+ byte
96
+ }};
97
+ }
98
+
99
+ /// Fetches a u8 operand using cached code/ip.
100
+ macro_rules! fetch_u8 {
101
+ ($cached_frame:expr) => {
102
+ fetch_byte!($cached_frame)
103
+ };
104
+ }
105
+
106
+ /// Fetches an i8 operand using cached code/ip.
107
+ macro_rules! fetch_i8 {
108
+ ($cached_frame:expr) => {{ i8::from_ne_bytes([fetch_byte!($cached_frame)]) }};
109
+ }
110
+
111
+ /// Fetches a u16 operand (little-endian) using cached code/ip.
112
+ macro_rules! fetch_u16 {
113
+ ($cached_frame:expr) => {{
114
+ let lo = $cached_frame.code.bytecode()[$cached_frame.ip];
115
+ let hi = $cached_frame.code.bytecode()[$cached_frame.ip + 1];
116
+ $cached_frame.ip += 2;
117
+ u16::from_le_bytes([lo, hi])
118
+ }};
119
+ }
120
+
121
+ /// Fetches an i16 operand (little-endian) using cached code/ip.
122
+ macro_rules! fetch_i16 {
123
+ ($cached_frame:expr) => {{
124
+ let lo = $cached_frame.code.bytecode()[$cached_frame.ip];
125
+ let hi = $cached_frame.code.bytecode()[$cached_frame.ip + 1];
126
+ $cached_frame.ip += 2;
127
+ i16::from_le_bytes([lo, hi])
128
+ }};
129
+ }
130
+
131
+ /// Reloads cached frame state from the current frame.
132
+ ///
133
+ /// Call this after any operation that modifies the frame stack (calls, returns,
134
+ /// exception handling).
135
+ macro_rules! reload_cache {
136
+ ($self:expr, $cached_frame:ident) => {{
137
+ $cached_frame = $self.new_cached_frame();
138
+ }};
139
+ }
140
+
141
+ /// Applies a relative jump offset to the cached IP.
142
+ ///
143
+ /// Uses checked arithmetic to safely compute the new IP, panicking if the
144
+ /// jump would result in a negative or overflowing instruction pointer.
145
+ macro_rules! jump_relative {
146
+ ($ip:expr, $offset:expr) => {{
147
+ let ip_i64 = i64::try_from($ip).expect("instruction pointer exceeds i64");
148
+ let new_ip = ip_i64 + i64::from($offset);
149
+ $ip = usize::try_from(new_ip).expect("jump resulted in negative or overflowing IP");
150
+ }};
151
+ }
152
+
153
+ /// Handles the result of a load operation that may yield a `FrameExit::NameLookup`.
154
+ ///
155
+ /// `load_local` and `load_global` return `Result<Option<FrameExit>, RunError>`:
156
+ /// - `Ok(None)`: load succeeded, value is on the stack
157
+ /// - `Ok(Some(FrameExit::NameLookup { .. }))`: unresolved name, yield to host
158
+ /// - `Err(e)`: exception (e.g., UnboundLocalError)
159
+ macro_rules! handle_load_result {
160
+ ($self:expr, $cached_frame:ident, $result:expr) => {
161
+ match $result {
162
+ Ok(None) => {}
163
+ Ok(Some(frame_exit)) => {
164
+ $self.current_frame_mut().ip = $cached_frame.ip;
165
+ return Ok(frame_exit);
166
+ }
167
+ Err(e) => catch_sync!($self, $cached_frame, e),
168
+ }
169
+ };
170
+ }
171
+
172
+ /// Handles the result of a call operation that returns `CallResult`.
173
+ ///
174
+ /// This macro eliminates the repetitive pattern of matching on `CallResult`
175
+ /// variants that appears in LoadAttr, CallFunction, CallFunctionKw, CallAttr,
176
+ /// CallAttrKw, and CallFunctionExtended opcodes.
177
+ ///
178
+ /// Actions taken for each variant:
179
+ /// - `Push(value)`: Push the value onto the stack
180
+ /// - `FramePushed`: Reload the cached frame (a new frame was pushed)
181
+ /// - `External(ext_id, args)`: Return `FrameExit::ExternalCall` to yield to host
182
+ /// - `OsCall(func, args)`: Return `FrameExit::OsCall` to yield to host
183
+ /// - `MethodCall(name, args)`: Return `FrameExit::MethodCall` to yield to host
184
+ /// - `AwaitValue(value)`: Push value, then implicitly await it via `exec_get_awaitable`
185
+ /// - `Err(err)`: Handle the exception via `catch_sync!`
186
+ macro_rules! handle_call_result {
187
+ ($self:expr, $cached_frame:ident, $result:expr) => {
188
+ match $result {
189
+ Ok(CallResult::Value(result)) => $self.push(result),
190
+ Ok(CallResult::FramePushed) => reload_cache!($self, $cached_frame),
191
+ Ok(CallResult::External(name, args)) => {
192
+ let call_id = $self.allocate_call_id();
193
+ let name_load_ip = $self.ext_function_load_ip.take();
194
+ // Sync cached IP back to frame before snapshot for resume
195
+ $self.current_frame_mut().ip = $cached_frame.ip;
196
+ return Ok(FrameExit::ExternalCall {
197
+ function_name: name,
198
+ args,
199
+ call_id,
200
+ name_load_ip,
201
+ });
202
+ }
203
+ Ok(CallResult::OsCall(func, args)) => {
204
+ let call_id = $self.allocate_call_id();
205
+ // Sync cached IP back to frame before snapshot for resume
206
+ $self.current_frame_mut().ip = $cached_frame.ip;
207
+ return Ok(FrameExit::OsCall {
208
+ function: func,
209
+ args,
210
+ call_id,
211
+ });
212
+ }
213
+ Ok(CallResult::MethodCall(method_name, args)) => {
214
+ let call_id = $self.allocate_call_id();
215
+ // Sync cached IP back to frame before snapshot for resume
216
+ $self.current_frame_mut().ip = $cached_frame.ip;
217
+ return Ok(FrameExit::MethodCall {
218
+ method_name,
219
+ args,
220
+ call_id,
221
+ });
222
+ }
223
+ Ok(CallResult::AwaitValue(value)) => {
224
+ // Push the value and implicitly await it (used by asyncio.run())
225
+ $self.push(value);
226
+ $self.current_frame_mut().ip = $cached_frame.ip;
227
+ match $self.exec_get_awaitable() {
228
+ Ok(AwaitResult::ValueReady(value)) => {
229
+ $self.push(value);
230
+ }
231
+ Ok(AwaitResult::FramePushed) => {
232
+ reload_cache!($self, $cached_frame);
233
+ }
234
+ Ok(AwaitResult::Yield(pending_calls)) => {
235
+ return Ok(FrameExit::ResolveFutures(pending_calls));
236
+ }
237
+ Err(e) => {
238
+ catch_sync!($self, $cached_frame, e);
239
+ }
240
+ }
241
+ }
242
+ Err(err) => catch_sync!($self, $cached_frame, err),
243
+ }
244
+ };
245
+ }
246
+
247
+ /// Result of VM execution.
248
+ pub enum FrameExit {
249
+ /// Execution completed successfully with a return value.
250
+ Return(Value),
251
+
252
+ /// Execution paused for an external function call.
253
+ ///
254
+ /// The caller should execute the external function and call `resume()`
255
+ /// with the result. The `call_id` allows the host to use async resolution
256
+ /// by calling `run_pending()` instead of `run(result)`.
257
+ ExternalCall {
258
+ /// Name of the external function to call (interned or heap-owned).
259
+ function_name: EitherStr,
260
+ /// Arguments for the external function (includes both positional and keyword args).
261
+ args: ArgValues,
262
+ /// Unique ID for this call, used for async correlation.
263
+ call_id: CallId,
264
+ /// Optional bytecode IP of the load instruction that produced this `ExtFunction`.
265
+ ///
266
+ /// When a `LoadGlobalCallable`/`LoadLocalCallable` opcode auto-injects an `ExtFunction`
267
+ /// for an undefined name, the load instruction's IP is saved here. In standard execution
268
+ /// (without external function support), this IP is used to restore the frame pointer
269
+ /// before raising `NameError`, so the traceback points to the name rather than the call.
270
+ name_load_ip: Option<usize>,
271
+ },
272
+
273
+ /// Execution paused for an os function call.
274
+ ///
275
+ /// The caller should execute a function corresponding to the `os_call` and call `resume()`
276
+ /// with the result. The `call_id` allows the host to use async resolution
277
+ /// by calling `run_pending()` instead of `run(result)`.
278
+ OsCall {
279
+ /// ID of the os function to call.
280
+ function: OsFunction,
281
+ /// Arguments for the external function (includes both positional and keyword args).
282
+ args: ArgValues,
283
+ /// Unique ID for this call, used for async correlation.
284
+ call_id: CallId,
285
+ },
286
+
287
+ /// Execution paused for a dataclass method call.
288
+ ///
289
+ /// The caller should invoke the method on the original Python dataclass and call
290
+ /// `resume()` with the result. The `method_name` is the attribute name (e.g.
291
+ /// `"distance"`) and `args` includes the dataclass instance as the first argument
292
+ /// (`self`).
293
+ MethodCall {
294
+ /// Method name (e.g., "distance").
295
+ method_name: EitherStr,
296
+ /// Arguments including the dataclass instance as the first positional arg.
297
+ args: ArgValues,
298
+ /// Unique ID for this call, used for async correlation.
299
+ call_id: CallId,
300
+ },
301
+
302
+ /// All tasks are blocked waiting for external futures to resolve.
303
+ ///
304
+ /// The caller must resolve the pending CallIds before calling `resume()`.
305
+ /// This happens when await is called on an ExternalFuture that hasn't
306
+ /// been resolved yet, and there are no other ready tasks to switch to.
307
+ ResolveFutures(Vec<CallId>),
308
+
309
+ /// Execution paused for an unresolved name lookup.
310
+ ///
311
+ /// When the VM encounters an `Undefined` value in a `LocalUnassigned` slot
312
+ /// (module level) or a global slot, it yields to the host to resolve the name.
313
+ /// The host can return a value to cache in the slot, or indicate the name is
314
+ /// truly undefined (which will raise `NameError`).
315
+ ///
316
+ /// This enables auto-detection of external functions without requiring upfront
317
+ /// declaration: unresolved names are lazily resolved by the host at runtime.
318
+ NameLookup {
319
+ /// The interned name being looked up.
320
+ name_id: StringId,
321
+ /// The namespace slot where the resolved value should be cached.
322
+ namespace_slot: u16,
323
+ /// Whether this is a global slot (true) or a local/function slot (false).
324
+ is_global: bool,
325
+ },
326
+ }
327
+
328
+ /// A single function activation record.
329
+ ///
330
+ /// Each frame represents one level in the call stack and owns its own
331
+ /// instruction pointer. This design avoids sync bugs on call/return.
332
+ #[derive(Debug)]
333
+ pub struct CallFrame<'code> {
334
+ /// Bytecode being executed.
335
+ code: &'code Code,
336
+
337
+ /// Instruction pointer within this frame's bytecode.
338
+ ip: usize,
339
+
340
+ /// Base index into the VM stack for this frame's locals region.
341
+ ///
342
+ /// The frame's locals occupy `stack[stack_base..stack_base + locals_count]`,
343
+ /// and operands are pushed above that.
344
+ stack_base: usize,
345
+
346
+ /// Number of local variable slots in this frame.
347
+ ///
348
+ /// Zero for module-level frames (globals are stored separately).
349
+ /// For function frames, this equals `func.namespace_size`.
350
+ locals_count: u16,
351
+
352
+ /// Function ID (for tracebacks). None for module-level code.
353
+ function_id: Option<FunctionId>,
354
+
355
+ /// Call site position (for tracebacks).
356
+ call_position: Option<CodeRange>,
357
+
358
+ /// When this frame returns (or exits with an exception) the VM should exit the run loop
359
+ /// and return to the caller. Supports `evaluate_function`.
360
+ should_return: bool,
361
+ }
362
+
363
+ impl<'code> CallFrame<'code> {
364
+ /// Creates a new call frame for module-level code.
365
+ ///
366
+ /// Module frames have `locals_count = 0` because module-level variables
367
+ /// are stored in the VM's `globals` vec, not in the stack.
368
+ pub fn new_module(code: &'code Code) -> Self {
369
+ Self {
370
+ code,
371
+ ip: 0,
372
+ stack_base: 0,
373
+ locals_count: 0,
374
+ function_id: None,
375
+ call_position: None,
376
+ should_return: false,
377
+ }
378
+ }
379
+
380
+ /// Creates a new call frame for a function call.
381
+ ///
382
+ /// The frame's locals occupy `stack[stack_base..stack_base + locals_count]`.
383
+ /// Operands are pushed above the locals region.
384
+ pub fn new_function(
385
+ code: &'code Code,
386
+ stack_base: usize,
387
+ locals_count: u16,
388
+ function_id: FunctionId,
389
+ call_position: Option<CodeRange>,
390
+ ) -> Self {
391
+ Self {
392
+ code,
393
+ ip: 0,
394
+ stack_base,
395
+ locals_count,
396
+ function_id: Some(function_id),
397
+ call_position,
398
+ should_return: false,
399
+ }
400
+ }
401
+ }
402
+
403
+ /// Cached state of the VM derived from the current frame as an optimization.
404
+ ///
405
+ /// Holds the hot fields from the current `CallFrame` to avoid repeated
406
+ /// `frames.last()` lookups in the main opcode loop.
407
+ #[derive(Debug, Copy, Clone)]
408
+ pub struct CachedFrame<'code> {
409
+ /// Bytecode being executed.
410
+ code: &'code Code,
411
+
412
+ /// Instruction pointer within this frame's bytecode.
413
+ ip: usize,
414
+
415
+ /// Base index into the VM stack for this frame's locals.
416
+ stack_base: usize,
417
+ }
418
+
419
+ impl<'code> From<&CallFrame<'code>> for CachedFrame<'code> {
420
+ fn from(frame: &CallFrame<'code>) -> Self {
421
+ Self {
422
+ code: frame.code,
423
+ ip: frame.ip,
424
+ stack_base: frame.stack_base,
425
+ }
426
+ }
427
+ }
428
+
429
+ /// Serializable representation of a call frame.
430
+ ///
431
+ /// Cannot store `&Code` (a reference) — instead stores `FunctionId` to look up
432
+ /// the pre-compiled Code object on resume. Module-level code uses `None`.
433
+ #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
434
+ pub struct SerializedFrame {
435
+ /// Which function's code this frame executes (None = module-level).
436
+ function_id: Option<FunctionId>,
437
+
438
+ /// Instruction pointer within this frame's bytecode.
439
+ ip: usize,
440
+
441
+ /// Base index into the VM stack for this frame's locals region.
442
+ stack_base: usize,
443
+
444
+ /// Number of local variable slots (0 for module-level frames).
445
+ locals_count: u16,
446
+
447
+ /// Call site position (for tracebacks).
448
+ call_position: Option<CodeRange>,
449
+ }
450
+
451
+ impl CallFrame<'_> {
452
+ /// Converts this frame to a serializable representation.
453
+ fn serialize(&self) -> SerializedFrame {
454
+ assert!(
455
+ !self.should_return,
456
+ "cannot serialize frame marked for return - not yet supported"
457
+ );
458
+ SerializedFrame {
459
+ function_id: self.function_id,
460
+ ip: self.ip,
461
+ stack_base: self.stack_base,
462
+ locals_count: self.locals_count,
463
+ call_position: self.call_position,
464
+ }
465
+ }
466
+ }
467
+
468
+ /// VM state for pause/resume at external function calls.
469
+ ///
470
+ /// **Ownership:** This struct OWNS the values (refcounts were already incremented).
471
+ /// Must be used with the serialized Heap - HeapId values are indices into that heap.
472
+ ///
473
+ /// **Usage:** When the VM pauses for an external call, call `into_snapshot()` to
474
+ /// create this snapshot. The snapshot can be serialized and stored. On resume,
475
+ /// use `restore()` to reconstruct the VM and continue execution.
476
+ ///
477
+ /// Note: This struct does not implement `Clone` because `Value` uses manual
478
+ /// reference counting. Snapshots transfer ownership - they are not copied.
479
+ #[derive(Debug, serde::Serialize, serde::Deserialize)]
480
+ pub struct VMSnapshot {
481
+ /// Operand stack — locals and operands interleaved per frame.
482
+ ///
483
+ /// Each function frame's locals occupy `stack[frame.stack_base..frame.stack_base + frame.locals_count]`,
484
+ /// with operands pushed above.
485
+ pub(crate) stack: Vec<Value>,
486
+
487
+ /// Module-level (global) variable storage.
488
+ pub(crate) globals: Vec<Value>,
489
+
490
+ /// Call frames (serializable form — stores FunctionId, not &Code).
491
+ frames: Vec<SerializedFrame>,
492
+
493
+ /// Stack of exceptions being handled for nested except blocks.
494
+ ///
495
+ /// When entering an except handler, the exception is pushed onto this stack.
496
+ /// When exiting via `ClearException`, the top is popped. This allows nested
497
+ /// except handlers to restore the outer exception context.
498
+ exception_stack: Vec<Value>,
499
+
500
+ /// IP of the instruction that caused the pause (for exception handling).
501
+ instruction_ip: usize,
502
+
503
+ /// Counter for external call IDs when scheduler is not initialized.
504
+ next_call_id: u32,
505
+
506
+ /// Scheduler state for async execution (optional).
507
+ ///
508
+ /// Contains all task state, pending calls, and resolved futures.
509
+ /// This enables async execution to be paused and resumed across host calls.
510
+ /// None if no async operations have been performed yet.
511
+ scheduler: Option<Scheduler>,
512
+ }
513
+
514
+ // ============================================================================
515
+ // Virtual Machine
516
+ // ============================================================================
517
+
518
+ /// The bytecode virtual machine.
519
+ ///
520
+ /// Executes compiled bytecode using a stack-based execution model.
521
+ /// The instruction pointer (IP) lives in each `CallFrame`, not here,
522
+ /// to avoid sync bugs on call/return.
523
+ ///
524
+ /// # Lifetimes
525
+ /// * `'a` - Lifetime of the heap, namespaces, and interns
526
+ /// * `'p` - Lifetime of the print writer's internal references
527
+ pub struct VM<'a, 'p, T: ResourceTracker> {
528
+ /// Operand stack — locals and operands interleaved per frame.
529
+ ///
530
+ /// Each function frame's locals occupy `stack[frame.stack_base..frame.stack_base + frame.locals_count]`,
531
+ /// with operands pushed above. Module-level frames have `locals_count = 0`
532
+ /// because globals are stored separately.
533
+ pub(crate) stack: Vec<Value>,
534
+
535
+ /// Module-level (global) variable storage.
536
+ ///
537
+ /// Indexed by slot number from `LoadGlobal`/`StoreGlobal` opcodes.
538
+ /// Separated from the stack because globals persist across function calls
539
+ /// and are accessed via dedicated opcodes.
540
+ pub(crate) globals: Vec<Value>,
541
+
542
+ /// Call stack — function frames (each frame has its own IP).
543
+ frames: Vec<CallFrame<'a>>,
544
+
545
+ /// Heap for reference-counted objects.
546
+ pub(crate) heap: &'a mut Heap<T>,
547
+
548
+ /// Interned strings/bytes.
549
+ pub(crate) interns: &'a Interns,
550
+
551
+ /// Print output writer, borrowed so callers retain access to collected output.
552
+ pub(crate) print_writer: PrintWriter<'p>,
553
+
554
+ /// Stack of exceptions being handled for nested except blocks.
555
+ ///
556
+ /// Used by bare `raise` to re-raise the current exception.
557
+ /// When entering an except handler, the exception is pushed onto this stack.
558
+ /// When exiting via `ClearException`, the top is popped. This allows nested
559
+ /// except handlers to restore the outer exception context.
560
+ exception_stack: Vec<Value>,
561
+
562
+ /// IP of the instruction being executed (for exception table lookup).
563
+ ///
564
+ /// Updated at the start of each instruction before operands are fetched.
565
+ /// This allows us to find the correct exception handler when an error occurs.
566
+ instruction_ip: usize,
567
+
568
+ /// Counter for external call IDs when scheduler is not initialized.
569
+ ///
570
+ /// Used by `allocate_call_id()` when no scheduler exists (sync code paths).
571
+ /// When a scheduler is created, this counter is transferred to it.
572
+ next_call_id: u32,
573
+
574
+ /// Scheduler for async task management (lazy — only created when needed).
575
+ ///
576
+ /// Manages concurrent tasks, external call tracking, and task switching.
577
+ /// Created lazily on first async operation to avoid allocations for sync code.
578
+ scheduler: Option<Scheduler>,
579
+
580
+ /// Module-level code (for restoring main task frames).
581
+ ///
582
+ /// Stored here because the main task's frames have `function_id: None` and
583
+ /// need a reference to the module code when being restored after task switching.
584
+ module_code: Option<&'a Code>,
585
+
586
+ /// Bytecode IP of the most recent `LoadGlobalCallable`/`LoadLocalCallable` that
587
+ /// pushed an `ExtFunction` for an undefined name.
588
+ ///
589
+ /// Used to restore the frame IP when standard execution converts an `ExternalCall`
590
+ /// back to a `NameError`, so the traceback points to the name reference rather than
591
+ /// the call expression.
592
+ ext_function_load_ip: Option<usize>,
593
+ }
594
+
595
+ impl<'a, 'p, T: ResourceTracker> VM<'a, 'p, T> {
596
+ /// Creates a new VM with the given runtime context.
597
+ pub fn new(
598
+ globals: Vec<Value>,
599
+ heap: &'a mut Heap<T>,
600
+ interns: &'a Interns,
601
+ print_writer: PrintWriter<'p>,
602
+ ) -> Self {
603
+ Self {
604
+ stack: Vec::with_capacity(64),
605
+ globals,
606
+ frames: Vec::with_capacity(16),
607
+ heap,
608
+ interns,
609
+ print_writer,
610
+ exception_stack: Vec::new(),
611
+ instruction_ip: 0,
612
+ next_call_id: 0,
613
+ scheduler: None, // Lazy - no allocation for sync code
614
+ ext_function_load_ip: None, // Set by LoadGlobalCallable/LoadLocalCallable
615
+ module_code: None,
616
+ }
617
+ }
618
+
619
+ /// Reconstructs a VM from a snapshot.
620
+ ///
621
+ /// The heap must already be deserialized. `FunctionId` values
622
+ /// in frames are used to look up pre-compiled `Code` objects from the `Interns`.
623
+ /// The `module_code` is used for frames with `function_id = None`.
624
+ ///
625
+ /// # Arguments
626
+ /// * `snapshot` - The VM snapshot to restore
627
+ /// * `module_code` - Compiled module code (for frames with function_id = None)
628
+ /// * `heap` - The deserialized heap
629
+ /// * `interns` - Interns for looking up function code
630
+ /// * `print_writer` - Writer for print output
631
+ pub fn restore(
632
+ snapshot: VMSnapshot,
633
+ module_code: &'a Code,
634
+ heap: &'a mut Heap<T>,
635
+ interns: &'a Interns,
636
+ print_writer: PrintWriter<'p>,
637
+ ) -> Self {
638
+ // Reconstruct call frames from serialized form
639
+ let frames: Vec<CallFrame<'_>> = snapshot
640
+ .frames
641
+ .into_iter()
642
+ .map(|sf| {
643
+ let code = match sf.function_id {
644
+ Some(func_id) => &interns.get_function(func_id).code,
645
+ None => module_code,
646
+ };
647
+ CallFrame {
648
+ code,
649
+ ip: sf.ip,
650
+ stack_base: sf.stack_base,
651
+ locals_count: sf.locals_count,
652
+ function_id: sf.function_id,
653
+ call_position: sf.call_position,
654
+ should_return: false,
655
+ }
656
+ })
657
+ .collect();
658
+
659
+ // Restore recursion depth to match the number of active function frames.
660
+ // During serialization, recursion_depth is transient (defaults to 0),
661
+ // but cleanup paths call decr_recursion_depth for each non-root frame.
662
+ let current_frame_depth = frames.len().saturating_sub(1); // Subtract 1 for root frame which doesn't contribute to depth
663
+ heap.set_recursion_depth(current_frame_depth);
664
+
665
+ Self {
666
+ stack: snapshot.stack,
667
+ globals: snapshot.globals,
668
+ frames,
669
+ heap,
670
+ interns,
671
+ print_writer,
672
+ exception_stack: snapshot.exception_stack,
673
+ instruction_ip: snapshot.instruction_ip,
674
+ next_call_id: snapshot.next_call_id,
675
+ scheduler: snapshot.scheduler,
676
+ module_code: Some(module_code),
677
+ ext_function_load_ip: None,
678
+ }
679
+ }
680
+ /// Consumes the VM and creates a snapshot for pause/resume.
681
+ ///
682
+ /// **Ownership transfer:** This method takes `self` by value, consuming the VM.
683
+ /// The snapshot owns all Values (refcounts already correct from the live VM).
684
+ /// The heap and namespaces must be serialized alongside this snapshot.
685
+ ///
686
+ /// This is NOT a clone - it's a transfer. After calling this, the original VM
687
+ /// is gone and only the snapshot (+ serialized heap/namespaces) represents the state.
688
+ pub fn snapshot(self) -> VMSnapshot {
689
+ VMSnapshot {
690
+ // Move values directly — no clone, no refcount increment needed
691
+ // (the VM owned them, now the snapshot owns them)
692
+ stack: self.stack,
693
+ globals: self.globals,
694
+ frames: self.frames.into_iter().map(|f| f.serialize()).collect(),
695
+ exception_stack: self.exception_stack,
696
+ instruction_ip: self.instruction_ip,
697
+ next_call_id: self.next_call_id,
698
+ scheduler: self.scheduler,
699
+ }
700
+ }
701
+
702
+ /// Pushes an initial frame for module-level code and runs the VM.
703
+ pub fn run_module(&mut self, code: &'a Code) -> Result<FrameExit, RunError> {
704
+ // Store module code for restoring main task frames during task switching
705
+ self.module_code = Some(code);
706
+ self.push_frame(CallFrame::new_module(code))?;
707
+ self.run()
708
+ }
709
+
710
+ /// Cleans up VM state before the VM is dropped.
711
+ ///
712
+ /// This method must be called before the VM goes out of scope to ensure
713
+ /// proper reference counting cleanup for any exception values and scheduler state.
714
+ pub fn cleanup(&mut self) {
715
+ // Drop all exceptions in the exception stack
716
+ self.exception_stack.drain(..).drop_with_heap(self.heap);
717
+ // Clean up current task's stack values and frame cell references
718
+ self.cleanup_current_task();
719
+ // Clean up scheduler state (task stacks, pending calls, resolved values, frame cells)
720
+ if let Some(scheduler) = &mut self.scheduler {
721
+ scheduler.cleanup(self.heap);
722
+ }
723
+ self.globals.drain(..).drop_with_heap(self.heap);
724
+ }
725
+
726
+ /// Returns the `stack_base` of the current (topmost) call frame.
727
+ ///
728
+ /// Used by `NameLookup` resolution to determine which stack region to cache
729
+ /// resolved values into when the lookup originated from a function scope.
730
+ pub fn current_stack_base(&self) -> usize {
731
+ self.frames
732
+ .last()
733
+ .expect("VM should have at least one frame")
734
+ .stack_base
735
+ }
736
+
737
+ /// Takes ownership of the globals vector, replacing it with an empty vec.
738
+ ///
739
+ /// Used by the REPL to reclaim globals after VM execution completes,
740
+ /// before calling `cleanup()` (which would destroy them in ref-count-panic mode).
741
+ pub fn take_globals(&mut self) -> Vec<Value> {
742
+ std::mem::take(&mut self.globals)
743
+ }
744
+
745
+ /// Allocates a new `CallId` for an external function call.
746
+ ///
747
+ /// Works with or without a scheduler. If a scheduler exists, delegates to it.
748
+ /// Otherwise, uses the VM's `next_call_id` counter directly, avoiding
749
+ /// scheduler creation overhead for synchronous external calls.
750
+ fn allocate_call_id(&mut self) -> CallId {
751
+ if let Some(scheduler) = &mut self.scheduler {
752
+ scheduler.allocate_call_id()
753
+ } else {
754
+ let id = CallId::new(self.next_call_id);
755
+ self.next_call_id += 1;
756
+ id
757
+ }
758
+ }
759
+
760
+ /// Returns true if we're on the main task (or no async at all).
761
+ ///
762
+ /// This is used to determine whether a `ReturnValue` at the last frame means
763
+ /// module-level completion (return to host) or spawned task completion
764
+ /// (handle task completion and switch).
765
+ fn is_main_task(&self) -> bool {
766
+ self.scheduler
767
+ .as_ref()
768
+ .is_none_or(|s| s.current_task_id().is_none_or(TaskId::is_main))
769
+ }
770
+
771
+ /// Main execution loop.
772
+ ///
773
+ /// Fetches opcodes from the current frame's bytecode and executes them.
774
+ /// Returns when execution completes, an error occurs, or an external
775
+ /// call is needed.
776
+ ///
777
+ /// Uses locally cached `code` and `ip` variables to avoid repeated
778
+ /// `frames.last_mut().expect()` calls during operand fetching. The cache
779
+ /// is reloaded after any operation that modifies the frame stack.
780
+ pub fn run(&mut self) -> Result<FrameExit, RunError> {
781
+ // Cache frame state locally to avoid repeated frames.last_mut() calls.
782
+ // The Code reference has lifetime 'a (lives in Interns), independent of frame borrow.
783
+ let mut cached_frame: CachedFrame<'a> = self.new_cached_frame();
784
+
785
+ loop {
786
+ // Check time limit and trigger GC if needed at each instruction.
787
+ // For NoLimitTracker, these are inlined no-ops that compile away.
788
+ self.heap.check_time()?;
789
+
790
+ if self.heap.should_gc() {
791
+ // Sync IP before GC for safety
792
+ self.current_frame_mut().ip = cached_frame.ip;
793
+ self.run_gc();
794
+ }
795
+
796
+ // Track instruction IP for exception table lookup
797
+ self.instruction_ip = cached_frame.ip;
798
+
799
+ // Fetch opcode using cached values (no frame access)
800
+ let opcode = {
801
+ let byte = cached_frame.code.bytecode()[cached_frame.ip];
802
+ cached_frame.ip += 1;
803
+ Opcode::try_from(byte).expect("invalid opcode in bytecode")
804
+ };
805
+
806
+ match opcode {
807
+ // ============================================================
808
+ // Stack Operations
809
+ // ============================================================
810
+ Opcode::Pop => {
811
+ let value = self.pop();
812
+ value.drop_with_heap(self);
813
+ }
814
+ Opcode::Dup => {
815
+ let value = self.peek().clone_with_heap(self);
816
+ self.push(value);
817
+ }
818
+ Opcode::Dup2 => {
819
+ let len = self.stack.len();
820
+ let first = self.stack[len - 2].clone_with_heap(self);
821
+ let second = self.stack[len - 1].clone_with_heap(self);
822
+ self.push(first);
823
+ self.push(second);
824
+ }
825
+ Opcode::Rot2 => {
826
+ // Swap top two: [a, b] → [b, a]
827
+ let len = self.stack.len();
828
+ self.stack.swap(len - 1, len - 2);
829
+ }
830
+ Opcode::Rot3 => {
831
+ // Rotate top three: [a, b, c] → [c, a, b]
832
+ // Uses in-place rotation without cloning
833
+ let len = self.stack.len();
834
+ // Move c out, then shift a→b→c, then put c at a's position
835
+ // Equivalent to: [..rest, a, b, c] → [..rest, c, a, b]
836
+ self.stack[len - 3..].rotate_right(1);
837
+ }
838
+ // Constants & Literals
839
+ Opcode::LoadConst => {
840
+ let idx = fetch_u16!(cached_frame);
841
+ let value = cached_frame.code.constants().get(idx);
842
+ // Handle InternLongInt specially - convert to heap-allocated LongInt
843
+ if let Value::InternLongInt(long_int_id) = value {
844
+ let bi = self.interns.get_long_int(*long_int_id).clone();
845
+ match LongInt::new(bi).into_value(self.heap) {
846
+ Ok(v) => self.push(v),
847
+ Err(e) => catch_sync!(self, cached_frame, RunError::from(e)),
848
+ }
849
+ } else {
850
+ self.push(value.clone_with_heap(self));
851
+ }
852
+ }
853
+ Opcode::LoadNone => self.push(Value::None),
854
+ Opcode::LoadTrue => self.push(Value::Bool(true)),
855
+ Opcode::LoadFalse => self.push(Value::Bool(false)),
856
+ Opcode::LoadSmallInt => {
857
+ let n = fetch_i8!(cached_frame);
858
+ self.push(Value::Int(i64::from(n)));
859
+ }
860
+ // Variables - Specialized Local Loads (no operand)
861
+ Opcode::LoadLocal0 => handle_load_result!(self, cached_frame, self.load_local(&cached_frame, 0)),
862
+ Opcode::LoadLocal1 => handle_load_result!(self, cached_frame, self.load_local(&cached_frame, 1)),
863
+ Opcode::LoadLocal2 => handle_load_result!(self, cached_frame, self.load_local(&cached_frame, 2)),
864
+ Opcode::LoadLocal3 => handle_load_result!(self, cached_frame, self.load_local(&cached_frame, 3)),
865
+ // Variables - General Local Operations
866
+ Opcode::LoadLocal => {
867
+ let slot = u16::from(fetch_u8!(cached_frame));
868
+ handle_load_result!(self, cached_frame, self.load_local(&cached_frame, slot));
869
+ }
870
+ Opcode::LoadLocalW => {
871
+ let slot = fetch_u16!(cached_frame);
872
+ handle_load_result!(self, cached_frame, self.load_local(&cached_frame, slot));
873
+ }
874
+ Opcode::StoreLocal => {
875
+ let slot = u16::from(fetch_u8!(cached_frame));
876
+ self.store_local(&cached_frame, slot);
877
+ }
878
+ Opcode::StoreLocalW => {
879
+ let slot = fetch_u16!(cached_frame);
880
+ self.store_local(&cached_frame, slot);
881
+ }
882
+ Opcode::DeleteLocal => {
883
+ let slot = u16::from(fetch_u8!(cached_frame));
884
+ self.delete_local(&cached_frame, slot);
885
+ }
886
+ Opcode::DeleteGlobal => {
887
+ let slot = fetch_u16!(cached_frame);
888
+ self.delete_global(slot);
889
+ }
890
+ // Variables - Callable-context Local Loads
891
+ Opcode::LoadLocalCallable => {
892
+ let slot = u16::from(fetch_u8!(cached_frame));
893
+ let name_id = StringId::from_index(fetch_u16!(cached_frame));
894
+ self.load_local_callable(&cached_frame, slot, name_id);
895
+ }
896
+ Opcode::LoadLocalCallableW => {
897
+ let slot = fetch_u16!(cached_frame);
898
+ let name_id = StringId::from_index(fetch_u16!(cached_frame));
899
+ self.load_local_callable(&cached_frame, slot, name_id);
900
+ }
901
+ // Variables - Global Operations
902
+ Opcode::LoadGlobal => {
903
+ let slot = fetch_u16!(cached_frame);
904
+ handle_load_result!(self, cached_frame, self.load_global(slot));
905
+ }
906
+ Opcode::LoadGlobalCallable => {
907
+ let slot = fetch_u16!(cached_frame);
908
+ let name_id = StringId::from_index(fetch_u16!(cached_frame));
909
+ self.load_global_callable(slot, name_id);
910
+ }
911
+ Opcode::StoreGlobal => {
912
+ let slot = fetch_u16!(cached_frame);
913
+ self.store_global(slot);
914
+ }
915
+ // Variables - Cell Operations (closures)
916
+ Opcode::LoadCell => {
917
+ let slot = fetch_u16!(cached_frame);
918
+ try_catch_sync!(self, cached_frame, self.load_cell(&cached_frame, slot));
919
+ }
920
+ Opcode::StoreCell => {
921
+ let slot = fetch_u16!(cached_frame);
922
+ self.store_cell(&cached_frame, slot);
923
+ }
924
+ // Binary Operations - route through exception handling for tracebacks
925
+ Opcode::BinaryAdd => try_catch_sync!(self, cached_frame, self.binary_add()),
926
+ Opcode::BinarySub => try_catch_sync!(self, cached_frame, self.binary_sub()),
927
+ Opcode::BinaryMul => try_catch_sync!(self, cached_frame, self.binary_mult()),
928
+ Opcode::BinaryDiv => try_catch_sync!(self, cached_frame, self.binary_div()),
929
+ Opcode::BinaryFloorDiv => try_catch_sync!(self, cached_frame, self.binary_floordiv()),
930
+ Opcode::BinaryMod => try_catch_sync!(self, cached_frame, self.binary_mod()),
931
+ Opcode::BinaryPow => try_catch_sync!(self, cached_frame, self.binary_pow()),
932
+ // Bitwise operations - only work on integers
933
+ Opcode::BinaryAnd => try_catch_sync!(self, cached_frame, self.binary_and()),
934
+ Opcode::BinaryOr => try_catch_sync!(self, cached_frame, self.binary_or()),
935
+ Opcode::BinaryXor => try_catch_sync!(self, cached_frame, self.binary_xor()),
936
+ Opcode::BinaryLShift => {
937
+ try_catch_sync!(self, cached_frame, self.binary_bitwise(BitwiseOp::LShift));
938
+ }
939
+ Opcode::BinaryRShift => {
940
+ try_catch_sync!(self, cached_frame, self.binary_bitwise(BitwiseOp::RShift));
941
+ }
942
+ Opcode::BinaryMatMul => try_catch_sync!(self, cached_frame, self.binary_matmul()),
943
+ // Comparison Operations
944
+ Opcode::CompareEq => try_catch_sync!(self, cached_frame, self.compare_eq()),
945
+ Opcode::CompareNe => try_catch_sync!(self, cached_frame, self.compare_ne()),
946
+ Opcode::CompareLt => try_catch_sync!(self, cached_frame, self.compare_ord(Ordering::is_lt)),
947
+ Opcode::CompareLe => try_catch_sync!(self, cached_frame, self.compare_ord(Ordering::is_le)),
948
+ Opcode::CompareGt => try_catch_sync!(self, cached_frame, self.compare_ord(Ordering::is_gt)),
949
+ Opcode::CompareGe => try_catch_sync!(self, cached_frame, self.compare_ord(Ordering::is_ge)),
950
+ Opcode::CompareIs => self.compare_is(false),
951
+ Opcode::CompareIsNot => self.compare_is(true),
952
+ Opcode::CompareIn => try_catch_sync!(self, cached_frame, self.compare_in(false)),
953
+ Opcode::CompareNotIn => try_catch_sync!(self, cached_frame, self.compare_in(true)),
954
+ Opcode::CompareModEq => {
955
+ let const_idx = fetch_u16!(cached_frame);
956
+ let k = cached_frame.code.constants().get(const_idx);
957
+ try_catch_sync!(self, cached_frame, self.compare_mod_eq(k));
958
+ }
959
+ // Unary Operations
960
+ Opcode::UnaryNot => {
961
+ let value = self.pop();
962
+ let result = !value.py_bool(self);
963
+ value.drop_with_heap(self);
964
+ self.push(Value::Bool(result));
965
+ }
966
+ Opcode::UnaryNeg => {
967
+ // Unary minus - negate numeric value
968
+ let value = self.pop();
969
+ match value {
970
+ Value::Int(n) => {
971
+ // Use checked_neg to handle i64::MIN overflow
972
+ if let Some(negated) = n.checked_neg() {
973
+ self.push(Value::Int(negated));
974
+ } else {
975
+ // i64::MIN negated overflows to LongInt
976
+ let li = -LongInt::from(n);
977
+ match li.into_value(self.heap) {
978
+ Ok(v) => self.push(v),
979
+ Err(e) => catch_sync!(self, cached_frame, RunError::from(e)),
980
+ }
981
+ }
982
+ }
983
+ Value::Float(f) => self.push(Value::Float(-f)),
984
+ Value::Bool(b) => self.push(Value::Int(if b { -1 } else { 0 })),
985
+ Value::Ref(id) => {
986
+ if let HeapData::LongInt(li) = self.heap.get(id) {
987
+ let negated = -LongInt::new(li.inner().clone());
988
+ value.drop_with_heap(self);
989
+ match negated.into_value(self.heap) {
990
+ Ok(v) => self.push(v),
991
+ Err(e) => catch_sync!(self, cached_frame, RunError::from(e)),
992
+ }
993
+ } else {
994
+ let value_type = value.py_type(self.heap);
995
+ value.drop_with_heap(self);
996
+ catch_sync!(self, cached_frame, ExcType::unary_type_error("-", value_type));
997
+ }
998
+ }
999
+ _ => {
1000
+ let value_type = value.py_type(self.heap);
1001
+ value.drop_with_heap(self);
1002
+ catch_sync!(self, cached_frame, ExcType::unary_type_error("-", value_type));
1003
+ }
1004
+ }
1005
+ }
1006
+ Opcode::UnaryPos => {
1007
+ // Unary plus - converts bools to int, no-op for other numbers
1008
+ let value = self.pop();
1009
+ match value {
1010
+ Value::Int(_) | Value::Float(_) => self.push(value),
1011
+ Value::Bool(b) => self.push(Value::Int(i64::from(b))),
1012
+ Value::Ref(id) => {
1013
+ if matches!(self.heap.get(id), HeapData::LongInt(_)) {
1014
+ // LongInt - return as-is (value already has correct refcount)
1015
+ self.push(value);
1016
+ } else {
1017
+ let value_type = value.py_type(self.heap);
1018
+ value.drop_with_heap(self);
1019
+ catch_sync!(self, cached_frame, ExcType::unary_type_error("+", value_type));
1020
+ }
1021
+ }
1022
+ _ => {
1023
+ let value_type = value.py_type(self.heap);
1024
+ value.drop_with_heap(self);
1025
+ catch_sync!(self, cached_frame, ExcType::unary_type_error("+", value_type));
1026
+ }
1027
+ }
1028
+ }
1029
+ Opcode::UnaryInvert => {
1030
+ // Bitwise NOT
1031
+ let value = self.pop();
1032
+ match value {
1033
+ Value::Int(n) => self.push(Value::Int(!n)),
1034
+ Value::Bool(b) => self.push(Value::Int(!i64::from(b))),
1035
+ Value::Ref(id) => {
1036
+ if let HeapData::LongInt(li) = self.heap.get(id) {
1037
+ // LongInt bitwise NOT: ~x = -(x + 1)
1038
+ let inverted = -(li.inner() + 1i32);
1039
+ value.drop_with_heap(self);
1040
+ match LongInt::new(inverted).into_value(self.heap) {
1041
+ Ok(v) => self.push(v),
1042
+ Err(e) => catch_sync!(self, cached_frame, RunError::from(e)),
1043
+ }
1044
+ } else {
1045
+ let value_type = value.py_type(self.heap);
1046
+ value.drop_with_heap(self);
1047
+ catch_sync!(self, cached_frame, ExcType::unary_type_error("~", value_type));
1048
+ }
1049
+ }
1050
+ _ => {
1051
+ let value_type = value.py_type(self.heap);
1052
+ value.drop_with_heap(self);
1053
+ catch_sync!(self, cached_frame, ExcType::unary_type_error("~", value_type));
1054
+ }
1055
+ }
1056
+ }
1057
+ // In-place Operations - route through exception handling
1058
+ Opcode::InplaceAdd => try_catch_sync!(self, cached_frame, self.inplace_add()),
1059
+ // Other in-place ops use the same logic as binary ops for now
1060
+ Opcode::InplaceSub => try_catch_sync!(self, cached_frame, self.binary_sub()),
1061
+ Opcode::InplaceMul => try_catch_sync!(self, cached_frame, self.binary_mult()),
1062
+ Opcode::InplaceDiv => try_catch_sync!(self, cached_frame, self.binary_div()),
1063
+ Opcode::InplaceFloorDiv => try_catch_sync!(self, cached_frame, self.binary_floordiv()),
1064
+ Opcode::InplaceMod => try_catch_sync!(self, cached_frame, self.binary_mod()),
1065
+ Opcode::InplacePow => try_catch_sync!(self, cached_frame, self.binary_pow()),
1066
+ Opcode::InplaceAnd => {
1067
+ try_catch_sync!(self, cached_frame, self.binary_bitwise(BitwiseOp::And));
1068
+ }
1069
+ Opcode::InplaceOr => try_catch_sync!(self, cached_frame, self.binary_bitwise(BitwiseOp::Or)),
1070
+ Opcode::InplaceXor => {
1071
+ try_catch_sync!(self, cached_frame, self.binary_bitwise(BitwiseOp::Xor));
1072
+ }
1073
+ Opcode::InplaceLShift => {
1074
+ try_catch_sync!(self, cached_frame, self.binary_bitwise(BitwiseOp::LShift));
1075
+ }
1076
+ Opcode::InplaceRShift => {
1077
+ try_catch_sync!(self, cached_frame, self.binary_bitwise(BitwiseOp::RShift));
1078
+ }
1079
+ // Collection Building - route through exception handling
1080
+ Opcode::BuildList => {
1081
+ let count = fetch_u16!(cached_frame) as usize;
1082
+ try_catch_sync!(self, cached_frame, self.build_list(count));
1083
+ }
1084
+ Opcode::BuildTuple => {
1085
+ let count = fetch_u16!(cached_frame) as usize;
1086
+ try_catch_sync!(self, cached_frame, self.build_tuple(count));
1087
+ }
1088
+ Opcode::BuildDict => {
1089
+ let count = fetch_u16!(cached_frame) as usize;
1090
+ try_catch_sync!(self, cached_frame, self.build_dict(count));
1091
+ }
1092
+ Opcode::BuildSet => {
1093
+ let count = fetch_u16!(cached_frame) as usize;
1094
+ try_catch_sync!(self, cached_frame, self.build_set(count));
1095
+ }
1096
+ Opcode::FormatValue => {
1097
+ let flags = fetch_u8!(cached_frame);
1098
+ try_catch_sync!(self, cached_frame, self.format_value(flags));
1099
+ }
1100
+ Opcode::BuildFString => {
1101
+ let count = fetch_u16!(cached_frame) as usize;
1102
+ try_catch_sync!(self, cached_frame, self.build_fstring(count));
1103
+ }
1104
+ Opcode::BuildSlice => {
1105
+ try_catch_sync!(self, cached_frame, self.build_slice());
1106
+ }
1107
+ Opcode::ListExtend => {
1108
+ try_catch_sync!(self, cached_frame, self.list_extend());
1109
+ }
1110
+ Opcode::ListToTuple => {
1111
+ try_catch_sync!(self, cached_frame, self.list_to_tuple());
1112
+ }
1113
+ Opcode::DictMerge => {
1114
+ let func_name_id = fetch_u16!(cached_frame);
1115
+ try_catch_sync!(self, cached_frame, self.dict_merge(func_name_id));
1116
+ }
1117
+ // PEP 448 literal building
1118
+ Opcode::DictUpdate => {
1119
+ let depth = fetch_u8!(cached_frame) as usize;
1120
+ try_catch_sync!(self, cached_frame, self.dict_update(depth));
1121
+ }
1122
+ Opcode::SetExtend => {
1123
+ let depth = fetch_u8!(cached_frame) as usize;
1124
+ try_catch_sync!(self, cached_frame, self.set_extend(depth));
1125
+ }
1126
+ // Comprehension Building - append/add/set items during iteration
1127
+ Opcode::ListAppend => {
1128
+ let depth = fetch_u8!(cached_frame) as usize;
1129
+ try_catch_sync!(self, cached_frame, self.list_append(depth));
1130
+ }
1131
+ Opcode::SetAdd => {
1132
+ let depth = fetch_u8!(cached_frame) as usize;
1133
+ try_catch_sync!(self, cached_frame, self.set_add(depth));
1134
+ }
1135
+ Opcode::DictSetItem => {
1136
+ let depth = fetch_u8!(cached_frame) as usize;
1137
+ try_catch_sync!(self, cached_frame, self.dict_set_item(depth));
1138
+ }
1139
+ // Subscript & Attribute - route through exception handling
1140
+ Opcode::BinarySubscr => {
1141
+ let index = self.pop();
1142
+ let obj = self.pop();
1143
+ let result = obj.py_getitem(&index, self);
1144
+ obj.drop_with_heap(self);
1145
+ index.drop_with_heap(self);
1146
+ match result {
1147
+ Ok(v) => self.push(v),
1148
+ Err(e) => catch_sync!(self, cached_frame, e),
1149
+ }
1150
+ }
1151
+ Opcode::StoreSubscr => {
1152
+ // Stack order: value, obj, index (TOS)
1153
+ let index = self.pop();
1154
+ let mut obj = self.pop();
1155
+ let value = self.pop();
1156
+ let result = obj.py_setitem(index, value, self);
1157
+ obj.drop_with_heap(self);
1158
+ if let Err(e) = result {
1159
+ catch_sync!(self, cached_frame, e);
1160
+ }
1161
+ }
1162
+ Opcode::LoadAttr => {
1163
+ let name_idx = fetch_u16!(cached_frame);
1164
+ let name_id = StringId::from_index(name_idx);
1165
+ handle_call_result!(self, cached_frame, self.load_attr(name_id));
1166
+ }
1167
+ Opcode::LoadAttrImport => {
1168
+ let name_idx = fetch_u16!(cached_frame);
1169
+ let name_id = StringId::from_index(name_idx);
1170
+ handle_call_result!(self, cached_frame, self.load_attr_import(name_id));
1171
+ }
1172
+ Opcode::StoreAttr => {
1173
+ let name_idx = fetch_u16!(cached_frame);
1174
+ let name_id = StringId::from_index(name_idx);
1175
+ try_catch_sync!(self, cached_frame, self.store_attr(name_id));
1176
+ }
1177
+ // Control Flow - use cached_frame.ip directly for jumps
1178
+ Opcode::Jump => {
1179
+ let offset = fetch_i16!(cached_frame);
1180
+ jump_relative!(cached_frame.ip, offset);
1181
+ }
1182
+ Opcode::JumpIfTrue => {
1183
+ let offset = fetch_i16!(cached_frame);
1184
+ let cond = self.pop();
1185
+ if cond.py_bool(self) {
1186
+ jump_relative!(cached_frame.ip, offset);
1187
+ }
1188
+ cond.drop_with_heap(self);
1189
+ }
1190
+ Opcode::JumpIfFalse => {
1191
+ let offset = fetch_i16!(cached_frame);
1192
+ let cond = self.pop();
1193
+ if !cond.py_bool(self) {
1194
+ jump_relative!(cached_frame.ip, offset);
1195
+ }
1196
+ cond.drop_with_heap(self);
1197
+ }
1198
+ Opcode::JumpIfTrueOrPop => {
1199
+ let offset = fetch_i16!(cached_frame);
1200
+ if self.peek().py_bool(self) {
1201
+ jump_relative!(cached_frame.ip, offset);
1202
+ } else {
1203
+ let value = self.pop();
1204
+ value.drop_with_heap(self);
1205
+ }
1206
+ }
1207
+ Opcode::JumpIfFalseOrPop => {
1208
+ let offset = fetch_i16!(cached_frame);
1209
+ if self.peek().py_bool(self) {
1210
+ let value = self.pop();
1211
+ value.drop_with_heap(self);
1212
+ } else {
1213
+ jump_relative!(cached_frame.ip, offset);
1214
+ }
1215
+ }
1216
+ // Iteration - route through exception handling
1217
+ Opcode::GetIter => {
1218
+ let value = self.pop();
1219
+ // Create a MontyIter from the value and store on heap
1220
+ match MontyIter::new(value, self) {
1221
+ Ok(iter) => match self.heap.allocate(HeapData::Iter(iter)) {
1222
+ Ok(heap_id) => self.push(Value::Ref(heap_id)),
1223
+ Err(e) => catch_sync!(self, cached_frame, e.into()),
1224
+ },
1225
+ Err(e) => catch_sync!(self, cached_frame, e),
1226
+ }
1227
+ }
1228
+ Opcode::ForIter => {
1229
+ let offset = fetch_i16!(cached_frame);
1230
+ // Peek at the iterator on TOS and extract heap_id
1231
+ let Value::Ref(heap_id) = *self.peek() else {
1232
+ return Err(RunError::internal("ForIter: expected iterator ref on stack"));
1233
+ };
1234
+
1235
+ // Use advance_iterator which avoids std::mem::replace overhead
1236
+ // by using a two-phase approach: read state, get value, update index
1237
+ match advance_on_heap(self.heap, heap_id, self.interns) {
1238
+ Ok(Some(value)) => self.push(value),
1239
+ Ok(None) => {
1240
+ // Iterator exhausted - pop it and jump to end
1241
+ let iter = self.pop();
1242
+ iter.drop_with_heap(self);
1243
+ jump_relative!(cached_frame.ip, offset);
1244
+ }
1245
+ Err(e) => {
1246
+ // Error during iteration (e.g., dict size changed)
1247
+ let iter = self.pop();
1248
+ iter.drop_with_heap(self);
1249
+ catch_sync!(self, cached_frame, e);
1250
+ }
1251
+ }
1252
+ }
1253
+ // Function Calls - sync IP before call, reload cache after frame changes
1254
+ Opcode::CallFunction => {
1255
+ let arg_count = fetch_u8!(cached_frame) as usize;
1256
+
1257
+ // Sync IP before call (call_function may access frame for traceback)
1258
+ self.current_frame_mut().ip = cached_frame.ip;
1259
+
1260
+ handle_call_result!(self, cached_frame, self.exec_call_function(arg_count));
1261
+ }
1262
+ Opcode::CallBuiltinFunction => {
1263
+ // Fetch operands: builtin_id (u8) + arg_count (u8)
1264
+ let builtin_id = fetch_u8!(cached_frame);
1265
+ let arg_count = fetch_u8!(cached_frame) as usize;
1266
+
1267
+ // Sync IP before call (builtins like map() may call evaluate_function
1268
+ // which pushes frames and runs a nested run() loop)
1269
+ self.current_frame_mut().ip = cached_frame.ip;
1270
+
1271
+ match self.exec_call_builtin_function(builtin_id, arg_count) {
1272
+ Ok(result) => self.push(result),
1273
+ Err(err) => catch_sync!(self, cached_frame, err),
1274
+ }
1275
+ }
1276
+ Opcode::CallBuiltinType => {
1277
+ // Fetch operands: type_id (u8) + arg_count (u8)
1278
+ let type_id = fetch_u8!(cached_frame);
1279
+ let arg_count = fetch_u8!(cached_frame) as usize;
1280
+
1281
+ match self.exec_call_builtin_type(type_id, arg_count) {
1282
+ Ok(result) => self.push(result),
1283
+ // IP sync deferred to error path (no frame push possible)
1284
+ Err(err) => catch_sync!(self, cached_frame, err),
1285
+ }
1286
+ }
1287
+ Opcode::CallFunctionKw => {
1288
+ // Fetch operands: pos_count, kw_count, then kw_count name indices
1289
+ let pos_count = fetch_u8!(cached_frame) as usize;
1290
+ let kw_count = fetch_u8!(cached_frame) as usize;
1291
+
1292
+ // Read keyword name StringIds
1293
+ let mut kwname_ids = Vec::with_capacity(kw_count);
1294
+ for _ in 0..kw_count {
1295
+ kwname_ids.push(StringId::from_index(fetch_u16!(cached_frame)));
1296
+ }
1297
+
1298
+ // Sync IP before call (call_function may access frame for traceback)
1299
+ self.current_frame_mut().ip = cached_frame.ip;
1300
+
1301
+ handle_call_result!(self, cached_frame, self.exec_call_function_kw(pos_count, kwname_ids));
1302
+ }
1303
+ Opcode::CallAttr => {
1304
+ // CallAttr: u16 name_id, u8 arg_count
1305
+ // Stack: [obj, arg1, arg2, ..., argN] -> [result]
1306
+ let name_idx = fetch_u16!(cached_frame);
1307
+ let arg_count = fetch_u8!(cached_frame) as usize;
1308
+ let name_id = StringId::from_index(name_idx);
1309
+
1310
+ // Sync IP before call (may yield to host for OS/external calls)
1311
+ self.current_frame_mut().ip = cached_frame.ip;
1312
+
1313
+ handle_call_result!(self, cached_frame, self.exec_call_attr(name_id, arg_count));
1314
+ }
1315
+ Opcode::CallAttrKw => {
1316
+ // CallAttrKw: u16 name_id, u8 pos_count, u8 kw_count, then kw_count u16 name indices
1317
+ // Stack: [obj, pos_args..., kw_values...] -> [result]
1318
+ let name_idx = fetch_u16!(cached_frame);
1319
+ let pos_count = fetch_u8!(cached_frame) as usize;
1320
+ let kw_count = fetch_u8!(cached_frame) as usize;
1321
+ let name_id = StringId::from_index(name_idx);
1322
+
1323
+ // Read keyword name StringIds
1324
+ let mut kwname_ids = Vec::with_capacity(kw_count);
1325
+ for _ in 0..kw_count {
1326
+ kwname_ids.push(StringId::from_index(fetch_u16!(cached_frame)));
1327
+ }
1328
+
1329
+ // Sync IP before call (may yield to host for OS/external calls)
1330
+ self.current_frame_mut().ip = cached_frame.ip;
1331
+
1332
+ handle_call_result!(
1333
+ self,
1334
+ cached_frame,
1335
+ self.exec_call_attr_kw(name_id, pos_count, kwname_ids)
1336
+ );
1337
+ }
1338
+ Opcode::CallFunctionExtended => {
1339
+ let flags = fetch_u8!(cached_frame);
1340
+ let has_kwargs = (flags & 0x01) != 0;
1341
+
1342
+ // Sync IP before call
1343
+ self.current_frame_mut().ip = cached_frame.ip;
1344
+
1345
+ handle_call_result!(self, cached_frame, self.exec_call_function_extended(has_kwargs));
1346
+ }
1347
+ Opcode::CallAttrExtended => {
1348
+ let name_idx = fetch_u16!(cached_frame);
1349
+ let flags = fetch_u8!(cached_frame);
1350
+ let name_id = StringId::from_index(name_idx);
1351
+ let has_kwargs = (flags & 0x01) != 0;
1352
+
1353
+ // Sync IP before call (may yield to host for OS/external calls)
1354
+ self.current_frame_mut().ip = cached_frame.ip;
1355
+
1356
+ handle_call_result!(self, cached_frame, self.exec_call_attr_extended(name_id, has_kwargs));
1357
+ }
1358
+ // Function Definition
1359
+ Opcode::MakeFunction => {
1360
+ let func_idx = fetch_u16!(cached_frame);
1361
+ let defaults_count = fetch_u8!(cached_frame) as usize;
1362
+ let func_id = FunctionId::from_index(func_idx);
1363
+
1364
+ if defaults_count == 0 {
1365
+ // No defaults - use inline Value::Function (no heap allocation)
1366
+ self.push(Value::DefFunction(func_id));
1367
+ } else {
1368
+ // Pop default values from stack (drain maintains order: first pushed = first in vec)
1369
+ let defaults = self.pop_n(defaults_count);
1370
+
1371
+ // Create FunctionDefaults on heap and push reference
1372
+ let heap_id = self
1373
+ .heap
1374
+ .allocate(HeapData::FunctionDefaults(FunctionDefaults { func_id, defaults }))?;
1375
+ self.push(Value::Ref(heap_id));
1376
+ }
1377
+ }
1378
+ Opcode::MakeClosure => {
1379
+ let func_idx = fetch_u16!(cached_frame);
1380
+ let defaults_count = fetch_u8!(cached_frame) as usize;
1381
+ let cell_count = fetch_u8!(cached_frame) as usize;
1382
+ let func_id = FunctionId::from_index(func_idx);
1383
+
1384
+ // Pop cells from stack (pushed after defaults, so on top)
1385
+ // Cells are Value::Ref pointing to HeapData::Cell
1386
+ // We use individual pops which reverses order, so we need to reverse back
1387
+ let mut cells = Vec::with_capacity(cell_count);
1388
+ for _ in 0..cell_count {
1389
+ // mut needed for dec_ref_forget when ref-count-panic feature is enabled
1390
+ #[cfg_attr(not(feature = "ref-count-panic"), expect(unused_mut))]
1391
+ let mut cell_val = self.pop();
1392
+ match &cell_val {
1393
+ Value::Ref(heap_id) => {
1394
+ // Keep the reference - the Closure will own the HeapId
1395
+ cells.push(*heap_id);
1396
+ // Mark the Value as dereferenced since Closure takes ownership
1397
+ // of the reference count (we don't call drop_with_heap because
1398
+ // we're not decrementing the refcount, just transferring it)
1399
+ #[cfg(feature = "ref-count-panic")]
1400
+ cell_val.dec_ref_forget();
1401
+ }
1402
+ _ => {
1403
+ return Err(RunError::internal("MakeClosure: expected cell reference on stack"));
1404
+ }
1405
+ }
1406
+ }
1407
+ // Reverse to get original order (individual pops reverse the order)
1408
+ cells.reverse();
1409
+
1410
+ // Pop default values from stack (drain maintains order: first pushed = first in vec)
1411
+ let defaults = self.pop_n(defaults_count);
1412
+
1413
+ // Create Closure on heap and push reference
1414
+ let heap_id = self.heap.allocate(HeapData::Closure(Closure {
1415
+ func_id,
1416
+ cells,
1417
+ defaults,
1418
+ }))?;
1419
+ self.push(Value::Ref(heap_id));
1420
+ }
1421
+ // Exception Handling
1422
+ Opcode::Raise => {
1423
+ let exc = self.pop();
1424
+ let error = self.make_exception(exc, true); // is_raise=true, hide caret
1425
+ catch_sync!(self, cached_frame, error);
1426
+ }
1427
+ Opcode::Reraise => {
1428
+ // Pop the current exception from the stack to re-raise it
1429
+ // If caught, handle_exception will push it back
1430
+ let error = if let Some(exc) = self.exception_stack.pop() {
1431
+ self.make_exception(exc, true) // is_raise=true for reraise
1432
+ } else {
1433
+ // No active exception - create a RuntimeError
1434
+ SimpleException::new_msg(ExcType::RuntimeError, "No active exception to reraise").into()
1435
+ };
1436
+ catch_sync!(self, cached_frame, error);
1437
+ }
1438
+ Opcode::ClearException => {
1439
+ // Pop the current exception from the stack
1440
+ // This restores the previous exception context (if any)
1441
+ if let Some(exc) = self.exception_stack.pop() {
1442
+ exc.drop_with_heap(self);
1443
+ }
1444
+ }
1445
+ Opcode::CheckExcMatch => {
1446
+ // Stack: [exception, exc_type] -> [exception, bool]
1447
+ let exc_type = self.pop();
1448
+ let exception = self.peek();
1449
+ let result = self.check_exc_match(exception, &exc_type);
1450
+ exc_type.drop_with_heap(self);
1451
+ let result = result?;
1452
+ self.push(Value::Bool(result));
1453
+ }
1454
+ // Return - reload cache after popping frame
1455
+ Opcode::ReturnValue => {
1456
+ let value = self.pop();
1457
+ if self.frames.len() == 1 {
1458
+ // Last frame - check if this is main task or spawned task
1459
+ let is_main_task = self.is_main_task();
1460
+
1461
+ if is_main_task {
1462
+ // Module-level return - we're done
1463
+ return Ok(FrameExit::Return(value));
1464
+ }
1465
+
1466
+ // Spawned task completed - handle task completion
1467
+ let result = self.handle_task_completion(value);
1468
+ match result {
1469
+ Ok(AwaitResult::ValueReady(v)) => {
1470
+ self.push(v);
1471
+ }
1472
+ Ok(AwaitResult::FramePushed) => {
1473
+ // Switched to another task - reload cache
1474
+ reload_cache!(self, cached_frame);
1475
+ }
1476
+ Ok(AwaitResult::Yield(pending)) => {
1477
+ // All tasks blocked - return to host
1478
+ return Ok(FrameExit::ResolveFutures(pending));
1479
+ }
1480
+ Err(e) => {
1481
+ catch_sync!(self, cached_frame, e);
1482
+ }
1483
+ }
1484
+ continue;
1485
+ }
1486
+ // Pop current frame and push return value
1487
+ if self.pop_frame() {
1488
+ // This frame indicated evaluation should stop - return to host with value
1489
+ // e.g. `evaluate_function`
1490
+ return Ok(FrameExit::Return(value));
1491
+ }
1492
+ self.push(value);
1493
+ // Reload cache from parent frame
1494
+ reload_cache!(self, cached_frame);
1495
+ }
1496
+ // Async/Await
1497
+ Opcode::Await => {
1498
+ // Sync IP before exec (may push new frame for coroutine)
1499
+ self.current_frame_mut().ip = cached_frame.ip;
1500
+ let result = self.exec_get_awaitable();
1501
+ match result {
1502
+ Ok(AwaitResult::ValueReady(value)) => {
1503
+ self.push(value);
1504
+ }
1505
+ Ok(AwaitResult::FramePushed) => {
1506
+ // Reload cache after pushing a new frame
1507
+ reload_cache!(self, cached_frame);
1508
+ }
1509
+ Ok(AwaitResult::Yield(pending_calls)) => {
1510
+ // All tasks are blocked - return control to host
1511
+ return Ok(FrameExit::ResolveFutures(pending_calls));
1512
+ }
1513
+ Err(e) => {
1514
+ catch_sync!(self, cached_frame, e);
1515
+ }
1516
+ }
1517
+ }
1518
+ // Unpacking - route through exception handling
1519
+ Opcode::UnpackSequence => {
1520
+ let count = fetch_u8!(cached_frame) as usize;
1521
+ try_catch_sync!(self, cached_frame, self.unpack_sequence(count));
1522
+ }
1523
+ Opcode::UnpackEx => {
1524
+ let before = fetch_u8!(cached_frame) as usize;
1525
+ let after = fetch_u8!(cached_frame) as usize;
1526
+ try_catch_sync!(self, cached_frame, self.unpack_ex(before, after));
1527
+ }
1528
+ // Special
1529
+ Opcode::Nop => {
1530
+ // No operation
1531
+ }
1532
+ // Module Operations
1533
+ Opcode::LoadModule => {
1534
+ let module_id = fetch_u8!(cached_frame);
1535
+ try_catch_sync!(self, cached_frame, self.load_module(module_id));
1536
+ }
1537
+ Opcode::RaiseImportError => {
1538
+ // Fetch the module name from the constant pool and raise ModuleNotFoundError
1539
+ let const_idx = fetch_u16!(cached_frame);
1540
+ let module_name = cached_frame.code.constants().get(const_idx);
1541
+ // The constant should be an InternString from compile_import/compile_import_from
1542
+ let name_str = match module_name {
1543
+ Value::InternString(id) => self.interns.get_str(*id),
1544
+ _ => "<unknown>",
1545
+ };
1546
+ let error = ExcType::module_not_found_error(name_str);
1547
+ catch_sync!(self, cached_frame, error);
1548
+ }
1549
+ }
1550
+ }
1551
+ }
1552
+
1553
+ /// Loads a built-in module and pushes it onto the stack.
1554
+ fn load_module(&mut self, module_id: u8) -> RunResult<()> {
1555
+ let module = BuiltinModule::from_repr(module_id).expect("unknown module id");
1556
+
1557
+ // Create the module on the heap using pre-interned strings
1558
+ let heap_id = module.create(self)?;
1559
+ self.push(Value::Ref(heap_id));
1560
+ Ok(())
1561
+ }
1562
+
1563
+ /// Resumes execution after an external call completes.
1564
+ ///
1565
+ /// Pushes the return value onto the stack and continues execution.
1566
+ pub fn resume(&mut self, obj: MontyObject) -> Result<FrameExit, RunError> {
1567
+ let value = obj
1568
+ .to_value(self)
1569
+ .map_err(|e| SimpleException::new(ExcType::RuntimeError, Some(format!("invalid return type: {e}"))))?;
1570
+ self.push(value);
1571
+ self.run()
1572
+ }
1573
+
1574
+ /// Sets the instruction IP used for exception table lookup and traceback generation.
1575
+ ///
1576
+ /// Used by `run()` to restore the IP to the load instruction's position before
1577
+ /// raising `NameError` for auto-injected `ExtFunction` values, so the traceback
1578
+ /// points to the name reference rather than the call expression.
1579
+ pub fn set_instruction_ip(&mut self, ip: usize) {
1580
+ self.instruction_ip = ip;
1581
+ }
1582
+
1583
+ /// Resumes execution after an external call raised an exception.
1584
+ ///
1585
+ /// Uses the exception handling mechanism to try to catch the exception.
1586
+ /// If caught, continues execution at the handler. If not, propagates the error.
1587
+ pub fn resume_with_exception(&mut self, error: RunError) -> Result<FrameExit, RunError> {
1588
+ // Use the normal exception handling mechanism
1589
+ // handle_exception returns None if caught, Some(error) if not caught
1590
+ if let Some(uncaught_error) = self.handle_exception(error) {
1591
+ return Err(uncaught_error);
1592
+ }
1593
+ // Exception was caught, continue execution
1594
+ self.run()
1595
+ }
1596
+
1597
+ // ========================================================================
1598
+ // Stack Operations
1599
+ // ========================================================================
1600
+
1601
+ /// Pushes a value onto the operand stack.
1602
+ #[inline]
1603
+ pub(crate) fn push(&mut self, value: Value) {
1604
+ self.stack.push(value);
1605
+ }
1606
+
1607
+ /// Pops a value from the operand stack.
1608
+ #[inline]
1609
+ pub(super) fn pop(&mut self) -> Value {
1610
+ self.stack.pop().expect("stack underflow")
1611
+ }
1612
+
1613
+ /// Peeks at the top of the operand stack without removing it.
1614
+ #[inline]
1615
+ pub(super) fn peek(&self) -> &Value {
1616
+ self.stack.last().expect("stack underflow")
1617
+ }
1618
+
1619
+ /// Pops n values from the stack in reverse order (first popped is last in vec).
1620
+ pub(super) fn pop_n(&mut self, n: usize) -> Vec<Value> {
1621
+ let start = self.stack.len() - n;
1622
+ self.stack.drain(start..).collect()
1623
+ }
1624
+
1625
+ // ========================================================================
1626
+ // Frame Operations
1627
+ // ========================================================================
1628
+
1629
+ /// Returns a reference to the current (topmost) call frame.
1630
+ #[inline]
1631
+ pub(crate) fn current_frame(&self) -> &CallFrame<'a> {
1632
+ self.frames.last().expect("no active frame")
1633
+ }
1634
+
1635
+ /// Creates a new cached frame from the current frame.
1636
+ #[inline]
1637
+ pub(super) fn new_cached_frame(&self) -> CachedFrame<'a> {
1638
+ self.current_frame().into()
1639
+ }
1640
+
1641
+ /// Returns a mutable reference to the current call frame.
1642
+ #[inline]
1643
+ pub(super) fn current_frame_mut(&mut self) -> &mut CallFrame<'a> {
1644
+ self.frames.last_mut().expect("no active frame")
1645
+ }
1646
+
1647
+ /// Pushes the given frame onto the call stack.
1648
+ ///
1649
+ /// Returns an error if the recursion depth limit is exceeded by pushing this frame.
1650
+ pub(super) fn push_frame(&mut self, frame: CallFrame<'a>) -> RunResult<()> {
1651
+ // root frame doesn't count towards recursion depth, so only check if there's already a frame on the stack
1652
+ if !self.frames.is_empty()
1653
+ && let Err(e) = self.heap.incr_recursion_depth()
1654
+ {
1655
+ self.cleanup_frame_state(&frame);
1656
+ return Err(e.into());
1657
+ }
1658
+ self.frames.push(frame);
1659
+
1660
+ Ok(())
1661
+ }
1662
+
1663
+ /// Pops the current frame from the call stack.
1664
+ ///
1665
+ /// Cleans up the frame's stack region and namespace (except for global namespace).
1666
+ /// Syncs `instruction_ip` to the parent frame's IP so that exception handling
1667
+ /// looks up handlers in the correct frame's exception table.
1668
+ ///
1669
+ /// Returns `true` if this frame indicated evaluation should stop when popped.
1670
+ pub(super) fn pop_frame(&mut self) -> bool {
1671
+ let frame = self.frames.pop().expect("no frame to pop");
1672
+ self.cleanup_frame_state(&frame);
1673
+ // Sync instruction_ip to the parent frame so exception table lookups
1674
+ // target the correct frame after returning from a nested run() call.
1675
+ if let Some(parent) = self.frames.last() {
1676
+ self.instruction_ip = parent.ip;
1677
+ }
1678
+ // Decrement recursion depth if this wasn't the root frame
1679
+ if !self.frames.is_empty() {
1680
+ self.heap.decr_recursion_depth();
1681
+ }
1682
+ frame.should_return
1683
+ }
1684
+
1685
+ fn cleanup_frame_state(&mut self, frame: &CallFrame<'_>) {
1686
+ // Clean up frame's stack region (locals + operands).
1687
+ // Locals occupy stack[frame.stack_base..frame.stack_base + frame.locals_count],
1688
+ // operands are above that. Draining from stack_base covers both.
1689
+ self.stack
1690
+ .drain(frame.stack_base..)
1691
+ .for_each(|value| value.drop_with_heap(&mut *self.heap));
1692
+
1693
+ // Track freed memory for locals
1694
+ if frame.locals_count > 0 {
1695
+ let size = frame.locals_count as usize * std::mem::size_of::<Value>();
1696
+ self.heap.tracker_mut().on_free(|| size);
1697
+ }
1698
+ }
1699
+
1700
+ /// Cleans up all frames and stack values for the current task.
1701
+ ///
1702
+ /// Used when a task completes or fails and we need to switch to another task.
1703
+ /// Drains the stack with proper `drop_with_heap` for each value (since locals
1704
+ /// are inlined on the stack), then cleans up each frame's cell references.
1705
+ pub(super) fn cleanup_current_task(&mut self) {
1706
+ self.stack.drain(..).drop_with_heap(self.heap);
1707
+ self.frames.clear();
1708
+ }
1709
+
1710
+ /// Runs garbage collection with proper GC roots.
1711
+ ///
1712
+ /// GC roots include values in the stack (locals + operands), globals, and exception stack.
1713
+ fn run_gc(&mut self) {
1714
+ // Collect roots from all reachable values
1715
+ let stack_roots = self.stack.iter().filter_map(Value::ref_id);
1716
+ let globals_roots = self.globals.iter().filter_map(Value::ref_id);
1717
+ let exc_roots = self.exception_stack.iter().filter_map(Value::ref_id);
1718
+
1719
+ // Collect all roots into a vec to avoid lifetime issues
1720
+ let roots: Vec<HeapId> = stack_roots.chain(globals_roots).chain(exc_roots).collect();
1721
+
1722
+ self.heap.collect_garbage(roots);
1723
+ }
1724
+
1725
+ /// Returns the current source position for traceback generation.
1726
+ ///
1727
+ /// Uses `instruction_ip` which is set at the start of each instruction in the run loop,
1728
+ /// ensuring accurate position tracking even when using cached IP for bytecode fetching.
1729
+ pub(super) fn current_position(&self) -> CodeRange {
1730
+ let frame = self.current_frame();
1731
+ // Use instruction_ip which points to the start of the current instruction
1732
+ // (set at the beginning of each loop iteration in run())
1733
+ frame
1734
+ .code
1735
+ .location_for_offset(self.instruction_ip)
1736
+ .map(crate::bytecode::code::LocationEntry::range)
1737
+ .unwrap_or_default()
1738
+ }
1739
+
1740
+ // ========================================================================
1741
+ // Variable Operations
1742
+ // ========================================================================
1743
+
1744
+ /// Loads a local variable and pushes it onto the stack.
1745
+ ///
1746
+ /// For true locals (assigned somewhere in the function), returns `UnboundLocalError`
1747
+ /// if accessed before assignment. For unassigned names (never assigned in this scope),
1748
+ /// returns `NameLookup` to signal that the host should resolve the name.
1749
+ ///
1750
+ /// Returns `Ok(None)` for normal loads, `Ok(Some(FrameExit::NameLookup))` when
1751
+ /// the host needs to resolve an unknown name, or `Err` for true unbound locals.
1752
+ fn load_local(&mut self, cached_frame: &CachedFrame<'a>, slot: u16) -> Result<Option<FrameExit>, RunError> {
1753
+ let value = &self.stack[cached_frame.stack_base + slot as usize];
1754
+
1755
+ // Check for undefined value — raise appropriate error based on whether
1756
+ // this is a true local (assigned somewhere) or an undefined reference
1757
+ if matches!(value, Value::Undefined) {
1758
+ let name = cached_frame.code.local_name(slot);
1759
+ if cached_frame.code.is_assigned_local(slot) {
1760
+ // True local accessed before assignment
1761
+ return Err(self.unbound_local_error(slot, name));
1762
+ }
1763
+ // Name doesn't exist in any scope — yield to host for resolution.
1764
+ let name_id = name.expect("LocalUnassigned should always have a name");
1765
+ return Ok(Some(FrameExit::NameLookup {
1766
+ name_id,
1767
+ namespace_slot: slot,
1768
+ is_global: false,
1769
+ }));
1770
+ }
1771
+
1772
+ self.push(value.clone_with_heap(self.heap));
1773
+ Ok(None)
1774
+ }
1775
+
1776
+ /// Loads a local variable in call context, pushing `ExtFunction` for undefined names.
1777
+ ///
1778
+ /// Unlike `load_local`, this never yields `NameLookup`. When the variable is undefined
1779
+ /// (a `LocalUnassigned` name), it pushes `Value::ExtFunction(name_id)` so that the
1780
+ /// subsequent `CallFunction` opcode can yield `FunctionCall` instead.
1781
+ fn load_local_callable(&mut self, cached_frame: &CachedFrame<'a>, slot: u16, name_id: StringId) {
1782
+ let value = &self.stack[cached_frame.stack_base + slot as usize];
1783
+
1784
+ if matches!(value, Value::Undefined) {
1785
+ // LocalUnassigned in call context — push ExtFunction for the host to handle.
1786
+ self.ext_function_load_ip = Some(self.instruction_ip);
1787
+ self.push(Value::ExtFunction(name_id));
1788
+ } else {
1789
+ self.push(value.clone_with_heap(self.heap));
1790
+ }
1791
+ }
1792
+
1793
+ /// Loads a global variable in call context, pushing `ExtFunction` for undefined names.
1794
+ ///
1795
+ /// Unlike `load_global`, this never yields `NameLookup`. When the variable is undefined,
1796
+ /// it pushes `Value::ExtFunction(name_id)` so that the subsequent `CallFunction` opcode
1797
+ /// can yield `FunctionCall` instead.
1798
+ fn load_global_callable(&mut self, slot: u16, name_id: StringId) {
1799
+ let value = self.globals[slot as usize].clone_with_heap(self.heap);
1800
+
1801
+ if matches!(value, Value::Undefined) {
1802
+ // Save the load instruction's IP so NameError tracebacks point to the name
1803
+ self.ext_function_load_ip = Some(self.instruction_ip);
1804
+ self.push(Value::ExtFunction(name_id));
1805
+ } else {
1806
+ self.push(value);
1807
+ }
1808
+ }
1809
+
1810
+ /// Creates an UnboundLocalError for a local variable accessed before assignment.
1811
+ fn unbound_local_error(&self, slot: u16, name: Option<StringId>) -> RunError {
1812
+ let name_str = match name {
1813
+ Some(id) => self.interns.get_str(id).to_string(),
1814
+ None => format!("<local {slot}>"),
1815
+ };
1816
+ ExcType::unbound_local_error(&name_str).into()
1817
+ }
1818
+
1819
+ /// Creates a NameError for an undefined global variable.
1820
+ fn name_error(&self, slot: u16, name: Option<StringId>) -> RunError {
1821
+ let name_str = match name {
1822
+ Some(id) => self.interns.get_str(id).to_string(),
1823
+ None => format!("<global {slot}>"),
1824
+ };
1825
+ ExcType::name_error(&name_str).into()
1826
+ }
1827
+
1828
+ /// Pops the top of stack and stores it in a local variable.
1829
+ fn store_local(&mut self, cached_frame: &CachedFrame<'a>, slot: u16) {
1830
+ let value = self.pop();
1831
+ let target = &mut self.stack[cached_frame.stack_base + slot as usize];
1832
+ let old_value = std::mem::replace(target, value);
1833
+ old_value.drop_with_heap(self);
1834
+ }
1835
+
1836
+ /// Deletes a local variable (sets it to Undefined).
1837
+ fn delete_local(&mut self, cached_frame: &CachedFrame<'a>, slot: u16) {
1838
+ let target = &mut self.stack[cached_frame.stack_base + slot as usize];
1839
+ let old_value = std::mem::replace(target, Value::Undefined);
1840
+ old_value.drop_with_heap(self);
1841
+ }
1842
+
1843
+ /// Loads a global variable and pushes it onto the stack.
1844
+ ///
1845
+ /// When the variable is undefined, yields `NameLookup` to the host for resolution
1846
+ /// instead of immediately raising `NameError`. This allows the host to provide
1847
+ /// external function bindings lazily.
1848
+ fn load_global(&mut self, slot: u16) -> Result<Option<FrameExit>, RunError> {
1849
+ let value = self.globals[slot as usize].clone_with_heap(self.heap);
1850
+
1851
+ // Check for undefined value — raise appropriate error or yield to host
1852
+ if matches!(value, Value::Undefined) {
1853
+ let name = self.current_frame().code.local_name(slot);
1854
+
1855
+ // If the name is registered as an assigned local (e.g. a module-level
1856
+ // variable or comprehension loop variable), raise UnboundLocalError
1857
+ // immediately rather than yielding NameLookup.
1858
+ if self.current_frame().code.is_assigned_local(slot) {
1859
+ return Err(self.unbound_local_error(slot, name));
1860
+ }
1861
+
1862
+ let Some(name_id) = name else {
1863
+ // No name available — raise NameError directly
1864
+ return Err(self.name_error(slot, None));
1865
+ };
1866
+ Ok(Some(FrameExit::NameLookup {
1867
+ name_id,
1868
+ namespace_slot: slot,
1869
+ is_global: true,
1870
+ }))
1871
+ } else {
1872
+ self.push(value);
1873
+ Ok(None)
1874
+ }
1875
+ }
1876
+
1877
+ /// Pops the top of stack and stores it in a global variable.
1878
+ fn store_global(&mut self, slot: u16) {
1879
+ let value = self.pop();
1880
+ let old_value = std::mem::replace(&mut self.globals[slot as usize], value);
1881
+ old_value.drop_with_heap(self);
1882
+ }
1883
+
1884
+ /// Deletes a global variable (sets it to Undefined).
1885
+ fn delete_global(&mut self, slot: u16) {
1886
+ let old_value = std::mem::replace(&mut self.globals[slot as usize], Value::Undefined);
1887
+ old_value.drop_with_heap(self);
1888
+ }
1889
+
1890
+ /// Loads from a closure cell and pushes onto the stack.
1891
+ ///
1892
+ /// The cell `HeapId` is read from the frame's local variable slot on the stack
1893
+ /// (cells are stored as `Value::Ref(cell_id)` at known positions in the locals region).
1894
+ /// Returns a `NameError` if the cell value is undefined (free variable not bound).
1895
+ fn load_cell(&mut self, cached_frame: &CachedFrame<'a>, slot: u16) -> RunResult<()> {
1896
+ let cell_id = self.cell_id_from_local(cached_frame, slot);
1897
+ let value = match self.heap.get(cell_id) {
1898
+ HeapData::Cell(c) => c.0.clone_with_heap(self),
1899
+ _ => panic!("LoadCell: entry is not a Cell"),
1900
+ };
1901
+
1902
+ // Check for undefined value - raise NameError for unbound free variable
1903
+ if matches!(value, Value::Undefined) {
1904
+ value.drop_with_heap(self);
1905
+ let name = cached_frame.code.local_name(slot);
1906
+ return Err(self.free_var_error(name));
1907
+ }
1908
+
1909
+ self.push(value);
1910
+ Ok(())
1911
+ }
1912
+
1913
+ /// Extracts the cell `HeapId` from a local variable slot on the stack.
1914
+ ///
1915
+ /// Cell variables are stored as `Value::Ref(cell_id)` in the frame's locals region.
1916
+ fn cell_id_from_local(&self, cached_frame: &CachedFrame<'_>, slot: u16) -> HeapId {
1917
+ match &self.stack[cached_frame.stack_base + slot as usize] {
1918
+ Value::Ref(cell_id) => *cell_id,
1919
+ other => panic!("LoadCell/StoreCell: expected cell reference in local slot {slot}, found {other:?}"),
1920
+ }
1921
+ }
1922
+
1923
+ /// Creates a NameError for an unbound free variable.
1924
+ fn free_var_error(&self, name: Option<StringId>) -> RunError {
1925
+ let name_str = match name {
1926
+ Some(id) => self.interns.get_str(id).to_string(),
1927
+ None => "<free var>".to_string(),
1928
+ };
1929
+ ExcType::name_error_free_variable(&name_str).into()
1930
+ }
1931
+
1932
+ /// Pops the top of stack and stores it in a closure cell.
1933
+ ///
1934
+ /// The cell `HeapId` is read from the frame's local variable slot on the stack.
1935
+ fn store_cell(&mut self, cached_frame: &CachedFrame<'_>, slot: u16) {
1936
+ let value = self.pop();
1937
+ // The guard will clean up the new value if we panic, or the old value if we swap
1938
+ let mut guard = HeapGuard::new(value, self);
1939
+ let (value, this) = guard.as_parts_mut();
1940
+
1941
+ let cell_id = this.cell_id_from_local(cached_frame, slot);
1942
+ match this.heap.get_mut(cell_id) {
1943
+ HeapDataMut::Cell(c) => std::mem::swap(&mut c.0, value),
1944
+ _ => panic!("StoreCell: entry is not a Cell"),
1945
+ }
1946
+ }
1947
+ }
1948
+
1949
+ // `heap` is not a public field on VM, so this implementation needs to go here rather than in `heap.rs`
1950
+ impl<T: ResourceTracker> ContainsHeap for VM<'_, '_, T> {
1951
+ type ResourceTracker = T;
1952
+ fn heap(&self) -> &Heap<T> {
1953
+ self.heap
1954
+ }
1955
+ fn heap_mut(&mut self) -> &mut Heap<T> {
1956
+ self.heap
1957
+ }
1958
+ }