difftreelog
feat argument map function call
in: master
2 files changed
crates/jrsonnet-evaluator/src/function.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/function.rs
+++ b/crates/jrsonnet-evaluator/src/function.rs
@@ -4,7 +4,10 @@
};
use closure::closure;
use jrsonnet_parser::{ArgsDesc, ParamsDesc};
-use std::collections::HashMap;
+use std::{collections::HashMap, rc::Rc};
+
+const NO_DEFAULT_CONTEXT: &str =
+ "no default context set for call with defined default parameter value";
/// Creates correct [context](Context) for function body evaluation, returning error on invalid call
///
@@ -45,12 +48,7 @@
let (ctx, expr) = if let Some(arg) = &positioned_args[id] {
(ctx.clone(), arg)
} else if let Some(default) = &p.1 {
- (
- body_ctx
- .clone()
- .expect("no default context set for call with defined default parameter value"),
- default,
- )
+ (body_ctx.clone().expect(NO_DEFAULT_CONTEXT), default)
} else {
create_error_result(Error::FunctionParameterNotBoundInCall(p.0.clone()))?;
unreachable!()
@@ -66,6 +64,55 @@
Ok(body_ctx.unwrap_or(ctx).extend(out, None, None, None)?)
}
+pub fn parse_function_call_map(
+ ctx: Context,
+ body_ctx: Option<Context>,
+ params: &ParamsDesc,
+ args: &HashMap<Rc<str>, Val>,
+ tailstrict: bool,
+) -> Result<Context> {
+ let mut out = HashMap::new();
+ let mut positioned_args = vec![None; params.0.len()];
+ for (name, val) in args.iter() {
+ let idx = params.iter().position(|p| *p.0 == **name).ok_or_else(|| {
+ create_error(Error::UnknownFunctionParameter((&name as &str).to_owned()))
+ })?;
+
+ if idx >= params.len() {
+ create_error_result(Error::TooManyArgsFunctionHas(params.len()))?;
+ }
+ if positioned_args[idx].is_some() {
+ create_error_result(Error::BindingParameterASecondTime(params[idx].0.clone()))?;
+ }
+ positioned_args[idx] = Some(val.clone());
+ }
+ // Fill defaults
+ for (id, p) in params.iter().enumerate() {
+ let val = if let Some(arg) = positioned_args[id].take() {
+ resolved_lazy_val!(arg)
+ } else if let Some(default) = &p.1 {
+ if tailstrict {
+ resolved_lazy_val!(evaluate(
+ body_ctx.clone().expect(NO_DEFAULT_CONTEXT),
+ default
+ )?)
+ } else {
+ let body_ctx = body_ctx.clone();
+ let default = default.clone();
+ lazy_val!(move || {
+ evaluate(body_ctx.clone().expect(NO_DEFAULT_CONTEXT), &default)
+ })
+ }
+ } else {
+ create_error_result(Error::FunctionParameterNotBoundInCall(p.0.clone()))?;
+ unreachable!()
+ };
+ out.insert(p.0.clone(), val);
+ }
+
+ Ok(body_ctx.unwrap_or(ctx).extend(out, None, None, None)?)
+}
+
pub(crate) fn place_args(
ctx: Context,
body_ctx: Option<Context>,
crates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth1use crate::{1use crate::{2 create_error_result, evaluate,2 create_error_result, evaluate,3 function::{parse_function_call, place_args},3 function::{parse_function_call, parse_function_call_map, place_args},4 with_state, Context, Error, ObjValue, Result,4 with_state, Context, Error, ObjValue, Result,5};5};6use jrsonnet_parser::{el, Arg, ArgsDesc, Expr, LocExpr, ParamsDesc};6use jrsonnet_parser::{el, Arg, ArgsDesc, Expr, LocExpr, ParamsDesc};7use std::{7use std::{8 cell::RefCell,8 cell::RefCell,9 collections::HashMap,9 fmt::{Debug, Display},10 fmt::{Debug, Display},10 rc::Rc,11 rc::Rc,11};12};76 evaluate(ctx, &self.body)77 evaluate(ctx, &self.body)77 }78 }7980 pub fn evaluate_map(81 &self,82 call_ctx: Context,83 args: &HashMap<Rc<str>, Val>,84 tailstrict: bool,85 ) -> Result<Val> {86 let ctx = parse_function_call_map(87 call_ctx,88 Some(self.ctx.clone()),89 &self.params,90 args,91 tailstrict,92 )?;93 evaluate(ctx, &self.body)94 }789579 pub fn evaluate_values(&self, call_ctx: Context, args: &[Val]) -> Result<Val> {96 pub fn evaluate_values(&self, call_ctx: Context, args: &[Val]) -> Result<Val> {80 let ctx = place_args(call_ctx, Some(self.ctx.clone()), &self.params, args)?;97 let ctx = place_args(call_ctx, Some(self.ctx.clone()), &self.params, args)?;