about summary refs log tree commit diff
path: root/src/comp/syntax
diff options
context:
space:
mode:
authorMarijn Haverbeke <marijnh@gmail.com>2011-07-11 14:13:20 +0200
committerMarijn Haverbeke <marijnh@gmail.com>2011-07-11 15:32:41 +0200
commit7595fe5153cfc3e703cec4516616c51af3223bc6 (patch)
treeb35cdf3f29627c1d5173f8058ac9f0222bf15b17 /src/comp/syntax
parent12cb128a0a8cfffeccae910c72831562bd9c3b93 (diff)
Implement record patterns
Closes #469.
Diffstat (limited to 'src/comp/syntax')
-rw-r--r--src/comp/syntax/ast.rs6
-rw-r--r--src/comp/syntax/fold.rs7
-rw-r--r--src/comp/syntax/parse/parser.rs39
-rw-r--r--src/comp/syntax/print/pprust.rs16
-rw-r--r--src/comp/syntax/visit.rs3
-rw-r--r--src/comp/syntax/walk.rs3
6 files changed, 74 insertions, 0 deletions
diff --git a/src/comp/syntax/ast.rs b/src/comp/syntax/ast.rs
index 37d57dacf3c..6c9c2f2f249 100644
--- a/src/comp/syntax/ast.rs
+++ b/src/comp/syntax/ast.rs
@@ -118,11 +118,14 @@ type pat = rec(node_id id,
                pat_ node,
                span span);
 
+type field_pat = rec(ident ident, @pat pat);
+
 tag pat_ {
     pat_wild;
     pat_bind(ident);
     pat_lit(@lit);
     pat_tag(path, (@pat)[]);
+    pat_rec(field_pat[], bool);
 }
 
 type pat_id_map = std::map::hashmap[str, ast::node_id];
@@ -137,6 +140,9 @@ fn pat_id_map(&@pat pat) -> pat_id_map {
             pat_tag(_, ?sub) {
                 for (@pat p in sub) { walk(map, p); }
             }
+            pat_rec(?fields, _) {
+                for (field_pat f in fields) { walk(map, f.pat); }
+            }
             _ {}
         }
     }
diff --git a/src/comp/syntax/fold.rs b/src/comp/syntax/fold.rs
index 8529542bf44..571473261ff 100644
--- a/src/comp/syntax/fold.rs
+++ b/src/comp/syntax/fold.rs
@@ -267,6 +267,13 @@ fn noop_fold_pat(&pat_ p, ast_fold fld) -> pat_ {
         case (pat_tag(?pth, ?pats)) {
             pat_tag(fld.fold_path(pth), ivec::map(fld.fold_pat, pats))
         }
+        case (pat_rec(?fields, ?etc)) {
+            auto fs = ~[];
+            for (ast::field_pat f in fields) {
+                fs += ~[rec(ident=f.ident, pat=fld.fold_pat(f.pat))];
+            }
+            pat_rec(fs, etc)
+        }
     };
 }
 
diff --git a/src/comp/syntax/parse/parser.rs b/src/comp/syntax/parse/parser.rs
index 567aa995fd6..29b12763d91 100644
--- a/src/comp/syntax/parse/parser.rs
+++ b/src/comp/syntax/parse/parser.rs
@@ -1455,6 +1455,45 @@ fn parse_pat(&parser p) -> @ast::pat {
                 }
             }
         }
+        case (token::LBRACE) {
+            p.bump();
+            auto fields = ~[];
+            auto etc = false;
+            auto first = true;
+            while (p.peek() != token::RBRACE) {
+                if (p.peek() == token::DOT) {
+                    p.bump();
+                    expect(p, token::DOT);
+                    expect(p, token::DOT);
+                    if (p.peek() != token::RBRACE) {
+                        p.fatal("expecting }, found " +
+                                token::to_str(p.get_reader(), p.peek()));
+                    }
+                    etc = true;
+                    break;
+                }
+                if (first) { first = false; }
+                else { expect(p, token::COMMA); }
+                auto fieldname = parse_ident(p);
+                auto subpat;
+                if (p.peek() == token::COLON) {
+                    p.bump();
+                    subpat = parse_pat(p);
+                } else {
+                    if (p.get_bad_expr_words().contains_key(fieldname)) {
+                        p.fatal("found " + fieldname +
+                                " in binding position");
+                    }
+                    subpat = @rec(id=p.get_id(),
+                                  node=ast::pat_bind(fieldname),
+                                  span=rec(lo=lo, hi=hi));
+                }
+                fields += ~[rec(ident=fieldname, pat=subpat)];
+            }
+            hi = p.get_hi_pos();
+            p.bump();
+            pat = ast::pat_rec(fields, etc);
+        }
         case (?tok) {
             if (!is_ident(tok) || is_word(p, "true") || is_word(p, "false")) {
                 auto lit = parse_lit(p);
diff --git a/src/comp/syntax/print/pprust.rs b/src/comp/syntax/print/pprust.rs
index 2bc4efb1e59..e62b37807f2 100644
--- a/src/comp/syntax/print/pprust.rs
+++ b/src/comp/syntax/print/pprust.rs
@@ -1120,6 +1120,22 @@ fn print_pat(&ps s, &@ast::pat pat) {
                 pclose(s);
             }
         }
+        case (ast::pat_rec(?fields, ?etc)) {
+            bopen(s);
+            fn print_field(&ps s, &ast::field_pat f) {
+                cbox(s, indent_unit);
+                word(s.s, f.ident);
+                word(s.s, ":");
+                print_pat(s, f.pat);
+                end(s);
+            }
+            fn get_span(&ast::field_pat f) -> codemap::span {
+                ret f.pat.span;
+            }
+            commasep_cmnt_ivec(s, consistent, fields, print_field, get_span);
+            if (etc) { space(s.s); word(s.s, "..."); }
+            bclose(s, pat.span);
+        }
     }
     s.ann.post(ann_node);
 }
diff --git a/src/comp/syntax/visit.rs b/src/comp/syntax/visit.rs
index c6e4d1911d4..470a8e4e38d 100644
--- a/src/comp/syntax/visit.rs
+++ b/src/comp/syntax/visit.rs
@@ -190,6 +190,9 @@ fn visit_pat[E](&@pat p, &E e, &vt[E] v) {
             for (@ty tp in path.node.types) { v.visit_ty(tp, e, v); }
             for (@pat child in children) { v.visit_pat(child, e, v); }
         }
+        case (pat_rec(?fields, _)) {
+            for (field_pat f in fields) { v.visit_pat(f.pat, e, v); }
+        }
         case (_) { }
     }
 }
diff --git a/src/comp/syntax/walk.rs b/src/comp/syntax/walk.rs
index 77b13f0c9b8..024437e4327 100644
--- a/src/comp/syntax/walk.rs
+++ b/src/comp/syntax/walk.rs
@@ -189,6 +189,9 @@ fn walk_pat(&ast_visitor v, &@ast::pat p) {
             for (@ast::ty tp in path.node.types) { walk_ty(v, tp); }
             for (@ast::pat child in children) { walk_pat(v, child); }
         }
+        case (ast::pat_rec(?fields, _)) {
+            for (ast::field_pat f in fields) { walk_pat(v, f.pat); }
+        }
         case (_) { }
     }
     v.visit_pat_post(p);