Repository: CSML-by-Clevy/csml-engine (rust)

Issue:
index as optional parameter for iterators
**Is your feature request related to a problem? Please describe.**
 Currently there is no easy way to access the index will using iterators

 [1, 2].map( (value) {  
  ...
 })

**Describe the solution you'd like**

Allow access of index as optional parameter

 [1, 2].map( (value, index) {
  ...
 })



Pull request description:
Feat: optional index parameter for iterators
Fixes #266 

## Proposed Changes

- index as optional parameter for map, reduce  and filter 


Patch:
diff --git a/csml_interpreter/src/data/primitive/array.rs b/csml_interpreter/src/data/primitive/array.rs
index 5fd78a3d..c417e46c 100644
--- a/csml_interpreter/src/data/primitive/array.rs
+++ b/csml_interpreter/src/data/primitive/array.rs
@@ -758,11 +758,17 @@ impl PrimitiveArray {
 
                 let mut vec = vec![];
 
-                for value in array.value.iter() {
+                for (index, value) in array.value.iter().enumerate() {
                     let mut map = HashMap::new();
                     map.insert("arg0".to_owned(), value.to_owned());
+                    if closure.args.len() >= 2 {
+                        map.insert(
+                            "arg1".to_owned(), 
+                            PrimitiveInt::get_literal(index as i64, interval)
+                        );
+                    }
+                    
                     let args = ArgsType::Normal(map);
-
                     let result = exec_fn(
                         &closure.func,
                         &closure.args,
@@ -806,9 +812,17 @@ impl PrimitiveArray {
 
                 let mut vec = vec![];
 
-                for value in array.value.iter() {
+                for (index, value) in array.value.iter().enumerate() {
                     let mut map = HashMap::new();
                     map.insert("arg0".to_owned(), value.to_owned());
+                    if closure.args.len() >= 2 {
+                        dbg!(index);
+                        map.insert(
+                            "arg1".to_owned(), 
+                            PrimitiveInt::get_literal(index as i64, interval)
+                        );
+                    }
+
                     let args = ArgsType::Normal(map);
 
                     let result = exec_fn(
@@ -856,10 +870,18 @@ impl PrimitiveArray {
                     format!("usage: {}", usage),
                 )?;
 
-                for value in array.value.iter() {
+                for (index, value) in array.value.iter().enumerate() {
                     let mut map = HashMap::new();
                     map.insert("arg0".to_owned(), accumulator);
                     map.insert("arg1".to_owned(), value.to_owned());
+
+                    if closure.args.len() >= 2 {
+                        map.insert(
+                            "arg2".to_owned(), 
+                            PrimitiveInt::get_literal(index as i64, interval)
+                        );
+                    }
+
                     let args = ArgsType::Normal(map);
 
                     accumulator = exec_fn(


Test patch:
diff --git a/csml_interpreter/CSML/basic_test/stdlib/array.csml b/csml_interpreter/CSML/basic_test/stdlib/array.csml
index a61e3f84..759fbb36 100644
--- a/csml_interpreter/CSML/basic_test/stdlib/array.csml
+++ b/csml_interpreter/CSML/basic_test/stdlib/array.csml
@@ -161,3 +161,18 @@ array_filter:
     })
 
     goto end
+
+array_map_index:
+    say [1, 2, 3, 4, 5].map((x, index) {
+        return index
+    })
+
+array_filter_index:
+    say [34, 232].filter((x, index) {
+        return 1
+    })
+
+array_reduce_index:
+    say [1, 2, 3].reduce(0, (x, index) {
+        return x + index
+    })
\ No newline at end of file
diff --git a/csml_interpreter/tests/array.rs b/csml_interpreter/tests/array.rs
index e38f3516..e7415a31 100644
--- a/csml_interpreter/tests/array.rs
+++ b/csml_interpreter/tests/array.rs
@@ -399,3 +399,70 @@ fn array_filter() {
 
     assert_eq!(v1, v2)
 }
+
+#[test]
+fn array_map_index() {
+    let data = r#"{"memories":[], "messages":[{"content":[0, 1, 2, 3, 4], "content_type":"array"}]}"#;
+    let msg = format_message(
+        Event::new("payload", "", serde_json::json!({})),
+        Context::new(
+            HashMap::new(),
+            HashMap::new(),
+            None,
+            None,
+            "array_map_index",
+            "flow",
+        ),
+        "CSML/basic_test/stdlib/array.csml",
+    );
+
+    let v1: Value = message_to_json_value(msg);
+    let v2: Value = serde_json::from_str(data).unwrap();
+
+    assert_eq!(v1, v2)
+}
+
+
+#[test]
+fn array_filter_index() {
+    let data = r#"{"memories":[], "messages":[{"content":[34, 232], "content_type":"array"}]}"#;
+    let msg = format_message(
+        Event::new("payload", "", serde_json::json!({})),
+        Context::new(
+            HashMap::new(),
+            HashMap::new(),
+            None,
+            None,
+            "array_filter_index",
+            "flow",
+        ),
+        "CSML/basic_test/stdlib/array.csml",
+    );
+
+    let v1: Value = message_to_json_value(msg);
+    let v2: Value = serde_json::from_str(data).unwrap();
+
+    assert_eq!(v1, v2)
+}
+
+#[test]
+fn array_reduce_index() {
+    let data = r#"{"memories":[], "messages":[{"content":{"text":"6"}, "content_type":"text"}]}"#;
+    let msg = format_message(
+        Event::new("payload", "", serde_json::json!({})),
+        Context::new(
+            HashMap::new(),
+            HashMap::new(),
+            None,
+            None,
+            "array_reduce_index",
+            "flow",
+        ),
+        "CSML/basic_test/stdlib/array.csml",
+    );
+
+    let v1: Value = message_to_json_value(msg);
+    let v2: Value = serde_json::from_str(data).unwrap();
+
+    assert_eq!(v1, v2)
+}