From 1c80bd2e2493915e3852f15842fdd3cfaa8bfbff Mon Sep 17 00:00:00 2001
From: Thomas Kinnen <thomas.kinnen@gmail.com>
Date: Thu, 14 Dec 2017 19:44:01 +0100
Subject: [PATCH] Add @reverse() method (#441)

---
 examples/array_methods.ion                    |  4 ++
 examples/array_methods.out                    |  3 ++
 manual/src/ch05-05-method.md                  | 17 +++++++
 .../shell_expand/words/methods/arrays.rs      | 45 ++++++++++++++++++-
 4 files changed, 68 insertions(+), 1 deletion(-)

diff --git a/examples/array_methods.ion b/examples/array_methods.ion
index 22566049..c15408ef 100644
--- a/examples/array_methods.ion
+++ b/examples/array_methods.ion
@@ -4,3 +4,7 @@ echo @graphemes("onetwo", "3")
 echo @bytes("onetwo")
 echo @chars("onetwo")
 echo @lines($unescape("firstline\nsecondline"))
+echo @reverse([1 2 3])
+echo @reverse(["a"])
+let foo = [1 2 3]
+echo @reverse(@foo)
diff --git a/examples/array_methods.out b/examples/array_methods.out
index dbc0b7e6..af8487b8 100644
--- a/examples/array_methods.out
+++ b/examples/array_methods.out
@@ -4,3 +4,6 @@ o n e t w o
 111 110 101 116 119 111
 o n e t w o
 firstline secondline
+3 2 1
+a
+3 2 1
diff --git a/manual/src/ch05-05-method.md b/manual/src/ch05-05-method.md
index 6a4f5425..95f27639 100644
--- a/manual/src/ch05-05-method.md
+++ b/manual/src/ch05-05-method.md
@@ -461,6 +461,7 @@ The following are the currently-supported array methods.
 - [bytes](#bytes)
 - [chars](#chars)
 - [graphemes](#graphemes)
+- [reverse](#reverse)
 
 ### lines
 
@@ -595,3 +596,19 @@ b
 a
 r
 ```
+
+### reverse
+
+Defaults to array variables. Returns a reversed copy of the input array.
+
+#### Examples
+
+```ion
+echo @reverse([1 2 3])
+```
+
+#### Output
+
+```
+3 2 1
+```
\ No newline at end of file
diff --git a/src/parser/shell_expand/words/methods/arrays.rs b/src/parser/shell_expand/words/methods/arrays.rs
index 0e339208..8df2de14 100644
--- a/src/parser/shell_expand/words/methods/arrays.rs
+++ b/src/parser/shell_expand/words/methods/arrays.rs
@@ -35,6 +35,7 @@ impl<'a> ArrayMethod<'a> {
             "bytes" => self.bytes(expand_func),
             "chars" => self.chars(expand_func),
             "lines" => self.lines(expand_func),
+            "reverse" => self.reverse(expand_func),
             _ => Err("invalid array method"),
         };
 
@@ -55,6 +56,17 @@ impl<'a> ArrayMethod<'a> {
         }
     }
 
+    #[inline]
+    fn resolve_array<E: Expander>(&self, expand_func: &E) -> Array {
+        if let Some(array) = expand_func.array(self.variable, Select::All) {
+            array.clone()
+        } else if is_expression(self.variable) {
+            expand_string(self.variable, expand_func, false)
+        } else {
+            array![]
+        }
+    }
+
     fn split<E: Expander>(&self, expand_func: &E) -> Result<Array, &'static str> {
         let variable = self.resolve_var(expand_func);
         let res = match (&self.pattern, self.selection.clone()) {
@@ -178,7 +190,17 @@ impl<'a> ArrayMethod<'a> {
 
     fn lines<E: Expander>(&self, expand_func: &E) -> Result<Array, &'static str> {
         let variable = self.resolve_var(expand_func);
-        Ok(variable.lines().into_iter().map(|line| line.to_string()).collect())
+        Ok(variable
+            .lines()
+            .into_iter()
+            .map(|line| line.to_string())
+            .collect())
+    }
+
+    fn reverse<E: Expander>(&self, expand_func: &E) -> Result<Array, &'static str> {
+        let mut result = self.resolve_array(expand_func);
+        result.reverse();
+        Ok(result)
     }
 }
 
@@ -200,6 +222,13 @@ mod test {
                 _ => None,
             }
         }
+
+        fn array(&self, variable: &str, _: Select) -> Option<Array> {
+            match variable {
+                "$ARRAY" => Some(array!["a", "b", "c"].to_owned()),
+                _ => None,
+            }
+        }
     }
 
     #[test]
@@ -434,4 +463,18 @@ mod test {
             array!["FOO", "BAR"]
         );
     }
+
+    #[test]
+    fn test_reverse() {
+        let method = ArrayMethod {
+            method:    "reverse",
+            variable:  "$ARRAY",
+            pattern:   Pattern::StringPattern("3"),
+            selection: Select::All,
+        };
+        assert_eq!(
+            method.handle_as_array(&VariableExpander),
+            array!["c", "b", "a"]
+        );
+    }
 }
-- 
GitLab