@@ -283,6 +283,7 @@ pub fn Parser(sess: @mut ParseSess,
283
283
token : @mut tok0. tok ,
284
284
span : @mut span,
285
285
last_span : @mut span,
286
+ last_token : @mut None ,
286
287
buffer : @mut ( [
287
288
placeholder. clone ( ) ,
288
289
placeholder. clone ( ) ,
@@ -309,6 +310,8 @@ pub struct Parser {
309
310
span : @mut span ,
310
311
// the span of the prior token:
311
312
last_span : @mut span ,
313
+ // the previous token or None (only stashed sometimes).
314
+ last_token : @mut Option < ~token:: Token > ,
312
315
buffer : @mut [ TokenAndSpan , ..4 ] ,
313
316
buffer_start : @mut int ,
314
317
buffer_end : @mut int ,
@@ -376,6 +379,89 @@ impl Parser {
376
379
}
377
380
}
378
381
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
+
379
465
pub fn parse_ident ( & self ) -> ast:: ident {
380
466
self . check_strict_keywords ( ) ;
381
467
self . check_reserved_keywords ( ) ;
@@ -578,6 +664,12 @@ impl Parser {
578
664
// advance the parser by one token
579
665
pub fn bump ( & self ) {
580
666
* 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
+ } ;
581
673
let next = if * self . buffer_start == * self . buffer_end {
582
674
self . reader . next_token ( )
583
675
} else {
@@ -1595,17 +1687,19 @@ impl Parser {
1595
1687
return self . mk_expr( lo, hi, expr_lit( lit) ) ;
1596
1688
}
1597
1689
let mut es = ~[ self . parse_expr( ) ] ;
1690
+ self . commit_expr( * es. last( ) , & [ ] , & [ token:: COMMA , token:: RPAREN ] ) ;
1598
1691
while * self . token == token:: COMMA {
1599
1692
self . bump( ) ;
1600
1693
if * self . token != token:: RPAREN {
1601
1694
es. push( self . parse_expr( ) ) ;
1695
+ self . commit_expr( * es. last( ) , & [ ] , & [ token:: COMMA , token:: RPAREN ] ) ;
1602
1696
}
1603
1697
else {
1604
1698
trailing_comma = true ;
1605
1699
}
1606
1700
}
1607
1701
hi = self . span . hi ;
1608
- self . expect ( & token:: RPAREN ) ;
1702
+ self . commit_expr_expecting ( * es . last ( ) , token:: RPAREN ) ;
1609
1703
1610
1704
return if es. len ( ) == 1 && !trailing_comma {
1611
1705
self . mk_expr ( lo, self . span . hi , expr_paren ( es[ 0 ] ) )
@@ -1745,7 +1839,7 @@ impl Parser {
1745
1839
break ;
1746
1840
}
1747
1841
1748
- self . expect ( & token:: COMMA ) ;
1842
+ self . commit_expr ( fields . last ( ) . expr , & [ token:: COMMA ] , & [ token :: RBRACE ] ) ;
1749
1843
1750
1844
if self . eat ( & token:: DOTDOT ) {
1751
1845
base = Some ( self . parse_expr ( ) ) ;
@@ -1760,7 +1854,7 @@ impl Parser {
1760
1854
}
1761
1855
1762
1856
hi = pth. span . hi ;
1763
- self . expect ( & token:: RBRACE ) ;
1857
+ self . commit_expr_expecting ( fields . last ( ) . expr , token:: RBRACE ) ;
1764
1858
ex = expr_struct ( pth, fields, base) ;
1765
1859
return self . mk_expr ( lo, hi, ex) ;
1766
1860
}
@@ -1854,7 +1948,7 @@ impl Parser {
1854
1948
self . bump ( ) ;
1855
1949
let ix = self . parse_expr ( ) ;
1856
1950
hi = ix. span . hi ;
1857
- self . expect ( & token:: RBRACKET ) ;
1951
+ self . commit_expr_expecting ( ix , token:: RBRACKET ) ;
1858
1952
e = self . mk_expr ( lo, hi, self . mk_index ( e, ix) ) ;
1859
1953
}
1860
1954
@@ -2463,7 +2557,7 @@ impl Parser {
2463
2557
fn parse_match_expr ( & self ) -> @expr {
2464
2558
let lo = self . last_span . lo ;
2465
2559
let discriminant = self . parse_expr ( ) ;
2466
- self . expect ( & token:: LBRACE ) ;
2560
+ self . commit_expr_expecting ( discriminant , token:: LBRACE ) ;
2467
2561
let mut arms: ~[ arm ] = ~[ ] ;
2468
2562
while * self . token != token:: RBRACE {
2469
2563
let pats = self . parse_pats ( ) ;
@@ -2479,7 +2573,7 @@ impl Parser {
2479
2573
&& * self . token != token:: RBRACE ;
2480
2574
2481
2575
if require_comma {
2482
- self . expect ( & token:: COMMA ) ;
2576
+ self . commit_expr ( expr , & [ token:: COMMA ] , & [ token :: RBRACE ] ) ;
2483
2577
} else {
2484
2578
self . eat ( & token:: COMMA ) ;
2485
2579
}
@@ -3179,37 +3273,26 @@ impl Parser {
3179
3273
match stmt. node {
3180
3274
stmt_expr( e, stmt_id) => {
3181
3275
// 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
+
3183
3281
match * self . token {
3184
3282
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
+ } ) ;
3186
3288
}
3187
3289
token:: RBRACE => {
3188
- has_semi = false ;
3189
3290
expr = Some ( e) ;
3190
3291
}
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
+ _ => {
3202
3293
stmts. push ( stmt) ;
3203
3294
}
3204
3295
}
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
- }
3213
3296
}
3214
3297
stmt_mac( ref m, _) => {
3215
3298
// statement macro; might be an expr
@@ -3245,7 +3328,7 @@ impl Parser {
3245
3328
stmts. push ( stmt) ;
3246
3329
3247
3330
if classify:: stmt_ends_with_semi ( stmt) {
3248
- self . expect ( & token:: SEMI ) ;
3331
+ self . commit_stmt_expecting ( stmt , token:: SEMI ) ;
3249
3332
}
3250
3333
}
3251
3334
}
@@ -3760,7 +3843,7 @@ impl Parser {
3760
3843
}
3761
3844
}
3762
3845
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;`" ,
3764
3847
get_ident_interner( ) . get( class_name. name) ) ) ;
3765
3848
}
3766
3849
self . bump ( ) ;
@@ -3952,7 +4035,7 @@ impl Parser {
3952
4035
let ty = self . parse_ty ( false ) ;
3953
4036
self . expect ( & token:: EQ ) ;
3954
4037
let e = self . parse_expr ( ) ;
3955
- self . expect ( & token:: SEMI ) ;
4038
+ self . commit_expr_expecting ( e , token:: SEMI ) ;
3956
4039
( id, item_static ( ty, m, e) , None )
3957
4040
}
3958
4041
0 commit comments