From b7a931173c91cd13909592d1c9a701d77d24da9c Mon Sep 17 00:00:00 2001
From: Michael Aaron Murphy <mmstickman@gmail.com>
Date: Sun, 25 Jun 2017 15:57:59 -0400
Subject: [PATCH] Implement Explicit Array Assignments

In order to create an array with the let command, arrays must be wrapped within [ and ] characters, like so:

let array = [ 1 2 3 ]
let copy_of_array = [  ]

Otherwise, if array arguments are passed to let but not wrapped within [ and ] characters, then the array arguments will be joined together as a string, with spaces between each element.
---
 examples/arrays.ion              |  8 +++++++-
 examples/arrays.out              |  1 +
 src/main.rs                      |  1 -
 src/parser/shell_expand/words.rs | 25 +++++--------------------
 src/shell/assignments.rs         | 28 ++++++++++++++--------------
 5 files changed, 27 insertions(+), 36 deletions(-)

diff --git a/examples/arrays.ion b/examples/arrays.ion
index 82d595f1..e8658556 100644
--- a/examples/arrays.ion
+++ b/examples/arrays.ion
@@ -11,7 +11,7 @@ end
 
 # Array Command Substitution
 
-let array_process = @(echo a  b c d    e)
+let array_process = [ @(echo a  b c d    e) ]
 for i in @array_process
     echo $i
 end
@@ -61,3 +61,9 @@ echo @array[..]
 for index in 0..3
   echo $(echo 😉😉😉)[$index]
 end
+
+# Convert Array to String
+
+let array = [ 1 2 3 4 5 ]
+let as_string = @array
+echo $as_string
diff --git a/examples/arrays.out b/examples/arrays.out
index 8b6b617d..e46fc022 100644
--- a/examples/arrays.out
+++ b/examples/arrays.out
@@ -51,3 +51,4 @@ a b c d e
 😉
 😉
 😉
+1 2 3 4 5
diff --git a/src/main.rs b/src/main.rs
index dfe7763d..ec2fc193 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -71,7 +71,6 @@ fn main() {
     let handle = core.handle();
     let ctrl_c = tokio_signal::ctrl_c(&handle).flatten_stream();
     let signal_handler = ctrl_c.for_each(|()| {
-        let _ = writeln!(stderr(), "ion: received SIGINT (Ctrl+C)");
         let _ = sigint_tx.send(true);
         Ok(())
     });
diff --git a/src/parser/shell_expand/words.rs b/src/parser/shell_expand/words.rs
index 92f7d5a8..241be85e 100644
--- a/src/parser/shell_expand/words.rs
+++ b/src/parser/shell_expand/words.rs
@@ -3,8 +3,8 @@ use std::char;
 use std::str::FromStr;
 use std::iter::{empty, FromIterator};
 
+use super::super::ArgumentSplitter;
 use super::unicode_segmentation::UnicodeSegmentation;
-
 use super::{ExpanderFunctions, expand_string};
 use super::ranges::parse_index_range;
 
@@ -824,32 +824,19 @@ impl<'a> WordIterator<'a> {
     fn array<I>(&mut self, iterator: &mut I) -> WordToken<'a>
         where I: Iterator<Item = u8>
     {
-        let mut start = self.read;
+        let start = self.read;
         let mut level = 0;
-        let mut whitespace = true;
-        let mut elements = Vec::new();
         while let Some(character) = iterator.next() {
             match character {
                 _ if self.flags.contains(BACKSL)      => self.flags ^= BACKSL,
                 b'\\'                                 => self.flags ^= BACKSL,
                 b'\'' if !self.flags.contains(DQUOTE) => self.flags ^= SQUOTE,
                 b'"'  if !self.flags.contains(SQUOTE) => self.flags ^= DQUOTE,
-                b' '  if !self.flags.intersects(SQUOTE | DQUOTE) && level == 0 => {
-                    if whitespace {
-                        self.read += 1;
-                        start = self.read;
-                    } else {
-                        elements.push(&self.data[start..self.read]);
-                        start = self.read + 1;
-                        self.read += 1;
-                        whitespace = true;
-                    }
-                    continue
-                },
                 b'[' if !self.flags.intersects(SQUOTE | DQUOTE) => level += 1,
                 b']' if !self.flags.intersects(SQUOTE | DQUOTE) => {
                     if level == 0 {
-                        elements.push(&self.data[start..self.read]);
+                        let elements = ArgumentSplitter::new(&self.data[start..self.read])
+                            .collect::<Vec<&str>>();
                         self.read += 1;
 
                         return if let Some(&b'[') = self.data.as_bytes().get(self.read) {
@@ -857,14 +844,12 @@ impl<'a> WordIterator<'a> {
                             WordToken::Array(elements, self.read_selection(iterator))
                         } else {
                             WordToken::Array(elements, Select::All)
-
                         }
                     } else {
                         level -= 1;
                     }
-
                 },
-                _ => whitespace = false
+                _ => ()
             }
             self.read += 1;
         }
diff --git a/src/shell/assignments.rs b/src/shell/assignments.rs
index 79da421c..2b9a9b02 100644
--- a/src/shell/assignments.rs
+++ b/src/shell/assignments.rs
@@ -63,10 +63,11 @@ fn print_arrays(list: &ArrayVariableContext) {
     }
 }
 
-fn parse_assignment(binding: Binding,
-                    vars: &mut Variables,
-                    dir_stack: &DirectoryStack) -> Result<Action, i32>
-{
+fn parse_assignment (
+    binding: Binding,
+    vars: &mut Variables,
+    dir_stack: &DirectoryStack
+) -> Result<Action, i32> {
     let expanders = get_expanders!(vars, dir_stack);
     match binding {
         Binding::InvalidKey(key) => {
@@ -76,7 +77,7 @@ fn parse_assignment(binding: Binding,
         },
         Binding::KeyValue(key, value) => match parse_expression(&value, &expanders) {
             Value::String(value) => Ok(Action::UpdateString(key, value)),
-            Value::Array(array)  => Ok(Action::UpdateArray(key, array))
+            Value::Array(array)  => Ok(Action::UpdateArray(key, array)),
         },
         Binding::MultipleKeys(keys, value) => match parse_expression(&value, &expanders) {
             Value::String(value) => {
@@ -171,19 +172,18 @@ pub fn export_variable(binding : Binding, vars: &mut Variables, dir_stack : &Dir
     SUCCESS
 }
 
-fn parse_expression(expression: &str, shell_funcs: &ExpanderFunctions) -> Value {
+fn parse_expression (
+    expression: &str,
+    shell_funcs: &ExpanderFunctions
+) -> Value {
     let arguments: Vec<&str> = ArgumentSplitter::new(expression).collect();
 
     if arguments.len() == 1 {
-        // If a single argument has been passed, it will be expanded and checked to determine
-        // whether or not the expression is an array or a string.
-        let expanded = expand_string(expression, shell_funcs, false);
-        if expanded.len() == 1 {
-            // Grab the inner value and return it as a String.
-            Value::String(expanded[0].clone())
+        let array = expand_string(expression, shell_funcs, false);
+        if expression.starts_with('[') && expression.ends_with(']') {
+            Value::Array(array)
         } else {
-            // Return the expanded values as an Array.
-            Value::Array(expanded)
+            Value::String(array.join(" "))
         }
     } else {
         // If multiple arguments have been passed, they will be collapsed into a single string.
-- 
GitLab