Skip to content

Commit

Permalink
Allow omission of the '.' after nullary tag patterns
Browse files Browse the repository at this point in the history
This commit allows patterns like:

alt x { some(_) { ... } none { } }

without the '.' after none. The parser suspends judgment about
whether a bare ident is a tag or a new bound variable; instead,
the resolver disambiguates.

This means that any code after resolution that pattern-matches on
patterns needs to call pat_util::normalize_pat, which consults
an environment to do this disambiguation.

In addition, local variables are no longer allowed to shadow
tag names, so this required changing some code (e.g. renaming
variables named "mut", and renaming ast::sub to subtract).

The parser currently accepts patterns with and without the '.'.
Once the compiler and libraries are changed, it will no longer
accept the '.'.
  • Loading branch information
catamorphism committed Jan 17, 2012
1 parent a7bd817 commit c3bc8fa
Show file tree
Hide file tree
Showing 25 changed files with 405 additions and 190 deletions.
10 changes: 6 additions & 4 deletions src/comp/middle/alias.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import std::list;
import option::{some, none, is_none};
import list::list;
import driver::session::session;
import pat_util::*;

// This is not an alias-analyser (though it would merit from becoming one, or
// getting input from one, to be more precise). It is a pass that checks
Expand Down Expand Up @@ -323,7 +324,7 @@ fn check_alt(cx: ctx, input: @ast::expr, arms: [ast::arm], sc: scope,
for a: ast::arm in arms {
let new_bs = sc.bs;
let root_var = path_def_id(cx, root.ex);
let pat_id_map = ast_util::pat_id_map(a.pats[0]);
let pat_id_map = pat_util::pat_id_map(cx.tcx, a.pats[0]);
type info = {
id: node_id,
mutable unsafe_tys: [unsafe_ty],
Expand Down Expand Up @@ -588,10 +589,11 @@ fn pattern_roots(tcx: ty::ctxt, mut: option::t<unsafe_ty>, pat: @ast::pat)
-> [pattern_root] {
fn walk(tcx: ty::ctxt, mut: option::t<unsafe_ty>, pat: @ast::pat,
&set: [pattern_root]) {
alt pat.node {
alt normalize_pat(tcx, pat).node {
ast::pat_wild. | ast::pat_lit(_) | ast::pat_range(_, _) {}
ast::pat_bind(nm, sub) {
set += [{id: pat.id, name: nm, mut: mut, span: pat.span}];
ast::pat_ident(nm, sub) {
set += [{id: pat.id, name: path_to_ident(nm), mut: mut,
span: pat.span}];
alt sub { some(p) { walk(tcx, mut, p, set); } _ {} }
}
ast::pat_tag(_, ps) | ast::pat_tup(ps) {
Expand Down
4 changes: 2 additions & 2 deletions src/comp/middle/ast_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,14 @@ fn map_fn(cx: ctx, _fk: visit::fn_kind, decl: fn_decl, _body: blk,
}

fn map_local(cx: ctx, loc: @local) {
ast_util::pat_bindings(loc.node.pat) {|p|
pat_util::pat_bindings(loc.node.pat) {|p|
cx.map.insert(p.id, node_local(cx.local_id));
cx.local_id += 1u;
};
}

fn map_arm(cx: ctx, arm: arm) {
ast_util::pat_bindings(arm.pats[0]) {|p|
pat_util::pat_bindings(arm.pats[0]) {|p|
cx.map.insert(p.id, node_local(cx.local_id));
cx.local_id += 1u;
};
Expand Down
18 changes: 12 additions & 6 deletions src/comp/middle/check_alt.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import syntax::ast::*;
import syntax::ast_util::{variant_def_ids, dummy_sp, compare_lit_exprs,
lit_expr_eq};
import pat_util::*;
import syntax::visit;
import option::{some, none};
import driver::session::session;
Expand All @@ -16,7 +17,12 @@ fn check_crate(tcx: ty::ctxt, crate: @crate) {

fn check_expr(tcx: ty::ctxt, ex: @expr, &&s: (), v: visit::vt<()>) {
visit::visit_expr(ex, s, v);
alt ex.node { expr_alt(_, arms) { check_arms(tcx, arms); } _ { } }
alt ex.node {
expr_alt(_, arms) {
check_arms(tcx, pat_util::normalize_arms(tcx, arms));
}
_ { }
}
}

fn check_arms(tcx: ty::ctxt, arms: [arm]) {
Expand Down Expand Up @@ -66,8 +72,8 @@ fn pattern_supersedes(tcx: ty::ctxt, a: @pat, b: @pat) -> bool {
}

alt a.node {
pat_bind(_, some(p)) { pattern_supersedes(tcx, p, b) }
pat_wild. | pat_bind(_, none.) { true }
pat_ident(_, some(p)) { pattern_supersedes(tcx, p, b) }
pat_wild. | pat_ident(_, none.) { true }
pat_lit(la) {
alt b.node {
pat_lit(lb) { lit_expr_eq(la, lb) }
Expand Down Expand Up @@ -132,11 +138,11 @@ fn check_local(tcx: ty::ctxt, loc: @local, &&s: (), v: visit::vt<()>) {
}

fn is_refutable(tcx: ty::ctxt, pat: @pat) -> bool {
alt pat.node {
pat_box(sub) | pat_uniq(sub) | pat_bind(_, some(sub)) {
alt normalize_pat(tcx, pat).node {
pat_box(sub) | pat_uniq(sub) | pat_ident(_, some(sub)) {
is_refutable(tcx, sub)
}
pat_wild. | pat_bind(_, none.) { false }
pat_wild. | pat_ident(_, none.) { false }
pat_lit(_) { true }
pat_rec(fields, _) {
for field: field_pat in fields {
Expand Down
8 changes: 5 additions & 3 deletions src/comp/middle/debuginfo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import middle::trans_build::B;
import middle::ty;
import syntax::{ast, codemap};
import ast::ty;
import pat_util::*;
import util::ppaux::ty_to_str;

export create_local_var;
Expand Down Expand Up @@ -629,9 +630,10 @@ fn create_local_var(bcx: @block_ctxt, local: @ast::local)
option::none. {}
}

let name = alt local.node.pat.node {
ast::pat_bind(ident, _) { ident /*XXX deal w/ optional node binding*/ }
};
let name = path_to_ident(alt pat_util::normalize_pat(bcx_tcx(bcx),
local.node.pat).node {
ast::pat_ident(ident, _) { ident /*XXX deal w/ optional node binding*/ }
});
let loc = codemap::lookup_char_pos(cx.sess.codemap,
local.span.lo);
let ty = trans::node_id_type(cx, local.node.id);
Expand Down
119 changes: 119 additions & 0 deletions src/comp/middle/pat_util.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import syntax::ast::*;
import syntax::ast_util;
import syntax::ast_util::respan;
import syntax::fold;
import syntax::fold::*;

export normalize_arms;
export normalize_pat;
export normalize_pat_def_map;
export pat_binding_ids;
export pat_bindings;
export pat_id_map;
export path_to_ident;

fn normalize_pat_def_map(dm: resolve::def_map, p: @pat) -> @pat {
// have to do it the hard way b/c ast fold doesn't pass around
// node IDs. bother.
alt p.node {
pat_wild. { p }
pat_ident(_, none.) { normalize_one(dm, p) }
pat_ident(q, some(r)) {
@{node: pat_ident(q, some(normalize_pat_def_map(dm, r)))
with *p}
}
pat_tag(a_path, subs) {
@{node: pat_tag(a_path,
vec::map(subs, {|p| normalize_pat_def_map(dm, p)})) with *p}
}
pat_rec(field_pats, b) {
@{node: pat_rec(vec::map(field_pats,
{|fp| {pat: normalize_pat_def_map(dm, fp.pat) with fp}}), b)
with *p}
}
pat_tup(subs) {
@{node: pat_tup(vec::map(subs, {|p| normalize_pat_def_map(dm, p)}))
with *p}
}
pat_box(q) {
@{node: pat_box(normalize_pat_def_map(dm, q))
with *p}
}
pat_uniq(q) {
@{node: pat_uniq(normalize_pat_def_map(dm, q))
with *p}
}
pat_lit(_) { p }
pat_range(_,_) { p }
}
}

fn normalize_one(dm: resolve::def_map, p: @pat) -> @pat {
alt dm.find(p.id) {
some(d) {
alt p.node {
pat_ident(tag_path, _) { @{id: p.id,
node: pat_tag(tag_path, []),
span: p.span} }
_ { p }
}
}
none. { p }
}
}

fn normalize_pat(tcx: ty::ctxt, p: @pat) -> @pat {
normalize_pat_def_map(tcx.def_map, p)
}

fn normalize_arms(tcx: ty::ctxt, arms:[arm]) -> [arm] {
vec::map(arms, {|a|
{pats:
vec::map(a.pats, {|p|
pat_util::normalize_pat(tcx, p)})
with a}})
}

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(tcx: ty::ctxt, pat: @pat) -> pat_id_map {
let map = std::map::new_str_hash::<node_id>();
pat_bindings(normalize_pat(tcx, pat)) {|bound|
let name = path_to_ident(alt bound.node
{ pat_ident(n, _) { n } });
map.insert(name, bound.id);
};
ret map;
}

// 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(pat: @pat, it: block(@pat)) {
alt pat.node {
pat_ident(_, option::none.) { it(pat); }
pat_ident(_, 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); } }
pat_box(sub) { pat_bindings(sub, it); }
pat_uniq(sub) { pat_bindings(sub, it); }
pat_wild. | pat_lit(_) | pat_range(_, _) { }
}
}

fn pat_binding_ids(pat: @pat) -> [node_id] {
let found = [];
pat_bindings(pat) {|b| found += [b.id]; };
ret found;
}

fn path_to_ident(p: @path) -> ident {
alt vec::last(p.node.idents) {
none. { // sigh
fail "Malformed path"; }
some(i) { ret i; }
}
}
Loading

0 comments on commit c3bc8fa

Please sign in to comment.