From 17e3353483da3a497b5137c613e50c60759381d3 Mon Sep 17 00:00:00 2001 From: Laurenz Date: Thu, 17 Feb 2022 14:09:26 +0100 Subject: [PATCH] Make values sync --- src/eval/mod.rs | 82 +++++++++++++++++++++++++++-------------------- src/eval/scope.rs | 16 ++++----- src/util/mod.rs | 21 ------------ 3 files changed, 54 insertions(+), 65 deletions(-) diff --git a/src/eval/mod.rs b/src/eval/mod.rs index 9ad23538b..5f339bc87 100644 --- a/src/eval/mod.rs +++ b/src/eval/mod.rs @@ -29,7 +29,6 @@ pub use styles::*; pub use template::*; pub use value::*; -use std::cell::RefMut; use std::collections::HashMap; use std::io; use std::mem; @@ -46,7 +45,7 @@ use crate::loading::Loader; use crate::source::{SourceId, SourceStore}; use crate::syntax::ast::*; use crate::syntax::{Span, Spanned}; -use crate::util::{EcoString, RefMutExt}; +use crate::util::EcoString; use crate::Context; /// An evaluated module, ready for importing or conversion to a root layout @@ -347,7 +346,7 @@ impl Eval for Ident { fn eval(&self, ctx: &mut EvalContext) -> TypResult { match ctx.scopes.get(self) { - Some(slot) => Ok(slot.borrow().clone()), + Some(slot) => Ok(slot.read().unwrap().clone()), None => bail!(self.span(), "unknown variable"), } } @@ -450,10 +449,11 @@ impl Eval for BinaryExpr { impl BinaryExpr { /// Apply a basic binary operation. - fn apply(&self, ctx: &mut EvalContext, op: F) -> TypResult - where - F: FnOnce(Value, Value) -> StrResult, - { + fn apply( + &self, + ctx: &mut EvalContext, + op: fn(Value, Value) -> StrResult, + ) -> TypResult { let lhs = self.lhs().eval(ctx)?; // Short-circuit boolean operations. @@ -468,14 +468,20 @@ impl BinaryExpr { } /// Apply an assignment operation. - fn assign(&self, ctx: &mut EvalContext, op: F) -> TypResult - where - F: FnOnce(Value, Value) -> StrResult, - { + fn assign( + &self, + ctx: &mut EvalContext, + op: fn(Value, Value) -> StrResult, + ) -> TypResult { let rhs = self.rhs().eval(ctx)?; - let mut target = self.lhs().access(ctx)?; - let lhs = mem::take(&mut *target); - *target = op(lhs, rhs).at(self.span())?; + self.lhs().access( + ctx, + Box::new(|target| { + let lhs = mem::take(&mut *target); + *target = op(lhs, rhs).at(self.span())?; + Ok(()) + }), + )?; Ok(Value::None) } } @@ -766,13 +772,13 @@ impl Eval for ImportExpr { match self.imports() { Imports::Wildcard => { for (var, slot) in module.scope.iter() { - ctx.scopes.def_mut(var, slot.borrow().clone()); + ctx.scopes.def_mut(var, slot.read().unwrap().clone()); } } Imports::Items(idents) => { for ident in idents { if let Some(slot) = module.scope.get(&ident) { - ctx.scopes.def_mut(ident.take(), slot.borrow().clone()); + ctx.scopes.def_mut(ident.take(), slot.read().unwrap().clone()); } else { bail!(ident.span(), "unresolved import"); } @@ -825,24 +831,27 @@ impl Eval for ReturnExpr { /// This only works if the expression is a valid lvalue. pub trait Access { /// Try to access the value. - fn access<'a>(&self, ctx: &'a mut EvalContext) -> TypResult>; + fn access(&self, ctx: &mut EvalContext, f: Handler) -> TypResult<()>; } +/// Process an accessed value. +type Handler<'a> = Box TypResult<()> + 'a>; + impl Access for Expr { - fn access<'a>(&self, ctx: &'a mut EvalContext) -> TypResult> { + fn access(&self, ctx: &mut EvalContext, f: Handler) -> TypResult<()> { match self { - Expr::Ident(ident) => ident.access(ctx), - Expr::Call(call) => call.access(ctx), + Expr::Ident(ident) => ident.access(ctx, f), + Expr::Call(call) => call.access(ctx, f), _ => bail!(self.span(), "cannot access this expression mutably"), } } } impl Access for Ident { - fn access<'a>(&self, ctx: &'a mut EvalContext) -> TypResult> { + fn access(&self, ctx: &mut EvalContext, f: Handler) -> TypResult<()> { match ctx.scopes.get(self) { - Some(slot) => match slot.try_borrow_mut() { - Ok(guard) => Ok(guard), + Some(slot) => match slot.try_write() { + Ok(mut guard) => f(&mut guard), Err(_) => bail!(self.span(), "cannot mutate a constant"), }, None => bail!(self.span(), "unknown variable"), @@ -851,18 +860,21 @@ impl Access for Ident { } impl Access for CallExpr { - fn access<'a>(&self, ctx: &'a mut EvalContext) -> TypResult> { + fn access(&self, ctx: &mut EvalContext, f: Handler) -> TypResult<()> { let args = self.args().eval(ctx)?; - let guard = self.callee().access(ctx)?; - - RefMut::try_map(guard, |value| match value { - Value::Array(array) => array.get_mut(args.into_index()?).at(self.span()), - Value::Dict(dict) => Ok(dict.get_mut(args.into_key()?)), - v => bail!( - self.callee().span(), - "expected collection, found {}", - v.type_name(), - ), - }) + self.callee().access( + ctx, + Box::new(|value| match value { + Value::Array(array) => { + f(array.get_mut(args.into_index()?).at(self.span())?) + } + Value::Dict(dict) => f(dict.get_mut(args.into_key()?)), + v => bail!( + self.callee().span(), + "expected collection, found {}", + v.type_name(), + ), + }), + ) } } diff --git a/src/eval/scope.rs b/src/eval/scope.rs index 1539b4af0..ed4ff70df 100644 --- a/src/eval/scope.rs +++ b/src/eval/scope.rs @@ -1,16 +1,15 @@ -use std::cell::RefCell; use std::collections::BTreeMap; use std::fmt::{self, Debug, Formatter}; use std::hash::{Hash, Hasher}; use std::iter; -use std::sync::Arc; +use std::sync::{Arc, RwLock}; use super::{Args, Class, Construct, EvalContext, Func, Set, Value}; use crate::diag::TypResult; use crate::util::EcoString; /// A slot where a variable is stored. -pub type Slot = Arc>; +pub type Slot = Arc>; /// A stack of scopes. #[derive(Debug, Default, Clone)] @@ -80,18 +79,17 @@ impl Scope { /// Define a constant variable with a value. pub fn def_const(&mut self, var: impl Into, value: impl Into) { - let cell = RefCell::new(value.into()); + let cell = RwLock::new(value.into()); // Make it impossible to write to this value again. - // FIXME: Use Ref::leak once stable. - std::mem::forget(cell.borrow()); + std::mem::forget(cell.read()); self.values.insert(var.into(), Arc::new(cell)); } /// Define a mutable variable with a value. pub fn def_mut(&mut self, var: impl Into, value: impl Into) { - self.values.insert(var.into(), Arc::new(RefCell::new(value.into()))); + self.values.insert(var.into(), Arc::new(RwLock::new(value.into()))); } /// Define a variable with a slot. @@ -132,7 +130,7 @@ impl Hash for Scope { self.values.len().hash(state); for (name, value) in self.values.iter() { name.hash(state); - value.borrow().hash(state); + value.read().unwrap().hash(state); } } } @@ -141,7 +139,7 @@ impl Debug for Scope { fn fmt(&self, f: &mut Formatter) -> fmt::Result { f.write_str("Scope ")?; f.debug_map() - .entries(self.values.iter().map(|(k, v)| (k, v.borrow()))) + .entries(self.values.iter().map(|(k, v)| (k, v.read().unwrap()))) .finish() } } diff --git a/src/util/mod.rs b/src/util/mod.rs index 84bd1aa1e..e42d0664b 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -9,7 +9,6 @@ pub use eco_string::EcoString; pub use mac_roman::decode_mac_roman; pub use prehashed::Prehashed; -use std::cell::RefMut; use std::cmp::Ordering; use std::fmt::{self, Debug, Formatter}; use std::ops::Range; @@ -223,23 +222,3 @@ impl PathExt for Path { out } } - -/// Additional methods for [`RefMut`]. -pub trait RefMutExt<'a, T> { - fn try_map(orig: Self, f: F) -> Result, E> - where - F: FnOnce(&mut T) -> Result<&mut U, E>; -} - -impl<'a, T> RefMutExt<'a, T> for RefMut<'a, T> { - fn try_map(mut orig: Self, f: F) -> Result, E> - where - F: FnOnce(&mut T) -> Result<&mut U, E>, - { - // Taken from here: - // https://github.com/rust-lang/rust/issues/27746#issuecomment-172899746 - f(&mut orig) - .map(|new| new as *mut U) - .map(|raw| RefMut::map(orig, |_| unsafe { &mut *raw })) - } -}