rust/src/rustc/middle/pat_util.rs
Tim Chevalier 0c5fdc8745 Rename last to last_opt, last_unsafe to last
As per discussion on IRC. I am about to file an RFC for further
discussion about the more general issue of whether to enforce
invariants through types, typestate, or dynamic checks, but for now,
removing the misleading name "last_unsafe".
2012-03-08 15:25:56 -08:00

75 lines
2.1 KiB
Rust

import syntax::ast::*;
import syntax::ast_util;
import syntax::ast_util::respan;
import syntax::fold;
import syntax::fold::*;
import syntax::codemap::span;
import std::map::hashmap;
export walk_pat;
export pat_binding_ids, pat_bindings, pat_id_map;
export pat_is_variant;
export path_to_ident;
type pat_id_map = std::map::hashmap<str, node_id>;
// This is used because same-named variables in alternative patterns need to
// use the node_id of their namesake in the first pattern.
fn pat_id_map(dm: resolve::def_map, pat: @pat) -> pat_id_map {
let map = std::map::new_str_hash();
pat_bindings(dm, pat) {|p_id, _s, n|
map.insert(path_to_ident(n), p_id);
};
ret map;
}
fn pat_is_variant(dm: resolve::def_map, pat: @pat) -> bool {
alt pat.node {
pat_enum(_, _) { true }
pat_ident(_, none) {
alt dm.find(pat.id) {
some(def_variant(_, _)) { true }
_ { false }
}
}
_ { false }
}
}
// This does *not* normalize. The pattern should be already normalized
// if you want to get a normalized pattern out of it.
// Could return a constrained type in order to express that (future work)
fn pat_bindings(dm: resolve::def_map, pat: @pat,
it: fn(node_id, span, @path)) {
walk_pat(pat) {|p|
alt p.node {
pat_ident(pth, _) if !pat_is_variant(dm, p) {
it(p.id, p.span, pth);
}
_ {}
}
}
}
fn walk_pat(pat: @pat, it: fn(@pat)) {
it(pat);
alt pat.node {
pat_ident(pth, some(p)) { walk_pat(p, it); }
pat_rec(fields, _) { for f in fields { walk_pat(f.pat, it); } }
pat_enum(_, s) | pat_tup(s) { for p in s { walk_pat(p, it); } }
pat_box(s) | pat_uniq(s) { walk_pat(s, it); }
pat_wild | pat_lit(_) | pat_range(_, _) | pat_ident(_, none) {}
}
}
fn pat_binding_ids(dm: resolve::def_map, pat: @pat) -> [node_id] {
let found = [];
pat_bindings(dm, pat) {|b_id, _sp, _pt| found += [b_id]; };
ret found;
}
fn path_to_ident(p: @path) -> ident {
assert (vec::is_not_empty(p.node.idents)); // should be a constraint on path
vec::last(p.node.idents)
}