about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/driver/driver.rs2
-rw-r--r--src/librustdoc/attr_parser.rs2
-rw-r--r--src/librustpkg/tests.rs2
-rw-r--r--src/libsyntax/ast_util.rs5
-rw-r--r--src/libsyntax/ext/base.rs4
-rw-r--r--src/libsyntax/opt_vec.rs4
-rw-r--r--src/libsyntax/parse/attr.rs7
-rw-r--r--src/libsyntax/parse/classify.rs10
-rw-r--r--src/libsyntax/parse/comments.rs2
-rw-r--r--src/libsyntax/parse/lexer.rs13
-rw-r--r--src/libsyntax/parse/mod.rs496
-rw-r--r--src/libsyntax/parse/obsolete.rs4
-rw-r--r--src/libsyntax/parse/parser.rs676
-rw-r--r--src/libsyntax/parse/prec.rs52
-rw-r--r--src/libsyntax/parse/token.rs134
-rw-r--r--src/libsyntax/syntax.rc5
-rw-r--r--src/test/compile-fail/enums-pats-not-idents.rs16
17 files changed, 889 insertions, 545 deletions
diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs
index a6c061fee1e..2e64c0c45bf 100644
--- a/src/librustc/driver/driver.rs
+++ b/src/librustc/driver/driver.rs
@@ -149,7 +149,7 @@ pub fn parse_input(sess: Session, cfg: ast::crate_cfg, input: &input)
     -> @ast::crate {
     match *input {
       file_input(ref file) => {
-        parse::parse_crate_from_file_using_tts(&(*file), cfg, sess.parse_sess)
+        parse::parse_crate_from_file(&(*file), cfg, sess.parse_sess)
       }
       str_input(ref src) => {
         // FIXME (#2319): Don't really want to box the source string
diff --git a/src/librustdoc/attr_parser.rs b/src/librustdoc/attr_parser.rs
index 5b97ccffc21..433809b9db2 100644
--- a/src/librustdoc/attr_parser.rs
+++ b/src/librustdoc/attr_parser.rs
@@ -79,7 +79,7 @@ mod test {
 
         let parse_sess = syntax::parse::new_parse_sess(None);
         let parser = parse::new_parser_from_source_str(
-            parse_sess, ~[], ~"-", codemap::FssNone, @source);
+            parse_sess, ~[], ~"-", @source);
 
         parser.parse_outer_attributes()
     }
diff --git a/src/librustpkg/tests.rs b/src/librustpkg/tests.rs
index 49cc875355b..bcee2992e5a 100644
--- a/src/librustpkg/tests.rs
+++ b/src/librustpkg/tests.rs
@@ -66,7 +66,7 @@ fn test_make_dir_rwx() {
 fn test_install_valid() {
     let ctxt = fake_ctxt();
     let temp_pkg_id = fake_pkg();
-    let temp_workspace() = mk_temp_workspace();
+    let temp_workspace = mk_temp_workspace();
     // should have test, bench, lib, and main
     ctxt.install(&temp_workspace, temp_pkg_id);
     // Check that all files exist
diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs
index bfacfc38df6..c28d369e7f8 100644
--- a/src/libsyntax/ast_util.rs
+++ b/src/libsyntax/ast_util.rs
@@ -355,6 +355,10 @@ pub fn operator_prec(op: ast::binop) -> uint {
   }
 }
 
+/// Precedence of the `as` operator, which is a binary operator
+/// not appearing in the prior table.
+pub static as_prec: uint = 11u;
+
 pub fn dtor_ty() -> @ast::Ty {
     @ast::Ty {id: 0, node: ty_nil, span: dummy_sp()}
 }
@@ -756,7 +760,6 @@ mod test {
         assert_eq!(refold_test_sc(3,&t),test_sc);
     }
 
-
     // extend a syntax context with a sequence of marks given
     // in a vector. v[0] will be the outermost mark.
     fn unfold_marks(mrks:~[Mrk],tail:SyntaxContext,table: &mut SCTable) -> SyntaxContext {
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index ecbccedbd9d..2d6d74b5c1e 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -461,9 +461,7 @@ impl <K: Eq + Hash + IterBytes ,V: Copy> MapChain<K,V>{
 
     // ugh: can't get this to compile with mut because of the
     // lack of flow sensitivity.
-    #[cfg(stage1)]
-    #[cfg(stage2)]
-    #[cfg(stage3)]
+    #[cfg(not(stage0))]
     fn get_map<'a>(&'a self) -> &'a HashMap<K,@V> {
         match *self {
             BaseMapChain (~ref map) => map,
diff --git a/src/libsyntax/opt_vec.rs b/src/libsyntax/opt_vec.rs
index fd1c5a960d1..6cf7bba600e 100644
--- a/src/libsyntax/opt_vec.rs
+++ b/src/libsyntax/opt_vec.rs
@@ -69,9 +69,7 @@ impl<T> OptVec<T> {
         }
     }
 
-    #[cfg(stage1)]
-    #[cfg(stage2)]
-    #[cfg(stage3)]
+    #[cfg(not(stage0))]
     fn get<'a>(&'a self, i: uint) -> &'a T {
         match *self {
             Empty => fail!(fmt!("Invalid index %u", i)),
diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs
index f851b9781ab..cc580155d70 100644
--- a/src/libsyntax/parse/attr.rs
+++ b/src/libsyntax/parse/attr.rs
@@ -62,12 +62,14 @@ impl parser_attr for Parser {
         return attrs;
     }
 
+    // matches attribute = # attribute_naked
     fn parse_attribute(&self, style: ast::attr_style) -> ast::attribute {
         let lo = self.span.lo;
         self.expect(&token::POUND);
         return self.parse_attribute_naked(style, lo);
     }
 
+    // matches attribute_naked = [ meta_item ]
     fn parse_attribute_naked(&self, style: ast::attr_style, lo: BytePos) ->
         ast::attribute {
         self.expect(&token::LBRACKET);
@@ -86,6 +88,7 @@ impl parser_attr for Parser {
     // is an inner attribute of the containing item or an outer attribute of
     // the first contained item until we see the semi).
 
+    // matches inner_attrs* outer_attr?
     // you can make the 'next' field an Option, but the result is going to be
     // more useful as a vector.
     fn parse_inner_attrs_and_next(&self) ->
@@ -134,6 +137,9 @@ impl parser_attr for Parser {
         (inner_attrs, next_outer_attrs)
     }
 
+    // matches meta_item = IDENT
+    // | IDENT = lit
+    // | IDENT meta_seq
     fn parse_meta_item(&self) -> @ast::meta_item {
         let lo = self.span.lo;
         let name = self.id_to_str(self.parse_ident());
@@ -156,6 +162,7 @@ impl parser_attr for Parser {
         }
     }
 
+    // matches meta_seq = ( COMMASEP(meta_item) )
     fn parse_meta_seq(&self) -> ~[@ast::meta_item] {
         copy self.parse_seq(
             &token::LPAREN,
diff --git a/src/libsyntax/parse/classify.rs b/src/libsyntax/parse/classify.rs
index 840fb891bff..e04914c0f1e 100644
--- a/src/libsyntax/parse/classify.rs
+++ b/src/libsyntax/parse/classify.rs
@@ -15,6 +15,13 @@
 use ast;
 use codemap;
 
+// does this expression require a semicolon to be treated
+// as a statement? The negation of this: 'can this expression
+// be used as a statement without a semicolon' -- is used
+// as an early-bail-out in the parser so that, for instance,
+// 'if true {...} else {...}
+//  |x| 5 '
+// isn't parsed as (if true {...} else {...} | x) | 5
 pub fn expr_requires_semi_to_be_stmt(e: @ast::expr) -> bool {
     match e.node {
       ast::expr_if(*)
@@ -40,6 +47,9 @@ pub fn expr_is_simple_block(e: @ast::expr) -> bool {
     }
 }
 
+// this statement requires a semicolon after it.
+// note that in one case (stmt_semi), we've already
+// seen the semicolon, and thus don't need another.
 pub fn stmt_ends_with_semi(stmt: &ast::stmt) -> bool {
     return match stmt.node {
         ast::stmt_decl(d, _) => {
diff --git a/src/libsyntax/parse/comments.rs b/src/libsyntax/parse/comments.rs
index 40bfd3d380c..4e29c3dcf18 100644
--- a/src/libsyntax/parse/comments.rs
+++ b/src/libsyntax/parse/comments.rs
@@ -309,6 +309,8 @@ pub struct lit {
     pos: BytePos
 }
 
+// it appears this function is called only from pprust... that's
+// probably not a good thing.
 pub fn gather_comments_and_literals(span_diagnostic:
                                     @diagnostic::span_handler,
                                     path: ~str,
diff --git a/src/libsyntax/parse/lexer.rs b/src/libsyntax/parse/lexer.rs
index fa425cf6285..60d6ce504fd 100644
--- a/src/libsyntax/parse/lexer.rs
+++ b/src/libsyntax/parse/lexer.rs
@@ -225,20 +225,12 @@ pub fn is_whitespace(c: char) -> bool {
     return c == ' ' || c == '\t' || c == '\r' || c == '\n';
 }
 
-fn may_begin_ident(c: char) -> bool { return is_alpha(c) || c == '_'; }
-
 fn in_range(c: char, lo: char, hi: char) -> bool {
     return lo <= c && c <= hi
 }
 
-fn is_alpha(c: char) -> bool {
-    return in_range(c, 'a', 'z') || in_range(c, 'A', 'Z');
-}
-
 fn is_dec_digit(c: char) -> bool { return in_range(c, '0', '9'); }
 
-fn is_alnum(c: char) -> bool { return is_alpha(c) || is_dec_digit(c); }
-
 fn is_hex_digit(c: char) -> bool {
     return in_range(c, '0', '9') || in_range(c, 'a', 'f') ||
             in_range(c, 'A', 'F');
@@ -294,6 +286,8 @@ fn consume_any_line_comment(rdr: @mut StringReader)
         }
     } else if rdr.curr == '#' {
         if nextch(rdr) == '!' {
+            // I guess this is the only way to figure out if
+            // we're at the beginning of the file...
             let cmap = @CodeMap::new();
             (*cmap).files.push(rdr.filemap);
             let loc = cmap.lookup_char_pos_adj(rdr.last_pos);
@@ -444,8 +438,7 @@ fn scan_number(c: char, rdr: @mut StringReader) -> token::Token {
         }
     }
     let mut is_float = false;
-    if rdr.curr == '.' && !(is_alpha(nextch(rdr)) || nextch(rdr) == '_' ||
-                            nextch(rdr) == '.') {
+    if rdr.curr == '.' && !(ident_start(nextch(rdr)) || nextch(rdr) == '.') {
         is_float = true;
         bump(rdr);
         let dec_part = scan_digits(rdr, 10u);
diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs
index 4d8fdcfe617..d27d788e23a 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -13,7 +13,7 @@
 
 use ast::node_id;
 use ast;
-use codemap::{span, CodeMap};
+use codemap::{span, CodeMap, FileMap, FileSubstr};
 use codemap;
 use diagnostic::{span_handler, mk_span_handler, mk_handler, Emitter};
 use parse::attr::parser_attr;
@@ -22,7 +22,7 @@ use parse::parser::Parser;
 use parse::token::{ident_interner, mk_ident_interner};
 
 use core::io;
-use core::option::{None, Option};
+use core::option::{None, Option, Some};
 use core::path::Path;
 use core::result::{Err, Ok, Result};
 
@@ -36,9 +36,6 @@ pub mod attr;
 /// Common routines shared by parser mods
 pub mod common;
 
-/// Functions dealing with operator precedence
-pub mod prec;
-
 /// Routines the parser uses to classify AST nodes
 pub mod classify;
 
@@ -82,31 +79,15 @@ pub fn new_parse_sess_special_handler(sh: @span_handler,
 // uses a HOF to parse anything, and <source> includes file and
 // source_str.
 
-// this appears to be the main entry point for rust parsing by
-// rustc and crate:
 pub fn parse_crate_from_file(
     input: &Path,
     cfg: ast::crate_cfg,
     sess: @mut ParseSess
 ) -> @ast::crate {
-    let p = new_parser_from_file(sess, /*bad*/ copy cfg, input);
-    p.parse_crate_mod(/*bad*/ copy cfg)
-    // why is there no p.abort_if_errors here?
-}
-
-pub fn parse_crate_from_file_using_tts(
-    input: &Path,
-    cfg: ast::crate_cfg,
-    sess: @mut ParseSess
-) -> @ast::crate {
-    let p = new_parser_from_file(sess, /*bad*/ copy cfg, input);
-    let tts = p.parse_all_token_trees();
-    new_parser_from_tts(sess,cfg,tts).parse_crate_mod(/*bad*/ copy cfg)
+    new_parser_from_file(sess, /*bad*/ copy cfg, input).parse_crate_mod()
     // why is there no p.abort_if_errors here?
 }
 
-
-
 pub fn parse_crate_from_source_str(
     name: ~str,
     source: @~str,
@@ -117,10 +98,9 @@ pub fn parse_crate_from_source_str(
         sess,
         /*bad*/ copy cfg,
         /*bad*/ copy name,
-        codemap::FssNone,
         source
     );
-    maybe_aborted(p.parse_crate_mod(/*bad*/ copy cfg),p)
+    maybe_aborted(p.parse_crate_mod(),p)
 }
 
 pub fn parse_expr_from_source_str(
@@ -133,7 +113,6 @@ pub fn parse_expr_from_source_str(
         sess,
         cfg,
         /*bad*/ copy name,
-        codemap::FssNone,
         source
     );
     maybe_aborted(p.parse_expr(), p)
@@ -150,7 +129,6 @@ pub fn parse_item_from_source_str(
         sess,
         cfg,
         /*bad*/ copy name,
-        codemap::FssNone,
         source
     );
     maybe_aborted(p.parse_item(attrs),p)
@@ -166,7 +144,6 @@ pub fn parse_meta_from_source_str(
         sess,
         cfg,
         /*bad*/ copy name,
-        codemap::FssNone,
         source
     );
     maybe_aborted(p.parse_meta_item(),p)
@@ -183,7 +160,6 @@ pub fn parse_stmt_from_source_str(
         sess,
         cfg,
         /*bad*/ copy name,
-        codemap::FssNone,
         source
     );
     maybe_aborted(p.parse_stmt(attrs),p)
@@ -199,13 +175,18 @@ pub fn parse_tts_from_source_str(
         sess,
         cfg,
         /*bad*/ copy name,
-        codemap::FssNone,
         source
     );
     *p.quote_depth += 1u;
+    // right now this is re-creating the token trees from ... token trees.
     maybe_aborted(p.parse_all_token_trees(),p)
 }
 
+// given a function and parsing information (source str,
+// filename, crate cfg, and sess), create a parser,
+// apply the function, and check that the parser
+// consumed all of the input before returning the function's
+// result.
 pub fn parse_from_source_str<T>(
     f: &fn(&Parser) -> T,
     name: ~str, ss: codemap::FileSubstr,
@@ -213,7 +194,7 @@ pub fn parse_from_source_str<T>(
     cfg: ast::crate_cfg,
     sess: @mut ParseSess
 ) -> T {
-    let p = new_parser_from_source_str(
+    let p = new_parser_from_source_substr(
         sess,
         cfg,
         name,
@@ -227,6 +208,7 @@ pub fn parse_from_source_str<T>(
     maybe_aborted(r,p)
 }
 
+// return the next unused node id.
 pub fn next_node_id(sess: @mut ParseSess) -> node_id {
     let rv = sess.next_id;
     sess.next_id += 1;
@@ -235,39 +217,24 @@ pub fn next_node_id(sess: @mut ParseSess) -> node_id {
     return rv;
 }
 
+// Create a new parser from a source string
 pub fn new_parser_from_source_str(sess: @mut ParseSess,
                                   cfg: ast::crate_cfg,
                                   name: ~str,
-                                  ss: codemap::FileSubstr,
                                   source: @~str)
                                -> Parser {
-    let filemap = sess.cm.new_filemap_w_substr(name, ss, source);
-    let srdr = lexer::new_string_reader(
-        copy sess.span_diagnostic,
-        filemap,
-        sess.interner
-    );
-    Parser(sess, cfg, srdr as @reader)
+    filemap_to_parser(sess,string_to_filemap(sess,source,name),cfg)
 }
 
-/// Read the entire source file, return a parser
-/// that draws from that string
-pub fn new_parser_result_from_file(
-    sess: @mut ParseSess,
-    cfg: ast::crate_cfg,
-    path: &Path
-) -> Result<Parser, ~str> {
-    match io::read_whole_file_str(path) {
-        Ok(src) => {
-            let filemap = sess.cm.new_filemap(path.to_str(), @src);
-            let srdr = lexer::new_string_reader(copy sess.span_diagnostic,
-                                                filemap,
-                                                sess.interner);
-            Ok(Parser(sess, cfg, srdr as @reader))
-
-        }
-        Err(e) => Err(e)
-    }
+// Create a new parser from a source string where the origin
+// is specified as a substring of another file.
+pub fn new_parser_from_source_substr(sess: @mut ParseSess,
+                                  cfg: ast::crate_cfg,
+                                  name: ~str,
+                                  ss: codemap::FileSubstr,
+                                  source: @~str)
+                               -> Parser {
+    filemap_to_parser(sess,substring_to_filemap(sess,source,name,ss),cfg)
 }
 
 /// Create a new parser, handling errors as appropriate
@@ -277,35 +244,85 @@ pub fn new_parser_from_file(
     cfg: ast::crate_cfg,
     path: &Path
 ) -> Parser {
-    match new_parser_result_from_file(sess, cfg, path) {
-        Ok(parser) => parser,
-        Err(e) => {
-            sess.span_diagnostic.handler().fatal(e)
-        }
-    }
+    filemap_to_parser(sess,file_to_filemap(sess,path,None),cfg)
 }
 
-/// Create a new parser based on a span from an existing parser. Handles
-/// error messages correctly when the file does not exist.
+/// Given a session, a crate config, a path, and a span, add
+/// the file at the given path to the codemap, and return a parser.
+/// On an error, use the given span as the source of the problem.
 pub fn new_sub_parser_from_file(
     sess: @mut ParseSess,
     cfg: ast::crate_cfg,
     path: &Path,
     sp: span
 ) -> Parser {
-    match new_parser_result_from_file(sess, cfg, path) {
-        Ok(parser) => parser,
+    filemap_to_parser(sess,file_to_filemap(sess,path,Some(sp)),cfg)
+}
+
+/// Given a filemap and config, return a parser
+pub fn filemap_to_parser(sess: @mut ParseSess,
+                         filemap: @FileMap,
+                         cfg: ast::crate_cfg) -> Parser {
+    tts_to_parser(sess,filemap_to_tts(sess,filemap),cfg)
+}
+
+// must preserve old name for now, because quote! from the *existing*
+// compiler expands into it
+pub fn new_parser_from_tts(sess: @mut ParseSess,
+                     cfg: ast::crate_cfg,
+                     tts: ~[ast::token_tree]) -> Parser {
+    tts_to_parser(sess,tts,cfg)
+}
+
+
+// base abstractions
+
+/// Given a session and a path and an optional span (for error reporting),
+/// add the path to the session's codemap and return the new filemap.
+pub fn file_to_filemap(sess: @mut ParseSess, path: &Path, spanopt: Option<span>)
+    -> @FileMap {
+    match io::read_whole_file_str(path) {
+        Ok(src) => string_to_filemap(sess, @src, path.to_str()),
         Err(e) => {
-            sess.span_diagnostic.span_fatal(sp, e)
+            match spanopt {
+                Some(span) => sess.span_diagnostic.span_fatal(span, e),
+                None => sess.span_diagnostic.handler().fatal(e)
+            }
         }
     }
 }
 
-pub fn new_parser_from_tts(
-    sess: @mut ParseSess,
-    cfg: ast::crate_cfg,
-    tts: ~[ast::token_tree]
-) -> Parser {
+// given a session and a string, add the string to
+// the session's codemap and return the new filemap
+pub fn string_to_filemap(sess: @mut ParseSess, source: @~str, path: ~str)
+    -> @FileMap {
+    sess.cm.new_filemap(path, source)
+}
+
+// given a session and a string and a path and a FileSubStr, add
+// the string to the CodeMap and return the new FileMap
+pub fn substring_to_filemap(sess: @mut ParseSess, source: @~str, path: ~str,
+                           filesubstr: FileSubstr) -> @FileMap {
+    sess.cm.new_filemap_w_substr(path,filesubstr,source)
+}
+
+// given a filemap, produce a sequence of token-trees
+pub fn filemap_to_tts(sess: @mut ParseSess, filemap: @FileMap)
+    -> ~[ast::token_tree] {
+    // it appears to me that the cfg doesn't matter here... indeed,
+    // parsing tt's probably shouldn't require a parser at all.
+    let cfg = ~[];
+    let srdr = lexer::new_string_reader(copy sess.span_diagnostic,
+                                        filemap,
+                                        sess.interner);
+    let p1 = Parser(sess, cfg, srdr as @reader);
+    p1.parse_all_token_trees()
+}
+
+// given tts and cfg, produce a parser
+pub fn tts_to_parser(sess: @mut ParseSess,
+                     tts: ~[ast::token_tree],
+                     cfg: ast::crate_cfg) -> Parser {
     let trdr = lexer::new_tt_reader(
         copy sess.span_diagnostic,
         sess.interner,
@@ -329,8 +346,77 @@ mod test {
     use std::serialize::Encodable;
     use std;
     use core::io;
+    use core::option::Option;
+    use core::option::Some;
     use core::option::None;
+    use core::int;
+    use core::num::NumCast;
+    use core::path::Path;
+    use codemap::{dummy_sp, CodeMap, span, BytePos, spanned};
+    use opt_vec;
     use ast;
+    use abi;
+    use ast_util::mk_ident;
+    use parse::parser::Parser;
+    use parse::token::{ident_interner, mk_ident_interner, mk_fresh_ident_interner};
+    use diagnostic::{span_handler, mk_span_handler, mk_handler, Emitter};
+
+    // add known names to interner for testing
+    fn mk_testing_interner() -> @ident_interner {
+        let i = mk_fresh_ident_interner();
+        // baby hack; in order to put the identifiers
+        // 'a' and 'b' at known locations, we're going
+        // to fill up the interner to length 100. If
+        // the # of preloaded items on the interner
+        // ever gets larger than 100, we'll have to
+        // adjust this number (say, to 200) and
+        // change the numbers in the identifier
+        // test cases below.
+
+        assert!(i.len() < 100);
+        for int::range(0,100-((i.len()).to_int())) |_dc| {
+            i.gensym(@~"dontcare");
+        }
+        i.intern(@~"a");
+        i.intern(@~"b");
+        i.intern(@~"c");
+        i.intern(@~"d");
+        i.intern(@~"return");
+        assert!(i.get(ast::ident{repr:101,ctxt:0}) == @~"b");
+        i
+    }
+
+    // make a parse_sess that's closed over a
+    // testing interner (where a -> 100, b -> 101)
+    fn mk_testing_parse_sess() -> @mut ParseSess {
+        let interner = mk_testing_interner();
+        let cm = @CodeMap::new();
+        @mut ParseSess {
+            cm: cm,
+            next_id: 1,
+            span_diagnostic: mk_span_handler(mk_handler(None), cm),
+            interner: interner,
+        }
+    }
+
+    // map a string to tts, using a made-up filename: return both the token_trees
+    // and the ParseSess
+    fn string_to_tts_t (source_str : @~str) -> (~[ast::token_tree],@mut ParseSess) {
+        let ps = mk_testing_parse_sess();
+        (filemap_to_tts(ps,string_to_filemap(ps,source_str,~"bogofile")),ps)
+    }
+
+    // map a string to tts, return the tt without its parsesess
+    fn string_to_tts_only(source_str : @~str) -> ~[ast::token_tree] {
+        let (tts,ps) = string_to_tts_t(source_str);
+        tts
+    }
+
+    // map string to parser (via tts)
+    fn string_to_parser(source_str: @~str) -> Parser {
+        let ps = mk_testing_parse_sess();
+        new_parser_from_source_str(ps,~[],~"bogofile",source_str)
+    }
 
     #[test] fn to_json_str<E : Encodable<std::json::Encoder>>(val: @E) -> ~str {
         do io::with_str_writer |writer| {
@@ -339,49 +425,71 @@ mod test {
     }
 
     fn string_to_crate (source_str : @~str) -> @ast::crate {
-        parse_crate_from_source_str(
-            ~"bogofile",
-            source_str,
-            ~[],
-            new_parse_sess(None))
+        string_to_parser(source_str).parse_crate_mod()
     }
 
-    fn string_to_tt_to_crate (source_str : @~str) -> @ast::crate {
-        let tts = parse_tts_from_source_str(
-            ~"bogofile",
-           source_str,
-           ~[],
-           new_parse_sess(None));
-        new_parser_from_tts(new_parse_sess(None),~[],tts)
-            .parse_crate_mod(~[])
+    fn string_to_expr (source_str : @~str) -> @ast::expr {
+        string_to_parser(source_str).parse_expr()
     }
 
-    // make sure that parsing from TTs produces the same result
-    // as parsing from strings
-    #[test] fn tts_produce_the_same_result () {
-        let source_str = @~"fn foo (x : int) { x; }";
-        assert_eq!(string_to_tt_to_crate(source_str),
-                     string_to_crate(source_str));
+    fn string_to_item (source_str : @~str) -> Option<@ast::item> {
+        string_to_parser(source_str).parse_item(~[])
     }
 
-    // check the contents of the tt manually:
-    #[test] fn alltts () {
-        let source_str = @~"fn foo (x : int) { x; }";
-        let tts = parse_tts_from_source_str(
-            ~"bogofile",
-            source_str,
-            ~[],
-            new_parse_sess(None));
-        assert_eq!(
-            to_json_str(@tts),
-            ~"[\
+    fn string_to_stmt (source_str : @~str) -> @ast::stmt {
+        string_to_parser(source_str).parse_stmt(~[])
+    }
+
+    // produce a codemap::span
+    fn sp (a: uint, b: uint) -> span {
+        span{lo:BytePos(a),hi:BytePos(b),expn_info:None}
+    }
+
+    // convert a vector of uints to a vector of ast::idents
+    fn ints_to_idents(ids: ~[uint]) -> ~[ast::ident] {
+        ids.map(|u| mk_ident(*u))
+    }
+
+    #[test] fn path_exprs_1 () {
+        assert_eq!(string_to_expr(@~"a"),
+                   @ast::expr{id:1,
+                              callee_id:2,
+                              node:ast::expr_path(@ast::Path {span:sp(0,1),
+                                                              global:false,
+                                                              idents:~[mk_ident(100)],
+                                                              rp:None,
+                                                              types:~[]}),
+                              span:sp(0,1)})
+    }
+
+    #[test] fn path_exprs_2 () {
+        assert_eq!(string_to_expr(@~"::a::b"),
+                   @ast::expr{id:1,
+                               callee_id:2,
+                               node:ast::expr_path(@ast::Path {span:sp(0,6),
+                                                               global:true,
+                                                               idents:ints_to_idents(~[100,101]),
+                                                               rp:None,
+                                                               types:~[]}),
+                              span:sp(0,6)})
+    }
+
+    #[should_fail]
+    #[test] fn bad_path_expr_1() {
+        string_to_expr(@~"::abc::def::return");
+    }
+
+    #[test] fn string_to_tts_1 () {
+        let (tts,ps) = string_to_tts_t(@~"fn a (b : int) { b; }");
+        assert_eq!(to_json_str(@tts),
+                   ~"[\
                 [\"tt_tok\",null,[\"IDENT\",\"fn\",false]],\
-                [\"tt_tok\",null,[\"IDENT\",\"foo\",false]],\
+                [\"tt_tok\",null,[\"IDENT\",\"a\",false]],\
                 [\
                     \"tt_delim\",\
                     [\
                         [\"tt_tok\",null,\"LPAREN\"],\
-                        [\"tt_tok\",null,[\"IDENT\",\"x\",false]],\
+                        [\"tt_tok\",null,[\"IDENT\",\"b\",false]],\
                         [\"tt_tok\",null,\"COLON\"],\
                         [\"tt_tok\",null,[\"IDENT\",\"int\",false]],\
                         [\"tt_tok\",null,\"RPAREN\"]\
@@ -391,21 +499,181 @@ mod test {
                     \"tt_delim\",\
                     [\
                         [\"tt_tok\",null,\"LBRACE\"],\
-                        [\"tt_tok\",null,[\"IDENT\",\"x\",false]],\
+                        [\"tt_tok\",null,[\"IDENT\",\"b\",false]],\
                         [\"tt_tok\",null,\"SEMI\"],\
                         [\"tt_tok\",null,\"RBRACE\"]\
                     ]\
                 ]\
             ]"
-        );
-        let ast1 = new_parser_from_tts(new_parse_sess(None),~[],tts)
-            .parse_item(~[]);
-        let ast2 = parse_item_from_source_str(
-            ~"bogofile",
-            @~"fn foo (x : int) { x; }",
-            ~[],~[],
-            new_parse_sess(None));
-        assert_eq!(ast1,ast2);
+                  );
+    }
+
+    #[test] fn ret_expr() {
+        assert_eq!(string_to_expr(@~"return d"),
+                   @ast::expr{id:3,
+                              callee_id:4,
+                              node:ast::expr_ret(
+                                  Some(@ast::expr{id:1,callee_id:2,
+                                                  node:ast::expr_path(
+                                                      @ast::Path{span:sp(7,8),
+                                                                 global:false,
+                                                                 idents:~[mk_ident(103)],
+                                                                 rp:None,
+                                                                 types:~[]
+                                                                }),
+                                                  span:sp(7,8)})),
+                              span:sp(0,8)})
+    }
+
+    #[test] fn parse_stmt_1 () {
+        assert_eq!(string_to_stmt(@~"b;"),
+                   @spanned{
+                       node: ast::stmt_expr(@ast::expr{
+                           id: 1,
+                           callee_id: 2,
+                           node: ast::expr_path(
+                               @ast::Path{
+                                   span:sp(0,1),
+                                   global:false,
+                                   idents:~[mk_ident(101)],
+                                   rp:None,
+                                   types: ~[]}),
+                           span: sp(0,1)},
+                                            3), // fixme
+                       span: sp(0,1)})
+
+    }
+
+    fn parser_done(p: Parser){
+        assert_eq!(*p.token,token::EOF);
+    }
+
+    #[test] fn parse_ident_pat () {
+        let parser = string_to_parser(@~"b");
+        assert_eq!(parser.parse_pat(false),
+                   @ast::pat{id:1, // fixme
+                             node: ast::pat_ident(ast::bind_by_copy,
+                                                  @ast::Path{
+                                                      span:sp(0,1),
+                                                      global:false,
+                                                      idents:~[mk_ident(101)],
+                                                      rp: None,
+                                                      types: ~[]},
+                                                  None // no idea
+                                                 ),
+                             span: sp(0,1)});
+        parser_done(parser);
+    }
+
+    #[test] fn parse_arg () {
+        let parser = string_to_parser(@~"b : int");
+        assert_eq!(parser.parse_arg_general(true),
+                   ast::arg{
+                       mode: ast::infer(1),
+                       is_mutbl: false,
+                       ty: @ast::Ty{id:4, // fixme
+                                    node: ast::ty_path(@ast::Path{
+                                        span:sp(4,4), // this is bizarre...
+                                        // check this in the original parser?
+                                        global:false,
+                                        idents:~[mk_ident(105)],
+                                        rp: None,
+                                        types: ~[]},
+                                                       3),
+                                    span:sp(4,7)},
+                       pat: @ast::pat{id:2,
+                                      node: ast::pat_ident(ast::bind_by_copy,
+                                                           @ast::Path{
+                                                               span:sp(0,1),
+                                                               global:false,
+                                                               idents:~[mk_ident(101)],
+                                                               rp: None,
+                                                               types: ~[]},
+                                                           None // no idea
+                                                          ),
+                                      span: sp(0,3)}, // really?
+                       id: 5 // fixme
+                   })
+    }
+
+    // check the contents of the tt manually:
+    #[test] fn parse_fundecl () {
+        // this test depends on the intern order of "fn" and "int", and on the
+        // assignment order of the node_ids.
+        assert_eq!(string_to_item(@~"fn a (b : int) { b; }"),
+                  Some(
+                      @ast::item{ident:mk_ident(100),
+                            attrs:~[],
+                            id: 11, // fixme
+                            node: ast::item_fn(ast::fn_decl{
+                                inputs: ~[ast::arg{
+                                    mode: ast::infer(1),
+                                    is_mutbl: false,
+                                    ty: @ast::Ty{id:4, // fixme
+                                                node: ast::ty_path(@ast::Path{
+                                        span:sp(10,13),
+                                        global:false,
+                                        idents:~[mk_ident(106)],
+                                        rp: None,
+                                        types: ~[]},
+                                                       3),
+                                                span:sp(10,13)},
+                                    pat: @ast::pat{id:2, // fixme
+                                                   node: ast::pat_ident(
+                                                       ast::bind_by_copy,
+                                                       @ast::Path{
+                                                           span:sp(6,7),
+                                                           global:false,
+                                                           idents:~[mk_ident(101)],
+                                                           rp: None,
+                                                           types: ~[]},
+                                                       None // no idea
+                                                   ),
+                                                  span: sp(6,9)}, // bleah.
+                                    id: 5 // fixme
+                                }],
+                                output: @ast::Ty{id:6, // fixme
+                                                 node: ast::ty_nil,
+                                                 span:sp(15,15)}, // not sure
+                                cf: ast::return_val
+                            },
+                                    ast::impure_fn,
+                                    abi::AbiSet::Rust(),
+                                    ast::Generics{ // no idea on either of these:
+                                        lifetimes: opt_vec::Empty,
+                                        ty_params: opt_vec::Empty,
+                                    },
+                                    spanned{
+                                        span: sp(15,21),
+                                        node: ast::blk_{
+                                            view_items: ~[],
+                                            stmts: ~[@spanned{
+                                                node: ast::stmt_semi(@ast::expr{
+                                                    id: 7,
+                                                    callee_id: 8,
+                                                    node: ast::expr_path(
+                                                        @ast::Path{
+                                                            span:sp(17,18),
+                                                            global:false,
+                                                            idents:~[mk_ident(101)],
+                                                            rp:None,
+                                                            types: ~[]}),
+                                                    span: sp(17,18)},
+                                                                     9), // fixme
+                                                span: sp(17,18)}],
+                                            expr: None,
+                                            id: 10, // fixme
+                                            rules: ast::default_blk // no idea
+                                        }}),
+                            vis: ast::inherited,
+                            span: sp(0,21)}));
+    }
+
+
+    #[test] fn parse_exprs () {
+        // just make sure that they parse....
+        string_to_expr(@~"3 + 4");
+        string_to_expr(@~"a::z.froob(b,@(987+3))");
     }
 }
 
diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs
index e6e98a35d6e..ce21e0f672d 100644
--- a/src/libsyntax/parse/obsolete.rs
+++ b/src/libsyntax/parse/obsolete.rs
@@ -259,7 +259,7 @@ pub impl Parser {
     fn try_parse_obsolete_struct_ctor(&self) -> bool {
         if self.eat_obsolete_ident("new") {
             self.obsolete(*self.last_span, ObsoleteStructCtor);
-            self.parse_fn_decl(|p| p.parse_arg());
+            self.parse_fn_decl();
             self.parse_block();
             true
         } else {
@@ -288,7 +288,7 @@ pub impl Parser {
             self.eat_keyword(&~"priv");
             self.bump();
             while *self.token != token::RBRACE {
-                self.parse_single_class_item(ast::private);
+                self.parse_single_struct_field(ast::private);
             }
             self.bump();
             true
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index c35b0e2e8c2..30275436c06 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -58,7 +58,7 @@ use ast::{view_item_, view_item_extern_mod, view_item_use};
 use ast::{view_path, view_path_glob, view_path_list, view_path_simple};
 use ast::visibility;
 use ast;
-use ast_util::{ident_to_path, operator_prec};
+use ast_util::{as_prec, ident_to_path, operator_prec};
 use ast_util;
 use codemap::{span, BytePos, spanned, mk_sp};
 use codemap;
@@ -82,9 +82,8 @@ use parse::obsolete::ObsoleteMode;
 use parse::obsolete::{ObsoleteLifetimeNotation, ObsoleteConstManagedPointer};
 use parse::obsolete::{ObsoletePurity, ObsoleteStaticMethod};
 use parse::obsolete::{ObsoleteConstItem, ObsoleteFixedLengthVectorType};
-use parse::prec::{as_prec, token_to_binop};
 use parse::token::{can_begin_expr, is_ident, is_ident_or_path};
-use parse::token::{is_plain_ident, INTERPOLATED, special_idents};
+use parse::token::{is_plain_ident, INTERPOLATED, special_idents, token_to_binop};
 use parse::token;
 use parse::{new_sub_parser_from_file, next_node_id, ParseSess};
 use opt_vec;
@@ -99,7 +98,6 @@ use core::vec;
 enum restriction {
     UNRESTRICTED,
     RESTRICT_STMT_EXPR,
-    RESTRICT_NO_CALL_EXPRS,
     RESTRICT_NO_BAR_OP,
     RESTRICT_NO_BAR_OR_DOUBLEBAR_OP,
 }
@@ -369,7 +367,7 @@ pub impl Parser {
 
         let opt_abis = self.parse_opt_abis();
         let abis = opt_abis.get_or_default(AbiSet::Rust());
-        let purity = self.parse_purity();
+        let purity = self.parse_unsafety();
         self.expect_keyword(&~"fn");
         let (decl, lifetimes) = self.parse_ty_fn_decl();
         return ty_bare_fn(@TyBareFn {
@@ -403,7 +401,7 @@ pub impl Parser {
         // At this point, the allocation type and lifetime bound have been
         // parsed.
 
-        let purity = self.parse_purity();
+        let purity = self.parse_unsafety();
         let onceness = parse_onceness(self);
         self.expect_keyword(&~"fn");
 
@@ -428,7 +426,8 @@ pub impl Parser {
         }
     }
 
-    fn parse_purity(&self) -> purity {
+    // looks like this should be called parse_unsafety
+    fn parse_unsafety(&self) -> purity {
         if self.eat_keyword(&~"pure") {
             self.obsolete(*self.last_span, ObsoletePurity);
             return impure_fn;
@@ -474,6 +473,7 @@ pub impl Parser {
         (decl, lifetimes)
     }
 
+    // parse the methods in a trait declaration
     fn parse_trait_methods(&self) -> ~[trait_method] {
         do self.parse_unspanned_seq(
             &token::LBRACE,
@@ -521,7 +521,7 @@ pub impl Parser {
               token::LBRACE => {
                 debug!("parse_trait_methods(): parsing provided method");
                 let (inner_attrs, body) =
-                    p.parse_inner_attrs_and_block(true);
+                    p.parse_inner_attrs_and_block();
                 let attrs = vec::append(attrs, inner_attrs);
                 provided(@ast::method {
                     ident: ident,
@@ -559,6 +559,7 @@ pub impl Parser {
     }
 
     // parse [mut/const/imm] ID : TY
+    // now used only by obsolete record syntax parser...
     fn parse_ty_field(&self) -> ty_field {
         let lo = self.span.lo;
         let mutbl = self.parse_mutability();
@@ -763,6 +764,7 @@ pub impl Parser {
         return ty_rptr(opt_lifetime, mt);
     }
 
+    // parse an optional mode.
     fn parse_arg_mode(&self) -> mode {
         if self.eat(&token::BINOP(token::MINUS)) {
             self.obsolete(*self.span, ObsoleteMode);
@@ -829,10 +831,12 @@ pub impl Parser {
                   ty: t, pat: pat, id: self.get_id() }
     }
 
+    // parse a single function argument
     fn parse_arg(&self) -> arg_or_capture_item {
         either::Left(self.parse_arg_general(true))
     }
 
+    // parse an argument in a lambda header e.g. |arg, arg|
     fn parse_fn_block_arg(&self) -> arg_or_capture_item {
         let m = self.parse_arg_mode();
         let is_mutbl = self.eat_keyword(&~"mut");
@@ -869,6 +873,7 @@ pub impl Parser {
         }
     }
 
+    // matches token_lit = LIT_INT | ...
     fn lit_from_token(&self, tok: &token::Token) -> lit_ {
         match *tok {
             token::LIT_INT(i, it) => lit_int(i, it),
@@ -883,6 +888,7 @@ pub impl Parser {
         }
     }
 
+    // matches lit = true | false | token_lit
     fn parse_lit(&self) -> lit {
         let lo = self.span.lo;
         let lit = if self.eat_keyword(&~"true") {
@@ -898,30 +904,45 @@ pub impl Parser {
         codemap::spanned { node: lit, span: mk_sp(lo, self.last_span.hi) }
     }
 
-    // parse a path that doesn't have type parameters attached
-    fn parse_path_without_tps(&self)
-        -> @ast::Path {
-        maybe_whole!(self, nt_path);
+    // parse a path into a vector of idents, whether the path starts
+    // with ::, and a span.
+    fn parse_path(&self) -> (~[ast::ident],bool,span) {
+        let lo = self.span.lo;
+        let is_global = self.eat(&token::MOD_SEP);
+        let (ids,span{lo:_,hi,expn_info}) = self.parse_path_non_global();
+        (ids,is_global,span{lo:lo,hi:hi,expn_info:expn_info})
+    }
+
+    // parse a path beginning with an identifier into a vector of idents and a span
+    fn parse_path_non_global(&self) -> (~[ast::ident],span) {
         let lo = self.span.lo;
-        let global = self.eat(&token::MOD_SEP);
         let mut ids = ~[];
+        // must be at least one to begin:
+        ids.push(self.parse_ident());
         loop {
-            // if there's a ::< coming, stop processing
-            // the path.
-            let is_not_last =
-                self.look_ahead(2u) != token::LT
-                && self.look_ahead(1u) == token::MOD_SEP;
-
-            if is_not_last {
-                ids.push(self.parse_ident());
-                self.expect(&token::MOD_SEP);
-            } else {
-                ids.push(self.parse_ident());
-                break;
+            match *self.token {
+                token::MOD_SEP => {
+                    match self.look_ahead(1u) {
+                        token::IDENT(id,_) => {
+                            self.bump();
+                            ids.push(self.parse_ident());
+                        }
+                        _ => break
+                    }
+                }
+                _ => break
             }
         }
-        @ast::Path { span: mk_sp(lo, self.last_span.hi),
-                     global: global,
+        (ids, mk_sp(lo, self.last_span.hi))
+    }
+
+    // parse a path that doesn't have type parameters attached
+    fn parse_path_without_tps(&self)
+        -> @ast::Path {
+        maybe_whole!(self, nt_path);
+        let (ids,is_global,sp) = self.parse_path();
+        @ast::Path { span: sp,
+                     global: is_global,
                      idents: ids,
                      rp: None,
                      types: ~[] }
@@ -1054,6 +1075,9 @@ pub impl Parser {
         }
     }
 
+    // matches lifetimes = ( lifetime ) | ( lifetime , lifetimes )
+    // actually, it matches the empty one too, but putting that in there
+    // messes up the grammar....
     fn parse_lifetimes(&self) -> OptVec<ast::Lifetime> {
         /*!
          *
@@ -1079,7 +1103,8 @@ pub impl Parser {
                 token::GT => { return res; }
                 token::BINOP(token::SHR) => { return res; }
                 _ => {
-                    self.fatal(~"expected `,` or `>` after lifetime name");
+                    self.fatal(fmt!("expected `,` or `>` after lifetime name, got: %?",
+                                    *self.token));
                 }
             }
         }
@@ -1101,11 +1126,12 @@ pub impl Parser {
         }
     }
 
-    fn parse_field(&self, sep: token::Token) -> field {
+    // parse ident COLON expr
+    fn parse_field(&self) -> field {
         let lo = self.span.lo;
         let m = self.parse_mutability();
         let i = self.parse_ident();
-        self.expect(&sep);
+        self.expect(&token::COLON);
         let e = self.parse_expr();
         spanned(lo, e.span.hi, ast::field_ { mutbl: m, ident: i, expr: e })
     }
@@ -1158,7 +1184,7 @@ pub impl Parser {
             self.bump();
             // (e) is parenthesized e
             // (e,) is a tuple with only one field, e
-            let mut one_tuple = false;
+            let mut trailing_comma = false;
             if *self.token == token::RPAREN {
                 hi = self.span.hi;
                 self.bump();
@@ -1172,13 +1198,13 @@ pub impl Parser {
                     es.push(self.parse_expr());
                 }
                 else {
-                    one_tuple = true;
+                    trailing_comma = true;
                 }
             }
             hi = self.span.hi;
             self.expect(&token::RPAREN);
 
-            return if es.len() == 1 && !one_tuple {
+            return if es.len() == 1 && !trailing_comma {
                 self.mk_expr(lo, self.span.hi, expr_paren(es[0]))
             }
             else {
@@ -1246,6 +1272,7 @@ pub impl Parser {
             }
             hi = self.span.hi;
         } else if self.eat_keyword(&~"__log") {
+            // LOG expression
             self.expect(&token::LPAREN);
             let lvl = self.parse_expr();
             self.expect(&token::COMMA);
@@ -1254,12 +1281,14 @@ pub impl Parser {
             hi = self.span.hi;
             self.expect(&token::RPAREN);
         } else if self.eat_keyword(&~"return") {
+            // RETURN expression
             if can_begin_expr(&*self.token) {
                 let e = self.parse_expr();
                 hi = e.span.hi;
                 ex = expr_ret(Some(e));
             } else { ex = expr_ret(None); }
         } else if self.eat_keyword(&~"break") {
+            // BREAK expression
             if is_ident(&*self.token) {
                 ex = expr_break(Some(self.parse_ident()));
             } else {
@@ -1267,6 +1296,7 @@ pub impl Parser {
             }
             hi = self.span.hi;
         } else if self.eat_keyword(&~"copy") {
+            // COPY expression
             let e = self.parse_expr();
             ex = expr_copy(e);
             hi = e.span.hi;
@@ -1277,6 +1307,7 @@ pub impl Parser {
 
             // `!`, as an operator, is prefix, so we know this isn't that
             if *self.token == token::NOT {
+                // MACRO INVOCATION expression
                 self.bump();
                 match *self.token {
                     token::LPAREN | token::LBRACE => {}
@@ -1301,7 +1332,7 @@ pub impl Parser {
                     let mut fields = ~[];
                     let mut base = None;
 
-                    fields.push(self.parse_field(token::COLON));
+                    fields.push(self.parse_field());
                     while *self.token != token::RBRACE {
                         if self.try_parse_obsolete_with() {
                             break;
@@ -1318,7 +1349,7 @@ pub impl Parser {
                             // Accept an optional trailing comma.
                             break;
                         }
-                        fields.push(self.parse_field(token::COLON));
+                        fields.push(self.parse_field());
                     }
 
                     hi = pth.span.hi;
@@ -1331,6 +1362,7 @@ pub impl Parser {
             hi = pth.span.hi;
             ex = expr_path(pth);
         } else {
+            // other literal expression
             let lit = self.parse_lit();
             hi = lit.span.hi;
             ex = expr_lit(@lit);
@@ -1339,6 +1371,7 @@ pub impl Parser {
         return self.mk_expr(lo, hi, ex);
     }
 
+    // parse a block or unsafe block
     fn parse_block_expr(
         &self,
         lo: BytePos,
@@ -1349,16 +1382,12 @@ pub impl Parser {
         return self.mk_expr(blk.span.lo, blk.span.hi, expr_block(blk));
     }
 
-    // parse a.b or a(13) or just a
+    // parse a.b or a(13) or a[4] or just a
     fn parse_dot_or_call_expr(&self) -> @expr {
         let b = self.parse_bottom_expr();
         self.parse_dot_or_call_expr_with(b)
     }
 
-    fn permits_call(&self) -> bool {
-        return *self.restriction != RESTRICT_NO_CALL_EXPRS;
-    }
-
     fn parse_dot_or_call_expr_with(&self, e0: @expr) -> @expr {
         let mut e = e0;
         let lo = e.span.lo;
@@ -1379,7 +1408,7 @@ pub impl Parser {
 
                     // expr.f() method call
                     match *self.token {
-                        token::LPAREN if self.permits_call() => {
+                        token::LPAREN => {
                             let es = self.parse_unspanned_seq(
                                 &token::LPAREN,
                                 &token::RPAREN,
@@ -1403,7 +1432,7 @@ pub impl Parser {
             if self.expr_is_complete(e) { break; }
             match *self.token {
               // expr(...)
-              token::LPAREN if self.permits_call() => {
+              token::LPAREN => {
                 let es = self.parse_unspanned_seq(
                     &token::LPAREN,
                     &token::RPAREN,
@@ -1771,10 +1800,10 @@ pub impl Parser {
         let lo = self.span.lo;
         let lhs = self.parse_binops();
         match *self.token {
-            token::EQ => {
-                self.bump();
-                let rhs = self.parse_expr();
-                self.mk_expr(lo, rhs.span.hi, expr_assign(lhs, rhs))
+          token::EQ => {
+              self.bump();
+              let rhs = self.parse_expr();
+              self.mk_expr(lo, rhs.span.hi, expr_assign(lhs, rhs))
           }
           token::BINOPEQ(op) => {
               self.bump();
@@ -1815,6 +1844,7 @@ pub impl Parser {
         }
     }
 
+    // parse an 'if' expression ('if' token already eaten)
     fn parse_if_expr(&self) -> @expr {
         let lo = self.last_span.lo;
         let cond = self.parse_expr();
@@ -1829,7 +1859,7 @@ pub impl Parser {
         self.mk_expr(lo, hi, expr_if(cond, thn, els))
     }
 
-    // `|args| { ... }` like in `do` expressions
+    // `|args| { ... }` or `{ ...}` like in `do` expressions
     fn parse_lambda_block_expr(&self) -> @expr {
         self.parse_lambda_expr_(
             || {
@@ -1863,6 +1893,9 @@ pub impl Parser {
                                 || self.parse_expr())
     }
 
+    // parse something of the form |args| expr
+    // this is used both in parsing a lambda expr
+    // and in parsing a block expr as e.g. in for...
     fn parse_lambda_expr_(
         &self,
         parse_decl: &fn() -> fn_decl,
@@ -1893,6 +1926,9 @@ pub impl Parser {
         }
     }
 
+    // parse a 'for' or 'do'.
+    // the 'for' and 'do' expressions parse as calls, but look like
+    // function calls followed by a closure expression.
     fn parse_sugary_call_expr(&self, keyword: ~str,
                               sugar: CallSugar,
                               ctor: &fn(v: @expr) -> expr_) -> @expr {
@@ -1953,7 +1989,7 @@ pub impl Parser {
     fn parse_while_expr(&self) -> @expr {
         let lo = self.last_span.lo;
         let cond = self.parse_expr();
-        let body = self.parse_block_no_value();
+        let body = self.parse_block();
         let hi = body.span.hi;
         return self.mk_expr(lo, hi, expr_while(cond, body));
     }
@@ -1981,7 +2017,7 @@ pub impl Parser {
             }
 
             let lo = self.last_span.lo;
-            let body = self.parse_block_no_value();
+            let body = self.parse_block();
             let hi = body.span.hi;
             return self.mk_expr(lo, hi, expr_loop(body, opt_ident));
         } else {
@@ -2079,6 +2115,7 @@ pub impl Parser {
         }
     }
 
+    // parse patterns, separated by '|' s
     fn parse_pats(&self) -> ~[@pat] {
         let mut pats = ~[];
         loop {
@@ -2133,6 +2170,7 @@ pub impl Parser {
         (before, slice, after)
     }
 
+    // parse the fields of a struct-like pattern
     fn parse_pat_fields(&self, refutable: bool) -> (~[ast::field_pat], bool) {
         let mut fields = ~[];
         let mut etc = false;
@@ -2176,6 +2214,9 @@ pub impl Parser {
         return (fields, etc);
     }
 
+    // parse a pattern. The 'refutable' argument
+    // appears to control whether the binding_mode
+    // 'bind_infer' or 'bind_by_copy' is used.
     fn parse_pat(&self, refutable: bool) -> @pat {
         maybe_whole!(self, nt_pat);
 
@@ -2183,7 +2224,9 @@ pub impl Parser {
         let mut hi = self.span.hi;
         let pat;
         match *self.token {
+            // parse _
           token::UNDERSCORE => { self.bump(); pat = pat_wild; }
+            // parse @pat
           token::AT => {
             self.bump();
             let sub = self.parse_pat(refutable);
@@ -2207,6 +2250,7 @@ pub impl Parser {
             };
           }
           token::TILDE => {
+            // parse ~pat
             self.bump();
             let sub = self.parse_pat(refutable);
             hi = sub.span.hi;
@@ -2229,6 +2273,7 @@ pub impl Parser {
             };
           }
           token::BINOP(token::AND) => {
+              // parse &pat
               let lo = self.span.lo;
               self.bump();
               let sub = self.parse_pat(refutable);
@@ -2259,6 +2304,7 @@ pub impl Parser {
             pat = pat_wild;
           }
           token::LPAREN => {
+            // parse (pat,pat,pat,...) as tuple
             self.bump();
             if *self.token == token::RPAREN {
                 hi = self.span.hi;
@@ -2283,6 +2329,7 @@ pub impl Parser {
             }
           }
           token::LBRACKET => {
+            // parse [pat,pat,...] as vector pattern
             self.bump();
             let (before, slice, after) =
                 self.parse_pat_vec_elements(refutable);
@@ -2295,6 +2342,7 @@ pub impl Parser {
                 || self.is_keyword(&~"true")
                 || self.is_keyword(&~"false")
             {
+                // parse an expression pattern or exp .. exp
                 let val = self.parse_expr_res(RESTRICT_NO_BAR_OP);
                 if self.eat(&token::DOTDOT) {
                     let end = self.parse_expr_res(RESTRICT_NO_BAR_OP);
@@ -2303,34 +2351,39 @@ pub impl Parser {
                     pat = pat_lit(val);
                 }
             } else if self.eat_keyword(&~"ref") {
+                // parse ref pat
                 let mutbl = self.parse_mutability();
                 pat = self.parse_pat_ident(refutable, bind_by_ref(mutbl));
             } else if self.eat_keyword(&~"copy") {
+                // parse copy pat
                 pat = self.parse_pat_ident(refutable, bind_by_copy);
             } else {
                 // XXX---refutable match bindings should work same as let
                 let binding_mode =
                     if refutable {bind_infer} else {bind_by_copy};
 
-                let cannot_be_enum_or_struct;
+                let can_be_enum_or_struct;
                 match self.look_ahead(1) {
                     token::LPAREN | token::LBRACKET | token::LT |
                     token::LBRACE | token::MOD_SEP =>
-                        cannot_be_enum_or_struct = false,
+                        can_be_enum_or_struct = true,
                     _ =>
-                        cannot_be_enum_or_struct = true
+                        can_be_enum_or_struct = false
                 }
 
-                if is_plain_ident(&*self.token) && cannot_be_enum_or_struct {
+                if is_plain_ident(&*self.token) && !can_be_enum_or_struct {
                     let name = self.parse_path_without_tps();
                     let sub;
                     if self.eat(&token::AT) {
+                        // parse foo @ pat
                         sub = Some(self.parse_pat(refutable));
                     } else {
+                        // or just foo
                         sub = None;
                     };
                     pat = pat_ident(binding_mode, name, sub);
                 } else {
+                    // parse an enum pat
                     let enum_path = self.parse_path_with_tps(true);
                     match *self.token {
                         token::LBRACE => {
@@ -2342,14 +2395,13 @@ pub impl Parser {
                         }
                         _ => {
                             let mut args: ~[@pat] = ~[];
-                            let mut star_pat = false;
                             match *self.token {
                               token::LPAREN => match self.look_ahead(1u) {
                                 token::BINOP(token::STAR) => {
                                     // This is a "top constructor only" pat
                                       self.bump(); self.bump();
-                                      star_pat = true;
                                       self.expect(&token::RPAREN);
+                                      pat = pat_enum(enum_path, None);
                                   }
                                 _ => {
                                     args = self.parse_unspanned_seq(
@@ -2360,23 +2412,21 @@ pub impl Parser {
                                         ),
                                         |p| p.parse_pat(refutable)
                                     );
+                                    pat = pat_enum(enum_path, Some(args));
                                   }
                               },
-                              _ => ()
-                            }
-                            // at this point, we're not sure whether it's a
-                            // enum or a bind
-                            if star_pat {
-                                pat = pat_enum(enum_path, None);
-                            }
-                            else if vec::is_empty(args) &&
-                                vec::len(enum_path.idents) == 1u {
-                                pat = pat_ident(binding_mode,
-                                                enum_path,
-                                                None);
-                            }
-                            else {
-                                pat = pat_enum(enum_path, Some(args));
+                              _ => {
+                                  if vec::len(enum_path.idents)==1u {
+                                      // it could still be either an enum
+                                      // or an identifier pattern, resolve
+                                      // will sort it out:
+                                      pat = pat_ident(binding_mode,
+                                                      enum_path,
+                                                      None);
+                                  } else {
+                                      pat = pat_enum(enum_path, Some(args));
+                                  }
+                              }
                             }
                         }
                     }
@@ -2388,6 +2438,8 @@ pub impl Parser {
         @ast::pat { id: self.get_id(), node: pat, span: mk_sp(lo, hi) }
     }
 
+    // used by the copy foo and ref foo patterns to give a good
+    // error message when parsing mistakes like ref foo(a,b)
     fn parse_pat_ident(&self, refutable: bool,
                        binding_mode: ast::binding_mode) -> ast::pat_ {
         if !is_plain_ident(&*self.token) {
@@ -2395,6 +2447,7 @@ pub impl Parser {
                 *self.last_span,
                 ~"expected identifier, found path");
         }
+        // why a path here, and not just an identifier?
         let name = self.parse_path_without_tps();
         let sub = if self.eat(&token::AT) {
             Some(self.parse_pat(refutable))
@@ -2416,8 +2469,7 @@ pub impl Parser {
     }
 
     // parse a local variable declaration
-    fn parse_local(&self, is_mutbl: bool,
-                   allow_init: bool) -> @local {
+    fn parse_local(&self, is_mutbl: bool) -> @local {
         let lo = self.span.lo;
         let pat = self.parse_pat(false);
         let mut ty = @Ty {
@@ -2426,7 +2478,7 @@ pub impl Parser {
             span: mk_sp(lo, lo),
         };
         if self.eat(&token::COLON) { ty = self.parse_ty(false); }
-        let init = if allow_init { self.parse_initializer() } else { None };
+        let init = self.parse_initializer();
         @spanned(
             lo,
             self.last_span.hi,
@@ -2440,18 +2492,19 @@ pub impl Parser {
         )
     }
 
+    // parse a "let" stmt
     fn parse_let(&self) -> @decl {
         let is_mutbl = self.eat_keyword(&~"mut");
         let lo = self.span.lo;
-        let mut locals = ~[self.parse_local(is_mutbl, true)];
+        let mut locals = ~[self.parse_local(is_mutbl)];
         while self.eat(&token::COMMA) {
-            locals.push(self.parse_local(is_mutbl, true));
+            locals.push(self.parse_local(is_mutbl));
         }
         return @spanned(lo, self.last_span.hi, decl_local(locals));
     }
 
-    /* assumes "let" token has already been consumed */
-    fn parse_instance_var(&self, pr: visibility) -> @struct_field {
+    // parse a structure field
+    fn parse_name_and_ty(&self, pr: visibility) -> @struct_field {
         let mut is_mutbl = struct_immutable;
         let lo = self.span.lo;
         if self.eat_keyword(&~"mut") {
@@ -2470,6 +2523,7 @@ pub impl Parser {
         })
     }
 
+    // parse a statement. may include decl
     fn parse_stmt(&self, first_item_attrs: ~[attribute]) -> @stmt {
         maybe_whole!(self, nt_stmt);
 
@@ -2489,6 +2543,11 @@ pub impl Parser {
         } else if is_ident(&*self.token)
             && !self.is_any_keyword(&copy *self.token)
             && self.look_ahead(1) == token::NOT {
+            // parse a macro invocation. Looks like there's serious
+            // overlap here; if this clause doesn't catch it (and it
+            // won't, for brace-delimited macros) it will fall through
+            // to the macro clause of parse_item_or_view_item. This
+            // could use some cleanup, it appears to me.
 
             check_expected_item(self, first_item_attrs);
 
@@ -2530,7 +2589,7 @@ pub impl Parser {
                                          self.parse_outer_attributes());
 
             match self.parse_item_or_view_item(/*bad*/ copy item_attrs,
-                                               true, false, false) {
+                                                           false) {
               iovi_item(i) => {
                 let hi = i.span.hi;
                 let decl = @spanned(lo, hi, decl_item(i));
@@ -2554,52 +2613,41 @@ pub impl Parser {
         }
     }
 
+    // is this expression a successfully-parsed statement?
     fn expr_is_complete(&self, e: @expr) -> bool {
         return *self.restriction == RESTRICT_STMT_EXPR &&
             !classify::expr_requires_semi_to_be_stmt(e);
     }
 
+    // parse a block. No inner attrs are allowed.
     fn parse_block(&self) -> blk {
-        // disallow inner attrs:
-        let (attrs, blk) = self.parse_inner_attrs_and_block(false);
-        assert!(vec::is_empty(attrs));
-        return blk;
+        maybe_whole!(self, nt_block);
+
+        let lo = self.span.lo;
+        if self.eat_keyword(&~"unsafe") {
+            self.obsolete(copy *self.span, ObsoleteUnsafeBlock);
+        }
+        self.expect(&token::LBRACE);
+
+        return self.parse_block_tail_(lo, default_blk, ~[]);
     }
 
-    // I claim the existence of the 'parse_attrs' flag strongly
-    // suggests a name-change or refactoring for this function.
-    fn parse_inner_attrs_and_block(&self, parse_attrs: bool)
+    // parse a block. Inner attrs are allowed.
+    fn parse_inner_attrs_and_block(&self)
         -> (~[attribute], blk) {
 
         maybe_whole!(pair_empty self, nt_block);
 
-        fn maybe_parse_inner_attrs_and_next(p: &Parser, parse_attrs: bool) ->
-            (~[attribute], ~[attribute]) {
-            if parse_attrs {
-                p.parse_inner_attrs_and_next()
-            } else {
-                (~[], ~[])
-            }
-        }
-
         let lo = self.span.lo;
         if self.eat_keyword(&~"unsafe") {
             self.obsolete(copy *self.span, ObsoleteUnsafeBlock);
         }
         self.expect(&token::LBRACE);
-        let (inner, next) =
-            maybe_parse_inner_attrs_and_next(self, parse_attrs);
+        let (inner, next) = self.parse_inner_attrs_and_next();
 
         (inner, self.parse_block_tail_(lo, default_blk, next))
     }
 
-    fn parse_block_no_value(&self) -> blk {
-        // We parse blocks that cannot have a value the same as any other
-        // block; the type checker will make sure that the tail expression (if
-        // any) has unit type.
-        return self.parse_block();
-    }
-
     // Precondition: already parsed the '{' or '#{'
     // I guess that also means "already parsed the 'impure'" if
     // necessary, and this should take a qualifier.
@@ -2620,7 +2668,7 @@ pub impl Parser {
             items: items,
             _
         } = self.parse_items_and_view_items(first_item_attrs,
-                                            IMPORTS_AND_ITEMS_ALLOWED, false);
+                                            false, false);
 
         for items.each |item| {
             let decl = @spanned(item.span.lo, item.span.hi, decl_item(*item));
@@ -2739,6 +2787,9 @@ pub impl Parser {
         if self.eat_keyword(&~"once") { ast::Once } else { ast::Many }
     }
 
+    // matches optbounds = ( ( : ( boundseq )? )? )
+    // where   boundseq  = ( bound + boundseq ) | bound
+    // and     bound     = 'static | ty
     fn parse_optional_ty_param_bounds(&self) -> @OptVec<TyParamBound> {
         if !self.eat(&token::COLON) {
             return @opt_vec::Empty;
@@ -2799,6 +2850,7 @@ pub impl Parser {
         return @result;
     }
 
+    // matches typaram = IDENT optbounds
     fn parse_ty_param(&self) -> TyParam {
         let ident = self.parse_ident();
         let bounds = self.parse_optional_ty_param_bounds();
@@ -2842,7 +2894,8 @@ pub impl Parser {
         (lifetimes, opt_vec::take_vec(result))
     }
 
-    fn parse_fn_decl(&self, parse_arg_fn: &fn(&Parser) -> arg_or_capture_item)
+    // parse the argument list and result type of a function declaration
+    fn parse_fn_decl(&self)
         -> fn_decl
     {
         let args_or_capture_items: ~[arg_or_capture_item] =
@@ -2850,7 +2903,7 @@ pub impl Parser {
                 &token::LPAREN,
                 &token::RPAREN,
                 seq_sep_trailing_disallowed(token::COMMA),
-                parse_arg_fn
+                |p| p.parse_arg()
             );
 
         let inputs = either::lefts(args_or_capture_items);
@@ -2883,6 +2936,8 @@ pub impl Parser {
         self.bump();
     }
 
+    // parse the argument list and result type of a function
+    // that may have a self type.
     fn parse_fn_decl_with_self(
         &self,
         parse_arg_fn:
@@ -3030,6 +3085,7 @@ pub impl Parser {
         (spanned(lo, hi, self_ty), fn_decl)
     }
 
+    // parse the |arg, arg| header on a lambda
     fn parse_fn_block_decl(&self) -> fn_decl {
         let inputs_captures = {
             if self.eat(&token::OROR) {
@@ -3056,6 +3112,7 @@ pub impl Parser {
         }
     }
 
+    // parse the name and optional generic types of a function header.
     fn parse_fn_header(&self) -> (ident, ast::Generics) {
         let id = self.parse_ident();
         let generics = self.parse_generics();
@@ -3073,15 +3130,17 @@ pub impl Parser {
                      span: mk_sp(lo, hi) }
     }
 
+    // parse an item-position function declaration.
     fn parse_item_fn(&self, purity: purity, abis: AbiSet) -> item_info {
         let (ident, generics) = self.parse_fn_header();
-        let decl = self.parse_fn_decl(|p| p.parse_arg());
-        let (inner_attrs, body) = self.parse_inner_attrs_and_block(true);
+        let decl = self.parse_fn_decl();
+        let (inner_attrs, body) = self.parse_inner_attrs_and_block();
         (ident,
          item_fn(decl, purity, abis, generics, body),
          Some(inner_attrs))
     }
 
+    // parse a method in a trait impl
     fn parse_method(&self) -> @method {
         let attrs = self.parse_outer_attributes();
         let lo = self.span.lo;
@@ -3094,7 +3153,7 @@ pub impl Parser {
             p.parse_arg()
         };
 
-        let (inner_attrs, body) = self.parse_inner_attrs_and_block(true);
+        let (inner_attrs, body) = self.parse_inner_attrs_and_block();
         let hi = body.span.hi;
         let attrs = vec::append(attrs, inner_attrs);
         @ast::method {
@@ -3227,7 +3286,7 @@ pub impl Parser {
             is_tuple_like = false;
             fields = ~[];
             while *self.token != token::RBRACE {
-                match self.parse_class_item() {
+                match self.parse_struct_decl_field() {
                   dtor_decl(ref blk, ref attrs, s) => {
                       match the_dtor {
                         Some((_, _, s_first)) => {
@@ -3310,12 +3369,13 @@ pub impl Parser {
         }
     }
 
-    fn parse_single_class_item(&self, vis: visibility) -> @struct_field {
+    // parse a structure field declaration
+    fn parse_single_struct_field(&self, vis: visibility) -> @struct_field {
         if self.eat_obsolete_ident("let") {
             self.obsolete(*self.last_span, ObsoleteLet);
         }
 
-        let a_var = self.parse_instance_var(vis);
+        let a_var = self.parse_name_and_ty(vis);
         match *self.token {
             token::SEMI => {
                 self.obsolete(copy *self.span, ObsoleteFieldTerminator);
@@ -3329,7 +3389,7 @@ pub impl Parser {
                 self.span_fatal(
                     copy *self.span,
                     fmt!(
-                        "expected `;`, `,`, or '}' but found `%s`",
+                        "expected `,`, or '}' but found `%s`",
                         self.this_token_to_str()
                     )
                 );
@@ -3338,13 +3398,8 @@ pub impl Parser {
         a_var
     }
 
-    fn parse_dtor(&self, attrs: ~[attribute]) -> class_contents {
-        let lo = self.last_span.lo;
-        let body = self.parse_block();
-        dtor_decl(body, attrs, mk_sp(lo, self.last_span.hi))
-    }
-
-    fn parse_class_item(&self) -> class_contents {
+    // parse an element of a struct definition
+    fn parse_struct_decl_field(&self) -> class_contents {
 
         if self.try_parse_obsolete_priv_section() {
             return members(~[]);
@@ -3353,11 +3408,11 @@ pub impl Parser {
         let attrs = self.parse_outer_attributes();
 
         if self.eat_keyword(&~"priv") {
-            return members(~[self.parse_single_class_item(private)])
+            return members(~[self.parse_single_struct_field(private)])
         }
 
         if self.eat_keyword(&~"pub") {
-           return members(~[self.parse_single_class_item(public)]);
+           return members(~[self.parse_single_struct_field(public)]);
         }
 
         if self.try_parse_obsolete_struct_ctor() {
@@ -3365,13 +3420,16 @@ pub impl Parser {
         }
 
         if self.eat_keyword(&~"drop") {
-           return self.parse_dtor(attrs);
+            let lo = self.last_span.lo;
+            let body = self.parse_block();
+            return dtor_decl(body, attrs, mk_sp(lo, self.last_span.hi))
         }
         else {
-           return members(~[self.parse_single_class_item(inherited)]);
+           return members(~[self.parse_single_struct_field(inherited)]);
         }
     }
 
+    // parse visiility: PUB, PRIV, or nothing
     fn parse_visibility(&self) -> visibility {
         if self.eat_keyword(&~"pub") { public }
         else if self.eat_keyword(&~"priv") { private }
@@ -3399,14 +3457,12 @@ pub impl Parser {
             items: starting_items,
             _
         } = self.parse_items_and_view_items(first_item_attrs,
-                                            VIEW_ITEMS_AND_ITEMS_ALLOWED,
-                                            true);
+                                            true, true);
         let mut items: ~[@item] = starting_items;
         let attrs_remaining_len = attrs_remaining.len();
 
-        // looks like this code depends on the invariant that
-        // outer attributes can't occur on view items (or macros
-        // invocations?)
+        // don't think this other loop is even necessary....
+
         let mut first = true;
         while *self.token != term {
             let mut attrs = self.parse_outer_attributes();
@@ -3418,9 +3474,7 @@ pub impl Parser {
                    attrs);
             match self.parse_item_or_view_item(
                 /*bad*/ copy attrs,
-                true,
-                false,
-                true
+                true // macros allowed
             ) {
               iovi_item(item) => items.push(item),
               iovi_view_item(view_item) => {
@@ -3525,6 +3579,7 @@ pub impl Parser {
         self.mod_path_stack.pop();
     }
 
+    // read a module from a source file.
     fn eval_src_mod(&self, id: ast::ident,
                     outer_attrs: ~[ast::attribute],
                     id_sp: span) -> (ast::item_, ~[ast::attribute]) {
@@ -3582,12 +3637,13 @@ pub impl Parser {
         }
     }
 
+    // parse a function declaration from a foreign module
     fn parse_item_foreign_fn(&self,  attrs: ~[attribute]) -> @foreign_item {
         let lo = self.span.lo;
         let vis = self.parse_visibility();
         let purity = self.parse_fn_purity();
         let (ident, generics) = self.parse_fn_header();
-        let decl = self.parse_fn_decl(|p| p.parse_arg());
+        let decl = self.parse_fn_decl();
         let hi = self.span.hi;
         self.expect(&token::SEMI);
         @ast::foreign_item { ident: ident,
@@ -3598,6 +3654,7 @@ pub impl Parser {
                              vis: vis }
     }
 
+    // parse a const definition from a foreign module
     fn parse_item_foreign_const(&self, vis: ast::visibility,
                                 attrs: ~[attribute]) -> @foreign_item {
         let lo = self.span.lo;
@@ -3622,6 +3679,7 @@ pub impl Parser {
                              vis: vis }
     }
 
+    // parse safe/unsafe and fn
     fn parse_fn_purity(&self) -> purity {
         if self.eat_keyword(&~"fn") { impure_fn }
         else if self.eat_keyword(&~"pure") {
@@ -3636,45 +3694,30 @@ pub impl Parser {
         else { self.unexpected(); }
     }
 
-    fn parse_foreign_item(&self, attrs: ~[attribute]) -> @foreign_item {
-        let vis = self.parse_visibility();
-        if self.is_keyword(&~"const") || self.is_keyword(&~"static") {
-            self.parse_item_foreign_const(vis, attrs)
-        } else {
-            self.parse_item_foreign_fn(attrs)
-        }
-    }
 
+    // at this point, this is essentially a wrapper for
+    // parse_foreign_items.
     fn parse_foreign_mod_items(&self, sort: ast::foreign_mod_sort,
                                abis: AbiSet,
                                first_item_attrs: ~[attribute])
                             -> foreign_mod {
-        // Shouldn't be any view items since we've already parsed an item attr
         let ParsedItemsAndViewItems {
             attrs_remaining: attrs_remaining,
             view_items: view_items,
             items: _,
             foreign_items: foreign_items
-        } = self.parse_items_and_view_items(first_item_attrs,
-                                            FOREIGN_ITEMS_ALLOWED,
-                                            true);
-
-        let mut items: ~[@foreign_item] = foreign_items;
+        } = self.parse_foreign_items(first_item_attrs, true);
         let mut initial_attrs = attrs_remaining;
-        while *self.token != token::RBRACE {
-            let attrs = vec::append(initial_attrs,
-                                    self.parse_outer_attributes());
-            initial_attrs = ~[];
-            items.push(self.parse_foreign_item(attrs));
-        }
+        assert!(*self.token == token::RBRACE);
         ast::foreign_mod {
             sort: sort,
             abis: abis,
             view_items: view_items,
-            items: items
+            items: foreign_items
         }
     }
 
+    // parse extern foo; or extern mod foo { ... } or extern { ... }
     fn parse_item_foreign_mod(&self,
                               lo: BytePos,
                               opt_abis: Option<AbiSet>,
@@ -3744,15 +3787,9 @@ pub impl Parser {
         })
     }
 
-    fn parse_type_decl(&self) -> (BytePos, ident) {
-        let lo = self.last_span.lo;
-        let id = self.parse_ident();
-        (lo, id)
-    }
-
     // parse type Foo = Bar;
     fn parse_item_type(&self) -> item_info {
-        let (_, ident) = self.parse_type_decl();
+        let ident = self.parse_ident();
         self.parse_region_param();
         let tps = self.parse_generics();
         self.expect(&token::EQ);
@@ -3769,11 +3806,13 @@ pub impl Parser {
         }
     }
 
+    // parse a structure-like enum variant definition
+    // this should probably be renamed or refactored...
     fn parse_struct_def(&self) -> @struct_def {
         let mut the_dtor: Option<(blk, ~[attribute], codemap::span)> = None;
         let mut fields: ~[@struct_field] = ~[];
         while *self.token != token::RBRACE {
-            match self.parse_class_item() {
+            match self.parse_struct_decl_field() {
                 dtor_decl(ref blk, ref attrs, s) => {
                     match the_dtor {
                         Some((_, _, s_first)) => {
@@ -3812,6 +3851,7 @@ pub impl Parser {
         };
     }
 
+    // parse the part of an "enum" decl following the '{'
     fn parse_enum_def(&self, _generics: &ast::Generics) -> enum_def {
         let mut variants = ~[];
         let mut all_nullary = true, have_disr = false;
@@ -3821,7 +3861,7 @@ pub impl Parser {
 
             let vis = self.parse_visibility();
 
-            let ident, needs_comma, kind;
+            let ident, kind;
             let mut args = ~[], disr_expr = None;
             ident = self.parse_ident();
             if self.eat(&token::LBRACE) {
@@ -3850,7 +3890,6 @@ pub impl Parser {
             } else {
                 kind = tuple_variant_kind(~[]);
             }
-            needs_comma = true;
 
             let vr = ast::variant_ {
                 name: ident,
@@ -3862,7 +3901,7 @@ pub impl Parser {
             };
             variants.push(spanned(vlo, self.last_span.hi, vr));
 
-            if needs_comma && !self.eat(&token::COMMA) { break; }
+            if !self.eat(&token::COMMA) { break; }
         }
         self.expect(&token::RBRACE);
         if (have_disr && !all_nullary) {
@@ -3873,6 +3912,7 @@ pub impl Parser {
         ast::enum_def { variants: variants }
     }
 
+    // parse an "enum" declaration
     fn parse_item_enum(&self) -> item_info {
         let id = self.parse_ident();
         self.parse_region_param();
@@ -3938,6 +3978,7 @@ pub impl Parser {
         }
     }
 
+    // parse a string as an ABI spec on an extern type or module
     fn parse_opt_abis(&self) -> Option<AbiSet> {
         match *self.token {
             token::LIT_STR(s) => {
@@ -3983,31 +4024,53 @@ pub impl Parser {
 
     // parse one of the items or view items allowed by the
     // flags; on failure, return iovi_none.
+    // NB: this function no longer parses the items inside an
+    // extern mod.
     fn parse_item_or_view_item(
         &self,
         attrs: ~[attribute],
-        items_allowed: bool,
-        foreign_items_allowed: bool,
         macros_allowed: bool
     ) -> item_or_view_item {
-        assert!(items_allowed != foreign_items_allowed);
-
         maybe_whole!(iovi self, nt_item);
         let lo = self.span.lo;
 
-        let visibility;
-        if self.eat_keyword(&~"pub") {
-            visibility = public;
-        } else if self.eat_keyword(&~"priv") {
-            visibility = private;
-        } else {
-            visibility = inherited;
+        let visibility = self.parse_visibility();
+
+        // must be a view item:
+        if self.eat_keyword(&~"use") {
+            // USE ITEM (iovi_view_item)
+            let view_item = self.parse_use();
+            self.expect(&token::SEMI);
+            return iovi_view_item(@ast::view_item {
+                node: view_item,
+                attrs: attrs,
+                vis: visibility,
+                span: mk_sp(lo, self.last_span.hi)
+            });
         }
+        // either a view item or an item:
+        if self.eat_keyword(&~"extern") {
+            let opt_abis = self.parse_opt_abis();
 
-        if items_allowed &&
-                (self.is_keyword(&~"const") ||
-                (self.is_keyword(&~"static") &&
-                    !self.token_is_keyword(&~"fn", &self.look_ahead(1)))) {
+            if self.eat_keyword(&~"fn") {
+                // EXTERN FUNCTION ITEM
+                let abis = opt_abis.get_or_default(AbiSet::C());
+                let (ident, item_, extra_attrs) =
+                    self.parse_item_fn(extern_fn, abis);
+                return iovi_item(self.mk_item(lo, self.last_span.hi, ident,
+                                              item_, visibility,
+                                              maybe_append(attrs,
+                                                           extra_attrs)));
+            } else  {
+                // EXTERN MODULE ITEM (iovi_view_item)
+                return self.parse_item_foreign_mod(lo, opt_abis, visibility, attrs,
+                                                   true);
+            }
+        }
+        // the rest are all guaranteed to be items:
+        if (self.is_keyword(&~"const") ||
+            (self.is_keyword(&~"static") &&
+             !self.token_is_keyword(&~"fn", &self.look_ahead(1)))) {
             // CONST / STATIC ITEM
             if self.is_keyword(&~"const") {
                 self.obsolete(*self.span, ObsoleteConstItem);
@@ -4018,13 +4081,7 @@ pub impl Parser {
                                           visibility,
                                           maybe_append(attrs, extra_attrs)));
         }
-        if foreign_items_allowed &&
-                (self.is_keyword(&~"const") || self.is_keyword(&~"static")) {
-            // FOREIGN CONST ITEM
-            let item = self.parse_item_foreign_const(visibility, attrs);
-            return iovi_foreign_item(item);
-        }
-        if items_allowed && self.is_keyword(&~"fn") &&
+        if self.is_keyword(&~"fn") &&
             !self.fn_expr_lookahead(self.look_ahead(1u)) {
             // FUNCTION ITEM
             self.bump();
@@ -4034,7 +4091,7 @@ pub impl Parser {
                                           visibility,
                                           maybe_append(attrs, extra_attrs)));
         }
-        if items_allowed && self.eat_keyword(&~"pure") {
+        if self.eat_keyword(&~"pure") {
             // PURE FUNCTION ITEM (obsolete)
             self.obsolete(*self.last_span, ObsoletePurity);
             self.expect_keyword(&~"fn");
@@ -4044,16 +4101,9 @@ pub impl Parser {
                                           visibility,
                                           maybe_append(attrs, extra_attrs)));
         }
-        if foreign_items_allowed &&
-            (self.is_keyword(&~"fn") || self.is_keyword(&~"pure") ||
-             self.is_keyword(&~"unsafe")) {
-            // FOREIGN FUNCTION ITEM (no items allowed)
-                let item = self.parse_item_foreign_fn(attrs);
-                return iovi_foreign_item(item);
-        }
-        if items_allowed && self.is_keyword(&~"unsafe")
+        if self.is_keyword(&~"unsafe")
             && self.look_ahead(1u) != token::LBRACE {
-            // UNSAFE FUNCTION ITEM (where items are allowed)
+            // UNSAFE FUNCTION ITEM
             self.bump();
             self.expect_keyword(&~"fn");
             let (ident, item_, extra_attrs) =
@@ -4062,59 +4112,35 @@ pub impl Parser {
                                           visibility,
                                           maybe_append(attrs, extra_attrs)));
         }
-        if self.eat_keyword(&~"extern") {
-            let opt_abis = self.parse_opt_abis();
-
-            if items_allowed && self.eat_keyword(&~"fn") {
-                // EXTERN FUNCTION ITEM
-                let abis = opt_abis.get_or_default(AbiSet::C());
-                let (ident, item_, extra_attrs) =
-                    self.parse_item_fn(extern_fn, abis);
-                return iovi_item(self.mk_item(lo, self.last_span.hi, ident,
-                                              item_, visibility,
-                                              maybe_append(attrs,
-                                                           extra_attrs)));
-            }
-            if !foreign_items_allowed {
-                // EXTERN MODULE ITEM
-                return self.parse_item_foreign_mod(lo, opt_abis, visibility, attrs,
-                                                   items_allowed);
-            }
-        }
-        if items_allowed && !foreign_items_allowed &&
-                self.eat_keyword(&~"mod") {
+        if self.eat_keyword(&~"mod") {
             // MODULE ITEM
             let (ident, item_, extra_attrs) = self.parse_item_mod(attrs);
             return iovi_item(self.mk_item(lo, self.last_span.hi, ident, item_,
                                           visibility,
                                           maybe_append(attrs, extra_attrs)));
         }
-        if items_allowed && !foreign_items_allowed &&
-                self.eat_keyword(&~"type") {
+        if self.eat_keyword(&~"type") {
             // TYPE ITEM
             let (ident, item_, extra_attrs) = self.parse_item_type();
             return iovi_item(self.mk_item(lo, self.last_span.hi, ident, item_,
                                           visibility,
                                           maybe_append(attrs, extra_attrs)));
         }
-        if items_allowed && !foreign_items_allowed &&
-                self.eat_keyword(&~"enum") {
+        if self.eat_keyword(&~"enum") {
             // ENUM ITEM
             let (ident, item_, extra_attrs) = self.parse_item_enum();
             return iovi_item(self.mk_item(lo, self.last_span.hi, ident, item_,
                                           visibility,
                                           maybe_append(attrs, extra_attrs)));
         }
-        if items_allowed && !foreign_items_allowed &&
-                self.eat_keyword(&~"trait") {
+        if self.eat_keyword(&~"trait") {
             // TRAIT ITEM
             let (ident, item_, extra_attrs) = self.parse_item_trait();
             return iovi_item(self.mk_item(lo, self.last_span.hi, ident, item_,
                                           visibility,
                                           maybe_append(attrs, extra_attrs)));
         }
-        if items_allowed && !foreign_items_allowed &&
-                self.eat_keyword(&~"impl") {
+        if self.eat_keyword(&~"impl") {
             // IMPL ITEM
             let (ident, item_, extra_attrs) =
                 self.parse_item_impl(visibility);
@@ -4122,25 +4148,49 @@ pub impl Parser {
                                           visibility,
                                           maybe_append(attrs, extra_attrs)));
         }
-        if items_allowed && !foreign_items_allowed &&
-                self.eat_keyword(&~"struct") {
+        if self.eat_keyword(&~"struct") {
             // STRUCT ITEM
             let (ident, item_, extra_attrs) = self.parse_item_struct();
             return iovi_item(self.mk_item(lo, self.last_span.hi, ident, item_,
                                           visibility,
                                           maybe_append(attrs, extra_attrs)));
         }
-        if !foreign_items_allowed && self.eat_keyword(&~"use") {
-            // USE ITEM
-            let view_item = self.parse_use();
-            self.expect(&token::SEMI);
-            return iovi_view_item(@ast::view_item {
-                node: view_item,
-                attrs: attrs,
-                vis: visibility,
-                span: mk_sp(lo, self.last_span.hi)
-            });
+        self.parse_macro_use_or_failure(attrs,macros_allowed,lo,visibility)
+    }
+
+    // parse a foreign item; on failure, return iovi_none.
+    fn parse_foreign_item(
+        &self,
+        attrs: ~[attribute],
+        macros_allowed: bool
+    ) -> item_or_view_item {
+        maybe_whole!(iovi self, nt_item);
+        let lo = self.span.lo;
+
+        let visibility = self.parse_visibility();
+
+        if (self.is_keyword(&~"const") || self.is_keyword(&~"static")) {
+            // FOREIGN CONST ITEM
+            let item = self.parse_item_foreign_const(visibility, attrs);
+            return iovi_foreign_item(item);
         }
+        if (self.is_keyword(&~"fn") || self.is_keyword(&~"pure") ||
+             self.is_keyword(&~"unsafe")) {
+            // FOREIGN FUNCTION ITEM
+                let item = self.parse_item_foreign_fn(attrs);
+                return iovi_foreign_item(item);
+        }
+        self.parse_macro_use_or_failure(attrs,macros_allowed,lo,visibility)
+    }
+
+    // this is the fall-through for parsing items.
+    fn parse_macro_use_or_failure(
+        &self,
+        attrs: ~[attribute],
+        macros_allowed: bool,
+        lo : BytePos,
+        visibility : visibility
+    ) -> item_or_view_item {
         if macros_allowed && !self.is_any_keyword(&copy *self.token)
                 && self.look_ahead(1) == token::NOT
                 && (is_plain_ident(&self.look_ahead(2))
@@ -4197,7 +4247,7 @@ pub impl Parser {
     }
 
     fn parse_item(&self, attrs: ~[attribute]) -> Option<@ast::item> {
-        match self.parse_item_or_view_item(attrs, true, false, true) {
+        match self.parse_item_or_view_item(attrs, true) {
             iovi_none =>
                 None,
             iovi_view_item(_) =>
@@ -4209,6 +4259,7 @@ pub impl Parser {
         }
     }
 
+    // parse, e.g., "use a::b::{z,y}"
     fn parse_use(&self) -> view_item_ {
         return view_item_use(self.parse_view_paths());
     }
@@ -4353,101 +4404,73 @@ pub impl Parser {
 
     // Parses a sequence of items. Stops when it finds program
     // text that can't be parsed as an item
-    // - mod_items uses VIEW_ITEMS_AND_ITEMS_ALLOWED
-    // - block_tail_ uses IMPORTS_AND_ITEMS_ALLOWED
-    // - foreign_mod_items uses FOREIGN_ITEMS_ALLOWED
+    // - mod_items uses extern_mod_allowed = true
+    // - block_tail_ uses extern_mod_allowed = false
     fn parse_items_and_view_items(&self, first_item_attrs: ~[attribute],
-                                  mode: view_item_parse_mode,
+                                  mut extern_mod_allowed: bool,
                                   macros_allowed: bool)
                                 -> ParsedItemsAndViewItems {
         let mut attrs = vec::append(first_item_attrs,
                                     self.parse_outer_attributes());
-
-        let items_allowed = match mode {
-            VIEW_ITEMS_AND_ITEMS_ALLOWED | IMPORTS_AND_ITEMS_ALLOWED => true,
-            FOREIGN_ITEMS_ALLOWED => false
-        };
-        let foreign_items_allowed = match mode {
-            FOREIGN_ITEMS_ALLOWED => true,
-            VIEW_ITEMS_AND_ITEMS_ALLOWED | IMPORTS_AND_ITEMS_ALLOWED => false
-        };
-
         // First, parse view items.
-        let mut (view_items, items, foreign_items) = (~[], ~[], ~[]);
+        let mut (view_items, items) = (~[], ~[]);
         let mut done = false;
-        if mode != FOREIGN_ITEMS_ALLOWED {
-            let mut extern_mod_allowed = match mode {
-                VIEW_ITEMS_AND_ITEMS_ALLOWED => true,
-                IMPORTS_AND_ITEMS_ALLOWED => false,
-                FOREIGN_ITEMS_ALLOWED => {
-                    self.bug(~"couldn't get here with FOREIGN_ITEMS_ALLOWED")
+        // I think this code would probably read better as a single
+        // loop with a mutable three-state-variable (for extern mods,
+        // view items, and regular items) ... except that because
+        // of macros, I'd like to delay that entire check until later.
+        loop {
+            match self.parse_item_or_view_item(/*bad*/ copy attrs,
+                                                           macros_allowed) {
+                iovi_none => {
+                    done = true;
+                    break;
                 }
-            };
-
-            loop {
-                match self.parse_item_or_view_item(/*bad*/ copy attrs,
-                                                   items_allowed,
-                                                   foreign_items_allowed,
-                                                   macros_allowed) {
-                    iovi_none => {
-                        done = true;
-                        break;
-                    }
-                    iovi_view_item(view_item) => {
-                        match view_item.node {
-                            view_item_use(*) => {
-                                // `extern mod` must precede `use`.
-                                extern_mod_allowed = false;
-                            }
-                            view_item_extern_mod(*)
-                                    if !extern_mod_allowed => {
-                                self.span_err(view_item.span,
-                                              ~"\"extern mod\" \
-                                                declarations are not \
-                                                allowed here");
-                            }
-                            view_item_extern_mod(*) => {}
+                iovi_view_item(view_item) => {
+                    match view_item.node {
+                        view_item_use(*) => {
+                            // `extern mod` must precede `use`.
+                            extern_mod_allowed = false;
                         }
-                        view_items.push(view_item);
-                    }
-                    iovi_item(item) => {
-                        assert!(items_allowed);
-                        items.push(item);
-                        attrs = self.parse_outer_attributes();
-                        break;
-                    }
-                    iovi_foreign_item(foreign_item) => {
-                        assert!(foreign_items_allowed);
-                        foreign_items.push(foreign_item);
-                        attrs = self.parse_outer_attributes();
-                        break;
+                        view_item_extern_mod(*)
+                        if !extern_mod_allowed => {
+                            self.span_err(view_item.span,
+                                          ~"\"extern mod\" \
+                                            declarations are not \
+                                            allowed here");
+                        }
+                        view_item_extern_mod(*) => {}
                     }
+                    view_items.push(view_item);
+                }
+                iovi_item(item) => {
+                    items.push(item);
+                    attrs = self.parse_outer_attributes();
+                    break;
+                }
+                iovi_foreign_item(_) => {
+                    fail!();
                 }
-                attrs = self.parse_outer_attributes();
             }
+            attrs = self.parse_outer_attributes();
         }
 
         // Next, parse items.
         if !done {
             loop {
                 match self.parse_item_or_view_item(/*bad*/ copy attrs,
-                                                   items_allowed,
-                                                   foreign_items_allowed,
                                                    macros_allowed) {
                     iovi_none => break,
                     iovi_view_item(view_item) => {
                         self.span_err(view_item.span,
                                       ~"`use` and `extern mod` declarations \
                                         must precede items");
-                        view_items.push(view_item);
                     }
                     iovi_item(item) => {
-                        assert!(items_allowed);
                         items.push(item)
                     }
-                    iovi_foreign_item(foreign_item) => {
-                        assert!(foreign_items_allowed);
-                        foreign_items.push(foreign_item);
+                    iovi_foreign_item(_) => {
+                        fail!();
                     }
                 }
                 attrs = self.parse_outer_attributes();
@@ -4458,12 +4481,49 @@ pub impl Parser {
             attrs_remaining: attrs,
             view_items: view_items,
             items: items,
+            foreign_items: ~[]
+        }
+    }
+
+    // Parses a sequence of foreign items. Stops when it finds program
+    // text that can't be parsed as an item
+    fn parse_foreign_items(&self, first_item_attrs: ~[attribute],
+                           macros_allowed: bool)
+        -> ParsedItemsAndViewItems {
+        let mut attrs = vec::append(first_item_attrs,
+                                    self.parse_outer_attributes());
+        let mut foreign_items = ~[];
+        loop {
+            match self.parse_foreign_item(/*bad*/ copy attrs, macros_allowed) {
+                iovi_none => break,
+                iovi_view_item(view_item) => {
+                    // I think this can't occur:
+                    self.span_err(view_item.span,
+                                  ~"`use` and `extern mod` declarations \
+                                    must precede items");
+                }
+                iovi_item(_) => {
+                    // FIXME #5668: this will occur for a macro invocation:
+                    fail!();
+                }
+                iovi_foreign_item(foreign_item) => {
+                    foreign_items.push(foreign_item);
+                }
+            }
+            attrs = self.parse_outer_attributes();
+        }
+
+        ParsedItemsAndViewItems {
+            attrs_remaining: attrs,
+            view_items: ~[],
+            items: ~[],
             foreign_items: foreign_items
         }
     }
 
-    // Parses a source module as a crate
-    fn parse_crate_mod(&self, _cfg: crate_cfg) -> @crate {
+    // Parses a source module as a crate. This is the main
+    // entry point for the parser.
+    fn parse_crate_mod(&self) -> @crate {
         let lo = self.span.lo;
         // parse the crate's inner attrs, maybe (oops) one
         // of the attrs of an item:
diff --git a/src/libsyntax/parse/prec.rs b/src/libsyntax/parse/prec.rs
deleted file mode 100644
index 5f37c922c1e..00000000000
--- a/src/libsyntax/parse/prec.rs
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use ast;
-use ast::*;
-use parse::token::*;
-use parse::token::Token;
-
-/// Unary operators have higher precedence than binary
-pub static unop_prec: uint = 100u;
-
-/**
- * Precedence of the `as` operator, which is a binary operator
- * but is not represented in the precedence table.
- */
-pub static as_prec: uint = 11u;
-
-/**
- * Maps a token to a record specifying the corresponding binary
- * operator and its precedence
- */
-pub fn token_to_binop(tok: Token) -> Option<ast::binop> {
-  match tok {
-      BINOP(STAR)    => Some(mul),
-      BINOP(SLASH)   => Some(quot),
-      BINOP(PERCENT) => Some(rem),
-      // 'as' sits between here with 11
-      BINOP(PLUS)    => Some(add),
-      BINOP(MINUS)   => Some(subtract),
-      BINOP(SHL)     => Some(shl),
-      BINOP(SHR)     => Some(shr),
-      BINOP(AND)     => Some(bitand),
-      BINOP(CARET)   => Some(bitxor),
-      BINOP(OR)      => Some(bitor),
-      LT             => Some(lt),
-      LE             => Some(le),
-      GE             => Some(ge),
-      GT             => Some(gt),
-      EQEQ           => Some(eq),
-      NE             => Some(ne),
-      ANDAND         => Some(and),
-      OROR           => Some(or),
-      _              => None
-  }
-}
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index 413f1688df1..0327a3b80da 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -364,6 +364,34 @@ impl<'self> to_bytes::IterBytes for StringRef<'self> {
     }
 }
 
+/**
+ * Maps a token to a record specifying the corresponding binary
+ * operator
+ */
+pub fn token_to_binop(tok: Token) -> Option<ast::binop> {
+  match tok {
+      BINOP(STAR)    => Some(ast::mul),
+      BINOP(SLASH)   => Some(ast::quot),
+      BINOP(PERCENT) => Some(ast::rem),
+      BINOP(PLUS)    => Some(ast::add),
+      BINOP(MINUS)   => Some(ast::subtract),
+      BINOP(SHL)     => Some(ast::shl),
+      BINOP(SHR)     => Some(ast::shr),
+      BINOP(AND)     => Some(ast::bitand),
+      BINOP(CARET)   => Some(ast::bitxor),
+      BINOP(OR)      => Some(ast::bitor),
+      LT             => Some(ast::lt),
+      LE             => Some(ast::le),
+      GE             => Some(ast::ge),
+      GT             => Some(ast::gt),
+      EQEQ           => Some(ast::eq),
+      NE             => Some(ast::ne),
+      ANDAND         => Some(ast::and),
+      OROR           => Some(ast::or),
+      _              => None
+  }
+}
+
 pub struct ident_interner {
     priv interner: Interner<@~str>,
 }
@@ -390,60 +418,68 @@ pub impl ident_interner {
     }
 }
 
+// return a fresh interner, preloaded with special identifiers.
+// EFFECT: stores this interner in TLS
+pub fn mk_fresh_ident_interner() -> @ident_interner {
+    // the indices here must correspond to the numbers in
+    // special_idents.
+    let init_vec = ~[
+        @~"_",                  // 0
+        @~"anon",               // 1
+        @~"drop",               // 2
+        @~"",                   // 3
+        @~"unary",              // 4
+        @~"!",                  // 5
+        @~"[]",                 // 6
+        @~"unary-",             // 7
+        @~"__extensions__",     // 8
+        @~"self",               // 9
+        @~"item",               // 10
+        @~"block",              // 11
+        @~"stmt",               // 12
+        @~"pat",                // 13
+        @~"expr",               // 14
+        @~"ty",                 // 15
+        @~"ident",              // 16
+        @~"path",               // 17
+        @~"tt",                 // 18
+        @~"matchers",           // 19
+        @~"str",                // 20
+        @~"TyVisitor",          // 21
+        @~"arg",                // 22
+        @~"descrim",            // 23
+        @~"__rust_abi",         // 24
+        @~"__rust_stack_shim",  // 25
+        @~"TyDesc",             // 26
+        @~"dtor",               // 27
+        @~"main",               // 28
+        @~"<opaque>",           // 29
+        @~"blk",                // 30
+        @~"static",             // 31
+        @~"intrinsic",          // 32
+        @~"__foreign_mod__",    // 33
+        @~"__field__",          // 34
+        @~"C",                  // 35
+        @~"Self",               // 36
+    ];
+
+    let rv = @ident_interner {
+        interner: interner::Interner::prefill(init_vec)
+    };
+    unsafe {
+        task::local_data::local_data_set(interner_key!(), @rv);
+    }
+    rv
+}
+
+// if an interner exists in TLS, return it. Otherwise, prepare a
+// fresh one.
 pub fn mk_ident_interner() -> @ident_interner {
     unsafe {
         match task::local_data::local_data_get(interner_key!()) {
             Some(interner) => *interner,
             None => {
-                // the indices here must correspond to the numbers in
-                // special_idents.
-                let init_vec = ~[
-                    @~"_",                  // 0
-                    @~"anon",               // 1
-                    @~"drop",               // 2
-                    @~"",                   // 3
-                    @~"unary",              // 4
-                    @~"!",                  // 5
-                    @~"[]",                 // 6
-                    @~"unary-",             // 7
-                    @~"__extensions__",     // 8
-                    @~"self",               // 9
-                    @~"item",               // 10
-                    @~"block",              // 11
-                    @~"stmt",               // 12
-                    @~"pat",                // 13
-                    @~"expr",               // 14
-                    @~"ty",                 // 15
-                    @~"ident",              // 16
-                    @~"path",               // 17
-                    @~"tt",                 // 18
-                    @~"matchers",           // 19
-                    @~"str",                // 20
-                    @~"TyVisitor",          // 21
-                    @~"arg",                // 22
-                    @~"descrim",            // 23
-                    @~"__rust_abi",         // 24
-                    @~"__rust_stack_shim",  // 25
-                    @~"TyDesc",             // 26
-                    @~"dtor",               // 27
-                    @~"main",               // 28
-                    @~"<opaque>",           // 29
-                    @~"blk",                // 30
-                    @~"static",             // 31
-                    @~"intrinsic",          // 32
-                    @~"__foreign_mod__",    // 33
-                    @~"__field__",          // 34
-                    @~"C",                  // 35
-                    @~"Self",               // 36
-                ];
-
-                let rv = @ident_interner {
-                    interner: interner::Interner::prefill(init_vec)
-                };
-
-                task::local_data::local_data_set(interner_key!(), @rv);
-
-                rv
+                mk_fresh_ident_interner()
             }
         }
     }
diff --git a/src/libsyntax/syntax.rc b/src/libsyntax/syntax.rc
index 2682139ce3f..a401d9eb8ac 100644
--- a/src/libsyntax/syntax.rc
+++ b/src/libsyntax/syntax.rc
@@ -8,6 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+/*! This module contains the Rust parser. It maps source text
+ *  to token trees and to ASTs. It contains code for expanding
+ *  macros.
+ */
+
 #[link(name = "syntax",
        vers = "0.7-pre",
        uuid = "9311401b-d6ea-4cd9-a1d9-61f89499c645")];
diff --git a/src/test/compile-fail/enums-pats-not-idents.rs b/src/test/compile-fail/enums-pats-not-idents.rs
new file mode 100644
index 00000000000..9eb98341112
--- /dev/null
+++ b/src/test/compile-fail/enums-pats-not-idents.rs
@@ -0,0 +1,16 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//error-pattern:unresolved enum variant
+
+fn main() {
+    // a bug in the parser is allowing this:
+    let a() = 13;
+}