clang-format: [JS] nested and tagged template strings.
JavaScript template strings can be nested arbitrarily:
foo = `text ${es.map(e => { return `<${e}>`; })} text`;
This change lexes nested template strings using a stack of lexer states to
correctly switch back to template string lexing on closing braces.
Also, reuse the same stack for the token-stashed logic.
Reviewers: djasper
Subscribers: cfe-commits, klimek
Differential Revision: https://reviews.llvm.org/D22431
llvm-svn: 279727
diff --git a/clang/lib/Format/FormatTokenLexer.h b/clang/lib/Format/FormatTokenLexer.h
index fa8c888..c47b0e7 100644
--- a/clang/lib/Format/FormatTokenLexer.h
+++ b/clang/lib/Format/FormatTokenLexer.h
@@ -23,9 +23,17 @@
#include "clang/Format/Format.h"
#include "llvm/Support/Regex.h"
+#include <stack>
+
namespace clang {
namespace format {
+enum LexerState {
+ NORMAL,
+ TEMPLATE_STRING,
+ TOKEN_STASHED,
+};
+
class FormatTokenLexer {
public:
FormatTokenLexer(const SourceManager &SourceMgr, FileID ID,
@@ -53,7 +61,16 @@
// its text if successful.
void tryParseJSRegexLiteral();
- void tryParseTemplateString();
+ // Handles JavaScript template strings.
+ //
+ // JavaScript template strings use backticks ('`') as delimiters, and allow
+ // embedding expressions nested in ${expr-here}. Template strings can be
+ // nested recursively, i.e. expressions can contain template strings in turn.
+ //
+ // The code below parses starting from a backtick, up to a closing backtick or
+ // an opening ${. It also maintains a stack of lexing contexts to handle
+ // nested template parts by balancing curly braces.
+ void handleTemplateStrings();
bool tryMerge_TMacro();
@@ -65,7 +82,7 @@
FormatToken *FormatTok;
bool IsFirstToken;
- bool GreaterStashed, LessStashed;
+ std::stack<LexerState> StateStack;
unsigned Column;
unsigned TrailingWhitespace;
std::unique_ptr<Lexer> Lex;