Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revert "Fix parsing interpolated strings with unmatched braces" #14759

Merged
merged 1 commit into from
Feb 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 6 additions & 18 deletions src/Compiler/lex.fsl
Original file line number Diff line number Diff line change
Expand Up @@ -601,9 +601,7 @@ rule token args skip = parse
// Single quote in triple quote ok, others disallowed
match args.stringNest with
| (_, LexerStringStyle.TripleQuote, _) :: _ -> ()
| _ :: rest ->
args.stringNest <- rest
errorR(Error(FSComp.SR.lexSingleQuoteInSingleQuote(), m))
| _ :: _ -> errorR(Error(FSComp.SR.lexSingleQuoteInSingleQuote(), m))
| [] -> ()

if not skip then STRING_TEXT (LexCont.String(args.ifdefStack, args.stringNest, LexerStringStyle.SingleQuote, LexerStringKind.String, m))
Expand All @@ -614,9 +612,7 @@ rule token args skip = parse

// Single quote in triple quote ok, others disallowed
match args.stringNest with
| _ :: rest ->
args.stringNest <- rest
errorR(Error(FSComp.SR.lexTripleQuoteInTripleQuote(), m))
| _ :: _ -> errorR(Error(FSComp.SR.lexTripleQuoteInTripleQuote(), m))
| [] -> ()

if not skip then STRING_TEXT (LexCont.String(args.ifdefStack, args.stringNest, LexerStringStyle.TripleQuote, LexerStringKind.InterpolatedStringFirst, m))
Expand All @@ -628,9 +624,7 @@ rule token args skip = parse
// Single quote in triple quote ok, others disallowed
match args.stringNest with
| (_, LexerStringStyle.TripleQuote, _) :: _ -> ()
| _ :: rest ->
args.stringNest <- rest
errorR(Error(FSComp.SR.lexSingleQuoteInSingleQuote(), m))
| _ :: _ -> errorR(Error(FSComp.SR.lexSingleQuoteInSingleQuote(), m))
| _ -> ()

if not skip then STRING_TEXT (LexCont.String(args.ifdefStack, args.stringNest, LexerStringStyle.SingleQuote, LexerStringKind.InterpolatedStringFirst, m))
Expand All @@ -641,9 +635,7 @@ rule token args skip = parse

// Single quote in triple quote ok, others disallowed
match args.stringNest with
| _ :: rest ->
args.stringNest <- rest
errorR(Error(FSComp.SR.lexTripleQuoteInTripleQuote(), m))
| _ :: _ -> errorR(Error(FSComp.SR.lexTripleQuoteInTripleQuote(), m))
| _ -> ()

if not skip then STRING_TEXT (LexCont.String(args.ifdefStack, args.stringNest, LexerStringStyle.TripleQuote, LexerStringKind.String, m))
Expand All @@ -655,9 +647,7 @@ rule token args skip = parse
// Single quote in triple quote ok, others disallowed
match args.stringNest with
| (_, LexerStringStyle.TripleQuote, _) :: _ -> ()
| _ :: rest ->
args.stringNest <- rest
errorR(Error(FSComp.SR.lexSingleQuoteInSingleQuote(), m))
| _ :: _ -> errorR(Error(FSComp.SR.lexSingleQuoteInSingleQuote(), m))
| _ -> ()

if not skip then STRING_TEXT (LexCont.String(args.ifdefStack, args.stringNest, LexerStringStyle.Verbatim, LexerStringKind.String, m))
Expand All @@ -669,9 +659,7 @@ rule token args skip = parse
// Single quote in triple quote ok, others disallowed
match args.stringNest with
| (_, LexerStringStyle.TripleQuote, _) :: _ -> ()
| _ :: rest ->
args.stringNest <- rest
errorR(Error(FSComp.SR.lexSingleQuoteInSingleQuote(), m))
| _ :: _ -> errorR(Error(FSComp.SR.lexSingleQuoteInSingleQuote(), m))
| _ -> ()

if not skip then STRING_TEXT (LexCont.String(args.ifdefStack, args.stringNest, LexerStringStyle.Verbatim, LexerStringKind.InterpolatedStringFirst, m))
Expand Down
135 changes: 63 additions & 72 deletions tests/fsharp/Compiler/Language/StringInterpolation.fs
Original file line number Diff line number Diff line change
Expand Up @@ -730,50 +730,70 @@ let x3 : FormattableString = $"one %10s{String.Empty}" // no %10s in Formattable
(FSharpDiagnosticSeverity.Error, 3376, (6, 30, 6, 55),
"Invalid interpolated string. Interpolated strings used as type IFormattable or type FormattableString may not use '%' specifiers, only .NET-style interpolands such as '{expr}', '{expr,3}' or '{expr:N5}' may be used.")|]

