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

difftreelog

source

crates/jrsonnet-evaluator/src/function/prepared.rs4.0 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::{bail, error::ErrorKind::*, Result};8use crate::{evaluate_named_param, Context, ContextBuilder, Pending, Thunk, Val};910pub struct PreparedCall {11	// Param, named input.12	named: Vec<(usize, usize)>,13	defaults: Vec<usize>,14}1516pub fn prepare_call(17	params: FunctionSignature,18	unnamed: usize,19	named: &[IStr],20) -> Result<PreparedCall> {21	if unnamed > params.len() {22		bail!(TooManyArgsFunctionHas(params.len(), params))23	}2425	let expected_defaults = params.len() - unnamed - named.len();26	let mut ops = PreparedCall {27		named: Vec::with_capacity(named.len()),28		defaults: Vec::with_capacity(expected_defaults),29	};3031	// FIXME: bitmask32	let mut passed: FxHashSet<usize> = (0..unnamed).collect();3334	for (input_id, name) in named.iter().enumerate() {35		// FIXME: O(n) for arg existence check36		let Some(param_idx) = params.iter().position(|p| p.name() == name) else {37			bail!(UnknownFunctionParameter(name.clone()));38		};39		if !passed.insert(param_idx) {40			bail!(BindingParameterASecondTime(name.clone()));41		}42		ops.named.push((param_idx, input_id));43	}4445	if named.len() + unnamed < params.len() {46		let mut defaults = 0;4748		for (param_id, param) in params49			.iter()50			.enumerate()51			.skip(unnamed)52			.filter(|p| p.1.has_default())53		{54			// Skip already passed parameters55			if !param.name().is_anonymous() && passed.contains(&param_id) {56				continue;57			}58			defaults += 1;5960			ops.defaults.push(param_id);61		}6263		// Some args still weren't filled64		if defaults != expected_defaults {65			for param in params.iter().skip(unnamed) {66				let mut found = false;67				for name in named {68					if param.name() == name {69						found = true;70					}71				}72				if !found {73					bail!(FunctionParameterNotBoundInCall(74						param.name().clone(),75						params76					));77				}78			}79			unreachable!();80		}81	}8283	Ok(ops)84}85pub fn parse_prepared_function_call(86	body_ctx: Context,87	prepared: &PreparedCall,88	params: &ExprParams,89	unnamed: &[Thunk<Val>],90	named: &[Thunk<Val>],91) -> Result<Context> {92	let mut passed_args = FxHashMap::with_capacity(params.binds_len());9394	let destruct_ctx = Pending::new();9596	for (param_idx, unnamed) in unnamed.iter().enumerate() {97		destruct(98			&params.exprs[param_idx].destruct,99			unnamed.clone(),100			destruct_ctx.clone(),101			&mut passed_args,102		)?;103	}104105	for (param_idx, arg_idx) in prepared.named.iter().copied() {106		destruct(107			&params.exprs[param_idx].destruct,108			named[arg_idx].clone(),109			destruct_ctx.clone(),110			&mut passed_args,111		)?;112	}113114	if prepared.defaults.is_empty() {115		let body_ctx = body_ctx116			.extend_bindings(passed_args)117			.into_future(destruct_ctx);118		Ok(body_ctx)119	} else {120		let fctx = Context::new_future();121		let mut defaults = FxHashMap::with_capacity(params.binds_len() - passed_args.len());122		for param_idx in prepared.defaults.iter().copied() {123			// let param = params.0.rc_idx(param_idx);124			destruct(125				&params.exprs[param_idx].destruct,126				{127					let ctx = fctx.clone();128					let params = params.clone();129					Thunk!(move || {130						let param = &params.exprs[param_idx];131						let name = param.destruct.name();132						let value = param.default.as_ref().expect("default exists");133						evaluate_named_param(ctx.unwrap(), value, name)134					})135				},136				fctx.clone(),137				&mut defaults,138			)?;139		}140141		let mut ctx = ContextBuilder::extend(body_ctx);142		ctx.binds(passed_args);143		ctx.binds(defaults);144		Ok(ctx.build().into_future(fctx).into_future(destruct_ctx))145	}146}147pub fn parse_prepared_builtin_call(148	prepared: &PreparedCall,149	params: FunctionSignature,150	unnamed: &[Thunk<Val>],151	named: &[Thunk<Val>],152) -> Result<Vec<Option<Thunk<Val>>>> {153	let mut passed_args = vec![None; params.len()];154155	for (param_idx, unnamed) in unnamed.iter().enumerate() {156		passed_args[param_idx] = Some(unnamed.clone());157	}158159	for (param_idx, arg_idx) in prepared.named.iter().copied() {160		passed_args[param_idx] = Some(named[arg_idx].clone());161	}162163	Ok(passed_args)164}