1use crate::{2 error::Error::*, map::LayeredHashMap, FutureWrapper, LazyBinding, LazyVal, ObjValue, Result,3 Val,4};5use gc::{Finalize, Gc, Trace};6use jrsonnet_interner::IStr;7use rustc_hash::FxHashMap;8use std::fmt::Debug;9use std::hash::BuildHasherDefault;1011#[derive(Clone, Trace, Finalize)]12pub struct ContextCreator(pub Context, pub FutureWrapper<FxHashMap<IStr, LazyBinding>>);13impl ContextCreator {14 pub fn create(&self, this: Option<ObjValue>, super_obj: Option<ObjValue>) -> Result<Context> {15 self.0.clone().extend_unbound(16 self.1.clone().unwrap(),17 self.0.dollar().clone().or_else(|| this.clone()),18 this,19 super_obj,20 )21 }22}2324#[derive(Trace, Finalize)]25struct ContextInternals {26 dollar: Option<ObjValue>,27 this: Option<ObjValue>,28 super_obj: Option<ObjValue>,29 bindings: LayeredHashMap<LazyVal>,30}31impl Debug for ContextInternals {32 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {33 f.debug_struct("Context").finish()34 }35}3637#[derive(Debug, Clone, Trace, Finalize)]38pub struct Context(Gc<ContextInternals>);39impl Context {40 pub fn new_future() -> FutureWrapper<Self> {41 FutureWrapper::new()42 }4344 pub fn dollar(&self) -> &Option<ObjValue> {45 &self.0.dollar46 }4748 pub fn this(&self) -> &Option<ObjValue> {49 &self.0.this50 }5152 pub fn super_obj(&self) -> &Option<ObjValue> {53 &self.0.super_obj54 }5556 pub fn new() -> Self {57 Self(Gc::new(ContextInternals {58 dollar: None,59 this: None,60 super_obj: None,61 bindings: LayeredHashMap::default(),62 }))63 }6465 pub fn binding(&self, name: IStr) -> Result<LazyVal> {66 Ok(self67 .068 .bindings69 .get(&name)70 .cloned()71 .ok_or(VariableIsNotDefined(name))?)72 }73 pub fn into_future(self, ctx: FutureWrapper<Self>) -> Self {74 {75 ctx.0.borrow_mut().replace(self);76 }77 ctx.unwrap()78 }7980 pub fn with_var(self, name: IStr, value: Val) -> Self {81 let mut new_bindings =82 FxHashMap::with_capacity_and_hasher(1, BuildHasherDefault::default());83 new_bindings.insert(name, LazyVal::new_resolved(value));84 self.extend(new_bindings, None, None, None)85 }8687 pub fn with_this_super(self, new_this: ObjValue, new_super_obj: Option<ObjValue>) -> Self {88 self.extend(FxHashMap::default(), None, Some(new_this), new_super_obj)89 }9091 pub fn extend(92 self,93 new_bindings: FxHashMap<IStr, LazyVal>,94 new_dollar: Option<ObjValue>,95 new_this: Option<ObjValue>,96 new_super_obj: Option<ObjValue>,97 ) -> Self {98 let ctx = &self.0;99 let dollar = new_dollar.or_else(|| ctx.dollar.clone());100 let this = new_this.or_else(|| ctx.this.clone());101 let super_obj = new_super_obj.or_else(|| ctx.super_obj.clone());102 let bindings = if new_bindings.is_empty() {103 ctx.bindings.clone()104 } else {105 ctx.bindings.clone().extend(new_bindings)106 };107 Self(Gc::new(ContextInternals {108 dollar,109 this,110 super_obj,111 bindings,112 }))113 }114 pub fn extend_bound(self, new_bindings: FxHashMap<IStr, LazyVal>) -> Self {115 let new_this = self.0.this.clone();116 let new_super_obj = self.0.super_obj.clone();117 self.extend(new_bindings, None, new_this, new_super_obj)118 }119 pub fn extend_unbound(120 self,121 new_bindings: FxHashMap<IStr, LazyBinding>,122 new_dollar: Option<ObjValue>,123 new_this: Option<ObjValue>,124 new_super_obj: Option<ObjValue>,125 ) -> Result<Self> {126 let this = new_this.or_else(|| self.0.this.clone());127 let super_obj = new_super_obj.or_else(|| self.0.super_obj.clone());128 let mut new =129 FxHashMap::with_capacity_and_hasher(new_bindings.len(), BuildHasherDefault::default());130 for (k, v) in new_bindings.into_iter() {131 new.insert(k, v.evaluate(this.clone(), super_obj.clone())?);132 }133 Ok(self.extend(new, new_dollar, this, super_obj))134 }135 #[cfg(feature = "unstable")]136 pub fn into_weak(self) -> WeakContext {137 WeakContext(Rc::downgrade(&self.0))138 }139}140141impl Default for Context {142 fn default() -> Self {143 Self::new()144 }145}146147impl PartialEq for Context {148 fn eq(&self, other: &Self) -> bool {149 Gc::ptr_eq(&self.0, &other.0)150 }151}