about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-02-19 09:14:33 -0800
committerbors <bors@rust-lang.org>2013-02-19 09:14:33 -0800
commitf68335113bf277f171494abb62a31293311f80c8 (patch)
treea790a66032447ff99658c7fe4525881c182170f6
parent2ec958db5ae37f193d4d632635818241b134a617 (diff)
parentaa284de1fc246b55fb53783ded3e9786e04b03d0 (diff)
downloadrust-f68335113bf277f171494abb62a31293311f80c8.tar.gz
rust-f68335113bf277f171494abb62a31293311f80c8.zip
auto merge of #5002 : catamorphism/rust/one-tuples, r=graydon
r? @graydon - This is for greater uniformity (for example, macros that generate
tuples). rustc already supported 1-tuple patterns, but there was no
way to construct a 1-tuple term.

@graydon , as far as your comment on #4898 - it did turn out to be solvable inside the macro (since @luqmana already fixed it using structs instead), but I still think it's a good idea to allow 1-tuples, for uniformity. I don't think anyone is likely to trip over it, and I'm not too worried that it changes the amount of ambiguity.
-rw-r--r--src/libcore/to_str.rs2
-rw-r--r--src/libcore/tuple.rs2
-rw-r--r--src/libsyntax/parse/parser.rs36
-rw-r--r--src/libsyntax/print/pprust.rs9
-rw-r--r--src/test/run-pass/one-tuple.rs24
-rw-r--r--src/test/run-pass/reflect-visit-data.rs7
6 files changed, 69 insertions, 11 deletions
diff --git a/src/libcore/to_str.rs b/src/libcore/to_str.rs
index e545f6567ec..4cccc1d2638 100644
--- a/src/libcore/to_str.rs
+++ b/src/libcore/to_str.rs
@@ -43,6 +43,8 @@ impl ToStr for @str {
     pure fn to_str(&self) -> ~str { ::str::from_slice(*self) }
 }
 
