@@ -1376,6 +1376,122 @@ fn ttdelim_span() {
13761376 } ) ;
13771377}
13781378
1379+ // Uses a macro rather than a function so that failure messages mention the
1380+ // correct line in the test function.
1381+ macro_rules! look {
1382+ ( $p: ident, $dist: literal, $kind: expr) => {
1383+ $p. look_ahead( $dist, |tok| assert_eq!( $kind, tok. kind) ) ;
1384+ } ;
1385+ }
1386+
1387+ #[ test]
1388+ fn look_ahead ( ) {
1389+ create_default_session_globals_then ( || {
1390+ let sym_f = Symbol :: intern ( "f" ) ;
1391+ let sym_x = Symbol :: intern ( "x" ) ;
1392+ #[ allow( non_snake_case) ]
1393+ let sym_S = Symbol :: intern ( "S" ) ;
1394+ let raw_no = IdentIsRaw :: No ;
1395+
1396+ let psess = psess ( ) ;
1397+ let mut p = string_to_parser ( & psess, "fn f(x: u32) { x } struct S;" . to_string ( ) ) ;
1398+
1399+ // Current position is the `fn`.
1400+ look ! ( p, 0 , token:: Ident ( kw:: Fn , raw_no) ) ;
1401+ look ! ( p, 1 , token:: Ident ( sym_f, raw_no) ) ;
1402+ look ! ( p, 2 , token:: OpenDelim ( Delimiter :: Parenthesis ) ) ;
1403+ look ! ( p, 3 , token:: Ident ( sym_x, raw_no) ) ;
1404+ look ! ( p, 4 , token:: Colon ) ;
1405+ look ! ( p, 5 , token:: Ident ( sym:: u32 , raw_no) ) ;
1406+ look ! ( p, 6 , token:: CloseDelim ( Delimiter :: Parenthesis ) ) ;
1407+ look ! ( p, 7 , token:: OpenDelim ( Delimiter :: Brace ) ) ;
1408+ look ! ( p, 8 , token:: Ident ( sym_x, raw_no) ) ;
1409+ look ! ( p, 9 , token:: CloseDelim ( Delimiter :: Brace ) ) ;
1410+ look ! ( p, 10 , token:: Ident ( kw:: Struct , raw_no) ) ;
1411+ look ! ( p, 11 , token:: Ident ( sym_S, raw_no) ) ;
1412+ look ! ( p, 12 , token:: Semi ) ;
1413+ // Any lookahead past the end of the token stream returns `Eof`.
1414+ look ! ( p, 13 , token:: Eof ) ;
1415+ look ! ( p, 14 , token:: Eof ) ;
1416+ look ! ( p, 15 , token:: Eof ) ;
1417+ look ! ( p, 100 , token:: Eof ) ;
1418+
1419+ // Move forward to the first `x`.
1420+ for _ in 0 ..3 {
1421+ p. bump ( ) ;
1422+ }
1423+ look ! ( p, 0 , token:: Ident ( sym_x, raw_no) ) ;
1424+ look ! ( p, 1 , token:: Colon ) ;
1425+ look ! ( p, 2 , token:: Ident ( sym:: u32 , raw_no) ) ;
1426+ look ! ( p, 3 , token:: CloseDelim ( Delimiter :: Parenthesis ) ) ;
1427+ // FIXME(nnethercote) If we lookahead any distance past a close delim
1428+ // we currently return that close delim.
1429+ look ! ( p, 4 , token:: CloseDelim ( Delimiter :: Parenthesis ) ) ;
1430+ look ! ( p, 5 , token:: CloseDelim ( Delimiter :: Parenthesis ) ) ;
1431+ look ! ( p, 6 , token:: CloseDelim ( Delimiter :: Parenthesis ) ) ;
1432+ look ! ( p, 100 , token:: CloseDelim ( Delimiter :: Parenthesis ) ) ;
1433+
1434+ // Move forward to the `;`.
1435+ for _ in 0 ..9 {
1436+ p. bump ( ) ;
1437+ }
1438+ look ! ( p, 0 , token:: Semi ) ;
1439+ // Any lookahead past the end of the token stream returns `Eof`.
1440+ look ! ( p, 1 , token:: Eof ) ;
1441+ look ! ( p, 100 , token:: Eof ) ;
1442+
1443+ // Move one past the `;`, i.e. past the end of the token stream.
1444+ p. bump ( ) ;
1445+ look ! ( p, 0 , token:: Eof ) ;
1446+ look ! ( p, 1 , token:: Eof ) ;
1447+ look ! ( p, 100 , token:: Eof ) ;
1448+
1449+ // Bumping after Eof is idempotent.
1450+ p. bump ( ) ;
1451+ look ! ( p, 0 , token:: Eof ) ;
1452+ look ! ( p, 1 , token:: Eof ) ;
1453+ look ! ( p, 100 , token:: Eof ) ;
1454+ } ) ;
1455+ }
1456+
1457+ /// FIXME(nnethercote) Currently there is some buggy behaviour when using
1458+ /// `look_ahead` not within the outermost token stream, as this test shows.
1459+ #[ test]
1460+ fn look_ahead_non_outermost_stream ( ) {
1461+ create_default_session_globals_then ( || {
1462+ let sym_f = Symbol :: intern ( "f" ) ;
1463+ #[ allow( non_snake_case) ]
1464+ let sym_S = Symbol :: intern ( "S" ) ;
1465+ let raw_no = IdentIsRaw :: No ;
1466+
1467+ let psess = psess ( ) ;
1468+ let mut p = string_to_parser ( & psess, "mod m { fn f(x: u32) { x } struct S; }" . to_string ( ) ) ;
1469+
1470+ // Move forward to the `fn`, which is not within the outermost token
1471+ // stream (because it's inside the `mod { ... }`).
1472+ for _ in 0 ..3 {
1473+ p. bump ( ) ;
1474+ }
1475+ look ! ( p, 0 , token:: Ident ( kw:: Fn , raw_no) ) ;
1476+ look ! ( p, 1 , token:: Ident ( sym_f, raw_no) ) ;
1477+ look ! ( p, 2 , token:: OpenDelim ( Delimiter :: Parenthesis ) ) ;
1478+ // FIXME(nnethercote) The current code incorrectly skips the `x: u32)`
1479+ // to the next token tree.
1480+ look ! ( p, 3 , token:: OpenDelim ( Delimiter :: Brace ) ) ;
1481+ // FIXME(nnethercote) The current code incorrectly skips the `x }`
1482+ // to the next token tree.
1483+ look ! ( p, 4 , token:: Ident ( kw:: Struct , raw_no) ) ;
1484+ look ! ( p, 5 , token:: Ident ( sym_S, raw_no) ) ;
1485+ look ! ( p, 6 , token:: Semi ) ;
1486+ // FIXME(nnethercote) If we lookahead any distance past a close delim
1487+ // we currently return that close delim.
1488+ look ! ( p, 7 , token:: CloseDelim ( Delimiter :: Brace ) ) ;
1489+ look ! ( p, 8 , token:: CloseDelim ( Delimiter :: Brace ) ) ;
1490+ look ! ( p, 9 , token:: CloseDelim ( Delimiter :: Brace ) ) ;
1491+ look ! ( p, 100 , token:: CloseDelim ( Delimiter :: Brace ) ) ;
1492+ } ) ;
1493+ }
1494+
13791495// This tests that when parsing a string (rather than a file) we don't try
13801496// and read in a file for a module declaration and just parse a stub.
13811497// See `recurse_into_file_modules` in the parser.
0 commit comments