about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMarijn Haverbeke <marijnh@gmail.com>2011-08-15 13:15:19 +0200
committerMarijn Haverbeke <marijnh@gmail.com>2011-08-15 13:20:16 +0200
commit3f127e397fdba5b982603aaab034f6e9aa0992bb (patch)
tree07fc3b6fb6fc599b2ce38fa481c507ea612f9471
parent1ee24d31e139683a93c6afa93689f5a4122341be (diff)
downloadrust-3f127e397fdba5b982603aaab034f6e9aa0992bb.tar.gz
rust-3f127e397fdba5b982603aaab034f6e9aa0992bb.zip
Add tuple patterns
-rw-r--r--src/comp/middle/check_alt.rs12
-rw-r--r--src/comp/middle/resolve.rs33
-rw-r--r--src/comp/middle/trans_alt.rs46
-rw-r--r--src/comp/middle/typeck.rs25
-rw-r--r--src/comp/syntax/ast.rs20
-rw-r--r--src/comp/syntax/fold.rs3
-rw-r--r--src/comp/syntax/parse/parser.rs18
-rw-r--r--src/comp/syntax/print/pprust.rs5
-rw-r--r--src/comp/syntax/visit.rs3
9 files changed, 130 insertions, 35 deletions
diff --git a/src/comp/middle/check_alt.rs b/src/comp/middle/check_alt.rs
index b3feeeb3fec..be8a9aba102 100644
--- a/src/comp/middle/check_alt.rs
+++ b/src/comp/middle/check_alt.rs
@@ -84,6 +84,12 @@ fn pattern_supersedes(tcx: &ty::ctxt, a: &@pat, b: &@pat) -> bool {
           _ { ret false; }
         }
       }
