From 61a24a898a7d1a6e71b4193ed850b3f0f6076077 Mon Sep 17 00:00:00 2001
From: Xavier L'Heureux <xavier.lheureux@icloud.com>
Date: Wed, 3 Apr 2019 21:46:39 -0400
Subject: [PATCH] Stop updating self.read on every round

---
 src/lib/parser/statement/splitter.rs | 67 +++++++++++++---------------
 1 file changed, 31 insertions(+), 36 deletions(-)

diff --git a/src/lib/parser/statement/splitter.rs b/src/lib/parser/statement/splitter.rs
index abf7df0d..5ca6a628 100644
--- a/src/lib/parser/statement/splitter.rs
+++ b/src/lib/parser/statement/splitter.rs
@@ -115,10 +115,8 @@ impl<'a> StatementSplitter<'a> {
 
     fn get_statement_from(&mut self, input: &'a str) -> StatementVariant<'a> {
         if self.logical == LogicalOp::And {
-            self.logical = LogicalOp::None;
             StatementVariant::And(input)
         } else if self.logical == LogicalOp::Or {
-            self.logical = LogicalOp::None;
             StatementVariant::Or(input)
         } else {
             StatementVariant::Default(input)
@@ -133,13 +131,12 @@ impl<'a> Iterator for StatementSplitter<'a> {
         let start = self.read;
         let mut first_arg_found = false;
         let mut error = None;
-        let mut bytes = self.data.bytes().skip(self.read).peekable();
+        let mut bytes = self.data.bytes().enumerate().skip(self.read).peekable();
         let mut last = None;
 
         bytes.peek()?;
 
-        while let Some(character) = bytes.next() {
-            self.read += 1;
+        while let Some((i, character)) = bytes.next() {
             match character {
                 _ if self.skip => {
                     self.skip = false;
@@ -162,7 +159,7 @@ impl<'a> Iterator for StatementSplitter<'a> {
                 {
                     // If we are just ending the braced section continue as normal
                     if error.is_none() {
-                        error = Some(StatementError::InvalidCharacter(character as char, self.read))
+                        error = Some(StatementError::InvalidCharacter(character as char, i + 1))
                     }
                 }
                 // Toggle quotes and stop matching variables.
@@ -179,8 +176,7 @@ impl<'a> Iterator for StatementSplitter<'a> {
                 b'}' if self.quotes == Quotes::None => {
                     if self.brace_level == 0 {
                         if error.is_none() {
-                            error =
-                                Some(StatementError::InvalidCharacter(character as char, self.read))
+                            error = Some(StatementError::InvalidCharacter(character as char, i + 1))
                         }
                     } else {
                         self.brace_level -= 1;
@@ -189,7 +185,7 @@ impl<'a> Iterator for StatementSplitter<'a> {
                 b'(' if self.math_expr => self.math_paren_level += 1,
                 b'(' if self.method || last == Some(b'$') => {
                     self.variable = false;
-                    if bytes.peek() == Some(&b'(') {
+                    if let Some(&(_, b'(')) = bytes.peek() {
                         self.math_expr = true;
                         // The next character will always be a left paren in this branch;
                         self.math_paren_level = -1;
@@ -203,20 +199,17 @@ impl<'a> Iterator for StatementSplitter<'a> {
                     self.variable = false;
                 }
                 b'(' if error.is_none() && self.quotes == Quotes::None => {
-                    error = Some(StatementError::InvalidCharacter(character as char, self.read))
+                    error = Some(StatementError::InvalidCharacter(character as char, i + 1))
                 }
                 b')' if self.math_expr => {
                     if self.math_paren_level == 0 {
                         match bytes.peek() {
-                            Some(&b')') => {
+                            Some(&(_, b')')) => {
                                 self.math_expr = false;
                                 self.skip = true;
                             }
-                            Some(&next_character) if error.is_none() => {
-                                error = Some(StatementError::InvalidCharacter(
-                                    next_character as char,
-                                    self.read,
-                                ));
+                            Some(&(_, next)) if error.is_none() => {
+                                error = Some(StatementError::InvalidCharacter(next as char, i + 1));
                             }
                             None if error.is_none() => {
                                 error = Some(StatementError::UnterminatedArithmetic)
@@ -232,14 +225,15 @@ impl<'a> Iterator for StatementSplitter<'a> {
                 }
                 b')' if self.paren_level == 0 => {
                     if error.is_none() && self.quotes == Quotes::None {
-                        error = Some(StatementError::InvalidCharacter(character as char, self.read))
+                        error = Some(StatementError::InvalidCharacter(character as char, i + 1))
                     }
                 }
                 b')' => self.paren_level -= 1,
                 b';' if self.quotes == Quotes::None && self.paren_level == 0 => {
-                    let statement = self.get_statement(start, self.read - 1);
+                    let statement = self.get_statement(start, i);
                     self.logical = LogicalOp::None;
 
+                    self.read = i + 1;
                     return match error {
                         Some(error) => Some(Err(error)),
                         None => Some(Ok(statement)),
@@ -251,19 +245,19 @@ impl<'a> Iterator for StatementSplitter<'a> {
                         && last == Some(character) =>
                 {
                     // Detecting if there is a 2nd `&` character
-                    let statement = self.get_statement(start, self.read - 2);
+                    let statement = self.get_statement(start, i - 1);
                     self.logical = if character == b'&' { LogicalOp::And } else { LogicalOp::Or };
+                    self.read = i + 1;
                     return match error {
                         Some(error) => Some(Err(error)),
                         None => Some(Ok(statement)),
                     };
                 }
-                b' ' if !first_arg_found => match self.data[start..self.read - 1].trim() {
+                b' ' if !first_arg_found => match self.data[start..i].trim() {
                     "else" => {
-                        if self.data.len() < self.read + 2
-                            || &self.data[self.read..self.read + 2] != "if"
-                        {
+                        if self.data.len() < i + 2 || &self.data[i + 1..=i + 2] != "if" {
                             self.logical = LogicalOp::None;
+                            self.read = i + 1;
                             return Some(Ok(StatementVariant::Default("else")));
                         }
                     }
@@ -277,6 +271,7 @@ impl<'a> Iterator for StatementSplitter<'a> {
             last = Some(character);
         }
 
+        self.read = self.data.len();
         match error {
             Some(error) => Some(Err(error)),
             None if self.paren_level != 0 => Some(Err(StatementError::UnterminatedSubshell)),
@@ -286,19 +281,19 @@ impl<'a> Iterator for StatementSplitter<'a> {
             None if self.math_expr => Some(Err(StatementError::UnterminatedArithmetic)),
             None => {
                 let output = self.data[start..].trim();
-                if output.is_empty() {
-                    Some(Ok(self.get_statement_from(output)))
-                } else {
-                    match output.as_bytes()[0] {
-                        b'>' | b'<' | b'^' => {
-                            Some(Err(StatementError::ExpectedCommandButFound("redirection")))
-                        }
-                        b'|' => Some(Err(StatementError::ExpectedCommandButFound("pipe"))),
-                        b'&' => Some(Err(StatementError::ExpectedCommandButFound("&"))),
-                        b'*' | b'%' | b'?' | b'{' | b'}' => {
-                            Some(Err(StatementError::IllegalCommandName(String::from(output))))
-                        }
-                        _ => Some(Ok(self.get_statement_from(output))),
+                match output.as_bytes().get(0) {
+                    Some(b'>') | Some(b'<') | Some(b'^') => {
+                        Some(Err(StatementError::ExpectedCommandButFound("redirection")))
+                    }
+                    Some(b'|') => Some(Err(StatementError::ExpectedCommandButFound("pipe"))),
+                    Some(b'&') => Some(Err(StatementError::ExpectedCommandButFound("&"))),
+                    Some(b'*') | Some(b'%') | Some(b'?') | Some(b'{') | Some(b'}') => {
+                        Some(Err(StatementError::IllegalCommandName(String::from(output))))
+                    }
+                    _ => {
+                        let stmt = self.get_statement_from(output);
+                        self.logical = LogicalOp::None;
+                        Some(Ok(stmt))
                     }
                 }
             }
-- 
GitLab