1use std::collections::HashMap;23use jrsonnet_gcmodule::Trace;4use jrsonnet_interner::IStr;5use jrsonnet_parser::{ArgsDesc, LocExpr};67use crate::{error::Result, evaluate, tb, typed::Typed, val::ThunkValue, Context, Thunk, Val};8910pub trait OptionalContext {}1112#[derive(Trace)]13struct EvaluateThunk {14 ctx: Context,15 expr: LocExpr,16}17impl ThunkValue for EvaluateThunk {18 type Output = Val;19 fn get(self: Box<Self>) -> Result<Val> {20 evaluate(self.ctx, &self.expr)21 }22}2324pub trait ArgLike {25 fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>>;26}2728impl ArgLike for &LocExpr {29 fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {30 Ok(if tailstrict {31 Thunk::evaluated(evaluate(ctx, self)?)32 } else {33 Thunk::new(tb!(EvaluateThunk {34 ctx,35 expr: (*self).clone(),36 }))37 })38 }39}4041impl<T> ArgLike for T42where43 T: Typed + Clone,44{45 fn evaluate_arg(&self, _ctx: Context, _tailstrict: bool) -> Result<Thunk<Val>> {46 let val = T::into_untyped(self.clone())?;47 Ok(Thunk::evaluated(val))48 }49}50impl<T> OptionalContext for T where T: Typed + Clone {}5152#[derive(Clone, Trace)]53pub enum TlaArg {54 String(IStr),55 Code(LocExpr),56 Val(Val),57}58impl ArgLike for TlaArg {59 fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {60 match self {61 TlaArg::String(s) => Ok(Thunk::evaluated(Val::Str(s.clone()))),62 TlaArg::Code(code) => Ok(if tailstrict {63 Thunk::evaluated(evaluate(ctx, code)?)64 } else {65 Thunk::new(tb!(EvaluateThunk {66 ctx,67 expr: code.clone(),68 }))69 }),70 TlaArg::Val(val) => Ok(Thunk::evaluated(val.clone())),71 }72 }73}7475mod sealed {76 77 pub trait Unnamed {}78 79 pub trait Named {}80}8182pub trait ArgsLike {83 fn unnamed_len(&self) -> usize;84 fn unnamed_iter(85 &self,86 ctx: Context,87 tailstrict: bool,88 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,89 ) -> Result<()>;90 fn named_iter(91 &self,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 _ctx: Context,106 _tailstrict: bool,107 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,108 ) -> Result<()> {109 for (idx, el) in self.iter().enumerate() {110 handler(idx, Thunk::evaluated(el.clone()))?;111 }112 Ok(())113 }114 fn named_iter(115 &self,116 _ctx: Context,117 _tailstrict: bool,118 _handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,119 ) -> Result<()> {120 Ok(())121 }122 fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}123}124impl OptionalContext for Vec<Val> {}125126impl ArgsLike for ArgsDesc {127 fn unnamed_len(&self) -> usize {128 self.unnamed.len()129 }130131 fn unnamed_iter(132 &self,133 ctx: Context,134 tailstrict: bool,135 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,136 ) -> Result<()> {137 for (id, arg) in self.unnamed.iter().enumerate() {138 handler(139 id,140 if tailstrict {141 Thunk::evaluated(evaluate(ctx.clone(), arg)?)142 } else {143 Thunk::new(tb!(EvaluateThunk {144 ctx: ctx.clone(),145 expr: arg.clone(),146 }))147 },148 )?;149 }150 Ok(())151 }152153 fn named_iter(154 &self,155 ctx: Context,156 tailstrict: bool,157 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,158 ) -> Result<()> {159 for (name, arg) in &self.named {160 handler(161 name,162 if tailstrict {163 Thunk::evaluated(evaluate(ctx.clone(), arg)?)164 } else {165 Thunk::new(tb!(EvaluateThunk {166 ctx: ctx.clone(),167 expr: arg.clone(),168 }))169 },170 )?;171 }172 Ok(())173 }174175 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {176 for (name, _) in &self.named {177 handler(name);178 }179 }180}181182impl<A: ArgLike, S> sealed::Named for HashMap<IStr, A, S> {}183impl<A: ArgLike, S> ArgsLike for HashMap<IStr, A, S> {184 fn unnamed_len(&self) -> usize {185 0186 }187188 fn unnamed_iter(189 &self,190 _ctx: Context,191 _tailstrict: bool,192 _handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,193 ) -> Result<()> {194 Ok(())195 }196197 fn named_iter(198 &self,199 ctx: Context,200 tailstrict: bool,201 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,202 ) -> Result<()> {203 for (name, value) in self.iter() {204 handler(name, value.evaluate_arg(ctx.clone(), tailstrict)?)?;205 }206 Ok(())207 }208209 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {210 for (name, _) in self.iter() {211 handler(name);212 }213 }214}215impl<A, S> OptionalContext for HashMap<IStr, A, S> where A: ArgLike + OptionalContext {}216217macro_rules! impl_args_like {218 ($count:expr; $($gen:ident)*) => {219 impl<$($gen: ArgLike,)*> sealed::Unnamed for ($($gen,)*) {}220 impl<$($gen: ArgLike,)*> ArgsLike for ($($gen,)*) {221 fn unnamed_len(&self) -> usize {222 $count223 }224 #[allow(non_snake_case, unused_assignments)]225 fn unnamed_iter(226 &self,227 ctx: Context,228 tailstrict: bool,229 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,230 ) -> Result<()> {231 let mut i = 0usize;232 let ($($gen,)*) = self;233 $(234 handler(i, $gen.evaluate_arg(ctx.clone(), tailstrict)?)?;235 i+=1;236 )*237 Ok(())238 }239 fn named_iter(240 &self,241 _ctx: Context,242 _tailstrict: bool,243 _handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,244 ) -> Result<()> {245 Ok(())246 }247 fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}248 }249 impl<$($gen: ArgLike,)*> OptionalContext for ($($gen,)*) where $($gen: OptionalContext),* {}250251 impl<$($gen: ArgLike,)*> sealed::Named for ($((IStr, $gen),)*) {}252 impl<$($gen: ArgLike,)*> ArgsLike for ($((IStr, $gen),)*) {253 fn unnamed_len(&self) -> usize {254 0255 }256 fn unnamed_iter(257 &self,258 _ctx: Context,259 _tailstrict: bool,260 _handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,261 ) -> Result<()> {262 Ok(())263 }264 #[allow(non_snake_case)]265 fn named_iter(266 &self,267 ctx: Context,268 tailstrict: bool,269 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,270 ) -> Result<()> {271 let ($($gen,)*) = self;272 $(273 handler(&$gen.0, $gen.1.evaluate_arg(ctx.clone(), tailstrict)?)?;274 )*275 Ok(())276 }277 #[allow(non_snake_case)]278 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {279 let ($($gen,)*) = self;280 $(281 handler(&$gen.0);282 )*283 }284 }285 impl<$($gen: ArgLike,)*> OptionalContext for ($((IStr, $gen),)*) where $($gen: OptionalContext),* {}286 };287 ($count:expr; $($cur:ident)* @ $c:ident $($rest:ident)*) => {288 impl_args_like!($count; $($cur)*);289 impl_args_like!($count + 1usize; $($cur)* $c @ $($rest)*);290 };291 ($count:expr; $($cur:ident)* @) => {292 impl_args_like!($count; $($cur)*);293 }294}295impl_args_like! {296 297 1usize; A @ B C D E F G H I J K L298}299300impl ArgsLike for () {301 fn unnamed_len(&self) -> usize {302 0303 }304305 fn unnamed_iter(306 &self,307 _ctx: Context,308 _tailstrict: bool,309 _handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,310 ) -> Result<()> {311 Ok(())312 }313314 fn named_iter(315 &self,316 _ctx: Context,317 _tailstrict: bool,318 _handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,319 ) -> Result<()> {320 Ok(())321 }322323 fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}324}325impl OptionalContext for () {}