1use std::fmt::Debug;23use gcmodule::{Cc, Trace};4use jrsonnet_interner::IStr;56use crate::{7 cc_ptr_eq, error::Error::*, gc::GcHashMap, map::LayeredHashMap, FutureWrapper, LazyBinding,8 LazyVal, ObjValue, Result, State, Val,9};1011#[derive(Clone, Trace)]12pub struct ContextCreator(pub Context, pub FutureWrapper<GcHashMap<IStr, LazyBinding>>);13impl ContextCreator {14 pub fn create(15 &self,16 s: State,17 this: Option<ObjValue>,18 super_obj: Option<ObjValue>,19 ) -> Result<Context> {20 self.0.clone().extend_unbound(21 s,22 self.1.clone().unwrap(),23 self.0.dollar().clone().or_else(|| this.clone()),24 this,25 super_obj,26 )27 }28}2930#[derive(Trace)]31struct ContextInternals {32 dollar: Option<ObjValue>,33 this: Option<ObjValue>,34 super_obj: Option<ObjValue>,35 bindings: LayeredHashMap,36}37impl Debug for ContextInternals {38 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {39 f.debug_struct("Context").finish()40 }41}4243#[derive(Debug, Clone, Trace)]44pub struct Context(Cc<ContextInternals>);45impl Context {46 pub fn new_future() -> FutureWrapper<Self> {47 FutureWrapper::new()48 }4950 pub fn dollar(&self) -> &Option<ObjValue> {51 &self.0.dollar52 }5354 pub fn this(&self) -> &Option<ObjValue> {55 &self.0.this56 }5758 pub fn super_obj(&self) -> &Option<ObjValue> {59 &self.0.super_obj60 }6162 pub fn new() -> Self {63 Self(Cc::new(ContextInternals {64 dollar: None,65 this: None,66 super_obj: None,67 bindings: LayeredHashMap::default(),68 }))69 }7071 pub fn binding(&self, name: IStr) -> Result<LazyVal> {72 Ok(self73 .074 .bindings75 .get(&name)76 .cloned()77 .ok_or(VariableIsNotDefined(name))?)78 }79 pub fn contains_binding(&self, name: IStr) -> bool {80 self.0.bindings.contains_key(&name)81 }82 #[must_use]83 pub fn into_future(self, ctx: FutureWrapper<Self>) -> Self {84 {85 ctx.0.borrow_mut().replace(self);86 }87 ctx.unwrap()88 }8990 #[must_use]91 pub fn with_var(self, name: IStr, value: Val) -> Self {92 let mut new_bindings = GcHashMap::with_capacity(1);93 new_bindings.insert(name, LazyVal::new_resolved(value));94 self.extend(new_bindings, None, None, None)95 }9697 #[must_use]98 pub fn with_this_super(self, new_this: ObjValue, new_super_obj: Option<ObjValue>) -> Self {99 self.extend(GcHashMap::new(), None, Some(new_this), new_super_obj)100 }101102 #[must_use]103 pub fn extend(104 self,105 new_bindings: GcHashMap<IStr, LazyVal>,106 new_dollar: Option<ObjValue>,107 new_this: Option<ObjValue>,108 new_super_obj: Option<ObjValue>,109 ) -> Self {110 let ctx = &self.0;111 let dollar = new_dollar.or_else(|| ctx.dollar.clone());112 let this = new_this.or_else(|| ctx.this.clone());113 let super_obj = new_super_obj.or_else(|| ctx.super_obj.clone());114 let bindings = if new_bindings.is_empty() {115 ctx.bindings.clone()116 } else {117 ctx.bindings.clone().extend(new_bindings)118 };119 Self(Cc::new(ContextInternals {120 dollar,121 this,122 super_obj,123 bindings,124 }))125 }126 #[must_use]127 pub fn extend_bound(self, new_bindings: GcHashMap<IStr, LazyVal>) -> Self {128 let new_this = self.0.this.clone();129 let new_super_obj = self.0.super_obj.clone();130 self.extend(new_bindings, None, new_this, new_super_obj)131 }132 pub fn extend_unbound(133 self,134 s: State,135 new_bindings: GcHashMap<IStr, LazyBinding>,136 new_dollar: Option<ObjValue>,137 new_this: Option<ObjValue>,138 new_super_obj: Option<ObjValue>,139 ) -> Result<Self> {140 let this = new_this.or_else(|| self.0.this.clone());141 let super_obj = new_super_obj.or_else(|| self.0.super_obj.clone());142 let mut new = GcHashMap::with_capacity(new_bindings.len());143 for (k, v) in new_bindings.0 {144 new.insert(k, v.evaluate(s.clone(), this.clone(), super_obj.clone())?);145 }146 Ok(self.extend(new, new_dollar, this, super_obj))147 }148}149150impl Default for Context {151 fn default() -> Self {152 Self::new()153 }154}155156impl PartialEq for Context {157 fn eq(&self, other: &Self) -> bool {158 cc_ptr_eq(&self.0, &other.0)159 }160}