about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPaul Stansifer <paul.stansifer@gmail.com>2011-08-02 12:22:17 -0700
committerPaul Stansifer <paul.stansifer@gmail.com>2011-08-02 14:46:02 -0700
commitab4764520c41a5ef5e0987b69e1673445bc40d0f (patch)
treeef996f561fff859f35da54758e43afc2228a6de2
parentea2a9681460c112e968a54f0d3378a0fab40e7b1 (diff)
downloadrust-ab4764520c41a5ef5e0987b69e1673445bc40d0f.tar.gz
rust-ab4764520c41a5ef5e0987b69e1673445bc40d0f.zip
Allow patterns of the form `[a, b, c ...] to be matched and transcribed.
-rw-r--r--src/comp/syntax/ext/simplext.rs142
-rw-r--r--src/test/run-pass/macro-2.rs4
-rw-r--r--src/test/run-pass/macro-3.rs4
-rw-r--r--src/test/run-pass/macro-by-example-1.rs4
-rw-r--r--src/test/run-pass/macro-by-example-2.rs12
-rw-r--r--src/test/run-pass/macro.rs4
6 files changed, 99 insertions, 71 deletions
diff --git a/src/comp/syntax/ext/simplext.rs b/src/comp/syntax/ext/simplext.rs
index d7de173e5e3..4e547094544 100644
--- a/src/comp/syntax/ext/simplext.rs
+++ b/src/comp/syntax/ext/simplext.rs
@@ -93,19 +93,20 @@ fn match_error(cx: &ext_ctxt, m: &matchable, expected: &str) -> ! {
 type match_result = option::t[arb_depth[matchable]];
 type selector = fn(&matchable) -> match_result ;
 
-fn elts_to_ell(cx: &ext_ctxt, elts: &(@expr)[]) -> option::t[@expr] {
+fn elts_to_ell(cx: &ext_ctxt, elts: &(@expr)[])
+    -> {fixed: (@expr)[], rep: option::t[@expr]} {
     let idx: uint = 0u;
     for elt: @expr  in elts {
         alt elt.node {
           expr_mac(m) {
             alt m.node {
               ast::mac_ellipsis. {
-                if idx != 1u || ivec::len(elts) != 2u {
-                    cx.span_fatal(m.span,
-                                  "Ellpisis may only appear" +
-                                      " after exactly 1 item.");
+                let last = ivec::len(elts) - 1u;
+                if idx != last {
+                    cx.span_fatal(m.span, "ellipses must occur last");
                 }
-                ret some(elts.(0));
+                ret {fixed: ivec::slice(elts, 0u, last - 1u),
+                     rep: some(elts.(last - 1u))};
               }
               _ { }
             }
@@ -114,7 +115,7 @@ fn elts_to_ell(cx: &ext_ctxt, elts: &(@expr)[]) -> option::t[@expr] {
         }
         idx += 1u;
     }
-    ret none;
+    ret {fixed: elts, rep: none};
 }
 
 fn option_flatten_map[T, U](f: &fn(&T) -> option::t[U] , v: &vec[T]) ->
@@ -271,57 +272,60 @@ iter free_vars(b: &bindings, e: @expr) -> ident {
 
 /* handle sequences (anywhere in the AST) of exprs, either real or ...ed */
 fn transcribe_exprs(cx: &ext_ctxt, b: &bindings, idx_path: @mutable vec[uint],
-                    recur: fn(&@expr) -> @expr , exprs: (@expr)[]) ->
-   (@expr)[] {
+                    recur: fn(&@expr) -> @expr , exprs: (@expr)[])
+    -> (@expr)[] {
     alt elts_to_ell(cx, exprs) {
-      some(repeat_me) {
-        let repeat: option::t[{rep_count: uint, name: ident}] = none;
-        /* we need to walk over all the free vars in lockstep, except for
-        the leaves, which are just duplicated */
-        for each fv: ident  in free_vars(b, repeat_me) {
-            let cur_pos = follow(b.get(fv), idx_path);
-            alt cur_pos {
-              leaf(_) { }
-              seq(ms, _) {
-                alt repeat {
-                  none. {
-                    repeat = some({rep_count: vec::len(ms), name: fv});
-                  }
-                  some({rep_count: old_len, name: old_name}) {
-                    let len = vec::len(ms);
-                    if old_len != len {
-                        cx.span_fatal(repeat_me.span,
-                                      #fmt("'%s' occurs %u times, but ", fv,
-                                           len) +
-                                          #fmt("'%s' occurs %u times",
-                                               old_name, old_len));
+      {fixed: fixed, rep: repeat_me_maybe} {
+        let res = ivec::map(recur, fixed);
+        alt repeat_me_maybe {
+          none. {}
+          some(repeat_me) {
+            let repeat: option::t[{rep_count: uint, name: ident}] = none;
+            /* we need to walk over all the free vars in lockstep, except for
+            the leaves, which are just duplicated */
+            for each fv: ident  in free_vars(b, repeat_me) {
+                let cur_pos = follow(b.get(fv), idx_path);
+                alt cur_pos {
+                  leaf(_) { }
+                  seq(ms, _) {
+                    alt repeat {
+                      none. {
+                        repeat = some({rep_count: vec::len(ms), name: fv});
+                      }
+                      some({rep_count: old_len, name: old_name}) {
+                        let len = vec::len(ms);
+                        if old_len != len {
+                            let msg = #fmt("'%s' occurs %u times, but ", fv,
+                                           len) + #fmt("'%s' occurs %u times",
+                                                       old_name, old_len);
+                            cx.span_fatal(repeat_me.span, msg);
+                        }
+                      }
                     }
                   }
                 }
-              }
             }
-        }
-        let res = ~[];
-        alt repeat {
-          none. {
-            cx.span_fatal(repeat_me.span,
-                          "'...' surrounds an expression without any" +
+            alt repeat {
+              none. {
+                cx.span_fatal(repeat_me.span,
+                              "'...' surrounds an expression without any" +
                               " repeating syntax variables");
-          }
-          some({rep_count: rc, _}) {
-            /* Whew, we now know how how many times to repeat */
-            let idx: uint = 0u;
-            while idx < rc {
-                vec::push(*idx_path, idx);
-                res += ~[recur(repeat_me)]; // whew!
-                vec::pop(*idx_path);
-                idx += 1u;
+              }
+              some({rep_count: rc, _}) {
+                /* Whew, we now know how how many times to repeat */
+                let idx: uint = 0u;
+                while idx < rc {
+                    vec::push(*idx_path, idx);
+                    res += ~[recur(repeat_me)]; // whew!
+                    vec::pop(*idx_path);
+                    idx += 1u;
+                }
+              }
             }
           }
         }
         ret res;
       }
-      none. { ret ivec::map(recur, exprs); }
     }
 }
 
@@ -436,8 +440,15 @@ fn p_t_s_rec(cx: &ext_ctxt, m: &matchable, s: &selector, b: &binders) {
           expr_path(p_pth) { p_t_s_r_path(cx, p_pth, s, b); }
           expr_vec(p_elts, _, _) {
             alt elts_to_ell(cx, p_elts) {
-              some(repeat_me) { p_t_s_r_ellipses(cx, repeat_me, s, b); }
-              none. { p_t_s_r_actual_vector(cx, p_elts, s, b); }
+              {fixed: fixed, rep: some(repeat_me)} {
+                if(ivec::len(fixed) > 0u) {
+                    p_t_s_r_actual_vector(cx, fixed, true, s, b);
+                }
+                p_t_s_r_ellipses(cx, repeat_me, ivec::len(fixed), s, b);
+              }
+              {fixed: fixed, rep: none.} {
+                p_t_s_r_actual_vector(cx, fixed, false, s, b);
+              }
             }
           }
 
@@ -575,20 +586,23 @@ fn ivec_to_vec[T](v: &T[]) -> vec[T] {
     ret rs;
 }
 
-fn p_t_s_r_ellipses(cx: &ext_ctxt, repeat_me: @expr, s: &selector,
-                    b: &binders) {
-    fn select(cx: &ext_ctxt, repeat_me: @expr, m: &matchable) ->
+fn p_t_s_r_ellipses(cx: &ext_ctxt, repeat_me: @expr, offset: uint,
+                    s: &selector, b: &binders) {
+    fn select(cx: &ext_ctxt, repeat_me: @expr, offset: uint, m: &matchable) ->
         match_result {
         ret alt m {
               match_expr(e) {
                 alt e.node {
                   expr_vec(arg_elts, _, _) {
-                    let elts =
-                        ivec::map(leaf, ivec::map(match_expr, arg_elts));
-
+                    let elts = [];
+                    let idx = offset;
+                    while idx < ivec::len(arg_elts) {
+                        elts += [leaf(match_expr(arg_elts.(idx)))];
+                        idx += 1u;
+                    }
                     // using repeat_me.span is a little wacky, but the
                     // error we want to report is one in the macro def
-                    some(seq(ivec_to_vec(elts), repeat_me.span))
+                    some(seq(elts, repeat_me.span))
                   }
                   _ { none }
                 }
@@ -597,17 +611,20 @@ fn p_t_s_r_ellipses(cx: &ext_ctxt, repeat_me: @expr, s: &selector,
             }
     }
     p_t_s_rec(cx, match_expr(repeat_me),
-              compose_sels(s, bind select(cx, repeat_me, _)), b);
+              compose_sels(s, bind select(cx, repeat_me, offset, _)), b);
 }
 
-fn p_t_s_r_actual_vector(cx: &ext_ctxt, elts: (@expr)[], s: &selector,
-                         b: &binders) {
-    fn len_select(cx: &ext_ctxt, m: &matchable, len: uint) -> match_result {
+fn p_t_s_r_actual_vector(cx: &ext_ctxt, elts: (@expr)[], repeat_after: bool,
+                         s: &selector, b: &binders) {
+    fn len_select(cx: &ext_ctxt, m: &matchable, repeat_after: bool, len: uint)
+        -> match_result {
         ret alt m {
               match_expr(e) {
                 alt e.node {
                   expr_vec(arg_elts, _, _) {
-                    if ivec::len(arg_elts) == len {
+                    let actual_len = ivec::len(arg_elts);
+                    if (repeat_after && actual_len >= len)
+                        || actual_len == len {
                         some(leaf(match_exact))
                     } else { none }
                   }
@@ -618,7 +635,8 @@ fn p_t_s_r_actual_vector(cx: &ext_ctxt, elts: (@expr)[], s: &selector,
             }
     }
     b.literal_ast_matchers +=
-        ~[compose_sels(s, bind len_select(cx, _, ivec::len(elts)))];
+        ~[compose_sels(s, bind len_select(cx, _, repeat_after,
+                                          ivec::len(elts)))];
 
 
     let idx: uint = 0u;
diff --git a/src/test/run-pass/macro-2.rs b/src/test/run-pass/macro-2.rs
index 0cd21a830eb..5a3973c79e3 100644
--- a/src/test/run-pass/macro-2.rs
+++ b/src/test/run-pass/macro-2.rs
@@ -1,7 +1,7 @@
 // xfail-stage0
 
 fn main() {
-  #macro([#mylambda(x,body), {fn f(x: int) -> int { ret body }; f}]);
+  #macro([#mylambda[x,body], {fn f(x: int) -> int { ret body }; f}]);
 
-  assert(#mylambda(y,y*2)(8) == 16);
+  assert(#mylambda[y,y*2](8) == 16);
 }
\ No newline at end of file
diff --git a/src/test/run-pass/macro-3.rs b/src/test/run-pass/macro-3.rs
index c14d8943083..ab4599327b9 100644
--- a/src/test/run-pass/macro-3.rs
+++ b/src/test/run-pass/macro-3.rs
@@ -1,7 +1,7 @@
 // xfail-stage0
 
 fn main() {
-  #macro([#trivial(), 1*2*4*2*1]);
+  #macro([#trivial[], 1*2*4*2*1]);
 
-  assert(#trivial() == 16);
+  assert(#trivial[] == 16);
 }
diff --git a/src/test/run-pass/macro-by-example-1.rs b/src/test/run-pass/macro-by-example-1.rs
index ef127049e09..08e5c4e249f 100644
--- a/src/test/run-pass/macro-by-example-1.rs
+++ b/src/test/run-pass/macro-by-example-1.rs
@@ -1,7 +1,7 @@
 fn main() {
-    #macro([#apply(f, [x, ...]), f(x, ...)]);
+    #macro([#apply[f, [x, ...]], f(x, ...)]);
 
     fn add(a: int, b: int) -> int { ret a + b; }
 
-    assert (#apply(add, [1, 15]) == 16);
+    assert (#apply[add, [1, 15]] == 16);
 }
\ No newline at end of file
diff --git a/src/test/run-pass/macro-by-example-2.rs b/src/test/run-pass/macro-by-example-2.rs
index c6bcc9323f8..382d06be37b 100644
--- a/src/test/run-pass/macro-by-example-2.rs
+++ b/src/test/run-pass/macro-by-example-2.rs
@@ -31,6 +31,16 @@ fn main() {
             }]);
 
 
-    assert ((#lambda[i, #<uint>, i + 4u, #<uint>])(12u) == 16u)
+    assert ((#lambda[i, #<uint>, i + 4u, #<uint>])(12u) == 16u);
+
+    #macro[[#sum[x, xs, ...], x + #sum[xs, ...]],
+           [#sum[], 0]];
+
+    assert (#sum[1,2,3,4] == 10);
+
+
+    #macro[[#transcr_mixed[a, as, ...], #sum[6, as, ...] * a]];
+
+    assert (#transcr_mixed[10, 5, 4, 3, 2, 1] == 210);
 
 }
\ No newline at end of file
diff --git a/src/test/run-pass/macro.rs b/src/test/run-pass/macro.rs
index f82e37deea2..9f001e93d2f 100644
--- a/src/test/run-pass/macro.rs
+++ b/src/test/run-pass/macro.rs
@@ -1,6 +1,6 @@
 // xfail-stage0
 
 fn main() {
-  #macro([#m1(a), a*4]);
-  assert (#m1(2) == 8);
+  #macro[[#m1[a], a*4]];
+  assert (#m1[2] == 8);
 }