Skip to content

Commit 78b09f8

Browse files
committed
feat(lang): add std.remove and std.removeAt functions
1 parent 9166b45 commit 78b09f8

File tree

14 files changed

+159
-0
lines changed

14 files changed

+159
-0
lines changed

rsjsonnet-lang/src/program/data.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,19 @@ impl<'p> Program<'p> {
4242
self.gc_alloc(thunk)
4343
}
4444

45+
#[inline]
46+
pub(super) fn make_thunk_array(
47+
&mut self,
48+
items: impl IntoIterator<Item = Gc<ThunkData<'p>>>,
49+
) -> Gc<ArrayData<'p>> {
50+
let items: Box<[_]> = items.into_iter().collect();
51+
if items.is_empty() {
52+
Gc::from(&self.empty_array)
53+
} else {
54+
self.gc_alloc(items)
55+
}
56+
}
57+
4558
#[inline]
4659
pub(super) fn make_value_array(
4760
&mut self,
@@ -786,6 +799,8 @@ pub(super) enum BuiltInFunc {
786799
MinArray,
787800
MaxArray,
788801
Contains,
802+
Remove,
803+
RemoveAt,
789804
// Sets
790805
Set,
791806
SetInter,

rsjsonnet-lang/src/program/eval/call.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -922,6 +922,19 @@ impl<'p> Evaluator<'_, 'p> {
922922
.push(State::StdContains { value: arg1.view() });
923923
self.state_stack.push(State::DoThunk(arg0.view()));
924924
}
925+
BuiltInFunc::Remove => {
926+
let [arg0, arg1] = check_num_args(args);
927+
self.state_stack
928+
.push(State::StdRemove { value: arg1.view() });
929+
self.state_stack.push(State::DoThunk(arg0.view()));
930+
}
931+
BuiltInFunc::RemoveAt => {
932+
let [arg0, arg1] = check_num_args(args);
933+
self.state_stack
934+
.push(State::FnFallible(Self::do_std_remove_at));
935+
self.state_stack.push(State::DoThunk(arg1.view()));
936+
self.state_stack.push(State::DoThunk(arg0.view()));
937+
}
925938
BuiltInFunc::Set => {
926939
let [arg0, arg1] = check_num_args(args);
927940
self.state_stack.push(State::StdSet);

rsjsonnet-lang/src/program/eval/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1472,6 +1472,10 @@ impl<'p, 'a> Evaluator<'a, 'p> {
14721472
} => self.do_std_max_array_check_item(keyf, array, cur_index, max_index)?,
14731473
State::StdContains { value } => self.do_std_contains(value)?,
14741474
State::StdContainsItem { array, index } => self.do_std_contains_item(array, index),
1475+
State::StdRemove { value } => self.do_std_remove(value)?,
1476+
State::StdRemoveCheckItem { array, index } => {
1477+
self.do_std_remove_check_item(array, index)
1478+
}
14751479
State::StdSet => self.do_std_set()?,
14761480
State::StdSetUniq {
14771481
orig_array,

rsjsonnet-lang/src/program/eval/state.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,13 @@ pub(super) enum State<'a, 'p> {
444444
array: GcView<ArrayData<'p>>,
445445
index: usize,
446446
},
447+
StdRemove {
448+
value: GcView<ThunkData<'p>>,
449+
},
450+
StdRemoveCheckItem {
451+
array: GcView<ArrayData<'p>>,
452+
index: usize,
453+
},
447454
StdSet,
448455
StdSetUniq {
449456
orig_array: GcView<ArrayData<'p>>,

rsjsonnet-lang/src/program/eval/stdlib.rs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3140,6 +3140,77 @@ impl<'p> Evaluator<'_, 'p> {
31403140
}
31413141
}
31423142

3143+
pub(super) fn do_std_remove(&mut self, value: GcView<ThunkData<'p>>) -> EvalResult<()> {
3144+
let array = self.value_stack.pop().unwrap();
3145+
let array = self.expect_std_func_arg_array(array, "contains", 0)?;
3146+
3147+
if let Some(item0) = array.first() {
3148+
let item0 = item0.view();
3149+
3150+
self.state_stack
3151+
.push(State::StdRemoveCheckItem { array, index: 0 });
3152+
self.state_stack.push(State::EqualsValue);
3153+
self.state_stack.push(State::DoThunk(item0));
3154+
self.state_stack.push(State::DoThunk(value.clone()));
3155+
self.state_stack.push(State::DoThunk(value));
3156+
} else {
3157+
self.value_stack.push(ValueData::Array(Gc::from(&array)));
3158+
}
3159+
3160+
Ok(())
3161+
}
3162+
3163+
pub(super) fn do_std_remove_check_item(&mut self, array: GcView<ArrayData<'p>>, index: usize) {
3164+
let equal = self.bool_stack.pop().unwrap();
3165+
if equal {
3166+
let new_array = self.program.make_thunk_array(
3167+
array[..index]
3168+
.iter()
3169+
.cloned()
3170+
.chain(array[(index + 1)..].iter().cloned()),
3171+
);
3172+
*self.value_stack.last_mut().unwrap() = ValueData::Array(new_array);
3173+
} else {
3174+
let next_index = index + 1;
3175+
if let Some(next_item) = array.get(next_index) {
3176+
let next_item = next_item.view();
3177+
self.value_stack
3178+
.push(self.value_stack.last().unwrap().clone());
3179+
self.state_stack.push(State::StdRemoveCheckItem {
3180+
array,
3181+
index: next_index,
3182+
});
3183+
self.state_stack.push(State::EqualsValue);
3184+
self.state_stack.push(State::DoThunk(next_item));
3185+
} else {
3186+
*self.value_stack.last_mut().unwrap() = ValueData::Array(Gc::from(&array));
3187+
}
3188+
}
3189+
}
3190+
3191+
pub(super) fn do_std_remove_at(&mut self) -> EvalResult<()> {
3192+
let index = self.value_stack.pop().unwrap();
3193+
let array = self.value_stack.pop().unwrap();
3194+
3195+
let array = self.expect_std_func_arg_array(array, "containsAt", 0)?;
3196+
let index_f = self.expect_std_func_arg_number(index, "containsAt", 1)?;
3197+
3198+
let index = index_f as usize;
3199+
if index_f.trunc() == index_f && index_f >= 0.0 && index < array.len() {
3200+
let new_array = self.program.make_thunk_array(
3201+
array[..index]
3202+
.iter()
3203+
.cloned()
3204+
.chain(array[(index + 1)..].iter().cloned()),
3205+
);
3206+
self.value_stack.push(ValueData::Array(new_array));
3207+
} else {
3208+
self.value_stack.push(ValueData::Array(Gc::from(&array)));
3209+
}
3210+
3211+
Ok(())
3212+
}
3213+
31433214
pub(super) fn do_std_set(&mut self) -> EvalResult<()> {
31443215
let keyf = self.value_stack.pop().unwrap();
31453216
let arr = self.value_stack.pop().unwrap();

rsjsonnet-lang/src/program/stdlib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,8 @@ impl<'p> Program<'p> {
228228
add_simple("sum", BuiltInFunc::Sum, &["sum"]);
229229
add_simple("avg", BuiltInFunc::Avg, &["avg"]);
230230
add_simple("contains", BuiltInFunc::Contains, &["arr", "elem"]);
231+
add_simple("remove", BuiltInFunc::Remove, &["arr", "elem"]);
232+
add_simple("removeAt", BuiltInFunc::RemoveAt, &["arr", "idx"]);
231233
add_simple("base64", BuiltInFunc::Base64, &["input"]);
232234
add_simple(
233235
"base64DecodeBytes",
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
std.remove(null, 0)
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: first argument of `std.contains` is expected to be array, got null
2+
note: while evaluating call to `remove`
3+
--> invalid_arg.jsonnet:1:1
4+
|
5+
1 | std.remove(null, 0)
6+
| -------------------
7+
note: during top-level value evaluation
8+
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
std.removeAt(null, 0)
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: first argument of `std.containsAt` is expected to be array, got null
2+
note: while evaluating call to `removeAt`
3+
--> invalid_arg_1.jsonnet:1:1
4+
|
5+
1 | std.removeAt(null, 0)
6+
| ---------------------
7+
note: during top-level value evaluation
8+

0 commit comments

Comments
 (0)