+// FIXME #4898: impl for one-tuples
+
 impl<A: ToStr, B: ToStr> ToStr for (A, B) {
     #[inline(always)]
     pure fn to_str(&self) -> ~str {
diff --git a/src/libcore/tuple.rs b/src/libcore/tuple.rs
index 23235104e9f..e49c1d26a06 100644
--- a/src/libcore/tuple.rs
+++ b/src/libcore/tuple.rs
@@ -111,6 +111,8 @@ impl<A: Copy, B: Copy> ExtendedTupleOps<A,B> for (~[A], ~[B]) {
     }
 }
 
+// FIXME #4898: impl for one-tuples
+
 #[cfg(notest)]
 impl<A: Eq, B: Eq> Eq for (A, B) {
     #[inline(always)]
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index fa51d4c29d2..e5b3024d3dc 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -576,12 +576,21 @@ pub impl Parser {
                 self.bump();
                 ty_nil
             } else {
+                // (t) is a parenthesized ty
+                // (t,) is the type of a tuple with only one field,
+                // of type t
                 let mut ts = ~[self.parse_ty(false)];
+                let mut one_tuple = false;
                 while self.token == token::COMMA {
                     self.bump();
-                    ts.push(self.parse_ty(false));
+                    if self.token != token::RPAREN {
+                        ts.push(self.parse_ty(false));
+                    }
+                    else {
+                        one_tuple = true;
+                    }
                 }
-                let t = if vec::len(ts) == 1u { ts[0].node }
+                let t = if ts.len() == 1 && !one_tuple { ts[0].node }
                 else { ty_tup(ts) };
                 self.expect(token::RPAREN);
                 t
@@ -1061,6 +1070,9 @@ pub impl Parser {
 
         if self.token == token::LPAREN {
             self.bump();
+            // (e) is parenthesized e
+            // (e,) is a tuple with only one field, e
+            let mut one_tuple = false;
             if self.token == token::RPAREN {
                 hi = self.span.hi;
                 self.bump();
@@ -1069,12 +1081,18 @@ pub impl Parser {
             }
             let mut es = ~[self.parse_expr()];
             while self.token == token::COMMA {
-                self.bump(); es.push(self.parse_expr());
+                self.bump();
+                if self.token != token::RPAREN {
+                    es.push(self.parse_expr());
+                }
+                else {
+                    one_tuple = true;
+                }
             }
             hi = self.span.hi;
             self.expect(token::RPAREN);
 
-            return if es.len() == 1 {
+            return if es.len() == 1 && !one_tuple {
                 self.mk_expr(lo, self.span.hi, expr_paren(es[0]))
             }
             else {
@@ -2158,11 +2176,13 @@ pub impl Parser {
                 pat = pat_lit(expr);
             } else {
                 let mut fields = ~[self.parse_pat(refutable)];
-                while self.token == token::COMMA {
-                    self.bump();
-                    fields.push(self.parse_pat(refutable));
+                if self.look_ahead(1) != token::RPAREN {
+                    while self.token == token::COMMA {
+                        self.bump();
+                        fields.push(self.parse_pat(refutable));
+                    }
                 }
-                if vec::len(fields) == 1u { self.expect(token::COMMA); }
+                if fields.len() == 1 { self.expect(token::COMMA); }
                 hi = self.span.hi;
                 self.expect(token::RPAREN);
                 pat = pat_tup(fields);
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index d5cba4312b7..c091c436381 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -414,6 +414,9 @@ pub fn print_type_ex(s: @ps, &&ty: @ast::Ty, print_colons: bool) {
       ast::ty_tup(elts) => {
         popen(s);
         commasep(s, inconsistent, elts, print_type);
+        if elts.len() == 1 {
+            word(s.s, ~",");
+        }
         pclose(s);
       }
       ast::ty_bare_fn(f) => {
@@ -1199,6 +1202,9 @@ pub fn print_expr(s: @ps, &&expr: @ast::expr) {
       ast::expr_tup(exprs) => {
         popen(s);
         commasep_exprs(s, inconsistent, exprs);
+        if exprs.len() == 1 {
+            word(s.s, ~",");
+        }
         pclose(s);
       }
       ast::expr_call(func, args, sugar) => {
@@ -1634,6 +1640,9 @@ pub fn print_pat(s: @ps, &&pat: @ast::pat, refutable: bool) {
       ast::pat_tup(elts) => {
         popen(s);
         commasep(s, inconsistent, elts, |s, p| print_pat(s, p, refutable));
+        if elts.len() == 1 {
+            word(s.s, ~",");
+        }
         pclose(s);
       }
       ast::pat_box(inner) => {
diff --git a/src/test/run-pass/one-tuple.rs b/src/test/run-pass/one-tuple.rs
new file mode 100644
index 00000000000..9d01fbface0
--- /dev/null
+++ b/src/test/run-pass/one-tuple.rs
@@ -0,0 +1,24 @@
+// 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.
+
+// Why one-tuples? Because macros.
+
+fn main() {
+    match ('c',) {
+        (x,) => {
+            assert x == 'c';
+        }
+    }
+    // test the 1-tuple type too
+    let x: (char,) = ('d',);
+    let (y,) = x;
+    assert y == 'd';
+}
+
diff --git a/src/test/run-pass/reflect-visit-data.rs b/src/test/run-pass/reflect-visit-data.rs
index d6470ad72b0..3694ffdfde0 100644
--- a/src/test/run-pass/reflect-visit-data.rs
+++ b/src/test/run-pass/reflect-visit-data.rs
@@ -636,11 +636,12 @@ struct Triple { x: int, y: int, z: int }
 
 pub fn main() {
     unsafe {
-        let r = (1,2,3,true,false, Triple {x:5,y:4,z:3});
+        let r = (1,2,3,true,false, Triple {x:5,y:4,z:3}, (12,));
         let p = ptr::addr_of(&r) as *c_void;
         let u = my_visitor(@Stuff {mut ptr1: p,
                              mut ptr2: p,
-                             mut vals: ~[]});
+                             mut vals: ~[]
+                                  });
         let v = ptr_visit_adaptor(Inner {inner: u});
         let td = get_tydesc_for(r);
         unsafe { error!("tydesc sz: %u, align: %u",
@@ -653,7 +654,7 @@ pub fn main() {
         }
         error!("%?", copy u.vals);
         assert u.vals == ~[
-            ~"1", ~"2", ~"3", ~"true", ~"false", ~"5", ~"4", ~"3"
+            ~"1", ~"2", ~"3", ~"true", ~"false", ~"5", ~"4", ~"3", ~"12"
         ];
     }
  }