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 typed::Typed,11 val::{StrValue, ThunkValue},12 Context, Thunk, Val,13};141516pub trait OptionalContext {}1718#[derive(Trace)]19struct EvaluateThunk {20 ctx: Context,21 expr: LocExpr,22}23impl ThunkValue for EvaluateThunk {24 type Output = Val;25 fn get(self: Box<Self>) -> Result<Val> {26 evaluate(self.ctx, &self.expr)27 }28}2930pub trait ArgLike {31 fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>>;32}3334impl ArgLike for &LocExpr {35 fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {36 Ok(if tailstrict {37 Thunk::evaluated(evaluate(ctx, self)?)38 } else {39 Thunk::new(EvaluateThunk {40 ctx,41 expr: (*self).clone(),42 })43 })44 }45}4647impl<T> ArgLike for T48where49 T: Typed + Clone,50{51 fn evaluate_arg(&self, _ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {52 if T::provides_lazy() && !tailstrict {53 return Ok(T::into_lazy_untyped(self.clone()));54 }55 let val = T::into_untyped(self.clone())?;56 Ok(Thunk::evaluated(val))57 }58}59impl<T> OptionalContext for T where T: Typed + Clone {}6061#[derive(Clone, Trace)]62pub enum TlaArg {63 String(IStr),64 Code(LocExpr),65 Val(Val),66 Lazy(Thunk<Val>),67}68impl ArgLike for TlaArg {69 fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {70 match self {71 TlaArg::String(s) => Ok(Thunk::evaluated(Val::Str(StrValue::Flat(s.clone())))),72 TlaArg::Code(code) => Ok(if tailstrict {73 Thunk::evaluated(evaluate(ctx, code)?)74 } else {75 Thunk::new(EvaluateThunk {76 ctx,77 expr: code.clone(),78 })79 }),80 TlaArg::Val(val) => Ok(Thunk::evaluated(val.clone())),81 TlaArg::Lazy(lazy) => Ok(lazy.clone()),82 }83 }84}8586mod sealed {87 88 pub trait Unnamed {}89 90 pub trait Named {}91}9293pub trait ArgsLike {94 fn unnamed_len(&self) -> usize;95 fn unnamed_iter(96 &self,97 ctx: Context,98 tailstrict: bool,99 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,100 ) -> Result<()>;101 fn named_iter(102 &self,103 ctx: Context,104 tailstrict: bool,105 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,106 ) -> Result<()>;107 fn named_names(&self, handler: &mut dyn FnMut(&IStr));108}109110impl ArgsLike for Vec<Val> {111 fn unnamed_len(&self) -> usize {112 self.len()113 }114 fn unnamed_iter(115 &self,116 _ctx: Context,117 _tailstrict: bool,118 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,119 ) -> Result<()> {120 for (idx, el) in self.iter().enumerate() {121 handler(idx, Thunk::evaluated(el.clone()))?;122 }123 Ok(())124 }125 fn named_iter(126 &self,127 _ctx: Context,128 _tailstrict: bool,129 _handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,130 ) -> Result<()> {131 Ok(())132 }133 fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}134}135136impl ArgsLike for ArgsDesc {137 fn unnamed_len(&self) -> usize {138 self.unnamed.len()139 }140141 fn unnamed_iter(142 &self,143 ctx: Context,144 tailstrict: bool,145 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,146 ) -> Result<()> {147 for (id, arg) in self.unnamed.iter().enumerate() {148 handler(149 id,150 if tailstrict {151 Thunk::evaluated(evaluate(ctx.clone(), arg)?)152 } else {153 Thunk::new(EvaluateThunk {154 ctx: ctx.clone(),155 expr: arg.clone(),156 })157 },158 )?;159 }160 Ok(())161 }162163 fn named_iter(164 &self,165 ctx: Context,166 tailstrict: bool,167 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,168 ) -> Result<()> {169 for (name, arg) in &self.named {170 handler(171 name,172 if tailstrict {173 Thunk::evaluated(evaluate(ctx.clone(), arg)?)174 } else {175 Thunk::new(EvaluateThunk {176 ctx: ctx.clone(),177 expr: arg.clone(),178 })179 },180 )?;181 }182 Ok(())183 }184185 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {186 for (name, _) in &self.named {187 handler(name);188 }189 }190}191192impl<V: ArgLike, S> sealed::Named for HashMap<IStr, V, S> {}193impl<V: ArgLike, S> ArgsLike for HashMap<IStr, V, S> {194 fn unnamed_len(&self) -> usize {195 0196 }197198 fn unnamed_iter(199 &self,200 _ctx: Context,201 _tailstrict: bool,202 _handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,203 ) -> Result<()> {204 Ok(())205 }206207 fn named_iter(208 &self,209 ctx: Context,210 tailstrict: bool,211 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,212 ) -> Result<()> {213 for (name, value) in self {214 handler(name, value.evaluate_arg(ctx.clone(), tailstrict)?)?;215 }216 Ok(())217 }218219 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {220 for (name, _) in self {221 handler(name);222 }223 }224}225impl<V, S> OptionalContext for HashMap<IStr, V, S> where V: ArgLike + OptionalContext {}226227impl<A: ArgLike> ArgsLike for GcHashMap<IStr, A> {228 fn unnamed_len(&self) -> usize {229 self.0.unnamed_len()230 }231232 fn unnamed_iter(233 &self,234 ctx: Context,235 tailstrict: bool,236 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,237 ) -> Result<()> {238 self.0.unnamed_iter(ctx, tailstrict, handler)239 }240241 fn named_iter(242 &self,243 ctx: Context,244 tailstrict: bool,245 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,246 ) -> Result<()> {247 self.0.named_iter(ctx, tailstrict, handler)248 }249250 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {251 self.0.named_names(handler);252 }253}254255macro_rules! impl_args_like {256 ($count:expr; $($gen:ident)*) => {257 impl<$($gen: ArgLike,)*> sealed::Unnamed for ($($gen,)*) {}258 impl<$($gen: ArgLike,)*> ArgsLike for ($($gen,)*) {259 fn unnamed_len(&self) -> usize {260 $count261 }262 #[allow(non_snake_case, unused_assignments)]263 fn unnamed_iter(264 &self,265 ctx: Context,266 tailstrict: bool,267 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,268 ) -> Result<()> {269 let mut i = 0usize;270 let ($($gen,)*) = self;271 $(272 handler(i, $gen.evaluate_arg(ctx.clone(), tailstrict)?)?;273 i+=1;274 )*275 Ok(())276 }277 fn named_iter(278 &self,279 _ctx: Context,280 _tailstrict: bool,281 _handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,282 ) -> Result<()> {283 Ok(())284 }285 fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}286 }287 impl<$($gen: ArgLike,)*> OptionalContext for ($($gen,)*) where $($gen: OptionalContext),* {}288289 impl<$($gen: ArgLike,)*> sealed::Named for ($((IStr, $gen),)*) {}290 impl<$($gen: ArgLike,)*> ArgsLike for ($((IStr, $gen),)*) {291 fn unnamed_len(&self) -> usize {292 0293 }294 fn unnamed_iter(295 &self,296 _ctx: Context,297 _tailstrict: bool,298 _handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,299 ) -> Result<()> {300 Ok(())301 }302 #[allow(non_snake_case)]303 fn named_iter(304 &self,305 ctx: Context,306 tailstrict: bool,307 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,308 ) -> Result<()> {309 let ($($gen,)*) = self;310 $(311 handler(&$gen.0, $gen.1.evaluate_arg(ctx.clone(), tailstrict)?)?;312 )*313 Ok(())314 }315 #[allow(non_snake_case)]316 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {317 let ($($gen,)*) = self;318 $(319 handler(&$gen.0);320 )*321 }322 }323 impl<$($gen: ArgLike,)*> OptionalContext for ($((IStr, $gen),)*) where $($gen: OptionalContext),* {}324 };325 ($count:expr; $($cur:ident)* @ $c:ident $($rest:ident)*) => {326 impl_args_like!($count; $($cur)*);327 impl_args_like!($count + 1usize; $($cur)* $c @ $($rest)*);328 };329 ($count:expr; $($cur:ident)* @) => {330 impl_args_like!($count; $($cur)*);331 }332}333impl_args_like! {334 335 1usize; A @ B C D E F G H I J K L336}337338impl ArgsLike for () {339 fn unnamed_len(&self) -> usize {340 0341 }342343 fn unnamed_iter(344 &self,345 _ctx: Context,346 _tailstrict: bool,347 _handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,348 ) -> Result<()> {349 Ok(())350 }351352 fn named_iter(353 &self,354 _ctx: Context,355 _tailstrict: bool,356 _handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,357 ) -> Result<()> {358 Ok(())359 }360361 fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}362}363impl OptionalContext for () {}