Introduced newtype for Rc<RefCell<Value>>

This commit is contained in:
Erin 2022-03-01 22:13:49 +01:00 committed by ondra05
parent 3f4cc58b87
commit 0ec54ecc51
2 changed files with 70 additions and 56 deletions

View file

@ -8,14 +8,12 @@
#![deny(missing_docs)] #![deny(missing_docs)]
use std::{ use std::{
cell::RefCell,
cmp::Ordering, cmp::Ordering,
collections::{HashMap, VecDeque}, collections::{HashMap, VecDeque},
io::{stdin, stdout, Read, Write}, io::{stdin, stdout, Read, Write},
mem::take, mem::take,
ops::Range, ops::Range,
process::exit, process::exit,
rc::Rc,
}; };
use rand::random; use rand::random;
@ -25,7 +23,7 @@ use crate::{
base_55, base_55,
consts::ablescript_consts, consts::ablescript_consts,
error::{Error, ErrorKind}, error::{Error, ErrorKind},
variables::{Functio, Value, Variable}, variables::{Functio, Value, ValueRef, Variable},
}; };
/// An environment for executing AbleScript code. /// An environment for executing AbleScript code.
@ -179,8 +177,7 @@ impl ExecEnv {
.iter() .iter()
.map(|(value, key)| { .map(|(value, key)| {
self.eval_expr(value).and_then(|value| { self.eval_expr(value).and_then(|value| {
self.eval_expr(key) self.eval_expr(key).map(|key| (key, ValueRef::new(value)))
.map(|key| (key, Rc::new(RefCell::new(value))))
}) })
}) })
.collect::<Result<HashMap<_, _>, _>>()?, .collect::<Result<HashMap<_, _>, _>>()?,
@ -323,14 +320,13 @@ impl ExecEnv {
if let Some(x) = c.get(&index) { if let Some(x) = c.get(&index) {
// cell[index] exists, get a shared // cell[index] exists, get a shared
// reference to it. // reference to it.
Rc::clone(x) ValueRef::clone(x)
} else { } else {
// cell[index] does not exist, so we // cell[index] does not exist, so we
// insert an empty cart by default // insert an empty cart by default
// instead. // instead.
let next_cell = let next_cell = ValueRef::new(Value::Cart(Default::default()));
Rc::new(RefCell::new(Value::Cart(Default::default()))); c.insert(index, ValueRef::clone(&next_cell));
c.insert(index, Rc::clone(&next_cell));
next_cell next_cell
} }
} }
@ -339,8 +335,8 @@ impl ExecEnv {
// it into a cart, and write the result // it into a cart, and write the result
// back into it. // back into it.
let mut cart = take(x).into_cart(); let mut cart = take(x).into_cart();
let next_cell = Rc::new(RefCell::new(Value::Cart(Default::default()))); let next_cell = ValueRef::new(Value::Cart(Default::default()));
cart.insert(index, Rc::clone(&next_cell)); cart.insert(index, ValueRef::clone(&next_cell));
*x = Value::Cart(cart); *x = Value::Cart(cart);
next_cell next_cell
} }
@ -369,7 +365,7 @@ impl ExecEnv {
span: arg.span.clone(), span: arg.span.clone(),
}) })
} else { } else {
self.eval_expr(arg).map(|v| Rc::new(RefCell::new(v))) self.eval_expr(arg).map(ValueRef::new)
} }
}) })
.collect::<Result<Vec<_>, Error>>()?; .collect::<Result<Vec<_>, Error>>()?;
@ -380,7 +376,7 @@ impl ExecEnv {
fn fn_call_with_values( fn fn_call_with_values(
&mut self, &mut self,
func: Functio, func: Functio,
args: &[Rc<RefCell<Value>>], args: &[ValueRef],
span: &Range<usize>, span: &Range<usize>,
) -> Result<(), Error> { ) -> Result<(), Error> {
match func { match func {
@ -464,9 +460,9 @@ impl ExecEnv {
} }
fn deinterlace( fn deinterlace(
args: &[Rc<RefCell<Value>>], args: &[ValueRef],
arities: (usize, usize), arities: (usize, usize),
) -> (Vec<Rc<RefCell<Value>>>, Vec<Rc<RefCell<Value>>>) { ) -> (Vec<ValueRef>, Vec<ValueRef>) {
let n_alternations = usize::min(arities.0, arities.1); let n_alternations = usize::min(arities.0, arities.1);
let (extra_l, extra_r) = match Ord::cmp(&arities.0, &arities.1) { let (extra_l, extra_r) = match Ord::cmp(&arities.0, &arities.1) {
Ordering::Less => (0, arities.1 - arities.0), Ordering::Less => (0, arities.1 - arities.0),
@ -477,21 +473,21 @@ impl ExecEnv {
( (
args.chunks(2) args.chunks(2)
.take(n_alternations) .take(n_alternations)
.map(|chunk| Rc::clone(&chunk[0])) .map(|chunk| ValueRef::clone(&chunk[0]))
.chain( .chain(
args[2 * n_alternations..] args[2 * n_alternations..]
.iter() .iter()
.map(Rc::clone) .map(ValueRef::clone)
.take(extra_l), .take(extra_l),
) )
.collect(), .collect(),
args.chunks(2) args.chunks(2)
.take(n_alternations) .take(n_alternations)
.map(|chunk| Rc::clone(&chunk[1])) .map(|chunk| ValueRef::clone(&chunk[1]))
.chain( .chain(
args[2 * n_alternations..] args[2 * n_alternations..]
.iter() .iter()
.map(Rc::clone) .map(ValueRef::clone)
.take(extra_r), .take(extra_r),
) )
.collect(), .collect(),
@ -582,17 +578,17 @@ impl ExecEnv {
/// Get an Rc'd pointer to the value of a variable. Throw an error /// Get an Rc'd pointer to the value of a variable. Throw an error
/// if the variable is inaccessible or banned. /// if the variable is inaccessible or banned.
fn get_var_rc(&mut self, name: &Ident) -> Result<Rc<RefCell<Value>>, Error> { fn get_var_rc(&mut self, name: &Ident) -> Result<ValueRef, Error> {
Ok(self.get_var_mut(name)?.value.clone()) Ok(self.get_var_mut(name)?.value.clone())
} }
/// Declare a new variable, with the given initial value. /// Declare a new variable, with the given initial value.
fn decl_var(&mut self, name: &str, value: 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. /// Declare a new variable, with the given shared initial value.
fn decl_var_shared(&mut self, name: &str, value: Rc<RefCell<Value>>) { fn decl_var_shared(&mut self, name: &str, value: ValueRef) {
self.stack self.stack
.iter_mut() .iter_mut()
.last() .last()

View file

@ -1,6 +1,13 @@
use std::{ use std::{
cell::RefCell, collections::HashMap, fmt::Display, hash::Hash, io::Write, mem::discriminant, cell::{Ref, RefCell, RefMut},
ops, rc::Rc, vec, collections::HashMap,
fmt::Display,
hash::Hash,
io::Write,
mem::discriminant,
ops,
rc::Rc,
vec,
}; };
use rand::Rng; use rand::Rng;
@ -69,14 +76,14 @@ impl Functio {
#[derive(Clone)] #[derive(Clone)]
pub struct BuiltinFunctio { pub struct BuiltinFunctio {
function: Rc<dyn Fn(&[Rc<RefCell<Value>>]) -> Result<(), crate::error::ErrorKind>>, function: Rc<dyn Fn(&[ValueRef]) -> Result<(), crate::error::ErrorKind>>,
arity: usize, arity: usize,
} }
impl BuiltinFunctio { impl BuiltinFunctio {
pub fn new<F>(f: F, arity: usize) -> Self pub fn new<F>(f: F, arity: usize) -> Self
where where
F: Fn(&[Rc<RefCell<Value>>]) -> Result<(), crate::error::ErrorKind> + 'static, F: Fn(&[ValueRef]) -> Result<(), crate::error::ErrorKind> + 'static,
{ {
Self { Self {
function: Rc::new(f), function: Rc::new(f),
@ -84,7 +91,7 @@ impl BuiltinFunctio {
} }
} }
pub fn call(&self, args: &[Rc<RefCell<Value>>]) -> Result<(), crate::error::ErrorKind> { pub fn call(&self, args: &[ValueRef]) -> Result<(), crate::error::ErrorKind> {
(self.function)(args) (self.function)(args)
} }
@ -121,7 +128,7 @@ pub enum FunctioChainKind {
ByArity, ByArity,
} }
pub type Cart = HashMap<Value, Rc<RefCell<Value>>>; pub type Cart = HashMap<Value, ValueRef>;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Value { pub enum Value {
@ -263,9 +270,8 @@ impl Value {
) )
.into_abool(), .into_abool(),
Functio::Able { params, body } => { Functio::Able { params, body } => {
let str_to_isize = |x: String| -> isize { let str_to_isize =
x.as_bytes().iter().map(|x| *x as isize).sum() |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 params: isize = params.into_iter().map(str_to_isize).sum();
let body: isize = body let body: isize = body
@ -377,7 +383,7 @@ impl Value {
.map(|(i, x)| { .map(|(i, x)| {
( (
Value::Int(i as isize + 1), Value::Int(i as isize + 1),
Rc::new(RefCell::new(Value::Str(x.to_string()))), ValueRef::new(Value::Str(x.to_string())),
) )
}) })
.collect(), .collect(),
@ -389,12 +395,7 @@ impl Value {
let params: Cart = params let params: Cart = params
.into_iter() .into_iter()
.enumerate() .enumerate()
.map(|(i, x)| { .map(|(i, x)| (Value::Int(i as isize + 1), ValueRef::new(Value::Str(x))))
(
Value::Int(i as isize + 1),
Rc::new(RefCell::new(Value::Str(x))),
)
})
.collect(); .collect();
let body: Cart = body let body: Cart = body
@ -403,7 +404,7 @@ impl Value {
.map(|(i, x)| { .map(|(i, x)| {
( (
Value::Int(i as isize + 1), Value::Int(i as isize + 1),
Rc::new(RefCell::new(Value::Str(format!("{:?}", x)))), ValueRef::new(Value::Str(format!("{:?}", x))),
) )
}) })
.collect(); .collect();
@ -411,12 +412,12 @@ impl Value {
let mut cart = HashMap::new(); let mut cart = HashMap::new();
cart.insert( cart.insert(
Value::Str("params".to_owned()), Value::Str("params".to_owned()),
Rc::new(RefCell::new(Value::Cart(params))), ValueRef::new(Value::Cart(params)),
); );
cart.insert( cart.insert(
Value::Str("body".to_owned()), Value::Str("body".to_owned()),
Rc::new(RefCell::new(Value::Cart(body))), ValueRef::new(Value::Cart(body)),
); );
cart cart
@ -431,18 +432,18 @@ impl Value {
.map(|(i, x)| { .map(|(i, x)| {
( (
Value::Int(i as isize + 1), Value::Int(i as isize + 1),
Rc::new(RefCell::new( ValueRef::new(
char::from_u32(x as u32) char::from_u32(x as u32)
.map(|x| Value::Str(x.to_string())) .map(|x| Value::Str(x.to_string()))
.unwrap_or(Value::Nul), .unwrap_or(Value::Nul),
)), ),
) )
}) })
.collect(); .collect();
cart.insert( cart.insert(
Value::Str("tapelen".to_owned()), Value::Str("tapelen".to_owned()),
Rc::new(RefCell::new(Value::Int(tape_len as _))), ValueRef::new(Value::Int(tape_len as _)),
); );
cart cart
} }
@ -450,14 +451,12 @@ impl Value {
let mut cart = HashMap::new(); let mut cart = HashMap::new();
cart.insert( cart.insert(
Value::Str("addr".to_owned()), Value::Str("addr".to_owned()),
Rc::new(RefCell::new(Value::Cart( ValueRef::new(Value::Cart(Value::Int(b.fn_addr() as _).into_cart())),
Value::Int(b.fn_addr() as _).into_cart(),
))),
); );
cart.insert( cart.insert(
Value::Str("arity".to_owned()), Value::Str("arity".to_owned()),
Rc::new(RefCell::new(Value::Int(b.arity as _))), ValueRef::new(Value::Int(b.arity as _)),
); );
cart cart
@ -647,9 +646,7 @@ impl ops::Sub for Value {
.iter() .iter()
.cloned() .cloned()
.take(resulting_arity) .take(resulting_arity)
.chain(std::iter::repeat_with(|| { .chain(std::iter::repeat_with(|| ValueRef::new(Value::Nul)))
Rc::new(RefCell::new(Value::Nul))
}))
.take(arity) .take(arity)
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
) )
@ -748,7 +745,7 @@ impl ops::Div for Value {
.map(|(i, x)| { .map(|(i, x)| {
( (
Value::Int(i as isize + 1), Value::Int(i as isize + 1),
Rc::new(RefCell::new(Value::Str(x.to_owned()))), ValueRef::new(Value::Str(x.to_owned())),
) )
}) })
.collect(), .collect(),
@ -817,7 +814,7 @@ impl ops::Div for Value {
.map(|(k, v)| { .map(|(k, v)| {
( (
Value::Int(k as isize + 1), 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(), .collect(),
@ -883,7 +880,7 @@ impl ops::Not for Value {
}), }),
Value::Cart(c) => Value::Cart( Value::Cart(c) => Value::Cart(
c.into_iter() c.into_iter()
.map(|(k, v)| (v.borrow().clone(), Rc::new(RefCell::new(k)))) .map(|(k, v)| (v.borrow().clone(), ValueRef::new(k)))
.collect(), .collect(),
), ),
} }
@ -999,20 +996,41 @@ impl Display for Value {
} }
} }
#[derive(Debug, Clone, PartialEq)]
pub struct ValueRef(Rc<RefCell<Value>>);
impl ValueRef {
pub fn new(v: Value) -> Self {
Self(Rc::new(RefCell::new(v)))
}
pub fn borrow(&self) -> Ref<Value> {
self.0.borrow()
}
pub fn borrow_mut(&self) -> RefMut<Value> {
self.0.borrow_mut()
}
pub fn replace(&self, v: Value) -> Value {
self.0.replace(v)
}
}
#[derive(Debug)] #[derive(Debug)]
pub struct Variable { pub struct Variable {
pub melo: bool, pub melo: bool,
// Multiple Variables can reference the same underlying Value when // Multiple Variables can reference the same underlying Value when
// pass-by-reference is used, therefore we use Rc here. // pass-by-reference is used, therefore we use Rc here.
pub value: Rc<RefCell<Value>>, pub value: ValueRef,
} }
impl Variable { impl Variable {
pub fn from_value(value: Value) -> Self { pub fn from_value(value: Value) -> Self {
Self { Self {
melo: false, melo: false,
value: Rc::new(RefCell::new(value)), value: ValueRef::new(value),
} }
} }
} }