git.delta.rocks / jrsonnet / refs/commits / 1979dbda1bc0

difftreelog

source

crates/jrsonnet-evaluator/src/function/prepared.rs4.3 KiBsourcehistory
1use std::rc::Rc;23use jrsonnet_gcmodule::{Acyclic, Trace};4use jrsonnet_ir::{ExprParams, IStr, function::FunctionSignature};5use rustc_hash::FxHashSet;67use super::{CallLocation, FuncVal};8use crate::{9	Context, ContextBuilder, Pending, Result, Thunk, Val, bail, destructure::destruct,10	error::ErrorKind::*, evaluate_named_param,11};1213#[derive(Debug, Trace, Clone)]14pub struct PreparedFuncVal {15	fun: FuncVal,16	prepared: Rc<PreparedCall>,17}1819impl PreparedFuncVal {20	pub fn new(fun: FuncVal, unnamed: usize, named: &[IStr]) -> Result<Self> {21		let prepared = prepare_call(fun.params(), unnamed, named)?;22		Ok(Self {23			fun,24			prepared: Rc::new(prepared),25		})26	}27	pub fn call(28		&self,29		loc: CallLocation<'_>,30		unnamed: &[Thunk<Val>],31		named: &[Thunk<Val>],32	) -> Result<Val> {33		self.fun34			.evaluate_prepared(&self.prepared, loc, unnamed, named, false)35	}36}3738#[derive(Acyclic, Debug)]39pub struct PreparedCall {40	// Param, named input.41	named: Vec<(usize, usize)>,42	defaults: Vec<usize>,43}4445pub fn prepare_call(46	params: FunctionSignature,47	unnamed: usize,48	named: &[IStr],49) -> Result<PreparedCall> {50	if unnamed > params.len() {51		bail!(TooManyArgsFunctionHas(params.len(), params))52	}5354	let expected_defaults = (params.len() - unnamed).saturating_sub(named.len());55	let mut ops = PreparedCall {56		named: Vec::with_capacity(named.len()),57		defaults: Vec::with_capacity(expected_defaults),58	};5960	// FIXME: bitmask61	let mut passed: FxHashSet<usize> = (0..unnamed).collect();6263	for (input_id, name) in named.iter().enumerate() {64		// FIXME: O(n) for arg existence check65		let Some(param_idx) = params.iter().position(|p| p.name() == name) else {66			bail!(UnknownFunctionParameter(name.clone()));67		};68		if !passed.insert(param_idx) {69			bail!(BindingParameterASecondTime(name.clone()));70		}71		ops.named.push((param_idx, input_id));72	}7374	if named.len() + unnamed < params.len() {75		let mut defaults = 0;7677		for (param_id, param) in params78			.iter()79			.enumerate()80			.skip(unnamed)81			.filter(|p| p.1.has_default())82		{83			// Skip already passed parameters84			if !param.name().is_anonymous() && passed.contains(&param_id) {85				continue;86			}87			defaults += 1;8889			ops.defaults.push(param_id);90		}9192		// Some args still weren't filled93		if defaults != expected_defaults {94			for param in params.iter().skip(unnamed) {95				let mut found = false;96				for name in named {97					if param.name() == name {98						found = true;99					}100				}101				if !found {102					bail!(FunctionParameterNotBoundInCall(103						param.name().clone(),104						params105					));106				}107			}108			unreachable!();109		}110	}111112	Ok(ops)113}114pub fn parse_prepared_function_call(115	body_ctx: Context,116	prepared: &PreparedCall,117	params: &ExprParams,118	unnamed: &[Thunk<Val>],119	named: &[Thunk<Val>],120) -> Result<Context> {121	let mut ctx = ContextBuilder::extend(body_ctx);122123	let destruct_ctx = Pending::new();124125	for (param_idx, unnamed) in unnamed.iter().enumerate() {126		destruct(127			&params.exprs[param_idx].destruct,128			unnamed.clone(),129			destruct_ctx.clone(),130			&mut ctx,131		)?;132	}133134	for (param_idx, arg_idx) in prepared.named.iter().copied() {135		destruct(136			&params.exprs[param_idx].destruct,137			named[arg_idx].clone(),138			destruct_ctx.clone(),139			&mut ctx,140		)?;141	}142143	if prepared.defaults.is_empty() {144		let body_ctx = ctx.build().into_future(destruct_ctx);145		Ok(body_ctx)146	} else {147		let fctx = Context::new_future();148		let mut ctx = ctx.commit();149		for param_idx in prepared.defaults.iter().copied() {150			// let param = params.0.rc_idx(param_idx);151			destruct(152				&params.exprs[param_idx].destruct,153				{154					let ctx = fctx.clone();155					let params = params.clone();156					Thunk!(move || {157						let param = &params.exprs[param_idx];158						let name = param.destruct.name();159						let value = param.default.as_ref().expect("default exists");160						evaluate_named_param(ctx.unwrap(), value, name)161					})162				},163				fctx.clone(),164				&mut ctx,165			)?;166		}167168		Ok(ctx.build().into_future(fctx).into_future(destruct_ctx))169	}170}171pub fn parse_prepared_builtin_call(172	prepared: &PreparedCall,173	params: FunctionSignature,174	unnamed: &[Thunk<Val>],175	named: &[Thunk<Val>],176) -> Vec<Option<Thunk<Val>>> {177	let mut passed_args = vec![None; params.len()];178179	for (param_idx, unnamed) in unnamed.iter().enumerate() {180		passed_args[param_idx] = Some(unnamed.clone());181	}182183	for (param_idx, arg_idx) in prepared.named.iter().copied() {184		passed_args[param_idx] = Some(named[arg_idx].clone());185	}186187	passed_args188}