[<TestCase("""let s1 = $"123{456}789{""", "\"012\"", "}345\"")>]
[<TestCase("""let s2 = $"123{456}789{""", "@\"012\"", "}345\"")>]
[<TestCase("""let s3 = $"123{456}789{""", "$\"012\"", "}345\"")>]
[<TestCase("""let s4 = $@"123{456}789{""", "\"012\"", "}345\"")>]
[<TestCase("""let s5 = @$"123{456}789{""", "\"012\"", "}345\"")>]
[<TestCase("""let s6 = $@"123{456}789{""", "@\"012\"", "}345\"")>]
[<TestCase("""let s7 = @$"123{456}789{""", "$\"012\"", "}345\"")>]
[<TestCase("""let s8 = $@"123{456}789{""", "@$\"012\"", "}345\"")>]
[<TestCase("""let s9 = @$"123{456}789{""", "$@\"012\"", "}345\"")>]
let ``String interpolation negative nested in single`` ((part1: string, expr: string, part2: string)) =
let code = part1 + expr + part2
let exprPosBegin = 1 + part1.Length
let quotePosInExpr = exprPosBegin + (expr |> Seq.findIndex (fun c -> c = '"'))
let closingBracePos = exprPosBegin + expr.Length
CompilerAssert.TypeCheckWithErrorsAndOptions [| "--langversion:5.0" |]

[<Test>]
let ``String interpolation negative nested in single`` () =
let code = """

open System
let s1 = $"123{456}789{"012"}345"
let s2 = $"123{456}789{@"012"}345"
let s3 = $"123{456}789{$"012"}345"
let s4 = $@"123{456}789{"012"}345"
let s5 = @$"123{456}789{"012"}345"
let s6 = $@"123{456}789{@"012"}345"
let s7 = @$"123{456}789{$"012"}345"
let s8 = $@"123{456}789{@$"012"}345"
let s9 = @$"123{456}789{$@"012"}345"
"""
CompilerAssert.TypeCheckWithErrorsAndOptions [| "--langversion:5.0" |]
code
[|(FSharpDiagnosticSeverity.Error, 3373, (1, exprPosBegin, 1, quotePosInExpr + 1),
"Invalid interpolated string. Single quote or verbatim string literals may not be used in interpolated expressions in single quote or verbatim strings. \
Consider using an explicit 'let' binding for the interpolation expression or use a triple quote string as the outer string literal.");
(FSharpDiagnosticSeverity.Error, 10, (1, closingBracePos, 1, closingBracePos + 1),
"Unexpected symbol '}' in binding. Expected interpolated string (final part), interpolated string (part) or other token.");
(FSharpDiagnosticSeverity.Error, 514, (1, code.Length, 1, code.Length + 1), "End of file in string begun at or before here")|]

