Slightly better ExecEnv::assign
A little more idiomatic, avoid some borrow checker clumsiness, add comments.
This commit is contained in:
parent
8a04d9d1e0
commit
38a3414e88
|
@ -11,7 +11,7 @@ use std::{
|
||||||
cell::RefCell,
|
cell::RefCell,
|
||||||
collections::{HashMap, VecDeque},
|
collections::{HashMap, VecDeque},
|
||||||
io::{stdin, stdout, Read, Write},
|
io::{stdin, stdout, Read, Write},
|
||||||
mem::swap,
|
mem::take,
|
||||||
ops::Range,
|
ops::Range,
|
||||||
process::exit,
|
process::exit,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
|
@ -292,28 +292,35 @@ impl ExecEnv {
|
||||||
for index in indices {
|
for index in indices {
|
||||||
let index = self.eval_expr(index)?;
|
let index = self.eval_expr(index)?;
|
||||||
|
|
||||||
let next_cell;
|
let next_cell = match &mut *cell.borrow_mut() {
|
||||||
match &mut *cell.borrow_mut() {
|
|
||||||
Value::Cart(c) => {
|
Value::Cart(c) => {
|
||||||
|
// cell is a cart, so we can do simple
|
||||||
|
// indexing.
|
||||||
if let Some(x) = c.get(&index) {
|
if let Some(x) = c.get(&index) {
|
||||||
next_cell = Rc::clone(x);
|
// cell[index] exists, get a shared
|
||||||
|
// reference to it.
|
||||||
|
Rc::clone(x)
|
||||||
} else {
|
} else {
|
||||||
next_cell = Rc::new(RefCell::new(Value::Cart(Default::default())));
|
// 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));
|
c.insert(index, Rc::clone(&next_cell));
|
||||||
|
next_cell
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
x => {
|
x => {
|
||||||
// Annoying borrow checker dance
|
// cell is not a cart; `take` it, convert
|
||||||
// to move *x.
|
// it into a cart, and write the result
|
||||||
let mut tmp = Value::Nul;
|
// back into it.
|
||||||
swap(&mut tmp, x);
|
let mut cart = take(x).into_cart();
|
||||||
|
let next_cell = Rc::new(RefCell::new(Value::Cart(Default::default())));
|
||||||
let mut c = tmp.into_cart();
|
cart.insert(index, Rc::clone(&next_cell));
|
||||||
next_cell = Rc::new(RefCell::new(Value::Cart(Default::default())));
|
*x = Value::Cart(cart);
|
||||||
c.insert(index, Rc::clone(&next_cell));
|
next_cell
|
||||||
*x = Value::Cart(c);
|
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
cell = next_cell;
|
cell = next_cell;
|
||||||
}
|
}
|
||||||
cell.replace(value);
|
cell.replace(value);
|
||||||
|
|
|
@ -60,6 +60,12 @@ pub enum Value {
|
||||||
Cart(Cart),
|
Cart(Cart),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for Value {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Nul
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Hash for Value {
|
impl Hash for Value {
|
||||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||||
discriminant(self).hash(state);
|
discriminant(self).hash(state);
|
||||||
|
|
Loading…
Reference in a new issue