1use std::{collections::HashMap, hash::BuildHasher};23use jrsonnet_gcmodule::Trace;4use jrsonnet_interner::IStr;5use jrsonnet_ir::{SourceFifo, SourcePath};67use crate::{8 Result, Thunk, Val, ensure_sufficient_stack,9 function::{CallLocation, PreparedFuncVal},10 in_description_frame, with_state,11};1213#[derive(Clone, Trace)]14pub enum TlaArg {15 String(IStr),16 Val(Val),17 Lazy(Thunk<Val>),18 Import(String),19 ImportStr(String),20 InlineCode(String),21}22impl TlaArg {23 pub fn evaluate_tailstrict(&self) -> Result<Val> {24 ensure_sufficient_stack(|| match self {25 Self::String(s) => Ok(Val::string(s.clone())),26 Self::Val(val) => Ok(val.clone()),27 Self::Lazy(lazy) => Ok(lazy.evaluate()?),28 Self::Import(p) => with_state(|s| {29 let resolved = s.resolve_from_default(&p.as_str())?;30 s.import_resolved(resolved)31 }),32 Self::ImportStr(p) => with_state(|s| {33 let resolved = s.resolve_from_default(&p.as_str())?;34 s.import_resolved_str(resolved).map(Val::string)35 }),36 Self::InlineCode(p) => with_state(|s| {37 let resolved =38 SourcePath::new(SourceFifo("<inline code>".to_owned(), p.as_bytes().into()));39 s.import_resolved(resolved)40 }),41 })42 }43 pub fn evaluate(&self) -> Result<Thunk<Val>> {44 match self {45 Self::String(s) => Ok(Thunk::evaluated(Val::string(s.clone()))),46 Self::Val(val) => Ok(Thunk::evaluated(val.clone())),47 Self::Lazy(lazy) => Ok(lazy.clone()),48 Self::Import(p) => with_state(|s| {49 let resolved = s.resolve_from_default(&p.as_str())?;50 Ok(Thunk!(move || s.import_resolved(resolved)))51 }),52 Self::ImportStr(p) => with_state(|s| {53 let resolved = s.resolve_from_default(&p.as_str())?;54 Ok(Thunk!(move || s55 .import_resolved_str(resolved)56 .map(Val::string)))57 }),58 Self::InlineCode(p) => with_state(|s| {59 let resolved =60 SourcePath::new(SourceFifo("<inline code>".to_owned(), p.as_bytes().into()));61 Ok(Thunk!(move || s.import_resolved(resolved)))62 }),63 }64 }65}6667pub fn apply_tla<H: BuildHasher>(args: &HashMap<IStr, TlaArg, H>, val: Val) -> Result<Val> {68 Ok(if let Val::Func(func) = val {69 in_description_frame(70 || "during TLA call".to_owned(),71 || {72 let mut names = Vec::with_capacity(args.len());73 let mut values = Vec::with_capacity(args.len());74 for (name, value) in args {75 names.push(name.clone());76 values.push(value.evaluate()?);77 }78 let prepared = PreparedFuncVal::new(func, 0, &names)?;79 prepared.call(CallLocation::native(), &[], &values)80 },81 )?82 } else {83 val84 })85}