[<TestCase("let TripleInTripleInterpolated = $\"\"\"123{456}789{", "\"\"\"012\"\"\"", "}345\"\"\"")>]
[<TestCase("let TripleInSingleInterpolated = $\"123{456}789{", "\"\"\"012\"\"\"", "}345\"\"\"")>]
[<TestCase("let TripleInVerbatimInterpolated = @$\"123{456}789{", "\"\"\"012\"\"\"", "}345\"\"\"")>]
[<TestCase("let TripleInterpolatedInTripleInterpolated = $\"\"\"123{456}789{", "$\"\"\"012\"\"\"", "}345\"\"\"")>]
[<TestCase("let TripleInterpolatedInSingleInterpolated = $\"123{456}789{", "$\"\"\"012\"\"\"", "}345\"\"\"")>]
[<TestCase("let TripleInterpolatedInVerbatimInterpolated = @$\"123{456}789{", "$\"\"\"012\"\"\"", "}345\"\"\"")>]
let ``String interpolation negative nested in triple`` ((part1: string, expr: string, part2: string)) =
let code = part1 + expr + part2
let exprPosBegin = 1 + part1.Length
let exprOpenQuoteEnd = exprPosBegin + 3 + (expr |> Seq.takeWhile (fun c -> c <> '"') |> Seq.length)
let closingBracePos = exprPosBegin + expr.Length
let closingQuotePos = code.Length + 1 - 3
[|(FSharpDiagnosticSeverity.Error, 3373, (4, 24, 4, 25),
"Invalid interpolated string. Single quote or verbatim string literals may not be used in interpolated expressions in single quote or verbatim strings. Consider using an explicit 'let' binding for the interpolation expression or use a triple quote string as the outer string literal.");
(FSharpDiagnosticSeverity.Error, 3373, (5, 24, 5, 26),
"Invalid interpolated string. Single quote or verbatim string literals may not be used in interpolated expressions in single quote or verbatim strings. Consider using an explicit 'let' binding for the interpolation expression or use a triple quote string as the outer string literal.");
(FSharpDiagnosticSeverity.Error, 3373, (6, 24, 6, 26),
"Invalid interpolated string. Single quote or verbatim string literals may not be used in interpolated expressions in single quote or verbatim strings. Consider using an explicit 'let' binding for the interpolation expression or use a triple quote string as the outer string literal.");
(FSharpDiagnosticSeverity.Error, 3373, (7, 25, 7, 26),
"Invalid interpolated string. Single quote or verbatim string literals may not be used in interpolated expressions in single quote or verbatim strings. Consider using an explicit 'let' binding for the interpolation expression or use a triple quote string as the outer string literal.");
(FSharpDiagnosticSeverity.Error, 3373, (8, 25, 8, 26),
"Invalid interpolated string. Single quote or verbatim string literals may not be used in interpolated expressions in single quote or verbatim strings. Consider using an explicit 'let' binding for the interpolation expression or use a triple quote string as the outer string literal.");
(FSharpDiagnosticSeverity.Error, 3373, (9, 25, 9, 27),
"Invalid interpolated string. Single quote or verbatim string literals may not be used in interpolated expressions in single quote or verbatim strings. Consider using an explicit 'let' binding for the interpolation expression or use a triple quote string as the outer string literal.");
(FSharpDiagnosticSeverity.Error, 3373, (10, 25, 10, 27),
"Invalid interpolated string. Single quote or verbatim string literals may not be used in interpolated expressions in single quote or verbatim strings. Consider using an explicit 'let' binding for the interpolation expression or use a triple quote string as the outer string literal.");
(FSharpDiagnosticSeverity.Error, 3373, (11, 25, 11, 28),
"Invalid interpolated string. Single quote or verbatim string literals may not be used in interpolated expressions in single quote or verbatim strings. Consider using an explicit 'let' binding for the interpolation expression or use a triple quote string as the outer string literal.");
(FSharpDiagnosticSeverity.Error, 3373, (12, 25, 12, 28),
"Invalid interpolated string. Single quote or verbatim string literals may not be used in interpolated expressions in single quote or verbatim strings. Consider using an explicit 'let' binding for the interpolation expression or use a triple quote string as the outer string literal.")|]

[<Test>]
let ``String interpolation negative nested in triple`` () =
let code = "