+      pat_tup(suba) {
+        alt b.node {
+          pat_tup(subb) { ret patterns_supersede(tcx, suba, subb); }
+          _ { ret false; }
+        }
+      }
       pat_box(suba) {
         alt b.node {
           pat_box(subb) { ret pattern_supersedes(tcx, suba, subb); }
@@ -112,6 +118,12 @@ fn is_refutable(tcx: &ty::ctxt, pat: &@pat) -> bool {
         }
         ret false;
       }
+      pat_tup(elts) {
+        for elt in elts {
+            if is_refutable(tcx, elt) { ret true; }
+        }
+        ret false;
+      }
       pat_tag(_, args) {
         let vdef = variant_def_ids(tcx.def_map.get(pat.id));
         if std::ivec::len(ty::tag_variants(tcx, vdef.tg)) != 1u {
diff --git a/src/comp/middle/resolve.rs b/src/comp/middle/resolve.rs
index c97c2f9eb0f..9a6a6cb088f 100644
--- a/src/comp/middle/resolve.rs
+++ b/src/comp/middle/resolve.rs
@@ -644,7 +644,7 @@ fn lookup_in_scope(e: &env, sc: scopes, sp: &span, name: &ident,
           }
           scope_loop(local) {
             if ns == ns_value {
-                alt lookup_in_pat(name, *local.node.pat) {
+                alt lookup_in_pat(name, local.node.pat) {
                   some(did) { ret some(ast::def_local(did)); }
                   _ {}
                 }
@@ -654,7 +654,7 @@ fn lookup_in_scope(e: &env, sc: scopes, sp: &span, name: &ident,
           scope_arm(a) {
             if ns == ns_value {
                 ret option::map(ast::def_binding,
-                                lookup_in_pat(name, *a.pats.(0)));
+                                lookup_in_pat(name, a.pats.(0)));
             }
           }
         }
@@ -711,30 +711,15 @@ fn lookup_in_ty_params(name: &ident, ty_params: &[ast::ty_param]) ->
     ret none[def];
 }
 
-fn lookup_in_pat(name: &ident, pat: &ast::pat) -> option::t[def_id] {
-    alt pat.node {
-      ast::pat_bind(p_name) {
+fn lookup_in_pat(name: &ident, pat: &@ast::pat) -> option::t[def_id] {
+    let found = none;
+    for each bound in ast::pat_bindings(pat) {
+        let p_name = alt bound.node { ast::pat_bind(n) { n } };
         if str::eq(p_name, name) {
-            ret some(local_def(pat.id));
+            found = some(local_def(bound.id));
         }
-      }
-      ast::pat_wild. { }
-      ast::pat_lit(_) { }
-      ast::pat_tag(_, pats) {
-        for p: @ast::pat  in pats {
-            let found = lookup_in_pat(name, *p);
-            if !is_none(found) { ret found; }
-        }
-      }
-      ast::pat_rec(fields, _) {
-        for f: ast::field_pat  in fields {
-            let found = lookup_in_pat(name, *f.pat);
-            if !is_none(found) { ret found; }
-        }
-      }
-      ast::pat_box(inner) { ret lookup_in_pat(name, *inner); }
     }
-    ret none;
+    ret found;
 }
 
 fn lookup_in_fn(name: &ident, decl: &ast::fn_decl,
@@ -779,7 +764,7 @@ fn lookup_in_block(name: &ident, b: &ast::blk_, ns: namespace) ->
               ast::decl_local(locs) {
                 for loc: @ast::local in locs {
                     if ns == ns_value {
-                        alt lookup_in_pat(name, *loc.node.pat) {
+                        alt lookup_in_pat(name, loc.node.pat) {
                           some(did) { ret some(ast::def_local(did)); }
                           _ {}
                         }
diff --git a/src/comp/middle/trans_alt.rs b/src/comp/middle/trans_alt.rs
index f15922a20fe..b694bbbf614 100644
--- a/src/comp/middle/trans_alt.rs
+++ b/src/comp/middle/trans_alt.rs
@@ -63,6 +63,7 @@ fn matches_always(p: &@ast::pat) -> bool {
           ast::pat_wild. { true }
           ast::pat_bind(_) { true }
           ast::pat_rec(_, _) { true }
+          ast::pat_tup(_) { true }
           _ { false }
         };
 }
@@ -145,6 +146,18 @@ fn enter_rec(m: &match, col: uint, fields: &[ast::ident], val: ValueRef) ->
     ret enter_match(m, col, val, bind e(dummy, fields, _));
 }
 
+fn enter_tup(m: &match, col: uint, val: ValueRef, n_elts: uint) -> match {
+    let dummy = @{id: 0, node: ast::pat_wild, span: {lo: 0u, hi: 0u}};
+    fn e(dummy: &@ast::pat, n_elts: uint, p: &@ast::pat)
+        -> option::t[[@ast::pat]] {
+        alt p.node {
+          ast::pat_tup(elts) { ret some(elts); }
+          _ { ret some(ivec::init_elt(dummy, n_elts)); }
+        }
+    }
+    ret enter_match(m, col, val, bind e(dummy, n_elts, _));
+}
+
 fn enter_box(m: &match, col: uint, val: ValueRef) -> match {
     let dummy = @{id: 0, node: ast::pat_wild, span: {lo: 0u, hi: 0u}};
     fn e(dummy: &@ast::pat, p: &@ast::pat) -> option::t[[@ast::pat]] {
@@ -227,6 +240,13 @@ fn any_box_pat(m: &match, col: uint) -> bool {
     ret false;
 }
 
+fn any_tup_pat(m: &match, col: uint) -> bool {
+    for br: match_branch in m {
+        alt br.pats.(col).node { ast::pat_tup(_) { ret true; } _ { } }
+    }
+    ret false;
+}
+
 type exit_node = {bound: bind_map, from: BasicBlockRef, to: BasicBlockRef};
 type mk_fail = fn() -> BasicBlockRef;
 
@@ -300,6 +320,23 @@ fn compile_submatch(bcx: @block_ctxt, m: &match, vals: [ValueRef],
         ret;
     }
 
+    if any_tup_pat(m, col) {
+        let tup_ty = ty::node_id_to_monotype(ccx.tcx, pat_id);
+        let n_tup_elts = alt ty::struct(ccx.tcx, tup_ty) {
+          ty::ty_tup(elts) { ivec::len(elts) }
+        };
+        let tup_vals = ~[], i = 0u;
+        while i < n_tup_elts {
+            let r = trans::GEP_tup_like(bcx, tup_ty, val, ~[0, i as int]);
+            tup_vals += ~[r.val];
+            bcx = r.bcx;
+            i += 1u;
+        }
+        compile_submatch(bcx, enter_tup(m, col, val, n_tup_elts),
+                         tup_vals + vals_left, f, exits);
+        ret;
+    }
+
     // Unbox in case of a box field
     if any_box_pat(m, col) {
         let box = bcx.build.Load(val);
@@ -518,6 +555,15 @@ fn bind_irrefutable_pat(bcx: @block_ctxt, pat: &@ast::pat, val: ValueRef,
             bcx = bind_irrefutable_pat(r.bcx, f.pat, r.val, table, copy);
         }
       }
+      ast::pat_tup(elems) {
+        let tup_ty = ty::node_id_to_monotype(ccx.tcx, pat.id);
+        let i = 0u;
+        for elem in elems {
+            let r = trans::GEP_tup_like(bcx, tup_ty, val, ~[0, i as int]);
+            bcx = bind_irrefutable_pat(r.bcx, elem, r.val, table, copy);
+            i += 1u;
+        }
+      }
       ast::pat_box(inner) {
         let box = bcx.build.Load(val);
         let unboxed = bcx.build.InBoundsGEP
diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs
index 6d10a6adaee..fbb69c226ed 100644
--- a/src/comp/middle/typeck.rs
+++ b/src/comp/middle/typeck.rs
@@ -1454,6 +1454,31 @@ fn check_pat(fcx: &@fn_ctxt, map: &ast::pat_id_map, pat: &@ast::pat,
         }
         write::ty_only_fixup(fcx, pat.id, expected);
       }
+      ast::pat_tup(elts) {
+        let ex_elts;
+        alt structure_of(fcx, pat.span, expected) {
+          ty::ty_tup(elts) { ex_elts = elts; }
+          _ {
+            fcx.ccx.tcx.sess.span_fatal(pat.span,
+                                        #fmt("mismatched types: expected %s, \
+                                         found tuple", ty_to_str(fcx.ccx.tcx,
+                                                                 expected)));
+          }
+        }
+        let e_count = ivec::len(elts);
+        if e_count != ivec::len(ex_elts) {
+            fcx.ccx.tcx.sess.span_fatal
+                (pat.span, #fmt("mismatched types: expected a tuple \
+                                 with %u fields, found one with %u \
+                                 fields", ivec::len(ex_elts), e_count));
+        }
+        let i = 0u;
+        for elt in elts {
+            check_pat(fcx, map, elt, ex_elts.(i));
+            i += 1u;
+        }
+        write::ty_only_fixup(fcx, pat.id, expected);
+      }
       ast::pat_box(inner) {
         alt structure_of(fcx, pat.span, expected) {
           ty::ty_box(e_inner) {
diff --git a/src/comp/syntax/ast.rs b/src/comp/syntax/ast.rs
index bedb2cad64d..d2ad2cd0f08 100644
--- a/src/comp/syntax/ast.rs
+++ b/src/comp/syntax/ast.rs
@@ -126,6 +126,7 @@ tag pat_ {
     pat_lit(@lit);
     pat_tag(path, [@pat]);
     pat_rec([field_pat], bool);
+    pat_tup([@pat]);
     pat_box(@pat);
 }
 
@@ -135,18 +136,10 @@ type pat_id_map = std::map::hashmap[str, ast::node_id];
 // use the node_id of their namesake in the first pattern.
 fn pat_id_map(pat: &@pat) -> pat_id_map {
     let map = std::map::new_str_hash[node_id]();
-    fn walk(map: &pat_id_map, pat: &@pat) {
-        alt pat.node {
-          pat_bind(name) { map.insert(name, pat.id); }
-          pat_tag(_, sub) { for p: @pat in sub { walk(map, p); } }
-          pat_rec(fields, _) {
-            for f: field_pat  in fields { walk(map, f.pat); }
-          }
-          pat_box(inner) { walk(map, inner); }
-          _ { }
-        }
+    for each bound in pat_bindings(pat) {
+        let name = alt bound.node { pat_bind(n) { n } };
+        map.insert(name, bound.id);
     }
-    walk(map, pat);
     ret map;
 }
 
@@ -163,6 +156,11 @@ iter pat_bindings(pat: &@pat) -> @pat {
             for each b in pat_bindings(f.pat) { put b; }
         }
       }
+      pat_tup(elts) {
+        for elt in elts {
+            for each b in pat_bindings(elt) { put b; }
+        }
+      }
       pat_box(sub) {
         for each b in pat_bindings(sub) { put b; }
       }
diff --git a/src/comp/syntax/fold.rs b/src/comp/syntax/fold.rs
index 177e05fa091..77ec93c809b 100644
--- a/src/comp/syntax/fold.rs
+++ b/src/comp/syntax/fold.rs
@@ -283,6 +283,9 @@ fn noop_fold_pat(p: &pat_, fld: ast_fold) -> pat_ {
             }
             pat_rec(fs, etc)
           }
+          pat_tup(elts) {
+            pat_tup(ivec::map(fld.fold_pat, elts))
+          }
           pat_box(inner) { pat_box(fld.fold_pat(inner)) }
         };
 }
diff --git a/src/comp/syntax/parse/parser.rs b/src/comp/syntax/parse/parser.rs
index 8f7dbd184c3..f28ea683cf9 100644
--- a/src/comp/syntax/parse/parser.rs
+++ b/src/comp/syntax/parse/parser.rs
@@ -1454,6 +1454,24 @@ fn parse_pat(p: &parser) -> @ast::pat {
         p.bump();
         pat = ast::pat_rec(fields, etc);
       }
+      token::LPAREN. {
+        p.bump();
+        if p.peek() == token::RPAREN {
+            hi = p.get_hi_pos();
+            p.bump();
+            pat = ast::pat_lit(@{node: ast::lit_nil, span: {lo: lo, hi: hi}});
+        } else {
+            let fields = ~[parse_pat(p)];
+            while p.peek() == token::COMMA {
+                p.bump();
+                fields += ~[parse_pat(p)];
+            }
+            if ivec::len(fields) == 1u { expect(p, token::COMMA); }
+            hi = p.get_hi_pos();
+            expect(p, token::RPAREN);
+            pat = ast::pat_tup(fields);
+        }
+      }
       tok {
         if !is_ident(tok) || is_word(p, "true") || is_word(p, "false") {
             let lit = parse_lit(p);
diff --git a/src/comp/syntax/print/pprust.rs b/src/comp/syntax/print/pprust.rs
index 569a5ad136a..fa2df63e280 100644
--- a/src/comp/syntax/print/pprust.rs
+++ b/src/comp/syntax/print/pprust.rs
@@ -1146,6 +1146,11 @@ fn print_pat(s: &ps, pat: &@ast::pat) {
         }
         word(s.s, "}");
       }
+      ast::pat_tup(elts) {
+        popen(s);
+        commasep(s, inconsistent, elts, print_pat);
+        pclose(s);
+      }
       ast::pat_box(inner) { word(s.s, "@"); print_pat(s, inner); }
     }
     s.ann.post(ann_node);
diff --git a/src/comp/syntax/visit.rs b/src/comp/syntax/visit.rs
index 3fbca6238ee..5f160d88e6f 100644
--- a/src/comp/syntax/visit.rs
+++ b/src/comp/syntax/visit.rs
@@ -175,6 +175,9 @@ fn visit_pat[E](p: &@pat, e: &E, v: &vt[E]) {
       pat_rec(fields, _) {
         for f: field_pat  in fields { v.visit_pat(f.pat, e, v); }
       }
+      pat_tup(elts) {
+        for elt in elts { v.visit_pat(elt, e, v); }
+      }
       pat_box(inner) { v.visit_pat(inner, e, v); }
       _ { }
     }