1use std::fmt::Debug;23use gcmodule::{Cc, Trace};4use jrsonnet_interner::IStr;56use crate::{7 cc_ptr_eq, error::Error::*, gc::GcHashMap, map::LayeredHashMap, ObjValue, Pending, Result,8 Thunk, Val,9};1011#[derive(Trace)]12struct ContextInternals {13 dollar: Option<ObjValue>,14 sup: Option<ObjValue>,15 this: Option<ObjValue>,16 bindings: LayeredHashMap,17}18impl Debug for ContextInternals {19 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {20 f.debug_struct("Context").finish()21 }22}2324#[derive(Debug, Clone, Trace)]25pub struct Context(Cc<ContextInternals>);26impl Context {27 pub fn new_future() -> Pending<Self> {28 Pending::new()29 }3031 pub fn dollar(&self) -> &Option<ObjValue> {32 &self.0.dollar33 }3435 pub fn this(&self) -> &Option<ObjValue> {36 &self.0.this37 }3839 pub fn super_obj(&self) -> &Option<ObjValue> {40 &self.0.sup41 }4243 pub fn new() -> Self {44 Self(Cc::new(ContextInternals {45 dollar: None,46 this: None,47 sup: None,48 bindings: LayeredHashMap::default(),49 }))50 }5152 pub fn binding(&self, name: IStr) -> Result<Thunk<Val>> {53 Ok(self54 .055 .bindings56 .get(&name)57 .cloned()58 .ok_or(VariableIsNotDefined(name))?)59 }60 pub fn contains_binding(&self, name: IStr) -> bool {61 self.0.bindings.contains_key(&name)62 }63 #[must_use]64 pub fn into_future(self, ctx: Pending<Self>) -> Self {65 {66 ctx.0.borrow_mut().replace(self);67 }68 ctx.unwrap()69 }7071 #[must_use]72 pub fn with_var(self, name: IStr, value: Val) -> Self {73 let mut new_bindings = GcHashMap::with_capacity(1);74 new_bindings.insert(name, Thunk::evaluated(value));75 self.extend(new_bindings, None, None, None)76 }7778 #[must_use]79 pub fn extend(80 self,81 new_bindings: GcHashMap<IStr, Thunk<Val>>,82 new_dollar: Option<ObjValue>,83 new_sup: Option<ObjValue>,84 new_this: Option<ObjValue>,85 ) -> Self {86 let ctx = &self.0;87 let dollar = new_dollar.or_else(|| ctx.dollar.clone());88 let this = new_this.or_else(|| ctx.this.clone());89 let sup = new_sup.or_else(|| ctx.sup.clone());90 let bindings = if new_bindings.is_empty() {91 ctx.bindings.clone()92 } else {93 ctx.bindings.clone().extend(new_bindings)94 };95 Self(Cc::new(ContextInternals {96 dollar,97 sup,98 this,99 bindings,100 }))101 }102}103104impl Default for Context {105 fn default() -> Self {106 Self::new()107 }108}109110impl PartialEq for Context {111 fn eq(&self, other: &Self) -> bool {112 cc_ptr_eq(&self.0, &other.0)113 }114}