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 Self::String(s) => Ok(Thunk::evaluated(Val::string(s.clone()))),65 Self::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 Self::Val(val) => Ok(Thunk::evaluated(val.clone())),74 Self::Lazy(lazy) => Ok(lazy.clone()),75 }76 }77}7879pub trait ArgsLike {80 fn unnamed_len(&self) -> usize;81 fn unnamed_iter(82 &self,83 ctx: Context,84 tailstrict: bool,85 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,86 ) -> Result<()>;87 fn named_iter(88 &self,89 ctx: Context,90 tailstrict: bool,91 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,92 ) -> Result<()>;93 fn named_names(&self, handler: &mut dyn FnMut(&IStr));94}9596impl ArgsLike for Vec<Val> {97 fn unnamed_len(&self) -> usize {98 self.len()99 }100 fn unnamed_iter(101 &self,102 _ctx: Context,103 _tailstrict: bool,104 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,105 ) -> Result<()> {106 for (idx, el) in self.iter().enumerate() {107 handler(idx, Thunk::evaluated(el.clone()))?;108 }109 Ok(())110 }111 fn named_iter(112 &self,113 _ctx: Context,114 _tailstrict: bool,115 _handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,116 ) -> Result<()> {117 Ok(())118 }119 fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}120}121122impl ArgsLike for ArgsDesc {123 fn unnamed_len(&self) -> usize {124 self.unnamed.len()125 }126127 fn unnamed_iter(128 &self,129 ctx: Context,130 tailstrict: bool,131 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,132 ) -> Result<()> {133 for (id, arg) in self.unnamed.iter().enumerate() {134 handler(135 id,136 if tailstrict {137 Thunk::evaluated(evaluate(ctx.clone(), arg)?)138 } else {139 Thunk::new(EvaluateThunk {140 ctx: ctx.clone(),141 expr: arg.clone(),142 })143 },144 )?;145 }146 Ok(())147 }148149 fn named_iter(150 &self,151 ctx: Context,152 tailstrict: bool,153 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,154 ) -> Result<()> {155 for (name, arg) in &self.named {156 handler(157 name,158 if tailstrict {159 Thunk::evaluated(evaluate(ctx.clone(), arg)?)160 } else {161 Thunk::new(EvaluateThunk {162 ctx: ctx.clone(),163 expr: arg.clone(),164 })165 },166 )?;167 }168 Ok(())169 }170171 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {172 for (name, _) in &self.named {173 handler(name);174 }175 }176}177178impl<V: ArgLike, S> ArgsLike for HashMap<IStr, V, S> {179 fn unnamed_len(&self) -> usize {180 0181 }182183 fn unnamed_iter(184 &self,185 _ctx: Context,186 _tailstrict: bool,187 _handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,188 ) -> Result<()> {189 Ok(())190 }191192 fn named_iter(193 &self,194 ctx: Context,195 tailstrict: bool,196 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,197 ) -> Result<()> {198 for (name, value) in self {199 handler(name, value.evaluate_arg(ctx.clone(), tailstrict)?)?;200 }201 Ok(())202 }203204 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {205 for (name, _) in self {206 handler(name);207 }208 }209}210impl<V, S> OptionalContext for HashMap<IStr, V, S> where V: ArgLike + OptionalContext {}211212impl<A: ArgLike> ArgsLike for GcHashMap<IStr, A> {213 fn unnamed_len(&self) -> usize {214 self.0.unnamed_len()215 }216217 fn unnamed_iter(218 &self,219 ctx: Context,220 tailstrict: bool,221 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,222 ) -> Result<()> {223 self.0.unnamed_iter(ctx, tailstrict, handler)224 }225226 fn named_iter(227 &self,228 ctx: Context,229 tailstrict: bool,230 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,231 ) -> Result<()> {232 self.0.named_iter(ctx, tailstrict, handler)233 }234235 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {236 self.0.named_names(handler);237 }238}239240macro_rules! impl_args_like {241 ($count:expr; $($gen:ident)*) => {242 impl<$($gen: ArgLike,)*> ArgsLike for ($($gen,)*) {243 fn unnamed_len(&self) -> usize {244 $count245 }246 #[allow(non_snake_case, unused_assignments)]247 fn unnamed_iter(248 &self,249 ctx: Context,250 tailstrict: bool,251 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,252 ) -> Result<()> {253 let mut i = 0usize;254 let ($($gen,)*) = self;255 $(256 handler(i, $gen.evaluate_arg(ctx.clone(), tailstrict)?)?;257 i+=1;258 )*259 Ok(())260 }261 fn named_iter(262 &self,263 _ctx: Context,264 _tailstrict: bool,265 _handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,266 ) -> Result<()> {267 Ok(())268 }269 fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}270 }271 impl<$($gen: ArgLike,)*> OptionalContext for ($($gen,)*) where $($gen: OptionalContext),* {}272273 impl<$($gen: ArgLike,)*> ArgsLike for ($((IStr, $gen),)*) {274 fn unnamed_len(&self) -> usize {275 0276 }277 fn unnamed_iter(278 &self,279 _ctx: Context,280 _tailstrict: bool,281 _handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,282 ) -> Result<()> {283 Ok(())284 }285 #[allow(non_snake_case)]286 fn named_iter(287 &self,288 ctx: Context,289 tailstrict: bool,290 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,291 ) -> Result<()> {292 let ($($gen,)*) = self;293 $(294 handler(&$gen.0, $gen.1.evaluate_arg(ctx.clone(), tailstrict)?)?;295 )*296 Ok(())297 }298 #[allow(non_snake_case)]299 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {300 let ($($gen,)*) = self;301 $(302 handler(&$gen.0);303 )*304 }305 }306 impl<$($gen: ArgLike,)*> OptionalContext for ($((IStr, $gen),)*) where $($gen: OptionalContext),* {}307 };308 ($count:expr; $($cur:ident)* @ $c:ident $($rest:ident)*) => {309 impl_args_like!($count; $($cur)*);310 impl_args_like!($count + 1usize; $($cur)* $c @ $($rest)*);311 };312 ($count:expr; $($cur:ident)* @) => {313 impl_args_like!($count; $($cur)*);314 }315}316impl_args_like! {317 318 1usize; A @ B C D E F G H I J K L319}320321impl ArgsLike for () {322 fn unnamed_len(&self) -> usize {323 0324 }325326 fn unnamed_iter(327 &self,328 _ctx: Context,329 _tailstrict: bool,330 _handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,331 ) -> Result<()> {332 Ok(())333 }334335 fn named_iter(336 &self,337 _ctx: Context,338 _tailstrict: bool,339 _handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,340 ) -> Result<()> {341 Ok(())342 }343344 fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}345}346impl OptionalContext for () {}