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 Vec<Val> {100 fn unnamed_len(&self) -> usize {101 self.len()102 }103 fn unnamed_iter(104 &self,105 _s: State,106 _ctx: Context,107 _tailstrict: bool,108 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,109 ) -> Result<()> {110 for (idx, el) in self.iter().enumerate() {111 handler(idx, Thunk::evaluated(el.clone()))?;112 }113 Ok(())114 }115 fn named_iter(116 &self,117 _s: State,118 _ctx: Context,119 _tailstrict: bool,120 _handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,121 ) -> Result<()> {122 Ok(())123 }124 fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}125}126127impl ArgsLike for ArgsDesc {128 fn unnamed_len(&self) -> usize {129 self.unnamed.len()130 }131132 fn unnamed_iter(133 &self,134 s: State,135 ctx: Context,136 tailstrict: bool,137 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,138 ) -> Result<()> {139 for (id, arg) in self.unnamed.iter().enumerate() {140 handler(141 id,142 if tailstrict {143 Thunk::evaluated(evaluate(s.clone(), ctx.clone(), arg)?)144 } else {145 Thunk::new(tb!(EvaluateThunk {146 ctx: ctx.clone(),147 expr: arg.clone(),148 }))149 },150 )?;151 }152 Ok(())153 }154155 fn named_iter(156 &self,157 s: State,158 ctx: Context,159 tailstrict: bool,160 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,161 ) -> Result<()> {162 for (name, arg) in &self.named {163 handler(164 name,165 if tailstrict {166 Thunk::evaluated(evaluate(s.clone(), ctx.clone(), arg)?)167 } else {168 Thunk::new(tb!(EvaluateThunk {169 ctx: ctx.clone(),170 expr: arg.clone(),171 }))172 },173 )?;174 }175 Ok(())176 }177178 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {179 for (name, _) in &self.named {180 handler(name);181 }182 }183}184185impl<A: ArgLike, S> sealed::Named for HashMap<IStr, A, S> {}186impl<A: ArgLike, S> ArgsLike for HashMap<IStr, A, S> {187 fn unnamed_len(&self) -> usize {188 0189 }190191 fn unnamed_iter(192 &self,193 _s: State,194 _ctx: Context,195 _tailstrict: bool,196 _handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,197 ) -> Result<()> {198 Ok(())199 }200201 fn named_iter(202 &self,203 s: State,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(210 name,211 value.evaluate_arg(s.clone(), ctx.clone(), tailstrict)?,212 )?;213 }214 Ok(())215 }216217 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {218 for (name, _) in self.iter() {219 handler(name);220 }221 }222}223224macro_rules! impl_args_like {225 ($count:expr; $($gen:ident)*) => {226 impl<$($gen: ArgLike,)*> sealed::Unnamed for ($($gen,)*) {}227 impl<$($gen: ArgLike,)*> ArgsLike for ($($gen,)*) {228 fn unnamed_len(&self) -> usize {229 $count230 }231 #[allow(non_snake_case, unused_assignments)]232 fn unnamed_iter(233 &self,234 s: State,235 ctx: Context,236 tailstrict: bool,237 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,238 ) -> Result<()> {239 let mut i = 0usize;240 let ($($gen,)*) = self;241 $(242 handler(i, $gen.evaluate_arg(s.clone(), ctx.clone(), tailstrict)?)?;243 i+=1;244 )*245 Ok(())246 }247 fn named_iter(248 &self,249 _s: State,250 _ctx: Context,251 _tailstrict: bool,252 _handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,253 ) -> Result<()> {254 Ok(())255 }256 fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}257 }258 impl<$($gen: ArgLike,)*> sealed::Named for ($((IStr, $gen),)*) {}259 impl<$($gen: ArgLike,)*> ArgsLike for ($((IStr, $gen),)*) {260 fn unnamed_len(&self) -> usize {261 0262 }263 fn unnamed_iter(264 &self,265 _s: State,266 _ctx: Context,267 _tailstrict: bool,268 _handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,269 ) -> Result<()> {270 Ok(())271 }272 #[allow(non_snake_case)]273 fn named_iter(274 &self,275 s: State,276 ctx: Context,277 tailstrict: bool,278 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,279 ) -> Result<()> {280 let ($($gen,)*) = self;281 $(282 handler(&$gen.0, $gen.1.evaluate_arg(s.clone(), ctx.clone(), tailstrict)?)?;283 )*284 Ok(())285 }286 #[allow(non_snake_case)]287 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {288 let ($($gen,)*) = self;289 $(290 handler(&$gen.0);291 )*292 }293 }294 };295 ($count:expr; $($cur:ident)* @ $c:ident $($rest:ident)*) => {296 impl_args_like!($count; $($cur)*);297 impl_args_like!($count + 1usize; $($cur)* $c @ $($rest)*);298 };299 ($count:expr; $($cur:ident)* @) => {300 impl_args_like!($count; $($cur)*);301 }302}303impl_args_like! {304 305 1usize; A @ B C D E F G H I J K L306}307308impl ArgsLike for () {309 fn unnamed_len(&self) -> usize {310 0311 }312313 fn unnamed_iter(314 &self,315 _s: State,316 _ctx: Context,317 _tailstrict: bool,318 _handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,319 ) -> Result<()> {320 Ok(())321 }322323 fn named_iter(324 &self,325 _s: State,326 _ctx: Context,327 _tailstrict: bool,328 _handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,329 ) -> Result<()> {330 Ok(())331 }332333 fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}334}