about summary refs log tree commit diff
path: root/src/libsyntax/parse
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-04-29 00:12:37 -0700
committerbors <bors@rust-lang.org>2013-04-29 00:12:37 -0700
commitea74f6845e08150e3b38766f57a4af928aea1376 (patch)
tree7f595ee292241ed3520742a968e3f5077c687fd5 /src/libsyntax/parse
parent7b7a0fc235cd2e0782302cd6fb83634e190b15b7 (diff)
parentcce13c18fe2f5c6dcd46f91a264cd99aa77f9135 (diff)
auto merge of #6083 : jbclements/rust/parser-cleanup, r=jbclements
r? @pcwalton

A month's worth of parser cleanup here. Much of this is new comments and renaming. A number of these commits also remove unneeded code.  Probably the biggest refactor here is splitting "parse_item_or_view_item" into two functions; it turns out that the only overlap between items in foreign modules and items in regular modules was macros, so this refactor should make things substantially easier for future maintenance.
Diffstat (limited to 'src/libsyntax/parse')
-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
9 files changed, 859 insertions, 535 deletions
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()
             }
         }
     }