From b92afb4bd89e9317429e1fef13c31c2a317bc0fb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Kr=C3=A1l?= <g4rrus@gmail.com>
Date: Tue, 10 Oct 2017 00:18:47 +0200
Subject: [PATCH] Fix TODO in is_array function: [1 2 3][0] is now treated as a
 string

* Fixed is_array to return false on "[1 2 3][0]"

* Added derive for Copy to IsArrayHelper
---
 src/parser/assignments/checker.rs | 71 +++++++++++++++++++++----------
 1 file changed, 48 insertions(+), 23 deletions(-)

diff --git a/src/parser/assignments/checker.rs b/src/parser/assignments/checker.rs
index ad919bc7..653368e1 100644
--- a/src/parser/assignments/checker.rs
+++ b/src/parser/assignments/checker.rs
@@ -2,12 +2,54 @@ use super::{Primitive, ReturnValue, TypeError};
 use super::super::Expander;
 use super::super::expand_string;
 
+use std::iter::Iterator;
+
+#[derive(PartialEq, Clone, Copy)]
+enum IsArrayHelper {
+    Valid(usize),
+    RootBracketClosed,
+    Invalid,
+}
+
 /// Determines if the supplied value is either an array or a string.
 ///
 /// - `[ 1 2 3 ]` = Array
 /// - `[ 1 2 3 ][1]` = String
 /// - `string` = String
-pub(crate) fn is_array(value: &str) -> bool { value.starts_with('[') && value.ends_with(']') }
+pub(crate) fn is_array(value: &str) -> bool {
+    if value.starts_with('[') && value.ends_with(']') {
+        !value
+            .chars()
+            .scan(IsArrayHelper::Valid(0), |state, x| {
+                // If previous iteration was RootBracketClosed or Invalid then indicate invalid
+                if *state == IsArrayHelper::RootBracketClosed || *state == IsArrayHelper::Invalid {
+                    *state = IsArrayHelper::Invalid;
+                    return Some(*state);
+                }
+
+                if x == '[' {
+                    if let IsArrayHelper::Valid(open) = *state {
+                        *state = IsArrayHelper::Valid(open + 1);
+                    }
+                } else if x == ']' {
+                    if let IsArrayHelper::Valid(open) = *state {
+                        *state = IsArrayHelper::Valid(open - 1);
+                    }
+                }
+
+                // if true, root bracket was closed
+                // => any characters after this one indicate invalid array
+                if *state == IsArrayHelper::Valid(0) {
+                    *state = IsArrayHelper::RootBracketClosed;
+                }
+
+                Some(*state)
+            })
+            .any(|x| x == IsArrayHelper::Invalid)
+    } else {
+        false
+    }
+}
 
 pub(crate) fn is_boolean(value: &str) -> Result<&str, ()> {
     if ["true", "1", "y"].contains(&value) {
@@ -34,11 +76,7 @@ fn is_integer_string(value: ReturnValue) -> Result<ReturnValue, ()> {
         unreachable!()
     };
 
-    if is_ok {
-        Ok(value)
-    } else {
-        Err(())
-    }
+    if is_ok { Ok(value) } else { Err(()) }
 }
 
 fn is_float_string(value: ReturnValue) -> Result<ReturnValue, ()> {
@@ -48,11 +86,7 @@ fn is_float_string(value: ReturnValue) -> Result<ReturnValue, ()> {
         unreachable!()
     };
 
-    if is_ok {
-        Ok(value)
-    } else {
-        Err(())
-    }
+    if is_ok { Ok(value) } else { Err(()) }
 }
 
 fn is_boolean_array(values: &mut ReturnValue) -> bool {
@@ -79,11 +113,7 @@ fn is_integer_array(value: ReturnValue) -> Result<ReturnValue, ()> {
         unreachable!()
     };
 
-    if is_ok {
-        Ok(value)
-    } else {
-        Err(())
-    }
+    if is_ok { Ok(value) } else { Err(()) }
 }
 
 fn is_float_array(value: ReturnValue) -> Result<ReturnValue, ()> {
@@ -93,11 +123,7 @@ fn is_float_array(value: ReturnValue) -> Result<ReturnValue, ()> {
         unreachable!()
     };
 
-    if is_ok {
-        Ok(value)
-    } else {
-        Err(())
-    }
+    if is_ok { Ok(value) } else { Err(()) }
 }
 
 fn get_string<E: Expander>(shell: &E, value: &str) -> ReturnValue {
@@ -159,8 +185,7 @@ mod test {
     #[test]
     fn is_array_() {
         assert!(is_array("[1 2 3]"));
-        // TODO: Fix This
-        // assert!(!is_array("[1 2 3][0]"));
+        assert!(!is_array("[1 2 3][0]"));
         assert!(!is_array("string"));
         assert!(is_array("[1  [2 3]  4 [5 6]]"))
     }
-- 
GitLab