@@ -14,17 +14,16 @@ use serde::de::DeserializeOwned;
1414use crate :: {
1515 ExcType , MontyException ,
1616 asyncio:: CallId ,
17- bytecode:: { Code , Compiler , FrameExit , VM , VMSnapshot } ,
18- exception_private:: { RunError , RunResult } ,
17+ bytecode:: { VM , VMSnapshot } ,
18+ exception_private:: RunError ,
1919 heap:: { DropWithHeap , Heap , HeapReader } ,
2020 intern:: { InternerBuilder , Interns } ,
2121 io:: PrintWriter ,
2222 namespace:: NamespaceId ,
2323 object:: MontyObject ,
2424 os:: OsFunction ,
25- parse:: parse_with_interner,
26- prepare:: prepare_with_existing_names,
2725 resource:: ResourceTracker ,
26+ run:: Executor ,
2827 run_progress:: { ConvertedExit , ExtFunctionResult , NameLookupResult , convert_frame_exit} ,
2928 value:: Value ,
3029} ;
@@ -127,7 +126,7 @@ impl<T: ResourceTracker> MontyRepl<T> {
127126 let ( input_names, input_values) : ( Vec < _ > , Vec < _ > ) = inputs. into_iter ( ) . unzip ( ) ;
128127
129128 let input_script_name = this. next_input_script_name ( ) ;
130- let executor = match ReplExecutor :: new_repl_snippet (
129+ let executor = match Executor :: new_repl_snippet (
131130 code. to_owned ( ) ,
132131 & input_script_name,
133132 this. global_name_map . clone ( ) ,
@@ -191,7 +190,7 @@ impl<T: ResourceTracker> MontyRepl<T> {
191190 let ( input_names, input_values) : ( Vec < _ > , Vec < _ > ) = inputs. into_iter ( ) . unzip ( ) ;
192191
193192 let input_script_name = self . next_input_script_name ( ) ;
194- let executor = ReplExecutor :: new_repl_snippet (
193+ let executor = Executor :: new_repl_snippet (
195194 code. to_owned ( ) ,
196195 & input_script_name,
197196 self . global_name_map . clone ( ) ,
@@ -210,19 +209,7 @@ impl<T: ResourceTracker> MontyRepl<T> {
210209 return Err ( e) ;
211210 }
212211
213- let mut frame_exit_result = vm. run_module ( & executor. module_code ) ;
214-
215- // Handle NameLookup exits by raising NameError through the VM so that
216- // traceback information is properly captured. In the non-iterative REPL path,
217- // there's no host to resolve names, so all NameLookup exits become NameErrors.
218- while let Ok ( FrameExit :: NameLookup { name_id, .. } ) = & frame_exit_result {
219- let name = executor. interns . get_str ( * name_id) ;
220- let err = ExcType :: name_error ( name) ;
221- frame_exit_result = vm. resume_with_exception ( err. into ( ) ) ;
222- }
223-
224- // Convert output while VM alive
225- let result = frame_exit_to_object ( frame_exit_result, & mut vm) ;
212+ let result = executor. run_to_completion ( & mut vm) ;
226213
227214 // Reclaim globals before cleanup.
228215 self . globals = vm. take_globals ( ) ;
@@ -233,7 +220,7 @@ impl<T: ResourceTracker> MontyRepl<T> {
233220 // Commit compiler metadata even on runtime errors.
234221 // Snippets can mutate globals before raising, and those values may contain
235222 // FunctionId/StringId values that must be interpreted with the updated tables.
236- let ReplExecutor {
223+ let Executor {
237224 name_map,
238225 interns,
239226 code,
@@ -637,7 +624,7 @@ pub struct ReplResolveFutures<T: ResourceTracker> {
637624 /// Persistent REPL session state while this snippet is suspended.
638625 repl : MontyRepl < T > ,
639626 /// Compiled snippet and intern/function tables for this execution.
640- executor : ReplExecutor ,
627+ executor : Executor ,
641628 /// VM stack/frame state at suspension.
642629 vm_state : VMSnapshot ,
643630 /// Pending call IDs expected by this snapshot.
@@ -825,88 +812,6 @@ pub fn detect_repl_continuation_mode(source: &str) -> ReplContinuationMode {
825812 }
826813}
827814
828- // ---------------------------------------------------------------------------
829- // ReplExecutor — internal compilation helper
830- // ---------------------------------------------------------------------------
831-
832- /// Compiled snippet representation used only by REPL execution.
833- ///
834- /// This intentionally mirrors the data shape needed by VM execution in
835- /// `run.rs` but lives in the REPL module so REPL evolution does not require
836- /// changing `run.rs`.
837- #[ derive( Debug , serde:: Serialize , serde:: Deserialize ) ]
838- struct ReplExecutor {
839- /// Number of slots needed in the global namespace.
840- namespace_size : usize ,
841- /// Maps variable names to their indices in the namespace.
842- ///
843- /// Stable slot assignment is required across snippets so previously created
844- /// objects continue to resolve names correctly.
845- name_map : AHashMap < String , NamespaceId > ,
846- /// Compiled bytecode for the snippet.
847- module_code : Code ,
848- /// Interned strings and compiled functions for this snippet.
849- interns : Interns ,
850- /// Source code used for traceback/error rendering.
851- code : String ,
852- /// Input variable names that were injected for this snippet.
853- ///
854- /// Stored so that `inject_inputs` can look up their namespace slots
855- /// after compilation assigns them.
856- input_names : Vec < String > ,
857- }
858-
859- impl ReplExecutor {
860- /// Compiles one REPL snippet against existing session metadata.
861- ///
862- /// This differs from normal compilation in three ways required for true
863- /// no-replay execution:
864- /// - Seeds parsing from `existing_interns` so old `StringId` values stay stable.
865- /// - Seeds compilation with existing functions so old `FunctionId` values remain valid.
866- /// - Reuses `existing_name_map` and appends new global names only.
867- ///
868- /// `input_names` are pre-registered in the name map before preparation so they
869- /// receive stable namespace slots that `inject_inputs` can use to store values.
870- fn new_repl_snippet (
871- code : String ,
872- script_name : & str ,
873- mut existing_name_map : AHashMap < String , NamespaceId > ,
874- existing_interns : & Interns ,
875- input_names : Vec < String > ,
876- ) -> Result < Self , MontyException > {
877- // Pre-register input names so they get stable slots before preparation.
878- for name in & input_names {
879- let next_slot = existing_name_map. len ( ) ;
880- existing_name_map
881- . entry ( name. clone ( ) )
882- . or_insert_with ( || NamespaceId :: new ( next_slot) ) ;
883- }
884-
885- let seeded_interner = InternerBuilder :: from_interns ( existing_interns, & code) ;
886- let parse_result = parse_with_interner ( & code, script_name, seeded_interner)
887- . map_err ( |e| e. into_python_exc ( script_name, & code) ) ?;
888- let prepared = prepare_with_existing_names ( parse_result, existing_name_map)
889- . map_err ( |e| e. into_python_exc ( script_name, & code) ) ?;
890-
891- let existing_functions = existing_interns. functions_clone ( ) ;
892- let mut interns = Interns :: new ( prepared. interner , Vec :: new ( ) ) ;
893- let namespace_size_u16 = u16:: try_from ( prepared. namespace_size ) . expect ( "module namespace size exceeds u16" ) ;
894- let compile_result =
895- Compiler :: compile_module_with_functions ( & prepared. nodes , & interns, namespace_size_u16, existing_functions)
896- . map_err ( |e| e. into_python_exc ( script_name, & code) ) ?;
897- interns. set_functions ( compile_result. functions ) ;
898-
899- Ok ( Self {
900- namespace_size : prepared. namespace_size ,
901- name_map : prepared. name_map ,
902- module_code : compile_result. code ,
903- interns,
904- code,
905- input_names,
906- } )
907- }
908- }
909-
910815// ---------------------------------------------------------------------------
911816// ReplSnapshot — internal execution state for suspend/resume
912817// ---------------------------------------------------------------------------
@@ -921,7 +826,7 @@ pub(crate) struct ReplSnapshot<T: ResourceTracker> {
921826 /// Persistent REPL session state while this snippet is suspended.
922827 repl : MontyRepl < T > ,
923828 /// Compiled snippet and intern/function tables for this execution.
924- executor : ReplExecutor ,
829+ executor : Executor ,
925830 /// VM stack/frame state at suspension.
926831 vm_state : VMSnapshot ,
927832}
@@ -999,7 +904,7 @@ impl<T: ResourceTracker> ReplSnapshot<T> {
999904/// Converts each `MontyObject` to a `Value` while the VM is alive, then stores
1000905/// it in the global slot that the compiler assigned for the corresponding input name.
1001906fn inject_inputs_into_vm (
1002- executor : & ReplExecutor ,
907+ executor : & Executor ,
1003908 input_values : Vec < MontyObject > ,
1004909 vm : & mut VM < ' _ , ' _ , impl ResourceTracker > ,
1005910) -> Result < ( ) , MontyException > {
@@ -1018,51 +923,6 @@ fn inject_inputs_into_vm(
1018923 Ok ( ( ) )
1019924}
1020925
1021- /// Converts module/frame exit results into plain `MontyObject` outputs.
1022- ///
1023- /// Used by the non-iterative `feed_run` path where suspendable outcomes (external calls,
1024- /// name lookups) are not supported and should produce errors.
1025- fn frame_exit_to_object (
1026- frame_exit_result : RunResult < FrameExit > ,
1027- vm : & mut VM < ' _ , ' _ , impl ResourceTracker > ,
1028- ) -> RunResult < MontyObject > {
1029- match frame_exit_result? {
1030- FrameExit :: Return ( return_value) => Ok ( MontyObject :: new ( return_value, vm) ) ,
1031- FrameExit :: ExternalCall {
1032- function_name, args, ..
1033- } => {
1034- args. drop_with_heap ( vm) ;
1035- let function_name = function_name. as_str ( vm. interns ) ;
1036- Err ( ExcType :: not_implemented ( format ! (
1037- "External function '{function_name}' not implemented with standard execution"
1038- ) )
1039- . into ( ) )
1040- }
1041- FrameExit :: OsCall { function, args, .. } => {
1042- args. drop_with_heap ( vm) ;
1043- Err ( ExcType :: not_implemented ( format ! (
1044- "OS function '{function}' not implemented with standard execution"
1045- ) )
1046- . into ( ) )
1047- }
1048- FrameExit :: MethodCall { method_name, args, .. } => {
1049- args. drop_with_heap ( vm) ;
1050- let name = method_name. as_str ( vm. interns ) ;
1051- Err (
1052- ExcType :: not_implemented ( format ! ( "Method call '{name}' not implemented with standard execution" ) )
1053- . into ( ) ,
1054- )
1055- }
1056- FrameExit :: ResolveFutures ( _) => {
1057- Err ( ExcType :: not_implemented ( "async futures not supported by standard execution." ) . into ( ) )
1058- }
1059- FrameExit :: NameLookup { name_id, .. } => {
1060- let name = vm. interns . get_str ( name_id) ;
1061- Err ( ExcType :: name_error ( name) . into ( ) )
1062- }
1063- }
1064- }
1065-
1066926/// Assembles a `ReplProgress` from already-converted data.
1067927///
1068928/// This is the REPL equivalent of `build_run_progress`. On completion/error,
@@ -1071,7 +931,7 @@ fn frame_exit_to_object(
1071931fn build_repl_progress < T : ResourceTracker > (
1072932 converted : ConvertedExit ,
1073933 vm_state : Option < VMSnapshot > ,
1074- executor : ReplExecutor ,
934+ executor : Executor ,
1075935 mut repl : MontyRepl < T > ,
1076936) -> Result < ReplProgress < T > , Box < ReplStartError < T > > > {
1077937 macro_rules! new_repl_snapshot {
@@ -1086,7 +946,7 @@ fn build_repl_progress<T: ResourceTracker>(
1086946
1087947 match converted {
1088948 ConvertedExit :: Complete ( obj) => {
1089- let ReplExecutor { name_map, interns, .. } = executor;
949+ let Executor { name_map, interns, .. } = executor;
1090950 repl. global_name_map = name_map;
1091951 repl. interns = interns;
1092952 Ok ( ReplProgress :: Complete { repl, value : obj } )
@@ -1138,7 +998,7 @@ fn build_repl_progress<T: ResourceTracker>(
1138998 // Commit compiler metadata even on runtime errors, matching feed() behavior.
1139999 // Snippets can create new variables or functions before raising, and those
11401000 // values may reference FunctionId/StringId values from the new tables.
1141- let ReplExecutor { name_map, interns, .. } = executor;
1001+ let Executor { name_map, interns, .. } = executor;
11421002 repl. global_name_map = name_map;
11431003 repl. interns = interns;
11441004 Err ( Box :: new ( ReplStartError { repl, error } ) )
0 commit comments