@@ -89,9 +89,15 @@ enum Token {
8989
9090 REGEX_MODIFIER ,
9191
92+ // A zero-width token that must be followed by a method call `.` token.
93+ // Only valid as certain points in the grammar, indicated by
94+ // IMPLICIT_OBJECT_AVAILABLE.
95+ IMPLICIT_OBJECT ,
96+
9297 // Never returned
9398 START_OF_PARENLESS_ARGS ,
9499 END_OF_RANGE ,
100+ IMPLICIT_OBJECT_AVAILABLE ,
95101
96102 // Only used when error recovery mode is active
97103 ERROR_RECOVERY ,
@@ -1848,20 +1854,51 @@ static bool inner_scan(void *payload, TSLexer *lexer, const bool *valid_symbols)
18481854 break ;
18491855
18501856 case '.' :
1851- if (valid_symbols [BEGINLESS_RANGE_OPERATOR ] && !valid_symbols [START_OF_PARENLESS_ARGS ]) {
1852- lex_advance (lexer );
1853- if (lexer -> lookahead != '.' ) {
1854- return false;
1855- }
1856- lex_advance (lexer );
1857- if (lexer -> lookahead == '.' ) {
1857+ {
1858+ bool implicit_object_possible = valid_symbols [IMPLICIT_OBJECT ] && valid_symbols [IMPLICIT_OBJECT_AVAILABLE ] && !valid_symbols [ERROR_RECOVERY ];
1859+ bool beginless_range_possible = valid_symbols [BEGINLESS_RANGE_OPERATOR ] && !valid_symbols [START_OF_PARENLESS_ARGS ];
1860+
1861+ if (implicit_object_possible && beginless_range_possible ) {
1862+ lexer -> mark_end (lexer );
18581863 lex_advance (lexer );
1859- }
18601864
1861- lexer -> result_symbol = BEGINLESS_RANGE_OPERATOR ;
1862- return true;
1865+ if (lexer -> lookahead != '.' ) {
1866+ // This looks like the beginning of a method call, not a range operator, so
1867+ // it's the right place to inject an IMPLICIT_OBJECT token. IMPLICIT_OBJECT
1868+ // is a zero-width token, we don't want to mark the end again.
1869+ lexer -> result_symbol = IMPLICIT_OBJECT ;
1870+ return true;
1871+ }
1872+
1873+ // This looks like a range operator.
1874+ lex_advance (lexer );
1875+ if (lexer -> lookahead == '.' ) {
1876+ lex_advance (lexer );
1877+ }
1878+
1879+ lexer -> mark_end (lexer );
1880+ lexer -> result_symbol = BEGINLESS_RANGE_OPERATOR ;
1881+ return true;
1882+ } else if (implicit_object_possible ) {
1883+ // IMPLICIT_OBJECT is a zero-width token, we don't want to advance.
1884+ lexer -> result_symbol = IMPLICIT_OBJECT ;
1885+ return true;
1886+ } else if (beginless_range_possible ) {
1887+ lex_advance (lexer );
1888+ if (lexer -> lookahead != '.' ) {
1889+ return false;
1890+ }
1891+
1892+ lex_advance (lexer );
1893+ if (lexer -> lookahead == '.' ) {
1894+ lex_advance (lexer );
1895+ }
1896+
1897+ lexer -> result_symbol = BEGINLESS_RANGE_OPERATOR ;
1898+ return true;
1899+ }
1900+ break ;
18631901 }
1864- break ;
18651902 case 'e' :
18661903 if (valid_symbols [REGULAR_ENSURE_KEYWORD ] || valid_symbols [MODIFIER_ENSURE_KEYWORD ]) {
18671904 lex_advance (lexer );
0 commit comments