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