Allow binding of nested patterns

See src/test/run-pass/nested-patterns.rs for some examples. The syntax is

    boundvar@subpattern

Which will match the subpattern as usual, but also bind boundvar to the
whole matched value.

Closes #838
This commit is contained in:
Marijn Haverbeke 2011-12-08 11:56:16 +01:00
parent 8c966b7b18
commit 9a269a3aa8
17 changed files with 132 additions and 79 deletions

View file

@ -92,7 +92,7 @@ type field_pat = {ident: ident, pat: @pat};
tag pat_ {
pat_wild;
pat_bind(ident);
pat_bind(ident, option::t<@pat>);
pat_tag(@path, [@pat]);
pat_rec([field_pat], bool);
pat_tup([@pat]);

View file

@ -58,7 +58,7 @@ type pat_id_map = std::map::hashmap<str, node_id>;
fn pat_id_map(pat: @pat) -> pat_id_map {
let map = std::map::new_str_hash::<node_id>();
pat_bindings(pat) {|bound|
let name = alt bound.node { pat_bind(n) { n } };
let name = alt bound.node { pat_bind(n, _) { n } };
map.insert(name, bound.id);
};
ret map;
@ -67,7 +67,8 @@ fn pat_id_map(pat: @pat) -> pat_id_map {
// FIXME: could return a constrained type
fn pat_bindings(pat: @pat, it: block(@pat)) {
alt pat.node {
pat_bind(_) { it(pat); }
pat_bind(_, option::none.) { it(pat); }
pat_bind(_, option::some(sub)) { it(pat); pat_bindings(sub, it); }
pat_tag(_, sub) { for p in sub { pat_bindings(p, it); } }
pat_rec(fields, _) { for f in fields { pat_bindings(f.pat, it); } }
pat_tup(elts) { for elt in elts { pat_bindings(elt, it); } }

View file

@ -270,7 +270,9 @@ fn noop_fold_arm(a: arm, fld: ast_fold) -> arm {
fn noop_fold_pat(p: pat_, fld: ast_fold) -> pat_ {
ret alt p {
pat_wild. { p }
pat_bind(ident) { pat_bind(fld.fold_ident(ident)) }
pat_bind(ident, sub) {
pat_bind(fld.fold_ident(ident), option::map(fld.fold_pat, sub))
}
pat_lit(_) { p }
pat_tag(pth, pats) {
pat_tag(fld.fold_path(pth), vec::map(fld.fold_pat, pats))

View file

@ -1429,10 +1429,9 @@ fn parse_pat(p: parser) -> @ast::pat {
if p.get_bad_expr_words().contains_key(fieldname) {
p.fatal("found " + fieldname + " in binding position");
}
subpat =
@{id: p.get_id(),
node: ast::pat_bind(fieldname),
span: ast_util::mk_sp(lo, hi)};
subpat = @{id: p.get_id(),
node: ast::pat_bind(fieldname, none),
span: ast_util::mk_sp(lo, hi)};
}
fields += [{ident: fieldname, pat: subpat}];
}
@ -1479,7 +1478,9 @@ fn parse_pat(p: parser) -> @ast::pat {
_ { true }
} {
hi = p.get_hi_pos();
pat = ast::pat_bind(parse_value_ident(p));
let name = parse_value_ident(p);
let sub = eat(p, token::AT) ? some(parse_pat(p)) : none;
pat = ast::pat_bind(name, sub);
} else {
let tag_path = parse_path_and_ty_param_substs(p);
hi = tag_path.span.hi;

View file

@ -1062,7 +1062,13 @@ fn print_pat(s: ps, &&pat: @ast::pat) {
s.ann.pre(ann_node);
alt pat.node {
ast::pat_wild. { word(s.s, "_"); }
ast::pat_bind(id) { word(s.s, id); }
ast::pat_bind(id, sub) {
word(s.s, id);
alt sub {
some(p) { word(s.s, "@"); print_pat(s, p); }
_ {}
}
}
ast::pat_tag(path, args) {
print_path(s, path, true);
if vec::len(args) > 0u {

View file

@ -159,8 +159,9 @@ fn visit_pat<E>(p: @pat, e: E, v: vt<E>) {
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); }
pat_uniq(inner) { v.visit_pat(inner, e, v); }
pat_box(inner) | pat_uniq(inner) | pat_bind(_, some(inner)) {
v.visit_pat(inner, e, v);
}
_ { }
}
}