@@ -281,6 +281,7 @@ pub fn Parser(sess: @mut ParseSess,
281
281
token : @mut tok0. tok ,
282
282
span : @mut span,
283
283
last_span : @mut span,
284
+ last_token : @mut None ,
284
285
buffer : @mut ( [
285
286
placeholder. clone ( ) ,
286
287
placeholder. clone ( ) ,
@@ -307,6 +308,8 @@ pub struct Parser {
307
308
span : @mut span ,
308
309
// the span of the prior token:
309
310
last_span : @mut span ,
311
+ // the previous token or None (only stashed sometimes).
312
+ last_token : @mut Option < ~token:: Token > ,
310
313
buffer : @mut [ TokenAndSpan , ..4 ] ,
311
314
buffer_start : @mut int ,
312
315
buffer_end : @mut int ,
@@ -374,6 +377,89 @@ impl Parser {
374
377
}
375
378
}
376
379
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
+
377
463
pub fn parse_ident ( & self ) -> ast:: ident {
378
464
self . check_strict_keywords ( ) ;
379
465
self . check_reserved_keywords ( ) ;
@@ -576,6 +662,12 @@ impl Parser {
576
662
// advance the parser by one token
577
663
pub fn bump ( & self ) {
578
664
* 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
+ } ;
579
671
let next = if * self . buffer_start == * self . buffer_end {
580
672
self . reader . next_token ( )
581
673
} else {
@@ -1593,17 +1685,19 @@ impl Parser {
1593
1685
return self . mk_expr( lo, hi, expr_lit( lit) ) ;
1594
1686
}
1595
1687
let mut es = ~[ self . parse_expr( ) ] ;
1688
+ self . commit_expr( * es. last( ) , & [ ] , & [ token:: COMMA , token:: RPAREN ] ) ;
1596
1689
while * self . token == token:: COMMA {
1597
1690
self . bump( ) ;
1598
1691
if * self . token != token:: RPAREN {
1599
1692
es. push( self . parse_expr( ) ) ;
1693
+ self . commit_expr( * es. last( ) , & [ ] , & [ token:: COMMA , token:: RPAREN ] ) ;
1600
1694
}
1601
1695
else {
1602
1696
trailing_comma = true ;
1603
1697
}
1604
1698
}
1605
1699
hi = self . span . hi ;
1606
- self . expect ( & token:: RPAREN ) ;
1700
+ self . commit_expr_expecting ( * es . last ( ) , token:: RPAREN ) ;
1607
1701
1608
1702
return if es. len ( ) == 1 && !trailing_comma {
1609
1703
self . mk_expr ( lo, self . span . hi , expr_paren ( es[ 0 ] ) )
@@ -1743,7 +1837,7 @@ impl Parser {
1743
1837
break ;
1744
1838
}
1745
1839
1746
- self . expect ( & token:: COMMA ) ;
1840
+ self . commit_expr ( fields . last ( ) . expr , & [ token:: COMMA ] , & [ token :: RBRACE ] ) ;
1747
1841
1748
1842
if self . eat ( & token:: DOTDOT ) {
1749
1843
base = Some ( self . parse_expr ( ) ) ;
@@ -1758,7 +1852,7 @@ impl Parser {
1758
1852
}
1759
1853
1760
1854
hi = pth. span . hi ;
1761
- self . expect ( & token:: RBRACE ) ;
1855
+ self . commit_expr_expecting ( fields . last ( ) . expr , token:: RBRACE ) ;
1762
1856
ex = expr_struct ( pth, fields, base) ;
1763
1857
return self . mk_expr ( lo, hi, ex) ;
1764
1858
}
@@ -1852,7 +1946,7 @@ impl Parser {
1852
1946
self . bump ( ) ;
1853
1947
let ix = self . parse_expr ( ) ;
1854
1948
hi = ix. span . hi ;
1855
- self . expect ( & token:: RBRACKET ) ;
1949
+ self . commit_expr_expecting ( ix , token:: RBRACKET ) ;
1856
1950
e = self . mk_expr ( lo, hi, self . mk_index ( e, ix) ) ;
1857
1951
}
1858
1952
@@ -2461,7 +2555,7 @@ impl Parser {
2461
2555
fn parse_match_expr ( & self ) -> @expr {
2462
2556
let lo = self . last_span . lo ;
2463
2557
let discriminant = self . parse_expr ( ) ;
2464
- self . expect ( & token:: LBRACE ) ;
2558
+ self . commit_expr_expecting ( discriminant , token:: LBRACE ) ;
2465
2559
let mut arms: ~[ arm ] = ~[ ] ;
2466
2560
while * self . token != token:: RBRACE {
2467
2561
let pats = self . parse_pats ( ) ;
@@ -2477,7 +2571,7 @@ impl Parser {
2477
2571
&& * self . token != token:: RBRACE ;
2478
2572
2479
2573
if require_comma {
2480
- self . expect ( & token:: COMMA ) ;
2574
+ self . commit_expr ( expr , & [ token:: COMMA ] , & [ token :: RBRACE ] ) ;
2481
2575
} else {
2482
2576
self . eat ( & token:: COMMA ) ;
2483
2577
}
@@ -3177,37 +3271,26 @@ impl Parser {
3177
3271
match stmt. node {
3178
3272
stmt_expr( e, stmt_id) => {
3179
3273
// 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
+
3181
3279
match * self . token {
3182
3280
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
+ } ) ;
3184
3286
}
3185
3287
token:: RBRACE => {
3186
- has_semi = false ;
3187
3288
expr = Some ( e) ;
3188
3289
}
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
+ _ => {
3200
3291
stmts. push ( stmt) ;
3201
3292
}
3202
3293
}
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
- }
3211
3294
}
3212
3295
stmt_mac( ref m, _) => {
3213
3296
// statement macro; might be an expr
@@ -3243,7 +3326,7 @@ impl Parser {
3243
3326
stmts. push ( stmt) ;
3244
3327
3245
3328
if classify:: stmt_ends_with_semi ( stmt) {
3246
- self . expect ( & token:: SEMI ) ;
3329
+ self . commit_stmt_expecting ( stmt , token:: SEMI ) ;
3247
3330
}
3248
3331
}
3249
3332
}
@@ -3758,7 +3841,7 @@ impl Parser {
3758
3841
}
3759
3842
}
3760
3843
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;`" ,
3762
3845
get_ident_interner( ) . get( class_name. name) ) ) ;
3763
3846
}
3764
3847
self . bump ( ) ;
@@ -3938,7 +4021,7 @@ impl Parser {
3938
4021
let ty = self . parse_ty ( false ) ;
3939
4022
self . expect ( & token:: EQ ) ;
3940
4023
let e = self . parse_expr ( ) ;
3941
- self . expect ( & token:: SEMI ) ;
4024
+ self . commit_expr_expecting ( e , token:: SEMI ) ;
3942
4025
( id, item_static ( ty, m, e) , None )
3943
4026
}
3944
4027
0 commit comments