@@ -26,12 +26,11 @@ namespace format {
26
26
FormatTokenLexer::FormatTokenLexer (const SourceManager &SourceMgr, FileID ID,
27
27
const FormatStyle &Style,
28
28
encoding::Encoding Encoding)
29
- : FormatTok(nullptr ), IsFirstToken(true ), GreaterStashed(false ),
30
- LessStashed (false ), Column(0 ), TrailingWhitespace(0 ),
31
- SourceMgr(SourceMgr), ID(ID), Style(Style),
32
- IdentTable(getFormattingLangOpts(Style)), Keywords(IdentTable),
33
- Encoding(Encoding), FirstInLineIndex(0 ), FormattingDisabled(false ),
34
- MacroBlockBeginRegex(Style.MacroBlockBegin),
29
+ : FormatTok(nullptr ), IsFirstToken(true ), StateStack({LexerState::NORMAL}),
30
+ Column (0 ), TrailingWhitespace(0 ), SourceMgr(SourceMgr), ID(ID),
31
+ Style (Style), IdentTable(getFormattingLangOpts(Style)),
32
+ Keywords (IdentTable), Encoding(Encoding), FirstInLineIndex(0 ),
33
+ FormattingDisabled (false ), MacroBlockBeginRegex(Style.MacroBlockBegin),
35
34
MacroBlockEndRegex (Style.MacroBlockEnd) {
36
35
Lex.reset (new Lexer (ID, SourceMgr.getBuffer (ID), SourceMgr,
37
36
getFormattingLangOpts (Style)));
@@ -49,7 +48,7 @@ ArrayRef<FormatToken *> FormatTokenLexer::lex() {
49
48
Tokens.push_back (getNextToken ());
50
49
if (Style.Language == FormatStyle::LK_JavaScript) {
51
50
tryParseJSRegexLiteral ();
52
- tryParseTemplateString ();
51
+ handleTemplateStrings ();
53
52
}
54
53
tryMergePreviousTokens ();
55
54
if (Tokens.back ()->NewlinesBefore > 0 || Tokens.back ()->IsMultiline )
@@ -228,17 +227,42 @@ void FormatTokenLexer::tryParseJSRegexLiteral() {
228
227
resetLexer (SourceMgr.getFileOffset (Lex->getSourceLocation (Offset)));
229
228
}
230
229
231
- void FormatTokenLexer::tryParseTemplateString () {
230
+ void FormatTokenLexer::handleTemplateStrings () {
232
231
FormatToken *BacktickToken = Tokens.back ();
233
- if (!BacktickToken->is (tok::unknown) || BacktickToken->TokenText != " `" )
232
+
233
+ if (BacktickToken->is (tok::l_brace)) {
234
+ StateStack.push (LexerState::NORMAL);
234
235
return ;
236
+ }
237
+ if (BacktickToken->is (tok::r_brace)) {
238
+ StateStack.pop ();
239
+ if (StateStack.top () != LexerState::TEMPLATE_STRING)
240
+ return ;
241
+ // If back in TEMPLATE_STRING, fallthrough and continue parsing the
242
+ } else if (BacktickToken->is (tok::unknown) &&
243
+ BacktickToken->TokenText == " `" ) {
244
+ StateStack.push (LexerState::TEMPLATE_STRING);
245
+ } else {
246
+ return ; // Not actually a template
247
+ }
235
248
236
249
// 'Manually' lex ahead in the current file buffer.
237
250
const char *Offset = Lex->getBufferLocation ();
238
251
const char *TmplBegin = Offset - BacktickToken->TokenText .size (); // at "`"
239
- for (; Offset != Lex->getBuffer ().end () && *Offset != ' `' ; ++Offset) {
240
- if (*Offset == ' \\ ' )
252
+ for (; Offset != Lex->getBuffer ().end (); ++Offset) {
253
+ if (Offset[0 ] == ' `' ) {
254
+ StateStack.pop ();
255
+ break ;
256
+ }
257
+ if (Offset[0 ] == ' \\ ' ) {
241
258
++Offset; // Skip the escaped character.
259
+ } else if (Offset + 1 < Lex->getBuffer ().end () && Offset[0 ] == ' $' &&
260
+ Offset[1 ] == ' {' ) {
261
+ // '${' introduces an expression interpolation in the template string.
262
+ StateStack.push (LexerState::NORMAL);
263
+ ++Offset;
264
+ break ;
265
+ }
242
266
}
243
267
244
268
StringRef LiteralText (TmplBegin, Offset - TmplBegin + 1 );
@@ -262,7 +286,10 @@ void FormatTokenLexer::tryParseTemplateString() {
262
286
Style.TabWidth , Encoding);
263
287
}
264
288
265
- resetLexer (SourceMgr.getFileOffset (Lex->getSourceLocation (Offset + 1 )));
289
+ SourceLocation loc = Offset < Lex->getBuffer ().end ()
290
+ ? Lex->getSourceLocation (Offset + 1 )
291
+ : SourceMgr.getLocForEndOfFile (ID);
292
+ resetLexer (SourceMgr.getFileOffset (loc));
266
293
}
267
294
268
295
bool FormatTokenLexer::tryMerge_TMacro () {
@@ -384,12 +411,8 @@ FormatToken *FormatTokenLexer::getStashedToken() {
384
411
}
385
412
386
413
FormatToken *FormatTokenLexer::getNextToken () {
387
- if (GreaterStashed) {
388
- GreaterStashed = false ;
389
- return getStashedToken ();
390
- }
391
- if (LessStashed) {
392
- LessStashed = false ;
414
+ if (StateStack.top () == LexerState::TOKEN_STASHED) {
415
+ StateStack.pop ();
393
416
return getStashedToken ();
394
417
}
395
418
@@ -500,11 +523,11 @@ FormatToken *FormatTokenLexer::getNextToken() {
500
523
} else if (FormatTok->Tok .is (tok::greatergreater)) {
501
524
FormatTok->Tok .setKind (tok::greater);
502
525
FormatTok->TokenText = FormatTok->TokenText .substr (0 , 1 );
503
- GreaterStashed = true ;
526
+ StateStack. push (LexerState::TOKEN_STASHED) ;
504
527
} else if (FormatTok->Tok .is (tok::lessless)) {
505
528
FormatTok->Tok .setKind (tok::less);
506
529
FormatTok->TokenText = FormatTok->TokenText .substr (0 , 1 );
507
- LessStashed = true ;
530
+ StateStack. push (LexerState::TOKEN_STASHED) ;
508
531
}
509
532
510
533
// Now FormatTok is the next non-whitespace token.
0 commit comments