difftreelog
feat destruct function arguments
in: master
5 files changed
crates/jrsonnet-evaluator/src/evaluate/destructure.rsdiffbeforeafterboth12};12};131314#[allow(clippy::too_many_lines)]14#[allow(clippy::too_many_lines)]15fn destruct(15pub fn destruct(16 d: &Destruct,16 d: &Destruct,17 parent: Thunk<Val>,17 parent: Thunk<Val>,18 new_bindings: &mut GcHashMap<IStr, Thunk<Val>>,18 new_bindings: &mut GcHashMap<IStr, Thunk<Val>>,crates/jrsonnet-evaluator/src/function/mod.rsdiffbeforeafterboth59}59}60impl FuncDesc {60impl FuncDesc {61 /// Create body context, but fill arguments without defaults with lazy error61 /// Create body context, but fill arguments without defaults with lazy error62 pub fn default_body_context(&self) -> Context {62 pub fn default_body_context(&self) -> Result<Context> {63 parse_default_function_call(self.ctx.clone(), &self.params)63 parse_default_function_call(self.ctx.clone(), &self.params)64 }64 }6565crates/jrsonnet-evaluator/src/function/parse.rsdiffbeforeafterboth7 builtin::{BuiltinParam, BuiltinParamName},7 builtin::{BuiltinParam, BuiltinParamName},8};8};9use crate::{9use crate::{10 destructure::destruct,10 error::{Error::*, Result},11 error::{Error::*, Result},11 evaluate_named,12 evaluate_named,12 gc::GcHashMap,13 gc::GcHashMap,50 throw!(TooManyArgsFunctionHas(params.len()))51 throw!(TooManyArgsFunctionHas(params.len()))51 }52 }525353 let mut filled_args = 0;54 let mut filled_named = 0;55 let mut filled_positionals = 0;545655 args.unnamed_iter(s.clone(), ctx.clone(), tailstrict, &mut |id, arg| {57 args.unnamed_iter(s.clone(), ctx.clone(), tailstrict, &mut |id, arg| {56 let name = params[id].0.clone();58 let name = params[id].0.clone();57 passed_args.insert(name, arg);59 destruct(&name, arg, &mut passed_args)?;58 filled_args += 1;60 filled_positionals += 1;59 Ok(())61 Ok(())60 })?;62 })?;616362 args.named_iter(s, ctx, tailstrict, &mut |name, value| {64 args.named_iter(s, ctx, tailstrict, &mut |name, value| {63 // FIXME: O(n) for arg existence check65 // FIXME: O(n) for arg existence check64 if !params.iter().any(|p| &p.0 == name) {66 if !params.iter().any(|p| p.0.name().as_ref() == Some(name)) {65 throw!(UnknownFunctionParameter((name as &str).to_owned()));67 throw!(UnknownFunctionParameter((name as &str).to_owned()));66 }68 }67 if passed_args.insert(name.clone(), value).is_some() {69 if passed_args.insert(name.clone(), value).is_some() {68 throw!(BindingParameterASecondTime(name.clone()));70 throw!(BindingParameterASecondTime(name.clone()));69 }71 }70 filled_args += 1;72 filled_named += 1;71 Ok(())73 Ok(())72 })?;74 })?;737574 if filled_args < params.len() {76 if filled_named + filled_positionals < params.len() {75 // Some args are unset, but maybe we have defaults for them77 // Some args are unset, but maybe we have defaults for them76 // Default values should be created in newly created context78 // Default values should be created in newly created context77 let fctx = Context::new_future();79 let fctx = Context::new_future();78 let mut defaults = GcHashMap::with_capacity(params.len() - filled_args);80 let mut defaults =81 GcHashMap::with_capacity(params.len() - filled_named - filled_positionals);798280 for param in params.iter().filter(|p| p.1.is_some()) {83 for (idx, param) in params.iter().enumerate().filter(|p| p.1 .1.is_some()) {81 if passed_args.contains_key(¶m.0.clone()) {84 if let Some(name) = param.0.name() {85 if passed_args.contains_key(&name) {82 continue;86 continue;83 }87 }88 } else if idx < filled_positionals {89 continue;90 }849185 defaults.insert(92 destruct(86 param.0.clone(),93 ¶m.0,87 Thunk::new(tb!(EvaluateNamedThunk {94 Thunk::new(tb!(EvaluateNamedThunk {88 ctx: fctx.clone(),95 ctx: fctx.clone(),89 name: param.0.clone(),96 name: param.0.name().unwrap_or_else(|| "<destruct>".into()),90 value: param.1.clone().expect("default exists"),97 value: param.1.clone().expect("default exists"),91 })),98 })),99 &mut defaults,92 );100 )?;101 if param.0.name().is_some() {93 filled_args += 1;102 filled_named += 1;103 } else {104 filled_positionals += 1;105 }94 }106 }9510796 // Some args still wasn't filled108 // Some args still weren't filled97 if filled_args != params.len() {109 if filled_named + filled_positionals != params.len() {98 for param in params.iter().skip(args.unnamed_len()) {110 for param in params.iter().skip(args.unnamed_len()) {99 let mut found = false;111 let mut found = false;100 args.named_names(&mut |name| {112 args.named_names(&mut |name| {101 if name == ¶m.0 {113 if Some(name) == param.0.name().as_ref() {102 found = true;114 found = true;103 }115 }104 });116 });105 if !found {117 if !found {106 throw!(FunctionParameterNotBoundInCall(param.0.clone()));118 throw!(FunctionParameterNotBoundInCall(119 param120 .0121 .clone()122 .name()123 .unwrap_or_else(|| "<destruct>".into())124 ));107 }125 }108 }126 }189207190/// Creates Context, which has all argument default values applied208/// Creates Context, which has all argument default values applied191/// and with unbound values causing error to be returned209/// and with unbound values causing error to be returned192pub fn parse_default_function_call(body_ctx: Context, params: &ParamsDesc) -> Context {210pub fn parse_default_function_call(body_ctx: Context, params: &ParamsDesc) -> Result<Context> {193 #[derive(Trace)]211 #[derive(Trace)]194 struct DependsOnUnbound(IStr);212 struct DependsOnUnbound(IStr);195 impl ThunkValue for DependsOnUnbound {213 impl ThunkValue for DependsOnUnbound {205223206 for param in params.iter() {224 for param in params.iter() {207 if let Some(v) = ¶m.1 {225 if let Some(v) = ¶m.1 {208 bindings.insert(226 destruct(209 param.0.clone(),227 ¶m.0.clone(),210 Thunk::new(tb!(EvaluateNamedThunk {228 Thunk::new(tb!(EvaluateNamedThunk {211 ctx: fctx.clone(),229 ctx: fctx.clone(),212 name: param.0.clone(),230 name: param.0.name().unwrap_or_else(|| "<destruct>".into()),213 value: v.clone(),231 value: v.clone(),214 })),232 })),233 &mut bindings,215 );234 )?;216 } else {235 } else {217 bindings.insert(236 destruct(218 param.0.clone(),237 ¶m.0,219 Thunk::new(tb!(DependsOnUnbound(param.0.clone()))),238 Thunk::new(tb!(DependsOnUnbound(239 param.0.name().unwrap_or_else(|| "<destruct>".into())240 ))),241 &mut bindings,220 );242 )?;221 }243 }222 }244 }223245224 body_ctx246 Ok(body_ctx225 .extend(bindings, None, None, None)247 .extend(bindings, None, None, None)226 .into_future(fctx)248 .into_future(fctx))227}249}228250crates/jrsonnet-parser/src/expr.rsdiffbeforeafterboth152/// name, default value152/// name, default value153#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]153#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]154#[derive(Debug, PartialEq, Trace)]154#[derive(Debug, PartialEq, Trace)]155pub struct Param(pub IStr, pub Option<LocExpr>);155pub struct Param(pub Destruct, pub Option<LocExpr>);156156157/// Defined function parameters157/// Defined function parameters158#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]158#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]206 },206 },207}207}208impl Destruct {208impl Destruct {209 /// Name of destructure, used for function parameter names209 pub fn name(&self) -> Option<IStr> {210 pub fn name(&self) -> Option<IStr> {210 match self {211 match self {211 Self::Full(name) => Some(name.clone()),212 Self::Full(name) => Some(name.clone()),crates/jrsonnet-parser/src/lib.rsdiffbeforeafterboth59 rule keyword(id: &'static str) -> ()59 rule keyword(id: &'static str) -> ()60 = ##parse_string_literal(id) end_of_ident()60 = ##parse_string_literal(id) end_of_ident()616162 pub rule param(s: &ParserSettings) -> expr::Param = name:id() expr:(_ "=" _ expr:expr(s){expr})? { expr::Param(name, expr) }62 pub rule param(s: &ParserSettings) -> expr::Param = name:destruct(s) expr:(_ "=" _ expr:expr(s){expr})? { expr::Param(name, expr) }63 pub rule params(s: &ParserSettings) -> expr::ParamsDesc63 pub rule params(s: &ParserSettings) -> expr::ParamsDesc64 = params:param(s) ** comma() comma()? { expr::ParamsDesc(Rc::new(params)) }64 = params:param(s) ** comma() comma()? { expr::ParamsDesc(Rc::new(params)) }65 / { expr::ParamsDesc(Rc::new(Vec::new())) }65 / { expr::ParamsDesc(Rc::new(Vec::new())) }