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

difftreelog

feat FuncDesc helper for default context

Yaroslav Bolyukin2022-04-17parent: #efea837.patch.diff
in: master

2 files changed

modifiedcrates/jrsonnet-evaluator/src/function.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/function.rs
+++ b/crates/jrsonnet-evaluator/src/function.rs
@@ -23,6 +23,18 @@
 	}
 }
 
+#[derive(Trace)]
+struct EvaluateNamedLazyVal {
+	future_context: FutureWrapper<Context>,
+	name: IStr,
+	value: LocExpr,
+}
+impl LazyValValue for EvaluateNamedLazyVal {
+	fn get(self: Box<Self>) -> Result<Val> {
+		evaluate_named(self.future_context.unwrap(), &self.value, self.name)
+	}
+}
+
 pub trait ArgLike {
 	fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<LazyVal>;
 }
@@ -309,25 +321,14 @@
 	if filled_args < params.len() {
 		// Some args are unset, but maybe we have defaults for them
 		// Default values should be created in newly created context
-		let future_context = FutureWrapper::<Context>::new();
+		let future_context = Context::new_future();
 		let mut defaults = GcHashMap::with_capacity(params.len() - filled_args);
 
 		for param in params.iter().filter(|p| p.1.is_some()) {
 			if passed_args.contains_key(&param.0.clone()) {
 				continue;
 			}
-			#[derive(Trace)]
-			struct LazyNamedBinding {
-				future_context: FutureWrapper<Context>,
-				name: IStr,
-				value: LocExpr,
-			}
-			impl LazyValValue for LazyNamedBinding {
-				fn get(self: Box<Self>) -> Result<Val> {
-					evaluate_named(self.future_context.unwrap(), &self.value, self.name)
-				}
-			}
-			LazyVal::new(TraceBox(Box::new(LazyNamedBinding {
+			LazyVal::new(TraceBox(Box::new(EvaluateNamedLazyVal {
 				future_context: future_context.clone(),
 				name: param.0.clone(),
 				value: param.1.clone().unwrap(),
@@ -335,7 +336,7 @@
 
 			defaults.insert(
 				param.0.clone(),
-				LazyVal::new(TraceBox(Box::new(LazyNamedBinding {
+				LazyVal::new(TraceBox(Box::new(EvaluateNamedLazyVal {
 					future_context: future_context.clone(),
 					name: param.0.clone(),
 					value: param.1.clone().unwrap(),
@@ -464,3 +465,39 @@
 	}
 	Ok(passed_args)
 }
+
+/// Creates Context, which has all argument default values applied
+/// and with unbound values causing error to be returned
+pub fn parse_default_function_call(body_ctx: Context, params: &ParamsDesc) -> Context {
+	let ctx = Context::new_future();
+
+	let mut bindings = GcHashMap::new();
+
+	#[derive(Trace)]
+	struct DependsOnUnbound(IStr);
+	impl LazyValValue for DependsOnUnbound {
+		fn get(self: Box<Self>) -> Result<Val> {
+			Err(FunctionParameterNotBoundInCall(self.0.clone()).into())
+		}
+	}
+
+	for param in params.iter() {
+		if let Some(v) = &param.1 {
+			bindings.insert(
+				param.0.clone(),
+				LazyVal::new(TraceBox(Box::new(EvaluateNamedLazyVal {
+					future_context: ctx.clone(),
+					name: param.0.clone(),
+					value: v.clone(),
+				}))),
+			);
+		} else {
+			bindings.insert(
+				param.0.clone(),
+				LazyVal::new(TraceBox(Box::new(DependsOnUnbound(param.0.clone())))),
+			);
+		}
+	}
+
+	body_ctx.extend(bindings, None, None, None).into_future(ctx)
+}
modifiedcrates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth
6 error::{Error::*, LocError},6 error::{Error::*, LocError},
7 evaluate,7 evaluate,
8 function::{parse_function_call, ArgsLike, Builtin, StaticBuiltin},8 function::{
9 parse_default_function_call, parse_function_call, ArgsLike, Builtin, StaticBuiltin,
10 },
9 gc::TraceBox,11 gc::TraceBox,
10 throw, Context, ObjValue, Result,12 throw, Context, ObjValue, Result,
84 pub params: ParamsDesc,86 pub params: ParamsDesc,
85 pub body: LocExpr,87 pub body: LocExpr,
86}88}
89impl FuncDesc {
90 /// Create body context, but fill arguments without defaults with lazy error
91 pub fn default_body_context(&self) -> Context {
92 parse_default_function_call(self.ctx.clone(), &self.params)
93 }
94
95 /// Create context, with which body code will run
96 pub fn call_body_context(
97 &self,
98 call_ctx: Context,
99 args: &dyn ArgsLike,
100 tailstrict: bool,
101 ) -> Result<Context> {
102 parse_function_call(call_ctx, self.ctx.clone(), &self.params, args, tailstrict)
103 }
104}
87105
88#[derive(Trace, Clone)]106#[derive(Trace, Clone)]
89pub enum FuncVal {107pub enum FuncVal {
140 ) -> Result<Val> {158 ) -> Result<Val> {
141 match self {159 match self {
142 Self::Normal(func) => {160 Self::Normal(func) => {
143 let ctx = parse_function_call(161 let body_ctx = func.call_body_context(call_ctx, args, tailstrict)?;
144 call_ctx,
145 func.ctx.clone(),
146 &func.params,
147 args,
148 tailstrict,
149 )?;
150 evaluate(ctx, &func.body)162 evaluate(body_ctx, &func.body)
151 }163 }
152 Self::StaticBuiltin(name) => name.call(call_ctx, loc, args),164 Self::StaticBuiltin(b) => b.call(call_ctx, loc, args),
153 Self::Builtin(b) => b.call(call_ctx, loc, args),165 Self::Builtin(b) => b.call(call_ctx, loc, args),
154 }166 }
155 }167 }