diff --git a/src/parser/shell_expand/words.rs b/src/parser/shell_expand/words.rs index 57bd91679c7bc4b470b13f0a88982b55374e50d5..4148dfb81c21f901b7f0b6b23420390db588eccd 100644 --- a/src/parser/shell_expand/words.rs +++ b/src/parser/shell_expand/words.rs @@ -579,6 +579,43 @@ impl<'a> WordIterator<'a> { WordToken::ArrayVariable(&self.data[start..], self.flags & DQUOTE != 0, Select::All) } + fn braced_array_variable<I>(&mut self, iterator : &mut I) -> WordToken<'a> + where I : Iterator<Item=u8> + { + let start = self.read; + //self.read += 1; + while let Some(character) = iterator.next() { + match character { + b'[' => { + let result = WordToken::ArrayVariable ( + &self.data[start..self.read], + self.flags & DQUOTE != 0, + self.read_selection(iterator) + ); + self.read += 1; + if let Some(b'}') = iterator.next() { + return result; + } + panic!("ion: fatal with syntax validation error: unterminated braced array expression"); + }, + b'}' => { + let output = &self.data[start..self.read]; + self.read += 1; + return WordToken::ArrayVariable(output, self.flags & DQUOTE != 0, Select::All); + } + // Only alphanumerical and underscores are allowed in variable names + 0...47 | 58...64 | 91...94 | 96 | 123...127 => { + return WordToken::ArrayVariable(&self.data[start..self.read], + self.flags & DQUOTE != 0, + Select::All); + }, + _ => (), + } + self.read += 1; + } + WordToken::ArrayVariable(&self.data[start..], self.flags & DQUOTE != 0, Select::All) + } + /// Contains the logic for parsing subshell syntax. fn process<I>(&mut self, iterator: &mut I) -> WordToken<'a> where I: Iterator<Item = u8> @@ -876,10 +913,10 @@ impl<'a> Iterator for WordIterator<'a> { Some(WordToken::Normal(&self.data[start..self.read],glob)) } }, - // Some(b'{') => { - // self.read += 2; - // return Some(self.braced_variable(&mut iterator)); - // } + Some(b'{') => { + self.read += 2; + return Some(self.braced_array_variable(&mut iterator)); + }, _ => { self.read += 1; return Some(self.array_variable(&mut iterator)); @@ -1053,11 +1090,13 @@ mod tests { #[test] fn array_variables() { - let input = "@array @array[0]"; + let input = "@array @array[0] @{array[1..]}"; let expected = vec![ WordToken::ArrayVariable("array", false, Select::All), WordToken::Whitespace(" "), WordToken::ArrayVariable("array", false, Select::Index(Index::new(0))), + WordToken::Whitespace(" "), + WordToken::ArrayVariable("array", false, Select::Range(Range::from(Index::new(1)))) ]; compare(input, expected); } diff --git a/src/parser/statements.rs b/src/parser/statements.rs index b6bbdb3c045e2539e2dae99751915651c97d0f08..f4272cb1ff19044afab8845d2bfe1a2f78389a84 100644 --- a/src/parser/statements.rs +++ b/src/parser/statements.rs @@ -119,7 +119,7 @@ impl<'a> Iterator for StatementSplitter<'a> { self.flags |= COMM_1 + VARIAB; continue }, - b'{' if self.flags & COMM_1 != 0 => self.flags |= VBRACE, + b'{' if self.flags & (COMM_1 + COMM_2) != 0 => self.flags |= VBRACE, b'{' if self.flags & (SQUOTE + DQUOTE) == 0 => self.brace_level += 1, b'}' if self.flags & VBRACE != 0 => self.flags ^= VBRACE, b'}' if self.flags & (SQUOTE + DQUOTE) == 0 => { @@ -329,7 +329,7 @@ fn nested_array_process() { #[test] fn braced_variables() { - let command = "echo ${foo}bar ${bar}baz ${baz}quux"; + let command = "echo ${foo}bar ${bar}baz ${baz}quux @{zardoz}wibble"; let results = StatementSplitter::new(command).collect::<Vec<Result<&str, StatementError>>>(); assert_eq!(results.len(), 1); assert_eq!(results, vec![Ok(command)]);