git.delta.rocks / jrsonnet / refs/commits / 2d0d919b58c4

difftreelog

source

crates/jrsonnet-evaluator/src/ctx.rs2.9 KiBsourcehistory
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	#[cfg(not(feature = "friendly-errors"))]53	pub fn binding(&self, name: IStr) -> Result<Thunk<Val>> {54		Ok(self55			.056			.bindings57			.get(&name)58			.cloned()59			.ok_or(VariableIsNotDefined(name, vec![]))?)60	}6162	#[cfg(feature = "friendly-errors")]63	pub fn binding(&self, name: IStr) -> Result<Thunk<Val>> {64		use std::cmp::Ordering;6566		use crate::throw;6768		if let Some(val) = self.0.bindings.get(&name).cloned() {69			return Ok(val);70		}7172		let mut heap = Vec::new();73		self.0.bindings.clone().iter_keys(|k| {74			let conf = strsim::jaro_winkler(&k as &str, &name as &str);75			if conf < 0.8 {76				return;77			}78			heap.push((conf, k));79		});80		heap.sort_by(|a, b| b.0.partial_cmp(&a.0).unwrap_or(Ordering::Equal));8182		throw!(VariableIsNotDefined(83			name,84			heap.into_iter().map(|(_, k)| k).collect()85		))86	}87	pub fn contains_binding(&self, name: IStr) -> bool {88		self.0.bindings.contains_key(&name)89	}90	#[must_use]91	pub fn into_future(self, ctx: Pending<Self>) -> Self {92		{93			ctx.0.borrow_mut().replace(self);94		}95		ctx.unwrap()96	}9798	#[must_use]99	pub fn with_var(self, name: IStr, value: Val) -> Self {100		let mut new_bindings = GcHashMap::with_capacity(1);101		new_bindings.insert(name, Thunk::evaluated(value));102		self.extend(new_bindings, None, None, None)103	}104105	#[must_use]106	pub fn extend(107		self,108		new_bindings: GcHashMap<IStr, Thunk<Val>>,109		new_dollar: Option<ObjValue>,110		new_sup: Option<ObjValue>,111		new_this: Option<ObjValue>,112	) -> Self {113		let ctx = &self.0;114		let dollar = new_dollar.or_else(|| ctx.dollar.clone());115		let this = new_this.or_else(|| ctx.this.clone());116		let sup = new_sup.or_else(|| ctx.sup.clone());117		let bindings = if new_bindings.is_empty() {118			ctx.bindings.clone()119		} else {120			ctx.bindings.clone().extend(new_bindings)121		};122		Self(Cc::new(ContextInternals {123			dollar,124			sup,125			this,126			bindings,127		}))128	}129}130131impl Default for Context {132	fn default() -> Self {133		Self::new()134	}135}136137impl PartialEq for Context {138	fn eq(&self, other: &Self) -> bool {139		cc_ptr_eq(&self.0, &other.0)140	}141}