Implement record patterns

Closes #469.
This commit is contained in:
Marijn Haverbeke 2011-07-11 14:13:20 +02:00
parent 12cb128a0a
commit 7595fe5153
13 changed files with 193 additions and 2 deletions

View file

@ -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); }
}
_ {}
}
}

View file

@ -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)
}
};
}

View file

@ -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);

View file

@ -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);
}

View file

@ -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 (_) { }
}
}

View file

@ -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);