diff --git a/paket.dependencies b/paket.dependencies index a7da0baade..1141c0c0a6 100644 --- a/paket.dependencies +++ b/paket.dependencies @@ -3,8 +3,8 @@ source https://api.nuget.org/v3/index.json framework: netstandard2.0, net5.0, netcoreapp3.1 storage: none -nuget FSharp.Core 5.0.3-beta.21352.5 -nuget FSharp.Compiler.Service 40.0.1-preview.21352.5 +nuget FSharp.Core 6.0.0-beta.21472.3 +nuget FSharp.Compiler.Service 41.0.0-preview.21472.3 nuget FsUnit nuget FsCheck nuget Microsoft.NET.Test.Sdk 16.9.1 @@ -38,7 +38,7 @@ group tool storage: none source https://api.nuget.org/v3/index.json - nuget FSharp.Core 5.0.3-beta.21352.5 + nuget FSharp.Core 6.0.0-beta.21472.3 nuget Argu nuget StreamJsonRpc nuget Thoth.Json.Net diff --git a/paket.lock b/paket.lock index 5ce47e7299..e4f039db5b 100644 --- a/paket.lock +++ b/paket.lock @@ -26,8 +26,8 @@ NUGET editorconfig (0.12.2) FsCheck (2.16.3) FSharp.Core (>= 4.2.3) - FSharp.Compiler.Service (40.0.1-preview.21352.5) - FSharp.Core (5.0.3-beta.21352.5) + FSharp.Compiler.Service (41.0.0-preview.21472.3) + FSharp.Core (6.0.0-beta.21472.3) Microsoft.Build.Framework (>= 16.9) Microsoft.Build.Tasks.Core (>= 16.9) Microsoft.Build.Utilities.Core (>= 16.9) @@ -39,7 +39,7 @@ NUGET System.Linq.Queryable (>= 4.3) System.Memory (>= 4.5.4) System.Net.Requests (>= 4.3) - System.Net.Security (>= 4.3) + System.Net.Security (>= 4.3.1) System.Reflection.Emit (>= 4.3) System.Reflection.Metadata (>= 5.0) System.Reflection.TypeExtensions (>= 4.3) @@ -53,7 +53,7 @@ NUGET System.Threading.Tasks.Parallel (>= 4.3) System.Threading.Thread (>= 4.3) System.Threading.ThreadPool (>= 4.3) - FSharp.Core (5.0.3-beta.21352.5) + FSharp.Core (6.0.0-beta.21472.3) FsUnit (4.0.4) FSharp.Core (>= 4.3.4) NETStandard.Library (>= 2.0.3) @@ -1799,7 +1799,7 @@ NUGET System.Configuration.ConfigurationManager (>= 4.4) - restriction: >= netstandard2.0 Fable.Core (3.4) - restriction: && (< net46) (>= netstandard2.0) FSharp.Core (>= 4.7.2) - restriction: >= netstandard2.0 - FSharp.Core (5.0.3-beta.21352.5) + FSharp.Core (6.0.0-beta.21472.3) MessagePack (2.3.85) - restriction: >= netstandard2.0 MessagePack.Annotations (>= 2.3.85) - restriction: >= netstandard2.0 Microsoft.Bcl.AsyncInterfaces (>= 1.0) - restriction: || (&& (>= netcoreapp2.1) (< netcoreapp3.1)) (&& (< netcoreapp2.1) (>= netstandard2.0)) diff --git a/src/Fantomas.Tests/AttributeTests.fs b/src/Fantomas.Tests/AttributeTests.fs index 352358c69c..90a3d67e34 100644 --- a/src/Fantomas.Tests/AttributeTests.fs +++ b/src/Fantomas.Tests/AttributeTests.fs @@ -724,7 +724,7 @@ type RoleAdminImportController(akkaService: AkkaService) = importer.ApiMaster ] diff --git a/src/Fantomas.Tests/BlankLinesAroundNestedMultilineExpressions.fs b/src/Fantomas.Tests/BlankLinesAroundNestedMultilineExpressions.fs index 9b2f3f628a..a39eacfbc6 100644 --- a/src/Fantomas.Tests/BlankLinesAroundNestedMultilineExpressions.fs +++ b/src/Fantomas.Tests/BlankLinesAroundNestedMultilineExpressions.fs @@ -239,7 +239,7 @@ let comp = """ let comp = eventually { - for x in 1 .. 2 do + for x in 1..2 do printfn " x = %d" x return 3 + 4 } diff --git a/src/Fantomas.Tests/ClassTests.fs b/src/Fantomas.Tests/ClassTests.fs index 150e63f4c1..c30f7d81db 100644 --- a/src/Fantomas.Tests/ClassTests.fs +++ b/src/Fantomas.Tests/ClassTests.fs @@ -294,14 +294,14 @@ type MyClassBase2(x: int) = let mutable z = x * x do - for i in 1 .. z do + for i in 1..z do printf "%d " i type MyClassDerived2(y: int) = inherit MyClassBase2(y * 2) do - for i in 1 .. y do + for i in 1..y do printf "%d " i """ diff --git a/src/Fantomas.Tests/ComputationExpressionTests.fs b/src/Fantomas.Tests/ComputationExpressionTests.fs index 8776952142..5a5e1d9caf 100644 --- a/src/Fantomas.Tests/ComputationExpressionTests.fs +++ b/src/Fantomas.Tests/ComputationExpressionTests.fs @@ -55,7 +55,7 @@ let comp = """ let comp = eventually { - for x in 1 .. 2 do + for x in 1..2 do printfn " x = %d" x return 3 + 4 @@ -84,8 +84,8 @@ let rec inorder tree = |> should equal """ -let s1 = seq { for i in 1 .. 10 -> i * i } -let s2 = seq { 0 .. 10 .. 100 } +let s1 = seq { for i in 1..10 -> i * i } +let s2 = seq { 0..10..100 } let rec inorder tree = seq { @@ -152,8 +152,8 @@ let y = async { |> should equal """ -let x = { 3 .. 7 } -let y = async { return { 0 .. 1 } } +let x = { 3..7 } +let y = async { return { 0..1 } } """ [] @@ -185,7 +185,7 @@ let ``multiple and! is supported`` () = false """ // Reads the values of x, y and z concurrently, then applies f to them -parallel { +``parallel`` { let! x = slowRequestX() and! y = slowRequestY() and! z = slowRequestZ() @@ -1109,9 +1109,9 @@ let squaresAndCubes = |> should equal """ -let squares = seq { for i in 1 .. 3 -> i * i } +let squares = seq { for i in 1..3 -> i * i } -let cubes = seq { for i in 1 .. 3 -> i * i * i } +let cubes = seq { for i in 1..3 -> i * i * i } let squaresAndCubes = seq { @@ -1623,7 +1623,7 @@ let rec loop () = newEvents |> function | Ok events -> eventStore.Append events - | Error err -> async { return Error err} + | Error err -> async {return Error err} do reply.Reply result diff --git a/src/Fantomas.Tests/ControlStructureTests.fs b/src/Fantomas.Tests/ControlStructureTests.fs index 01c9669764..bcc0977bc5 100644 --- a/src/Fantomas.Tests/ControlStructureTests.fs +++ b/src/Fantomas.Tests/ControlStructureTests.fs @@ -196,7 +196,7 @@ let ``range expressions`` () = equal """ let function2 () = - for i in 1 .. 2 .. 10 do + for i in 1..2..10 do printf "%d " i printfn "" @@ -557,7 +557,7 @@ for _ in 1..10 do () |> should equal """ -for _ in 1 .. 10 do +for _ in 1..10 do () """ diff --git a/src/Fantomas.Tests/DisableElmishTests.fs b/src/Fantomas.Tests/DisableElmishTests.fs index c73b1f5ced..65acc2751b 100644 --- a/src/Fantomas.Tests/DisableElmishTests.fs +++ b/src/Fantomas.Tests/DisableElmishTests.fs @@ -206,9 +206,9 @@ let counter = Html.div [ Html.button - [ prop.style [ style.marginRight 5 ] - prop.onClick (fun _ -> setCount (count + 1)) - prop.text "Increment" ] + [ prop.style [ style.marginRight 5 ] + prop.onClick (fun _ -> setCount (count + 1)) + prop.text "Increment" ] Html.button [ prop.style [ style.marginLeft 5 ] prop.onClick (fun _ -> setCount (count - 1)) diff --git a/src/Fantomas.Tests/ElmishTests.fs b/src/Fantomas.Tests/ElmishTests.fs index 602819ab37..a9b377616e 100644 --- a/src/Fantomas.Tests/ElmishTests.fs +++ b/src/Fantomas.Tests/ElmishTests.fs @@ -115,10 +115,10 @@ let loginPage = View.StackLayout( children = [ View.Entry( - placeholder = "User name", - isEnabled = (not model.IsSigningIn), - textChanged = - (fun args -> (dispatch (UserNameChanged args.NewTextValue))) + placeholder = "User name", + isEnabled = (not model.IsSigningIn), + textChanged = + (fun args -> (dispatch (UserNameChanged args.NewTextValue))) ) View.Entry( placeholder = "Password", diff --git a/src/Fantomas.Tests/Fantomas.Tests.fsproj b/src/Fantomas.Tests/Fantomas.Tests.fsproj index e22fb32ba0..7eb4630a05 100644 --- a/src/Fantomas.Tests/Fantomas.Tests.fsproj +++ b/src/Fantomas.Tests/Fantomas.Tests.fsproj @@ -38,7 +38,6 @@ - @@ -90,6 +89,7 @@ + diff --git a/src/Fantomas.Tests/FormatAstTests.fs b/src/Fantomas.Tests/FormatAstTests.fs index 94434ead85..fe7d504b11 100644 --- a/src/Fantomas.Tests/FormatAstTests.fs +++ b/src/Fantomas.Tests/FormatAstTests.fs @@ -48,7 +48,7 @@ let ``let in should not be used`` () = ()""" [] -let ``elif keyword is not present in raw AST`` () = +let ``elif keyword is present in raw AST`` () = let source = """ if a then () @@ -59,7 +59,7 @@ let ``elif keyword is not present in raw AST`` () = |> should equal """if a then () -else if b then () +elif b then () else ()""" /// There is no dead code in this test diff --git a/src/Fantomas.Tests/IfThenElseTests.fs b/src/Fantomas.Tests/IfThenElseTests.fs index 3126e35f44..846c305731 100644 --- a/src/Fantomas.Tests/IfThenElseTests.fs +++ b/src/Fantomas.Tests/IfThenElseTests.fs @@ -1367,7 +1367,7 @@ let a = elif trimmed.StartsWith("#endif") then defines.Add(processLine "#endif" trimmed lineNumber offset) - for idx in [ 0 .. lastIndex ] do + for idx in [ 0..lastIndex ] do let zero = sourceCode.[idx] let plusOne = sourceCode.[idx + 1] let plusTwo = sourceCode.[idx + 2] diff --git a/src/Fantomas.Tests/IndexSyntaxTests.fs b/src/Fantomas.Tests/IndexSyntaxTests.fs new file mode 100644 index 0000000000..c2ce62da4b --- /dev/null +++ b/src/Fantomas.Tests/IndexSyntaxTests.fs @@ -0,0 +1,101 @@ +module Fantomas.Tests.IndexSyntaxTests + +open NUnit.Framework +open FsUnit +open Fantomas.Tests.TestHelper + +[] +let ``don't convert index syntax without dot to application`` () = + formatSourceString + false + """ +expr1[expr2] +""" + config + |> prepend newline + |> should + equal + """ +expr1[expr2] +""" + +[] +let ``slicing examples`` () = + formatSourceString + false + """ +let arr = [| 1;2;3 |] +arr[0] <- 2 +arr[0] +arr[0..1] +arr[..1] +arr[0..] +""" + config + |> prepend newline + |> should + equal + """ +let arr = [| 1; 2; 3 |] +arr[0] <- 2 +arr[0] +arr[0..1] +arr[..1] +arr[0..] +""" + +[] +let ``higher-dimensional arrays`` () = + formatSourceString + false + """ +let arr = Array4D.create 3 4 5 6 0 +arr[0,2,3,4] <- 2 +arr[0,2,3,4] +""" + config + |> prepend newline + |> should + equal + """ +let arr = Array4D.create 3 4 5 6 0 +arr[0, 2, 3, 4] <- 2 +arr[0, 2, 3, 4] +""" + +[] +let ``only add spaces when expressions are atomic`` () = + formatSourceString + false + """ +let a = [ 2 .. 7 ] // integers +let b = [ one .. two ] // identifiers +let c = [ .. 9 ] // also when there is only one expression +let d = [ 0.7 .. 9.2 ] // doubles +let e = [ 2L .. number / 2L ] // complex expression +let f = [| A.B .. C.D |] // identifiers with dots +let g = [ .. (39 - 3) ] // complex expression +let h = [| 1 .. MyModule.SomeConst |] // not all expressions are atomic +for x in 1 .. 2 do + printfn " x = %d" x +let s = seq { 0..10..100 } +""" + config + |> prepend newline + |> should + equal + """ +let a = [ 2..7 ] // integers +let b = [ one..two ] // identifiers +let c = [ ..9 ] // also when there is only one expression +let d = [ 0.7 .. 9.2 ] // doubles +let e = [ 2L .. number / 2L ] // complex expression +let f = [| A.B .. C.D |] // identifiers with dots +let g = [ .. (39 - 3) ] // complex expression +let h = [| 1 .. MyModule.SomeConst |] // not all expressions are atomic + +for x in 1..2 do + printfn " x = %d" x + +let s = seq { 0..10..100 } +""" diff --git a/src/Fantomas.Tests/InterpolatedStringTests.fs b/src/Fantomas.Tests/InterpolatedStringTests.fs index 29f04da691..ca3970cb6b 100644 --- a/src/Fantomas.Tests/InterpolatedStringTests.fs +++ b/src/Fantomas.Tests/InterpolatedStringTests.fs @@ -104,7 +104,7 @@ let str = {let square x = x * x let isOdd x = x % 2 <> 0 let oddSquares = List.filter isOdd >> List.map square - oddSquares [ 1 .. 0 ]}\"\"\" + oddSquares [ 1..0 ]}\"\"\" " [] diff --git a/src/Fantomas.Tests/KeepIndentInBranchTests.fs b/src/Fantomas.Tests/KeepIndentInBranchTests.fs index 89bdab1de8..b7f798ef34 100644 --- a/src/Fantomas.Tests/KeepIndentInBranchTests.fs +++ b/src/Fantomas.Tests/KeepIndentInBranchTests.fs @@ -2072,7 +2072,7 @@ module Foo = let assertConsistent () : unit = if veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLong then () - elif foo = bar then + else if foo = bar then () else diff --git a/src/Fantomas.Tests/LetBindingTests.fs b/src/Fantomas.Tests/LetBindingTests.fs index af8566d75e..5c58cf37c3 100644 --- a/src/Fantomas.Tests/LetBindingTests.fs +++ b/src/Fantomas.Tests/LetBindingTests.fs @@ -140,7 +140,7 @@ let x = equal """ let x = - [| 1 .. 2 |] + [| 1..2 |] |> Array.mapi (fun _ _ -> let num = "".PadLeft(9) num) diff --git a/src/Fantomas.Tests/ListTests.fs b/src/Fantomas.Tests/ListTests.fs index 274b622894..3c44e72c28 100644 --- a/src/Fantomas.Tests/ListTests.fs +++ b/src/Fantomas.Tests/ListTests.fs @@ -27,6 +27,21 @@ array2.[..3, ..1] array1.[1] <- 3 """ +[] +let ``index range`` () = + formatSourceString + false + """ +let v = 1 .. 2 +""" + config + |> prepend newline + |> should + equal + """ +let v = 1..2 +""" + [] let ``array values`` () = formatSourceString @@ -147,8 +162,8 @@ let list0to3 = [0 .. 3]""" |> should equal """ -let listOfSquares = [ for i in 1 .. 10 -> i * i ] -let list0to3 = [ 0 .. 3 ] +let listOfSquares = [ for i in 1..10 -> i * i ] +let list0to3 = [ 0..3 ] """ [] @@ -164,11 +179,11 @@ let a3 = [| for n in 1 .. 100 do if isPrime n then yield n |]""" |> should equal """ -let a1 = [| for i in 1 .. 10 -> i * i |] -let a2 = [| 0 .. 99 |] +let a1 = [| for i in 1..10 -> i * i |] +let a2 = [| 0..99 |] let a3 = - [| for n in 1 .. 100 do + [| for n in 1..100 do if isPrime n then yield n |] """ @@ -385,8 +400,8 @@ let ``line comment inside list`` () = equal """ [7 -// foo -] + // foo + ] """ [] @@ -403,8 +418,8 @@ let ``line comment inside array`` () = equal """ [| 7 -// foo - |] + // foo + |] """ #if RELEASE @@ -1778,21 +1793,21 @@ let emptyString = s.[-2..(-1)] |> should equal """ -let l = [ 1 .. 10 ] -let a = [| 1 .. 10 |] +let l = [ 1..10 ] +let a = [| 1..10 |] let s = "hello!" // Before: would return empty list // F# 5: same -let emptyList = l.[-2..(-1)] +let emptyList = l.[-2 .. (-1)] // Before: would throw exception // F# 5: returns empty array -let emptyArray = a.[-2..(-1)] +let emptyArray = a.[-2 .. (-1)] // Before: would throw exception // F# 5: returns empty string -let emptyString = s.[-2..(-1)] +let emptyString = s.[-2 .. (-1)] """ [] @@ -2246,8 +2261,8 @@ let fns = let fns = [ { x = "long enough to not go to one line" y = 5 } - // { name = fn "String" "endsWith" 0 - // deprecated = NotDeprecated } - // I think the space at the start of the lines above matter - ] + // { name = fn "String" "endsWith" 0 + // deprecated = NotDeprecated } + // I think the space at the start of the lines above matter + ] """ diff --git a/src/Fantomas.Tests/MultilineBlockBracketsOnSameColumnArrayOrListTests.fs b/src/Fantomas.Tests/MultilineBlockBracketsOnSameColumnArrayOrListTests.fs index 24ebf84686..4b99e5ec4e 100644 --- a/src/Fantomas.Tests/MultilineBlockBracketsOnSameColumnArrayOrListTests.fs +++ b/src/Fantomas.Tests/MultilineBlockBracketsOnSameColumnArrayOrListTests.fs @@ -110,11 +110,11 @@ let a2 = [| for n in 1 .. 100 do if isPrime n then yield n |]""" |> should equal """ -let a1 = [| 0 .. 99 |] +let a1 = [| 0..99 |] let a2 = [| - for n in 1 .. 100 do + for n in 1..100 do if isPrime n then yield n |] """ diff --git a/src/Fantomas.Tests/NumberOfItemsListOrArrayTests.fs b/src/Fantomas.Tests/NumberOfItemsListOrArrayTests.fs index b4ee1230da..88125cb462 100644 --- a/src/Fantomas.Tests/NumberOfItemsListOrArrayTests.fs +++ b/src/Fantomas.Tests/NumberOfItemsListOrArrayTests.fs @@ -135,9 +135,7 @@ let xs = ] let ys = - [ - AReallyLongExpressionThatIsMuchLongerThan50Characters - ] + [ AReallyLongExpressionThatIsMuchLongerThan50Characters ] f xs @@ -180,9 +178,7 @@ let xs = |] let ys = - [| - AReallyLongExpressionThatIsMuchLongerThan50Characters - |] + [| AReallyLongExpressionThatIsMuchLongerThan50Characters |] f xs @@ -226,9 +222,7 @@ f [ z ] -g [ - longValueThatIsALotOfCharactersSoooooLong - ] [ +g [ longValueThatIsALotOfCharactersSoooooLong ] [ longValueThatIsALotOfCharactersSoooooLong ] diff --git a/src/Fantomas.Tests/OperatorTests.fs b/src/Fantomas.Tests/OperatorTests.fs index d4db9ca4b0..e3f561e626 100644 --- a/src/Fantomas.Tests/OperatorTests.fs +++ b/src/Fantomas.Tests/OperatorTests.fs @@ -298,20 +298,20 @@ let ``should not add newline before = operator after |>`` () = """ [] -let ``should add space around .. operator`` () = +let ``should not add space around .. operator`` () = formatSourceString false """[1..10]""" config |> should equal - """[ 1 .. 10 ] + """[ 1..10 ] """ [] -let ``should add space around .. .. operators`` () = +let ``should not add space around .. .. operators`` () = formatSourceString false """[10 .. -1 .. 1]""" config |> should equal - """[ 10 .. -1 .. 1 ] + """[ 10..-1..1 ] """ [] @@ -1185,8 +1185,7 @@ let ``list concat chain using operators, 1188`` () = |> should equal """ -[ 1 .. 86 ] -@ [ 89 .. 699 ] @ [ 901 .. 912 ] @ [ 988 ] +[ 1..86 ] @ [ 89..699 ] @ [ 901..912 ] @ [ 988 ] """ [] diff --git a/src/Fantomas.Tests/PatternMatchingTests.fs b/src/Fantomas.Tests/PatternMatchingTests.fs index ee6012abac..5cefe0d6b6 100644 --- a/src/Fantomas.Tests/PatternMatchingTests.fs +++ b/src/Fantomas.Tests/PatternMatchingTests.fs @@ -1273,6 +1273,7 @@ let private formatResponse<'options> () = } """ +[] [] let ``match inside match expression, 1400`` () = formatSourceString @@ -1303,6 +1304,7 @@ match | _ -> failwith "" """ +[] [] let ``match bang inside match expression`` () = formatSourceString @@ -1333,6 +1335,7 @@ match | _ -> failwith "" """ +[] [] let ``match inside match bang expression`` () = formatSourceString @@ -1363,6 +1366,7 @@ match! | _ -> failwith "" """ +[] [] let ``match bang inside match bang expression`` () = formatSourceString diff --git a/src/Fantomas.Tests/RecordTests.fs b/src/Fantomas.Tests/RecordTests.fs index 16b22e71b4..7a8ba5781f 100644 --- a/src/Fantomas.Tests/RecordTests.fs +++ b/src/Fantomas.Tests/RecordTests.fs @@ -718,8 +718,8 @@ let expect = Result.Ok { opts = [ Opts.anyOf ( - [ (Optional, Opt.flagTrue [ "first"; "f" ]) - (Optional, Opt.value [ "second"; "s" ]) ] + [ (Optional, Opt.flagTrue [ "first"; "f" ]) + (Optional, Opt.value [ "second"; "s" ]) ] ) Opts.oneOf ( Optional, diff --git a/src/Fantomas.Tests/TokenParserTests.fs b/src/Fantomas.Tests/TokenParserTests.fs index f5c718e55a..e3fdd6144f 100644 --- a/src/Fantomas.Tests/TokenParserTests.fs +++ b/src/Fantomas.Tests/TokenParserTests.fs @@ -294,21 +294,6 @@ type T() = | [ { Item = Newline; Range = rAbove } ] -> rAbove.StartLine == 1 | _ -> fail () -[] -let ``if keyword should be found in tokens`` () = - let source = - """if true then () -elif true then ()""" - - let triviaNodes = tokenize source |> getTriviaFromTokens - - match triviaNodes with - | [ { Item = Keyword { Content = "if" } } - { Item = Keyword { Content = "then" } } - { Item = Keyword { Content = "elif" } } - { Item = Keyword { Content = "then" } } ] -> pass () - | _ -> fail () - [] let ``directives are found in tokens`` () = let source = diff --git a/src/Fantomas.Tests/TriviaTests.fs b/src/Fantomas.Tests/TriviaTests.fs index 5ec4ad4ac3..c394bf519a 100644 --- a/src/Fantomas.Tests/TriviaTests.fs +++ b/src/Fantomas.Tests/TriviaTests.fs @@ -281,25 +281,6 @@ MEH | [ { ContentBefore = [ Comment (BlockComment (c, _, true)) ] } ] -> c == (String.normalizeNewLine comment) | _ -> failwith "Expected block comment" -[] -let ``if keyword before SynExpr.IfThenElse`` () = - let source = - """if true then () -elif true then ()""" - - let triviaNodes = toTrivia source |> List.head - - match triviaNodes with - | [ { Type = Token (IF, _) - ContentItself = Some (Keyword { Content = "if" }) } - { Type = Token (THEN, _) - ContentItself = Some (Keyword { Content = "then" }) } - { Type = Token (ELIF, _) - ContentItself = Some (Keyword { Content = "elif" }) } - { Type = Token (THEN, _) - ContentItself = Some (Keyword { Content = "then" }) } ] -> pass () - | _ -> fail () - [] let ``directives before and after are linked to let binding`` () = let source = @@ -403,19 +384,6 @@ let foo = 42 ContentAfter = [ Directive "#if SOMETHING\n\n#endif" ] } ] -> pass () | _ -> fail () - -[] -let ``if keyword should be keyword itself`` () = - let source = "if meh then ()" - let trivia = toTrivia source |> List.head - - match trivia with - | [ { ContentItself = Some (Keyword { TokenInfo = { TokenName = "IF" } }) - Type = TriviaNodeType.Token (IF, _) } - { ContentItself = Some (Keyword { TokenInfo = { TokenName = "THEN" } }) - Type = TriviaNodeType.Token (THEN, _) } ] -> pass () - | _ -> fail () - [] let ``string constant with blank lines`` () = let multilineString = @@ -463,7 +431,7 @@ let ``char content`` () = match trivia with | [ { ContentItself = Some (CharContent "\'\\u0000\'") Type = TriviaNodeType.MainNode SynConst_Char } ] -> pass () - | _ -> fail () + | _ -> Assert.Fail(sprintf "Unexpected trivia: %A" trivia) [] let ``leading newlines should not be captured as trivia`` () = diff --git a/src/Fantomas.Tests/TypeDeclarationTests.fs b/src/Fantomas.Tests/TypeDeclarationTests.fs index 4ab86693fa..ecab1dd4c5 100644 --- a/src/Fantomas.Tests/TypeDeclarationTests.fs +++ b/src/Fantomas.Tests/TypeDeclarationTests.fs @@ -500,7 +500,7 @@ type SparseMatrix() = let matrix1 = new SparseMatrix() -for i in 1 .. 1000 do +for i in 1..1000 do matrix1.[i, i] <- float i * float i """ diff --git a/src/Fantomas.Tests/UnionTests.fs b/src/Fantomas.Tests/UnionTests.fs index 8ee8d52a97..819253bbc0 100644 --- a/src/Fantomas.Tests/UnionTests.fs +++ b/src/Fantomas.Tests/UnionTests.fs @@ -702,7 +702,7 @@ type CardValue = | King static member allWithKnight = [ - for n in 1 .. 10 do + for n in 1..10 do yield Basic n yield Jack yield Knight diff --git a/src/Fantomas.Tests/ValidationTests.fs b/src/Fantomas.Tests/ValidationTests.fs index 061a2f1f1a..028c1506de 100644 --- a/src/Fantomas.Tests/ValidationTests.fs +++ b/src/Fantomas.Tests/ValidationTests.fs @@ -5,13 +5,13 @@ open FsUnit open Fantomas.Tests.TestHelper [] -let ``naked ranges are invalid outside for..in.do`` () = +let ``naked ranges are valid outside for..in.do`` () = isValidFSharpCode false """ let factors number = 2L..number / 2L |> Seq.filter (fun x -> number % x = 0L)""" - |> should equal false + |> should equal true [] let ``misplaced comments should give parser errors`` () = diff --git a/src/Fantomas.Tests/VerboseSyntaxConversionTests.fs b/src/Fantomas.Tests/VerboseSyntaxConversionTests.fs deleted file mode 100644 index bf3f74daf9..0000000000 --- a/src/Fantomas.Tests/VerboseSyntaxConversionTests.fs +++ /dev/null @@ -1,32 +0,0 @@ -module Fantomas.Tests.VerboseSyntaxConversionTests - -open NUnit.Framework -open FsUnit -open Fantomas.Tests.TestHelper - -[] -let ``verbose syntax`` () = - formatSourceString - false - """ - #light "off" - - let div2 = 2;; - - let f x = - let r = x % div2 in - if r = 1 then - begin "Odd" end - else - begin "Even" end - """ - config - |> prepend newline - |> should - equal - """ -let div2 = 2 - -let f x = - let r = x % div2 in if r = 1 then ("Odd") else ("Even") -""" diff --git a/src/Fantomas/AstTransformer.fs b/src/Fantomas/AstTransformer.fs index 12a00e4cab..aa70095ca0 100644 --- a/src/Fantomas/AstTransformer.fs +++ b/src/Fantomas/AstTransformer.fs @@ -192,19 +192,22 @@ module private Ast = |> finalContinuation Continuation.sequence continuations finalContinuation - | SynExpr.ArrayOrListOfSeqExpr (_, expr, range) -> + | SynExpr.ArrayOrListComputed (_, expr, range) -> visit expr (fun nodes -> - mkNode SynExpr_ArrayOrListOfSeqExpr range :: nodes + mkNode SynExpr_ArrayOrListComputed range :: nodes |> finalContinuation) - | SynExpr.CompExpr (_, _, expr, _) -> visit expr finalContinuation - | SynExpr.Lambda (_, _, args, body, _parsedData, range) -> + | SynExpr.ComputationExpr (_, expr, _) -> visit expr finalContinuation + | SynExpr.Lambda (_, _, args, arrowRange, body, _parsedData, range) -> visit body (fun nodes -> [ yield mkNode SynExpr_Lambda range yield! visitSynSimplePats args + yield! + (Option.toList arrowRange + |> List.map (mkNode SynExpr_Lambda_Arrow)) yield! nodes ] |> finalContinuation) | SynExpr.MatchLambda (_, keywordRange, matchClauses, _, range) -> @@ -297,10 +300,12 @@ module private Ast = Continuation.sequence continuations finalContinuation // don't collect nested elif expression as nodes. // the ranges are often incorrect and using the else if or elif token is more reliable. - | SourceParser.ElIf ((ifExpr, thenExpr, _, range, _) :: es, elseExpr) -> + | SourceParser.ElIf ((_leadingElseKw, ifKw, isElif, ifExpr, thenKw, thenExpr) :: es, + (elseKw, elseExpr), + range) -> let elifs = es - |> List.collect (fun (e1, e2, _, _, _) -> [ visit e1; visit e2 ]) + |> List.collect (fun (_, _, _, e1, _, e2) -> [ visit e1; visit e2 ]) let continuations: ((TriviaNodeAssigner list -> TriviaNodeAssigner list) -> TriviaNodeAssigner list) list = [ yield visit ifExpr @@ -309,21 +314,60 @@ module private Ast = yield! (Option.toList elseExpr |> List.map visit) ] let finalContinuation (nodes: TriviaNodeAssigner list list) : TriviaNodeAssigner list = - mkNode SynExpr_IfThenElse range - :: (List.collect id nodes) + let elseNode elseKw = + Option.map (mkNode SynExpr_IfThenElse_Else) elseKw + |> Option.toList + + let elifKeywords = + es + |> List.collect + (fun (elseKw, ifKw, isElif, _, thenKw, _) -> + [ yield! elseNode elseKw + yield + mkNode + (if isElif then + SynExpr_IfThenElse_Elif + else + SynExpr_IfThenElse_If) + ifKw + yield mkNode SynExpr_IfThenElse_Then thenKw ]) + + [ yield mkNode SynExpr_IfThenElse range + yield + mkNode + (if isElif then + SynExpr_IfThenElse_Elif + else + SynExpr_IfThenElse_If) + ifKw + yield mkNode SynExpr_IfThenElse_Then thenKw + yield! elifKeywords + yield! elseNode elseKw + yield! (List.collect id nodes) ] |> finalContinuation Continuation.sequence continuations finalContinuation - | SynExpr.IfThenElse (ifExpr, thenExpr, elseExpr, _, _, _, range) -> + | SynExpr.IfThenElse (ifKw, isElif, ifExpr, thenKw, thenExpr, elseKw, elseExpr, _, _, _, range) -> let continuations: ((TriviaNodeAssigner list -> TriviaNodeAssigner list) -> TriviaNodeAssigner list) list = [ yield visit ifExpr yield visit thenExpr yield! (Option.toList elseExpr |> List.map visit) ] let finalContinuation (nodes: TriviaNodeAssigner list list) : TriviaNodeAssigner list = - mkNode SynExpr_IfThenElse range - :: (List.collect id nodes) + [ yield mkNode SynExpr_IfThenElse range + yield + mkNode + (if isElif then + SynExpr_IfThenElse_Elif + else + SynExpr_IfThenElse_If) + ifKw + yield mkNode SynExpr_IfThenElse_Then thenKw + yield! + (Option.map (mkNode SynExpr_IfThenElse_Else) elseKw + |> Option.toList) + yield! (List.collect id nodes) ] |> finalContinuation Continuation.sequence continuations finalContinuation @@ -370,22 +414,22 @@ module private Ast = |> finalContinuation Continuation.sequence continuations finalContinuation - | SynExpr.DotIndexedGet (objectExpr, indexExprs, _, range) -> + | SynExpr.DotIndexedGet (objectExpr, indexArgs, _, range) -> visit objectExpr (fun nodes -> [ yield mkNode SynExpr_DotIndexedGet range yield! nodes - yield! indexExprs |> List.collect visitSynIndexerArg ] + yield! visitSynExpr indexArgs ] |> finalContinuation) - | SynExpr.DotIndexedSet (objectExpr, indexExprs, valueExpr, _, _, range) -> + | SynExpr.DotIndexedSet (objectExpr, indexArgs, valueExpr, _, _, range) -> let continuations: ((TriviaNodeAssigner list -> TriviaNodeAssigner list) -> TriviaNodeAssigner list) list = [ visit objectExpr; visit valueExpr ] let finalContinuation (nodes: TriviaNodeAssigner list list) : TriviaNodeAssigner list = [ yield mkNode SynExpr_DotIndexedSet range yield! (List.collect id nodes) - yield! indexExprs |> List.collect visitSynIndexerArg ] + yield! visitSynExpr indexArgs ] |> finalContinuation Continuation.sequence continuations finalContinuation @@ -571,6 +615,14 @@ module private Ast = mkNode SynExpr_InterpolatedString range :: (List.collect visitSynInterpolatedStringPart parts) |> finalContinuation + | SynExpr.IndexRange (e1, _, e2, _, _, range) -> + [ yield mkNode SynExpr_IndexRange range + yield! (e1 |> Option.toList |> List.collect visitSynExpr) + yield! (e2 |> Option.toList |> List.collect visitSynExpr) ] + |> finalContinuation + | SynExpr.IndexFromEnd (e, range) -> + [ yield mkNode SynExpr_IndexFromEnd range + yield! visitSynExpr e ] visit synExpr id @@ -611,18 +663,16 @@ module private Ast = mkNode SynMemberSig_NestedType range :: (visitSynTypeDefnSig typedef) - and visitSynIndexerArg (ia: SynIndexerArg) : TriviaNodeAssigner list = - match ia with - | SynIndexerArg.One (e, _fromEnd, _) -> visitSynExpr e - | SynIndexerArg.Two (e1, _fromEnd1, e2, _fromEnd2, _, _) -> visitSynExpr e1 @ visitSynExpr e2 - and visitSynMatchClause (mc: SynMatchClause) : TriviaNodeAssigner list = match mc with - | SynMatchClause (pat, e1, e2, _range, _) -> + | SynMatchClause (pat, e1, arrowRange, e2, _range, _) -> mkNode SynMatchClause_ mc.Range // _range is the same range as pat, see https://github.com/dotnet/fsharp/issues/10877 :: [ yield! visitSynPat pat if e1.IsSome then yield! visitSynExpr e1.Value + yield! + (Option.toList arrowRange + |> List.map (mkNode SynMatchClause_Arrow)) yield! visitSynExpr e2 ] and visitArgsOption (expr: SynExpr, _: Ident option) = visitSynExpr expr diff --git a/src/Fantomas/CodeFormatterImpl.fs b/src/Fantomas/CodeFormatterImpl.fs index 568073a8da..a0b92ab7b7 100644 --- a/src/Fantomas/CodeFormatterImpl.fs +++ b/src/Fantomas/CodeFormatterImpl.fs @@ -23,7 +23,8 @@ let sharedChecker = lazy (FSharpChecker.Create()) let createParsingOptionsFromFile fileName = { FSharpParsingOptions.Default with SourceFiles = [| fileName |] - IsExe = true } + IsExe = true + LangVersionText = "preview" } let private getSourceString (source: SourceOrigin) = match source with @@ -88,13 +89,6 @@ let parse (checker: FSharpChecker) (parsingOptions: FSharpParsingOptions) { File /// Check whether an AST consists of parsing errors let isValidAST ast = - let (|IndexerArg|) = - function - | SynIndexerArg.Two (e1, _, e2, _, _, _) -> [ e1; e2 ] - | SynIndexerArg.One (e, _, _) -> [ e ] - - let (|IndexerArgList|) xs = List.collect (|IndexerArg|) xs - let rec validateImplFileInput (SourceParser.ParsedImplFileInput (_, moduleOrNamespaceList)) = List.forall validateModuleOrNamespace moduleOrNamespaceList @@ -175,7 +169,7 @@ let isValidAST ast = = validateExpr expr && validatePattern headPat - and validateClause (Clause (pat, expr, exprOpt)) = + and validateClause (Clause (pat, exprOpt, _, expr)) = validatePattern pat && validateExpr expr && defaultArg (Option.map validateExpr exprOpt) true @@ -209,9 +203,9 @@ let isValidAST ast = | SynExpr.For (_sequencePointInfoForForLoop, _ident, synExpr1, _, synExpr2, synExpr3, _range) -> List.forall validateExpr [ synExpr1; synExpr2; synExpr3 ] - | SynExpr.ArrayOrListOfSeqExpr (_, synExpr, _range) -> validateExpr synExpr - | SynExpr.CompExpr (_, _, synExpr, _range) -> validateExpr synExpr - | SynExpr.Lambda (_, _, _synSimplePats, synExpr, _parsedData, _range) -> validateExpr synExpr + | SynExpr.ArrayOrListComputed (_, synExpr, _range) -> validateExpr synExpr + | SynExpr.ComputationExpr (_, synExpr, _range) -> validateExpr synExpr + | SynExpr.Lambda (_, _, _synSimplePats, _arrow, synExpr, _parsedData, _range) -> validateExpr synExpr | SynExpr.MatchLambda (_isExnMatch, _argm, synMatchClauseList, _spBind, _wholem) -> List.forall validateClause synMatchClauseList @@ -250,7 +244,17 @@ let isValidAST ast = | SynExpr.SequentialOrImplicitYield (_sequencePointInfoForSeq, synExpr1, synExpr2, _, _range) -> List.forall validateExpr [ synExpr1; synExpr2 ] - | SynExpr.IfThenElse (synExpr1, synExpr2, synExprOpt, _sequencePointInfoForBinding, _isRecovery, _range, _range2) -> + | SynExpr.IfThenElse (_, + _, + synExpr1, + _, + synExpr2, + _, + synExprOpt, + _sequencePointInfoForBinding, + _isRecovery, + _range, + _range2) -> match synExprOpt with | Some synExpr3 -> List.forall validateExpr [ synExpr1; synExpr2; synExpr3 ] | None -> List.forall validateExpr [ synExpr1; synExpr2 ] @@ -264,14 +268,10 @@ let isValidAST ast = | SynExpr.DotSet (synExpr1, _, synExpr2, _) | SynExpr.Set (synExpr1, synExpr2, _) -> List.forall validateExpr [ synExpr1; synExpr2 ] - | SynExpr.DotIndexedGet (synExpr, IndexerArgList synExprList, _range, _range2) -> - validateExpr synExpr - && List.forall validateExpr synExprList + | SynExpr.DotIndexedGet (synExpr, indexArgs, _range, _range2) -> validateExpr synExpr && validateExpr indexArgs - | SynExpr.DotIndexedSet (synExpr1, IndexerArgList synExprList, synExpr2, _, _range, _range2) -> - [ yield synExpr1 - yield! synExprList - yield synExpr2 ] + | SynExpr.DotIndexedSet (synExpr1, indexArgs, synExpr2, _, _range, _range2) -> + [ synExpr1; indexArgs; synExpr2 ] |> List.forall validateExpr | SynExpr.JoinIn (synExpr1, _range, synExpr2, _range2) -> List.forall validateExpr [ synExpr1; synExpr2 ] @@ -319,6 +319,10 @@ let isValidAST ast = (function | SynInterpolatedStringPart.String _ -> true | SynInterpolatedStringPart.FillExpr (e, _) -> validateExpr e) + | SynExpr.IndexRange (e1, _, e2, _, _, _) -> + defaultArg (Option.map validateExpr e1) true + && defaultArg (Option.map validateExpr e2) true + | SynExpr.IndexFromEnd (e, _) -> validateExpr e and validatePattern = function diff --git a/src/Fantomas/CodePrinter.fs b/src/Fantomas/CodePrinter.fs index af858b551a..512caccae5 100644 --- a/src/Fantomas/CodePrinter.fs +++ b/src/Fantomas/CodePrinter.fs @@ -1284,7 +1284,7 @@ and genExpr astContext synExpr ctx = +> sepOpenT +> genTuple astContext es +> sepCloseT - | ArrayOrList (isArray, [], _) -> + | ArrayOrList (isArray, []) -> ifElse isArray (enterNodeTokenByName synExpr.Range LBRACK_BAR @@ -1299,7 +1299,7 @@ and genExpr astContext synExpr ctx = +> enterNodeTokenByName synExpr.Range RBRACK +> sepCloseLFixed +> leaveNodeTokenByName synExpr.Range RBRACK) - | ArrayOrList (isArray, xs, _) as alNode -> + | ArrayOrList (isArray, xs) as alNode -> let tokenSize = if isArray then 2 else 1 let openingTokenRange = @@ -1433,24 +1433,54 @@ and genExpr astContext synExpr ctx = +> unindent) ) - | CompExpr (isArrayOrList, e) -> - ifElse - isArrayOrList - (genExpr astContext e) - // The opening { of the CompExpr is being added at the App(_,_,Ident(_),CompExr(_)) level + | NamedComputationExpr (nameExpr, bodyExpr, bodyRange) -> + fun ctx -> + let openingBrace = + ctx.MkRangeWith + (bodyRange.StartLine, bodyRange.StartColumn) + (bodyRange.StartLine, bodyRange.StartColumn + 1) + + let closingBrace = + ctx.MkRangeWith(bodyRange.EndLine, bodyRange.EndColumn - 1) (bodyRange.EndLine, bodyRange.EndColumn) + + let short = + genExpr astContext nameExpr + +> sepSpace + +> tokN openingBrace LBRACE sepOpenS + +> genExpr astContext bodyExpr + +> tokN closingBrace RBRACE sepCloseS + + let long = + genExpr astContext nameExpr + +> sepSpace + +> tokN openingBrace LBRACE sepOpenS + +> indent + +> sepNln + +> genExpr astContext bodyExpr + +> unindent + +> sepNln + +> tokN closingBrace RBRACE sepCloseSFixed + + expressionFitsOnRestOfLine short long ctx + | ComputationExpr (e, bodyRange) -> + fun ctx -> + let openingBrace = + ctx.MkRangeWith + (bodyRange.StartLine, bodyRange.StartColumn) + (bodyRange.StartLine, bodyRange.StartColumn + 1) + + let closingBrace = + ctx.MkRangeWith(bodyRange.EndLine, bodyRange.EndColumn - 1) (bodyRange.EndLine, bodyRange.EndColumn) + (expressionFitsOnRestOfLine - (genExpr astContext e +> sepCloseS) - (genExpr astContext e + (tokN openingBrace LBRACE sepOpenS + +> genExpr astContext e + +> tokN closingBrace RBRACE sepCloseS) + (tokN openingBrace LBRACE sepOpenS + +> genExpr astContext e +> unindent - +> (fun ctx -> - let closingBraceRange = - ctx.MkRangeWith - (synExpr.Range.EndLine, synExpr.Range.EndColumn - 1) - (synExpr.Range.EndLine, synExpr.Range.EndColumn) - - enterNodeTokenByName closingBraceRange RBRACE ctx) - +> sepNlnUnlessLastEventIsNewline - +> sepCloseSFixed)) + +> tokN closingBrace RBRACE (sepNlnUnlessLastEventIsNewline +> sepCloseSFixed))) + ctx | CompExprBody statements -> let genCompExprStatement astContext ces = @@ -1498,60 +1528,11 @@ and genExpr astContext synExpr ctx = ColMultilineItem(expr, sepNln)) |> colWithNlnWhenItemIsMultilineUsingConfig - | ArrayOrListOfSeqExpr (isArray, e) as alNode -> - let astContext = { astContext with IsNakedRange = true } - let tokenSize = if isArray then 2 else 1 - - let openingTokenRange = - ctx.MkRangeWith - (alNode.Range.Start.Line, alNode.Range.Start.Column) - (alNode.Range.Start.Line, (alNode.Range.Start.Column + tokenSize)) - - let closingTokenRange = - ctx.MkRangeWith - (alNode.Range.End.Line, (alNode.Range.End.Column - tokenSize)) - (alNode.Range.End.Line, alNode.Range.End.Column) - - - let shortExpression = - ifElse - isArray - ((tokN openingTokenRange LBRACK_BAR sepOpenA) - +> atCurrentColumnIndent (genExpr astContext e) - +> (tokN closingTokenRange BAR_RBRACK sepCloseA)) - ((tokN openingTokenRange LBRACK sepOpenL) - +> atCurrentColumnIndent (genExpr astContext e) - +> (tokN closingTokenRange RBRACK sepCloseL)) - - let bracketsOnSameColumn = - ifElse - isArray - (tokN openingTokenRange LBRACK_BAR sepOpenAFixed) - (tokN openingTokenRange LBRACK sepOpenLFixed) - +> indent - +> sepNln - +> genExpr astContext e - +> unindent - +> sepNln - +> ifElse - isArray - (tokN closingTokenRange BAR_RBRACK sepCloseAFixed) - (tokN closingTokenRange RBRACK sepCloseLFixed) - - let multilineExpression = - ifAlignBrackets bracketsOnSameColumn shortExpression - - fun ctx -> isShortExpression ctx.Config.MaxArrayOrListWidth shortExpression multilineExpression ctx - | JoinIn (e1, e2) -> genExpr astContext e1 -- " in " +> genExpr astContext e2 - | Paren (lpr, Lambda (pats, expr, lambdaRange), rpr, pr) -> + | Paren (lpr, Lambda (pats, arrowRange, expr, lambdaRange), rpr, pr) -> fun (ctx: Context) -> - let arrowRange = - List.last pats - |> fun lastPat -> ctx.MkRange lastPat.Range.End expr.Range.Start - let body = genExprKeepIndentInBranch astContext expr @@ -1568,7 +1549,7 @@ and genExpr astContext synExpr ctx = +> col sepSpace pats (genPat astContext) +> (fun ctx -> if not ctx.Config.MultiLineLambdaClosingNewline then - genArrowWithTrivia + genLambdaArrowWithTrivia (body +> triviaOfLambda printContentAfter +> sepNlnWhenWriteBeforeNewlineNotEmpty id @@ -1577,7 +1558,7 @@ and genExpr astContext synExpr ctx = ctx else leadingExpressionIsMultiline - (genArrowWithTrivia + (genLambdaArrowWithTrivia (body +> triviaOfLambda printContentAfter +> sepNlnWhenWriteBeforeNewlineNotEmpty id) @@ -1588,11 +1569,15 @@ and genExpr astContext synExpr ctx = expr ctx // When there are parentheses, most likely lambda will appear in function application - | Lambda (pats, expr, _range) -> + | Lambda (pats, arrowRange, expr, _range) -> atCurrentColumn ( !- "fun " +> col sepSpace pats (genPat astContext) - +> sepArrow + +> optSingle + (fun arrowRange -> + sepArrow + |> genTriviaFor SynExpr_Lambda_Arrow arrowRange) + arrowRange +> autoIndentAndNlnIfExpressionExceedsPageWidth (genExpr astContext expr) ) | MatchLambda (keywordRange, cs) -> @@ -2046,10 +2031,6 @@ and genExpr astContext synExpr ctx = | UppercaseSynExpr -> onlyIf ctx.Config.SpaceBeforeUppercaseInvocation sepSpace ctx | LowercaseSynExpr -> onlyIf ctx.Config.SpaceBeforeLowercaseInvocation sepSpace ctx - let arrowRange pats (bodyExpr: SynExpr) = - List.last pats - |> fun (lastPat: SynPat) -> ctx.MkRange lastPat.Range.End bodyExpr.Range.Start - let short = genExpr astContext e +> sepSpaceAfterFunctionName @@ -2057,10 +2038,14 @@ and genExpr astContext synExpr ctx = +> onlyIf (List.isNotEmpty es) sepSpace +> (sepOpenTFor lpr +> (match lambda with - | Choice1Of2 (pats, body, lambdaRange) -> + | Choice1Of2 (pats, arrowRange, body, lambdaRange) -> !- "fun " +> col sepSpace pats (genPat astContext) - +> tokN (arrowRange pats body) RARROW sepArrow + +> optSingle + (fun arrowRange -> + sepArrow + |> genTriviaFor SynExpr_Lambda_Arrow arrowRange) + arrowRange +> genExprKeepIndentInBranch astContext body |> genTriviaFor SynExpr_Lambda lambdaRange | Choice2Of2 (keywordRange, cs, range) -> @@ -2081,13 +2066,13 @@ and genExpr astContext synExpr ctx = match es with | [] -> match lambda with - | Choice1Of2 (pats, bodyExpr, range) -> + | Choice1Of2 (pats, arrowRange, bodyExpr, range) -> sepOpenTFor lpr +> (!- "fun " +> col sepSpace pats (genPat astContext) - +> genArrowWithTrivia + +> genLambdaArrowWithTrivia (genExprKeepIndentInBranch astContext bodyExpr) - (arrowRange pats bodyExpr) + arrowRange |> genTriviaFor SynExpr_Lambda range) +> sepNln +> sepCloseTFor rpr pr @@ -2110,8 +2095,16 @@ and genExpr astContext synExpr ctx = col sepNln es (genExpr astContext) +> sepNln +> (match lambda with - | Choice1Of2 (pats, bodyExpr, range) -> - genLambdaMultiLineClosingNewline astContext lpr pats bodyExpr range rpr pr + | Choice1Of2 (pats, arrowRange, bodyExpr, range) -> + genLambdaMultiLineClosingNewline + astContext + lpr + pats + arrowRange + bodyExpr + range + rpr + pr | Choice2Of2 (keywordRange, cs, matchLambdaRange) -> (sepOpenTFor lpr +> ((!- "function " @@ -2130,9 +2123,7 @@ and genExpr astContext synExpr ctx = ctx else match lambda with - | Choice1Of2 (pats, body, lambdaRange) -> - let arrowRange = arrowRange pats body - + | Choice1Of2 (pats, arrowRange, body, lambdaRange) -> let singleLineTestExpr = genExpr astContext e +> sepSpaceAfterFunctionName @@ -2143,7 +2134,11 @@ and genExpr astContext synExpr ctx = +> enterNodeFor SynExpr_Lambda lambdaRange +> !- "fun " +> col sepSpace pats (genPat astContext) - +> tokN arrowRange RARROW sepArrow + +> optSingle + (fun arrowRange -> + sepArrow + |> genTriviaFor SynExpr_Lambda_Arrow arrowRange) + arrowRange let singleLine = genExpr astContext e @@ -2153,7 +2148,7 @@ and genExpr astContext synExpr ctx = +> (sepOpenTFor lpr +> (!- "fun " +> col sepSpace pats (genPat astContext) - +> genArrowWithTrivia (genExprKeepIndentInBranch astContext body) arrowRange + +> genLambdaArrowWithTrivia (genExprKeepIndentInBranch astContext body) arrowRange |> genTriviaFor SynExpr_Lambda lambdaRange) +> sepNlnWhenWriteBeforeNewlineNotEmpty sepNone +> sepCloseTFor rpr pr @@ -2168,7 +2163,7 @@ and genExpr astContext synExpr ctx = +> (sepOpenTFor lpr +> (!- "fun " +> col sepSpace pats (genPat astContext) - +> genArrowWithTrivia (genExprKeepIndentInBranch astContext body) arrowRange + +> genLambdaArrowWithTrivia (genExprKeepIndentInBranch astContext body) arrowRange |> genTriviaFor SynExpr_Lambda lambdaRange) +> sepCloseTFor rpr pr |> genTriviaFor SynExpr_Paren pr) @@ -2233,6 +2228,12 @@ and genExpr astContext synExpr ctx = expressionFitsOnRestOfLine short long + | IndexWithoutDotExpr (identifierExpr, indexExpr) -> + genExpr astContext identifierExpr + +> sepOpenLFixed + +> genExpr astContext indexExpr + +> sepCloseLFixed + // Always spacing in multiple arguments | App (e, es) -> genApp astContext e es | TypeApp (e, lt, ts, gt) -> @@ -2281,7 +2282,6 @@ and genExpr astContext synExpr ctx = +> unindent ) - | SequentialSimple es | Sequentials es -> fun ctx -> let inKeywords = @@ -2292,187 +2292,154 @@ and genExpr astContext synExpr ctx = atCurrentColumn (colWithNlnWhenItemIsMultilineUsingConfig items) ctx // A generalization of IfThenElse - | ElIf ((e1, e2, _, _, _) :: es, enOpt) -> + | ElIf ((_, ifKw, isElif, e1, thenKw, e2) :: es, (elseKw, elseOpt), _) -> // https://docs.microsoft.com/en-us/dotnet/fsharp/style-guide/formatting#formatting-if-expressions - fun ctx -> - let elfis = - es - |> List.mapi - (fun idx (condition, body, _, _, fullIfThenElseExpr) -> - let endOfPreviousBranch = - if idx = 0 then - e2.Range.End - else - let _, e2, _, _, _ = es.[idx - 1] - e2.Range.End - - let maxRangeBetween = - ctx.MkRange endOfPreviousBranch body.Range.End - - let elifKeyword = - [ yield! Map.tryFindOrEmptyList ELSE ctx.TriviaTokenNodes - yield! Map.tryFindOrEmptyList ELIF ctx.TriviaTokenNodes ] - |> List.filter (fun tn -> RangeHelpers.``range contains`` maxRangeBetween tn.Range) - |> List.sortBy (fun tn -> tn.Range.StartLine, tn.Range.EndLine) - |> List.tryHead - - // This range spans from the elif keyword to the end of the body expression - let correctedRange = - match elifKeyword with - | Some { Range = range } -> ctx.MkRange range.Start body.Range.End - | _ -> fullIfThenElseExpr.Range - - let elifKeywordRange = - ctx.MkRange correctedRange.Start body.Range.Start - - let thenKeywordRange = - ctx.MkRange condition.Range.End body.Range.Start + let hasElfis = not (List.isEmpty es) + let hasElse = Option.isSome elseOpt + + let genIf ifKeywordRange isElif = + (ifElse isElif (!- "elif ") (!- "if ") + |> genTriviaFor + (if isElif then + SynExpr_IfThenElse_Elif + else + SynExpr_IfThenElse_If) + ifKeywordRange) + +> sepSpace - condition, body, elifKeywordRange, thenKeywordRange) + let genThen thenRange = + !- "then " + |> genTriviaFor SynExpr_IfThenElse_Then thenRange - let hasElfis = not (List.isEmpty elfis) - let hasElse = Option.isSome enOpt + let genElse elseRange = + !- "else " + |> genTriviaFor SynExpr_IfThenElse_Else elseRange - let genIf ifElseRange = - tokN ifElseRange IF (!- "if ") +> sepSpace + let genElifOneliner (elseKw, ifKw, isElif, e1, thenKw, e2) = + optSingle genElse elseKw + +> sepNlnWhenWriteBeforeNewlineNotEmpty sepSpace + +> genIf ifKw isElif + +> sepNlnWhenWriteBeforeNewlineNotEmpty sepSpace + +> genExpr astContext e1 + +> sepNlnWhenWriteBeforeNewlineNotEmpty sepSpace + +> genThen thenKw + +> sepNlnWhenWriteBeforeNewlineNotEmpty sepSpace + +> genExpr astContext e2 - let genThen ifElseRange = tokN ifElseRange THEN (!- "then ") - let genElse ifElseRange = tokN ifElseRange ELSE (!- "else ") + let genElifMultiLine (elseKw, ifKw, isElif, e1, thenKw, e2) = + optSingle genElse elseKw + +> sepNlnWhenWriteBeforeNewlineNotEmpty sepSpace + +> genIf ifKw isElif + +> autoIndentAndNlnWhenWriteBeforeNewlineNotEmpty (genExprInIfOrMatch astContext e1) + +> sepNlnWhenWriteBeforeNewlineNotEmpty sepSpace + +> genThen thenKw + +> indent + +> sepNln + +> genExpr astContext e2 + +> unindent - let genElifOneliner (elf1: SynExpr, elf2: SynExpr, elifKeywordRange, thenKeywordRange) = - TriviaContext.``else if / elif`` elifKeywordRange - +> sepNlnWhenWriteBeforeNewlineNotEmpty sepSpace - +> genExpr astContext elf1 - +> sepNlnWhenWriteBeforeNewlineNotEmpty sepSpace - +> genThen thenKeywordRange - +> sepNlnWhenWriteBeforeNewlineNotEmpty sepSpace - +> genExpr astContext elf2 + let genShortElse e elseRange = + optSingle + (fun e -> + sepSpace + +> optSingle genElse elseRange + +> genExpr astContext e) + e - let genElifMultiLine (elf1: SynExpr, elf2, elifKeywordRange, thenKeywordRange) = - (TriviaContext.``else if / elif`` elifKeywordRange) - +> autoIndentAndNlnWhenWriteBeforeNewlineNotEmpty (genExprInIfOrMatch astContext elf1) - +> sepNlnWhenWriteBeforeNewlineNotEmpty sepSpace - +> genThen thenKeywordRange - +> indent - +> sepNln - +> genExpr astContext elf2 - +> unindent + let genOneliner elseOpt = + genIf ifKw isElif + +> genExpr astContext e1 + +> sepNlnWhenWriteBeforeNewlineNotEmpty sepSpace + +> genThen thenKw + +> genExpr astContext e2 + +> genShortElse elseOpt elseKw - let genShortElse e elseRange = - optSingle - (fun e -> - sepSpace - +> genElse elseRange - +> genExpr astContext e) - e + let isIfThenElse = + function + | SynExpr.IfThenElse _ -> true + | _ -> false - let genOneliner enOpt = - genIf synExpr.Range - +> genExpr astContext e1 + let longIfThenElse = + genIf ifKw isElif + // f.ex. if // meh + // x + // bool expr x should be indented + +> autoIndentAndNlnWhenWriteBeforeNewlineNotEmpty ( + genExprInIfOrMatch astContext e1 +> sepNlnWhenWriteBeforeNewlineNotEmpty sepSpace - +> genThen synExpr.Range - +> genExpr astContext e2 - +> genShortElse enOpt synExpr.Range - - let isIfThenElse = - function - | SynExpr.IfThenElse _ -> true - | _ -> false - - let longIfThenElse = - genIf synExpr.Range - // f.ex. if // meh - // x - // bool expr x should be indented - +> autoIndentAndNlnWhenWriteBeforeNewlineNotEmpty ( - genExprInIfOrMatch astContext e1 - +> sepNlnWhenWriteBeforeNewlineNotEmpty sepSpace - ) - +> genThen synExpr.Range - +> indent - +> sepNln - +> genExpr astContext e2 - +> unindent - +> onlyIf (hasElfis || hasElse) sepNln - +> col sepNln elfis genElifMultiLine - +> opt - id - enOpt - (fun e4 -> - let correctedElseRange = - match List.tryLast elfis with - | Some (_, te, _, _) -> ctx.MkRange te.Range.End synExpr.Range.End - | None -> synExpr.Range - - onlyIf (List.isNotEmpty elfis) sepNln - +> genElse correctedElseRange - +> indent - +> sepNln - +> genExpr astContext e4 - +> unindent) - - let shortIfThenElif (ctx: Context) = - // Try and format if each conditional follow the one-liner rules - // Abort if something is too long - let shortCtx, isShort = - let elseExpr = - let elseRange = - List.last elfis - |> fun (_, b, _, _) -> ctx.MkRange b.Range.End synExpr.Range.End - - enOpt - |> Option.map (fun _ -> genShortElse enOpt elseRange) - |> Option.toList - - let exprs = - [ genOneliner None - yield! (List.map genElifOneliner elfis) - yield! elseExpr ] - - let lastIndex = List.length exprs - 1 - - exprs - |> List.indexed - |> List.fold - (fun (acc, allLinesShort) (idx, expr) -> - if allLinesShort then - let lastLine, lastColumn = - acc.WriterModel.Lines.Length, acc.Column - - let nextCtx = expr acc - - let currentLine, currentColumn = - nextCtx.WriterModel.Lines.Length, nextCtx.Column - - let isStillShort = - lastLine = currentLine - && (currentColumn - lastColumn - <= acc.Config.MaxIfThenElseShortWidth) - - (ifElse (lastIndex > idx) sepNln sepNone nextCtx, isStillShort) - else - ctx, false) - (ctx, true) - - if isShort then - shortCtx - else - longIfThenElse ctx + ) + +> genThen thenKw + +> indent + +> sepNln + +> genExpr astContext e2 + +> unindent + +> onlyIf (hasElfis || hasElse) sepNln + +> col sepNln es genElifMultiLine + +> opt + id + elseOpt + (fun e4 -> + onlyIf (List.isNotEmpty es) sepNln + +> optSingle genElse elseKw + +> indent + +> sepNln + +> genExpr astContext e4 + +> unindent) + + let shortIfThenElif (ctx: Context) = + // Try and format if each conditional follow the one-liner rules + // Abort if something is too long + let shortCtx, isShort = + let exprs = + [ yield genOneliner None + yield! (List.map genElifOneliner es) + yield! + (Option.map (fun _ -> genShortElse elseOpt elseKw) elseOpt + |> Option.toList) ] + + let lastIndex = List.length exprs - 1 + + exprs + |> List.indexed + |> List.fold + (fun (acc, allLinesShort) (idx, expr) -> + if allLinesShort then + let lastLine, lastColumn = + acc.WriterModel.Lines.Length, acc.Column + + let nextCtx = expr acc + + let currentLine, currentColumn = + nextCtx.WriterModel.Lines.Length, nextCtx.Column + + let isStillShort = + lastLine = currentLine + && (currentColumn - lastColumn + <= acc.Config.MaxIfThenElseShortWidth) + + (ifElse (lastIndex > idx) sepNln sepNone nextCtx, isStillShort) + else + ctx, false) + (ctx, true) - let expr = - if hasElfis && not (isIfThenElse e2) then - shortIfThenElif - elif isIfThenElse e2 then - // If branch expression is an if/then/else expressions. - // Always go with long version in this case - longIfThenElse - else - let shortExpression = genOneliner enOpt - let longExpression = longIfThenElse + if isShort then + shortCtx + else + longIfThenElse ctx - isShortExpression ctx.Config.MaxIfThenElseShortWidth shortExpression longExpression + let expr = + if hasElfis && not (isIfThenElse e2) then + shortIfThenElif + elif isIfThenElse e2 then + // If branch expression is an if/then/else expressions. + // Always go with long version in this case + longIfThenElse + else + let shortExpression = genOneliner elseOpt + let longExpression = longIfThenElse + (fun ctx -> isShortExpression ctx.Config.MaxIfThenElseShortWidth shortExpression longExpression ctx) - atCurrentColumnIndent expr ctx + atCurrentColumnIndent expr // At this stage, all symbolic operators have been handled. | OptVar (s, isOpt, ranges) -> @@ -2490,15 +2457,15 @@ and genExpr astContext synExpr ctx = | LongIdentSet (s, e, _) -> !-(sprintf "%s <- " s) +> autoIndentAndNlnIfExpressionExceedsPageWidth (genExpr astContext e) - | DotIndexedGet (App (e, [ ConstExpr (SynConst.Unit, _) as ux ]), es) -> + | DotIndexedGet (App (e, [ ConstExpr (SynConst.Unit, _) as ux ]), indexArgs) -> genExpr astContext e +> genExpr astContext ux +> !- "." +> sepOpenLFixed - +> genIndexers astContext es + +> genExpr astContext indexArgs +> sepCloseLFixed +> leaveNodeTokenByName synExpr.Range RBRACK - | DotIndexedGet (AppSingleParenArg (e, px), es) -> + | DotIndexedGet (AppSingleParenArg (e, px), indexArgs) -> let short = genExpr astContext e +> genExpr astContext px @@ -2509,35 +2476,36 @@ and genExpr astContext synExpr ctx = let idx = !- "." +> sepOpenLFixed - +> genIndexers astContext es + +> genExpr astContext indexArgs +> sepCloseLFixed +> leaveNodeTokenByName synExpr.Range RBRACK expressionFitsOnRestOfLine (short +> idx) (long +> idx) - | DotIndexedGet (e, es) -> - addParenIfAutoNln e (genExpr astContext) -- "." + | DotIndexedGet (objectExpr, indexArgs) -> + addParenIfAutoNln objectExpr (genExpr astContext) + -- "." +> sepOpenLFixed - +> genIndexers astContext es + +> genExpr astContext indexArgs +> sepCloseLFixed +> leaveNodeTokenByName synExpr.Range RBRACK - | DotIndexedSet (App (e, [ ConstExpr (SynConst.Unit, _) as ux ]), es, e2) -> + | DotIndexedSet (App (e, [ ConstExpr (SynConst.Unit, _) as ux ]), indexArgs, valueExpr) -> let appExpr = genExpr astContext e +> genExpr astContext ux let idx = !- "." +> sepOpenLFixed - +> genIndexers astContext es + +> genExpr astContext indexArgs +> sepCloseLFixed +> leaveNodeTokenByName synExpr.Range RBRACK +> sepArrowRev expressionFitsOnRestOfLine - (appExpr +> idx +> genExpr astContext e2) + (appExpr +> idx +> genExpr astContext valueExpr) (appExpr +> idx - +> autoIndentAndNlnIfExpressionExceedsPageWidth (genExpr astContext e2)) - | DotIndexedSet (AppSingleParenArg (a, px), es, e2) -> + +> autoIndentAndNlnIfExpressionExceedsPageWidth (genExpr astContext valueExpr)) + | DotIndexedSet (AppSingleParenArg (a, px), indexArgs, valueExpr) -> let short = genExpr astContext a +> genExpr astContext px @@ -2548,22 +2516,23 @@ and genExpr astContext synExpr ctx = let idx = !- "." +> sepOpenLFixed - +> genIndexers astContext es + +> genExpr astContext indexArgs +> sepCloseLFixed +> leaveNodeTokenByName synExpr.Range RBRACK +> sepArrowRev expressionFitsOnRestOfLine - (short +> idx +> genExpr astContext e2) + (short +> idx +> genExpr astContext valueExpr) (long +> idx - +> autoIndentAndNlnIfExpressionExceedsPageWidth (genExpr astContext e2)) + +> autoIndentAndNlnIfExpressionExceedsPageWidth (genExpr astContext valueExpr)) - | DotIndexedSet (e1, es, e2) -> - addParenIfAutoNln e1 (genExpr astContext) -- ".[" - +> genIndexers astContext es + | DotIndexedSet (objectExpr, indexArgs, valueExpr) -> + addParenIfAutoNln objectExpr (genExpr astContext) + -- ".[" + +> genExpr astContext indexArgs -- "] <- " - +> autoIndentAndNlnIfExpressionExceedsPageWidth (genExpr astContext e2) + +> autoIndentAndNlnIfExpressionExceedsPageWidth (genExpr astContext valueExpr) | NamedIndexedPropertySet (ident, e1, e2) -> !-ident +> genExpr astContext e1 -- " <- " +> autoIndentAndNlnIfExpressionExceedsPageWidth (genExpr astContext e2) @@ -2624,7 +2593,7 @@ and genExpr astContext synExpr ctx = r.EndLine (r.EndColumn + 1) ) - | SynExpr.InterpolatedString (parts, _stringKind, _) -> + | InterpolatedStringExpr (parts, _stringKind) -> // TODO: string kind fun (ctx: Context) -> let stringRanges = @@ -2701,6 +2670,27 @@ and genExpr astContext synExpr ctx = +> !- "\"" expr ctx + | IndexRangeExpr (None, None) -> !- "*" + | IndexRangeExpr (e1, e2) -> + let hasSpaces = + let rec (|AtomicExpr|_|) e = + match e with + | SynExpr.Ident _ + | SynExpr.Const (SynConst.Int32 _, _) + | IndexRangeExpr (Some (AtomicExpr _), Some (AtomicExpr _)) + | IndexFromEndExpr (AtomicExpr _) -> Some e + | _ -> None + + match e1, e2 with + | Some (AtomicExpr _), None + | None, Some (AtomicExpr _) + | Some (AtomicExpr _), Some (AtomicExpr _) -> false + | _ -> true + + optSingle (fun e -> genExpr astContext e +> onlyIf hasSpaces sepSpace) e1 + +> !- ".." + +> optSingle (fun e -> onlyIf hasSpaces sepSpace +> genExpr astContext e) e2 + | IndexFromEndExpr e -> !- "^" +> genExpr astContext e | e -> failwithf "Unexpected expression: %O" e |> (match synExpr with | SynExpr.App _ -> genTriviaFor SynExpr_App synExpr.Range @@ -2718,7 +2708,7 @@ and genExpr astContext synExpr ctx = | SynExpr.TryFinally _ -> genTriviaFor SynExpr_TryFinally synExpr.Range | SynExpr.LongIdentSet _ -> genTriviaFor SynExpr_LongIdentSet synExpr.Range | SynExpr.ArrayOrList _ -> genTriviaFor SynExpr_ArrayOrList synExpr.Range - | SynExpr.ArrayOrListOfSeqExpr _ -> genTriviaFor SynExpr_ArrayOrListOfSeqExpr synExpr.Range + | SynExpr.ArrayOrListComputed _ -> genTriviaFor SynExpr_ArrayOrListComputed synExpr.Range | SynExpr.Paren _ -> genTriviaFor SynExpr_Paren synExpr.Range | SynExpr.InterpolatedString _ -> genTriviaFor SynExpr_InterpolatedString synExpr.Range | SynExpr.Tuple _ -> genTriviaFor SynExpr_Tuple synExpr.Range @@ -2762,12 +2752,14 @@ and genExpr astContext synExpr ctx = | SynExpr.LibraryOnlyUnionCaseFieldSet _ -> genTriviaFor SynExpr_LibraryOnlyUnionCaseFieldSet synExpr.Range | SynExpr.SequentialOrImplicitYield _ -> genTriviaFor SynExpr_SequentialOrImplicitYield synExpr.Range | SynExpr.TypeTest _ -> genTriviaFor SynExpr_TypeTest synExpr.Range + | SynExpr.IndexRange _ -> genTriviaFor SynExpr_IndexRange synExpr.Range + | SynExpr.IndexFromEnd _ -> genTriviaFor SynExpr_IndexFromEnd synExpr.Range | SynExpr.Const _ -> // SynConst has trivia attached to it id | SynExpr.LetOrUse _ | SynExpr.Sequential _ - | SynExpr.CompExpr _ -> + | SynExpr.ComputationExpr _ -> // first and last nested node has trivia attached to it id | SynExpr.LetOrUseBang _ -> @@ -2931,17 +2923,13 @@ and genMultilineFunctionApplicationArguments astContext argExpr = | _ -> genExpr astContext e match argExpr with - | Paren (lpr, Lambda (pats, body, range), rpr, pr) -> + | Paren (lpr, Lambda (pats, arrowRange, body, range), rpr, pr) -> fun ctx -> if ctx.Config.MultiLineLambdaClosingNewline then - let arrowRange = - List.last pats - |> fun lastPat -> ctx.MkRange lastPat.Range.End body.Range.Start - (sepOpenTFor lpr +> (!- "fun " +> col sepSpace pats (genPat astContext) - +> genArrowWithTrivia (genExprKeepIndentInBranch astContext body) arrowRange + +> genLambdaArrowWithTrivia (genExprKeepIndentInBranch astContext body) arrowRange |> genTriviaFor SynExpr_Lambda range) +> sepNln +> sepCloseTFor rpr pr) @@ -3238,7 +3226,7 @@ and genMultiLineArrayOrList = if isArray then (tokN openingTokenRange LBRACK_BAR sepOpenA - +> atCurrentColumn ( + +> atCurrentColumnIndent ( sepNlnWhenWriteBeforeNewlineNotEmpty sepNone +> col sepSemiNln xs (genExpr astContext) +> tokN closingTokenRange BAR_RBRACK (ifElseCtx lastWriteEventIsNewline sepCloseAFixed sepCloseA) @@ -3246,7 +3234,7 @@ and genMultiLineArrayOrList ctx else (tokN openingTokenRange LBRACK sepOpenL - +> atCurrentColumn ( + +> atCurrentColumnIndent ( sepNlnWhenWriteBeforeNewlineNotEmpty sepNone +> col sepSemiNln xs (genExpr astContext) +> tokN closingTokenRange RBRACK (ifElseCtx lastWriteEventIsNewline sepCloseLFixed sepCloseL) @@ -3254,81 +3242,22 @@ and genMultiLineArrayOrList ctx and genMultiLineArrayOrListAlignBrackets (isArray: bool) xs openingTokenRange closingTokenRange astContext = - let isLastItem (x: SynExpr) = - List.tryLast xs - |> Option.map (fun i -> RangeHelpers.rangeEq i.Range x.Range) - |> Option.defaultValue false - - fun ctx -> - let innerExpr = - xs - |> List.fold - (fun acc e (ctx: Context) -> - let isLastItem = isLastItem e - - (acc - +> genExpr astContext e - +> ifElse isLastItem sepNone sepSemiNln) - ctx) - sepNone - |> atCurrentColumn - - let expr = - if isArray then - tokN openingTokenRange LBRACK_BAR sepOpenAFixed - +> indent - +> sepNlnUnlessLastEventIsNewline - +> innerExpr - +> unindent - +> sepNlnUnlessLastEventIsNewline - +> tokN closingTokenRange BAR_RBRACK sepCloseAFixed - else - tokN openingTokenRange LBRACK sepOpenLFixed - +> indent - +> sepNlnUnlessLastEventIsNewline - +> innerExpr - +> unindent - +> sepNlnUnlessLastEventIsNewline - +> tokN closingTokenRange RBRACK sepCloseLFixed - - expr ctx - -/// Use in indexed set and get only -and genIndexers astContext node = - // helper to generate the remaining indexer expressions - // (pulled out due to duplication) - let inline genRest astContext (es: _ list) = - ifElse es.IsEmpty sepNone (sepComma +> genIndexers astContext es) - - // helper to generate a single indexer expression with support for the from-end slice marker - let inline genSingle astContext (isFromEnd: bool) (e: SynExpr) = - ifElse isFromEnd (!- "^") sepNone - +> genExpr astContext e - - match node with - // list.[*] - | Indexer (Pair ((IndexedVar None, _), (IndexedVar None, _))) :: es -> !- "*" +> genRest astContext es - // list.[(fromEnd)..] - | Indexer (Pair ((IndexedVar (Some e01), e1FromEnd), (IndexedVar None, _))) :: es -> - genSingle astContext e1FromEnd e01 -- ".." - +> genRest astContext es - // list.[..(fromEnd)] - | Indexer (Pair ((IndexedVar None, _), (IndexedVar (Some e2), e2FromEnd))) :: es -> - !- ".." - +> genSingle astContext e2FromEnd e2 - +> genRest astContext es - // list.[(fromEnd)..(fromEnd)] - | Indexer (Pair ((IndexedVar (Some e01), e1FromEnd), (IndexedVar (Some eo2), e2FromEnd))) :: es -> - genSingle astContext e1FromEnd e01 -- ".." - +> genSingle astContext e2FromEnd eo2 - +> genRest astContext es - // list.[*] - | Indexer (Single (IndexedVar None, _)) :: es -> !- "*" +> genRest astContext es - // list.[(fromEnd)] - | Indexer (Single (eo, fromEnd)) :: es -> - genSingle astContext fromEnd eo - +> genRest astContext es - | _ -> sepNone + if isArray then + tokN openingTokenRange LBRACK_BAR sepOpenAFixed + +> indent + +> sepNlnUnlessLastEventIsNewline + +> col sepNln xs (genExpr astContext) + +> unindent + +> sepNlnUnlessLastEventIsNewline + +> tokN closingTokenRange BAR_RBRACK sepCloseAFixed + else + tokN openingTokenRange LBRACK sepOpenLFixed + +> indent + +> sepNlnUnlessLastEventIsNewline + +> col sepNln xs (genExpr astContext) + +> unindent + +> sepNlnUnlessLastEventIsNewline + +> tokN closingTokenRange RBRACK sepCloseLFixed and genApp astContext e es ctx = let shortExpression = @@ -3342,21 +3271,10 @@ and genApp astContext e es ctx = sepSpace sepNone - let genEx e = - if isCompExpr e then - sepSpace - +> sepOpenSFixed - +> sepSpace - +> indent - +> autoNlnIfExpressionExceedsPageWidth (genExpr astContext e) - +> unindent - else - genExpr astContext e - atCurrentColumn ( genExpr astContext e +> addFirstSpace - +> col sepSpace es genEx + +> col sepSpace es (genExpr astContext) ) let isParenLambda = @@ -3390,24 +3308,20 @@ and genApp astContext e es ctx = (bodyExpr: SynExpr) (lpr: Range) (rpr: Range option) - (arrowRange: Range) + (arrowRange: Range option) (pr: Range) : Context -> Context = leadingExpressionIsMultiline (sepOpenTFor lpr -- "fun " +> pats - +> genArrowWithTrivia (genExprKeepIndentInBranch astContext bodyExpr) arrowRange) + +> genLambdaArrowWithTrivia (genExprKeepIndentInBranch astContext bodyExpr) arrowRange) (fun isMultiline -> onlyIf isMultiline sepNln +> sepCloseTFor rpr e.Range) |> genTriviaFor SynExpr_Paren pr match e with - | Paren (lpr, Lambda (pats, expr, _range), rpr, pr) -> - let arrowRange = - List.last pats - |> fun lastPat -> ctx.MkRange lastPat.Range.End expr.Range.Start - + | Paren (lpr, Lambda (pats, arrowRange, expr, _range), rpr, pr) -> genLambda (col sepSpace pats (genPat astContext)) expr lpr rpr arrowRange pr | _ -> genExpr astContext e) @@ -3427,7 +3341,7 @@ and genApp astContext e es ctx = if List.exists (function - | CompExpr _ -> true + | ComputationExpr _ -> true | _ -> false) es then shortExpression ctx @@ -3438,19 +3352,16 @@ and genLambdaMultiLineClosingNewline (astContext: ASTContext) (lpr: Range) (pats: SynPat list) + (arrowRange: Range option) (bodyExpr: SynExpr) (lambdaRange: Range) (rpr: Range option) (pr: Range) : Context -> Context = - let arrowRange (ctx: Context) = - List.last pats - |> fun lastPat -> ctx.MkRange lastPat.Range.End bodyExpr.Range.Start - leadingExpressionIsMultiline (sepOpenTFor lpr -- "fun " +> col sepSpace pats (genPat astContext) - +> (fun ctx -> genArrowWithTrivia (genExprKeepIndentInBranch astContext bodyExpr) (arrowRange ctx) ctx) + +> genLambdaArrowWithTrivia (genExprKeepIndentInBranch astContext bodyExpr) arrowRange |> genTriviaFor SynExpr_Lambda lambdaRange) (fun isMultiline -> onlyIf isMultiline sepNln +> sepCloseTFor rpr pr) |> genTriviaFor SynExpr_Paren pr @@ -4747,9 +4658,7 @@ and genInterfaceImpl astContext (InterfaceImpl (t, bs, range)) = bs +> unindent -and genClause astContext hasBar (Clause (p, e, eo) as ce) = - let arrowRange (ctx: Context) = ctx.MkRange p.Range.End e.Range.Start - +and genClause astContext hasBar (Clause (p, eo, arrowRange, e) as ce) = let astCtx = { astContext with IsInsideMatchClausePattern = true } @@ -4782,13 +4691,21 @@ and genClause astContext hasBar (Clause (p, e, eo) as ce) = if isMultiline then (indent +> sepNln - +> tokN (arrowRange ctx) RARROW sepArrowFixed + +> optSingle + (fun arrowRange -> + sepArrowFixed + |> genTriviaFor SynMatchClause_Arrow arrowRange) + arrowRange +> sepNln +> genExpr astContext e +> unindent) ctx else - (tokN (arrowRange ctx) RARROW sepArrow + (optSingle + (fun arrowRange -> + sepArrow + |> genTriviaFor SynMatchClause_Arrow arrowRange) + arrowRange +> autoIndentAndNlnIfExpressionExceedsPageWidth (genExpr astContext e)) ctx) @@ -5709,38 +5626,53 @@ and genKeepIndentMatch genLastClauseKeepIdent astContext) |> genTriviaFor triviaType matchRange -and genLastClauseKeepIdent (astContext: ASTContext) (Clause (pat, expr, whenExpr)) = +and genLastClauseKeepIdent (astContext: ASTContext) (Clause (pat, whenExpr, arrowRange, expr)) = sepBar +> genPat astContext pat +> sepSpace +> optSingle (genExpr astContext) whenExpr - +> (fun ctx -> - let arrowRange = - ctx.MkRange pat.Range.End expr.Range.Start - - tokN arrowRange FsTokenType.RARROW sepArrowFixed ctx) + +> optSingle + (fun arrowRange -> + sepArrowFixed + |> genTriviaFor SynMatchClause_Arrow arrowRange) + arrowRange +> sepNln +> (let t, r = synExprToFsAstType expr in sepNlnConsideringTriviaContentBeforeForMainNode t r) +> genExprKeepIndentInBranch astContext expr and genKeepIdentIf (astContext: ASTContext) - (branches: (SynExpr * SynExpr * Range * Range * SynExpr) list) + (branches: (range option * range * bool * SynExpr * range * SynExpr) list) (elseExpr: SynExpr) (ifElseRange: Range) = - coli + col sepNln branches - (fun idx (ifExpr, thenExpr, _r, _fullRange, _node) -> + (fun (elseKw, ifKw, isElif, ifExpr, thenKw, thenExpr) -> let genIf = + let genKeywordStart = + optSingle + (fun r -> + !- "else " + |> genTriviaFor SynExpr_IfThenElse_Else r) + elseKw + +> (ifElse isElif (!- "elif ") (!- "if ") + |> genTriviaFor + (if isElif then + SynExpr_IfThenElse_Elif + else + SynExpr_IfThenElse_If) + ifKw) + let short = - ifElse (idx = 0) (!- "if ") (!- "elif ") + genKeywordStart +> genExpr astContext ifExpr - +> !- " then" + +> (!- " then" + |> genTriviaFor SynExpr_IfThenElse_Then thenKw) let long = - ifElse (idx = 0) (!- "if ") (!- "elif ") + genKeywordStart +> genExprInIfOrMatch astContext ifExpr +> sepSpace +> !- "then" @@ -5929,6 +5861,18 @@ and genTriviaFor (mainNodeName: FsAstType) (range: Range) f ctx = +> leaveNodeFor mainNodeName range) ctx +and genLambdaArrowWithTrivia (bodyExpr: Context -> Context) (arrowRange: Range option) = + optSingle + (fun arrowRange -> + sepArrow + |> genTriviaFor SynExpr_Lambda_Arrow arrowRange) + arrowRange + +> (fun ctx -> + if String.isNotNullOrEmpty ctx.WriterModel.WriteBeforeNewline then + (indent +> sepNln +> bodyExpr +> unindent) ctx + else + (autoIndentAndNlnIfExpressionExceedsPageWidth bodyExpr) ctx) + and infixOperatorFromTrivia range fallback (ctx: Context) = // by specs, section 3.4 https://fsharp.org/specs/language-spec/4.1/FSharpSpec-4.1-latest.pdf#page=24&zoom=auto,-137,312 let validIdentRegex = diff --git a/src/Fantomas/SourceParser.fs b/src/Fantomas/SourceParser.fs index 8b6ff786fd..22ae860276 100644 --- a/src/Fantomas/SourceParser.fs +++ b/src/Fantomas/SourceParser.fs @@ -33,8 +33,10 @@ let (|Ident|) (s: Ident) = match ident with | "`global`" -> "global" - | "_" -> "_" // workaround for https://github.com/dotnet/fsharp/issues/7681 - | _ -> QuoteIdentifierIfNeeded ident + | "not" -> "not" + | "params" -> "``params``" + | "parallel" -> "``parallel``" + | _ -> PrettyNaming.AddBackticksToIdentifierIfNeeded ident let (|LongIdent|) (li: LongIdent) = li @@ -670,34 +672,28 @@ let (|SimpleExpr|_|) = | SynExpr.Const _ as e -> Some e | _ -> None -/// Only recognize numbers; strings are ignored -let rec (|SequentialSimple|_|) = +let (|ComputationExpr|_|) = function - | Sequential (SimpleExpr e, SequentialSimple es, true) -> Some(e :: es) - | Sequential (SimpleExpr e1, SimpleExpr e2, true) -> Some [ e1; e2 ] + | SynExpr.ComputationExpr (_, expr, range) -> Some(expr, range) | _ -> None -let (|CompExpr|_|) = +// seq { expr } +let (|NamedComputationExpr|_|) = function - | SynExpr.CompExpr (isArray, _, expr, _) -> Some(isArray, expr) - | _ -> None - -let isCompExpr = - function - | CompExpr _ -> true - | _ -> false - -let (|ArrayOrListOfSeqExpr|_|) = - function - | SynExpr.ArrayOrListOfSeqExpr (isArray, expr, _) -> Some(isArray, expr) + | SynExpr.App (ExprAtomicFlag.NonAtomic, + false, + (SynExpr.App _ as nameExpr + | SimpleExpr nameExpr), + ComputationExpr (compExpr, bodyRange), + _) -> Some(nameExpr, compExpr, bodyRange) | _ -> None -/// This pattern only includes arrays and lists in computation expressions +/// Combines all ArrayOrList patterns let (|ArrayOrList|_|) = function - | ArrayOrListOfSeqExpr (isArray, CompExpr (_, SequentialSimple xs)) -> Some(isArray, xs, true) - | SynExpr.ArrayOrList (isArray, xs, _) - | ArrayOrListOfSeqExpr (isArray, CompExpr (_, Sequentials xs)) -> Some(isArray, xs, false) + | SynExpr.ArrayOrListComputed (isArray, Sequentials xs, _) -> Some(isArray, xs) + | SynExpr.ArrayOrListComputed (isArray, singleExpr, _) -> Some(isArray, [ singleExpr ]) + | SynExpr.ArrayOrList (isArray, xs, _) -> Some(isArray, xs) | _ -> None let (|Tuple|_|) = @@ -718,10 +714,20 @@ let (|IndexedVar|_|) = | SynExpr.LongIdent (_, LongIdentWithDots "Microsoft.FSharp.Core.None", _, _) -> Some None | _ -> None -let (|Indexer|) = +let (|InterpolatedStringExpr|_|) = + function + | SynExpr.InterpolatedString (parts, stringKind, _) -> Some(parts, stringKind) + | _ -> None + +let (|IndexRangeExpr|_|) = + function + | SynExpr.IndexRange (expr1, _, expr2, _, _, _) -> Some(expr1, expr2) + | _ -> None + +let (|IndexFromEndExpr|_|) = function - | SynIndexerArg.Two (e1, e1FromEnd, e2, e2FromEnd, _, _) -> Pair((e1, e1FromEnd), (e2, e2FromEnd)) - | SynIndexerArg.One (e, fromEnd, _) -> Single(e, fromEnd) + | SynExpr.IndexFromEnd (e, _r) -> Some e + | _ -> None let (|OptVar|_|) = function @@ -849,6 +855,14 @@ let (|TernaryApp|_|) = | SynExpr.App (_, _, SynExpr.App (_, _, SynExpr.App (_, true, Var "?<-", e1, _), e2, _), e3, _) -> Some(e1, e2, e3) | _ -> None +// expr1[expr2] +// ref: https://github.com/fsharp/fslang-design/blob/main/FSharp-6.0/FS-1110-index-syntax.md +let (|IndexWithoutDotExpr|_|) = + function + | SynExpr.App (ExprAtomicFlag.Atomic, false, identifierExpr, SynExpr.ArrayOrListComputed (false, indexExpr, _), _) -> + Some(identifierExpr, indexExpr) + | _ -> None + let (|MatchLambda|_|) = function | SynExpr.MatchLambda (_, keywordRange, pats, _, _) -> Some(keywordRange, pats) @@ -966,7 +980,7 @@ let (|ForEach|_|) = let (|DotIndexedSet|_|) = function - | SynExpr.DotIndexedSet (e1, es, e2, _, _, _) -> Some(e1, es, e2) + | SynExpr.DotIndexedSet (objectExpr, indexArgs, valueExpr, _, _, _) -> Some(objectExpr, indexArgs, valueExpr) | _ -> None let (|NamedIndexedPropertySet|_|) = @@ -981,7 +995,7 @@ let (|DotNamedIndexedPropertySet|_|) = let (|DotIndexedGet|_|) = function - | SynExpr.DotIndexedGet (e1, es, _, _) -> Some(e1, es) + | SynExpr.DotIndexedGet (objectExpr, indexArgs, _, _) -> Some(objectExpr, indexArgs) | _ -> None let (|DotGet|_|) = @@ -1029,14 +1043,32 @@ let (|DotSet|_|) = let (|IfThenElse|_|) = function - | SynExpr.IfThenElse (e1, e2, e3, _, _, mIfToThen, _) -> Some(e1, e2, e3, mIfToThen) + | SynExpr.IfThenElse _ as e -> Some e | _ -> None let rec (|ElIf|_|) = function - | SynExpr.IfThenElse (e1, e2, Some (ElIf (es, e3)), _, _, r, fullRange) as node -> - Some((e1, e2, r, fullRange, node) :: es, e3) - | SynExpr.IfThenElse (e1, e2, e3, _, _, r, fullRange) as node -> Some([ (e1, e2, r, fullRange, node) ], e3) + | SynExpr.IfThenElse (ifKw, + isElif, + e1, + thenKw, + e2, + elseKw, + Some (ElIf ((_, eshIfKw, eshIsElif, eshE1, eshThenKw, eshE2) :: es, elseInfo, _)), + _, + _, + _, + range) -> + Some( + ((None, ifKw, isElif, e1, thenKw, e2) + :: (elseKw, eshIfKw, eshIsElif, eshE1, eshThenKw, eshE2) + :: es), + elseInfo, + range + ) + + | SynExpr.IfThenElse (ifKw, isElif, e1, thenKw, e2, elseKw, e3, _, _, _, range) -> + Some([ (None, ifKw, isElif, e1, thenKw, e2) ], (elseKw, e3), range) | _ -> None let (|Record|_|) = @@ -1248,17 +1280,17 @@ let (|RecordField|) = function | SynField (ats, _, ido, _, _, px, ao, _) -> (ats, px, ao, Option.map (|Ident|) ido) -let (|Clause|) (SynMatchClause (p, eo, e, _, _)) = (p, e, eo) +let (|Clause|) (SynMatchClause (p, eo, arrowRange, e, _, _)) = (p, eo, arrowRange, e) /// Process compiler-generated matches in an appropriate way let rec private skipGeneratedLambdas expr = match expr with - | SynExpr.Lambda (_, true, _, bodyExpr, _, _) -> skipGeneratedLambdas bodyExpr + | SynExpr.Lambda (_, true, _, _, bodyExpr, _, _) -> skipGeneratedLambdas bodyExpr | _ -> expr and skipGeneratedMatch expr = match expr with - | SynExpr.Match (_, _, [ SynMatchClause.SynMatchClause (_, _, innerExpr, _, _) as clause ], matchRange) when + | SynExpr.Match (_, _, [ SynMatchClause.SynMatchClause (_, _, _, innerExpr, _, _) as clause ], matchRange) when matchRange.Start = clause.Range.Start -> skipGeneratedMatch innerExpr @@ -1266,12 +1298,12 @@ and skipGeneratedMatch expr = let (|Lambda|_|) = function - | SynExpr.Lambda (_, _, _, _, Some (pats, body), range) -> + | SynExpr.Lambda (_, _, _, arrowRange, _, Some (pats, body), range) -> let inline getLambdaBodyExpr expr = let skippedLambdas = skipGeneratedLambdas expr skipGeneratedMatch skippedLambdas - Some(pats, getLambdaBodyExpr body, range) + Some(pats, arrowRange, getLambdaBodyExpr body, range) | _ -> None let (|AppWithLambda|_|) (e: SynExpr) = @@ -1280,8 +1312,8 @@ let (|AppWithLambda|_|) (e: SynExpr) = let rec visit (es: SynExpr list) (finalContinuation: SynExpr list -> SynExpr list) = match es with | [] -> None - | [ Paren (lpr, Lambda (pats, body, range), rpr, pr) ] -> - Some(e, finalContinuation [], lpr, (Choice1Of2(pats, body, range)), rpr, pr) + | [ Paren (lpr, Lambda (pats, arrowRange, body, range), rpr, pr) ] -> + Some(e, finalContinuation [], lpr, (Choice1Of2(pats, arrowRange, body, range)), rpr, pr) | [ Paren (lpr, (MatchLambda (keywordRange, pats) as me), rpr, pr) ] -> Some(e, finalContinuation [], lpr, (Choice2Of2(keywordRange, pats, me.Range)), rpr, pr) | h :: tail -> @@ -1630,17 +1662,9 @@ let isFunctionBinding (p: SynPat) = let (|ElmishReactWithoutChildren|_|) e = match e with - | SynExpr.App (_, - false, - OptVar (ident, _, _), - (ArrayOrList (isArray, children, _) - | ArrayOrListOfSeqExpr (isArray, CompExpr (_, Sequentials children)) as aolEx), - _) -> Some(ident, isArray, children, aolEx.Range) - | SynExpr.App (_, - false, - OptVar (ident, _, _), - (ArrayOrListOfSeqExpr (isArray, CompExpr (_, singleChild)) as aolEx), - _) -> Some(ident, isArray, [ singleChild ], aolEx.Range) + | IndexWithoutDotExpr _ -> None + | SynExpr.App (_, false, OptVar (ident, _, _), (ArrayOrList (isArray, children) as aolEx), _) -> + Some(ident, isArray, children, aolEx.Range) | _ -> None let (|ElmishReactWithChildren|_|) (e: SynExpr) = @@ -1648,36 +1672,16 @@ let (|ElmishReactWithChildren|_|) (e: SynExpr) = | SynExpr.App (_, false, SynExpr.App (_, false, OptVar ident, (ArrayOrList _ as attributes), _), - (ArrayOrList (isArray, children, _) as childrenNode), + (ArrayOrList (isArray, children) as childrenNode), _) -> Some(ident, attributes, (isArray, children, childrenNode.Range)) - | SynExpr.App (_, - false, - SynExpr.App (_, false, OptVar ident, (ArrayOrListOfSeqExpr _ as attributes), _), - (ArrayOrListOfSeqExpr (isArray, CompExpr (_, Sequentials children)) as childrenNode), - _) -> Some(ident, attributes, (isArray, children, childrenNode.Range)) - | SynExpr.App (_, - false, - SynExpr.App (_, - false, - OptVar ident, - ((ArrayOrListOfSeqExpr _ - | ArrayOrList _) as attributes), - _), - (ArrayOrListOfSeqExpr (isArray, CompExpr (_, singleChild)) as childrenNode), - _) -> Some(ident, attributes, (isArray, [ singleChild ], childrenNode.Range)) - | SynExpr.App (_, - false, - SynExpr.App (_, false, OptVar ident, (ArrayOrListOfSeqExpr _ as attributes), _), - (ArrayOrList (isArray, [], _) as childrenNode), - _) -> Some(ident, attributes, (isArray, [], childrenNode.Range)) | _ -> None let isIfThenElseWithYieldReturn e = match e with - | SynExpr.IfThenElse (_, SynExpr.YieldOrReturn _, None, _, _, _, _) - | SynExpr.IfThenElse (_, SynExpr.YieldOrReturn _, Some (SynExpr.YieldOrReturn _), _, _, _, _) - | SynExpr.IfThenElse (_, SynExpr.YieldOrReturnFrom _, None, _, _, _, _) - | SynExpr.IfThenElse (_, SynExpr.YieldOrReturn _, Some (SynExpr.YieldOrReturnFrom _), _, _, _, _) -> true + | SynExpr.IfThenElse (thenExpr = SynExpr.YieldOrReturn _; elseExpr = None) + | SynExpr.IfThenElse (thenExpr = SynExpr.YieldOrReturn _; elseExpr = Some (SynExpr.YieldOrReturn _)) + | SynExpr.IfThenElse (thenExpr = SynExpr.YieldOrReturnFrom _; elseExpr = None) + | SynExpr.IfThenElse (thenExpr = SynExpr.YieldOrReturn _; elseExpr = Some (SynExpr.YieldOrReturnFrom _)) -> true | _ -> false let isSynExprLambda = @@ -1728,7 +1732,7 @@ let (|KeepIndentMatch|_|) (e: SynExpr) = let mapClauses matchExpr clauses range t = match clauses with | [] -> None - | [ (Clause (_, lastClause, _)) ] -> + | [ (Clause (_, _, _, lastClause)) ] -> if shouldNotIndentBranch lastClause [] then Some(matchExpr, clauses, range, t) else @@ -1737,9 +1741,9 @@ let (|KeepIndentMatch|_|) (e: SynExpr) = let firstClauses = clauses |> List.take (clauses.Length - 1) - |> List.map (fun (Clause (_, expr, _)) -> expr) + |> List.map (fun (Clause (_, _, _, expr)) -> expr) - let (Clause (_, lastClause, _)) = List.last clauses + let (Clause (_, _, _, lastClause)) = List.last clauses if shouldNotIndentBranch lastClause firstClauses then Some(matchExpr, clauses, range, t) @@ -1753,9 +1757,9 @@ let (|KeepIndentMatch|_|) (e: SynExpr) = let (|KeepIndentIfThenElse|_|) (e: SynExpr) = match e with - | ElIf (branches, Some elseExpr) -> + | ElIf (branches, (_, Some elseExpr), _) -> let branchBodies = - branches |> List.map (fun (_, e, _, _, _) -> e) + branches |> List.map (fun (_, _, _, e, _, _) -> e) if shouldNotIndentBranch elseExpr branchBodies then Some(branches, elseExpr, e.Range) diff --git a/src/Fantomas/SourceTransformer.fs b/src/Fantomas/SourceTransformer.fs index 387ba7bf1c..752d9a8dc4 100644 --- a/src/Fantomas/SourceTransformer.fs +++ b/src/Fantomas/SourceTransformer.fs @@ -202,7 +202,7 @@ let rec synExprToFsAstType (expr: SynExpr) : FsAstType * Range = | SynExpr.DoBang _ -> SynExpr_DoBang, expr.Range | SynExpr.Paren _ -> SynExpr_Paren, expr.Range | SynExpr.AnonRecd _ -> SynExpr_AnonRecd, expr.Range - | SynExpr.ArrayOrListOfSeqExpr _ -> SynExpr_ArrayOrListOfSeqExpr, expr.Range + | SynExpr.ArrayOrListComputed _ -> SynExpr_ArrayOrListComputed, expr.Range | SynExpr.LongIdentSet _ -> SynExpr_LongIdentSet, expr.Range | SynExpr.New _ -> SynExpr_New, expr.Range | SynExpr.Quote _ -> SynExpr_Quote, expr.Range @@ -226,7 +226,7 @@ let rec synExprToFsAstType (expr: SynExpr) : FsAstType * Range = | SynExpr.ObjExpr _ -> SynExpr_ObjExpr, expr.Range | SynExpr.For _ -> SynExpr_For, expr.Range | SynExpr.ForEach _ -> SynExpr_ForEach, expr.Range - | SynExpr.CompExpr (_, _, e, _) -> synExprToFsAstType e + | SynExpr.ComputationExpr (_, e, _) -> synExprToFsAstType e | SynExpr.MatchLambda _ -> SynExpr_MatchLambda, expr.Range | SynExpr.Assert _ -> SynExpr_Assert, expr.Range | SynExpr.TypeApp _ -> SynExpr_TypeApp, expr.Range @@ -259,6 +259,8 @@ let rec synExprToFsAstType (expr: SynExpr) : FsAstType * Range = | SynExpr.Fixed _ -> SynExpr_Fixed, expr.Range | SynExpr.InterpolatedString _ -> SynExpr_InterpolatedString, expr.Range | SynExpr.Sequential (_, _, e, _, _) -> synExprToFsAstType e + | SynExpr.IndexRange _ -> SynExpr_IndexRange, expr.Range + | SynExpr.IndexFromEnd _ -> SynExpr_IndexFromEnd, expr.Range let synModuleSigDeclToFsAstType = function diff --git a/src/Fantomas/TokenParser.fs b/src/Fantomas/TokenParser.fs index 82e540a29e..3a63ef1f88 100644 --- a/src/Fantomas/TokenParser.fs +++ b/src/Fantomas/TokenParser.fs @@ -475,11 +475,7 @@ let private getContentFromTokens tokens = |> String.concat String.Empty let private keywordTrivia = - [ "IF" - "ELIF" - "ELSE" - "THEN" - "OVERRIDE" + [ "OVERRIDE" "MEMBER" "DEFAULT" "ABSTRACT" @@ -1175,12 +1171,7 @@ let private tokenNames = "LBRACK_BAR" "BAR_RBRACK" "EQUALS" - "IF" - "THEN" - "ELSE" - "ELIF" "BAR" - "RARROW" "TRY" "FINALLY" "WITH" @@ -1234,7 +1225,6 @@ let internal getFsToken tokenName = | "PREFIX_OP" -> PREFIX_OP | "QMARK" -> QMARK | "QMARK_QMARK" -> QMARK_QMARK - | "RARROW" -> RARROW | "RBRACE" -> RBRACE | "RBRACK" -> RBRACK | "RPAREN" -> RPAREN diff --git a/src/Fantomas/TriviaContext.fs b/src/Fantomas/TriviaContext.fs index d05d526a9c..0acd71bdac 100644 --- a/src/Fantomas/TriviaContext.fs +++ b/src/Fantomas/TriviaContext.fs @@ -15,48 +15,6 @@ let sepOpenTFor r = tokN r LPAREN sepOpenT let sepCloseTFor rpr pr = tokN (Option.defaultValue pr rpr) RPAREN sepCloseT -let genArrowWithTrivia (bodyExpr: Context -> Context) (range: Range) = - (tokN range RARROW sepArrow) - +> (fun ctx -> - if String.isNotNullOrEmpty ctx.WriterModel.WriteBeforeNewline then - (indent +> sepNln +> bodyExpr +> unindent) ctx - else - (autoIndentAndNlnIfExpressionExceedsPageWidth bodyExpr) ctx) - -let ``else if / elif`` (rangeOfIfThenElse: Range) (ctx: Context) = - let keywords = - [ yield! (Map.tryFindOrEmptyList ELSE ctx.TriviaTokenNodes) - yield! (Map.tryFindOrEmptyList IF ctx.TriviaTokenNodes) - yield! (Map.tryFindOrEmptyList ELIF ctx.TriviaTokenNodes) ] - |> List.sortBy (fun tn -> tn.Range.StartLine, tn.Range.StartColumn) - |> TriviaHelpers.``keyword token inside range`` rangeOfIfThenElse - |> List.map (fun (tok, t) -> (TokenParser.getFsToken tok.TokenInfo.TokenName, t)) - - let resultExpr = - match keywords with - | (ELSE, elseTrivia) :: (IF, ifTrivia) :: _ -> - printContentBefore elseTrivia - +> (!- "else") - +> printContentAfter elseTrivia - +> sepNlnWhenWriteBeforeNewlineNotEmpty sepSpace - +> printContentBefore ifTrivia - +> (!- "if ") - +> printContentAfter ifTrivia - | (ELIF, elifTok) :: _ - | [ (ELIF, elifTok) ] -> - printContentBefore elifTok - +> (!- "elif ") - +> printContentAfter elifTok - | [] -> - // formatting from AST - !- "else if " - | _ -> - failwithf - "Unexpected scenario when formatting else if / elif (near %A), please open an issue via https://fsprojects.github.io/fantomas-tools/#/fantomas/preview" - rangeOfIfThenElse - - resultExpr ctx - let getIndentBetweenTicksFromSynPat patRange fallback ctx = TriviaHelpers.getNodesForTypes [ SynPat_LongIdent; SynPat_Named ] ctx.TriviaMainNodes |> List.choose diff --git a/src/Fantomas/TriviaTypes.fs b/src/Fantomas/TriviaTypes.fs index 815484d94c..b4ef4445f7 100644 --- a/src/Fantomas/TriviaTypes.fs +++ b/src/Fantomas/TriviaTypes.fs @@ -46,7 +46,6 @@ type FsTokenType = | PREFIX_OP | QMARK | QMARK_QMARK - | RARROW | RBRACE | RBRACK | RPAREN @@ -128,10 +127,11 @@ type FsAstType = | SynExpr_While | SynExpr_For | SynExpr_ForEach - | SynExpr_ArrayOrListOfSeqExpr + | SynExpr_ArrayOrListComputed | SynExpr_ArrayOrList - // | SynExpr_CompExpr use first nested SynExpr + // | SynExpr_ComputationExpr use first nested SynExpr | SynExpr_Lambda + | SynExpr_Lambda_Arrow | SynExpr_MatchLambda | SynExpr_MatchLambda_Function | SynExpr_Match @@ -146,6 +146,10 @@ type FsAstType = // | SynExpr_Sequential use first nested SynExpr | SynExpr_SequentialOrImplicitYield | SynExpr_IfThenElse + | SynExpr_IfThenElse_If + | SynExpr_IfThenElse_Elif + | SynExpr_IfThenElse_Then + | SynExpr_IfThenElse_Else | SynExpr_Ident | SynExpr_LongIdent | SynExpr_LongIdentSet @@ -180,6 +184,8 @@ type FsAstType = | SynExpr_DiscardAfterMissingQualificationAfterDot | SynExpr_Fixed | SynExpr_InterpolatedString + | SynExpr_IndexRange + | SynExpr_IndexFromEnd | SynInterpolatedStringPart_String | SynInterpolatedStringPart_FillExpr | RecordField_ @@ -193,6 +199,7 @@ type FsAstType = | SynIndexerArg_One | SynIndexerArg_Two | SynMatchClause_ + | SynMatchClause_Arrow | ArgOptions_ | SynInterfaceImpl_ | SynTypeDefn_