1use std::collections::HashMap;23use jrsonnet_gcmodule::Trace;4use jrsonnet_interner::IStr;5use jrsonnet_parser::{ArgsDesc, LocExpr};67use crate::{8 error::Result, evaluate, tb, typed::Typed, val::ThunkValue, Context, State, Thunk, Val,9};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>, s: State) -> Result<Val> {19 evaluate(s, self.ctx, &self.expr)20 }21}2223pub trait ArgLike {24 fn evaluate_arg(&self, s: State, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>>;25}2627impl ArgLike for &LocExpr {28 fn evaluate_arg(&self, s: State, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {29 Ok(if tailstrict {30 Thunk::evaluated(evaluate(s, ctx, self)?)31 } else {32 Thunk::new(tb!(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, s: State, _ctx: Context, _tailstrict: bool) -> Result<Thunk<Val>> {45 let val = T::into_untyped(self.clone(), s)?;46 Ok(Thunk::evaluated(val))47 }48}4950#[derive(Clone)]51pub enum TlaArg {52 String(IStr),53 Code(LocExpr),54 Val(Val),55}56impl ArgLike for TlaArg {57 fn evaluate_arg(&self, s: State, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {58 match self {59 TlaArg::String(s) => Ok(Thunk::evaluated(Val::Str(s.clone()))),60 TlaArg::Code(code) => Ok(if tailstrict {61 Thunk::evaluated(evaluate(s, ctx, code)?)62 } else {63 Thunk::new(tb!(EvaluateThunk {64 ctx,65 expr: code.clone(),66 }))67 }),68 TlaArg::Val(val) => Ok(Thunk::evaluated(val.clone())),69 }70 }71}7273mod sealed {74 75 pub trait Unnamed {}76 77 pub trait Named {}78}7980pub trait ArgsLike {81 fn unnamed_len(&self) -> usize;82 fn unnamed_iter(83 &self,84 s: State,85 ctx: Context,86 tailstrict: bool,87 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,88 ) -> Result<()>;89 fn named_iter(90 &self,91 s: State,92 ctx: Context,93 tailstrict: bool,94 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,95 ) -> Result<()>;96 fn named_names(&self, handler: &mut dyn FnMut(&IStr));97}9899impl ArgsLike for ArgsDesc {100 fn unnamed_len(&self) -> usize {101 self.unnamed.len()102 }103104 fn unnamed_iter(105 &self,106 s: State,107 ctx: Context,108 tailstrict: bool,109 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,110 ) -> Result<()> {111 for (id, arg) in self.unnamed.iter().enumerate() {112 handler(113 id,114 if tailstrict {115 Thunk::evaluated(evaluate(s.clone(), ctx.clone(), arg)?)116 } else {117 Thunk::new(tb!(EvaluateThunk {118 ctx: ctx.clone(),119 expr: arg.clone(),120 }))121 },122 )?;123 }124 Ok(())125 }126127 fn named_iter(128 &self,129 s: State,130 ctx: Context,131 tailstrict: bool,132 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,133 ) -> Result<()> {134 for (name, arg) in &self.named {135 handler(136 name,137 if tailstrict {138 Thunk::evaluated(evaluate(s.clone(), ctx.clone(), arg)?)139 } else {140 Thunk::new(tb!(EvaluateThunk {141 ctx: ctx.clone(),142 expr: arg.clone(),143 }))144 },145 )?;146 }147 Ok(())148 }149150 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {151 for (name, _) in &self.named {152 handler(name);153 }154 }155}156157impl<A: ArgLike, S> sealed::Named for HashMap<IStr, A, S> {}158impl<A: ArgLike, S> ArgsLike for HashMap<IStr, A, S> {159 fn unnamed_len(&self) -> usize {160 0161 }162163 fn unnamed_iter(164 &self,165 _s: State,166 _ctx: Context,167 _tailstrict: bool,168 _handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,169 ) -> Result<()> {170 Ok(())171 }172173 fn named_iter(174 &self,175 s: State,176 ctx: Context,177 tailstrict: bool,178 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,179 ) -> Result<()> {180 for (name, value) in self.iter() {181 handler(182 name,183 value.evaluate_arg(s.clone(), ctx.clone(), tailstrict)?,184 )?;185 }186 Ok(())187 }188189 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {190 for (name, _) in self.iter() {191 handler(name);192 }193 }194}195196macro_rules! impl_args_like {197 ($count:expr; $($gen:ident)*) => {198 impl<$($gen: ArgLike,)*> sealed::Unnamed for ($($gen,)*) {}199 impl<$($gen: ArgLike,)*> ArgsLike for ($($gen,)*) {200 fn unnamed_len(&self) -> usize {201 $count202 }203 #[allow(non_snake_case, unused_assignments)]204 fn unnamed_iter(205 &self,206 s: State,207 ctx: Context,208 tailstrict: bool,209 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,210 ) -> Result<()> {211 let mut i = 0usize;212 let ($($gen,)*) = self;213 $(214 handler(i, $gen.evaluate_arg(s.clone(), ctx.clone(), tailstrict)?)?;215 i+=1;216 )*217 Ok(())218 }219 fn named_iter(220 &self,221 _s: State,222 _ctx: Context,223 _tailstrict: bool,224 _handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,225 ) -> Result<()> {226 Ok(())227 }228 fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}229 }230 impl<$($gen: ArgLike,)*> sealed::Named for ($((IStr, $gen),)*) {}231 impl<$($gen: ArgLike,)*> ArgsLike for ($((IStr, $gen),)*) {232 fn unnamed_len(&self) -> usize {233 0234 }235 fn unnamed_iter(236 &self,237 _s: State,238 _ctx: Context,239 _tailstrict: bool,240 _handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,241 ) -> Result<()> {242 Ok(())243 }244 #[allow(non_snake_case)]245 fn named_iter(246 &self,247 s: State,248 ctx: Context,249 tailstrict: bool,250 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,251 ) -> Result<()> {252 let ($($gen,)*) = self;253 $(254 handler(&$gen.0, $gen.1.evaluate_arg(s.clone(), ctx.clone(), tailstrict)?)?;255 )*256 Ok(())257 }258 #[allow(non_snake_case)]259 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {260 let ($($gen,)*) = self;261 $(262 handler(&$gen.0);263 )*264 }265 }266 };267 ($count:expr; $($cur:ident)* @ $c:ident $($rest:ident)*) => {268 impl_args_like!($count; $($cur)*);269 impl_args_like!($count + 1usize; $($cur)* $c @ $($rest)*);270 };271 ($count:expr; $($cur:ident)* @) => {272 impl_args_like!($count; $($cur)*);273 }274}275impl_args_like! {276 0usize; A @ B C D E F G H I J K L277}278279impl ArgsLike for () {280 fn unnamed_len(&self) -> usize {281 0282 }283284 fn unnamed_iter(285 &self,286 _s: State,287 _ctx: Context,288 _tailstrict: bool,289 _handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,290 ) -> Result<()> {291 Ok(())292 }293294 fn named_iter(295 &self,296 _s: State,297 _ctx: Context,298 _tailstrict: bool,299 _handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,300 ) -> Result<()> {301 Ok(())302 }303304 fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}305}