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 let val = T::into_untyped(self.clone())?;53 Ok(Thunk::evaluated(val))54 }55}56impl<T> OptionalContext for T where T: Typed + Clone {}5758#[derive(Clone, Trace)]59pub enum TlaArg {60 String(IStr),61 Code(LocExpr),62 Val(Val),63}64impl ArgLike for TlaArg {65 fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {66 match self {67 TlaArg::String(s) => Ok(Thunk::evaluated(Val::Str(StrValue::Flat(s.clone())))),68 TlaArg::Code(code) => Ok(if tailstrict {69 Thunk::evaluated(evaluate(ctx, code)?)70 } else {71 Thunk::new(EvaluateThunk {72 ctx,73 expr: code.clone(),74 })75 }),76 TlaArg::Val(val) => Ok(Thunk::evaluated(val.clone())),77 }78 }79}8081mod sealed {82 83 pub trait Unnamed {}84 85 pub trait Named {}86}8788pub trait ArgsLike {89 fn unnamed_len(&self) -> usize;90 fn unnamed_iter(91 &self,92 ctx: Context,93 tailstrict: bool,94 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,95 ) -> Result<()>;96 fn named_iter(97 &self,98 ctx: Context,99 tailstrict: bool,100 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,101 ) -> Result<()>;102 fn named_names(&self, handler: &mut dyn FnMut(&IStr));103}104105impl ArgsLike for Vec<Val> {106 fn unnamed_len(&self) -> usize {107 self.len()108 }109 fn unnamed_iter(110 &self,111 _ctx: Context,112 _tailstrict: bool,113 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,114 ) -> Result<()> {115 for (idx, el) in self.iter().enumerate() {116 handler(idx, Thunk::evaluated(el.clone()))?;117 }118 Ok(())119 }120 fn named_iter(121 &self,122 _ctx: Context,123 _tailstrict: bool,124 _handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,125 ) -> Result<()> {126 Ok(())127 }128 fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}129}130131impl ArgsLike for ArgsDesc {132 fn unnamed_len(&self) -> usize {133 self.unnamed.len()134 }135136 fn unnamed_iter(137 &self,138 ctx: Context,139 tailstrict: bool,140 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,141 ) -> Result<()> {142 for (id, arg) in self.unnamed.iter().enumerate() {143 handler(144 id,145 if tailstrict {146 Thunk::evaluated(evaluate(ctx.clone(), arg)?)147 } else {148 Thunk::new(EvaluateThunk {149 ctx: ctx.clone(),150 expr: arg.clone(),151 })152 },153 )?;154 }155 Ok(())156 }157158 fn named_iter(159 &self,160 ctx: Context,161 tailstrict: bool,162 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,163 ) -> Result<()> {164 for (name, arg) in &self.named {165 handler(166 name,167 if tailstrict {168 Thunk::evaluated(evaluate(ctx.clone(), arg)?)169 } else {170 Thunk::new(EvaluateThunk {171 ctx: ctx.clone(),172 expr: arg.clone(),173 })174 },175 )?;176 }177 Ok(())178 }179180 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {181 for (name, _) in &self.named {182 handler(name);183 }184 }185}186187impl<V: ArgLike, S> sealed::Named for HashMap<IStr, V, S> {}188impl<V: ArgLike, S> ArgsLike for HashMap<IStr, V, S> {189 fn unnamed_len(&self) -> usize {190 0191 }192193 fn unnamed_iter(194 &self,195 _ctx: Context,196 _tailstrict: bool,197 _handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,198 ) -> Result<()> {199 Ok(())200 }201202 fn named_iter(203 &self,204 ctx: Context,205 tailstrict: bool,206 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,207 ) -> Result<()> {208 for (name, value) in self.iter() {209 handler(name, value.evaluate_arg(ctx.clone(), tailstrict)?)?;210 }211 Ok(())212 }213214 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {215 for (name, _) in self.iter() {216 handler(name);217 }218 }219}220impl<V, S> OptionalContext for HashMap<IStr, V, S> where V: ArgLike + OptionalContext {}221222impl<A: ArgLike> ArgsLike for GcHashMap<IStr, A> {223 fn unnamed_len(&self) -> usize {224 self.0.unnamed_len()225 }226227 fn unnamed_iter(228 &self,229 ctx: Context,230 tailstrict: bool,231 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,232 ) -> Result<()> {233 self.0.unnamed_iter(ctx, tailstrict, handler)234 }235236 fn named_iter(237 &self,238 ctx: Context,239 tailstrict: bool,240 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,241 ) -> Result<()> {242 self.0.named_iter(ctx, tailstrict, handler)243 }244245 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {246 self.0.named_names(handler);247 }248}249250macro_rules! impl_args_like {251 ($count:expr; $($gen:ident)*) => {252 impl<$($gen: ArgLike,)*> sealed::Unnamed for ($($gen,)*) {}253 impl<$($gen: ArgLike,)*> ArgsLike for ($($gen,)*) {254 fn unnamed_len(&self) -> usize {255 $count256 }257 #[allow(non_snake_case, unused_assignments)]258 fn unnamed_iter(259 &self,260 ctx: Context,261 tailstrict: bool,262 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,263 ) -> Result<()> {264 let mut i = 0usize;265 let ($($gen,)*) = self;266 $(267 handler(i, $gen.evaluate_arg(ctx.clone(), tailstrict)?)?;268 i+=1;269 )*270 Ok(())271 }272 fn named_iter(273 &self,274 _ctx: Context,275 _tailstrict: bool,276 _handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,277 ) -> Result<()> {278 Ok(())279 }280 fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}281 }282 impl<$($gen: ArgLike,)*> OptionalContext for ($($gen,)*) where $($gen: OptionalContext),* {}283284 impl<$($gen: ArgLike,)*> sealed::Named for ($((IStr, $gen),)*) {}285 impl<$($gen: ArgLike,)*> ArgsLike for ($((IStr, $gen),)*) {286 fn unnamed_len(&self) -> usize {287 0288 }289 fn unnamed_iter(290 &self,291 _ctx: Context,292 _tailstrict: bool,293 _handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,294 ) -> Result<()> {295 Ok(())296 }297 #[allow(non_snake_case)]298 fn named_iter(299 &self,300 ctx: Context,301 tailstrict: bool,302 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,303 ) -> Result<()> {304 let ($($gen,)*) = self;305 $(306 handler(&$gen.0, $gen.1.evaluate_arg(ctx.clone(), tailstrict)?)?;307 )*308 Ok(())309 }310 #[allow(non_snake_case)]311 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {312 let ($($gen,)*) = self;313 $(314 handler(&$gen.0);315 )*316 }317 }318 impl<$($gen: ArgLike,)*> OptionalContext for ($((IStr, $gen),)*) where $($gen: OptionalContext),* {}319 };320 ($count:expr; $($cur:ident)* @ $c:ident $($rest:ident)*) => {321 impl_args_like!($count; $($cur)*);322 impl_args_like!($count + 1usize; $($cur)* $c @ $($rest)*);323 };324 ($count:expr; $($cur:ident)* @) => {325 impl_args_like!($count; $($cur)*);326 }327}328impl_args_like! {329 330 1usize; A @ B C D E F G H I J K L331}332333impl ArgsLike for () {334 fn unnamed_len(&self) -> usize {335 0336 }337338 fn unnamed_iter(339 &self,340 _ctx: Context,341 _tailstrict: bool,342 _handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,343 ) -> Result<()> {344 Ok(())345 }346347 fn named_iter(348 &self,349 _ctx: Context,350 _tailstrict: bool,351 _handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,352 ) -> Result<()> {353 Ok(())354 }355356 fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}357}358impl OptionalContext for () {}