Skip to content

Commit

Permalink
feat: object destructuring defaults
Browse files Browse the repository at this point in the history
Signed-off-by: Yaroslav Bolyukin <[email protected]>
  • Loading branch information
CertainLach committed Jun 3, 2022
1 parent 3961a53 commit d76beb2
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 14 deletions.
3 changes: 3 additions & 0 deletions crates/jrsonnet-evaluator/src/dynamic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ impl<T: Trace + 'static> Pending<T> {
pub fn new() -> Self {
Self(Cc::new(RefCell::new(None)))
}
pub fn new_filled(v: T) -> Self {
Self(Cc::new(RefCell::new(Some(v))))
}
/// # Panics
/// If wrapper is filled already
pub fn fill(self, value: T) {
Expand Down
38 changes: 29 additions & 9 deletions crates/jrsonnet-evaluator/src/evaluate/destructure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ use crate::{
};

#[allow(clippy::too_many_lines)]
#[allow(unused_variables)]
pub fn destruct(
d: &Destruct,
parent: Thunk<Val>,
fctx: Pending<Context>,
new_bindings: &mut GcHashMap<IStr, Thunk<Val>>,
) -> Result<()> {
match d {
Expand Down Expand Up @@ -89,6 +91,7 @@ pub fn destruct(
full: full.clone(),
index: i,
})),
fctx.clone(),
new_bindings,
)?;
}
Expand Down Expand Up @@ -119,6 +122,7 @@ pub fn destruct(
start: start.len(),
end: end.len(),
})),
fctx.clone(),
new_bindings,
)?;
}
Expand Down Expand Up @@ -151,6 +155,7 @@ pub fn destruct(
index: i,
end: end.len(),
})),
fctx.clone(),
new_bindings,
)?;
}
Expand Down Expand Up @@ -189,36 +194,51 @@ pub fn destruct(
Ok(obj)
}
}
let field_names: Vec<_> = fields.iter().map(|f| f.0.clone()).collect();
let field_names: Vec<_> = fields
.iter()
.filter(|f| f.2.is_none())
.map(|f| f.0.clone())
.collect();
let full = Thunk::new(tb!(DataThunk {
parent,
field_names: field_names.clone(),
has_rest: rest.is_some()
}));

for (field, d) in fields {
for (field, d, default) in fields {
#[derive(Trace)]
struct FieldThunk {
full: Thunk<ObjValue>,
field: IStr,
default: Option<(Pending<Context>, LocExpr)>,
}
impl ThunkValue for FieldThunk {
type Output = Val;

fn get(self: Box<Self>, s: State) -> Result<Self::Output> {
let full = self.full.evaluate(s.clone())?;
let field = full.get(s, self.field)?.expect("shape is checked");
Ok(field)
if let Some(field) = full.get(s.clone(), self.field)? {
Ok(field)
} else {
let (fctx, expr) = self.default.as_ref().expect("shape is checked");
Ok(evaluate(s, fctx.clone().unwrap(), &expr)?)
}
}
}
let value = Thunk::new(tb!(FieldThunk {
full: full.clone(),
field: field.clone()
field: field.clone(),
default: default.clone().map(|e| (fctx.clone(), e)),
}));
if let Some(d) = d {
destruct(d, value, new_bindings)?;
destruct(d, value, fctx.clone(), new_bindings)?;
} else {
destruct(&Destruct::Full(field.clone()), value, new_bindings)?;
destruct(
&Destruct::Full(field.clone()),
value,
fctx.clone(),
new_bindings,
)?;
}
}
}
Expand Down Expand Up @@ -251,10 +271,10 @@ pub fn evaluate_dest(
}
let data = Thunk::new(tb!(EvaluateThunkValue {
name: into.name(),
fctx,
fctx: fctx.clone(),
expr: value.clone(),
}));
destruct(into, data, new_bindings)?;
destruct(into, data, fctx, new_bindings)?;
}
BindSpec::Function {
name,
Expand Down
10 changes: 9 additions & 1 deletion crates/jrsonnet-evaluator/src/function/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,12 @@ pub fn parse_function_call(

args.unnamed_iter(s.clone(), ctx.clone(), tailstrict, &mut |id, arg| {
let name = params[id].0.clone();
destruct(&name, arg, &mut passed_args)?;
destruct(
&name,
arg,
Pending::new_filled(ctx.clone()),
&mut passed_args,
)?;
filled_positionals += 1;
Ok(())
})?;
Expand Down Expand Up @@ -96,6 +101,7 @@ pub fn parse_function_call(
name: param.0.name().unwrap_or_else(|| "<destruct>".into()),
value: param.1.clone().expect("default exists"),
})),
fctx.clone(),
&mut defaults,
)?;
if param.0.name().is_some() {
Expand Down Expand Up @@ -230,6 +236,7 @@ pub fn parse_default_function_call(body_ctx: Context, params: &ParamsDesc) -> Re
name: param.0.name().unwrap_or_else(|| "<destruct>".into()),
value: v.clone(),
})),
fctx.clone(),
&mut bindings,
)?;
} else {
Expand All @@ -238,6 +245,7 @@ pub fn parse_default_function_call(body_ctx: Context, params: &ParamsDesc) -> Re
Thunk::new(tb!(DependsOnUnbound(
param.0.name().unwrap_or_else(|| "<destruct>".into())
))),
fctx.clone(),
&mut bindings,
)?;
}
Expand Down
4 changes: 2 additions & 2 deletions crates/jrsonnet-parser/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ pub enum DestructRest {
}

#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, PartialEq, Eq, Trace)]
#[derive(Debug, Clone, PartialEq, Trace)]
pub enum Destruct {
Full(IStr),
#[cfg(feature = "exp-destruct")]
Expand All @@ -201,7 +201,7 @@ pub enum Destruct {
},
#[cfg(feature = "exp-destruct")]
Object {
fields: Vec<(IStr, Option<Destruct>)>,
fields: Vec<(IStr, Option<Destruct>, Option<LocExpr>)>,
rest: Option<DestructRest>,
},
}
Expand Down
4 changes: 2 additions & 2 deletions crates/jrsonnet-parser/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![allow(clippy::redundant_closure_call)]
#![allow(clippy::redundant_closure_call, clippy::derive_partial_eq_without_eq)]

use std::rc::Rc;

Expand Down Expand Up @@ -109,7 +109,7 @@ parser! {
}
pub rule destruct_object(s: &ParserSettings) -> expr::Destruct
= "{" _
fields:(name:id() _ into:(":" _ into:destruct(s) {into})? {(name, into)})**comma()
fields:(name:id() into:(_ ":" _ into:destruct(s) {into})? default:(_ "=" _ v:expr(s) {v})? {(name, into, default)})**comma()
rest:(
comma() rest:destruct_rest()? {rest}
/ comma()? {None}
Expand Down

0 comments on commit d76beb2

Please sign in to comment.