use std::cell::RefCell; use std::fmt::Display; use std::io::{stdin, stdout, Read, Write}; use std::rc::Rc; use rustc_hash::FxHashMap; use smol_str::SmolStr; use crate::error::RuntimeError; use super::lox_std::init_std; use super::Value; pub struct Runtime { globals: FxHashMap, in_stream: Rc>, out_stream: Rc>, debug: bool, } impl Runtime { pub fn new( in_stream: Rc>, out_stream: Rc>, ) -> Self { let mut runtime = Runtime { globals: FxHashMap::default(), in_stream, out_stream, debug: false, }; init_std(&mut runtime); runtime } pub fn set_debug(&mut self, debug: bool) { self.debug = debug; } pub fn is_debug(&self) -> bool { self.debug } pub fn in_stream(&mut self) -> std::cell::RefMut { self.in_stream.as_ref().borrow_mut() } pub fn out_stream(&mut self) -> std::cell::RefMut { // &mut self.out_stream self.out_stream.as_ref().borrow_mut() } pub fn globals(&self) -> &FxHashMap { &self.globals } pub fn get_global(&self, name: &str) -> Result { self.globals .get(name) .cloned() .ok_or_else(|| RuntimeError::GlobalNotDefined { name: name.to_owned(), }) } pub fn define_global(&mut self, name: impl Into, value: Value) { let name = name.into(); self.globals.insert(name, value); } pub fn assign_global(&mut self, name: &str, value: Value) -> Result<(), RuntimeError> { if let Some(old_value) = self.globals.get_mut(name) { *old_value = value; Ok(()) } else { panic!("Global not defined not caught by resolver"); // Err(RuntimeError::GlobalNotDefined { // name: name.to_owned(), // }) } } } impl Default for Runtime { fn default() -> Self { // let buf_reader = std::io::BufReader::new(stdin()); // let buf_reader_boxed = Box::new(&mut buf_reader); let in_stream = Rc::new(RefCell::new(stdin())); let out_stream = Rc::new(RefCell::new(stdout())); Runtime::new(in_stream, out_stream) } } impl std::fmt::Debug for Runtime { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("Runtime") .field("globals", &self.globals) .finish() } } impl Display for Runtime { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "Globals:")?; for (name, value) in self.globals.iter() { write!(f, "\n\t{name} = {value}")?; } Ok(()) } } impl Drop for Runtime { fn drop(&mut self) { self.out_stream().flush().unwrap(); } } impl Read for Runtime { fn read(&mut self, buf: &mut [u8]) -> std::io::Result { self.in_stream().read(buf) } } impl Write for Runtime { fn write(&mut self, buf: &[u8]) -> std::io::Result { self.out_stream().write(buf) } fn flush(&mut self) -> std::io::Result<()> { self.out_stream().flush() } }