1use crate::{2 error::Error::*, future_wrapper, map::LayeredHashMap, rc_fn_helper, resolved_lazy_val,3 LazyBinding, LazyVal, ObjValue, Result, Val,4};5use std::{6 cell::RefCell,7 collections::HashMap,8 fmt::Debug,9 rc::{Rc, Weak},10};1112rc_fn_helper!(13 ContextCreator,14 context_creator,15 dyn Fn(Option<ObjValue>, Option<ObjValue>) -> Result<Context>16);1718future_wrapper!(Context, FutureContext);1920struct ContextInternals {21 dollar: Option<ObjValue>,22 this: Option<ObjValue>,23 super_obj: Option<ObjValue>,24 bindings: LayeredHashMap<Rc<str>, LazyVal>,25}26impl Debug for ContextInternals {27 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {28 f.debug_struct("Context")29 .field("this", &self.this.as_ref().map(|e| Rc::as_ptr(&e.0)))30 .field("bindings", &self.bindings)31 .finish()32 }33}3435#[derive(Debug, Clone)]36pub struct Context(Rc<ContextInternals>);37impl Context {38 pub fn new_future() -> FutureContext {39 FutureContext(Rc::new(RefCell::new(None)))40 }4142 pub fn dollar(&self) -> &Option<ObjValue> {43 &self.0.dollar44 }4546 pub fn this(&self) -> &Option<ObjValue> {47 &self.0.this48 }4950 pub fn super_obj(&self) -> &Option<ObjValue> {51 &self.0.super_obj52 }5354 pub fn new() -> Context {55 Context(Rc::new(ContextInternals {56 dollar: None,57 this: None,58 super_obj: None,59 bindings: LayeredHashMap::default(),60 }))61 }6263 pub fn binding(&self, name: Rc<str>) -> Result<LazyVal> {64 Ok(self65 .066 .bindings67 .get(&name)68 .cloned()69 .ok_or_else(|| UnknownVariable(name))?)70 }71 pub fn into_future(self, ctx: FutureContext) -> Context {72 {73 ctx.0.borrow_mut().replace(self);74 }75 ctx.unwrap()76 }7778 pub fn with_var(&self, name: Rc<str>, value: Val) -> Result<Context> {79 let mut new_bindings = HashMap::with_capacity(1);80 new_bindings.insert(name, resolved_lazy_val!(value));81 self.extend(new_bindings, None, None, None)82 }8384 pub fn extend(85 &self,86 new_bindings: HashMap<Rc<str>, LazyVal>,87 new_dollar: Option<ObjValue>,88 new_this: Option<ObjValue>,89 new_super_obj: Option<ObjValue>,90 ) -> Result<Context> {91 let dollar = new_dollar.or_else(|| self.0.dollar.clone());92 let this = new_this.or_else(|| self.0.this.clone());93 let super_obj = new_super_obj.or_else(|| self.0.super_obj.clone());94 let bindings = if new_bindings.is_empty() {95 self.0.bindings.clone()96 } else {97 self.0.bindings.extend(new_bindings)98 };99 Ok(Context(Rc::new(ContextInternals {100 dollar,101 this,102 super_obj,103 bindings,104 })))105 }106 pub fn extend_unbound(107 &self,108 new_bindings: HashMap<Rc<str>, LazyBinding>,109 new_dollar: Option<ObjValue>,110 new_this: Option<ObjValue>,111 new_super_obj: Option<ObjValue>,112 ) -> Result<Context> {113 let this = new_this.or_else(|| self.0.this.clone());114 let super_obj = new_super_obj.or_else(|| self.0.super_obj.clone());115 let mut new = HashMap::with_capacity(new_bindings.len());116 for (k, v) in new_bindings.into_iter() {117 new.insert(k, v.evaluate(this.clone(), super_obj.clone())?);118 }119 self.extend(new, new_dollar, this, super_obj)120 }121 pub fn into_weak(self) -> WeakContext {122 WeakContext(Rc::downgrade(&self.0))123 }124}125126impl Default for Context {127 fn default() -> Self {128 Self::new()129 }130}131132impl PartialEq for Context {133 fn eq(&self, other: &Self) -> bool {134 Rc::ptr_eq(&self.0, &other.0)135 }136}137138#[derive(Debug, Clone)]139pub struct WeakContext(Weak<ContextInternals>);140impl WeakContext {141 pub fn upgrade(&self) -> Context {142 Context(self.0.upgrade().expect("context is removed"))143 }144}145impl PartialEq for WeakContext {146 fn eq(&self, other: &Self) -> bool {147 self.0.ptr_eq(&other.0)148 }149}