@@ -61,6 +61,16 @@ enum class LexerMode {
6161 SIL
6262};
6363
64+ // / Whether or not the lexer should attempt to lex a `/.../` regex literal.
65+ enum class LexerForwardSlashRegexMode {
66+ // / No `/.../` regex literals will be lexed.
67+ None,
68+ // / A `/.../` regex literal will be lexed, but only if successful.
69+ Tentative,
70+ // / A `/.../` regex literal will always be lexed for a '/' character.
71+ Always
72+ };
73+
6474// / Kinds of conflict marker which the lexer might encounter.
6575enum class ConflictMarkerKind {
6676 // / A normal or diff3 conflict marker, initiated by at least 7 "<"s,
@@ -75,7 +85,10 @@ class Lexer {
7585 const LangOptions &LangOpts;
7686 const SourceManager &SourceMgr;
7787 const unsigned BufferID;
78- DiagnosticEngine *Diags;
88+
89+ // / A queue of diagnostics to emit when a token is consumed. We want to queue
90+ // / them, as the parser may backtrack and re-lex a token.
91+ Optional<DiagnosticQueue> DiagQueue;
7992
8093 using State = LexerState;
8194
@@ -109,6 +122,10 @@ class Lexer {
109122 // / a .sil file.
110123 const LexerMode LexMode;
111124
125+ // / Whether or not a `/.../` literal will be lexed.
126+ LexerForwardSlashRegexMode ForwardSlashRegexMode =
127+ LexerForwardSlashRegexMode::None;
128+
112129 // / True if we should skip past a `#!` line at the start of the file.
113130 const bool IsHashbangAllowed;
114131
@@ -154,6 +171,19 @@ class Lexer {
154171
155172 void initialize (unsigned Offset, unsigned EndOffset);
156173
174+ // / Retrieve the diagnostic engine for emitting diagnostics for the current
175+ // / token.
176+ DiagnosticEngine *getTokenDiags () {
177+ return DiagQueue ? &DiagQueue->getDiags () : nullptr ;
178+ }
179+
180+ // / Retrieve the underlying diagnostic engine we emit diagnostics to. Note
181+ // / this should only be used for diagnostics not concerned with the current
182+ // / token.
183+ DiagnosticEngine *getUnderlyingDiags () {
184+ return DiagQueue ? &DiagQueue->getUnderlyingDiags () : nullptr ;
185+ }
186+
157187public:
158188 // / Create a normal lexer that scans the whole source buffer.
159189 // /
@@ -209,6 +239,10 @@ class Lexer {
209239 LeadingTriviaResult = LeadingTrivia;
210240 TrailingTriviaResult = TrailingTrivia;
211241 }
242+ // Emit any diagnostics recorded for this token.
243+ if (DiagQueue)
244+ DiagQueue->emit ();
245+
212246 if (Result.isNot (tok::eof))
213247 lexImpl ();
214248 }
@@ -298,12 +332,12 @@ class Lexer {
298332 void restoreState (State S, bool enableDiagnostics = false ) {
299333 assert (S.isValid ());
300334 CurPtr = getBufferPtrForSourceLoc (S.Loc );
301- // Don't reemit diagnostics while readvancing the lexer.
302- llvm::SaveAndRestore<DiagnosticEngine*>
303- D (Diags, enableDiagnostics ? Diags : nullptr );
304-
305335 lexImpl ();
306336
337+ // Don't re-emit diagnostics from readvancing the lexer.
338+ if (DiagQueue && !enableDiagnostics)
339+ DiagQueue->clear ();
340+
307341 // Restore Trivia.
308342 if (TriviaRetention == TriviaRetentionMode::WithTrivia)
309343 LeadingTrivia = S.LeadingTrivia ;
@@ -505,7 +539,7 @@ class Lexer {
505539
506540 void getStringLiteralSegments (const Token &Str,
507541 SmallVectorImpl<StringSegment> &Segments) {
508- return getStringLiteralSegments (Str, Segments, Diags );
542+ return getStringLiteralSegments (Str, Segments, getTokenDiags () );
509543 }
510544
511545 static SourceLoc getSourceLoc (const char *Loc) {
@@ -531,6 +565,11 @@ class Lexer {
531565 void operator =(const SILBodyRAII&) = delete ;
532566 };
533567
568+ // / Attempt to re-lex a regex literal with forward slashes `/.../` from a
569+ // / given lexing state. If \p mustBeRegex is set to true, a regex literal will
570+ // / always be lexed. Otherwise, it will not be lexed if it may be ambiguous.
571+ void tryLexForwardSlashRegexLiteralFrom (State S, bool mustBeRegex);
572+
534573private:
535574 // / Nul character meaning kind.
536575 enum class NulCharacterKind {
@@ -595,8 +634,8 @@ class Lexer {
595634 void lexStringLiteral (unsigned CustomDelimiterLen = 0 );
596635 void lexEscapedIdentifier ();
597636
598- // / Attempt to lex a regex literal, returning true if a regex literal was
599- // / lexed, false if this is not a regex literal.
637+ // / Attempt to lex a regex literal, returning true if lexing should continue,
638+ // / false if this is not a regex literal.
600639 bool tryLexRegexLiteral (const char *TokStart);
601640
602641 void tryLexEditorPlaceholder ();
0 commit comments