about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBrendan Zabarauskas <bjzaba@yahoo.com.au>2013-05-09 01:38:39 +1000
committerBrendan Zabarauskas <bjzaba@yahoo.com.au>2013-05-15 07:02:43 +1000
commitb9824e18c2b02d74bd1bf646fea5f05477ca5071 (patch)
tree855c8c7f4c9f59d9790a4ee9ac74bf7d0f587735
parentd217174987466010cd8810179c5fdb7ae4a126d0 (diff)
downloadrust-b9824e18c2b02d74bd1bf646fea5f05477ca5071.tar.gz
rust-b9824e18c2b02d74bd1bf646fea5f05477ca5071.zip
Add Scheme-style `cond!` macro to syntax::ext::expand
Addresses issue #6037
-rw-r--r--src/libstd/fun_treemap.rs51
-rw-r--r--src/libstd/std.rc1
-rw-r--r--src/libsyntax/ext/expand.rs36
-rw-r--r--src/test/run-pass/cond-macro-no-default.rs23
-rw-r--r--src/test/run-pass/cond-macro.rs23
5 files changed, 105 insertions, 29 deletions
diff --git a/src/libstd/fun_treemap.rs b/src/libstd/fun_treemap.rs
index 3bffeddbe09..30edd535a88 100644
--- a/src/libstd/fun_treemap.rs
+++ b/src/libstd/fun_treemap.rs
@@ -33,45 +33,40 @@ enum TreeNode<K, V> {
 pub fn init<K, V>() -> Treemap<K, V> { @Empty }
 
 /// Insert a value into the map
-pub fn insert<K:Copy + Eq + Ord,V:Copy>(m: Treemap<K, V>, k: K, v: V)
-  -> Treemap<K, V> {
+pub fn insert<K:Copy + Eq + Ord,V:Copy>(m: Treemap<K, V>, k: K, v: V) -> Treemap<K, V> {
     @match m {
-       @Empty => Node(@k, @v, @Empty, @Empty),
-       @Node(@copy kk, vv, left, right) => {
-         if k < kk {
-             Node(@kk, vv, insert(left, k, v), right)
-         } else if k == kk {
-             Node(@kk, @v, left, right)
-         } else { Node(@kk, vv, left, insert(right, k, v)) }
-       }
-     }
+        @Empty => Node(@k, @v, @Empty, @Empty),
+        @Node(@copy kk, vv, left, right) => cond!(
+            | k <  kk { Node(@kk, vv, insert(left, k, v), right) }
+            | k == kk { Node(@kk, @v, left, right)               }
+            _         { Node(@kk, vv, left, insert(right, k, v)) }
+        )
+    }
 }
 
 /// Find a value based on the key
 pub fn find<K:Eq + Ord,V:Copy>(m: Treemap<K, V>, k: K) -> Option<V> {
     match *m {
-      Empty => None,
-      Node(@ref kk, @copy v, left, right) => {
-        if k == *kk {
-            Some(v)
-        } else if k < *kk { find(left, k) } else { find(right, k) }
-      }
+        Empty => None,
+        Node(@ref kk, @copy v, left, right) => cond!(
+            | k == *kk { Some(v)        }
+            | k <  *kk { find(left, k)  }
+            _          { find(right, k) }
+        )
     }
 }
 
 /// Visit all pairs in the map in order.
 pub fn traverse<K, V: Copy>(m: Treemap<K, V>, f: &fn(&K, &V)) {
     match *m {
-      Empty => (),
-      /*
-        Previously, this had what looked like redundant
-        matches to me, so I changed it. but that may be a
-        de-optimization -- tjc
-       */
-      Node(@ref k, @ref v, left, right) => {
-        traverse(left, f);
-        f(k, v);
-        traverse(right, f);
-      }
+        Empty => (),
+        // Previously, this had what looked like redundant
+        // matches to me, so I changed it. but that may be a
+        // de-optimization -- tjc
+        Node(@ref k, @ref v, left, right) => {
+            traverse(left, f);
+            f(k, v);
+            traverse(right, f);
+        }
     }
 }
diff --git a/src/libstd/std.rc b/src/libstd/std.rc
index 915aab59a71..d29791449b6 100644
--- a/src/libstd/std.rc
+++ b/src/libstd/std.rc
@@ -63,6 +63,7 @@ pub mod flatpipes;
 
 pub mod bitv;
 pub mod deque;
+#[cfg(not(stage0))]
 pub mod fun_treemap;
 pub mod list;
 pub mod priority_queue;
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 9afbe1e479d..ad1da0a8685 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -542,7 +542,41 @@ pub fn core_macros() -> ~str {
         }
     )
 
-
+    //
+    // A scheme-style conditional that helps to improve code clarity in some instances when
+    // the `if`, `else if`, and `else` keywords obscure predicates undesirably.
+    //
+    // # Example
+    //
+    // ~~~
+    // let clamped =
+    //     if x > mx { mx }
+    //     else if x < mn { mn }
+    //     else { x };
+    // ~~~
+    //
+    // Using `cond!`, the above could be written as:
+    //
+    // ~~~
+    // let clamped = cond!(
+    //     | x > mx { mx }
+    //     | x < mn { mn }
+    //     _        { x  }
+    // );
+    // ~~~
+    //
+    // The optional default case is denoted by `_`.
+    //
+    macro_rules! cond (
+        ($( | $pred:expr $body:block)+ _ $default:block ) => (
+            $(if $pred $body else)+
+            $default
+        );
+        // for if the default case was ommitted
+        ( $( | $pred:expr $body:block )+ ) => (
+            $(if $pred $body)else+
+        );
+    )
 }";
 }
 
diff --git a/src/test/run-pass/cond-macro-no-default.rs b/src/test/run-pass/cond-macro-no-default.rs
new file mode 100644
index 00000000000..b8280c30e08
--- /dev/null
+++ b/src/test/run-pass/cond-macro-no-default.rs
@@ -0,0 +1,23 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn clamp<T:Copy + Ord + Signed>(x: T, mn: T, mx: T) -> T {
+    cond!(
+        | x > mx { return mx; }
+        | x < mn { return mn; }
+    )
+    return x;
+}
+
+fn main() {
+    assert_eq!(clamp(1, 2, 4), 2);
+    assert_eq!(clamp(8, 2, 4), 4);
+    assert_eq!(clamp(3, 2, 4), 3);
+}
\ No newline at end of file
diff --git a/src/test/run-pass/cond-macro.rs b/src/test/run-pass/cond-macro.rs
new file mode 100644
index 00000000000..ebe1cbbfd82
--- /dev/null
+++ b/src/test/run-pass/cond-macro.rs
@@ -0,0 +1,23 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn clamp<T:Copy + Ord + Signed>(x: T, mn: T, mx: T) -> T {
+    cond!(
+        | x > mx { mx }
+        | x < mn { mn }
+        _        { x  }
+    )
+}
+
+fn main() {
+    assert_eq!(clamp(1, 2, 4), 2);
+    assert_eq!(clamp(8, 2, 4), 4);
+    assert_eq!(clamp(3, 2, 4), 3);
+}
\ No newline at end of file