git.delta.rocks / jrsonnet / refs/commits / eee6c6261500

difftreelog

source

crates/jrsonnet-evaluator/src/ctx.rs4.3 KiBsourcehistory
1use std::fmt::Debug;23use educe::Educe;4use jrsonnet_gcmodule::{Cc, Trace};5use jrsonnet_interner::IStr;6use rustc_hash::{FxHashMap, FxHashSet};78use crate::{9	ObjValue, Pending, Result, SupThis, Thunk, Val, bail, error::ErrorKind::*,10	gc::WithCapacityExt as _,11};12/// Context keeps information about current lexical code location13///14/// This information includes local variables, top-level object (`$`), current object (`this`), and super object (`super`)15#[derive(Debug, Trace, Clone, Educe)]16#[educe(PartialEq)]17pub struct Context(#[educe(PartialEq(method = Cc::ptr_eq))] Cc<ContextInternal>);1819#[derive(Debug, Trace)]20struct ContextInternal {21	dollar: Option<ObjValue>,22	sup_this: Option<SupThis>,23	bindings: FxHashMap<IStr, Thunk<Val>>,2425	branch_point: Option<Context>,26}27impl Context {28	pub fn new_future() -> Pending<Self> {29		Pending::new()30	}3132	pub fn dollar(&self) -> Option<&ObjValue> {33		self.0.dollar.as_ref()34	}3536	pub fn try_dollar(&self) -> Result<ObjValue> {37		self.038			.dollar39			.clone()40			.ok_or_else(|| CantUseSelfSupOutsideOfObject.into())41	}4243	pub fn this(&self) -> Option<&ObjValue> {44		self.0.sup_this.as_ref().map(SupThis::this)45	}4647	pub fn try_this(&self) -> Result<ObjValue> {48		self.049			.sup_this50			.as_ref()51			.ok_or_else(|| CantUseSelfSupOutsideOfObject.into())52			.map(SupThis::this)53			.cloned()54	}5556	pub fn sup_this(&self) -> Option<&SupThis> {57		self.0.sup_this.as_ref()58	}5960	pub fn try_sup_this(&self) -> Result<SupThis> {61		self.062			.sup_this63			.clone()64			.ok_or_else(|| CantUseSelfSupOutsideOfObject.into())65	}6667	pub fn binding(&self, name: IStr) -> Result<Thunk<Val>> {68		use std::cmp::Ordering;6970		use crate::bail;7172		if let Some(val) = self.0.bindings.get(&name).cloned() {73			return Ok(val);74		}7576		if let Some(branch_point) = &self.0.branch_point {77			return branch_point.binding(name);78		}7980		let mut heap = Vec::new();81		for k in self.0.bindings.keys() {82			let conf = strsim::jaro_winkler(k as &str, &name as &str);83			if conf < 0.8 {84				continue;85			}86			heap.push((conf, k.clone()));87		}88		heap.sort_by(|a, b| b.0.partial_cmp(&a.0).unwrap_or(Ordering::Equal));8990		bail!(VariableIsNotDefined(91			name,92			heap.into_iter().map(|(_, k)| k).collect()93		))94	}95	pub fn contains_binding(&self, name: IStr) -> bool {96		self.0.bindings.contains_key(&name)97	}98	#[must_use]99	pub fn into_future(self, ctx: Pending<Self>) -> Self {100		{101			ctx.clone().fill(self);102		}103		ctx.unwrap()104	}105106	#[must_use]107	pub fn branch_point(self) -> Self {108		if self.0.bindings.is_empty() {109			self110		} else {111			ContextBuilder::extend(self).build()112		}113	}114}115116#[derive(Clone)]117pub struct ContextBuilder {118	dollar: Option<ObjValue>,119	sup_this: Option<SupThis>,120	bindings: FxHashMap<IStr, Thunk<Val>>,121	filled: FxHashSet<IStr>,122	branch_point: Option<Context>,123}124125impl ContextBuilder {126	pub fn new() -> Self {127		Self {128			dollar: None,129			sup_this: None,130			bindings: FxHashMap::new(),131			filled: FxHashSet::new(),132			branch_point: None,133		}134	}135136	pub fn extend_fast(parent: Context) -> Self {137		Self {138			dollar: parent.0.dollar.clone(),139			sup_this: parent.0.sup_this.clone(),140			bindings: parent.0.bindings.clone(),141			filled: FxHashSet::new(),142			branch_point: parent.0.branch_point.clone(),143		}144	}145146	pub fn extend(parent: Context) -> Self {147		Self {148			dollar: parent.0.dollar.clone(),149			sup_this: parent.0.sup_this.clone(),150			bindings: FxHashMap::new(),151			filled: FxHashSet::new(),152			branch_point: Some(parent.clone()),153		}154	}155156	pub fn bind(&mut self, name: impl Into<IStr>, value: Thunk<Val>) {157		let _ = self.bindings.insert(name.into(), value);158	}159	/// After commit, binds would shadow the previous declarations160	#[must_use]161	pub fn commit(mut self) -> Self {162		self.filled.clear();163		self164	}165	pub fn try_bind(&mut self, name: impl Into<IStr>, value: Thunk<Val>) -> Result<()> {166		let name = name.into();167		if !self.filled.insert(name.clone()) {168			bail!(DuplicateLocalVar(name))169		}170		self.bind(name, value);171		Ok(())172	}173	pub fn build(self) -> Context {174		Context(Cc::new(ContextInternal {175			dollar: self.dollar,176			sup_this: self.sup_this,177			bindings: self.bindings,178			branch_point: self.branch_point,179		}))180	}181	pub fn build_sup_this(mut self, st: SupThis) -> Context {182		if self.dollar.is_none() {183			self.dollar = Some(st.this().clone());184		}185		self.sup_this = Some(st);186		self.build()187	}188}189190impl Default for ContextBuilder {191	fn default() -> Self {192		Self::new()193	}194}