1use hashbrown::HashMap;2use jrsonnet_gcmodule::Trace;3use jrsonnet_interner::IStr;4use jrsonnet_parser::{ArgsDesc, LocExpr};56use crate::{evaluate, gc::GcHashMap, typed::Typed, val::ThunkValue, Context, Result, Thunk, Val};789pub trait OptionalContext {}1011#[derive(Trace)]12struct EvaluateThunk {13 ctx: Context,14 expr: LocExpr,15}16impl ThunkValue for EvaluateThunk {17 type Output = Val;18 fn get(self: Box<Self>) -> Result<Val> {19 evaluate(self.ctx, &self.expr)20 }21}2223pub trait ArgLike {24 fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>>;25}2627impl ArgLike for &LocExpr {28 fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {29 Ok(if tailstrict {30 Thunk::evaluated(evaluate(ctx, self)?)31 } else {32 Thunk::new(EvaluateThunk {33 ctx,34 expr: (*self).clone(),35 })36 })37 }38}3940impl<T> ArgLike for T41where42 T: Typed + Clone,43{44 fn evaluate_arg(&self, _ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {45 if T::provides_lazy() && !tailstrict {46 return Ok(T::into_lazy_untyped(self.clone()));47 }48 let val = T::into_untyped(self.clone())?;49 Ok(Thunk::evaluated(val))50 }51}52impl<T> OptionalContext for T where T: Typed + Clone {}5354#[derive(Clone, Trace)]55pub enum TlaArg {56 String(IStr),57 Code(LocExpr),58 Val(Val),59 Lazy(Thunk<Val>),60}61impl ArgLike for TlaArg {62 fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {63 match self {64 TlaArg::String(s) => Ok(Thunk::evaluated(Val::string(s.clone()))),65 TlaArg::Code(code) => Ok(if tailstrict {66 Thunk::evaluated(evaluate(ctx, code)?)67 } else {68 Thunk::new(EvaluateThunk {69 ctx,70 expr: code.clone(),71 })72 }),73 TlaArg::Val(val) => Ok(Thunk::evaluated(val.clone())),74 TlaArg::Lazy(lazy) => Ok(lazy.clone()),75 }76 }77}7879mod sealed {80 81 pub trait Unnamed {}82 83 pub trait Named {}84}8586pub trait ArgsLike {87 fn unnamed_len(&self) -> usize;88 fn unnamed_iter(89 &self,90 ctx: Context,91 tailstrict: bool,92 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,93 ) -> Result<()>;94 fn named_iter(95 &self,96 ctx: Context,97 tailstrict: bool,98 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,99 ) -> Result<()>;100 fn named_names(&self, handler: &mut dyn FnMut(&IStr));101}102103impl ArgsLike for Vec<Val> {104 fn unnamed_len(&self) -> usize {105 self.len()106 }107 fn unnamed_iter(108 &self,109 _ctx: Context,110 _tailstrict: bool,111 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,112 ) -> Result<()> {113 for (idx, el) in self.iter().enumerate() {114 handler(idx, Thunk::evaluated(el.clone()))?;115 }116 Ok(())117 }118 fn named_iter(119 &self,120 _ctx: Context,121 _tailstrict: bool,122 _handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,123 ) -> Result<()> {124 Ok(())125 }126 fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}127}128129impl ArgsLike for ArgsDesc {130 fn unnamed_len(&self) -> usize {131 self.unnamed.len()132 }133134 fn unnamed_iter(135 &self,136 ctx: Context,137 tailstrict: bool,138 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,139 ) -> Result<()> {140 for (id, arg) in self.unnamed.iter().enumerate() {141 handler(142 id,143 if tailstrict {144 Thunk::evaluated(evaluate(ctx.clone(), arg)?)145 } else {146 Thunk::new(EvaluateThunk {147 ctx: ctx.clone(),148 expr: arg.clone(),149 })150 },151 )?;152 }153 Ok(())154 }155156 fn named_iter(157 &self,158 ctx: Context,159 tailstrict: bool,160 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,161 ) -> Result<()> {162 for (name, arg) in &self.named {163 handler(164 name,165 if tailstrict {166 Thunk::evaluated(evaluate(ctx.clone(), arg)?)167 } else {168 Thunk::new(EvaluateThunk {169 ctx: ctx.clone(),170 expr: arg.clone(),171 })172 },173 )?;174 }175 Ok(())176 }177178 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {179 for (name, _) in &self.named {180 handler(name);181 }182 }183}184185impl<V: ArgLike, S> sealed::Named for HashMap<IStr, V, S> {}186impl<V: ArgLike, S> ArgsLike for HashMap<IStr, V, S> {187 fn unnamed_len(&self) -> usize {188 0189 }190191 fn unnamed_iter(192 &self,193 _ctx: Context,194 _tailstrict: bool,195 _handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,196 ) -> Result<()> {197 Ok(())198 }199200 fn named_iter(201 &self,202 ctx: Context,203 tailstrict: bool,204 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,205 ) -> Result<()> {206 for (name, value) in self {207 handler(name, value.evaluate_arg(ctx.clone(), tailstrict)?)?;208 }209 Ok(())210 }211212 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {213 for (name, _) in self {214 handler(name);215 }216 }217}218impl<V, S> OptionalContext for HashMap<IStr, V, S> where V: ArgLike + OptionalContext {}219220impl<A: ArgLike> ArgsLike for GcHashMap<IStr, A> {221 fn unnamed_len(&self) -> usize {222 self.0.unnamed_len()223 }224225 fn unnamed_iter(226 &self,227 ctx: Context,228 tailstrict: bool,229 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,230 ) -> Result<()> {231 self.0.unnamed_iter(ctx, tailstrict, handler)232 }233234 fn named_iter(235 &self,236 ctx: Context,237 tailstrict: bool,238 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,239 ) -> Result<()> {240 self.0.named_iter(ctx, tailstrict, handler)241 }242243 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {244 self.0.named_names(handler);245 }246}247248macro_rules! impl_args_like {249 ($count:expr; $($gen:ident)*) => {250 impl<$($gen: ArgLike,)*> sealed::Unnamed for ($($gen,)*) {}251 impl<$($gen: ArgLike,)*> ArgsLike for ($($gen,)*) {252 fn unnamed_len(&self) -> usize {253 $count254 }255 #[allow(non_snake_case, unused_assignments)]256 fn unnamed_iter(257 &self,258 ctx: Context,259 tailstrict: bool,260 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,261 ) -> Result<()> {262 let mut i = 0usize;263 let ($($gen,)*) = self;264 $(265 handler(i, $gen.evaluate_arg(ctx.clone(), tailstrict)?)?;266 i+=1;267 )*268 Ok(())269 }270 fn named_iter(271 &self,272 _ctx: Context,273 _tailstrict: bool,274 _handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,275 ) -> Result<()> {276 Ok(())277 }278 fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}279 }280 impl<$($gen: ArgLike,)*> OptionalContext for ($($gen,)*) where $($gen: OptionalContext),* {}281282 impl<$($gen: ArgLike,)*> sealed::Named for ($((IStr, $gen),)*) {}283 impl<$($gen: ArgLike,)*> ArgsLike for ($((IStr, $gen),)*) {284 fn unnamed_len(&self) -> usize {285 0286 }287 fn unnamed_iter(288 &self,289 _ctx: Context,290 _tailstrict: bool,291 _handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,292 ) -> Result<()> {293 Ok(())294 }295 #[allow(non_snake_case)]296 fn named_iter(297 &self,298 ctx: Context,299 tailstrict: bool,300 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,301 ) -> Result<()> {302 let ($($gen,)*) = self;303 $(304 handler(&$gen.0, $gen.1.evaluate_arg(ctx.clone(), tailstrict)?)?;305 )*306 Ok(())307 }308 #[allow(non_snake_case)]309 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {310 let ($($gen,)*) = self;311 $(312 handler(&$gen.0);313 )*314 }315 }316 impl<$($gen: ArgLike,)*> OptionalContext for ($((IStr, $gen),)*) where $($gen: OptionalContext),* {}317 };318 ($count:expr; $($cur:ident)* @ $c:ident $($rest:ident)*) => {319 impl_args_like!($count; $($cur)*);320 impl_args_like!($count + 1usize; $($cur)* $c @ $($rest)*);321 };322 ($count:expr; $($cur:ident)* @) => {323 impl_args_like!($count; $($cur)*);324 }325}326impl_args_like! {327 328 1usize; A @ B C D E F G H I J K L329}330331impl ArgsLike for () {332 fn unnamed_len(&self) -> usize {333 0334 }335336 fn unnamed_iter(337 &self,338 _ctx: Context,339 _tailstrict: bool,340 _handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,341 ) -> Result<()> {342 Ok(())343 }344345 fn named_iter(346 &self,347 _ctx: Context,348 _tailstrict: bool,349 _handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,350 ) -> Result<()> {351 Ok(())352 }353354 fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}355}356impl OptionalContext for () {}