1use hashbrown::HashMap;2use jrsonnet_gcmodule::Trace;3use jrsonnet_interner::IStr;4use jrsonnet_parser::{ArgsDesc, LocExpr};56use crate::{7 error::Result,8 evaluate,9 gc::GcHashMap,10 tb,11 typed::Typed,12 val::{StrValue, ThunkValue},13 Context, Thunk, Val,14};151617pub trait OptionalContext {}1819#[derive(Trace)]20struct EvaluateThunk {21 ctx: Context,22 expr: LocExpr,23}24impl ThunkValue for EvaluateThunk {25 type Output = Val;26 fn get(self: Box<Self>) -> Result<Val> {27 evaluate(self.ctx, &self.expr)28 }29}3031pub trait ArgLike {32 fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>>;33}3435impl ArgLike for &LocExpr {36 fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {37 Ok(if tailstrict {38 Thunk::evaluated(evaluate(ctx, self)?)39 } else {40 Thunk::new(tb!(EvaluateThunk {41 ctx,42 expr: (*self).clone(),43 }))44 })45 }46}4748impl<T> ArgLike for T49where50 T: Typed + Clone,51{52 fn evaluate_arg(&self, _ctx: Context, _tailstrict: bool) -> Result<Thunk<Val>> {53 let val = T::into_untyped(self.clone())?;54 Ok(Thunk::evaluated(val))55 }56}57impl<T> OptionalContext for T where T: Typed + Clone {}5859#[derive(Clone, Trace)]60pub enum TlaArg {61 String(IStr),62 Code(LocExpr),63 Val(Val),64}65impl ArgLike for TlaArg {66 fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {67 match self {68 TlaArg::String(s) => Ok(Thunk::evaluated(Val::Str(StrValue::Flat(s.clone())))),69 TlaArg::Code(code) => Ok(if tailstrict {70 Thunk::evaluated(evaluate(ctx, code)?)71 } else {72 Thunk::new(tb!(EvaluateThunk {73 ctx,74 expr: code.clone(),75 }))76 }),77 TlaArg::Val(val) => Ok(Thunk::evaluated(val.clone())),78 }79 }80}8182mod sealed {83 84 pub trait Unnamed {}85 86 pub trait Named {}87}8889pub trait ArgsLike {90 fn unnamed_len(&self) -> usize;91 fn unnamed_iter(92 &self,93 ctx: Context,94 tailstrict: bool,95 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,96 ) -> Result<()>;97 fn named_iter(98 &self,99 ctx: Context,100 tailstrict: bool,101 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,102 ) -> Result<()>;103 fn named_names(&self, handler: &mut dyn FnMut(&IStr));104}105106impl ArgsLike for Vec<Val> {107 fn unnamed_len(&self) -> usize {108 self.len()109 }110 fn unnamed_iter(111 &self,112 _ctx: Context,113 _tailstrict: bool,114 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,115 ) -> Result<()> {116 for (idx, el) in self.iter().enumerate() {117 handler(idx, Thunk::evaluated(el.clone()))?;118 }119 Ok(())120 }121 fn named_iter(122 &self,123 _ctx: Context,124 _tailstrict: bool,125 _handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,126 ) -> Result<()> {127 Ok(())128 }129 fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}130}131impl OptionalContext for Vec<Val> {}132133impl ArgsLike for ArgsDesc {134 fn unnamed_len(&self) -> usize {135 self.unnamed.len()136 }137138 fn unnamed_iter(139 &self,140 ctx: Context,141 tailstrict: bool,142 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,143 ) -> Result<()> {144 for (id, arg) in self.unnamed.iter().enumerate() {145 handler(146 id,147 if tailstrict {148 Thunk::evaluated(evaluate(ctx.clone(), arg)?)149 } else {150 Thunk::new(tb!(EvaluateThunk {151 ctx: ctx.clone(),152 expr: arg.clone(),153 }))154 },155 )?;156 }157 Ok(())158 }159160 fn named_iter(161 &self,162 ctx: Context,163 tailstrict: bool,164 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,165 ) -> Result<()> {166 for (name, arg) in &self.named {167 handler(168 name,169 if tailstrict {170 Thunk::evaluated(evaluate(ctx.clone(), arg)?)171 } else {172 Thunk::new(tb!(EvaluateThunk {173 ctx: ctx.clone(),174 expr: arg.clone(),175 }))176 },177 )?;178 }179 Ok(())180 }181182 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {183 for (name, _) in &self.named {184 handler(name);185 }186 }187}188189impl<V: ArgLike, S> sealed::Named for HashMap<IStr, V, S> {}190impl<V: ArgLike, S> ArgsLike for HashMap<IStr, V, S> {191 fn unnamed_len(&self) -> usize {192 0193 }194195 fn unnamed_iter(196 &self,197 _ctx: Context,198 _tailstrict: bool,199 _handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,200 ) -> Result<()> {201 Ok(())202 }203204 fn named_iter(205 &self,206 ctx: Context,207 tailstrict: bool,208 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,209 ) -> Result<()> {210 for (name, value) in self.iter() {211 handler(name, value.evaluate_arg(ctx.clone(), tailstrict)?)?;212 }213 Ok(())214 }215216 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {217 for (name, _) in self.iter() {218 handler(name);219 }220 }221}222impl<V, S> OptionalContext for HashMap<IStr, V, S> where V: ArgLike + OptionalContext {}223224impl<A: ArgLike> ArgsLike for GcHashMap<IStr, A> {225 fn unnamed_len(&self) -> usize {226 self.0.unnamed_len()227 }228229 fn unnamed_iter(230 &self,231 ctx: Context,232 tailstrict: bool,233 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,234 ) -> Result<()> {235 self.0.unnamed_iter(ctx, tailstrict, handler)236 }237238 fn named_iter(239 &self,240 ctx: Context,241 tailstrict: bool,242 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,243 ) -> Result<()> {244 self.0.named_iter(ctx, tailstrict, handler)245 }246247 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {248 self.0.named_names(handler);249 }250}251252macro_rules! impl_args_like {253 ($count:expr; $($gen:ident)*) => {254 impl<$($gen: ArgLike,)*> sealed::Unnamed for ($($gen,)*) {}255 impl<$($gen: ArgLike,)*> ArgsLike for ($($gen,)*) {256 fn unnamed_len(&self) -> usize {257 $count258 }259 #[allow(non_snake_case, unused_assignments)]260 fn unnamed_iter(261 &self,262 ctx: Context,263 tailstrict: bool,264 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,265 ) -> Result<()> {266 let mut i = 0usize;267 let ($($gen,)*) = self;268 $(269 handler(i, $gen.evaluate_arg(ctx.clone(), tailstrict)?)?;270 i+=1;271 )*272 Ok(())273 }274 fn named_iter(275 &self,276 _ctx: Context,277 _tailstrict: bool,278 _handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,279 ) -> Result<()> {280 Ok(())281 }282 fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}283 }284 impl<$($gen: ArgLike,)*> OptionalContext for ($($gen,)*) where $($gen: OptionalContext),* {}285286 impl<$($gen: ArgLike,)*> sealed::Named for ($((IStr, $gen),)*) {}287 impl<$($gen: ArgLike,)*> ArgsLike for ($((IStr, $gen),)*) {288 fn unnamed_len(&self) -> usize {289 0290 }291 fn unnamed_iter(292 &self,293 _ctx: Context,294 _tailstrict: bool,295 _handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,296 ) -> Result<()> {297 Ok(())298 }299 #[allow(non_snake_case)]300 fn named_iter(301 &self,302 ctx: Context,303 tailstrict: bool,304 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,305 ) -> Result<()> {306 let ($($gen,)*) = self;307 $(308 handler(&$gen.0, $gen.1.evaluate_arg(ctx.clone(), tailstrict)?)?;309 )*310 Ok(())311 }312 #[allow(non_snake_case)]313 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {314 let ($($gen,)*) = self;315 $(316 handler(&$gen.0);317 )*318 }319 }320 impl<$($gen: ArgLike,)*> OptionalContext for ($((IStr, $gen),)*) where $($gen: OptionalContext),* {}321 };322 ($count:expr; $($cur:ident)* @ $c:ident $($rest:ident)*) => {323 impl_args_like!($count; $($cur)*);324 impl_args_like!($count + 1usize; $($cur)* $c @ $($rest)*);325 };326 ($count:expr; $($cur:ident)* @) => {327 impl_args_like!($count; $($cur)*);328 }329}330impl_args_like! {331 332 1usize; A @ B C D E F G H I J K L333}334335impl ArgsLike for () {336 fn unnamed_len(&self) -> usize {337 0338 }339340 fn unnamed_iter(341 &self,342 _ctx: Context,343 _tailstrict: bool,344 _handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,345 ) -> Result<()> {346 Ok(())347 }348349 fn named_iter(350 &self,351 _ctx: Context,352 _tailstrict: bool,353 _handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,354 ) -> Result<()> {355 Ok(())356 }357358 fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}359}360impl OptionalContext for () {}