Skip to content

Commit fba5a91

Browse files
committed
feat(stdlib): add fold function
Adds a new fold function to reduce objects and arrays into a single value based on a closure and initial value. Signed-off-by: Jacob Hull <[email protected]>
1 parent acfd9f9 commit fba5a91

File tree

6 files changed

+414
-70
lines changed

6 files changed

+414
-70
lines changed

changelog.d/1192.feature.md

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Add new function `fold` to reduce objects and arrays into a single value from an initial value and
2+
closure.
3+
4+
authors: jakedipity

src/compiler/expression/function_call.rs

+56-5
Original file line numberDiff line numberDiff line change
@@ -309,17 +309,41 @@ impl<'a> Builder<'a> {
309309
//
310310
// We set "bar" (index 0) to return bytes, and "baz" (index 1) to return an
311311
// integer.
312+
//
313+
// If one of the arguments is dependant on a closure, the parameters initial
314+
// type is assigned here and it's recomputed from the compiled closure.
312315
for (index, input_var) in input.variables.clone().into_iter().enumerate() {
313316
let call_ident = &variables[index];
314317
let type_def = target.type_info(state).result;
315318

316-
let (type_def, value) = match input_var.kind {
319+
let mut var_kind = input_var.kind;
320+
if let VariableKind::Closure(vk) = var_kind {
321+
var_kind = vk.into();
322+
}
323+
324+
let (type_def, value) = match var_kind {
325+
// A closure variable kind is not possible here but we need to
326+
// satisfy all variants with a match arm.
327+
VariableKind::Closure(_) => {
328+
panic!("got unexpected variable kind")
329+
}
330+
331+
// The variable kind is expected to be equal to the kind of a
332+
// specified parameter of the closure.
333+
VariableKind::Parameter(keyword) => {
334+
let expr = list
335+
.arguments
336+
.get(keyword)
337+
.expect("parameter should exist");
338+
(expr.type_info(state).result, expr.resolve_constant(state))
339+
}
340+
317341
// The variable kind is expected to be exactly
318342
// the kind provided by the closure definition.
319343
VariableKind::Exact(kind) => (kind.into(), None),
320344

321345
// The variable kind is expected to be equal to
322-
// the ind of the target of the closure.
346+
// the kind of the target of the closure.
323347
VariableKind::Target => (
324348
target.type_info(state).result,
325349
target.resolve_constant(state),
@@ -505,7 +529,36 @@ impl<'a> Builder<'a> {
505529
// TODO: This assumes the closure will run exactly once, which is incorrect.
506530
// see: https://github.com/vectordotdev/vector/issues/13782
507531

508-
let block = closure_block.expect("closure must contain block");
532+
let (block_span, (block, mut block_type_def)) =
533+
closure_block.expect("closure must contain block").take();
534+
535+
let mut closure_dependent_variables = input
536+
.variables
537+
.iter()
538+
.enumerate()
539+
.filter_map(|(index, input_var)| match input_var.kind {
540+
VariableKind::Closure(_) => Some(&variables[index]),
541+
_ => None,
542+
})
543+
.peekable();
544+
545+
// If any of the arugments are dependant on the closure, union the initial type with the
546+
// returned type of the closure and then recompute the closures type.
547+
if closure_dependent_variables.peek().is_some() {
548+
let block_kind = block_type_def
549+
.kind()
550+
.union(block_type_def.returns().clone());
551+
552+
closure_dependent_variables.for_each(|ident| {
553+
let details = state
554+
.local
555+
.variable_mut(ident)
556+
.expect("state must contain a closure dependant argument");
557+
details.type_def = details.type_def.kind().union(block_kind.clone()).into();
558+
});
559+
560+
block_type_def = block.apply_type_info(state);
561+
}
509562

510563
// At this point, we've compiled the block, so we can remove the
511564
// closure variables from the compiler's local environment.
@@ -518,8 +571,6 @@ impl<'a> Builder<'a> {
518571
}
519572
});
520573

521-
let (block_span, (block, block_type_def)) = block.take();
522-
523574
let closure_fallible = block_type_def.is_fallible();
524575

525576
// Check the type definition of the resulting block.This needs to match

0 commit comments

Comments
 (0)