1use std::fmt::Debug;23use jrsonnet_gcmodule::{Cc, Trace};4use jrsonnet_interner::IStr;5use rustc_hash::FxHashMap;67use crate::{8 error::ErrorKind::*, gc::WithCapacityExt as _, map::LayeredHashMap, ObjValue, Pending, Result,9 State, Thunk, Val,10};1112#[derive(Trace)]13struct ContextInternals {14 state: Option<State>,15 dollar: Option<ObjValue>,16 sup: Option<ObjValue>,17 this: Option<ObjValue>,18 bindings: LayeredHashMap,19}20impl Debug for ContextInternals {21 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {22 f.debug_struct("Context").finish()23 }24}2526272829#[derive(Debug, Clone, Trace)]30pub struct Context(Cc<ContextInternals>);31impl Context {32 pub fn new_future() -> Pending<Self> {33 Pending::new()34 }3536 pub fn state(&self) -> &State {37 self.038 .state39 .as_ref()40 .expect("used state from dummy context")41 }4243 pub fn dollar(&self) -> Option<&ObjValue> {44 self.0.dollar.as_ref()45 }4647 pub fn this(&self) -> Option<&ObjValue> {48 self.0.this.as_ref()49 }5051 pub fn super_obj(&self) -> Option<&ObjValue> {52 self.0.sup.as_ref()53 }5455 pub fn binding(&self, name: IStr) -> Result<Thunk<Val>> {56 use std::cmp::Ordering;5758 use crate::bail;5960 if let Some(val) = self.0.bindings.get(&name).cloned() {61 return Ok(val);62 }6364 let mut heap = Vec::new();65 self.0.bindings.clone().iter_keys(|k| {66 let conf = strsim::jaro_winkler(&k as &str, &name as &str);67 if conf < 0.8 {68 return;69 }70 heap.push((conf, k));71 });72 heap.sort_by(|a, b| b.0.partial_cmp(&a.0).unwrap_or(Ordering::Equal));7374 bail!(VariableIsNotDefined(75 name,76 heap.into_iter().map(|(_, k)| k).collect()77 ))78 }79 pub fn contains_binding(&self, name: IStr) -> bool {80 self.0.bindings.contains_key(&name)81 }82 #[must_use]83 pub fn into_future(self, ctx: Pending<Self>) -> Self {84 {85 ctx.clone().fill(self);86 }87 ctx.unwrap()88 }8990 #[must_use]91 pub fn with_var(self, name: impl Into<IStr>, value: Val) -> Self {92 let mut new_bindings = FxHashMap::with_capacity(1);93 new_bindings.insert(name.into(), Thunk::evaluated(value));94 self.extend(new_bindings, None, None, None)95 }9697 #[must_use]98 pub fn extend(99 self,100 new_bindings: FxHashMap<IStr, Thunk<Val>>,101 new_dollar: Option<ObjValue>,102 new_sup: Option<ObjValue>,103 new_this: Option<ObjValue>,104 ) -> Self {105 let ctx = &self.0;106 let dollar = new_dollar.or_else(|| ctx.dollar.clone());107 let this = new_this.or_else(|| ctx.this.clone());108 let sup = new_sup.or_else(|| ctx.sup.clone());109 let bindings = if new_bindings.is_empty() {110 ctx.bindings.clone()111 } else {112 ctx.bindings.clone().extend(new_bindings)113 };114 Self(Cc::new(ContextInternals {115 state: ctx.state.clone(),116 dollar,117 sup,118 this,119 bindings,120 }))121 }122}123124impl PartialEq for Context {125 fn eq(&self, other: &Self) -> bool {126 Cc::ptr_eq(&self.0, &other.0)127 }128}129130pub struct ContextBuilder {131 state: Option<State>,132 bindings: FxHashMap<IStr, Thunk<Val>>,133 extend: Option<Context>,134}135136impl ContextBuilder {137 138 139 pub fn dangerous_empty_state() -> Self {140 Self {141 state: None,142 bindings: FxHashMap::new(),143 extend: None,144 }145 }146 pub fn new(state: State) -> Self {147 Self::with_capacity(state, 0)148 }149 pub fn with_capacity(state: State, capacity: usize) -> Self {150 Self {151 state: Some(state),152 bindings: FxHashMap::with_capacity(capacity),153 extend: None,154 }155 }156 pub fn extend(parent: Context) -> Self {157 Self {158 state: parent.0.state.clone(),159 bindings: FxHashMap::new(),160 extend: Some(parent),161 }162 }163 164 165 pub fn bind(&mut self, name: impl Into<IStr>, value: Thunk<Val>) -> &mut Self {166 let old = self.bindings.insert(name.into(), value);167 assert!(old.is_none(), "variable bound twice in single context call");168 self169 }170 pub fn build(self) -> Context {171 if let Some(parent) = self.extend {172 173 parent.extend(self.bindings, None, None, None)174 } else {175 Context(Cc::new(ContextInternals {176 state: self.state,177 bindings: LayeredHashMap::new(self.bindings),178 dollar: None,179 sup: None,180 this: None,181 }))182 }183 }184}