@@ -1021,6 +1021,100 @@ pub fn evaluate_script<T: AsRef<str>>(script: T) -> Result<Value, JSError> {
10211021 }
10221022}
10231023
1024+ /// A small persistent REPL environment wrapper.
1025+ ///
1026+ /// Notes:
1027+ /// - `Repl::new()` creates a persistent environment and initializes built-ins.
1028+ /// - `Repl::eval(&self, code)` evaluates the provided code in the persistent env
1029+ /// so variables, functions and imports persist between calls.
1030+ pub struct Repl {
1031+ env : JSObjectDataPtr ,
1032+ }
1033+
1034+ impl Default for Repl {
1035+ fn default ( ) -> Self {
1036+ Self :: new ( )
1037+ }
1038+ }
1039+
1040+ impl Repl {
1041+ /// Create a new persistent REPL environment (with built-ins initialized).
1042+ pub fn new ( ) -> Self {
1043+ let env: JSObjectDataPtr = Rc :: new ( RefCell :: new ( JSObjectData :: new ( ) ) ) ;
1044+ env. borrow_mut ( ) . is_function_scope = true ;
1045+ // Initialize built-in constructors once for the persistent environment
1046+ initialize_global_constructors ( & env) ;
1047+ Repl { env }
1048+ }
1049+
1050+ /// Evaluate a script in the persistent environment.
1051+ /// Returns the evaluation result or an error.
1052+ pub fn eval < T : AsRef < str > > ( & self , script : T ) -> Result < Value , JSError > {
1053+ let script = script. as_ref ( ) ;
1054+ let filtered = filter_input_script ( script) ;
1055+
1056+ // Parse tokens and statements
1057+ let mut tokens = tokenize ( & filtered) ?;
1058+ let statements = parse_statements ( & mut tokens) ?;
1059+
1060+ // Inject simple host `std` / `os` shims when importing with the pattern:
1061+ // import * as NAME from "std";
1062+ for line in script. lines ( ) {
1063+ let l = line. trim ( ) ;
1064+ if l. starts_with ( "import * as" )
1065+ && l. contains ( "from" )
1066+ && let ( Some ( as_idx) , Some ( from_idx) ) = ( l. find ( "as" ) , l. find ( "from" ) )
1067+ {
1068+ let name_part = & l[ as_idx + 2 ..from_idx] . trim ( ) ;
1069+ let name = PropertyKey :: String ( name_part. trim ( ) . to_string ( ) ) ;
1070+ if let Some ( start_quote) = l[ from_idx..] . find ( |c : char | [ '"' , '\'' ] . contains ( & c) ) {
1071+ let quote_char = l[ from_idx + start_quote..] . chars ( ) . next ( ) . unwrap ( ) ;
1072+ let rest = & l[ from_idx + start_quote + 1 ..] ;
1073+ if let Some ( end_quote) = rest. find ( quote_char) {
1074+ let module = & rest[ ..end_quote] ;
1075+ if module == "std" {
1076+ obj_set_value ( & self . env , & name, Value :: Object ( crate :: js_std:: make_std_object ( ) ?) ) ?;
1077+ } else if module == "os" {
1078+ obj_set_value ( & self . env , & name, Value :: Object ( crate :: js_os:: make_os_object ( ) ?) ) ?;
1079+ }
1080+ }
1081+ }
1082+ }
1083+ }
1084+
1085+ match evaluate_statements ( & self . env , & statements) {
1086+ Ok ( v) => {
1087+ // If the result is a Promise object (wrapped in Object with __promise property), wait for it to resolve
1088+ if let Value :: Object ( obj) = & v
1089+ && let Some ( promise_val_rc) = obj_get_value ( obj, & "__promise" . into ( ) ) ?
1090+ && let Value :: Promise ( promise) = & * promise_val_rc. borrow ( )
1091+ {
1092+ // Run the event loop until the promise is resolved
1093+ loop {
1094+ run_event_loop ( ) ?;
1095+ let promise_borrow = promise. borrow ( ) ;
1096+ match & promise_borrow. state {
1097+ PromiseState :: Fulfilled ( val) => return Ok ( val. clone ( ) ) ,
1098+ PromiseState :: Rejected ( reason) => {
1099+ return Err ( JSError :: EvaluationError {
1100+ message : format ! ( "Promise rejected: {}" , value_to_string( reason) ) ,
1101+ } ) ;
1102+ }
1103+ PromiseState :: Pending => {
1104+ // Continue running the event loop
1105+ }
1106+ }
1107+ }
1108+ }
1109+ // Run event loop once to process any queued asynchronous tasks
1110+ run_event_loop ( ) ?;
1111+ Ok ( v)
1112+ }
1113+ Err ( e) => Err ( e) ,
1114+ }
1115+ }
1116+ }
1117+
10241118pub fn parse_statements ( tokens : & mut Vec < Token > ) -> Result < Vec < Statement > , JSError > {
10251119 let mut statements = Vec :: new ( ) ;
10261120 while !tokens. is_empty ( ) && !matches ! ( tokens[ 0 ] , Token :: RBrace ) {
0 commit comments