git.delta.rocks / jrsonnet / refs/commits / 3961a530b796

difftreelog

feat destruct function arguments

Yaroslav Bolyukin2022-06-03parent: #c35e2bd.patch.diff
in: master

5 files changed

modifiedcrates/jrsonnet-evaluator/src/evaluate/destructure.rsdiffbeforeafterboth
12};12};
1313
14#[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>>,
modifiedcrates/jrsonnet-evaluator/src/function/mod.rsdiffbeforeafterboth
59}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 error
62 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 }
6565
modifiedcrates/jrsonnet-evaluator/src/function/parse.rsdiffbeforeafterboth
7 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 }
5253
53 let mut filled_args = 0;54 let mut filled_named = 0;
55 let mut filled_positionals = 0;
5456
55 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 })?;
6163
62 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 check
64 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 })?;
7375
74 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 them
76 // Default values should be created in newly created context78 // Default values should be created in newly created context
77 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);
7982
80 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(&param.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 }
8491
85 defaults.insert(92 destruct(
86 param.0.clone(),93 &param.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 }
95107
96 // Some args still wasn't filled108 // Some args still weren't filled
97 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 == &param.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 param
120 .0
121 .clone()
122 .name()
123 .unwrap_or_else(|| "<destruct>".into())
124 ));
107 }125 }
108 }126 }
189207
190/// Creates Context, which has all argument default values applied208/// Creates Context, which has all argument default values applied
191/// and with unbound values causing error to be returned209/// and with unbound values causing error to be returned
192pub 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 {
205223
206 for param in params.iter() {224 for param in params.iter() {
207 if let Some(v) = &param.1 {225 if let Some(v) = &param.1 {
208 bindings.insert(226 destruct(
209 param.0.clone(),227 &param.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 &param.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 }
223245
224 body_ctx246 Ok(body_ctx
225 .extend(bindings, None, None, None)247 .extend(bindings, None, None, None)
226 .into_future(fctx)248 .into_future(fctx))
227}249}
228250
modifiedcrates/jrsonnet-parser/src/expr.rsdiffbeforeafterboth
152/// name, default value152/// name, default value
153#[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>);
156156
157/// Defined function parameters157/// Defined function parameters
158#[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 names
209 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()),
modifiedcrates/jrsonnet-parser/src/lib.rsdiffbeforeafterboth
59 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()
6161
62 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::ParamsDesc
64 = 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())) }