diff --git a/ablescript/src/interpret.rs b/ablescript/src/interpret.rs index 2a38632f..95aabe10 100644 --- a/ablescript/src/interpret.rs +++ b/ablescript/src/interpret.rs @@ -8,14 +8,12 @@ #![deny(missing_docs)] use std::{ - cell::RefCell, cmp::Ordering, collections::{HashMap, VecDeque}, io::{stdin, stdout, Read, Write}, mem::take, ops::Range, process::exit, - rc::Rc, }; use rand::random; @@ -25,7 +23,7 @@ use crate::{ base_55, consts::ablescript_consts, error::{Error, ErrorKind}, - variables::{Functio, Value, Variable}, + variables::{Functio, Value, ValueRef, Variable}, }; /// An environment for executing AbleScript code. @@ -179,8 +177,7 @@ impl ExecEnv { .iter() .map(|(value, key)| { self.eval_expr(value).and_then(|value| { - self.eval_expr(key) - .map(|key| (key, Rc::new(RefCell::new(value)))) + self.eval_expr(key).map(|key| (key, ValueRef::new(value))) }) }) .collect::, _>>()?, @@ -323,14 +320,13 @@ impl ExecEnv { if let Some(x) = c.get(&index) { // cell[index] exists, get a shared // reference to it. - Rc::clone(x) + ValueRef::clone(x) } else { // cell[index] does not exist, so we // insert an empty cart by default // instead. - let next_cell = - Rc::new(RefCell::new(Value::Cart(Default::default()))); - c.insert(index, Rc::clone(&next_cell)); + let next_cell = ValueRef::new(Value::Cart(Default::default())); + c.insert(index, ValueRef::clone(&next_cell)); next_cell } } @@ -339,8 +335,8 @@ impl ExecEnv { // it into a cart, and write the result // back into it. let mut cart = take(x).into_cart(); - let next_cell = Rc::new(RefCell::new(Value::Cart(Default::default()))); - cart.insert(index, Rc::clone(&next_cell)); + let next_cell = ValueRef::new(Value::Cart(Default::default())); + cart.insert(index, ValueRef::clone(&next_cell)); *x = Value::Cart(cart); next_cell } @@ -369,7 +365,7 @@ impl ExecEnv { span: arg.span.clone(), }) } else { - self.eval_expr(arg).map(|v| Rc::new(RefCell::new(v))) + self.eval_expr(arg).map(ValueRef::new) } }) .collect::, Error>>()?; @@ -380,7 +376,7 @@ impl ExecEnv { fn fn_call_with_values( &mut self, func: Functio, - args: &[Rc>], + args: &[ValueRef], span: &Range, ) -> Result<(), Error> { match func { @@ -464,9 +460,9 @@ impl ExecEnv { } fn deinterlace( - args: &[Rc>], + args: &[ValueRef], arities: (usize, usize), - ) -> (Vec>>, Vec>>) { + ) -> (Vec, Vec) { let n_alternations = usize::min(arities.0, arities.1); let (extra_l, extra_r) = match Ord::cmp(&arities.0, &arities.1) { Ordering::Less => (0, arities.1 - arities.0), @@ -477,21 +473,21 @@ impl ExecEnv { ( args.chunks(2) .take(n_alternations) - .map(|chunk| Rc::clone(&chunk[0])) + .map(|chunk| ValueRef::clone(&chunk[0])) .chain( args[2 * n_alternations..] .iter() - .map(Rc::clone) + .map(ValueRef::clone) .take(extra_l), ) .collect(), args.chunks(2) .take(n_alternations) - .map(|chunk| Rc::clone(&chunk[1])) + .map(|chunk| ValueRef::clone(&chunk[1])) .chain( args[2 * n_alternations..] .iter() - .map(Rc::clone) + .map(ValueRef::clone) .take(extra_r), ) .collect(), @@ -582,17 +578,17 @@ impl ExecEnv { /// Get an Rc'd pointer to the value of a variable. Throw an error /// if the variable is inaccessible or banned. - fn get_var_rc(&mut self, name: &Ident) -> Result>, Error> { + fn get_var_rc(&mut self, name: &Ident) -> Result { Ok(self.get_var_mut(name)?.value.clone()) } /// Declare a new variable, with the given initial value. fn decl_var(&mut self, name: &str, value: Value) { - self.decl_var_shared(name, Rc::new(RefCell::new(value))); + self.decl_var_shared(name, ValueRef::new(value)); } /// Declare a new variable, with the given shared initial value. - fn decl_var_shared(&mut self, name: &str, value: Rc>) { + fn decl_var_shared(&mut self, name: &str, value: ValueRef) { self.stack .iter_mut() .last() diff --git a/ablescript/src/variables.rs b/ablescript/src/variables.rs index 992b88d5..22b4aa8a 100644 --- a/ablescript/src/variables.rs +++ b/ablescript/src/variables.rs @@ -1,6 +1,13 @@ use std::{ - cell::RefCell, collections::HashMap, fmt::Display, hash::Hash, io::Write, mem::discriminant, - ops, rc::Rc, vec, + cell::{Ref, RefCell, RefMut}, + collections::HashMap, + fmt::Display, + hash::Hash, + io::Write, + mem::discriminant, + ops, + rc::Rc, + vec, }; use rand::Rng; @@ -69,14 +76,14 @@ impl Functio { #[derive(Clone)] pub struct BuiltinFunctio { - function: Rc>]) -> Result<(), crate::error::ErrorKind>>, + function: Rc Result<(), crate::error::ErrorKind>>, arity: usize, } impl BuiltinFunctio { pub fn new(f: F, arity: usize) -> Self where - F: Fn(&[Rc>]) -> Result<(), crate::error::ErrorKind> + 'static, + F: Fn(&[ValueRef]) -> Result<(), crate::error::ErrorKind> + 'static, { Self { function: Rc::new(f), @@ -84,7 +91,7 @@ impl BuiltinFunctio { } } - pub fn call(&self, args: &[Rc>]) -> Result<(), crate::error::ErrorKind> { + pub fn call(&self, args: &[ValueRef]) -> Result<(), crate::error::ErrorKind> { (self.function)(args) } @@ -121,7 +128,7 @@ pub enum FunctioChainKind { ByArity, } -pub type Cart = HashMap>>; +pub type Cart = HashMap; #[derive(Debug, Clone)] pub enum Value { @@ -263,9 +270,8 @@ impl Value { ) .into_abool(), Functio::Able { params, body } => { - let str_to_isize = |x: String| -> isize { - x.as_bytes().iter().map(|x| *x as isize).sum() - }; + let str_to_isize = + |x: String| -> isize { x.as_bytes().iter().map(|x| *x as isize).sum() }; let params: isize = params.into_iter().map(str_to_isize).sum(); let body: isize = body @@ -377,7 +383,7 @@ impl Value { .map(|(i, x)| { ( Value::Int(i as isize + 1), - Rc::new(RefCell::new(Value::Str(x.to_string()))), + ValueRef::new(Value::Str(x.to_string())), ) }) .collect(), @@ -389,12 +395,7 @@ impl Value { let params: Cart = params .into_iter() .enumerate() - .map(|(i, x)| { - ( - Value::Int(i as isize + 1), - Rc::new(RefCell::new(Value::Str(x))), - ) - }) + .map(|(i, x)| (Value::Int(i as isize + 1), ValueRef::new(Value::Str(x)))) .collect(); let body: Cart = body @@ -403,7 +404,7 @@ impl Value { .map(|(i, x)| { ( Value::Int(i as isize + 1), - Rc::new(RefCell::new(Value::Str(format!("{:?}", x)))), + ValueRef::new(Value::Str(format!("{:?}", x))), ) }) .collect(); @@ -411,12 +412,12 @@ impl Value { let mut cart = HashMap::new(); cart.insert( Value::Str("params".to_owned()), - Rc::new(RefCell::new(Value::Cart(params))), + ValueRef::new(Value::Cart(params)), ); cart.insert( Value::Str("body".to_owned()), - Rc::new(RefCell::new(Value::Cart(body))), + ValueRef::new(Value::Cart(body)), ); cart @@ -431,18 +432,18 @@ impl Value { .map(|(i, x)| { ( Value::Int(i as isize + 1), - Rc::new(RefCell::new( + ValueRef::new( char::from_u32(x as u32) .map(|x| Value::Str(x.to_string())) .unwrap_or(Value::Nul), - )), + ), ) }) .collect(); cart.insert( Value::Str("tapelen".to_owned()), - Rc::new(RefCell::new(Value::Int(tape_len as _))), + ValueRef::new(Value::Int(tape_len as _)), ); cart } @@ -450,14 +451,12 @@ impl Value { let mut cart = HashMap::new(); cart.insert( Value::Str("addr".to_owned()), - Rc::new(RefCell::new(Value::Cart( - Value::Int(b.fn_addr() as _).into_cart(), - ))), + ValueRef::new(Value::Cart(Value::Int(b.fn_addr() as _).into_cart())), ); cart.insert( Value::Str("arity".to_owned()), - Rc::new(RefCell::new(Value::Int(b.arity as _))), + ValueRef::new(Value::Int(b.arity as _)), ); cart @@ -647,9 +646,7 @@ impl ops::Sub for Value { .iter() .cloned() .take(resulting_arity) - .chain(std::iter::repeat_with(|| { - Rc::new(RefCell::new(Value::Nul)) - })) + .chain(std::iter::repeat_with(|| ValueRef::new(Value::Nul))) .take(arity) .collect::>(), ) @@ -748,7 +745,7 @@ impl ops::Div for Value { .map(|(i, x)| { ( Value::Int(i as isize + 1), - Rc::new(RefCell::new(Value::Str(x.to_owned()))), + ValueRef::new(Value::Str(x.to_owned())), ) }) .collect(), @@ -817,7 +814,7 @@ impl ops::Div for Value { .map(|(k, v)| { ( Value::Int(k as isize + 1), - Rc::new(RefCell::new(Value::Cart(v.iter().cloned().collect()))), + ValueRef::new(Value::Cart(v.iter().cloned().collect())), ) }) .collect(), @@ -883,7 +880,7 @@ impl ops::Not for Value { }), Value::Cart(c) => Value::Cart( c.into_iter() - .map(|(k, v)| (v.borrow().clone(), Rc::new(RefCell::new(k)))) + .map(|(k, v)| (v.borrow().clone(), ValueRef::new(k))) .collect(), ), } @@ -999,20 +996,41 @@ impl Display for Value { } } +#[derive(Debug, Clone, PartialEq)] +pub struct ValueRef(Rc>); + +impl ValueRef { + pub fn new(v: Value) -> Self { + Self(Rc::new(RefCell::new(v))) + } + + pub fn borrow(&self) -> Ref { + self.0.borrow() + } + + pub fn borrow_mut(&self) -> RefMut { + self.0.borrow_mut() + } + + pub fn replace(&self, v: Value) -> Value { + self.0.replace(v) + } +} + #[derive(Debug)] pub struct Variable { pub melo: bool, // Multiple Variables can reference the same underlying Value when // pass-by-reference is used, therefore we use Rc here. - pub value: Rc>, + pub value: ValueRef, } impl Variable { pub fn from_value(value: Value) -> Self { Self { melo: false, - value: Rc::new(RefCell::new(value)), + value: ValueRef::new(value), } } }