@@ -513,7 +513,7 @@ ParserResult<Expr> Parser::parseExprUnary(Diag<> Message, bool isExprBasic) {
513
513
UnresolvedDeclRefExpr *Operator;
514
514
515
515
// First check to see if we have the start of a regex literal `/.../`.
516
- tryLexRegexLiteral (/* mustBeRegex */ true );
516
+ tryLexRegexLiteral (/* forUnappliedOperator */ false );
517
517
518
518
switch (Tok.getKind ()) {
519
519
default :
@@ -880,56 +880,64 @@ UnresolvedDeclRefExpr *Parser::parseExprOperator() {
880
880
return new (Context) UnresolvedDeclRefExpr (name, refKind, DeclNameLoc (loc));
881
881
}
882
882
883
- void Parser::tryLexRegexLiteral (bool mustBeRegex ) {
883
+ void Parser::tryLexRegexLiteral (bool forUnappliedOperator ) {
884
884
if (!Context.LangOpts .EnableBareSlashRegexLiterals )
885
885
return ;
886
886
887
887
// Check to see if we have a regex literal `/.../`, optionally with a prefix
888
888
// operator e.g `!/.../`.
889
+ bool mustBeRegex = false ;
889
890
switch (Tok.getKind ()) {
890
891
case tok::oper_prefix:
892
+ // Prefix operators may contain `/` characters, so this may not be a regex,
893
+ // and as such need to make sure we have a closing `/`.
894
+ break ;
891
895
case tok::oper_binary_spaced:
892
- case tok::oper_binary_unspaced: {
893
- // Check to see if we have an operator containing '/'.
894
- auto slashIdx = Tok.getText ().find (" /" );
895
- if (slashIdx == StringRef::npos)
896
- break ;
896
+ case tok::oper_binary_unspaced:
897
+ // When re-lexing for a unary expression, binary operators are always
898
+ // invalid, so we can be confident in always lexing a regex literal.
899
+ mustBeRegex = !forUnappliedOperator;
900
+ break ;
901
+ default :
902
+ // We only re-lex regex literals for operator tokens.
903
+ return ;
904
+ }
897
905
898
- CancellableBacktrackingScope backtrack (*this );
899
- {
900
- Optional<Lexer::ForwardSlashRegexRAII> regexScope;
901
- regexScope.emplace (*L, mustBeRegex);
902
-
903
- // Try re-lex as a `/.../` regex literal, this will split an operator if
904
- // necessary.
905
- L->restoreState (getParserPosition ().LS , /* enableDiagnostics*/ true );
906
-
907
- // If we didn't split a prefix operator, reset the regex lexing scope.
908
- // Otherwise, we want to keep it in place for the next token.
909
- auto didSplit = L->peekNextToken ().getLength () == slashIdx;
910
- if (!didSplit)
911
- regexScope.reset ();
912
-
913
- // Discard the current token, which will be replaced by the re-lexed
914
- // token, which will either be a regex literal token, a prefix operator,
915
- // or the original unchanged token.
916
- discardToken ();
917
-
918
- // If we split a prefix operator from the regex literal, and are not sure
919
- // whether this should be a regex, backtrack if we didn't end up lexing a
920
- // regex literal.
921
- if (didSplit && !mustBeRegex &&
922
- !L->peekNextToken ().is (tok::regex_literal)) {
923
- return ;
924
- }
906
+ // Check to see if we have an operator containing '/'.
907
+ auto slashIdx = Tok.getText ().find (" /" );
908
+ if (slashIdx == StringRef::npos)
909
+ return ;
910
+
911
+ CancellableBacktrackingScope backtrack (*this );
912
+ {
913
+ Optional<Lexer::ForwardSlashRegexRAII> regexScope;
914
+ regexScope.emplace (*L, mustBeRegex);
925
915
926
- // Otherwise, accept the result.
927
- backtrack.cancelBacktrack ();
916
+ // Try re-lex as a `/.../` regex literal, this will split an operator if
917
+ // necessary.
918
+ L->restoreState (getParserPosition ().LS , /* enableDiagnostics*/ true );
919
+
920
+ // If we didn't split a prefix operator, reset the regex lexing scope.
921
+ // Otherwise, we want to keep it in place for the next token.
922
+ auto didSplit = L->peekNextToken ().getLength () == slashIdx;
923
+ if (!didSplit)
924
+ regexScope.reset ();
925
+
926
+ // Discard the current token, which will be replaced by the re-lexed
927
+ // token, which will either be a regex literal token, a prefix operator,
928
+ // or the original unchanged token.
929
+ discardToken ();
930
+
931
+ // If we split a prefix operator from the regex literal, and are not sure
932
+ // whether this should be a regex, backtrack if we didn't end up lexing a
933
+ // regex literal.
934
+ if (didSplit && !mustBeRegex &&
935
+ !L->peekNextToken ().is (tok::regex_literal)) {
936
+ return ;
928
937
}
929
- break ;
930
- }
931
- default :
932
- break ;
938
+
939
+ // Otherwise, accept the result.
940
+ backtrack.cancelBacktrack ();
933
941
}
934
942
}
935
943
@@ -3223,17 +3231,23 @@ ParserStatus Parser::parseExprList(tok leftTok, tok rightTok,
3223
3231
SourceLoc FieldNameLoc;
3224
3232
parseOptionalArgumentLabel (FieldName, FieldNameLoc);
3225
3233
3226
- // First check to see if we have the start of a regex literal `/.../`. We
3227
- // need to do this before handling unapplied operator references, as e.g
3228
- // `(/, /)` might be a regex literal.
3229
- tryLexRegexLiteral (/* mustBeRegex*/ false );
3230
-
3231
3234
// See if we have an operator decl ref '(<op>)'. The operator token in
3232
3235
// this case lexes as a binary operator because it neither leads nor
3233
3236
// follows a proper subexpression.
3237
+ auto isUnappliedOperator = [&]() {
3238
+ return Tok.isBinaryOperator () && peekToken ().isAny (rightTok, tok::comma);
3239
+ };
3240
+
3241
+ if (isUnappliedOperator ()) {
3242
+ // Check to see if we have the start of a regex literal `/.../`. We need
3243
+ // to do this for an unapplied operator reference, as e.g `(/, /)` might
3244
+ // be a regex literal.
3245
+ tryLexRegexLiteral (/* forUnappliedOperator*/ true );
3246
+ }
3247
+
3234
3248
ParserStatus Status;
3235
3249
Expr *SubExpr = nullptr ;
3236
- if (Tok. isBinaryOperator () && peekToken (). isAny (rightTok, tok::comma )) {
3250
+ if (isUnappliedOperator ( )) {
3237
3251
SyntaxParsingContext operatorContext (SyntaxContext,
3238
3252
SyntaxKind::IdentifierExpr);
3239
3253
DeclNameLoc Loc;
0 commit comments