open System
let TripleInTripleInterpolated = $\"\"\"123{456}789{\"\"\"012\"\"\"}345\"\"\"
let TripleInSingleInterpolated = $\"123{456}789{\"\"\"012\"\"\"}345\"
let TripleInVerbatimInterpolated = $\"123{456}789{\"\"\"012\"\"\"}345\"
let TripleInterpolatedInTripleInterpolated = $\"\"\"123{456}789{$\"\"\"012\"\"\"}345\"\"\"
let TripleInterpolatedInSingleInterpolated = $\"123{456}789{$\"\"\"012\"\"\"}345\"
let TripleInterpolatedInVerbatimInterpolated = $\"123{456}789{$\"\"\"012\"\"\"}345\"
"
CompilerAssert.TypeCheckWithErrorsAndOptions [| "--langversion:5.0" |]
code
[|(FSharpDiagnosticSeverity.Error, 3374, (1, exprPosBegin, 1, exprOpenQuoteEnd),
[|(FSharpDiagnosticSeverity.Error, 3374, (4, 52, 4, 55),
"Invalid interpolated string. Triple quote string literals may not be used in interpolated expressions. Consider using an explicit 'let' binding for the interpolation expression.");
(FSharpDiagnosticSeverity.Error, 10, (1, closingBracePos, 1, closingBracePos + 1),
"Unexpected symbol '}' in binding. Expected interpolated string (final part), interpolated string (part) or other token.");
(FSharpDiagnosticSeverity.Error, 1232, (1, closingQuotePos, 1, closingQuotePos + 3),
"End of file in triple-quote string begun at or before here")|]

(FSharpDiagnosticSeverity.Error, 3374, (5, 50, 5, 53),
"Invalid interpolated string. Triple quote string literals may not be used in interpolated expressions. Consider using an explicit 'let' binding for the interpolation expression.");
(FSharpDiagnosticSeverity.Error, 3374, (6, 50, 6, 53),
"Invalid interpolated string. Triple quote string literals may not be used in interpolated expressions. Consider using an explicit 'let' binding for the interpolation expression.");
(FSharpDiagnosticSeverity.Error, 3374, (7, 64, 7, 68),
"Invalid interpolated string. Triple quote string literals may not be used in interpolated expressions. Consider using an explicit 'let' binding for the interpolation expression.");
(FSharpDiagnosticSeverity.Error, 3374, (8, 62, 8, 66),
"Invalid interpolated string. Triple quote string literals may not be used in interpolated expressions. Consider using an explicit 'let' binding for the interpolation expression.");
(FSharpDiagnosticSeverity.Error, 3374, (9, 62, 9, 66),
"Invalid interpolated string. Triple quote string literals may not be used in interpolated expressions. Consider using an explicit 'let' binding for the interpolation expression.")|]

[<Test>]
let ``String interpolation negative incomplete string`` () =
let code = """let x1 = $"one %d{System.String.Empty}"""
Expand All @@ -783,46 +803,17 @@ let x3 : FormattableString = $"one %10s{String.Empty}" // no %10s in Formattable
"Incomplete structured construct at or before this point in binding. Expected interpolated string (final part), interpolated string (part) or other token.");
(FSharpDiagnosticSeverity.Error, 3379, (1, 38, 1, 39),
"Incomplete interpolated string begun at or before here")|]

[<Test>]
let ``String interpolation negative incomplete string with incomplete fill`` () =
let ``String interpolation negative incomplete string fill`` () =
let code = """let x1 = $"one %d{System.String.Empty"""
CompilerAssert.TypeCheckWithErrorsAndOptions [| "--langversion:5.0" |]
code
[|(FSharpDiagnosticSeverity.Error, 10, (1, 1, 1, 38),
"Incomplete structured construct at or before this point in binding. Expected interpolated string (final part), interpolated string (part) or other token.");
(FSharpDiagnosticSeverity.Error, 3378, (1, 18, 1, 19),
"Incomplete interpolated string expression fill begun at or before here")|]

[<Test>]
let ``String interpolation negative incomplete fill`` () =
let code = "let x1 = $\"one %d{System.String.Empty\""
CompilerAssert.TypeCheckWithErrorsAndOptions [| "--langversion:5.0" |]
code
[|(FSharpDiagnosticSeverity.Error, 3373, (1, 38, 1, 39),
"Invalid interpolated string. Single quote or verbatim string literals may not be used in interpolated expressions in single quote or verbatim strings. \
Consider using an explicit 'let' binding for the interpolation expression or use a triple quote string as the outer string literal.");
(FSharpDiagnosticSeverity.Error, 10, (1, 1, 1, 39),
"Incomplete structured construct at or before this point in binding. Expected interpolated string (final part), interpolated string (part) or other token.");
(FSharpDiagnosticSeverity.Error, 514, (1, 38, 1, 39),
"End of file in string begun at or before here")|]

[<Test>]
let ``String interpolation negative incomplete fill with another valid string`` () =
let code = """
let x1 = $"one %d{System.String.Empty"
let x2 = "any old string"
"""
CompilerAssert.TypeCheckWithErrorsAndOptions [| "--langversion:5.0" |]
code
[|(FSharpDiagnosticSeverity.Error, 3373, (2, 38, 2, 39),
"Invalid interpolated string. Single quote or verbatim string literals may not be used in interpolated expressions in single quote or verbatim strings. \
Consider using an explicit 'let' binding for the interpolation expression or use a triple quote string as the outer string literal.");
(FSharpDiagnosticSeverity.Error, 10, (4, 1, 4, 1),
"Incomplete structured construct at or before this point in binding. Expected interpolated string (final part), interpolated string (part) or other token.");
(FSharpDiagnosticSeverity.Error, 514, (3, 25, 3, 26),
"End of file in string begun at or before here")|]


[<Test>]
let ``String interpolation negative incomplete verbatim string`` () =
let code = """let x1 = @$"one %d{System.String.Empty} """
Expand Down