forked from AbleScript/ablescript
Introduced newtype for Rc<RefCell<Value>>
This commit is contained in:
parent
81f433e633
commit
d7ec6b3658
|
@ -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()
|
||||||
|
|
|
@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue