From 0117fc920e84d877c014209aeb3fd2db87f2da67 Mon Sep 17 00:00:00 2001
From: Michael Aaron Murphy <mmstickman@gmail.com>
Date: Mon, 17 Jul 2017 17:05:42 -0400
Subject: [PATCH] Implement Brace Parsing in pipeline::Collector

---
 examples/fibonacci.ion  |  2 ++
 src/parser/pipelines.rs | 19 ++++++++++++++++++-
 2 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/examples/fibonacci.ion b/examples/fibonacci.ion
index 94cee368..4274a701 100644
--- a/examples/fibonacci.ion
+++ b/examples/fibonacci.ion
@@ -7,6 +7,8 @@ fn fib n
             let temp = $output
             let output += $previous
             let previous = $temp
+            # This also works, but has a higher performance penalty:
+            # let output previous = $((output + previous)) $output
         end
         echo $output
     end
diff --git a/src/parser/pipelines.rs b/src/parser/pipelines.rs
index bc59a023..d2107f85 100644
--- a/src/parser/pipelines.rs
+++ b/src/parser/pipelines.rs
@@ -73,10 +73,11 @@ impl<'a> Collector<'a> {
         // not sure of a better solution
         let mut array_level = 0;
         let mut proc_level = 0;
+        let mut brace_level = 0;
         let mut start = None;
         let mut end = None;
 
-        macro_rules! is_toplevel { () => (array_level == 0 && proc_level == 0) }
+        macro_rules! is_toplevel { () => (array_level + proc_level + brace_level == 0) }
 
         // Skip over any leading whitespace
         while let Some(&(_, b)) = bytes.peek() {
@@ -93,6 +94,8 @@ impl<'a> Collector<'a> {
                 b')' => { proc_level -= 1; bytes.next(); }
                 b'[' => { array_level += 1; bytes.next(); }
                 b']' => { array_level -= 1; bytes.next(); }
+                b'{' => { brace_level += 1; bytes.next(); }
+                b'}' => { brace_level -= 1; bytes.next();}
                 // This is a tricky one: we only end the argment if `^` is followed by a
                 // redirection character
                 b'^' => if is_toplevel!() {
@@ -142,6 +145,9 @@ impl<'a> Collector<'a> {
         if array_level > 0 {
             return Err("ion: syntax error: unmatched left bracket");
         }
+        if brace_level > 0 {
+            return Err("ion: syntax error: unmatched left brace");
+        }
         if proc_level < 0 {
             return Err("ion: syntax error: extra right paren(s)");
         }
@@ -344,6 +350,17 @@ mod tests {
         }
     }
 
+    #[test]
+    fn braces() {
+        if let Statement::Pipeline(pipeline) = parse("echo {a b} {a {b c}}") {
+            let jobs = pipeline.jobs;
+            assert_eq!("{a b}", jobs[0].args[1]);
+            assert_eq!("{a {b c}}", jobs[0].args[2]);
+        } else {
+            assert!(false);
+        }
+    }
+
     #[test]
     fn methods() {
         if let Statement::Pipeline(pipeline) = parse("echo @split(var, ', ') $join(array, ',')") {
-- 
GitLab