From c7fb88801c20f00b5114f38231a5b76df0429e7c Mon Sep 17 00:00:00 2001 From: Yaroslav Bolyukin Date: Sun, 17 Apr 2022 18:42:07 +0000 Subject: [PATCH] feat: FuncDesc helper for default context --- --- 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, + name: IStr, + value: LocExpr, +} +impl LazyValValue for EvaluateNamedLazyVal { + fn get(self: Box) -> Result { + evaluate_named(self.future_context.unwrap(), &self.value, self.name) + } +} + pub trait ArgLike { fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result; } @@ -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::::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(¶m.0.clone()) { continue; } - #[derive(Trace)] - struct LazyNamedBinding { - future_context: FutureWrapper, - name: IStr, - value: LocExpr, - } - impl LazyValValue for LazyNamedBinding { - fn get(self: Box) -> Result { - 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) -> Result { + Err(FunctionParameterNotBoundInCall(self.0.clone()).into()) + } + } + + for param in params.iter() { + if let Some(v) = ¶m.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) +} --- a/crates/jrsonnet-evaluator/src/val.rs +++ b/crates/jrsonnet-evaluator/src/val.rs @@ -5,7 +5,9 @@ cc_ptr_eq, error::{Error::*, LocError}, evaluate, - function::{parse_function_call, ArgsLike, Builtin, StaticBuiltin}, + function::{ + parse_default_function_call, parse_function_call, ArgsLike, Builtin, StaticBuiltin, + }, gc::TraceBox, throw, Context, ObjValue, Result, }; @@ -84,6 +86,22 @@ pub params: ParamsDesc, pub body: LocExpr, } +impl FuncDesc { + /// Create body context, but fill arguments without defaults with lazy error + pub fn default_body_context(&self) -> Context { + parse_default_function_call(self.ctx.clone(), &self.params) + } + + /// Create context, with which body code will run + pub fn call_body_context( + &self, + call_ctx: Context, + args: &dyn ArgsLike, + tailstrict: bool, + ) -> Result { + parse_function_call(call_ctx, self.ctx.clone(), &self.params, args, tailstrict) + } +} #[derive(Trace, Clone)] pub enum FuncVal { @@ -140,16 +158,10 @@ ) -> Result { match self { Self::Normal(func) => { - let ctx = parse_function_call( - call_ctx, - func.ctx.clone(), - &func.params, - args, - tailstrict, - )?; - evaluate(ctx, &func.body) + let body_ctx = func.call_body_context(call_ctx, args, tailstrict)?; + evaluate(body_ctx, &func.body) } - Self::StaticBuiltin(name) => name.call(call_ctx, loc, args), + Self::StaticBuiltin(b) => b.call(call_ctx, loc, args), Self::Builtin(b) => b.call(call_ctx, loc, args), } } -- gitstuff