Enters the interactive interpreter. The `console` provided here is used for the REPL prompt interaction and should match the console that's in use by the machine (if any). They don't necessarily have to match though.
(
machine: &mut Machine,
console: Rc<RefCell<dyn Console>>,
program: Rc<RefCell<dyn Program>>,
)
| 220 | /// The `console` provided here is used for the REPL prompt interaction and should match the |
| 221 | /// console that's in use by the machine (if any). They don't necessarily have to match though. |
| 222 | pub async fn run_repl_loop( |
| 223 | machine: &mut Machine, |
| 224 | console: Rc<RefCell<dyn Console>>, |
| 225 | program: Rc<RefCell<dyn Program>>, |
| 226 | ) -> io::Result<i32> { |
| 227 | let mut stop_reason = None; |
| 228 | let mut history = vec![]; |
| 229 | while stop_reason.is_none() { |
| 230 | let line = { |
| 231 | let mut console = console.borrow_mut(); |
| 232 | if console.is_interactive() { |
| 233 | console.print("Ready")?; |
| 234 | } |
| 235 | console::read_line(&mut *console, "", "", Some(&mut history)).await |
| 236 | }; |
| 237 | |
| 238 | // Any signals entered during console input should not impact upcoming execution. Drain |
| 239 | // them all. |
| 240 | machine.drain_signals(); |
| 241 | |
| 242 | match line { |
| 243 | Ok(line) => match machine.compile(&mut line.as_bytes()) { |
| 244 | Ok(()) => match machine.exec().await { |
| 245 | Ok(None) => stop_reason = None, |
| 246 | Ok(Some(code)) => { |
| 247 | let should_continue = { |
| 248 | let program = program.borrow(); |
| 249 | let mut console = console.borrow_mut(); |
| 250 | continue_if_modified(&*program, &mut *console).await? |
| 251 | }; |
| 252 | if should_continue { |
| 253 | stop_reason = Some(code); |
| 254 | } else { |
| 255 | let mut console = console.borrow_mut(); |
| 256 | console.print("Exit aborted; resuming REPL loop.")?; |
| 257 | } |
| 258 | } |
| 259 | Err(StdError::Break) => { |
| 260 | let mut console = console.borrow_mut(); |
| 261 | console.print(BREAK_MSG)?; |
| 262 | } |
| 263 | Err(e) => { |
| 264 | let mut console = console.borrow_mut(); |
| 265 | console.print(format!("ERROR: {}", e).as_str())?; |
| 266 | } |
| 267 | }, |
| 268 | Err(e) => { |
| 269 | let mut console = console.borrow_mut(); |
| 270 | console.print(format!("ERROR: {}", e).as_str())?; |
| 271 | } |
| 272 | }, |
| 273 | Err(e) => { |
| 274 | if e.kind() == io::ErrorKind::Interrupted { |
| 275 | let mut console = console.borrow_mut(); |
| 276 | console.print(BREAK_MSG)?; |
| 277 | // Do not exit the interpreter. Other REPLs, such as Python's, do not do so, |
| 278 | // and it is actually pretty annoying to exit the REPL when one may be furiously |
| 279 | // pressing CTRL+C to stop a program inside of it. |