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

difftreelog

source

crates/jrsonnet-evaluator/src/function/prepared.rs4.7 KiBsourcehistory
1use std::rc::Rc;23use jrsonnet_gcmodule::{Acyclic, Trace};4use jrsonnet_parser::function::FunctionSignature;5use jrsonnet_parser::{ExprParams, IStr};6use rustc_hash::{FxHashMap, FxHashSet};78use crate::destructure::destruct;9use crate::gc::WithCapacityExt;10use crate::{bail, error::ErrorKind::*, Result};11use crate::{evaluate_named_param, Context, ContextBuilder, Pending, Thunk, Val};1213use super::{CallLocation, FuncVal};1415#[derive(Debug, Trace, Clone)]16pub struct PreparedFuncVal {17	fun: FuncVal,18	prepared: Rc<PreparedCall>,19}2021impl PreparedFuncVal {22	pub fn new(fun: FuncVal, unnamed: usize, named: &[IStr]) -> Result<Self> {23		let prepared = prepare_call(fun.params(), unnamed, named)?;24		Ok(Self {25			fun,26			prepared: Rc::new(prepared),27		})28	}29	pub fn call(30		&self,31		loc: CallLocation<'_>,32		unnamed: &[Thunk<Val>],33		named: &[Thunk<Val>],34	) -> Result<Val> {35		self.fun36			.evaluate_prepared(&self.prepared, loc, unnamed, named, false)37	}38}3940#[derive(Acyclic, Debug)]41pub struct PreparedCall {42	// Param, named input.43	named: Vec<(usize, usize)>,44	defaults: Vec<usize>,45}4647pub fn prepare_call(48	params: FunctionSignature,49	unnamed: usize,50	named: &[IStr],51) -> Result<PreparedCall> {52	if unnamed > params.len() {53		bail!(TooManyArgsFunctionHas(params.len(), params))54	}5556	let expected_defaults = params.len() - unnamed - named.len();57	let mut ops = PreparedCall {58		named: Vec::with_capacity(named.len()),59		defaults: Vec::with_capacity(expected_defaults),60	};6162	// FIXME: bitmask63	let mut passed: FxHashSet<usize> = (0..unnamed).collect();6465	for (input_id, name) in named.iter().enumerate() {66		// FIXME: O(n) for arg existence check67		let Some(param_idx) = params.iter().position(|p| p.name() == name) else {68			bail!(UnknownFunctionParameter(name.clone()));69		};70		if !passed.insert(param_idx) {71			bail!(BindingParameterASecondTime(name.clone()));72		}73		ops.named.push((param_idx, input_id));74	}7576	if named.len() + unnamed < params.len() {77		let mut defaults = 0;7879		for (param_id, param) in params80			.iter()81			.enumerate()82			.skip(unnamed)83			.filter(|p| p.1.has_default())84		{85			// Skip already passed parameters86			if !param.name().is_anonymous() && passed.contains(&param_id) {87				continue;88			}89			defaults += 1;9091			ops.defaults.push(param_id);92		}9394		// Some args still weren't filled95		if defaults != expected_defaults {96			for param in params.iter().skip(unnamed) {97				let mut found = false;98				for name in named {99					if param.name() == name {100						found = true;101					}102				}103				if !found {104					bail!(FunctionParameterNotBoundInCall(105						param.name().clone(),106						params107					));108				}109			}110			unreachable!();111		}112	}113114	Ok(ops)115}116pub fn parse_prepared_function_call(117	body_ctx: Context,118	prepared: &PreparedCall,119	params: &ExprParams,120	unnamed: &[Thunk<Val>],121	named: &[Thunk<Val>],122) -> Result<Context> {123	let mut passed_args = FxHashMap::with_capacity(params.binds_len());124125	let destruct_ctx = Pending::new();126127	for (param_idx, unnamed) in unnamed.iter().enumerate() {128		destruct(129			&params.exprs[param_idx].destruct,130			unnamed.clone(),131			destruct_ctx.clone(),132			&mut passed_args,133		)?;134	}135136	for (param_idx, arg_idx) in prepared.named.iter().copied() {137		destruct(138			&params.exprs[param_idx].destruct,139			named[arg_idx].clone(),140			destruct_ctx.clone(),141			&mut passed_args,142		)?;143	}144145	if prepared.defaults.is_empty() {146		let body_ctx = body_ctx147			.extend_bindings(passed_args)148			.into_future(destruct_ctx);149		Ok(body_ctx)150	} else {151		let fctx = Context::new_future();152		let mut defaults = FxHashMap::with_capacity(params.binds_len() - passed_args.len());153		for param_idx in prepared.defaults.iter().copied() {154			// let param = params.0.rc_idx(param_idx);155			destruct(156				&params.exprs[param_idx].destruct,157				{158					let ctx = fctx.clone();159					let params = params.clone();160					Thunk!(move || {161						let param = &params.exprs[param_idx];162						let name = param.destruct.name();163						let value = param.default.as_ref().expect("default exists");164						evaluate_named_param(ctx.unwrap(), value, name)165					})166				},167				fctx.clone(),168				&mut defaults,169			)?;170		}171172		let mut ctx = ContextBuilder::extend(body_ctx);173		ctx.binds(passed_args);174		ctx.binds(defaults);175		Ok(ctx.build().into_future(fctx).into_future(destruct_ctx))176	}177}178pub fn parse_prepared_builtin_call(179	prepared: &PreparedCall,180	params: FunctionSignature,181	unnamed: &[Thunk<Val>],182	named: &[Thunk<Val>],183) -> Result<Vec<Option<Thunk<Val>>>> {184	let mut passed_args = vec![None; params.len()];185186	for (param_idx, unnamed) in unnamed.iter().enumerate() {187		passed_args[param_idx] = Some(unnamed.clone());188	}189190	for (param_idx, arg_idx) in prepared.named.iter().copied() {191		passed_args[param_idx] = Some(named[arg_idx].clone());192	}193194	Ok(passed_args)195}