Skip to content

Commit d76beb2

Browse files
committed
feat: object destructuring defaults
Signed-off-by: Yaroslav Bolyukin <[email protected]>
1 parent 3961a53 commit d76beb2

File tree

5 files changed

+45
-14
lines changed

5 files changed

+45
-14
lines changed

crates/jrsonnet-evaluator/src/dynamic.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ impl<T: Trace + 'static> Pending<T> {
88
pub fn new() -> Self {
99
Self(Cc::new(RefCell::new(None)))
1010
}
11+
pub fn new_filled(v: T) -> Self {
12+
Self(Cc::new(RefCell::new(Some(v))))
13+
}
1114
/// # Panics
1215
/// If wrapper is filled already
1316
pub fn fill(self, value: T) {

crates/jrsonnet-evaluator/src/evaluate/destructure.rs

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@ use crate::{
1212
};
1313

1414
#[allow(clippy::too_many_lines)]
15+
#[allow(unused_variables)]
1516
pub fn destruct(
1617
d: &Destruct,
1718
parent: Thunk<Val>,
19+
fctx: Pending<Context>,
1820
new_bindings: &mut GcHashMap<IStr, Thunk<Val>>,
1921
) -> Result<()> {
2022
match d {
@@ -89,6 +91,7 @@ pub fn destruct(
8991
full: full.clone(),
9092
index: i,
9193
})),
94+
fctx.clone(),
9295
new_bindings,
9396
)?;
9497
}
@@ -119,6 +122,7 @@ pub fn destruct(
119122
start: start.len(),
120123
end: end.len(),
121124
})),
125+
fctx.clone(),
122126
new_bindings,
123127
)?;
124128
}
@@ -151,6 +155,7 @@ pub fn destruct(
151155
index: i,
152156
end: end.len(),
153157
})),
158+
fctx.clone(),
154159
new_bindings,
155160
)?;
156161
}
@@ -189,36 +194,51 @@ pub fn destruct(
189194
Ok(obj)
190195
}
191196
}
192-
let field_names: Vec<_> = fields.iter().map(|f| f.0.clone()).collect();
197+
let field_names: Vec<_> = fields
198+
.iter()
199+
.filter(|f| f.2.is_none())
200+
.map(|f| f.0.clone())
201+
.collect();
193202
let full = Thunk::new(tb!(DataThunk {
194203
parent,
195204
field_names: field_names.clone(),
196205
has_rest: rest.is_some()
197206
}));
198207

