git.delta.rocks / jrsonnet / refs/commits / 7e18d98fd529

difftreelog

source

crates/jrsonnet-evaluator/src/ctx.rs3.8 KiBsourcehistory
1use std::{clone::Clone, fmt::Debug};23use educe::Educe;4use jrsonnet_gcmodule::{Cc, Trace};5use jrsonnet_interner::IStr;67use crate::{Pending, Result, SupThis, Thunk, Val, analyze::LocalId, error, error::ErrorKind::*};89#[derive(Debug, Trace, Clone, Educe)]10#[educe(PartialEq)]11pub struct Context(#[educe(PartialEq(method = Cc::ptr_eq))] Cc<ContextInternal>);1213#[derive(Debug, Trace, Clone)]14struct ContextInternal {15	sup_this: Option<SupThis>,16	/// `bindings[i]` corresponds to `LocalId(offset + i)`.17	bindings: Vec<Option<Thunk<Val>>>,18	offset: u32,19	parent: Option<Context>,20}2122impl Context {23	pub fn new_future() -> Pending<Self> {24		Pending::new()25	}2627	pub fn sup_this(&self) -> Option<&SupThis> {28		self.0.sup_this.as_ref()29	}3031	pub fn try_sup_this(&self) -> Result<SupThis> {32		self.033			.sup_this34			.clone()35			.ok_or_else(|| error!(CantUseSelfSupOutsideOfObject))36	}3738	/// Update binding in `CoW` fashion. Only useful for eager comprehension39	/// fast-path, as it requires Cc refcount to be 1; Use `ContextBuilder` otherwise.40	pub(crate) fn cow_fill_binding(&mut self, id: LocalId, value: Thunk<Val>) {41		let mut value = Some(Some(value));4243		self.0.update_with(|inner| {44			let local_idx = (id.0 - inner.offset) as usize;45			while inner.bindings.len() <= local_idx {46				inner.bindings.push(None);47			}48			inner.bindings[local_idx] = value.take().expect("called once");49		});50	}5152	pub fn binding(&self, id: LocalId) -> Option<Thunk<Val>> {53		let id_num = id.0;54		if id_num >= self.0.offset {55			let local_idx = (id_num - self.0.offset) as usize;56			if let Some(Some(thunk)) = self.0.bindings.get(local_idx) {57				return Some(thunk.clone());58			}59		}60		if let Some(parent) = &self.0.parent {61			return parent.binding(id);62		}63		None64	}6566	#[must_use]67	pub fn into_future(self, ctx: Pending<Self>) -> Self {68		{69			ctx.clone().fill(self);70		}71		ctx.unwrap()72	}73}7475#[derive(Clone)]76pub struct ContextBuilder {77	sup_this: Option<SupThis>,78	bindings: Vec<Option<Thunk<Val>>>,79	offset: u32,80	parent: Option<Context>,81}8283impl ContextBuilder {84	pub fn new() -> Self {85		Self {86			sup_this: None,87			bindings: Vec::new(),88			offset: 0,89			parent: None,90		}91	}9293	pub(crate) fn extend(parent: Context, capacity: usize) -> Self {94		let offset = parent.0.offset + parent.0.bindings.len() as u32;95		Self {96			sup_this: parent.0.sup_this.clone(),97			bindings: Vec::with_capacity(capacity),98			offset,99			parent: Some(parent),100		}101	}102103	pub(crate) fn bind(&mut self, id: LocalId, value: Thunk<Val>) {104		debug_assert!(105			id.0 >= self.offset,106			"cannot bind {id:?} below offset {}",107			self.offset,108		);109		let local_idx = (id.0 - self.offset) as usize;110		self.bindings.reserve(local_idx);111		while self.bindings.len() <= local_idx {112			self.bindings.push(None);113		}114		self.bindings[local_idx] = Some(value);115	}116117	pub(crate) fn build(self) -> Context {118		Context(Cc::new(ContextInternal {119			sup_this: self.sup_this,120			bindings: self.bindings,121			offset: self.offset,122			parent: self.parent,123		}))124	}125126	pub(crate) fn build_sup_this(mut self, st: SupThis) -> Context {127		self.sup_this = Some(st);128		self.build()129	}130}131132impl Default for ContextBuilder {133	fn default() -> Self {134		Self::new()135	}136}137138pub struct InitialContextBuilder {139	builder: ContextBuilder,140	externals: Vec<(IStr, LocalId)>,141	next_id: u32,142}143144impl InitialContextBuilder {145	pub(crate) fn new() -> Self {146		Self {147			builder: ContextBuilder::new(),148			externals: Vec::new(),149			next_id: 0,150		}151	}152153	pub fn bind(&mut self, name: impl Into<IStr>, value: Thunk<Val>) {154		let name = name.into();155		let id = LocalId(self.next_id);156		self.next_id += 1;157		self.externals.push((name, id));158		self.builder.bind(id, value);159	}160161	pub(crate) fn build(self) -> (ContextBuilder, Vec<(IStr, LocalId)>) {162		(self.builder, self.externals)163	}164}165166impl Default for InitialContextBuilder {167	fn default() -> Self {168		Self::new()169	}170}