git.delta.rocks / jrsonnet / refs/commits / b915f23c48a1

difftreelog

source

crates/jrsonnet-evaluator/src/function/prepared.rs4.1 KiBsourcehistory
1use jrsonnet_parser::function::FunctionSignature;2use jrsonnet_parser::{ExprParams, IStr};3use rustc_hash::{FxHashMap, FxHashSet};45use crate::destructure::destruct;6use crate::gc::WithCapacityExt;7use crate::val::ThunkValue as _;8use crate::{bail, error::ErrorKind::*, Result};9use crate::{evaluate_named, evaluate_named_param, Context, ContextBuilder, Pending, Thunk, Val};1011pub struct PreparedCall {12	// Param, named input.13	named: Vec<(usize, usize)>,14	defaults: Vec<usize>,15}1617pub fn prepare_call(18	params: FunctionSignature,19	unnamed: usize,20	named: &[IStr],21) -> Result<PreparedCall> {22	if unnamed > params.len() {23		bail!(TooManyArgsFunctionHas(params.len(), params))24	}2526	let expected_defaults = params.len() - unnamed - named.len();27	let mut ops = PreparedCall {28		named: Vec::with_capacity(named.len()),29		defaults: Vec::with_capacity(expected_defaults),30	};3132	// FIXME: bitmask33	let mut passed: FxHashSet<usize> = (0..unnamed).collect();3435	for (input_id, name) in named.iter().enumerate() {36		// FIXME: O(n) for arg existence check37		let Some(param_idx) = params.iter().position(|p| p.name() == name) else {38			bail!(UnknownFunctionParameter(name.clone()));39		};40		if !passed.insert(param_idx) {41			bail!(BindingParameterASecondTime(name.clone()));42		}43		ops.named.push((param_idx, input_id));44	}4546	if named.len() + unnamed < params.len() {47		let mut defaults = 0;4849		for (param_id, param) in params50			.iter()51			.enumerate()52			.skip(unnamed)53			.filter(|p| p.1.has_default())54		{55			// Skip already passed parameters56			if !param.name().is_anonymous() && passed.contains(&param_id) {57				continue;58			}59			defaults += 1;6061			ops.defaults.push(param_id);62		}6364		// Some args still weren't filled65		if defaults != expected_defaults {66			for param in params.iter().skip(unnamed) {67				let mut found = false;68				for name in named {69					if param.name() == name {70						found = true;71					}72				}73				if !found {74					bail!(FunctionParameterNotBoundInCall(75						param.name().clone(),76						params77					));78				}79			}80			unreachable!();81		}82	}8384	Ok(ops)85}86pub fn parse_prepared_function_call(87	body_ctx: Context,88	prepared: &PreparedCall,89	params: &ExprParams,90	unnamed: &[Thunk<Val>],91	named: &[Thunk<Val>],92) -> Result<Context> {93	let mut passed_args = FxHashMap::with_capacity(params.binds_len());9495	let destruct_ctx = Pending::new();9697	for (param_idx, unnamed) in unnamed.iter().enumerate() {98		destruct(99			&params.exprs[param_idx].destruct,100			unnamed.clone(),101			destruct_ctx.clone(),102			&mut passed_args,103		)?;104	}105106	for (param_idx, arg_idx) in prepared.named.iter().copied() {107		destruct(108			&params.exprs[param_idx].destruct,109			named[arg_idx].clone(),110			destruct_ctx.clone(),111			&mut passed_args,112		)?;113	}114115	if prepared.defaults.is_empty() {116		let body_ctx = body_ctx117			.extend_bindings(passed_args)118			.into_future(destruct_ctx);119		Ok(body_ctx)120	} else {121		let fctx = Context::new_future();122		let mut defaults = FxHashMap::with_capacity(params.binds_len() - passed_args.len());123		for param_idx in prepared.defaults.iter().copied() {124			// let param = params.0.rc_idx(param_idx);125			destruct(126				&params.exprs[param_idx].destruct,127				{128					let ctx = fctx.clone();129					let params = params.clone();130					Thunk!(move || {131						let param = &params.exprs[param_idx];132						let name = param.destruct.name();133						let value = param.default.as_ref().expect("default exists");134						evaluate_named_param(ctx.unwrap(), value, name)135					})136				},137				fctx.clone(),138				&mut defaults,139			)?;140		}141142		let mut ctx = ContextBuilder::extend(body_ctx);143		ctx.binds(passed_args);144		ctx.binds(defaults);145		Ok(ctx.build().into_future(fctx).into_future(destruct_ctx))146	}147}148pub fn parse_prepared_builtin_call(149	prepared: &PreparedCall,150	params: FunctionSignature,151	unnamed: &[Thunk<Val>],152	named: &[Thunk<Val>],153) -> Result<Vec<Option<Thunk<Val>>>> {154	let mut passed_args = vec![None; params.len()];155156	for (param_idx, unnamed) in unnamed.iter().enumerate() {157		passed_args[param_idx] = Some(unnamed.clone());158	}159160	for (param_idx, arg_idx) in prepared.named.iter().copied() {161		passed_args[param_idx] = Some(named[arg_idx].clone());162	}163164	Ok(passed_args)165}