199-
for (field, d) in fields {
208+
for (field, d, default) in fields {
200209
#[derive(Trace)]
201210
struct FieldThunk {
202211
full: Thunk<ObjValue>,
203212
field: IStr,
213+
default: Option<(Pending<Context>, LocExpr)>,
204214
}
205215
impl ThunkValue for FieldThunk {
206216
type Output = Val;
207217

208218
fn get(self: Box<Self>, s: State) -> Result<Self::Output> {
209219
let full = self.full.evaluate(s.clone())?;
210-
let field = full.get(s, self.field)?.expect("shape is checked");
211-
Ok(field)
220+
if let Some(field) = full.get(s.clone(), self.field)? {
221+
Ok(field)
222+
} else {
223+
let (fctx, expr) = self.default.as_ref().expect("shape is checked");
224+
Ok(evaluate(s, fctx.clone().unwrap(), &expr)?)
225+
}
212226
}
213227
}
214228
let value = Thunk::new(tb!(FieldThunk {
215229
full: full.clone(),
216-
field: field.clone()
230+
field: field.clone(),
231+
default: default.clone().map(|e| (fctx.clone(), e)),
217232
}));
218233
if let Some(d) = d {
219-
destruct(d, value, new_bindings)?;
234+
destruct(d, value, fctx.clone(), new_bindings)?;
220235
} else {
221-
destruct(&Destruct::Full(field.clone()), value, new_bindings)?;
236+
destruct(
237+
&Destruct::Full(field.clone()),
238+
value,
239+
fctx.clone(),
240+
new_bindings,
241+
)?;
222242
}
223243
}
224244
}
@@ -251,10 +271,10 @@ pub fn evaluate_dest(
251271
}
252272
let data = Thunk::new(tb!(EvaluateThunkValue {
253273
name: into.name(),
254-
fctx,
274+
fctx: fctx.clone(),
255275
expr: value.clone(),
256276
}));
257-
destruct(into, data, new_bindings)?;
277+
destruct(into, data, fctx, new_bindings)?;
258278
}
259279
BindSpec::Function {
260280
name,

crates/jrsonnet-evaluator/src/function/parse.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,12 @@ pub fn parse_function_call(
5656

5757
args.unnamed_iter(s.clone(), ctx.clone(), tailstrict, &mut |id, arg| {
5858
let name = params[id].0.clone();
59-
destruct(&name, arg, &mut passed_args)?;
59+
destruct(
60+
&name,
61+
arg,
62+
Pending::new_filled(ctx.clone()),
63+
&mut passed_args,
64+
)?;
6065
filled_positionals += 1;
6166
Ok(())
6267
})?;
@@ -96,6 +101,7 @@ pub fn parse_function_call(
96101
name: param.0.name().unwrap_or_else(|| "<destruct>".into()),
97102
value: param.1.clone().expect("default exists"),
98103
})),
104+
fctx.clone(),
99105
&mut defaults,
100106
)?;
101107
if param.0.name().is_some() {
@@ -230,6 +236,7 @@ pub fn parse_default_function_call(body_ctx: Context, params: &ParamsDesc) -> Re
230236
name: param.0.name().unwrap_or_else(|| "<destruct>".into()),
231237
value: v.clone(),
232238
})),
239+
fctx.clone(),
233240
&mut bindings,
234241
)?;
235242
} else {
@@ -238,6 +245,7 @@ pub fn parse_default_function_call(body_ctx: Context, params: &ParamsDesc) -> Re
238245
Thunk::new(tb!(DependsOnUnbound(
239246
param.0.name().unwrap_or_else(|| "<destruct>".into())
240247
))),
248+
fctx.clone(),
241249
&mut bindings,
242250
)?;
243251
}

crates/jrsonnet-parser/src/expr.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ pub enum DestructRest {
188188
}
189189

190190
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
191-
#[derive(Debug, Clone, PartialEq, Eq, Trace)]
191+
#[derive(Debug, Clone, PartialEq, Trace)]
192192
pub enum Destruct {
193193
Full(IStr),
194194
#[cfg(feature = "exp-destruct")]
@@ -201,7 +201,7 @@ pub enum Destruct {
201201
},
202202
#[cfg(feature = "exp-destruct")]
203203
Object {
204-
fields: Vec<(IStr, Option<Destruct>)>,
204+
fields: Vec<(IStr, Option<Destruct>, Option<LocExpr>)>,
205205
rest: Option<DestructRest>,
206206
},
207207
}

crates/jrsonnet-parser/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#![allow(clippy::redundant_closure_call)]
1+
#![allow(clippy::redundant_closure_call, clippy::derive_partial_eq_without_eq)]
22

33
use std::rc::Rc;
44

@@ -109,7 +109,7 @@ parser! {
109109
}
110110
pub rule destruct_object(s: &ParserSettings) -> expr::Destruct
111111
= "{" _
112-
fields:(name:id() _ into:(":" _ into:destruct(s) {into})? {(name, into)})**comma()
112+
fields:(name:id() into:(_ ":" _ into:destruct(s) {into})? default:(_ "=" _ v:expr(s) {v})? {(name, into, default)})**comma()
113113
rest:(
114114
comma() rest:destruct_rest()? {rest}
115115
/ comma()? {None}

0 commit comments

Comments
 (0)