1use crate::{future_wrapper, rc_fn_helper, LazyBinding, LazyVal, ObjValue};2use std::{cell::RefCell, collections::HashMap, fmt::Debug, rc::Rc};34rc_fn_helper!(5 ContextCreator,6 context_creator,7 dyn Fn(Option<ObjValue>, Option<ObjValue>) -> Context8);910future_wrapper!(Context, FutureContext);1112#[derive(Debug)]13struct ContextInternals {14 dollar: Option<ObjValue>,15 this: Option<ObjValue>,16 super_obj: Option<ObjValue>,17 bindings: Rc<HashMap<String, LazyVal>>,18}19pub struct Context(Rc<ContextInternals>);20impl Debug for Context {21 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {22 f.debug_struct("Context")23 .field("this", &self.0.this.clone().map(|e| Rc::as_ptr(&e.0)))24 .finish()25 }26}27impl Context {28 pub fn new_future() -> FutureContext {29 FutureContext(Rc::new(RefCell::new(None)))30 }3132 pub fn dollar(&self) -> &Option<ObjValue> {33 &self.0.dollar34 }3536 pub fn this(&self) -> &Option<ObjValue> {37 &self.0.this38 }3940 pub fn super_obj(&self) -> &Option<ObjValue> {41 &self.0.super_obj42 }4344 pub fn new() -> Context {45 Context(Rc::new(ContextInternals {46 dollar: None,47 this: None,48 super_obj: None,49 bindings: Rc::new(HashMap::new()),50 }))51 }5253 pub fn binding(&self, name: &str) -> LazyVal {54 self.0.bindings.get(name).cloned().unwrap_or_else(|| {55 panic!("can't find {} in {:?}", name, self);56 })57 }58 pub fn into_future(self, ctx: FutureContext) -> Context {59 {60 ctx.0.borrow_mut().replace(self);61 }62 ctx.unwrap()63 }6465 pub fn extend(66 &self,67 new_bindings: HashMap<String, LazyBinding>,68 new_dollar: Option<ObjValue>,69 new_this: Option<ObjValue>,70 new_super_obj: Option<ObjValue>,71 ) -> Context {72 let dollar = new_dollar.or_else(|| self.0.dollar.clone());73 let this = new_this.or_else(|| self.0.this.clone());74 let super_obj = new_super_obj.or_else(|| self.0.super_obj.clone());75 let bindings = if new_bindings.is_empty() {76 self.0.bindings.clone()77 } else {78 let mut new = HashMap::new(); 79 for (k, v) in self.0.bindings.iter() {80 new.insert(k.clone(), v.clone());81 }82 for (k, v) in new_bindings.into_iter() {83 new.insert(k, v.0(this.clone(), super_obj.clone()));84 }85 Rc::new(new)86 };87 Context(Rc::new(ContextInternals {88 dollar,89 this,90 super_obj,91 bindings,92 }))93 }94}9596impl Default for Context {97 fn default() -> Self {98 Self::new()99 }100}101102impl PartialEq for Context {103 fn eq(&self, other: &Self) -> bool {104 Rc::ptr_eq(&self.0, &other.0)105 }106}107108impl Clone for Context {109 fn clone(&self) -> Self {110 Context(self.0.clone())111 }112}