git.delta.rocks / jrsonnet / refs/commits / 3ee61c42d34d

difftreelog

source

crates/jrsonnet-evaluator/src/ctx.rs3.5 KiBsourcehistory
1use std::fmt::Debug;23use jrsonnet_gcmodule::{Cc, Trace};4use jrsonnet_interner::IStr;56use crate::{7	error::Error::*, gc::GcHashMap, map::LayeredHashMap, ObjValue, Pending, Result, Thunk, Val,8};910#[derive(Trace)]11struct ContextInternals {12	dollar: Option<ObjValue>,13	sup: Option<ObjValue>,14	this: Option<ObjValue>,15	bindings: LayeredHashMap,16}17impl Debug for ContextInternals {18	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {19		f.debug_struct("Context").finish()20	}21}2223#[derive(Debug, Clone, Trace)]24pub struct Context(Cc<ContextInternals>);25impl Context {26	pub fn new_future() -> Pending<Self> {27		Pending::new()28	}2930	pub fn dollar(&self) -> &Option<ObjValue> {31		&self.0.dollar32	}3334	pub fn this(&self) -> &Option<ObjValue> {35		&self.0.this36	}3738	pub fn super_obj(&self) -> &Option<ObjValue> {39		&self.0.sup40	}4142	pub fn new() -> Self {43		Self(Cc::new(ContextInternals {44			dollar: None,45			this: None,46			sup: None,47			bindings: LayeredHashMap::default(),48		}))49	}5051	#[cfg(not(feature = "friendly-errors"))]52	pub fn binding(&self, name: IStr) -> Result<Thunk<Val>> {53		Ok(self54			.055			.bindings56			.get(&name)57			.cloned()58			.ok_or(VariableIsNotDefined(name, vec![]))?)59	}6061	#[cfg(feature = "friendly-errors")]62	pub fn binding(&self, name: IStr) -> Result<Thunk<Val>> {63		use std::cmp::Ordering;6465		use crate::throw;6667		if let Some(val) = self.0.bindings.get(&name).cloned() {68			return Ok(val);69		}7071		let mut heap = Vec::new();72		self.0.bindings.clone().iter_keys(|k| {73			let conf = strsim::jaro_winkler(&k as &str, &name as &str);74			if conf < 0.8 {75				return;76			}77			heap.push((conf, k));78		});79		heap.sort_by(|a, b| b.0.partial_cmp(&a.0).unwrap_or(Ordering::Equal));8081		throw!(VariableIsNotDefined(82			name,83			heap.into_iter().map(|(_, k)| k).collect()84		))85	}86	pub fn contains_binding(&self, name: IStr) -> bool {87		self.0.bindings.contains_key(&name)88	}89	#[must_use]90	pub fn into_future(self, ctx: Pending<Self>) -> Self {91		{92			ctx.0.borrow_mut().replace(self);93		}94		ctx.unwrap()95	}9697	#[must_use]98	pub fn with_var(self, name: IStr, value: Val) -> Self {99		let mut new_bindings = GcHashMap::with_capacity(1);100		new_bindings.insert(name, Thunk::evaluated(value));101		self.extend(new_bindings, None, None, None)102	}103104	#[must_use]105	pub fn extend(106		self,107		new_bindings: GcHashMap<IStr, Thunk<Val>>,108		new_dollar: Option<ObjValue>,109		new_sup: Option<ObjValue>,110		new_this: Option<ObjValue>,111	) -> Self {112		let ctx = &self.0;113		let dollar = new_dollar.or_else(|| ctx.dollar.clone());114		let this = new_this.or_else(|| ctx.this.clone());115		let sup = new_sup.or_else(|| ctx.sup.clone());116		let bindings = if new_bindings.is_empty() {117			ctx.bindings.clone()118		} else {119			ctx.bindings.clone().extend(new_bindings)120		};121		Self(Cc::new(ContextInternals {122			dollar,123			sup,124			this,125			bindings,126		}))127	}128}129130impl Default for Context {131	fn default() -> Self {132		Self::new()133	}134}135136impl PartialEq for Context {137	fn eq(&self, other: &Self) -> bool {138		Cc::ptr_eq(&self.0, &other.0)139	}140}141142#[derive(Default)]143pub struct ContextBuilder {144	bindings: GcHashMap<IStr, Thunk<Val>>,145}146impl ContextBuilder {147	pub fn new() -> Self {148		Self::default()149	}150	pub fn with_capacity(capacity: usize) -> Self {151		Self {152			bindings: GcHashMap::with_capacity(capacity),153		}154	}155	pub fn bind(&mut self, name: IStr, value: Thunk<Val>) -> &mut Self {156		self.bindings.insert(name, value);157		self158	}159	pub fn build(self) -> Context {160		Context(Cc::new(ContextInternals {161			bindings: LayeredHashMap::new(self.bindings),162			dollar: None,163			sup: None,164			this: None,165		}))166	}167}