difftreelog
feat destruct function arguments
in: master
5 files changed
crates/jrsonnet-evaluator/src/evaluate/destructure.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/evaluate/destructure.rs
+++ b/crates/jrsonnet-evaluator/src/evaluate/destructure.rs
@@ -12,7 +12,7 @@
};
#[allow(clippy::too_many_lines)]
-fn destruct(
+pub fn destruct(
d: &Destruct,
parent: Thunk<Val>,
new_bindings: &mut GcHashMap<IStr, Thunk<Val>>,
crates/jrsonnet-evaluator/src/function/mod.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/function/mod.rs
+++ b/crates/jrsonnet-evaluator/src/function/mod.rs
@@ -59,7 +59,7 @@
}
impl FuncDesc {
/// Create body context, but fill arguments without defaults with lazy error
- pub fn default_body_context(&self) -> Context {
+ pub fn default_body_context(&self) -> Result<Context> {
parse_default_function_call(self.ctx.clone(), &self.params)
}
crates/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.rsdiffbeforeafterboth--- a/crates/jrsonnet-parser/src/expr.rs
+++ b/crates/jrsonnet-parser/src/expr.rs
@@ -152,7 +152,7 @@
/// name, default value
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, PartialEq, Trace)]
-pub struct Param(pub IStr, pub Option<LocExpr>);
+pub struct Param(pub Destruct, pub Option<LocExpr>);
/// Defined function parameters
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
@@ -206,6 +206,7 @@
},
}
impl Destruct {
+ /// Name of destructure, used for function parameter names
pub fn name(&self) -> Option<IStr> {
match self {
Self::Full(name) => Some(name.clone()),
crates/jrsonnet-parser/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-parser/src/lib.rs
+++ b/crates/jrsonnet-parser/src/lib.rs
@@ -59,7 +59,7 @@
rule keyword(id: &'static str) -> ()
= ##parse_string_literal(id) end_of_ident()
- pub rule param(s: &ParserSettings) -> expr::Param = name:id() expr:(_ "=" _ expr:expr(s){expr})? { expr::Param(name, expr) }
+ pub rule param(s: &ParserSettings) -> expr::Param = name:destruct(s) expr:(_ "=" _ expr:expr(s){expr})? { expr::Param(name, expr) }
pub rule params(s: &ParserSettings) -> expr::ParamsDesc
= params:param(s) ** comma() comma()? { expr::ParamsDesc(Rc::new(params)) }
/ { expr::ParamsDesc(Rc::new(Vec::new())) }