|
| 1 | +import syntax::ast::*; |
| 2 | +import syntax::ast_util; |
| 3 | +import syntax::ast_util::respan; |
| 4 | +import syntax::fold; |
| 5 | +import syntax::fold::*; |
| 6 | + |
| 7 | +export normalize_arms; |
| 8 | +export normalize_pat; |
| 9 | +export normalize_pat_def_map; |
| 10 | +export pat_binding_ids; |
| 11 | +export pat_bindings; |
| 12 | +export pat_id_map; |
| 13 | +export path_to_ident; |
| 14 | + |
| 15 | +fn normalize_pat_def_map(dm: resolve::def_map, p: @pat) -> @pat { |
| 16 | + // have to do it the hard way b/c ast fold doesn't pass around |
| 17 | + // node IDs. bother. |
| 18 | + alt p.node { |
| 19 | + pat_wild. { p } |
| 20 | + pat_ident(_, none.) { normalize_one(dm, p) } |
| 21 | + pat_ident(q, some(r)) { |
| 22 | + @{node: pat_ident(q, some(normalize_pat_def_map(dm, r))) |
| 23 | + with *p} |
| 24 | + } |
| 25 | + pat_tag(a_path, subs) { |
| 26 | + @{node: pat_tag(a_path, |
| 27 | + vec::map(subs, {|p| normalize_pat_def_map(dm, p)})) with *p} |
| 28 | + } |
| 29 | + pat_rec(field_pats, b) { |
| 30 | + @{node: pat_rec(vec::map(field_pats, |
| 31 | + {|fp| {pat: normalize_pat_def_map(dm, fp.pat) with fp}}), b) |
| 32 | + with *p} |
| 33 | + } |
| 34 | + pat_tup(subs) { |
| 35 | + @{node: pat_tup(vec::map(subs, {|p| normalize_pat_def_map(dm, p)})) |
| 36 | + with *p} |
| 37 | + } |
| 38 | + pat_box(q) { |
| 39 | + @{node: pat_box(normalize_pat_def_map(dm, q)) |
| 40 | + with *p} |
| 41 | + } |
| 42 | + pat_uniq(q) { |
| 43 | + @{node: pat_uniq(normalize_pat_def_map(dm, q)) |
| 44 | + with *p} |
| 45 | + } |
| 46 | + pat_lit(_) { p } |
| 47 | + pat_range(_,_) { p } |
| 48 | + } |
| 49 | +} |
| 50 | + |
| 51 | +fn normalize_one(dm: resolve::def_map, p: @pat) -> @pat { |
| 52 | + alt dm.find(p.id) { |
| 53 | + some(d) { |
| 54 | + alt p.node { |
| 55 | + pat_ident(tag_path, _) { @{id: p.id, |
| 56 | + node: pat_tag(tag_path, []), |
| 57 | + span: p.span} } |
| 58 | + _ { p } |
| 59 | + } |
| 60 | + } |
| 61 | + none. { p } |
| 62 | + } |
| 63 | +} |
| 64 | + |
| 65 | +fn normalize_pat(tcx: ty::ctxt, p: @pat) -> @pat { |
| 66 | + normalize_pat_def_map(tcx.def_map, p) |
| 67 | +} |
| 68 | + |
| 69 | +fn normalize_arms(tcx: ty::ctxt, arms:[arm]) -> [arm] { |
| 70 | + vec::map(arms, {|a| |
| 71 | + {pats: |
| 72 | + vec::map(a.pats, {|p| |
| 73 | + pat_util::normalize_pat(tcx, p)}) |
| 74 | + with a}}) |
| 75 | +} |
| 76 | + |
| 77 | +type pat_id_map = std::map::hashmap<str, node_id>; |
| 78 | + |
| 79 | +// This is used because same-named variables in alternative patterns need to |
| 80 | +// use the node_id of their namesake in the first pattern. |
| 81 | +fn pat_id_map(tcx: ty::ctxt, pat: @pat) -> pat_id_map { |
| 82 | + let map = std::map::new_str_hash::<node_id>(); |
| 83 | + pat_bindings(normalize_pat(tcx, pat)) {|bound| |
| 84 | + let name = path_to_ident(alt bound.node |
| 85 | + { pat_ident(n, _) { n } }); |
| 86 | + map.insert(name, bound.id); |
| 87 | + }; |
| 88 | + ret map; |
| 89 | +} |
| 90 | + |
| 91 | +// This does *not* normalize. The pattern should be already normalized |
| 92 | +// if you want to get a normalized pattern out of it. |
| 93 | +// Could return a constrained type in order to express that (future work) |
| 94 | +fn pat_bindings(pat: @pat, it: block(@pat)) { |
| 95 | + alt pat.node { |
| 96 | + pat_ident(_, option::none.) { it(pat); } |
| 97 | + pat_ident(_, option::some(sub)) { it(pat); pat_bindings(sub, it); } |
| 98 | + pat_tag(_, sub) { for p in sub { pat_bindings(p, it); } } |
| 99 | + pat_rec(fields, _) { for f in fields { pat_bindings(f.pat, it); } } |
| 100 | + pat_tup(elts) { for elt in elts { pat_bindings(elt, it); } } |
| 101 | + pat_box(sub) { pat_bindings(sub, it); } |
| 102 | + pat_uniq(sub) { pat_bindings(sub, it); } |
| 103 | + pat_wild. | pat_lit(_) | pat_range(_, _) { } |
| 104 | + } |
| 105 | +} |
| 106 | + |
| 107 | +fn pat_binding_ids(pat: @pat) -> [node_id] { |
| 108 | + let found = []; |
| 109 | + pat_bindings(pat) {|b| found += [b.id]; }; |
| 110 | + ret found; |
| 111 | +} |
| 112 | + |
| 113 | +fn path_to_ident(p: @path) -> ident { |
| 114 | + alt vec::last(p.node.idents) { |
| 115 | + none. { // sigh |
| 116 | + fail "Malformed path"; } |
| 117 | + some(i) { ret i; } |
| 118 | + } |
| 119 | +} |
0 commit comments