@@ -281,6 +281,7 @@ pub fn Parser(sess: @mut ParseSess,
281281 token : @mut tok0. tok ,
282282 span : @mut span,
283283 last_span : @mut span,
284+ last_token : @mut None ,
284285 buffer : @mut ( [
285286 placeholder. clone ( ) ,
286287 placeholder. clone ( ) ,
@@ -307,6 +308,8 @@ pub struct Parser {
307308 span : @mut span ,
308309 // the span of the prior token:
309310 last_span : @mut span ,
311+ // the previous token or None (only stashed sometimes).
312+ last_token : @mut Option < ~token:: Token > ,
310313 buffer : @mut [ TokenAndSpan , ..4 ] ,
311314 buffer_start : @mut int ,
312315 buffer_end : @mut int ,
@@ -374,6 +377,89 @@ impl Parser {
374377 }
375378 }
376379
380+ // Expect next token to be edible or inedible token. If edible,
381+ // then consume it; if inedible, then return without consuming
382+ // anything. Signal a fatal error if next token is unexpected.
383+ pub fn expect_one_of ( & self , edible : & [ token:: Token ] , inedible : & [ token:: Token ] ) {
384+ fn tokens_to_str ( p : & Parser , tokens : & [ token:: Token ] ) -> ~str {
385+ let mut i = tokens. iter ( ) ;
386+ // This might be a sign we need a connect method on Iterator.
387+ let b = i. next ( ) . map_default ( ~"", |t| p. token_to_str ( * t) ) ;
388+ i. fold ( b, |b, a| b + " " + p. token_to_str ( a) )
389+ }
390+ if edible. contains ( self . token ) {
391+ self . bump ( ) ;
392+ } else if inedible. contains ( self . token ) {
393+ // leave it in the input
394+ } else {
395+ let expected = vec:: append ( edible. to_owned ( ) , inedible) ;
396+ let expect = tokens_to_str ( self , expected) ;
397+ let actual = self . this_token_to_str ( ) ;
398+ self . fatal (
399+ if expected. len ( ) != 1 {
400+ fmt ! ( "expected one of `%s` but found `%s`" , expect, actual)
401+ } else {
402+ fmt ! ( "expected `%s` but found `%s`" , expect, actual)
403+ }
404+ )
405+ }
406+ }
407+
408+ // Check for erroneous `ident { }`; if matches, signal error and
409+ // recover (without consuming any expected input token). Returns
410+ // true if and only if input was consumed for recovery.
411+ pub fn check_for_erroneous_unit_struct_expecting ( & self , expected : & [ token:: Token ] ) -> bool {
412+ if * self . token == token:: LBRACE
413+ && expected. iter ( ) . all ( |t| * t != token:: LBRACE )
414+ && self . look_ahead ( 1 , |t| * t == token:: RBRACE ) {
415+ // matched; signal non-fatal error and recover.
416+ self . span_err ( * self . span ,
417+ "Unit-like struct construction is written with no trailing `{ }`" ) ;
418+ self . eat ( & token:: LBRACE ) ;
419+ self . eat ( & token:: RBRACE ) ;
420+ true
421+ } else {
422+ false
423+ }
424+ }
425+
426+ // Commit to parsing a complete expression `e` expected to be
427+ // followed by some token from the set edible + inedible. Recover
428+ // from anticipated input errors, discarding erroneous characters.
429+ pub fn commit_expr ( & self , e: @expr, edible : & [ token:: Token ] , inedible : & [ token:: Token ] ) {
430+ debug ! ( "commit_expr %?" , e) ;
431+ match e. node {
432+ expr_path( * ) => {
433+ // might be unit-struct construction; check for recoverableinput error.
434+ let expected = vec:: append ( edible. to_owned ( ) , inedible) ;
435+ self . check_for_erroneous_unit_struct_expecting ( expected) ;
436+ }
437+ _ => { }
438+ }
439+ self . expect_one_of ( edible, inedible)
440+ }
441+
442+ pub fn commit_expr_expecting ( & self , e: @expr, edible : token:: Token ) {
443+ self . commit_expr ( e, & [ edible] , & [ ] )
444+ }
445+
446+ // Commit to parsing a complete statement `s`, which expects to be
447+ // followed by some token from the set edible + inedible. Check
448+ // for recoverable input errors, discarding erroneous characters.
449+ pub fn commit_stmt ( & self , s: @stmt, edible : & [ token:: Token ] , inedible : & [ token:: Token ] ) {
450+ debug ! ( "commit_stmt %?" , s) ;
451+ let _s = s; // unused, but future checks might want to inspect `s`.
452+ if self . last_token . map_default ( false , |t|is_ident_or_path ( * t) ) {
453+ let expected = vec:: append ( edible. to_owned ( ) , inedible) ;
454+ self . check_for_erroneous_unit_struct_expecting ( expected) ;
455+ }
456+ self . expect_one_of ( edible, inedible)
457+ }
458+
459+ pub fn commit_stmt_expecting ( & self , s: @stmt, edible : token:: Token ) {
460+ self . commit_stmt ( s, & [ edible] , & [ ] )
461+ }
462+
377463 pub fn parse_ident ( & self ) -> ast:: ident {
378464 self . check_strict_keywords ( ) ;
379465 self . check_reserved_keywords ( ) ;
@@ -576,6 +662,12 @@ impl Parser {
576662 // advance the parser by one token
577663 pub fn bump ( & self ) {
578664 * self . last_span = * self . span ;
665+ // Stash token for error recovery (sometimes; clone is not necessarily cheap).
666+ * self . last_token = if is_ident_or_path ( self . token ) {
667+ Some ( ~( * self . token ) . clone ( ) )
668+ } else {
669+ None
670+ } ;
579671 let next = if * self . buffer_start == * self . buffer_end {
580672 self . reader . next_token ( )
581673 } else {
@@ -1593,17 +1685,19 @@ impl Parser {
15931685 return self . mk_expr( lo, hi, expr_lit( lit) ) ;
15941686 }
15951687 let mut es = ~[ self . parse_expr( ) ] ;
1688+ self . commit_expr( * es. last( ) , & [ ] , & [ token:: COMMA , token:: RPAREN ] ) ;
15961689 while * self . token == token:: COMMA {
15971690 self . bump( ) ;
15981691 if * self . token != token:: RPAREN {
15991692 es. push( self . parse_expr( ) ) ;
1693+ self . commit_expr( * es. last( ) , & [ ] , & [ token:: COMMA , token:: RPAREN ] ) ;
16001694 }
16011695 else {
16021696 trailing_comma = true ;
16031697 }
16041698 }
16051699 hi = self . span . hi ;
1606- self . expect ( & token:: RPAREN ) ;
1700+ self . commit_expr_expecting ( * es . last ( ) , token:: RPAREN ) ;
16071701
16081702 return if es. len ( ) == 1 && !trailing_comma {
16091703 self . mk_expr ( lo, self . span . hi , expr_paren ( es[ 0 ] ) )
@@ -1743,7 +1837,7 @@ impl Parser {
17431837 break ;
17441838 }
17451839
1746- self . expect ( & token:: COMMA ) ;
1840+ self . commit_expr ( fields . last ( ) . expr , & [ token:: COMMA ] , & [ token :: RBRACE ] ) ;
17471841
17481842 if self . eat ( & token:: DOTDOT ) {
17491843 base = Some ( self . parse_expr ( ) ) ;
@@ -1758,7 +1852,7 @@ impl Parser {
17581852 }
17591853
17601854 hi = pth. span . hi ;
1761- self . expect ( & token:: RBRACE ) ;
1855+ self . commit_expr_expecting ( fields . last ( ) . expr , token:: RBRACE ) ;
17621856 ex = expr_struct ( pth, fields, base) ;
17631857 return self . mk_expr ( lo, hi, ex) ;
17641858 }
@@ -1852,7 +1946,7 @@ impl Parser {
18521946 self . bump ( ) ;
18531947 let ix = self . parse_expr ( ) ;
18541948 hi = ix. span . hi ;
1855- self . expect ( & token:: RBRACKET ) ;
1949+ self . commit_expr_expecting ( ix , token:: RBRACKET ) ;
18561950 e = self . mk_expr ( lo, hi, self . mk_index ( e, ix) ) ;
18571951 }
18581952
@@ -2461,7 +2555,7 @@ impl Parser {
24612555 fn parse_match_expr ( & self ) -> @expr {
24622556 let lo = self . last_span . lo ;
24632557 let discriminant = self . parse_expr ( ) ;
2464- self . expect ( & token:: LBRACE ) ;
2558+ self . commit_expr_expecting ( discriminant , token:: LBRACE ) ;
24652559 let mut arms: ~[ arm ] = ~[ ] ;
24662560 while * self . token != token:: RBRACE {
24672561 let pats = self . parse_pats ( ) ;
@@ -2477,7 +2571,7 @@ impl Parser {
24772571 && * self . token != token:: RBRACE ;
24782572
24792573 if require_comma {
2480- self . expect ( & token:: COMMA ) ;
2574+ self . commit_expr ( expr , & [ token:: COMMA ] , & [ token :: RBRACE ] ) ;
24812575 } else {
24822576 self . eat ( & token:: COMMA ) ;
24832577 }
@@ -3177,37 +3271,26 @@ impl Parser {
31773271 match stmt. node {
31783272 stmt_expr( e, stmt_id) => {
31793273 // expression without semicolon
3180- let has_semi;
3274+ if classify:: stmt_ends_with_semi ( stmt) {
3275+ // Just check for errors and recover; do not eat semicolon yet.
3276+ self . commit_stmt ( stmt, & [ ] , & [ token:: SEMI , token:: RBRACE ] ) ;
3277+ }
3278+
31813279 match * self . token {
31823280 token:: SEMI => {
3183- has_semi = true ;
3281+ self . bump ( ) ;
3282+ stmts. push ( @codemap:: spanned {
3283+ node : stmt_semi ( e, stmt_id) ,
3284+ span : stmt. span ,
3285+ } ) ;
31843286 }
31853287 token:: RBRACE => {
3186- has_semi = false ;
31873288 expr = Some ( e) ;
31883289 }
3189- ref t => {
3190- has_semi = false ;
3191- if classify:: stmt_ends_with_semi ( stmt) {
3192- self . fatal (
3193- fmt ! (
3194- "expected `;` or `}` after \
3195- expression but found `%s`",
3196- self . token_to_str( t)
3197- )
3198- ) ;
3199- }
3290+ _ => {
32003291 stmts. push ( stmt) ;
32013292 }
32023293 }
3203-
3204- if has_semi {
3205- self . bump ( ) ;
3206- stmts. push ( @codemap:: spanned {
3207- node : stmt_semi ( e, stmt_id) ,
3208- span : stmt. span ,
3209- } ) ;
3210- }
32113294 }
32123295 stmt_mac( ref m, _) => {
32133296 // statement macro; might be an expr
@@ -3243,7 +3326,7 @@ impl Parser {
32433326 stmts. push ( stmt) ;
32443327
32453328 if classify:: stmt_ends_with_semi ( stmt) {
3246- self . expect ( & token:: SEMI ) ;
3329+ self . commit_stmt_expecting ( stmt , token:: SEMI ) ;
32473330 }
32483331 }
32493332 }
@@ -3758,7 +3841,7 @@ impl Parser {
37583841 }
37593842 }
37603843 if fields. len ( ) == 0 {
3761- self . fatal ( fmt ! ( "Unit-like struct should be written as `struct %s;`" ,
3844+ self . fatal ( fmt ! ( "Unit-like struct definition should be written as `struct %s;`" ,
37623845 get_ident_interner( ) . get( class_name. name) ) ) ;
37633846 }
37643847 self . bump ( ) ;
@@ -3938,7 +4021,7 @@ impl Parser {
39384021 let ty = self . parse_ty ( false ) ;
39394022 self . expect ( & token:: EQ ) ;
39404023 let e = self . parse_expr ( ) ;
3941- self . expect ( & token:: SEMI ) ;
4024+ self . commit_expr_expecting ( e , token:: SEMI ) ;
39424025 ( id, item_static ( ty, m, e) , None )
39434026 }
39444027
0 commit comments