about summary refs log tree commit diff
path: root/src/libsyntax/parse/parser.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/libsyntax/parse/parser.rs')
-rw-r--r--src/libsyntax/parse/parser.rs676
1 files changed, 368 insertions, 308 deletions
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: