@@ -283,6 +283,7 @@ pub fn Parser(sess: @mut ParseSess,
283283 token : @mut tok0. tok ,
284284 span : @mut span,
285285 last_span : @mut span,
286+ last_token : @mut None ,
286287 buffer : @mut ( [
287288 placeholder. clone ( ) ,
288289 placeholder. clone ( ) ,
@@ -309,6 +310,8 @@ pub struct Parser {
309310 span : @mut span ,
310311 // the span of the prior token:
311312 last_span : @mut span ,
313+ // the previous token or None (only stashed sometimes).
314+ last_token : @mut Option < ~token:: Token > ,
312315 buffer : @mut [ TokenAndSpan , ..4 ] ,
313316 buffer_start : @mut int ,
314317 buffer_end : @mut int ,
@@ -376,6 +379,89 @@ impl Parser {
376379 }
377380 }
378381
382+ // Expect next token to be edible or inedible token. If edible,
383+ // then consume it; if inedible, then return without consuming
384+ // anything. Signal a fatal error if next token is unexpected.
385+ pub fn expect_one_of ( & self , edible : & [ token:: Token ] , inedible : & [ token:: Token ] ) {
386+ fn tokens_to_str ( p : & Parser , tokens : & [ token:: Token ] ) -> ~str {
387+ let mut i = tokens. iter ( ) ;
388+ // This might be a sign we need a connect method on Iterator.
389+ let b = i. next ( ) . map_default ( ~"", |t| p. token_to_str ( * t) ) ;
390+ i. fold ( b, |b, a| b + " " + p. token_to_str ( a) )
391+ }
392+ if edible. contains ( self . token ) {
393+ self . bump ( ) ;
394+ } else if inedible. contains ( self . token ) {
395+ // leave it in the input
396+ } else {
397+ let expected = vec:: append ( edible. to_owned ( ) , inedible) ;
398+ let expect = tokens_to_str ( self , expected) ;
399+ let actual = self . this_token_to_str ( ) ;
400+ self . fatal (
401+ if expected. len ( ) != 1 {
402+ fmt ! ( "expected one of `%s` but found `%s`" , expect, actual)
403+ } else {
404+ fmt ! ( "expected `%s` but found `%s`" , expect, actual)
405+ }
406+ )
407+ }
408+ }
409+
410+ // Check for erroneous `ident { }`; if matches, signal error and
411+ // recover (without consuming any expected input token). Returns
412+ // true if and only if input was consumed for recovery.
413+ pub fn check_for_erroneous_unit_struct_expecting ( & self , expected : & [ token:: Token ] ) -> bool {
414+ if * self . token == token:: LBRACE
415+ && expected. iter ( ) . all ( |t| * t != token:: LBRACE )
416+ && self . look_ahead ( 1 , |t| * t == token:: RBRACE ) {
417+ // matched; signal non-fatal error and recover.
418+ self . span_err ( * self . span ,
419+ "Unit-like struct construction is written with no trailing `{ }`" ) ;
420+ self . eat ( & token:: LBRACE ) ;
421+ self . eat ( & token:: RBRACE ) ;
422+ true
423+ } else {
424+ false
425+ }
426+ }
427+
428+ // Commit to parsing a complete expression `e` expected to be
429+ // followed by some token from the set edible + inedible. Recover
430+ // from anticipated input errors, discarding erroneous characters.
431+ pub fn commit_expr ( & self , e: @expr, edible : & [ token:: Token ] , inedible : & [ token:: Token ] ) {
432+ debug ! ( "commit_expr %?" , e) ;
433+ match e. node {
434+ expr_path( * ) => {
435+ // might be unit-struct construction; check for recoverableinput error.
436+ let expected = vec:: append ( edible. to_owned ( ) , inedible) ;
437+ self . check_for_erroneous_unit_struct_expecting ( expected) ;
438+ }
439+ _ => { }
440+ }
441+ self . expect_one_of ( edible, inedible)
442+ }
443+
444+ pub fn commit_expr_expecting ( & self , e: @expr, edible : token:: Token ) {
445+ self . commit_expr ( e, & [ edible] , & [ ] )
446+ }
447+
448+ // Commit to parsing a complete statement `s`, which expects to be
449+ // followed by some token from the set edible + inedible. Check
450+ // for recoverable input errors, discarding erroneous characters.
451+ pub fn commit_stmt ( & self , s: @stmt, edible : & [ token:: Token ] , inedible : & [ token:: Token ] ) {
452+ debug ! ( "commit_stmt %?" , s) ;
453+ let _s = s; // unused, but future checks might want to inspect `s`.
454+ if self . last_token . map_default ( false , |t|is_ident_or_path ( * t) ) {
455+ let expected = vec:: append ( edible. to_owned ( ) , inedible) ;
456+ self . check_for_erroneous_unit_struct_expecting ( expected) ;
457+ }
458+ self . expect_one_of ( edible, inedible)
459+ }
460+
461+ pub fn commit_stmt_expecting ( & self , s: @stmt, edible : token:: Token ) {
462+ self . commit_stmt ( s, & [ edible] , & [ ] )
463+ }
464+
379465 pub fn parse_ident ( & self ) -> ast:: ident {
380466 self . check_strict_keywords ( ) ;
381467 self . check_reserved_keywords ( ) ;
@@ -578,6 +664,12 @@ impl Parser {
578664 // advance the parser by one token
579665 pub fn bump ( & self ) {
580666 * self . last_span = * self . span ;
667+ // Stash token for error recovery (sometimes; clone is not necessarily cheap).
668+ * self . last_token = if is_ident_or_path ( self . token ) {
669+ Some ( ~( * self . token ) . clone ( ) )
670+ } else {
671+ None
672+ } ;
581673 let next = if * self . buffer_start == * self . buffer_end {
582674 self . reader . next_token ( )
583675 } else {
@@ -1595,17 +1687,19 @@ impl Parser {
15951687 return self . mk_expr( lo, hi, expr_lit( lit) ) ;
15961688 }
15971689 let mut es = ~[ self . parse_expr( ) ] ;
1690+ self . commit_expr( * es. last( ) , & [ ] , & [ token:: COMMA , token:: RPAREN ] ) ;
15981691 while * self . token == token:: COMMA {
15991692 self . bump( ) ;
16001693 if * self . token != token:: RPAREN {
16011694 es. push( self . parse_expr( ) ) ;
1695+ self . commit_expr( * es. last( ) , & [ ] , & [ token:: COMMA , token:: RPAREN ] ) ;
16021696 }
16031697 else {
16041698 trailing_comma = true ;
16051699 }
16061700 }
16071701 hi = self . span . hi ;
1608- self . expect ( & token:: RPAREN ) ;
1702+ self . commit_expr_expecting ( * es . last ( ) , token:: RPAREN ) ;
16091703
16101704 return if es. len ( ) == 1 && !trailing_comma {
16111705 self . mk_expr ( lo, self . span . hi , expr_paren ( es[ 0 ] ) )
@@ -1745,7 +1839,7 @@ impl Parser {
17451839 break ;
17461840 }
17471841
1748- self . expect ( & token:: COMMA ) ;
1842+ self . commit_expr ( fields . last ( ) . expr , & [ token:: COMMA ] , & [ token :: RBRACE ] ) ;
17491843
17501844 if self . eat ( & token:: DOTDOT ) {
17511845 base = Some ( self . parse_expr ( ) ) ;
@@ -1760,7 +1854,7 @@ impl Parser {
17601854 }
17611855
17621856 hi = pth. span . hi ;
1763- self . expect ( & token:: RBRACE ) ;
1857+ self . commit_expr_expecting ( fields . last ( ) . expr , token:: RBRACE ) ;
17641858 ex = expr_struct ( pth, fields, base) ;
17651859 return self . mk_expr ( lo, hi, ex) ;
17661860 }
@@ -1854,7 +1948,7 @@ impl Parser {
18541948 self . bump ( ) ;
18551949 let ix = self . parse_expr ( ) ;
18561950 hi = ix. span . hi ;
1857- self . expect ( & token:: RBRACKET ) ;
1951+ self . commit_expr_expecting ( ix , token:: RBRACKET ) ;
18581952 e = self . mk_expr ( lo, hi, self . mk_index ( e, ix) ) ;
18591953 }
18601954
@@ -2463,7 +2557,7 @@ impl Parser {
24632557 fn parse_match_expr ( & self ) -> @expr {
24642558 let lo = self . last_span . lo ;
24652559 let discriminant = self . parse_expr ( ) ;
2466- self . expect ( & token:: LBRACE ) ;
2560+ self . commit_expr_expecting ( discriminant , token:: LBRACE ) ;
24672561 let mut arms: ~[ arm ] = ~[ ] ;
24682562 while * self . token != token:: RBRACE {
24692563 let pats = self . parse_pats ( ) ;
@@ -2479,7 +2573,7 @@ impl Parser {
24792573 && * self . token != token:: RBRACE ;
24802574
24812575 if require_comma {
2482- self . expect ( & token:: COMMA ) ;
2576+ self . commit_expr ( expr , & [ token:: COMMA ] , & [ token :: RBRACE ] ) ;
24832577 } else {
24842578 self . eat ( & token:: COMMA ) ;
24852579 }
@@ -3179,37 +3273,26 @@ impl Parser {
31793273 match stmt. node {
31803274 stmt_expr( e, stmt_id) => {
31813275 // expression without semicolon
3182- let has_semi;
3276+ if classify:: stmt_ends_with_semi ( stmt) {
3277+ // Just check for errors and recover; do not eat semicolon yet.
3278+ self . commit_stmt ( stmt, & [ ] , & [ token:: SEMI , token:: RBRACE ] ) ;
3279+ }
3280+
31833281 match * self . token {
31843282 token:: SEMI => {
3185- has_semi = true ;
3283+ self . bump ( ) ;
3284+ stmts. push ( @codemap:: spanned {
3285+ node : stmt_semi ( e, stmt_id) ,
3286+ span : stmt. span ,
3287+ } ) ;
31863288 }
31873289 token:: RBRACE => {
3188- has_semi = false ;
31893290 expr = Some ( e) ;
31903291 }
3191- ref t => {
3192- has_semi = false ;
3193- if classify:: stmt_ends_with_semi ( stmt) {
3194- self . fatal (
3195- fmt ! (
3196- "expected `;` or `}` after \
3197- expression but found `%s`",
3198- self . token_to_str( t)
3199- )
3200- ) ;
3201- }
3292+ _ => {
32023293 stmts. push ( stmt) ;
32033294 }
32043295 }
3205-
3206- if has_semi {
3207- self . bump ( ) ;
3208- stmts. push ( @codemap:: spanned {
3209- node : stmt_semi ( e, stmt_id) ,
3210- span : stmt. span ,
3211- } ) ;
3212- }
32133296 }
32143297 stmt_mac( ref m, _) => {
32153298 // statement macro; might be an expr
@@ -3245,7 +3328,7 @@ impl Parser {
32453328 stmts. push ( stmt) ;
32463329
32473330 if classify:: stmt_ends_with_semi ( stmt) {
3248- self . expect ( & token:: SEMI ) ;
3331+ self . commit_stmt_expecting ( stmt , token:: SEMI ) ;
32493332 }
32503333 }
32513334 }
@@ -3760,7 +3843,7 @@ impl Parser {
37603843 }
37613844 }
37623845 if fields. len ( ) == 0 {
3763- self . fatal ( fmt ! ( "Unit-like struct should be written as `struct %s;`" ,
3846+ self . fatal ( fmt ! ( "Unit-like struct definition should be written as `struct %s;`" ,
37643847 get_ident_interner( ) . get( class_name. name) ) ) ;
37653848 }
37663849 self . bump ( ) ;
@@ -3952,7 +4035,7 @@ impl Parser {
39524035 let ty = self . parse_ty ( false ) ;
39534036 self . expect ( & token:: EQ ) ;
39544037 let e = self . parse_expr ( ) ;
3955- self . expect ( & token:: SEMI ) ;
4038+ self . commit_expr_expecting ( e , token:: SEMI ) ;
39564039 ( id, item_static ( ty, m, e) , None )
39574040 }
39584041
0 commit comments