Repository: reubeno/brush
Pull request #418 (2025-03-20 10:51:10)

fix: parse '#' as char only if inside a variable expansion
Only in arithmetic expressions '#' is a valid token, in other contexts it is treated as a comment, and all following characters will be ignored by the tokenizer.

Closes: #408


Patch:
diff --git a/brush-parser/src/tokenizer.rs b/brush-parser/src/tokenizer.rs
index 5d7d9df..a0c476c 100644
--- a/brush-parser/src/tokenizer.rs
+++ b/brush-parser/src/tokenizer.rs
@@ -1091,11 +1091,11 @@ impl<'a, R: ?Sized + std::io::BufRead> Tokenizer<'a, R> {
                 self.consume_char()?;
             }
             //
-            // N.B. We need to remember if we were recursively called, say in a command
-            // substitution; in that case we won't think a token was started but... we'd
-            // be wrong.
+            // N.B. We need to remember if we were recursively called in a variable
+            // expansion expression; in that case we won't think a token was started but...
+            // we'd be wrong.
             else if !state.token_is_operator
-                && (state.started_token() || terminating_char.is_some())
+                && (state.started_token() || matches!(terminating_char, Some('}')))
             {
                 self.consume_char()?;
                 state.append_char(c);
@@ -1115,7 +1115,6 @@ impl<'a, R: ?Sized + std::io::BufRead> Tokenizer<'a, R> {
                         }
                     };
                 }
-
                 // Re-start loop as if the comment never happened.
                 continue;
             //


Test patch:
diff --git a/brush-shell/tests/cases/command_substitution.yaml b/brush-shell/tests/cases/command_substitution.yaml
new file mode 100644
index 0000000..6347298
--- /dev/null
+++ b/brush-shell/tests/cases/command_substitution.yaml
@@ -0,0 +1,73 @@
+name: "Command substitution"
+cases:
+  - name: "Ignore single quote in comment in command substitution"
+    stdin: |
+      var=$(
+        # I'm
+        echo "Batman"
+      )
+      echo $var
+
+  - name: "Ignore double quote in comment in command substitution"
+    stdin: |
+      var=$(
+        # This " is not being
+        echo "parsed"
+      )
+      echo $var
+
+  - name: "Ignore parantheses in comment in command substitution"
+    stdin: |
+      var=$(
+        # :(
+        echo "Sad"
+      )
+      echo $var
+
+  - name: "Ignore dollar in comment in command substitution"
+    stdin: |
+      var=$(
+        #               $
+        echo "Mr. Crabs ^"
+      )
+      echo $var
+
+  - name: "Positional parameter count not mistaken for comment"
+    stdin: |
+      echo $(echo $#)
+
+  - name: "Ignore single quote in comment in command substitution (backticks)"
+    stdin: |
+      var=`
+        # I'm
+        echo "Batman"
+      `
+      echo $var
+
+  - name: "Ignore double quote in comment in command substitution (backticks)"
+    stdin: |
+      var=`
+        # This " is not being
+        echo "parsed"
+      `
+      echo $var
+
+  - name: "Ignore parantheses in comment in command substitution (backticks)"
+    stdin: |
+      var=`
+        # :(
+        echo "Sad"
+      `
+      echo $var
+
+  - name: "Ignore dollar in comment in command substitution (backticks)"
+    stdin: |
+      var=`
+        #               $
+        echo "Mr. Crabs ^"
+      `
+      echo $var
+
+  - name: "Positional parameter count not mistaken for comment (backticks)"
+    stdin: |
+      echo `echo $#`
diff --git a/brush-shell/tests/cases/list.yaml b/brush-shell/tests/cases/list.yaml
new file mode 100644
index 0000000..17dac4d
--- /dev/null
+++ b/brush-shell/tests/cases/list.yaml
@@ -0,0 +1,30 @@
+name: "List"
+cases:
+  - name: "Ignore single quote in comment in list"
+    stdin: |
+      (
+        # I'm
+        echo "Batman"
+      )
+
+  - name: "Ignore double quote in comment in list"
+    stdin: |
+      (
+        # This " is not being
+        echo "parsed"
+      )
+
+  - name: "Ignore parantheses in comment in list"
+    stdin: |
+      (
+        # :(
+        echo "Sad"
+      )
+
+  - name: "Ignore dollar in comment in list"
+    stdin: |
+      (
+        #               $
+        echo "Mr. Crabs ^"
+      )
+