From 14432ca25207ec0a6818862a4093e3f22233f65a Mon Sep 17 00:00:00 2001 From: Adam Chalmers Date: Fri, 4 Oct 2024 09:55:49 -0500 Subject: [PATCH] KCL: Reduce can take and return any KCL values Previously it only took Array of Number and could only return Sketch. Now it has been unshackled from the chains of poor type signatures. --- src/wasm-lib/kcl/src/docs/gen_std_tests.rs | 14 ++-- src/wasm-lib/kcl/src/docs/mod.rs | 2 + src/wasm-lib/kcl/src/std/array.rs | 60 ++++++++---------- .../outputs/serial_test_example_reduce1.png | Bin 0 -> 19651 bytes 4 files changed, 37 insertions(+), 39 deletions(-) create mode 100644 src/wasm-lib/kcl/tests/outputs/serial_test_example_reduce1.png diff --git a/src/wasm-lib/kcl/src/docs/gen_std_tests.rs b/src/wasm-lib/kcl/src/docs/gen_std_tests.rs index e59ac53923..6f0a7718a9 100644 --- a/src/wasm-lib/kcl/src/docs/gen_std_tests.rs +++ b/src/wasm-lib/kcl/src/docs/gen_std_tests.rs @@ -787,12 +787,14 @@ fn test_generate_stdlib_json_schema() { let stdlib = StdLib::new(); let combined = stdlib.combined(); - let mut json_data = vec![]; - - for key in combined.keys().sorted() { - let internal_fn = combined.get(key).unwrap(); - json_data.push(internal_fn.to_json().unwrap()); - } + let json_data: Vec<_> = combined + .keys() + .sorted() + .map(|key| { + let internal_fn = combined.get(key).unwrap(); + internal_fn.to_json().unwrap() + }) + .collect(); expectorate::assert_contents( "../../../docs/kcl/std.json", &serde_json::to_string_pretty(&json_data).unwrap(), diff --git a/src/wasm-lib/kcl/src/docs/mod.rs b/src/wasm-lib/kcl/src/docs/mod.rs index 56ddf9f079..63eb0ec04c 100644 --- a/src/wasm-lib/kcl/src/docs/mod.rs +++ b/src/wasm-lib/kcl/src/docs/mod.rs @@ -83,6 +83,8 @@ impl StdLibFnArg { return Ok(Some((index, format!("${{{}:{}}}", index, "myTag")))); } else if self.type_ == "[KclValue]" && self.required { return Ok(Some((index, format!("${{{}:{}}}", index, "[0..9]")))); + } else if self.type_ == "KclValue" && self.required { + return Ok(Some((index, format!("${{{}:{}}}", index, "3")))); } get_autocomplete_snippet_from_schema(&self.schema.schema.clone().into(), index) } diff --git a/src/wasm-lib/kcl/src/std/array.rs b/src/wasm-lib/kcl/src/std/array.rs index 22c287f504..9bf837ddeb 100644 --- a/src/wasm-lib/kcl/src/std/array.rs +++ b/src/wasm-lib/kcl/src/std/array.rs @@ -4,7 +4,7 @@ use serde_json::Value as JValue; use super::{args::FromArgs, Args, FnAsArg}; use crate::{ errors::{KclError, KclErrorDetails}, - executor::{ExecState, KclValue, Sketch, SourceRange, UserVal}, + executor::{ExecState, KclValue, SourceRange, UserVal}, function_param::FunctionParam, }; @@ -98,7 +98,16 @@ async fn call_map_closure<'a>( /// For each item in an array, update a value. pub async fn reduce(exec_state: &mut ExecState, args: Args) -> Result { - let (array, start, f): (Vec, Sketch, FnAsArg<'_>) = FromArgs::from_args(&args, 0)?; + let (array, start, f): (Vec, KclValue, FnAsArg<'_>) = FromArgs::from_args(&args, 0)?; + let array: Vec = array + .into_iter() + .map(|jval| { + KclValue::UserVal(UserVal { + value: jval, + meta: vec![args.source_range.into()], + }) + }) + .collect(); let reduce_fn = FunctionParam { inner: f.func, fn_expr: f.expr, @@ -106,9 +115,7 @@ pub async fn reduce(exec_state: &mut ExecState, args: Args) -> Result Result close(%) /// ``` +/// ```no_run +/// array = [1, 2, 3] +/// sum = reduce(array, 0, (i, result_so_far) => { return i + result_so_far }) +/// assertEqual(sum, 6, 0.00001, "1 + 2 + 3 summed is 6") +/// ``` #[stdlib { name = "reduce", }] async fn inner_reduce<'a>( - array: Vec, - start: Sketch, + array: Vec, + start: KclValue, reduce_fn: FunctionParam<'a>, exec_state: &mut ExecState, args: &'a Args, -) -> Result { +) -> Result { let mut reduced = start; - for i in array { - reduced = call_reduce_closure(i, reduced, &reduce_fn, args.source_range, exec_state).await?; + for elem in array { + reduced = call_reduce_closure(elem, reduced, &reduce_fn, args.source_range, exec_state).await?; } Ok(reduced) } async fn call_reduce_closure<'a>( - i: u64, - start: Sketch, + elem: KclValue, + start: KclValue, reduce_fn: &FunctionParam<'a>, source_range: SourceRange, exec_state: &mut ExecState, -) -> Result { +) -> Result { // Call the reduce fn for this repetition. - let reduce_fn_args = vec![ - KclValue::UserVal(UserVal { - value: serde_json::Value::Number(i.into()), - meta: vec![source_range.into()], - }), - KclValue::new_user_val(start.meta.clone(), start), - ]; + let reduce_fn_args = vec![elem, start]; let transform_fn_return = reduce_fn.call(exec_state, reduce_fn_args).await?; // Unpack the returned transform object. let source_ranges = vec![source_range]; - let closure_retval = transform_fn_return.ok_or_else(|| { + let out = transform_fn_return.ok_or_else(|| { KclError::Semantic(KclErrorDetails { message: "Reducer function must return a value".to_string(), source_ranges: source_ranges.clone(), }) })?; - let Some(out) = closure_retval.as_user_val() else { - return Err(KclError::Semantic(KclErrorDetails { - message: "Reducer function must return a UserValue".to_string(), - source_ranges: source_ranges.clone(), - })); - }; - let Some((out, _meta)) = out.get() else { - return Err(KclError::Semantic(KclErrorDetails { - message: "Reducer function must return a Sketch".to_string(), - source_ranges: source_ranges.clone(), - })); - }; Ok(out) } diff --git a/src/wasm-lib/kcl/tests/outputs/serial_test_example_reduce1.png b/src/wasm-lib/kcl/tests/outputs/serial_test_example_reduce1.png new file mode 100644 index 0000000000000000000000000000000000000000..6148ae43278779b7986fcf452545890b852f2298 GIT binary patch literal 19651 zcmeI4!7GDd9LHZon&jl-C?`jbifD_Wg*HnO<%C>TLrTg;TO6%imK>1PyBpbs3rUL0 zPI6f(DJusDD_-y9@O7zy<^`dWOJWi%OeMudj2T?$#d1Eo(R#^!J8Ws$MT@_Sz;=S8vX8ar^rAFg7%6FFu_7KIXR4sljZz zqqDX6v2;4Wda&8Gkk58M_cj%dGj{H!@>1$a+(e>N@qFdweZ6_d`=;EB)86iVQ#|iP z!k#U;tvi{cNw1dN_nheHnMe1^UH;1M$2_`M{-Dq4z*FUze#TikPckqgqI_dA{h5l! z++dB#+{oC7hYCO9Arl1gKs+E1698dFGa5j!MgzLntcSEkvQ5N8mkSxREElW+aX%0b z#Djc{djE0W62PRE xN<2F@{=~Cm<4-+1!~^jlA5)0rkJ=KSWhV+DQx8VLcnH3C#{C3~W#y8*Q5*+{l literal 0 HcmV?d00001