From 4cbf674ad4a98fb797c41ebe118a4f27e84945e2 Mon Sep 17 00:00:00 2001 From: nojaf Date: Fri, 4 Mar 2022 10:38:22 +0100 Subject: [PATCH 01/16] Upgrade FSharp.Compiler.Service to 41.0.3. --- paket.dependencies | 6 +++--- paket.lock | 16 ++++++++-------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/paket.dependencies b/paket.dependencies index 8bd81a12e3..032a95d907 100644 --- a/paket.dependencies +++ b/paket.dependencies @@ -3,8 +3,8 @@ source https://api.nuget.org/v3/index.json framework: netstandard2.0, net6.0, netcoreapp3.1 storage: none -nuget FSharp.Core 6.0.1 content: none -nuget FSharp.Compiler.Service == 41.0.1 +nuget FSharp.Core content: none +nuget FSharp.Compiler.Service == 41.0.3 nuget FsUnit nuget FsCheck nuget Microsoft.NET.Test.Sdk @@ -40,7 +40,7 @@ group tool storage: none source https://api.nuget.org/v3/index.json - nuget FSharp.Core 6.0.1 content: none + nuget FSharp.Core content: none nuget Argu nuget StreamJsonRpc nuget Thoth.Json.Net diff --git a/paket.lock b/paket.lock index 8f86ccecc1..2941eb4869 100644 --- a/paket.lock +++ b/paket.lock @@ -31,11 +31,11 @@ NUGET editorconfig (0.12.2) FsCheck (2.16.4) FSharp.Core (>= 4.2.3) - FSharp.Compiler.Service (41.0.1) - FSharp.Core (6.0.1) - Microsoft.Build.Framework (>= 16.11) - Microsoft.Build.Tasks.Core (>= 16.11) - Microsoft.Build.Utilities.Core (>= 16.11) + FSharp.Compiler.Service (41.0.3) + FSharp.Core (6.0.3) + Microsoft.Build.Framework (>= 17.0) + Microsoft.Build.Tasks.Core (>= 17.0) + Microsoft.Build.Utilities.Core (>= 17.0) System.Buffers (>= 4.5.1) System.Collections.Immutable (>= 5.0) System.Diagnostics.Process (>= 4.3) @@ -49,7 +49,7 @@ NUGET System.Reflection.Metadata (>= 5.0) System.Reflection.TypeExtensions (>= 4.3) System.Runtime (>= 4.3) - System.Runtime.CompilerServices.Unsafe (>= 5.0) + System.Runtime.CompilerServices.Unsafe (>= 6.0) System.Runtime.InteropServices (>= 4.3) System.Runtime.Loader (>= 4.3) System.Security.Claims (>= 4.3) @@ -58,7 +58,7 @@ NUGET System.Threading.Tasks.Parallel (>= 4.3) System.Threading.Thread (>= 4.3) System.Threading.ThreadPool (>= 4.3) - FSharp.Core (6.0.1) - content: none + FSharp.Core (6.0.3) - content: none FsUnit (4.2) FSharp.Core (>= 5.0.2) NETStandard.Library (>= 2.0.3) @@ -372,7 +372,7 @@ NUGET System.Resources.ResourceManager (>= 4.3) System.Runtime (>= 4.3) System.Management (6.0) - Microsoft.Win32.Registry (>= 5.0) - restriction: || (&& (== net6.0) (== netstandard2.0)) (== netcoreapp3.1) (&& (== netstandard2.0) (>= netcoreapp3.1)) + Microsoft.Win32.Registry (>= 5.0) - restriction: || (== netcoreapp3.1) (&& (== netstandard2.0) (>= netcoreapp3.1)) System.CodeDom (>= 6.0) System.Memory (4.5.4) System.Buffers (>= 4.5.1) - restriction: || (&& (== net6.0) (>= monotouch)) (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netcoreapp2.0)) (&& (== net6.0) (< netstandard1.1)) (&& (== net6.0) (< netstandard2.0)) (&& (== net6.0) (>= xamarinios)) (&& (== net6.0) (>= xamarinmac)) (&& (== net6.0) (>= xamarintvos)) (&& (== net6.0) (>= xamarinwatchos)) (&& (== netcoreapp3.1) (>= monotouch)) (&& (== netcoreapp3.1) (>= net461)) (&& (== netcoreapp3.1) (< netcoreapp2.0)) (&& (== netcoreapp3.1) (< netstandard1.1)) (&& (== netcoreapp3.1) (< netstandard2.0)) (&& (== netcoreapp3.1) (>= xamarinios)) (&& (== netcoreapp3.1) (>= xamarinmac)) (&& (== netcoreapp3.1) (>= xamarintvos)) (&& (== netcoreapp3.1) (>= xamarinwatchos)) (== netstandard2.0) From ba38c8c644a5e1c8de7e6afbae97bf8b948afae8 Mon Sep 17 00:00:00 2001 From: nojaf Date: Tue, 18 Jan 2022 20:39:59 +0100 Subject: [PATCH 02/16] Process changes of FCS main branch 18/01. Remove EQUALS and WITH keyword from trivia tokens. --- src/Fantomas.Tests/ClassTests.fs | 4 +- src/Fantomas.Tests/CommentTests.fs | 2 +- src/Fantomas.Tests/TestHelpers.fs | 3 +- src/Fantomas.Tests/TriviaTests.fs | 2 +- src/Fantomas/AstExtensions.fs | 23 --- src/Fantomas/AstTransformer.fs | 174 +++++++++------- src/Fantomas/CodeFormatterImpl.fs | 67 ++---- src/Fantomas/CodePrinter.fs | 316 ++++++++++++++++------------- src/Fantomas/Context.fs | 18 +- src/Fantomas/SourceParser.fs | 149 +++++++++----- src/Fantomas/SourceTransformer.fs | 18 +- src/Fantomas/TokenParser.fs | 7 +- src/Fantomas/TriviaTypes.fs | 36 +++- 13 files changed, 453 insertions(+), 366 deletions(-) diff --git a/src/Fantomas.Tests/ClassTests.fs b/src/Fantomas.Tests/ClassTests.fs index 75dc1c7c8b..d9e7da3754 100644 --- a/src/Fantomas.Tests/ClassTests.fs +++ b/src/Fantomas.Tests/ClassTests.fs @@ -393,8 +393,8 @@ let ``member properties with type annotation`` () = and set (_: int): unit = () member this.Z - with get (): int = 1 - and set (_: int): unit = () + with set (_: int): unit = () + and get (): int = 1 """ [] diff --git a/src/Fantomas.Tests/CommentTests.fs b/src/Fantomas.Tests/CommentTests.fs index 9cefb95a99..26ede91311 100644 --- a/src/Fantomas.Tests/CommentTests.fs +++ b/src/Fantomas.Tests/CommentTests.fs @@ -1729,7 +1729,7 @@ with """ [] -let ``comment shold not be lost`` () = +let ``comment should not be lost`` () = formatSourceString false """ diff --git a/src/Fantomas.Tests/TestHelpers.fs b/src/Fantomas.Tests/TestHelpers.fs index 52a2e21bb5..03f22a529c 100644 --- a/src/Fantomas.Tests/TestHelpers.fs +++ b/src/Fantomas.Tests/TestHelpers.fs @@ -23,7 +23,8 @@ let sharedChecker = lazy (FSharpChecker.Create()) let private safeToIgnoreWarnings = [ "This construct is deprecated: it is only for use in the F# library" - "Identifiers containing '@' are reserved for use in F# code generation" ] + "Identifiers containing '@' are reserved for use in F# code generation" + "XML comment is not placed on a valid language element." ] let private isValidAndHasNoWarnings fileName source parsingOptions = let allDefineOptions, _ = TokenParser.getDefines source diff --git a/src/Fantomas.Tests/TriviaTests.fs b/src/Fantomas.Tests/TriviaTests.fs index 8eeb72ad18..42ff2e3607 100644 --- a/src/Fantomas.Tests/TriviaTests.fs +++ b/src/Fantomas.Tests/TriviaTests.fs @@ -143,7 +143,7 @@ let ``block comment added to trivia`` () = let triviaNodes = toTrivia source |> List.head match triviaNodes with - | [ { ContentBefore = [ Comment (BlockComment (comment, _, _)) ] } ] -> comment == "(* meh *)" + | [ { ContentAfter = [ Comment (BlockComment (comment, _, _)) ] } ] -> comment == "(* meh *)" | _ -> failwith "Expected block comment" [] diff --git a/src/Fantomas/AstExtensions.fs b/src/Fantomas/AstExtensions.fs index 46357e00a5..257d30817b 100644 --- a/src/Fantomas/AstExtensions.fs +++ b/src/Fantomas/AstExtensions.fs @@ -59,26 +59,3 @@ type SynModuleSigDecl with | SynModuleSigDecl.NestedModule(moduleInfo = SynComponentInfo (attributes = attrs; longId = lid :: _)) -> hasLinesBetweenAttributesAndFirstNode attrs lid.idRange | _ -> None - -// TODO: Remove when https://github.com/dotnet/fsharp/pull/12441 is part of FCS -type SynExceptionDefnRepr with - member this.FullRange: range = - match this with - | SynExceptionDefnRepr (attributes = attrs; range = m) -> - match attrs with - | h :: _ -> mkRange m.FileName h.Range.Start m.End - | _ -> m - -type SynExceptionSig with - member this.FullRange: range = - match this with - | SynExceptionSig (exnRepr = exnRepr; members = members; range = m) -> - match List.tryLast members with - | Some lastMember -> mkRange m.FileName exnRepr.FullRange.Start lastMember.Range.End - | None -> exnRepr.FullRange - -type SynModuleSigDecl with - member this.FullRange: Range = - match this with - | SynModuleSigDecl.Exception (SynExceptionSig _ as ses, _) -> ses.FullRange - | _ -> this.Range diff --git a/src/Fantomas/AstTransformer.fs b/src/Fantomas/AstTransformer.fs index 4c68875d29..c3decefad6 100644 --- a/src/Fantomas/AstTransformer.fs +++ b/src/Fantomas/AstTransformer.fs @@ -37,19 +37,20 @@ module private Ast = | SynModuleDecl.ModuleAbbrev (_, _, range) -> [ mkNode SynModuleDecl_ModuleAbbrev range ] |> finalContinuation - | SynModuleDecl.NestedModule (sci, _, decls, _, range) -> + | SynModuleDecl.NestedModule (sci, _, equalsRange, decls, _, range) -> let continuations: ((TriviaNodeAssigner list -> TriviaNodeAssigner list) -> TriviaNodeAssigner list) list = decls |> List.map visit let finalContinuation (nodes: TriviaNodeAssigner list list) : TriviaNodeAssigner list = let afterAttributesBeforeNestedModule = - ast.AfterAttributesBeforeNestedModuleName - |> Option.map (mkNode SynModuleDecl_NestedModule_AfterAttributesBeforeModuleName) - |> Option.toList + mkNodeOption + SynModuleDecl_NestedModule_AfterAttributesBeforeModuleName + ast.AfterAttributesBeforeNestedModuleName [ mkNode SynModuleDecl_NestedModule range yield! afterAttributesBeforeNestedModule yield! visitSynComponentInfo sci + yield! mkNodeOption SynModuleDecl_NestedModule_Equals equalsRange yield! (List.collect id nodes) ] |> finalContinuation @@ -162,11 +163,12 @@ module private Ast = yield! nodes yield! visitSynType typeName ] |> finalContinuation) - | SynExpr.ObjExpr (objType, argOptions, bindings, extraImpls, _, range) -> + | SynExpr.ObjExpr (objType, argOptions, withRange, bindings, extraImpls, _, range) -> [ yield mkNode SynExpr_ObjExpr range yield! visitSynType objType if argOptions.IsSome then yield! visitArgsOption argOptions.Value + yield! mkNodeOption SynExpr_ObjExpr_With withRange yield! extraImpls |> List.collect visitSynInterfaceImpl yield! bindings |> List.collect visitSynBinding ] |> finalContinuation @@ -180,15 +182,16 @@ module private Ast = |> finalContinuation Continuation.sequence continuations finalContinuation - | SynExpr.For (_, _, identBody, _, toBody, doBody, range) -> + | SynExpr.For (_, _, equalsRange, identBody, _, toBody, doBody, range) -> let continuations: ((TriviaNodeAssigner list -> TriviaNodeAssigner list) -> TriviaNodeAssigner list) list = [ visit identBody visit toBody visit doBody ] let finalContinuation (nodes: TriviaNodeAssigner list list) : TriviaNodeAssigner list = - mkNode SynExpr_For range - :: (List.collect id nodes) + [ yield mkNode SynExpr_For range + yield! mkNodeOption SynExpr_For_Equals equalsRange + yield! (List.collect id nodes) ] |> finalContinuation Continuation.sequence continuations finalContinuation @@ -211,9 +214,7 @@ module private Ast = visit body (fun nodes -> [ yield mkNode SynExpr_Lambda range yield! visitSynSimplePats args - yield! - (Option.toList arrowRange - |> List.map (mkNode SynExpr_Lambda_Arrow)) + yield! mkNodeOption SynExpr_Lambda_Arrow arrowRange yield! nodes ] |> finalContinuation) | SynExpr.MatchLambda (_, keywordRange, matchClauses, _, range) -> @@ -221,10 +222,12 @@ module private Ast = :: mkNode SynExpr_MatchLambda_Function keywordRange :: (List.collect visitSynMatchClause matchClauses) |> finalContinuation - | SynExpr.Match (_, expr, clauses, range) -> + | SynExpr.Match (matchKeywordRange, _, expr, withKeywordRange, clauses, range) -> visit expr (fun nodes -> [ yield mkNode SynExpr_Match range + yield mkNode SynExpr_Match_Match matchKeywordRange yield! nodes + yield mkNode SynExpr_Match_With withKeywordRange yield! (List.collect visitSynMatchClause clauses) ] |> finalContinuation) | SynExpr.Do (expr, StartRange 2 (doKeyword, range)) -> @@ -262,10 +265,12 @@ module private Ast = [ yield! (List.collect visitSynBinding bindings) yield! nodes ] |> finalContinuation) - | SynExpr.TryWith (tryExpr, _, withCases, _, range, _, _) -> + | SynExpr.TryWith (tryKeyword, tryExpr, _, withKeyword, withCases, _, range, _, _) -> visit tryExpr (fun nodes -> [ yield mkNode SynExpr_TryWith range + yield mkNode SynExpr_TryWith_Try tryKeyword yield! nodes + yield mkNode SynExpr_TryWith_With withKeyword yield! withCases |> List.collect visitSynMatchClause ] |> finalContinuation) | SynExpr.TryFinally (tryExpr, finallyExpr, range, _, _) -> @@ -315,8 +320,7 @@ module private Ast = let finalContinuation (nodes: TriviaNodeAssigner list list) : TriviaNodeAssigner list = let elseNode elseKw = - Option.map (mkNode SynExpr_IfThenElse_Else) elseKw - |> Option.toList + mkNodeOption SynExpr_IfThenElse_Else elseKw let elifKeywords = es @@ -363,9 +367,7 @@ module private Ast = SynExpr_IfThenElse_If) ifKw yield mkNode SynExpr_IfThenElse_Then thenKw - yield! - (Option.map (mkNode SynExpr_IfThenElse_Else) elseKw - |> Option.toList) + yield! mkNodeOption SynExpr_IfThenElse_Else elseKw yield! (List.collect id nodes) ] |> finalContinuation @@ -536,26 +538,26 @@ module private Ast = yield mkNode keywordType keywordRange yield! nodes ] |> finalContinuation) - | SynExpr.LetOrUseBang (_, _, _, pat, rhsExpr, andBangs, body, range) -> + | SynExpr.LetOrUseBang (_, _, _, pat, equalsRange, rhsExpr, andBangs, body, range) -> let continuations: ((TriviaNodeAssigner list -> TriviaNodeAssigner list) -> TriviaNodeAssigner list) list = [ yield visit rhsExpr yield visit body - yield! (List.map (fun (_, _, _, _, body, _) -> visit body) andBangs) ] + yield (fun continuation -> continuation (List.collect visitSynExprAndBang andBangs)) ] let finalContinuation (nodes: TriviaNodeAssigner list list) : TriviaNodeAssigner list = [ yield mkNode SynExpr_LetOrUseBang range yield! visitSynPat pat - yield! (List.collect id nodes) - yield! - andBangs - |> List.collect (fun (_, _, _, pat, _, _) -> visitSynPat pat) ] + yield! mkNodeOption SynExpr_LetOrUseBang_Equals equalsRange + yield! (List.collect id nodes) ] |> finalContinuation Continuation.sequence continuations finalContinuation - | SynExpr.MatchBang (_, expr, clauses, range) -> + | SynExpr.MatchBang (matchKeyword, _, expr, withKeyword, clauses, range) -> visit expr (fun nodes -> [ yield mkNode SynExpr_MatchBang range + yield mkNode SynExpr_MatchBang_Match matchKeyword yield! nodes + yield mkNode SynExpr_MatchBang_With withKeyword yield! clauses |> List.collect visitSynMatchClause ] |> finalContinuation) | SynExpr.DoBang (expr, StartRange 3 (doBangKeyword, range)) -> @@ -630,13 +632,18 @@ module private Ast = visitSynExpr expr @ (Option.toList ident |> List.map visitIdent) - and visitRecordField ((longId, _): RecordFieldName, expr: SynExpr option, _: BlockSeparator option) = - mkNode RecordField_ longId.Range - :: (match expr with - | Some e -> visitSynExpr e - | None -> []) + and visitRecordField (SynExprRecordField ((fieldName, _), equalsRange, synExprOption, blockSeparator)) = + [ yield mkNode RecordField_ fieldName.Range + yield! mkNodeOption RecordField_Equals equalsRange + yield! + (match synExprOption with + | Some e -> visitSynExpr e + | None -> []) ] - and visitAnonRecordField (ident: Ident, expr: SynExpr) = visitIdent ident :: visitSynExpr expr + and visitAnonRecordField (_: Ident, equalsRange: range option, expr: SynExpr) = + [ yield visitIdent ident + yield! mkNodeOption SynExpr_AnonRecd_Field_Equals equalsRange + yield! visitSynExpr expr ] and visitAnonRecordTypeField (_: Ident, t: SynType) = visitSynType t @@ -665,23 +672,28 @@ module private Ast = :: [ yield! visitSynPat pat if e1.IsSome then yield! visitSynExpr e1.Value - yield! - (Option.toList arrowRange - |> List.map (mkNode SynMatchClause_Arrow)) + yield! mkNodeOption SynMatchClause_Arrow arrowRange yield! visitSynExpr e2 ] + and visitSynExprAndBang (SynExprAndBang (_, _, _, pat, equalsRange, body, _range)) : TriviaNodeAssigner list = + [ // yield mkNode SynExprAndBang_ range + yield! visitSynPat pat + yield mkNode SynExprAndBang_Equals equalsRange + yield! visitSynExpr body ] + and visitArgsOption (expr: SynExpr, _: Ident option) = visitSynExpr expr and visitSynInterfaceImpl (ii: SynInterfaceImpl) : TriviaNodeAssigner list = match ii with - | SynInterfaceImpl (typ, bindings, range) -> + | SynInterfaceImpl (typ, withKeyword, bindings, range) -> [ yield mkNode SynInterfaceImpl_ range + yield! mkNodeOption SynInterfaceImpl_With withKeyword yield! visitSynType typ yield! (bindings |> List.collect visitSynBinding) ] and visitSynTypeDefn (td: SynTypeDefn) = match td with - | SynTypeDefn (sci, stdr, members, implicitConstructor, range) -> + | SynTypeDefn (sci, equalsRange, stdr, withKeyword, members, implicitConstructor, range) -> let afterAttributesBeforeRepr = match td.AfterAttributesBeforeComponentInfo with | None -> [] @@ -691,17 +703,21 @@ module private Ast = // TODO process implicitConstructor ?? [ yield mkNode SynTypeDefn_ range + yield! mkNodeOption SynTypeDefn_Equals equalsRange yield! visitSynComponentInfo sci yield! afterAttributesBeforeRepr yield! visitSynTypeDefnRepr stdr + yield! mkNodeOption SynTypeDefn_With withKeyword yield! (members |> List.collect visitSynMemberDefn) ] and visitSynTypeDefnSig (typeDefSig: SynTypeDefnSig) : TriviaNodeAssigner list = match typeDefSig with - | SynTypeDefnSig (sci, synTypeDefnSigReprs, memberSig, _) -> + | SynTypeDefnSig (sci, equalsRange, synTypeDefnSigReprs, withRange, memberSig, _) -> [ yield mkNode SynTypeDefnSig_ typeDefSig.Range yield! visitSynComponentInfo sci + yield! mkNodeOption SynTypeDefnSig_Equals equalsRange yield! visitSynTypeDefnSigRepr synTypeDefnSigReprs + yield! mkNodeOption SynTypeDefnSig_With withRange yield! (memberSig |> List.collect visitSynMemberSig) ] and visitSynTypeDefnSigRepr (stdr: SynTypeDefnSigRepr) : TriviaNodeAssigner list = @@ -740,8 +756,9 @@ module private Ast = | SynMemberDefn.AbstractSlot (valSig, _, range) -> mkNode SynMemberDefn_AbstractSlot range :: (visitSynValSig valSig) - | SynMemberDefn.Interface (typ, members, range) -> + | SynMemberDefn.Interface (typ, withKeyword, members, range) -> [ yield mkNode SynMemberDefn_Interface range + yield! mkNodeOption SynMemberDefn_Interface_With withKeyword yield! visitSynType typ if members.IsSome then yield! members.Value |> List.collect visitSynMemberDefn ] @@ -754,8 +771,10 @@ module private Ast = | SynMemberDefn.NestedType (typeDefn, _, range) -> mkNode SynMemberDefn_NestedType range :: (visitSynTypeDefn typeDefn) - | SynMemberDefn.AutoProperty (attrs, _, _, typeOpt, _, _, _, _, synExpr, _, range) -> + | SynMemberDefn.AutoProperty (attrs, _, _, typeOpt, _, _, _, _, equalsRange, synExpr, withKeyword, _, range) -> [ yield mkNode SynMemberDefn_AutoProperty range + yield mkNode SynMemberDefn_AutoProperty_Equals equalsRange + yield! mkNodeOption SynMemberDefn_AutoProperty_With withKeyword yield! (visitSynAttributeLists attrs) if typeOpt.IsSome then yield! visitSynType typeOpt.Value @@ -804,7 +823,7 @@ module private Ast = and visitSynBinding (binding: SynBinding) : TriviaNodeAssigner list = match binding with - | SynBinding (_, kind, _, _, attrs, _, valData, headPat, returnInfo, expr, _range, _) -> + | SynBinding (_, kind, _, _, attrs, _, valData, headPat, returnInfo, equalsRange, expr, _range, _) -> let t = match kind with | SynBindingKind.StandaloneExpression -> SynBindingKind_StandaloneExpression @@ -832,6 +851,7 @@ module private Ast = (match returnInfo with | Some ri -> visitSynBindingReturnInfo ri | None -> []) + yield! mkNodeOption SynBinding_Equals equalsRange yield! visitSynExpr expr ] and visitSynValData (svd: SynValData) : TriviaNodeAssigner list = @@ -840,7 +860,7 @@ module private Ast = and visitSynValSig (svs: SynValSig) : TriviaNodeAssigner list = match svs with - | SynValSig (attrs, ident, explicitValDecls, synType, arity, _, _, _, _, expr, range) -> + | SynValSig (attrs, ident, explicitValDecls, synType, arity, _, _, _, _, expr, withKeyword, range) -> [ yield mkNode SynValSig_ range yield visitIdent ident yield! (visitSynAttributeLists attrs) @@ -848,7 +868,8 @@ module private Ast = yield! visitSynType synType yield! visitSynValInfo arity if expr.IsSome then - yield! visitSynExpr expr.Value ] + yield! visitSynExpr expr.Value + yield! mkNodeOption SynValSig_With withKeyword ] and visitSynValTyparDecls (valTypeDecl: SynValTyparDecls) : TriviaNodeAssigner list = match valTypeDecl with @@ -923,8 +944,15 @@ module private Ast = |> finalContinuation Continuation.sequence continuations finalContinuation - | SynPat.LongIdent (_, _, svtd, ctorArgs, _, range) -> + | SynPat.LongIdent (_, propertyKeyword, _, svtd, ctorArgs, _, range) -> + let propertyNodes = + match propertyKeyword with + | Some (PropertyKeyword.And r) -> [ mkNode SynPat_LongIdent_And r ] + | Some (PropertyKeyword.With r) -> [ mkNode SynPat_LongIdent_With r ] + | None -> [] + [ yield mkNode SynPat_LongIdent range + yield! propertyNodes if svtd.IsSome then yield! visitSynValTyparDecls svtd.Value yield! visitSynConstructorArgs ctorArgs ] @@ -960,7 +988,11 @@ module private Ast = | SynPat.Record (pats, range) -> let continuations: ((TriviaNodeAssigner list -> TriviaNodeAssigner list) -> TriviaNodeAssigner list) list = - pats |> List.map (snd >> visit) + pats + |> List.map (fun (_, equalsRange, pat) -> + fun nodes -> + mkNode SynPat_Record_Field_Equals equalsRange + :: visit pat nodes) let finalContinuation (nodes: TriviaNodeAssigner list list) : TriviaNodeAssigner list = mkNode SynPat_Record range @@ -1002,7 +1034,11 @@ module private Ast = | SynArgPats.Pats pats -> List.collect visitSynPat pats | SynArgPats.NamePatPairs (pats, range) -> mkNode SynArgPats_NamePatPairs range - :: (List.collect (snd >> visitSynPat) pats) + :: (List.collect + (fun (_, equalsRange, pat) -> + mkNode SynArgPats_NamePatPairs_Equals equalsRange + :: visitSynPat pat) + pats) and visitSynComponentInfo (sci: SynComponentInfo) : TriviaNodeAssigner list = match sci with @@ -1042,9 +1078,10 @@ module private Ast = | SynTypeDefnKind.Record | SynTypeDefnKind.Abbrev | SynTypeDefnKind.Opaque - | SynTypeDefnKind.Augmentation | SynTypeDefnKind.Union | SynTypeDefnKind.IL -> [] + | SynTypeDefnKind.Augmentation withRange -> [ mkNode SynTypeDefnKind_Augmentation_With withRange ] + | SynTypeDefnKind.Delegate (typ, valinfo) -> visitSynType typ @ visitSynValInfo valinfo and visitSynTypeDefnSimpleRepr (arg: SynTypeDefnSimpleRepr) = @@ -1076,17 +1113,16 @@ module private Ast = and visitSynExceptionDefn (exceptionDef: SynExceptionDefn) : TriviaNodeAssigner list = match exceptionDef with - | SynExceptionDefn (sedr, members, range) -> + | SynExceptionDefn (sedr, withKeyword, members, range) -> [ yield mkNode SynExceptionDefn_ range yield! visitSynExceptionDefnRepr sedr + yield! mkNodeOption SynExceptionDefn_With withKeyword yield! (members |> List.collect visitSynMemberDefn) ] and visitSynExceptionDefnRepr (sedr: SynExceptionDefnRepr) : TriviaNodeAssigner list = match sedr with - | SynExceptionDefnRepr (attrs, unionCase, _, _, _, _range) -> - let fullRange = sedr.FullRange - - [ yield mkNode SynExceptionDefnRepr_ fullRange + | SynExceptionDefnRepr (attrs, unionCase, _, _, _, range) -> + [ yield mkNode SynExceptionDefnRepr_ range yield! (visitSynAttributeLists attrs) yield! visitSynUnionCase unionCase ] @@ -1096,17 +1132,6 @@ module private Ast = and visitSynAttributeLists (attrs: SynAttributeList list) : TriviaNodeAssigner list = List.collect visitSynAttributeList attrs - // match attrs with -// | [ h ] -> visitSynAttributeList h -// | _ :: tail -> -// let aRanges = -// tail -// |> List.map (fun a -> a.Range) -// |> fun r -> r @ [ parentRange ] -// -// List.zip attrs aRanges -// |> List.collect (fun (a, r) -> visitSynAttributeList r a) -// | [] -> [] and visitSynAttributeList (attrs: SynAttributeList) : TriviaNodeAssigner list = TriviaNodeAssigner(MainNode(SynAttributeList_), attrs.Range) @@ -1126,10 +1151,11 @@ module private Ast = and visitSynEnumCase (sec: SynEnumCase) : TriviaNodeAssigner list = match sec with - | SynEnumCase (attrs, ident, value, valueRange, _, range) -> + | SynEnumCase (attrs, ident, equalsRange, value, valueRange, _, range) -> [ yield mkNode SynEnumCase_ range yield! (visitSynAttributeLists attrs) yield visitIdent ident + yield mkNode SynEnumCase_Equals equalsRange yield! visitSynConst valueRange value ] and visitSynField (sfield: SynField) : TriviaNodeAssigner list = @@ -1336,19 +1362,20 @@ module private Ast = mkNode SynModuleSigDecl_ModuleAbbrev range |> List.singleton |> finalContinuation - | SynModuleSigDecl.NestedModule (sci, _, decls, range) -> + | SynModuleSigDecl.NestedModule (sci, _, equalsRange, decls, range) -> let continuations: ((TriviaNodeAssigner list -> TriviaNodeAssigner list) -> TriviaNodeAssigner list) list = List.map visit decls let finalContinuation (nodes: TriviaNodeAssigner list list) : TriviaNodeAssigner list = let afterAttributesBeforeNestedModule = - ast.AfterAttributesBeforeNestedModuleName - |> Option.map (mkNode SynModuleSigDecl_NestedModule_AfterAttributesBeforeModuleName) - |> Option.toList + mkNodeOption + SynModuleSigDecl_NestedModule_AfterAttributesBeforeModuleName + ast.AfterAttributesBeforeNestedModuleName [ yield mkNode SynModuleSigDecl_NestedModule range yield! afterAttributesBeforeNestedModule yield! visitSynComponentInfo sci + yield! mkNodeOption SynModuleSigDecl_NestedModule_Equals equalsRange yield! (List.collect id nodes) ] |> finalContinuation @@ -1376,10 +1403,8 @@ module private Ast = | SynModuleSigDecl.NamespaceFragment moduleOrNamespace -> visitSynModuleOrNamespaceSig moduleOrNamespace |> finalContinuation - | SynModuleSigDecl.Exception (synExceptionSig, _range) -> - let fullRange = ast.FullRange - - mkNode SynModuleSigDecl_Exception fullRange + | SynModuleSigDecl.Exception (synExceptionSig, range) -> + mkNode SynModuleSigDecl_Exception range :: (visitSynExceptionSig synExceptionSig) |> finalContinuation @@ -1387,11 +1412,10 @@ module private Ast = and visitSynExceptionSig (exceptionDef: SynExceptionSig) : TriviaNodeAssigner list = match exceptionDef with - | SynExceptionSig (sedr, members, _range) -> - let fullRange = exceptionDef.FullRange - - [ yield mkNode SynExceptionSig_ fullRange + | SynExceptionSig (sedr, withKeyword, members, range) -> + [ yield mkNode SynExceptionSig_ range yield! visitSynExceptionDefnRepr sedr + yield! mkNodeOption SynExceptionSig_With withKeyword yield! (members |> List.collect visitSynMemberSig) ] and visitLongIdentWithDots (lid: LongIdentWithDots) : TriviaNodeAssigner list = diff --git a/src/Fantomas/CodeFormatterImpl.fs b/src/Fantomas/CodeFormatterImpl.fs index 65c2f4550f..7a1fe09dcb 100644 --- a/src/Fantomas/CodeFormatterImpl.fs +++ b/src/Fantomas/CodeFormatterImpl.fs @@ -93,20 +93,19 @@ let isValidAST ast = and validateModuleDecl (decl: SynModuleDecl) = match decl with - | SynModuleDecl.Exception (SynExceptionDefn (_repr, synMembers, _defnRange), _range) -> + | SynModuleDecl.Exception(exnDefn = SynExceptionDefn (members = synMembers)) -> List.forall validateMemberDefn synMembers | SynModuleDecl.Let (_isRecursive, bindings, _range) -> List.forall validateBinding bindings | SynModuleDecl.ModuleAbbrev (_lhs, _rhs, _range) -> true | SynModuleDecl.NamespaceFragment fragment -> validateModuleOrNamespace fragment - | SynModuleDecl.NestedModule (_componentInfo, _isRec, modules, _isContinuing, _range) -> - List.forall validateModuleDecl modules + | SynModuleDecl.NestedModule (decls = decls) -> List.forall validateModuleDecl decls | SynModuleDecl.Types (typeDefs, _range) -> List.forall validateTypeDefn typeDefs | SynModuleDecl.DoExpr (_, expr, _) -> validateExpr expr | SynModuleDecl.Attributes _ | SynModuleDecl.HashDirective _ | SynModuleDecl.Open _ -> true - and validateTypeDefn (SynTypeDefn (_componentInfo, representation, members, _implicitConstructor, _range)) = + and validateTypeDefn (SynTypeDefn (typeRepr = representation; members = members)) = validateTypeDefnRepr representation && List.forall validateMemberDefn members @@ -128,18 +127,8 @@ let isValidAST ast = and validateMemberDefn (memberDefn: SynMemberDefn) = match memberDefn with | SynMemberDefn.AbstractSlot (_synValSig, _memberFlags, _range) -> true - | SynMemberDefn.AutoProperty (_attributes, - _isStatic, - _id, - _type, - _memberKind, - _memberFlags, - _xmlDoc, - _access, - expr, - _r1, - _r2) -> validateExpr expr - | SynMemberDefn.Interface (_interfaceType, members, _range) -> + | SynMemberDefn.AutoProperty (synExpr = expr) -> validateExpr expr + | SynMemberDefn.Interface (members = members) -> defaultArg (Option.map (List.forall validateMemberDefn) members) true | SynMemberDefn.Member (binding, _range) -> validateBinding binding | SynMemberDefn.NestedType (typeDef, _access, _range) -> validateTypeDefn typeDef @@ -150,20 +139,7 @@ let isValidAST ast = | SynMemberDefn.ImplicitCtor _ -> true | SynMemberDefn.ImplicitInherit (_, expr, _, _) -> validateExpr expr - and validateBinding - (SynBinding (_access, - _bindingKind, - _isInline, - _isMutable, - _attrs, - _xmldoc, - _valData, - headPat, - _retTy, - expr, - _bindingRange, - _seqPoint)) - = + and validateBinding (SynBinding (headPat = headPat; expr = expr)) = validateExpr expr && validatePattern headPat and validateClause (Clause (pat, exprOpt, _, expr)) = @@ -184,12 +160,13 @@ let isValidAST ast = | SynExpr.ArrayOrList (_, synExprList, _range) -> List.forall validateExpr synExprList | SynExpr.Record (_inheritOpt, _copyOpt, fields, _range) -> - List.forall (fun (_, e, _) -> defaultArg (Option.map validateExpr e) true) fields - | SynExpr.AnonRecd (_inheritOpt, _copyOpt, fields, _range) -> List.forall (fun (_, e) -> validateExpr e) fields + List.forall (fun (SynExprRecordField (expr = e)) -> defaultArg (Option.map validateExpr e) true) fields + | SynExpr.AnonRecd (_inheritOpt, _copyOpt, fields, _range) -> + List.forall (fun (_, _, e) -> validateExpr e) fields | SynExpr.New (_, _synType, synExpr, _range) -> validateExpr synExpr - | SynExpr.ObjExpr (_ty, _baseCallOpt, binds, _ifaces, _range1, _range2) -> List.forall validateBinding binds + | SynExpr.ObjExpr (bindings = binds) -> List.forall validateBinding binds | SynExpr.While (_sequencePointInfoForWhileLoop, synExpr1, synExpr2, _range) -> List.forall validateExpr [ synExpr1; synExpr2 ] @@ -197,7 +174,7 @@ let isValidAST ast = List.forall validateExpr [ synExpr1; synExpr2 ] && validatePattern synPat - | SynExpr.For (_sequencePointInfoForForLoop, _ident, synExpr1, _, synExpr2, synExpr3, _range) -> + | SynExpr.For (identBody = synExpr1; toBody = synExpr2; doBody = synExpr3) -> List.forall validateExpr [ synExpr1; synExpr2; synExpr3 ] | SynExpr.ArrayOrListComputed (_, synExpr, _range) -> validateExpr synExpr @@ -206,8 +183,8 @@ let isValidAST ast = | SynExpr.MatchLambda (_isExnMatch, _argm, synMatchClauseList, _spBind, _wholem) -> List.forall validateClause synMatchClauseList - | SynExpr.Match (_sequencePointInfoForBinding, synExpr, synMatchClauseList, _range) - | SynExpr.MatchBang (_sequencePointInfoForBinding, synExpr, synMatchClauseList, _range) -> + | SynExpr.Match (expr = synExpr; clauses = synMatchClauseList) + | SynExpr.MatchBang (expr = synExpr; clauses = synMatchClauseList) -> validateExpr synExpr && List.forall validateClause synMatchClauseList @@ -224,13 +201,7 @@ let isValidAST ast = List.forall validateBinding synBindingList && validateExpr synExpr - | SynExpr.TryWith (synExpr, - _range, - synMatchClauseList, - _range2, - _range3, - _sequencePointInfoForTry, - _sequencePointInfoForWith) -> + | SynExpr.TryWith (tryExpr = synExpr; withCases = synMatchClauseList) -> validateExpr synExpr && List.forall validateClause synMatchClauseList @@ -293,13 +264,13 @@ let isValidAST ast = | SynExpr.YieldOrReturnFrom (_, synExpr, _range) | SynExpr.DoBang (synExpr, _range) -> validateExpr synExpr - | SynExpr.LetOrUseBang (_sequencePointInfoForBinding, _, _, synPat, synExpr1, ands, synExpr2, _range) -> + | SynExpr.LetOrUseBang (pat = synPat; rhs = synExpr1; andBangs = ands; body = synExpr2) -> List.forall validateExpr [ synExpr1; synExpr2 ] && validatePattern synPat && List.forall (fun (pat, e) -> validateExpr e && validatePattern pat) (ands - |> List.map (fun (_, _, _, pat, e, _) -> pat, e)) + |> List.map (fun (SynExprAndBang (pat = pat; body = e)) -> pat, e)) | SynExpr.LibraryOnlyILAssembly _ | SynExpr.LibraryOnlyStaticOptimization _ @@ -331,11 +302,11 @@ let isValidAST ast = | SynPat.Attrib (pat, _attrib, _range) -> validatePattern pat | SynPat.Or (pat1, pat2, _range) -> validatePattern pat1 && validatePattern pat2 | SynPat.Ands (pats, _range) -> List.forall validatePattern pats - | SynPat.LongIdent (_, _, _, constructorArgs, _, _) -> validateConstructorArgs constructorArgs + | SynPat.LongIdent (argPats = constructorArgs) -> validateConstructorArgs constructorArgs | SynPat.Tuple (false, pats, _range) -> List.forall validatePattern pats | SynPat.Paren (pat, _range) -> validatePattern pat | SynPat.ArrayOrList (_isArray, pats, _range) -> List.forall validatePattern pats - | SynPat.Record (identPats, _range) -> List.forall (fun (_, pat) -> validatePattern pat) identPats + | SynPat.Record (identPats, _range) -> List.forall (fun (_, _, pat) -> validatePattern pat) identPats | SynPat.OptionalVal (_ident, _range) -> true | SynPat.IsInst (_typ, _range) -> true | SynPat.QuoteExpr (expr, _range) -> validateExpr expr @@ -347,7 +318,7 @@ let isValidAST ast = and validateConstructorArgs = function | SynArgPats.Pats pats -> List.forall validatePattern pats - | SynArgPats.NamePatPairs (identPats, _range) -> List.forall (snd >> validatePattern) identPats + | SynArgPats.NamePatPairs (identPats, _range) -> List.forall (fun (_, _, pat) -> validatePattern pat) identPats match ast with | ParsedInput.SigFile _input -> diff --git a/src/Fantomas/CodePrinter.fs b/src/Fantomas/CodePrinter.fs index df196400c1..adf7e11a92 100644 --- a/src/Fantomas/CodePrinter.fs +++ b/src/Fantomas/CodePrinter.fs @@ -264,7 +264,7 @@ and genSigModuleDeclList astContext (e: SynModuleSigDecl list) = |> finalContinuation) | s :: rest -> let sepNln = - sepNlnConsideringTriviaContentBeforeForMainNode (synModuleSigDeclToFsAstType s) s.FullRange + sepNlnConsideringTriviaContentBeforeForMainNode (synModuleSigDeclToFsAstType s) s.Range let expr = genSigModuleDecl astContext s @@ -424,7 +424,7 @@ and genSigModuleDecl astContext node = | SynModuleSigDecl.Open (SynOpenDeclTarget.ModuleOrNamespace _, _) -> genTriviaFor SynModuleSigDecl_Open node.Range | SynModuleSigDecl.Open (SynOpenDeclTarget.Type _, _) -> genTriviaFor SynModuleSigDecl_OpenType node.Range - | SynModuleSigDecl.Exception _ -> genTriviaFor SynModuleSigDecl_Exception node.FullRange + | SynModuleSigDecl.Exception _ -> genTriviaFor SynModuleSigDecl_Exception node.Range | _ -> id) and genAccess (Access s) = !-s @@ -560,9 +560,9 @@ and genLetBinding astContext pref b = let isRecursiveLetOrUseFunction = (pref = "and ") match b with - | LetBinding (ats, px, ao, isInline, isMutable, p, e, valInfo) -> + | LetBinding (ats, px, ao, isInline, isMutable, p, equalsRange, e, valInfo) -> match e, p with - | TypedExpr (Typed, e, t), PatLongIdent (ao, s, ps, tpso) when (List.isNotEmpty ps) -> + | TypedExpr (Typed, e, t), PatLongIdent (ao, s, _, ps, tpso) when (List.isNotEmpty ps) -> genSynBindingFunctionWithReturnType astContext false @@ -580,8 +580,9 @@ and genLetBinding astContext pref b = tpso t valInfo + equalsRange e - | e, PatLongIdent (ao, s, ps, tpso) when (List.isNotEmpty ps) -> + | e, PatLongIdent (ao, s, _, ps, tpso) when (List.isNotEmpty ps) -> genSynBindingFunction astContext false @@ -597,6 +598,7 @@ and genLetBinding astContext pref b = p.Range ps tpso + equalsRange e | TypedExpr (Typed, e, t), pat -> genSynBindingValue @@ -611,9 +613,21 @@ and genLetBinding astContext pref b = isMutable pat (Some t) + equalsRange e | _, PatTuple _ -> - genLetBindingDestructedTuple astContext isRecursiveLetOrUseFunction px ats pref ao isInline isMutable p e + genLetBindingDestructedTuple + astContext + isRecursiveLetOrUseFunction + px + ats + pref + ao + isInline + isMutable + p + equalsRange + e | _, pat -> genSynBindingValue astContext @@ -627,6 +641,7 @@ and genLetBinding astContext pref b = isMutable pat None + equalsRange e | _ -> sepNone | DoBinding (ats, px, e) -> @@ -643,7 +658,7 @@ and genLetBinding astContext pref b = | b -> failwithf "%O isn't a let binding" b +> leaveNodeFor (synBindingToFsAstType b) b.RangeOfBindingWithRhs -and genProperty astContext prefix ao propertyKind ps e = +and genProperty astContext (prefix: Context -> Context) ao propertyKind ps e = let tuplerize ps = let rec loop acc = function @@ -657,7 +672,7 @@ and genProperty astContext prefix ao propertyKind ps e = | [ PatTuple ps ] -> let ps, p = tuplerize ps - !-prefix +> opt sepSpace ao genAccess + prefix +> opt sepSpace ao genAccess -- propertyKind +> ifElse (List.atMostOne ps) @@ -670,15 +685,15 @@ and genProperty astContext prefix ao propertyKind ps e = +> genExprSepEqPrependType astContext e | ps -> - !-prefix +> opt sepSpace ao genAccess + prefix +> opt sepSpace ao genAccess -- propertyKind +> col sepSpace ps (genPat astContext) +> genExprSepEqPrependType astContext e -and genPropertyWithGetSet astContext (b1, b2) rangeOfMember = +and genPropertyWithGetSet astContext (b1, b2) = match b1, b2 with - | PropertyBinding (ats, px, ao, isInline, mf1, PatLongIdent (ao1, s1, ps1, _), e1, _), - PropertyBinding (_, _, _, _, _, PatLongIdent (ao2, _, ps2, _), e2, _) -> + | PropertyBinding (ats, px, ao, isInline, mf1, PatLongIdent (ao1, s1, pk1, ps1, _), eqR1, e1, _), + PropertyBinding (_, _, _, _, _, PatLongIdent (ao2, _, pk2, ps2, _), eqR2, e2, _) -> let prefix = genPreXmlDoc px +> genAttributes astContext ats @@ -691,17 +706,28 @@ and genPropertyWithGetSet astContext (b1, b2) rangeOfMember = let ps1 = List.map snd ps1 let ps2 = List.map snd ps2 + let genGet = genProperty astContext (genPropertyKeyword pk1) ao1 "get " ps1 e1 + let genSet = genProperty astContext (genPropertyKeyword pk2) ao2 "set " ps2 e2 + + let genGetSet = + match pk2 with + | Some (PropertyKeyword.With _) -> genSet +> sepNln +> genGet + | _ -> genGet +> sepNln +> genSet + prefix +> !-s1 +> indent +> sepNln - +> optSingle (fun rom -> enterNodeTokenByName rom WITH) rangeOfMember - +> genProperty astContext "with " ao1 "get " ps1 e1 - +> sepNln - +> genProperty astContext "and " ao2 "set " ps2 e2 + +> genGetSet +> unindent | _ -> sepNone +and genPropertyKeyword (pkw: PropertyKeyword option) (ctx: Context) = + match pkw with + | None -> ctx + | Some (PropertyKeyword.And r) -> (!- "and " |> genTriviaFor SynPat_LongIdent_And r) ctx + | Some (PropertyKeyword.With r) -> (!- "with " |> genTriviaFor SynPat_LongIdent_With r) ctx + and genMemberBindingList astContext node = let rec collectItems (node: SynBinding list) @@ -725,7 +751,7 @@ and genMemberBindingList astContext node = and genMemberBinding astContext b = match b with - | PropertyBinding (ats, px, ao, isInline, mf, p, e, synValInfo) -> + | PropertyBinding (ats, px, ao, isInline, mf, p, equalsRange, e, synValInfo) -> let prefix = genPreXmlDoc px +> genAttributes astContext ats @@ -740,7 +766,7 @@ and genMemberBinding astContext b = | mf -> failwithf "Unexpected member flags: %O" mf match p with - | PatLongIdent (ao, s, ps, _) -> + | PatLongIdent (ao, s, propertyKeyword, ps, _) -> assert (ps |> Seq.map fst |> Seq.forall Option.isNone) match ao, propertyKind, ps with @@ -748,29 +774,45 @@ and genMemberBinding astContext b = // Provide short-hand notation `x.Member = ...` for `x.Member with get()` getters let pat = match p with - | SynPat.LongIdent (lid, extraId, typarDecls, _, accessibility, range) -> - SynPat.LongIdent(lid, extraId, typarDecls, SynArgPats.Pats([]), accessibility, range) + | SynPat.LongIdent (lid, propertyKeyword, extraId, typarDecls, _, accessibility, range) -> + SynPat.LongIdent( + lid, + propertyKeyword, + extraId, + typarDecls, + SynArgPats.Pats([]), + accessibility, + range + ) | _ -> p let prefix = (onlyIfNot mf.IsInstance (!- "static ") +> !- "member ") - genMemberBindingImpl astContext prefix b ats px ao isInline pat e synValInfo + genMemberBindingImpl astContext prefix b ats px ao isInline pat equalsRange e synValInfo | _ -> let ps = List.map snd ps + let genPropertyKeyword ctx = + match propertyKeyword with + | None -> ctx + | Some (PropertyKeyword.And r) -> + // even if the keyword was `and` in the original source, due to transformations we always want to use `with` here. + (!- "with " |> genTriviaFor SynPat_LongIdent_And r) ctx + | Some (PropertyKeyword.With r) -> (!- "with " |> genTriviaFor SynPat_LongIdent_With r) ctx + prefix -- s +> indent +> sepNln - +> genProperty astContext "with " ao propertyKind ps e + +> genProperty astContext genPropertyKeyword ao propertyKind ps e +> unindent | p -> failwithf "Unexpected pattern: %O" p - | MemberBinding (ats, px, ao, isInline, mf, p, e, synValInfo) -> + | MemberBinding (ats, px, ao, isInline, mf, p, equalsRange, e, synValInfo) -> let prefix = genMemberFlagsForMemberBinding astContext mf b.RangeOfBindingWithRhs - genMemberBindingImpl astContext prefix b ats px ao isInline p e synValInfo + genMemberBindingImpl astContext prefix b ats px ao isInline p equalsRange e synValInfo | ExplicitCtor (ats, px, ao, p, e, so) -> let prefix = @@ -819,11 +861,12 @@ and genMemberBindingImpl (ao: SynAccess option) (isInline: bool) (p: SynPat) + (equalsRange: range option) (e: SynExpr) (synValInfo: SynValInfo) = match e, p with - | TypedExpr (Typed, e, t), PatLongIdent (ao, s, ps, tpso) when (List.isNotEmpty ps) -> + | TypedExpr (Typed, e, t), PatLongIdent (ao, s, _, ps, tpso) when (List.isNotEmpty ps) -> genSynBindingFunctionWithReturnType astContext true @@ -841,8 +884,9 @@ and genMemberBindingImpl tpso t synValInfo + equalsRange e - | e, PatLongIdent (ao, s, ps, tpso) when (List.isNotEmpty ps) -> + | e, PatLongIdent (ao, s, _, ps, tpso) when (List.isNotEmpty ps) -> genSynBindingFunction astContext true @@ -858,6 +902,7 @@ and genMemberBindingImpl p.Range ps tpso + equalsRange e | TypedExpr (Typed, e, t), pat -> genSynBindingValue @@ -872,6 +917,7 @@ and genMemberBindingImpl false pat (Some t) + equalsRange e | _, pat -> genSynBindingValue @@ -886,6 +932,7 @@ and genMemberBindingImpl false pat None + equalsRange e and genMemberFlags astContext (mf: SynMemberFlags) = @@ -955,9 +1002,11 @@ and genVal astContext (Val (ats, px, ao, s, identRange, t, vi, isInline, isMutab +> optSingle (fun e -> sepEq +> sepSpace +> genExpr astContext e) eo |> genTriviaFor SynValSig_ range -and genRecordFieldName astContext (RecordFieldName (s, eo) as node) = - let rfn, _, _ = node - let range = (fst rfn).Range +and genRecordFieldName + astContext + (SynExprRecordField ((LongIdentWithDots s as rfn, _), equalsRange, eo, _blockSeparator) as node) + = + let range = rfn.Range opt sepNone eo (fun e -> let expr = sepSpaceOrIndentAndNlnIfExpressionExceedsPageWidth (genExpr astContext e) @@ -1578,30 +1627,28 @@ and genExpr astContext synExpr ctx = |> genTriviaFor SynExpr_MatchLambda_Function keywordRange) +> sepNln +> genClauses astContext cs - | Match (e, cs) -> - let withRange = ctx.MkRange e.Range.Start (List.head cs).Range.Start - + | Match (matchRange, e, withRange, cs) -> let genMatchExpr = !- "match " +> expressionFitsOnRestOfLine (genExpr astContext e - +> genWithAfterMatch withRange) + +> genWithAfterMatch SynExpr_Match_With withRange) (genExprInIfOrMatch astContext e +> (sepNlnUnlessLastEventIsNewline - +> (genWithAfterMatch withRange))) + +> (genWithAfterMatch SynExpr_Match_With withRange))) atCurrentColumn (genMatchExpr +> sepNln +> genClauses astContext cs) - | MatchBang (e, cs) -> + | MatchBang (matchRange, e, withRange, cs) -> let withRange = ctx.MkRange e.Range.Start (List.head cs).Range.Start let genMatchExpr = !- "match! " +> expressionFitsOnRestOfLine (genExpr astContext e - +> genWithAfterMatch withRange) + +> genWithAfterMatch SynExpr_MatchBang_With withRange) (genExprInIfOrMatch astContext e +> (sepNlnUnlessLastEventIsNewline - +> (genWithAfterMatch withRange))) + +> (genWithAfterMatch SynExpr_MatchBang_With withRange))) atCurrentColumn (genMatchExpr +> sepNln +> genClauses astContext cs) | TraitCall (tps, msg, e) -> @@ -2226,20 +2273,15 @@ and genExpr astContext synExpr ctx = atCurrentColumn (colWithNlnWhenItemIsMultilineUsingConfig items) ctx // Could customize a bit if e is single line - | TryWith (e, mWithToLast, cs) -> + | TryWith (tryKeyword, e, withKeyword, mWithToLast, cs) -> atCurrentColumn ( kw TRY !- "try " +> indent +> sepNln +> genExpr astContext e +> unindent - +> (fun ctx -> - let lookupRange = - ctx.MkRangeWith - (mWithToLast.StartLine, mWithToLast.StartColumn) - (mWithToLast.StartLine, mWithToLast.StartColumn + 3) - - tokN lookupRange WITH !+~ "with" ctx) + +> sepNln // unless trivia? + +> genTriviaFor SynExpr_TryWith_With withKeyword (!- "with") +> indentOnWith +> sepNln +> col sepNln cs (genClause astContext true) @@ -2920,7 +2962,7 @@ and genMultilineRecordInstance (astContext: ASTContext) (openingBrace: Range) (inheritOpt: (SynType * SynExpr) option) - (xs: (RecordFieldName * SynExpr option * BlockSeparator option) list) + (xs: SynExprRecordField list) (eo: SynExpr option) (closingBrace: Range) (ctx: Context) @@ -2998,7 +3040,7 @@ and genMultilineRecordInstanceAlignBrackets (astContext: ASTContext) (openingBrace: Range) (inheritOpt: (SynType * SynExpr) option) - (xs: (RecordFieldName * SynExpr option * BlockSeparator option) list) + (xs: SynExprRecordField list) (eo: SynExpr option) (closingBrace: Range) = @@ -3445,8 +3487,8 @@ and genExprInIfOrMatch astContext (e: SynExpr) (ctx: Context) : Context = expressionFitsOnRestOfLine short long ctx -and genWithAfterMatch (withRange: Range) = - tokN withRange WITH (fun ctx -> +and genWithAfterMatch (astType: FsAstType) (withRange: Range) = + genTriviaFor astType withRange (fun ctx -> let hasContentOnLastLine = List.tryHead ctx.WriterModel.Lines |> Option.map String.isNotNullOrWhitespace @@ -3564,30 +3606,15 @@ and genInKeyword (binding: SynBinding) (e: SynExpr) (ctx: Context) = ctx | None -> sepNone ctx -and sepNlnBetweenTypeAndMembers (tdr: SynTypeDefnRepr) (ms: SynMemberDefn list) = +and sepNlnBetweenTypeAndMembers (withKeywordRange: range option) (ms: SynMemberDefn list) = match List.tryHead ms with - | Some m -> - let range, mainNodeType = - match m with - | SynMemberDefn.Interface (_, _, r) -> r, SynMemberDefn_Interface - | SynMemberDefn.Open (_, r) -> r, SynMemberDefn_Open - | SynMemberDefn.Member (_, r) -> r, SynMemberDefn_Member - | SynMemberDefn.ImplicitCtor (_, _, _, _, _, r) -> r, SynMemberDefn_ImplicitCtor - | SynMemberDefn.ImplicitInherit (_, _, _, r) -> r, SynMemberDefn_ImplicitInherit - | SynMemberDefn.LetBindings (_, _, _, r) -> r, SynMemberDefn_LetBindings - | SynMemberDefn.AbstractSlot (_, _, r) -> r, SynMemberDefn_AbstractSlot - | SynMemberDefn.Inherit (_, _, r) -> r, SynMemberDefn_Inherit - | SynMemberDefn.ValField (_, r) -> r, SynMemberDefn_ValField - | SynMemberDefn.NestedType (_, _, r) -> r, SynMemberDefn_NestedType - | SynMemberDefn.AutoProperty (_, _, _, _, _, _, _, _, _, _, r) -> r, SynMemberDefn_AutoProperty - - sepNlnTypeAndMembers tdr.Range.End range mainNodeType + | Some m -> sepNlnTypeAndMembers SynTypeDefn_With withKeywordRange m.Range (synMemberDefnToFsAstType m) | None -> sepNone and genTypeDefn astContext (isFirstTypeDefn: bool) - (TypeDef (ats, px, ao, tds, tcs, tdr, ms, s, preferPostfix) as node) + (TypeDef (ats, px, ao, tds, tcs, tdr, withKeyword, ms, s, preferPostfix) as node) = let typeName = genPreXmlDoc px @@ -3613,7 +3640,7 @@ and genTypeDefn tdr.Range (col sepNln ecs (genEnumCase astContext) +> onlyIf (List.isNotEmpty ms) sepNln - +> sepNlnBetweenTypeAndMembers tdr ms + +> sepNlnBetweenTypeAndMembers withKeyword ms +> genMemberDefnList { astContext with InterfaceRange = None } ms // Add newline after un-indent to be spacing-correct +> unindent) @@ -3657,7 +3684,7 @@ and genTypeDefn +> sepEq +> unionCases +> onlyIf (List.isNotEmpty ms) sepNln - +> sepNlnBetweenTypeAndMembers tdr ms + +> sepNlnBetweenTypeAndMembers withKeyword ms +> genMemberDefnList { astContext with InterfaceRange = None } ms +> unindent @@ -3671,8 +3698,16 @@ and genTypeDefn let multilineExpression = ifAlignBrackets - (genMultilineSimpleRecordTypeDefnAlignBrackets astContext openingBrace tdr ms ao' fs closingBrace) - (genMultilineSimpleRecordTypeDefn astContext openingBrace tdr ms ao' fs closingBrace) + (genMultilineSimpleRecordTypeDefnAlignBrackets + astContext + openingBrace + tdr + withKeyword + ms + ao' + fs + closingBrace) + (genMultilineSimpleRecordTypeDefn astContext openingBrace tdr withKeyword ms ao' fs closingBrace) let bodyExpr ctx = let size = getRecordSize ctx fs @@ -3714,7 +3749,7 @@ and genTypeDefn (indent ++ "with" +> indent +> sepNln - +> sepNlnBetweenTypeAndMembers tdr ms + +> sepNlnBetweenTypeAndMembers withKeyword ms +> genMemberDefnList { astContext with InterfaceRange = None } ms +> unindent +> unindent) @@ -3750,7 +3785,7 @@ and genTypeDefn +> genTypeDefKind tdk +> indent +> onlyIf (List.isNotEmpty others) sepNln - +> sepNlnBetweenTypeAndMembers tdr ms + +> sepNlnBetweenTypeAndMembers withKeyword ms +> genMemberDefnList astContext others +> unindent ++ "end" @@ -3791,7 +3826,7 @@ and genTypeDefn +> indent // Remember that we use MemberDefn of parent node +> sepNln - +> sepNlnBetweenTypeAndMembers tdr ms + +> sepNlnBetweenTypeAndMembers withKeyword ms +> genMemberDefnList { astContext with InterfaceRange = None } ms +> unindent @@ -3831,7 +3866,7 @@ and genTypeDefn | ExceptionRepr (ExceptionDefRepr (ats, px, ao, uc)) -> genExceptionBody astContext ats px ao uc |> genTriviaFor SynTypeDefn_ node.Range -and genMultilineSimpleRecordTypeDefn astContext openingBrace tdr ms ao' fs closingBrace = +and genMultilineSimpleRecordTypeDefn astContext openingBrace tdr withKeyword ms ao' fs closingBrace = // the typeName is already printed sepNlnUnlessLastEventIsNewline +> opt (indent +> sepNln) ao' genAccess @@ -3845,10 +3880,10 @@ and genMultilineSimpleRecordTypeDefn astContext openingBrace tdr ms ao' fs closi +> genTriviaFor SynTypeDefnSimpleRepr_Record_ClosingBrace closingBrace sepCloseS +> optSingle (fun _ -> unindent) ao' +> onlyIf (List.isNotEmpty ms) sepNln - +> sepNlnBetweenTypeAndMembers tdr ms + +> sepNlnBetweenTypeAndMembers withKeyword ms +> genMemberDefnList { astContext with InterfaceRange = None } ms -and genMultilineSimpleRecordTypeDefnAlignBrackets astContext openingBrace tdr ms ao' fs closingBrace = +and genMultilineSimpleRecordTypeDefnAlignBrackets astContext openingBrace tdr withKeyword ms ao' fs closingBrace = // the typeName is already printed sepNlnUnlessLastEventIsNewline +> opt (indent +> sepNln) ao' genAccess @@ -3865,27 +3900,18 @@ and genMultilineSimpleRecordTypeDefnAlignBrackets astContext openingBrace tdr ms +> genTriviaFor SynTypeDefnSimpleRepr_Record_ClosingBrace closingBrace sepCloseSFixed +> optSingle (fun _ -> unindent) ao' +> onlyIf (List.isNotEmpty ms) sepNln - +> sepNlnBetweenTypeAndMembers tdr ms + +> sepNlnBetweenTypeAndMembers withKeyword ms +> genMemberDefnList { astContext with InterfaceRange = None } ms -and sepNlnBetweenSigTypeAndMembers (synTypeDefnRepr: SynTypeDefnSigRepr) (ms: SynMemberSig list) : Context -> Context = +and sepNlnBetweenSigTypeAndMembers (withKeyword: range option) (ms: SynMemberSig list) : Context -> Context = match List.tryHead ms with - | Some m -> - let range, mainNodeType = - match m with - | SynMemberSig.Interface (_, r) -> r, SynMemberSig_Interface - | SynMemberSig.Inherit (_, r) -> r, SynMemberSig_Inherit - | SynMemberSig.Member (_, _, r) -> r, SynMemberSig_Member - | SynMemberSig.NestedType (_, r) -> r, SynMemberSig_NestedType - | SynMemberSig.ValField (_, r) -> r, SynMemberSig_ValField - - sepNlnTypeAndMembers synTypeDefnRepr.Range.End range mainNodeType + | Some m -> sepNlnTypeAndMembers SynTypeDefnSig_With withKeyword m.Range (synMemberSigToFsAstType m) | None -> sepNone and genSigTypeDefn astContext (isFirstSigTypeDefn: bool) - (SigTypeDef (ats, px, ao, tds, tcs, tdr, ms, s, _preferPostfix, fullRange)) + (SigTypeDef (ats, px, ao, tds, tcs, tdr, withKeyword, ms, s, _preferPostfix, fullRange)) = let genTriviaForOnelinerAttributes f (ctx: Context) = match ats with @@ -3916,7 +3942,7 @@ and genSigTypeDefn +> indent +> sepNln +> col sepNln ecs (genEnumCase astContext) - +> sepNlnBetweenSigTypeAndMembers tdr ms + +> sepNlnBetweenSigTypeAndMembers withKeyword ms +> colPre sepNln sepNln ms (genMemberSig astContext) // Add newline after un-indent to be spacing-correct +> unindent @@ -3957,7 +3983,7 @@ and genSigTypeDefn typeName +> sepEq +> unionCases - +> sepNlnBetweenSigTypeAndMembers tdr ms + +> sepNlnBetweenSigTypeAndMembers withKeyword ms +> colPre sepNln sepNln ms (genMemberSig astContext) +> unindent @@ -3971,8 +3997,8 @@ and genSigTypeDefn let multilineExpression = ifAlignBrackets - (genSigSimpleRecordAlignBrackets astContext openingBrace tdr ms ao' fs closingBrace) - (genSigSimpleRecord astContext openingBrace tdr ms ao' fs closingBrace) + (genSigSimpleRecordAlignBrackets astContext openingBrace tdr withKeyword ms ao' fs closingBrace) + (genSigSimpleRecord astContext openingBrace tdr withKeyword ms ao' fs closingBrace) let bodyExpr ctx = let size = getRecordSize ctx fs @@ -4000,7 +4026,7 @@ and genSigTypeDefn !- " with" +> indent +> sepNln - +> sepNlnBetweenSigTypeAndMembers tdr ms + +> sepNlnBetweenSigTypeAndMembers withKeyword ms +> col sepNln ms (genMemberSig astContext) +> unindent @@ -4072,7 +4098,7 @@ and genSigTypeDefn | SigExceptionRepr (SigExceptionDefRepr (ats, px, ao, uc)) -> genExceptionBody astContext ats px ao uc |> genTriviaFor SynTypeDefnSig_ fullRange -and genSigSimpleRecord astContext openingBrace tdr ms ao' fs closingBrace = +and genSigSimpleRecord astContext openingBrace tdr withKeyword ms ao' fs closingBrace = // the typeName is already printed sepNlnUnlessLastEventIsNewline +> opt (indent +> sepNln) ao' genAccess @@ -4085,10 +4111,10 @@ and genSigSimpleRecord astContext openingBrace tdr ms ao' fs closingBrace = ) +> genTriviaFor SynTypeDefnSimpleRepr_Record_ClosingBrace closingBrace sepCloseS +> optSingle (fun _ -> unindent) ao' - +> sepNlnBetweenSigTypeAndMembers tdr ms + +> sepNlnBetweenSigTypeAndMembers withKeyword ms +> colPre sepNln sepNln ms (genMemberSig astContext) -and genSigSimpleRecordAlignBrackets astContext openingBrace tdr ms ao' fs closingBrace = +and genSigSimpleRecordAlignBrackets astContext openingBrace tdr withKeyword ms ao' fs closingBrace = // the typeName is already printed sepNlnUnlessLastEventIsNewline +> opt (indent +> sepNln) ao' genAccess @@ -4104,7 +4130,7 @@ and genSigSimpleRecordAlignBrackets astContext openingBrace tdr ms ao' fs closin +> sepNln +> genTriviaFor SynTypeDefnSimpleRepr_Record_ClosingBrace closingBrace sepCloseSFixed +> optSingle (fun _ -> unindent) ao' - +> sepNlnBetweenSigTypeAndMembers tdr ms + +> sepNlnBetweenSigTypeAndMembers withKeyword ms +> colPre sepNln sepNln ms (genMemberSig astContext) and genMemberSig astContext node = @@ -4199,7 +4225,7 @@ and genExceptionBody astContext ats px ao uc = +> opt sepSpace ao genAccess +> genUnionCase astContext false uc -and genException astContext (ExceptionDef (ats, px, ao, uc, ms) as node) = +and genException astContext (ExceptionDef (ats, px, ao, uc, withKeyword, ms) as node) = genExceptionBody astContext ats px ao uc +> ifElse ms.IsEmpty @@ -4642,7 +4668,7 @@ and genMemberDefnList astContext nodes = let expr = enterNodeFor SynMemberDefn_Member rangeOfFirstMember - +> genPropertyWithGetSet astContext gs (Some rangeOfFirstMember) + +> genPropertyWithGetSet astContext gs let sepNln = sepNlnConsideringTriviaContentBeforeForMainNode SynMemberDefn_Member rangeOfFirstMember @@ -4898,7 +4924,7 @@ and genSimplePats astContext node = +> sepColon +> genType astContext false t -and genPatRecordFieldName astContext (PatRecordFieldName (s1, s2, p)) = +and genPatRecordFieldName astContext (PatRecordFieldName (s1, s2, equalsRange, p)) = ifElse (s1 = "") (!-(sprintf "%s = " s2)) (!-(sprintf "%s.%s = " s1 s2)) +> genPat { astContext with IsInsideMatchClausePattern = false } p // see issue 1252. @@ -4942,7 +4968,7 @@ and genPat astContext pat = genPat astContext p1 -- " as " +> genPat astContext p2 |> genTriviaFor SynPat_As r - | PatLongIdent (ao, s, ps, tpso) -> + | PatLongIdent (ao, s, _, ps, tpso) -> let aoc = opt sepSpace ao genAccess let tpsoc = @@ -5101,6 +5127,7 @@ and genSynBindingFunction (patRange: Range) (parameters: (string option * SynPat) list) (genericTypeParameters: SynValTyparDecls option) + (equalsRange: range option) (e: SynExpr) (ctx: Context) = @@ -5129,14 +5156,6 @@ and genSynBindingFunction +> opt sepNone genericTypeParameters (fun (ValTyparDecls (tds, _)) -> genTypeParamPostfix astContext tds) let genSignature = - let rangeBetweenBindingPatternAndExpression = - let endOfParameters = - List.last parameters - |> snd - |> fun p -> p.Range.End - - ctx.MkRange endOfParameters e.Range.Start - let spaceBeforeParameters = match parameters with | [] -> sepNone @@ -5149,7 +5168,7 @@ and genSynBindingFunction +> genFunctionName +> spaceBeforeParameters +> col sepSpace parameters (genPatWithIdent astContext) - +> tokN rangeBetweenBindingPatternAndExpression EQUALS sepEq + +> genEq SynBinding_Equals equalsRange let long (ctx: Context) = let genParameters, hasSingleTupledArg = @@ -5166,7 +5185,7 @@ and genSynBindingFunction +> sepNln +> genParameters +> ifElse (hasSingleTupledArg && not alternativeSyntax) sepSpace sepNln - +> tokN rangeBetweenBindingPatternAndExpression EQUALS sepEqFixed + +> genEqFixed SynBinding_Equals equalsRange +> unindent) ctx @@ -5204,6 +5223,7 @@ and genSynBindingFunctionWithReturnType (genericTypeParameters: SynValTyparDecls option) (returnType: SynType) (valInfo: SynValInfo) + (equalsRange: range option) (e: SynExpr) (ctx: Context) = @@ -5242,8 +5262,6 @@ and genSynBindingFunctionWithReturnType +> genType astContext false returnType let genSignature = - let equalsRange = ctx.MkRange returnType.Range.End e.Range.Start - let spaceBeforeParameters = match parameters with | [] -> sepNone @@ -5258,7 +5276,7 @@ and genSynBindingFunctionWithReturnType +> spaceBeforeParameters +> col sepSpace parameters (genPatWithIdent astContext) +> genReturnType false - +> tokN equalsRange EQUALS sepEq + +> genEq SynBinding_Equals equalsRange let long (ctx: Context) = let genParameters, hasSingleTupledArg = @@ -5276,7 +5294,7 @@ and genSynBindingFunctionWithReturnType +> genParameters +> onlyIf (not hasSingleTupledArg || alternativeSyntax) sepNln +> genReturnType (not hasSingleTupledArg || alternativeSyntax) - +> ifElse alternativeSyntax (sepNln +> tokN equalsRange EQUALS sepEqFixed) sepEq + +> ifElse alternativeSyntax (sepNln +> genEqFixed SynBinding_Equals equalsRange) sepEq +> unindent) ctx @@ -5306,6 +5324,7 @@ and genLetBindingDestructedTuple (isInline: bool) (isMutable: bool) (pat: SynPat) + (equalsRange: range option) (e: SynExpr) = let genAttrAndPref = @@ -5322,8 +5341,6 @@ and genLetBindingDestructedTuple let genDestructedTuples = expressionFitsOnRestOfLine (genPat astContext pat) (sepOpenT +> genPat astContext pat +> sepCloseT) - let equalsRange (ctx: Context) = ctx.MkRange pat.Range.End e.Range.Start - genPreXmlDoc px +> genAttrAndPref +> (fun ctx -> @@ -5331,7 +5348,7 @@ and genLetBindingDestructedTuple afterLetKeyword +> sepSpace +> genDestructedTuples - +> (fun ctx -> tokN (equalsRange ctx) EQUALS sepEq ctx) + +> genEq SynBinding_Equals equalsRange let long = prefix @@ -5356,6 +5373,7 @@ and genSynBindingValue (isMutable: bool) (valueName: SynPat) (returnType: SynType option) + (equalsRange: range option) (e: SynExpr) = let genAttrIsFirstChild = @@ -5375,25 +5393,19 @@ and genSynBindingValue let genValueName = genPat astContext valueName let genEqualsInBinding (ctx: Context) = - let equalsRange = - let endPos = - match returnType with - | Some rt -> rt.Range.End - | None -> valueName.Range.End - - ctx.MkRange endPos e.Range.Start - let space = - ctx.TriviaTokenNodes - |> Map.tryFindOrEmptyList EQUALS - |> fun triviaNodes -> - match TriviaHelpers.findInRange triviaNodes equalsRange with - | Some tn when (List.isNotEmpty tn.ContentAfter) -> sepNone - | _ -> sepSpace - - (tokN equalsRange EQUALS (sepSpace +> sepEqFixed) - +> space) - ctx + match equalsRange with + | None -> sepSpace + | Some eqR -> + ctx.TriviaMainNodes + |> Map.tryFindOrEmptyList SynBinding_Equals + |> List.tryFind (fun tn -> tn.Range = eqR) + |> fun triviaNode -> + match triviaNode with + | Some tn when (List.isNotEmpty tn.ContentAfter) -> sepNone + | _ -> sepSpace + + (genEq SynBinding_Equals equalsRange +> space) ctx let genReturnType = match returnType with @@ -5473,9 +5485,9 @@ and collectMultilineItemForSynExprKeepIndent else collectMultilineItemForSynExpr astContext inKeyWordTrivia e) |> List.collect id - | KeepIndentMatch (me, clauses, matchRange, matchTriviaType) -> + | KeepIndentMatch (me, withRange, clauses, matchRange, matchTriviaType) -> ColMultilineItem( - genKeepIndentMatch astContext me clauses matchRange matchTriviaType, + genKeepIndentMatch astContext me withRange clauses matchRange matchTriviaType, sepNlnConsideringTriviaContentBeforeForMainNode matchTriviaType matchRange ) |> List.singleton @@ -5501,18 +5513,22 @@ and genExprKeepIndentInBranch (astContext: ASTContext) (e: SynExpr) : Context -> and genKeepIndentMatch (astContext: ASTContext) (e: SynExpr) + (withRange: range) (clauses: SynMatchClause list) (matchRange: Range) (triviaType: FsAstType) : Context -> Context = - let withRange (ctx: Context) = - ctx.MkRange e.Range.Start (List.head clauses).Range.Start - let lastClauseIndex = clauses.Length - 1 + let isMatchBang = triviaType = SynExpr_MatchBang - ifElse (triviaType = SynExpr_MatchBang) !- "match! " !- "match " + ifElse isMatchBang !- "match! " !- "match " +> genExprInIfOrMatch astContext e - +> (fun ctx -> genWithAfterMatch (withRange ctx) ctx) + +> genWithAfterMatch + (if isMatchBang then + SynExpr_MatchBang_With + else + SynExpr_Match_With) + withRange +> sepNln +> coli sepNln clauses (fun idx -> if idx < lastClauseIndex then @@ -5816,3 +5832,13 @@ and sepCloseTFor (rpr: range option) (ctx: Context) = match rpr with | None -> ctx | Some rpr -> genTriviaFor SynExpr_Paren_ClosingParenthesis rpr sepCloseT ctx + +and genEq (nodeType: FsAstType) (range: range option) = + match range with + | None -> sepEq + | Some r -> genTriviaFor nodeType r sepEq + +and genEqFixed (nodeType: FsAstType) (range: range option) = + match range with + | None -> sepEqFixed + | Some r -> genTriviaFor nodeType r sepEqFixed diff --git a/src/Fantomas/Context.fs b/src/Fantomas/Context.fs index fa543962fc..fc940b78b5 100644 --- a/src/Fantomas/Context.fs +++ b/src/Fantomas/Context.fs @@ -1320,22 +1320,18 @@ let internal sepNlnForEmptyNamespace (namespaceRange: Range) ctx = | _ -> sepNln ctx let internal sepNlnTypeAndMembers - (lastPositionBeforeMembers: Position) + (withKeywordNodeType: FsAstType) + (withKeywordRange: range option) (firstMemberRange: Range) (mainNodeType: FsAstType) (ctx: Context) : Context = let triviaNodeOfWithKeyword: TriviaNode option = - let r = ctx.MkRange lastPositionBeforeMembers firstMemberRange.Start - - Map.tryFindOrEmptyList WITH ctx.TriviaTokenNodes - |> TriviaHelpers.``keyword token inside range`` r - |> List.choose (fun (_, tn) -> - if List.isNotEmpty tn.ContentBefore then - Some tn - else - None) - |> List.tryHead + withKeywordRange + |> Option.bind (fun r -> + ctx.TriviaMainNodes + |> Map.tryFindOrEmptyList withKeywordNodeType + |> List.tryFind (fun tn -> RangeHelpers.rangeEq r tn.Range)) match triviaNodeOfWithKeyword with | Some tn -> printContentBefore tn ctx diff --git a/src/Fantomas/SourceParser.fs b/src/Fantomas/SourceParser.fs index 6c7c95332c..839d6940d3 100644 --- a/src/Fantomas/SourceParser.fs +++ b/src/Fantomas/SourceParser.fs @@ -140,7 +140,7 @@ let (|OpNameFullInPattern|) (x: Identifier) = let s' = DecompileOpName s (if IsActivePatternName s - || IsInfixOperator s + || IsMangledInfixOperator s || IsPrefixOperator s || IsTernaryOperator s || s = "op_Dynamic" then @@ -164,7 +164,7 @@ let (|OpNameFull|) (x: Identifier) = (if IsActivePatternName s then s - elif IsInfixOperator s + elif IsMangledInfixOperator s || IsPrefixOperator s || IsTernaryOperator s || s = "op_Dynamic" then @@ -326,8 +326,12 @@ let (|Types|_|) = let (|NestedModule|_|) = function - | SynModuleDecl.NestedModule (SynComponentInfo (ats, _, _, LongIdent s, px, _, ao, _), isRecursive, xs, _, _) -> - Some(ats, px, ao, s, isRecursive, xs) + | SynModuleDecl.NestedModule (SynComponentInfo (ats, _, _, LongIdent s, px, _, ao, _), + isRecursive, + _equalsRange, + xs, + _, + _) -> Some(ats, px, ao, s, isRecursive, xs) | _ -> None let (|Exception|_|) = @@ -374,7 +378,7 @@ let (|SigTypes|_|) = let (|SigNestedModule|_|) = function - | SynModuleSigDecl.NestedModule (SynComponentInfo (ats, _, _, LongIdent s, px, _, ao, _), _, xs, _) -> + | SynModuleSigDecl.NestedModule (SynComponentInfo (ats, _, _, LongIdent s, px, _, ao, _), _, _equalsRange, xs, _) -> Some(ats, px, ao, s, xs) | _ -> None @@ -390,12 +394,18 @@ let (|ExceptionDefRepr|) (SynExceptionDefnRepr.SynExceptionDefnRepr (ats, uc, _, let (|SigExceptionDefRepr|) (SynExceptionDefnRepr.SynExceptionDefnRepr (ats, uc, _, px, ao, _)) = (ats, px, ao, uc) let (|ExceptionDef|) - (SynExceptionDefn.SynExceptionDefn (SynExceptionDefnRepr.SynExceptionDefnRepr (ats, uc, _, px, ao, _), ms, _)) + (SynExceptionDefn.SynExceptionDefn (SynExceptionDefnRepr.SynExceptionDefnRepr (ats, uc, _, px, ao, _), + withKeyword, + ms, + _)) = - (ats, px, ao, uc, ms) + (ats, px, ao, uc, withKeyword, ms) let (|SigExceptionDef|) - (SynExceptionSig.SynExceptionSig (SynExceptionDefnRepr.SynExceptionDefnRepr (ats, uc, _, px, ao, _), ms, _)) + (SynExceptionSig.SynExceptionSig (SynExceptionDefnRepr.SynExceptionDefnRepr (ats, uc, _, px, ao, _), + _withKeyword, + ms, + _)) = (ats, px, ao, uc, ms) @@ -409,7 +419,7 @@ let (|UnionCaseType|) = let (|Field|) (SynField (ats, isStatic, ido, t, isMutable, px, ao, _)) = (ats, px, ao, isStatic, isMutable, t, Option.map (|Ident|) ido) -let (|EnumCase|) (SynEnumCase (ats, Ident s, c, cr, px, r)) = (ats, px, s, c, cr, r) +let (|EnumCase|) (SynEnumCase (ats, Ident s, _equalsRange, c, cr, px, r)) = (ats, px, s, c, cr, r) // Member definitions (11 cases) @@ -460,24 +470,35 @@ let (|MDLetBindings|_|) = let (|MDAbstractSlot|_|) = function - | SynMemberDefn.AbstractSlot (SynValSig (ats, Ident s, tds, t, vi, _, _, px, ao, _, _), mf, _) -> + | SynMemberDefn.AbstractSlot (SynValSig (ats, Ident s, tds, t, vi, _, _, px, ao, _, _withKeyword, _), mf, _) -> Some(ats, px, ao, s, t, vi, tds, mf) | _ -> None let (|MDInterface|_|) = function - | SynMemberDefn.Interface (t, mdo, range) -> Some(t, mdo, range) + | SynMemberDefn.Interface (t, _withKeyword, mdo, range) -> Some(t, mdo, range) | _ -> None let (|MDAutoProperty|_|) = function - | SynMemberDefn.AutoProperty (ats, isStatic, Ident s, typeOpt, mk, memberKindToMemberFlags, px, ao, e, _, _) -> - Some(ats, px, ao, mk, e, s, isStatic, typeOpt, memberKindToMemberFlags) + | SynMemberDefn.AutoProperty (ats, + isStatic, + Ident s, + typeOpt, + mk, + memberKindToMemberFlags, + px, + ao, + _equalsRange, + e, + _withKeyword, + _, + _) -> Some(ats, px, ao, mk, e, s, isStatic, typeOpt, memberKindToMemberFlags) | _ -> None // Interface impl -let (|InterfaceImpl|) (SynInterfaceImpl (t, bs, range)) = (t, bs, range) +let (|InterfaceImpl|) (SynInterfaceImpl (t, _withKeywordRange, bs, range)) = (t, bs, range) // Bindings @@ -523,15 +544,26 @@ let (|MFMember|MFStaticMember|MFConstructor|MFOverride|) (mf: SynMemberFlags) = let (|DoBinding|LetBinding|MemberBinding|PropertyBinding|ExplicitCtor|) = function - | SynBinding (ao, _, _, _, ats, px, SynValData (Some MFConstructor, _, ido), pat, _, expr, _, _) -> + | SynBinding (ao, _, _, _, ats, px, SynValData (Some MFConstructor, _, ido), pat, _, _equalsRange, expr, _, _) -> ExplicitCtor(ats, px, ao, pat, expr, Option.map (|Ident|) ido) - | SynBinding (ao, _, isInline, _, ats, px, SynValData (Some (MFProperty _ as mf), synValInfo, _), pat, _, expr, _, _) -> - PropertyBinding(ats, px, ao, isInline, mf, pat, expr, synValInfo) - | SynBinding (ao, _, isInline, _, ats, px, SynValData (Some mf, synValInfo, _), pat, _, expr, _, _) -> - MemberBinding(ats, px, ao, isInline, mf, pat, expr, synValInfo) - | SynBinding (_, SynBindingKind.Do, _, _, ats, px, _, _, _, expr, _, _) -> DoBinding(ats, px, expr) - | SynBinding (ao, _, isInline, isMutable, attrs, px, SynValData (_, valInfo, _), pat, _, expr, _, _) -> - LetBinding(attrs, px, ao, isInline, isMutable, pat, expr, valInfo) + | SynBinding (ao, + _, + isInline, + _, + ats, + px, + SynValData (Some (MFProperty _ as mf), synValInfo, _), + pat, + _, + equalsRange, + expr, + _, + _) -> PropertyBinding(ats, px, ao, isInline, mf, pat, equalsRange, expr, synValInfo) + | SynBinding (ao, _, isInline, _, ats, px, SynValData (Some mf, synValInfo, _), pat, _, equalsRange, expr, _, _) -> + MemberBinding(ats, px, ao, isInline, mf, pat, equalsRange, expr, synValInfo) + | SynBinding (_, SynBindingKind.Do, _, _, ats, px, _, _, _, _equalsRange, expr, _, _) -> DoBinding(ats, px, expr) + | SynBinding (ao, _, isInline, isMutable, attrs, px, SynValData (_, valInfo, _), pat, _, equalsRange, expr, _, _) -> + LetBinding(attrs, px, ao, isInline, isMutable, pat, equalsRange, expr, valInfo) // Expressions (55 cases, lacking to handle 11 cases) @@ -609,7 +641,7 @@ let (|While|_|) = let (|For|_|) = function - | SynExpr.For (_, Ident s, e1, isUp, e2, e3, _) -> Some(s, e1, e2, e3, isUp) + | SynExpr.For (_, Ident s, _equalsRange, e1, isUp, e2, e3, _) -> Some(s, e1, e2, e3, isUp) | _ -> None let (|NullExpr|_|) = @@ -634,12 +666,12 @@ let (|TypeApp|_|) = let (|Match|_|) = function - | SynExpr.Match (_, e, cs, _) -> Some(e, cs) + | SynExpr.Match (matchKeyword, _, e, withKeyword, cs, _) -> Some(matchKeyword, e, withKeyword, cs) | _ -> None let (|MatchBang|_|) = function - | SynExpr.MatchBang (_, e, cs, _) -> Some(e, cs) + | SynExpr.MatchBang (matchKeyword, _, e, withKeyword, cs, _) -> Some(matchKeyword, e, withKeyword, cs) | _ -> None let (|Sequential|_|) = @@ -952,12 +984,13 @@ let rec collectComputationExpressionStatements [ yield! letBindings yield! bodyStatements ] |> finalContinuation) - | SynExpr.LetOrUseBang (_, isUse, _, pat, expr, andBangs, body, r) -> + | SynExpr.LetOrUseBang (_, isUse, _, pat, _equalsRange, expr, andBangs, body, r) -> let letOrUseBang = LetOrUseBangStatement(isUse, pat, expr, r) let andBangs = andBangs - |> List.map (fun (_, _, _, ap, ae, andRange) -> AndBangStatement(ap, ae, andRange)) + |> List.map (fun (SynExprAndBang (_, _, _, ap, _equalsRange, ae, andRange)) -> + AndBangStatement(ap, ae, andRange)) collectComputationExpressionStatements body (fun bodyStatements -> [ letOrUseBang @@ -1099,7 +1132,7 @@ let (|AnonRecord|_|) = let (|ObjExpr|_|) = function - | SynExpr.ObjExpr (t, eio, bd, ims, _, range) -> Some(t, eio, bd, ims, range) + | SynExpr.ObjExpr (t, eio, _withKeyword, bd, ims, _, range) -> Some(t, eio, bd, ims, range) | _ -> None let (|LongIdentSet|_|) = @@ -1109,7 +1142,8 @@ let (|LongIdentSet|_|) = let (|TryWith|_|) = function - | SynExpr.TryWith (e, _, cs, mWithToLast, _, _, _) -> Some(e, mWithToLast, cs) + | SynExpr.TryWith (tryKeyword, e, _, withKeyword, cs, mWithToLast, _, _, _) -> + Some(tryKeyword, e, withKeyword, mWithToLast, cs) | _ -> None let (|TryFinally|_|) = @@ -1217,14 +1251,16 @@ let (|PatAs|_|) = let (|PatLongIdent|_|) = function | SynPat.LongIdent (LongIdentWithDots.LongIdentWithDots (LongIdentOrKeyword (OpNameFullInPattern (s, _)), _), + propertyKeyword, _, tpso, xs, ao, _) -> match xs with - | SynArgPats.Pats ps -> Some(ao, s, List.map (fun p -> (None, p)) ps, tpso) - | SynArgPats.NamePatPairs (nps, _) -> Some(ao, s, List.map (fun (Ident ident, p) -> (Some ident, p)) nps, tpso) + | SynArgPats.Pats ps -> Some(ao, s, propertyKeyword, List.map (fun p -> (None, p)) ps, tpso) + | SynArgPats.NamePatPairs (nps, _) -> + Some(ao, s, propertyKeyword, List.map (fun (Ident ident, _equalsRange, p) -> (Some ident, p)) nps, tpso) | _ -> None let (|PatParen|_|) = @@ -1260,6 +1296,7 @@ let (|PatQuoteExpr|_|) = let (|PatExplicitCtor|_|) = function | SynPat.LongIdent (LongIdentWithDots.LongIdentWithDots ([ newIdent ], _), + _propertyKeyword, _, _, SynArgPats.Pats [ PatParen _ as pat ], @@ -1301,10 +1338,12 @@ let rec private skipGeneratedLambdas expr = and skipGeneratedMatch expr = match expr with - | SynExpr.Match (_, _, [ SynMatchClause.SynMatchClause (_, _, _, innerExpr, _, _) as clause ], matchRange) when - matchRange.Start = clause.Range.Start - -> - skipGeneratedMatch innerExpr + | SynExpr.Match (_matchKeyword, + _, + _, + _withKeyword, + [ SynMatchClause.SynMatchClause (_, _, _, innerExpr, _, _) as clause ], + matchRange) when matchRange.Start = clause.Range.Start -> skipGeneratedMatch innerExpr | _ -> expr let (|Lambda|_|) = @@ -1402,17 +1441,30 @@ let (|TCSimple|TCDelegate|) = | SynTypeDefnKind.Union -> TCSimple TCUnion | SynTypeDefnKind.Abbrev -> TCSimple TCAbbrev | SynTypeDefnKind.Opaque -> TCSimple TCOpaque - | SynTypeDefnKind.Augmentation -> TCSimple TCAugmentation + | SynTypeDefnKind.Augmentation _withKeyword -> TCSimple TCAugmentation | SynTypeDefnKind.IL -> TCSimple TCIL | SynTypeDefnKind.Delegate (t, vi) -> TCDelegate(t, vi) -let (|TypeDef|) (SynTypeDefn (SynComponentInfo (ats, tds, tcs, LongIdent s, px, preferPostfix, ao, _), tdr, ms, _, _)) = - (ats, px, ao, tds, tcs, tdr, ms, s, preferPostfix) +let (|TypeDef|) + (SynTypeDefn (SynComponentInfo (ats, tds, tcs, LongIdent s, px, preferPostfix, ao, _), + _equalsRange, + tdr, + withKeyword, + ms, + _, + _)) + = + (ats, px, ao, tds, tcs, tdr, withKeyword, ms, s, preferPostfix) let (|SigTypeDef|) - (SynTypeDefnSig (SynComponentInfo (ats, tds, tcs, LongIdent s, px, preferPostfix, ao, _), tdr, ms, range)) + (SynTypeDefnSig (SynComponentInfo (ats, tds, tcs, LongIdent s, px, preferPostfix, ao, _), + _equalsRange, + tdr, + withKeyword, + ms, + range)) = - (ats, px, ao, tds, tcs, tdr, ms, s, preferPostfix, range) + (ats, px, ao, tds, tcs, tdr, withKeyword, ms, s, preferPostfix, range) let (|TyparDecl|) (SynTyparDecl (ats, tp)) = (ats, tp) @@ -1575,6 +1627,7 @@ let (|Val|) px, ao, eo, + _withKeyword, range)) = (ats, px, ao, s, ident.idRange, t, vi, isInline, isMutable, typars, eo, range) @@ -1586,7 +1639,7 @@ let (|RecordFieldName|) ((LongIdentWithDots s, _): RecordFieldName, eo: SynExpr let (|AnonRecordFieldName|) (ident: Ident, e: SynExpr) = (ident.idRange, ident.idText, e) let (|AnonRecordFieldType|) (Ident s: Ident, t: SynType) = (s, t) -let (|PatRecordFieldName|) ((LongIdent s1, Ident s2), p) = (s1, s2, p) +let (|PatRecordFieldName|) ((LongIdent s1, Ident s2), equalsRange, p) = (s1, s2, equalsRange, p) let (|ValInfo|) (SynValInfo (aiss, ai)) = (aiss, ai) @@ -1609,7 +1662,7 @@ let (|FunType|) (t, ValInfo (argTypes, returnType)) = /// Probably we should use lexing information to improve its accuracy let (|Extern|_|) = function - | Let (LetBinding (ats, px, ao, _, _, PatLongIdent (_, s, [ _, PatTuple ps ], _), TypedExpr (Typed, _, t), _)) -> + | Let (LetBinding (ats, px, ao, _, _, PatLongIdent (_, s, _, [ _, PatTuple ps ], _), _, TypedExpr (Typed, _, t), _)) -> let hasDllImportAttr = ats |> List.exists (fun { Attributes = attrs } -> @@ -1739,12 +1792,12 @@ let private shouldNotIndentBranch e es = && isLongElseBranch e let (|KeepIndentMatch|_|) (e: SynExpr) = - let mapClauses matchExpr clauses range t = + let mapClauses matchExpr withKeyword clauses range t = match clauses with | [] -> None | [ (Clause (_, _, _, lastClause)) ] -> if shouldNotIndentBranch lastClause [] then - Some(matchExpr, clauses, range, t) + Some(matchExpr, withKeyword, clauses, range, t) else None | clauses -> @@ -1756,13 +1809,15 @@ let (|KeepIndentMatch|_|) (e: SynExpr) = let (Clause (_, _, _, lastClause)) = List.last clauses if shouldNotIndentBranch lastClause firstClauses then - Some(matchExpr, clauses, range, t) + Some(matchExpr, withKeyword, clauses, range, t) else None match e with - | Match (matchExpr, clauses) -> mapClauses matchExpr clauses e.Range SynExpr_Match - | MatchBang (matchExpr, clauses) -> mapClauses matchExpr clauses e.Range SynExpr_MatchBang + | Match (_matchKeyword, matchExpr, withKeyword, clauses) -> + mapClauses matchExpr withKeyword clauses e.Range SynExpr_Match + | MatchBang (_matchKeyword, matchExpr, withKeyword, clauses) -> + mapClauses matchExpr withKeyword clauses e.Range SynExpr_MatchBang | _ -> None let (|KeepIndentIfThenElse|_|) (e: SynExpr) = diff --git a/src/Fantomas/SourceTransformer.fs b/src/Fantomas/SourceTransformer.fs index 72a351e429..12e6ee5df7 100644 --- a/src/Fantomas/SourceTransformer.fs +++ b/src/Fantomas/SourceTransformer.fs @@ -100,16 +100,16 @@ let rec (|SigValL|_|) = /// Assume that PropertySet comes right after PropertyGet. let (|PropertyWithGetSet|_|) = function - | PropertyBinding (_, _, _, _, MFProperty PropertyGet, PatLongIdent (_, s1, _, _), _, _) as b1 :: bs -> + | PropertyBinding (_, _, _, _, MFProperty PropertyGet, PatLongIdent (_, s1, _, _, _), _, _, _) as b1 :: bs -> match bs with - | PropertyBinding (_, _, _, _, MFProperty PropertySet, PatLongIdent (_, s2, _, _), _, _) as b2 :: bs when + | PropertyBinding (_, _, _, _, MFProperty PropertySet, PatLongIdent (_, s2, _, _, _), _, _, _) as b2 :: bs when s1 = s2 -> Some((b1, b2), bs) | _ -> None - | PropertyBinding (_, _, _, _, MFProperty PropertySet, PatLongIdent (_, s2, _, _), _, _) as b2 :: bs -> + | PropertyBinding (_, _, _, _, MFProperty PropertySet, PatLongIdent (_, s2, _, _, _), _, _, _) as b2 :: bs -> match bs with - | PropertyBinding (_, _, _, _, MFProperty PropertyGet, PatLongIdent (_, s1, _, _), _, _) as b1 :: bs when + | PropertyBinding (_, _, _, _, MFProperty PropertyGet, PatLongIdent (_, s1, _, _, _), _, _, _) as b1 :: bs when s1 = s2 -> Some((b1, b2), bs) @@ -166,6 +166,14 @@ let synMemberDefnToFsAstType = | SynMemberDefn.NestedType _ -> SynMemberDefn_NestedType | SynMemberDefn.AutoProperty _ -> SynMemberDefn_AutoProperty +let synMemberSigToFsAstType = + function + | SynMemberSig.Interface _ -> SynMemberSig_Interface + | SynMemberSig.Inherit _ -> SynMemberSig_Inherit + | SynMemberSig.Member _ -> SynMemberSig_Member + | SynMemberSig.NestedType _ -> SynMemberSig_NestedType + | SynMemberSig.ValField _ -> SynMemberSig_ValField + let synConstToFsAstType = function | SynConst.Bool _ -> SynConst_Bool @@ -277,7 +285,7 @@ let synModuleSigDeclToFsAstType = | SynModuleSigDecl.NamespaceFragment _ -> SynModuleSigDecl_NamespaceFragment | SynModuleSigDecl.ModuleAbbrev _ -> SynModuleSigDecl_ModuleAbbrev -let synBindingToFsAstType (SynBinding (_, kind, _, _, _, _, _, _, _, _, _, _)) = +let synBindingToFsAstType (SynBinding (kind = kind)) = match kind with | SynBindingKind.StandaloneExpression -> SynBindingKind_StandaloneExpression | SynBindingKind.Normal -> SynBindingKind_Normal diff --git a/src/Fantomas/TokenParser.fs b/src/Fantomas/TokenParser.fs index 05ac947bfa..7930aba7ca 100644 --- a/src/Fantomas/TokenParser.fs +++ b/src/Fantomas/TokenParser.fs @@ -13,6 +13,7 @@ let private lineCommentTag = 8 let private commentTag = 3 let private greaterTag = 160 let private identTag = 192 +let private equalsTag = 69 // workaround for cases where tokenizer dont output "delayed" part of operator after ">." // See https://github.com/fsharp/FSharp.Compiler.Service/issues/874 @@ -1120,11 +1121,9 @@ let getTriviaFromTokens (mkRange: MkRange) (tokens: Token list) = |> List.sortBy (fun t -> t.Range.StartLine, t.Range.StartColumn) let private tokenNames = - [ "EQUALS" - "BAR" + [ "BAR" "TRY" "FINALLY" - "WITH" "MEMBER" "AND_BANG" "IN" ] @@ -1148,7 +1147,6 @@ let internal getFsToken tokenName = | "DOT_DOT_HAT" -> DOT_DOT_HAT | "ELIF" -> ELIF | "ELSE" -> ELSE - | "EQUALS" -> EQUALS | "FINALLY" -> FINALLY | "GREATER" -> GREATER | "IF" -> IF @@ -1170,7 +1168,6 @@ let internal getFsToken tokenName = | "QMARK_QMARK" -> QMARK_QMARK | "THEN" -> THEN | "TRY" -> TRY - | "WITH" -> WITH | _ -> failwithf "was not expecting token %s" tokenName let getTriviaNodesFromTokens (mkRange: MkRange) (tokens: Token list) = diff --git a/src/Fantomas/TriviaTypes.fs b/src/Fantomas/TriviaTypes.fs index e3a718a4a3..ffa6055e20 100644 --- a/src/Fantomas/TriviaTypes.fs +++ b/src/Fantomas/TriviaTypes.fs @@ -21,7 +21,6 @@ type FsTokenType = | DOT_DOT_HAT | ELIF | ELSE - | EQUALS | FINALLY | GREATER | IF @@ -43,7 +42,6 @@ type FsTokenType = | QMARK_QMARK | THEN | TRY - | WITH type Token = { TokenInfo: FSharpTokenInfo @@ -98,6 +96,7 @@ type FsAstType = | SynModuleDecl_ModuleAbbrev | SynModuleDecl_NestedModule | SynModuleDecl_NestedModule_AfterAttributesBeforeModuleName + | SynModuleDecl_NestedModule_Equals | SynModuleDecl_Let | SynModuleDecl_DoExpr | SynModuleDecl_Types @@ -119,10 +118,13 @@ type FsAstType = | SynExpr_Record_OpeningBrace | SynExpr_Record_ClosingBrace | SynExpr_AnonRecd + | SynExpr_AnonRecd_Field_Equals | SynExpr_New | SynExpr_ObjExpr + | SynExpr_ObjExpr_With | SynExpr_While | SynExpr_For + | SynExpr_For_Equals | SynExpr_ForEach // | SynExpr_ArrayOrListComputed generalized in SynExpr_ArrayOrList | SynExpr_ArrayOrList @@ -136,6 +138,8 @@ type FsAstType = | SynExpr_MatchLambda | SynExpr_MatchLambda_Function | SynExpr_Match + | SynExpr_Match_Match + | SynExpr_Match_With | SynExpr_Do | SynExpr_Do_Do | SynExpr_Assert @@ -146,6 +150,8 @@ type FsAstType = | SynExpr_TypeApp_Greater // | SynExpr_LetOrUse use first nested SynExpr | SynExpr_TryWith + | SynExpr_TryWith_Try + | SynExpr_TryWith_With | SynExpr_TryFinally | SynExpr_Lazy | SynExpr_Lazy_Lazy @@ -187,7 +193,13 @@ type FsAstType = | SynExpr_YieldOrReturnFrom_ReturnBang | SynExpr_YieldOrReturnFrom_YieldBang | SynExpr_LetOrUseBang + | SynExpr_LetOrUseBang_Equals + // Maybe a thing after https://github.com/dotnet/fsharp/issues/12619 + // | SynExprAndBang_ + | SynExprAndBang_Equals | SynExpr_MatchBang + | SynExpr_MatchBang_Match + | SynExpr_MatchBang_With | SynExpr_DoBang | SynExpr_DoBang_DoBang | SynExpr_LibraryOnlyILAssembly @@ -205,6 +217,7 @@ type FsAstType = | SynInterpolatedStringPart_String | SynInterpolatedStringPart_FillExpr | RecordField_ + | RecordField_Equals | AnonRecordField_ | AnonRecordTypeField_ | SynMemberSig_Member @@ -218,9 +231,14 @@ type FsAstType = | SynMatchClause_Arrow | ArgOptions_ | SynInterfaceImpl_ + | SynInterfaceImpl_With | SynTypeDefn_ | SynTypeDefn_AfterAttributesBeforeComponentInfo + | SynTypeDefn_Equals + | SynTypeDefn_With | SynTypeDefnSig_ + | SynTypeDefnSig_Equals + | SynTypeDefnSig_With // | SynTypeDefnSigRepr_ObjectModel use first nested node | SynTypeDefnSigRepr_Exception | SynMemberDefn_Open @@ -231,10 +249,13 @@ type FsAstType = | SynMemberDefn_LetBindings | SynMemberDefn_AbstractSlot | SynMemberDefn_Interface + | SynMemberDefn_Interface_With | SynMemberDefn_Inherit | SynMemberDefn_ValField | SynMemberDefn_NestedType | SynMemberDefn_AutoProperty + | SynMemberDefn_AutoProperty_Equals + | SynMemberDefn_AutoProperty_With | SynSimplePat_Id | SynSimplePat_Typed | SynSimplePat_Attrib @@ -244,6 +265,7 @@ type FsAstType = | SynBindingKind_Normal | SynBindingKind_Do | SynBinding_AfterAttributes_BeforeHeadPattern + | SynBinding_Equals | SynBindingReturnInfo_ | SynTyparDecls_PostfixList | SynTyparDecls_SinglePrefix @@ -251,6 +273,7 @@ type FsAstType = | SynTyparDecl_ // | Typar_ , unused | SynValSig_ + | SynValSig_With // | SynPat_Const, use SynConst instead | SynPat_Wild | SynPat_Named @@ -260,12 +283,15 @@ type FsAstType = // | SynPat_Or, use the inner patterns instead | SynPat_Ands | SynPat_LongIdent + | SynPat_LongIdent_And + | SynPat_LongIdent_With | SynPat_Tuple | SynPat_Paren | SynPat_Paren_OpeningParenthesis | SynPat_Paren_ClosingParenthesis | SynPat_ArrayOrList | SynPat_Record + | SynPat_Record_Field_Equals | SynPat_Null | SynPat_OptionalVal | SynPat_IsInst @@ -299,6 +325,7 @@ type FsAstType = | SynConst_SourceIdentifier | SynArgPats_Pats | SynArgPats_NamePatPairs + | SynArgPats_NamePatPairs_Equals | SynComponentInfo_ // | SynTypeDefnRepr_ObjectModel use first nested node // | SynTypeDefnRepr_Simple use first nested node @@ -312,6 +339,7 @@ type FsAstType = | SynTypeDefnKind_Abbrev | SynTypeDefnKind_Opaque | SynTypeDefnKind_Augmentation + | SynTypeDefnKind_Augmentation_With | SynTypeDefnKind_IL | SynTypeDefnKind_Delegate | SynTypeDefnSimpleRepr_None @@ -325,6 +353,7 @@ type FsAstType = | SynTypeDefnSimpleRepr_TypeAbbrev | SynTypeDefnSimpleRepr_Exception | SynExceptionDefn_ + | SynExceptionDefn_With | SynExceptionDefnRepr_ | SynAttribute_ | SynAttributeList_ @@ -332,6 +361,7 @@ type FsAstType = | SynUnionCaseKind_Fields | SynUnionCaseKind_FullType | SynEnumCase_ + | SynEnumCase_Equals | SynField_ | SynField_AfterAttributesBeforeIdentifier | SynType_LongIdent @@ -373,6 +403,7 @@ type FsAstType = | SynModuleSigDecl_ModuleAbbrev | SynModuleSigDecl_NestedModule | SynModuleSigDecl_NestedModule_AfterAttributesBeforeModuleName + | SynModuleSigDecl_NestedModule_Equals | SynModuleSigDecl_Types | SynModuleSigDecl_Open | SynModuleSigDecl_OpenType @@ -380,6 +411,7 @@ type FsAstType = | SynModuleSigDecl_Exception | SynModuleSigDecl_NamespaceFragment | SynExceptionSig_ + | SynExceptionSig_With | SynAccess_Private | SynAccess_Internal | SynAccess_Public From b565c8b9e0dbb1f604513b5bc0195e361366889a Mon Sep 17 00:00:00 2001 From: nojaf Date: Sat, 22 Jan 2022 10:14:13 +0100 Subject: [PATCH 03/16] Further process equals and with keyword range in AST. --- src/Fantomas.Tests/ClassTests.fs | 25 ++ src/Fantomas.Tests/KeepIndentInBranchTests.fs | 54 ++++ src/Fantomas.Tests/ModuleTests.fs | 38 +++ ...ineBlockBracketsOnSameColumnRecordTests.fs | 38 +++ src/Fantomas.Tests/PatternMatchingTests.fs | 56 ++++ src/Fantomas.Tests/RecordTests.fs | 51 ++++ src/Fantomas.Tests/TypeDeclarationTests.fs | 38 +++ src/Fantomas.Tests/UnionTests.fs | 36 +++ src/Fantomas/AstTransformer.fs | 8 +- src/Fantomas/CodePrinter.fs | 283 +++++++++++------- src/Fantomas/SourceParser.fs | 94 +++--- src/Fantomas/TriviaTypes.fs | 3 +- 12 files changed, 560 insertions(+), 164 deletions(-) diff --git a/src/Fantomas.Tests/ClassTests.fs b/src/Fantomas.Tests/ClassTests.fs index d9e7da3754..55995bc033 100644 --- a/src/Fantomas.Tests/ClassTests.fs +++ b/src/Fantomas.Tests/ClassTests.fs @@ -1048,3 +1048,28 @@ type Subject<'a> private () = /// Each notification is broadcasted to all subscribed observers. static member broadcast = new System.Reactive.Subjects.Subject<'a>() """ + +[] +let ``comments after equals sign in read/write property`` () = + formatSourceString + false + """ +type Foo() = + member this.MyReadWriteProperty + with get () = //comment get + myInternalValue + and set (value) = // comment set + myInternalValue <- value +""" + config + |> prepend newline + |> should + equal + """ +type Foo() = + member this.MyReadWriteProperty + with get () = //comment get + myInternalValue + and set (value) = // comment set + myInternalValue <- value +""" diff --git a/src/Fantomas.Tests/KeepIndentInBranchTests.fs b/src/Fantomas.Tests/KeepIndentInBranchTests.fs index adf4df59dc..4d4ed2322b 100644 --- a/src/Fantomas.Tests/KeepIndentInBranchTests.fs +++ b/src/Fantomas.Tests/KeepIndentInBranchTests.fs @@ -2147,3 +2147,57 @@ module Foo = leftSet.SymmetricExceptWith(FooBarBaz.keys rightThings) |> ignore """ + +[] +let ``comment after match keyword`` () = + formatSourceString + false + """ +match // comment + Stream.peel rest with +| None -> failwith "oh no" +| Some longName -> + +longName +|> Map.map (fun _ -> TypedTerm.force) +""" + config + |> prepend newline + |> should + equal + """ +match // comment + Stream.peel rest with +| None -> failwith "oh no" +| Some longName -> + +longName +|> Map.map (fun _ -> TypedTerm.force) +""" + +[] +let ``comment after match bang keyword`` () = + formatSourceString + false + """ +match! // comment + Stream.peel rest with +| None -> failwith "oh no" +| Some longName -> + +longName +|> Map.map (fun _ -> TypedTerm.force) +""" + config + |> prepend newline + |> should + equal + """ +match! // comment + Stream.peel rest with +| None -> failwith "oh no" +| Some longName -> + +longName +|> Map.map (fun _ -> TypedTerm.force) +""" diff --git a/src/Fantomas.Tests/ModuleTests.fs b/src/Fantomas.Tests/ModuleTests.fs index ac93d72c37..78339d36ee 100644 --- a/src/Fantomas.Tests/ModuleTests.fs +++ b/src/Fantomas.Tests/ModuleTests.fs @@ -741,3 +741,41 @@ module Input let modules = [ 109024; 137172; 80445; 80044 ] """ + +[] +let ``comment after equals sign in named module`` () = + formatSourceString + false + """ +module Foo = // comment + let bar = 9 +""" + config + |> prepend newline + |> should + equal + """ +module Foo = // comment + let bar = 9 +""" + +[] +let ``comment after equals sign in named module, signature file`` () = + formatSourceString + true + """ +namespace Meh + +module Foo = // comment + val bar : int +""" + config + |> prepend newline + |> should + equal + """ +namespace Meh + +module Foo = // comment + val bar: int +""" diff --git a/src/Fantomas.Tests/MultilineBlockBracketsOnSameColumnRecordTests.fs b/src/Fantomas.Tests/MultilineBlockBracketsOnSameColumnRecordTests.fs index a588fcecf2..0255c9305c 100644 --- a/src/Fantomas.Tests/MultilineBlockBracketsOnSameColumnRecordTests.fs +++ b/src/Fantomas.Tests/MultilineBlockBracketsOnSameColumnRecordTests.fs @@ -1229,3 +1229,41 @@ let x = Age = 41 |} """ + +[] +let ``comment after equals in record field`` () = + formatSourceString + false + """ +{ A = //comment + B } +""" + config + |> prepend newline + |> should + equal + """ +{ + A = //comment + B +} +""" + +[] +let ``comment after equals in anonymous record field`` () = + formatSourceString + false + """ +{| A = //comment + B |} +""" + config + |> prepend newline + |> should + equal + """ +{| + A = //comment + B +|} +""" diff --git a/src/Fantomas.Tests/PatternMatchingTests.fs b/src/Fantomas.Tests/PatternMatchingTests.fs index 51a936244c..9d64801fc9 100644 --- a/src/Fantomas.Tests/PatternMatchingTests.fs +++ b/src/Fantomas.Tests/PatternMatchingTests.fs @@ -2067,3 +2067,59 @@ let examineData x = | OnePartData (part1 = p1) -> p1 | TwoPartData (part1 = p1; part2 = p2) -> p1 + p2 """ + +[] +let ``comment after match keyword`` () = + formatSourceString + false + """ +match // foo + a with +| B b -> () +""" + config + |> prepend newline + |> should + equal + """ +match // foo + a with +| B b -> () +""" + +[] +let ``comment after match bang keyword`` () = + formatSourceString + false + """ +match! // foo + a with +| B b -> () +""" + config + |> prepend newline + |> should + equal + """ +match! // foo + a with +| B b -> () +""" + +[] +let ``comment after with keyword in match bang`` () = + formatSourceString + false + """ +match! + a with // foo +| B b -> () +""" + config + |> prepend newline + |> should + equal + """ +match! a with // foo +| B b -> () +""" diff --git a/src/Fantomas.Tests/RecordTests.fs b/src/Fantomas.Tests/RecordTests.fs index fb272d7acb..b33997e62b 100644 --- a/src/Fantomas.Tests/RecordTests.fs +++ b/src/Fantomas.Tests/RecordTests.fs @@ -1949,3 +1949,54 @@ let defaultTestOptions fwk common (o: DotNet.TestOptions) = Framework = fwk // Some "netcoreapp3.0" Configuration = DotNet.BuildConfiguration.Debug } """ + +[] +let ``comment after equals in record field`` () = + formatSourceString + false + """ +{ A = //comment + B } +""" + config + |> prepend newline + |> should + equal + """ +{ A = //comment + B } +""" + +[] +let ``comment after equals in anonymous record field`` () = + formatSourceString + false + """ +{| A = //comment + B |} +""" + config + |> prepend newline + |> should + equal + """ +{| A = //comment + B |} +""" + +[] +let ``comment after equals sign in record type definition`` () = + formatSourceString + false + """ +type Foo = // comment + { Bar: int } +""" + config + |> prepend newline + |> should + equal + """ +type Foo = // comment + { Bar: int } +""" diff --git a/src/Fantomas.Tests/TypeDeclarationTests.fs b/src/Fantomas.Tests/TypeDeclarationTests.fs index 09743b1e11..a34a017d2d 100644 --- a/src/Fantomas.Tests/TypeDeclarationTests.fs +++ b/src/Fantomas.Tests/TypeDeclarationTests.fs @@ -30,6 +30,44 @@ exception BuildException of string * list with override x.ToString() = x.Data0.ToString() + "\r\n" + (separated "\r\n" x.Data1) """ +[] +let ``comment after with keyword in exception type`` () = + formatSourceString + false + """ +exception FooException with // comment + member this.Bar () = () +""" + config + |> prepend newline + |> should + equal + """ +exception FooException with // comment + member this.Bar() = () +""" + +[] +let ``comment after with keyword in exception type in signature files`` () = + formatSourceString + true + """ +namespace Moon + +exception FooException with // comment + member Bar: unit -> unit +""" + config + |> prepend newline + |> should + equal + """ +namespace Moon + +exception FooException with // comment + member Bar: unit -> unit +""" + [] let ``type annotations`` () = formatSourceString diff --git a/src/Fantomas.Tests/UnionTests.fs b/src/Fantomas.Tests/UnionTests.fs index f94d2c2b79..cda6fafb32 100644 --- a/src/Fantomas.Tests/UnionTests.fs +++ b/src/Fantomas.Tests/UnionTests.fs @@ -859,3 +859,39 @@ type TransactionType = | [] ExternalCreditBalanceRefund | [] CreditBalanceAdjustmentAppliedFromCreditBalance """ + +[] +let ``comment after equals in enum`` () = + formatSourceString + false + """ +type Foo = // comment + | Bar = // other comment + 1 +""" + config + |> prepend newline + |> should + equal + """ +type Foo = // comment + | Bar = // other comment + 1 +""" + +[] +let ``comment after equals in union`` () = + formatSourceString + false + """ +type Foo = // comment + | Bar of string * int64 +""" + config + |> prepend newline + |> should + equal + """ +type Foo = // comment + | Bar of string * int64 +""" diff --git a/src/Fantomas/AstTransformer.fs b/src/Fantomas/AstTransformer.fs index c3decefad6..cd5b041d08 100644 --- a/src/Fantomas/AstTransformer.fs +++ b/src/Fantomas/AstTransformer.fs @@ -632,7 +632,7 @@ module private Ast = visitSynExpr expr @ (Option.toList ident |> List.map visitIdent) - and visitRecordField (SynExprRecordField ((fieldName, _), equalsRange, synExprOption, blockSeparator)) = + and visitRecordField (SynExprRecordField ((fieldName, _), equalsRange, synExprOption, _blockSeparator)) = [ yield mkNode RecordField_ fieldName.Range yield! mkNodeOption RecordField_Equals equalsRange yield! @@ -988,11 +988,7 @@ module private Ast = | SynPat.Record (pats, range) -> let continuations: ((TriviaNodeAssigner list -> TriviaNodeAssigner list) -> TriviaNodeAssigner list) list = - pats - |> List.map (fun (_, equalsRange, pat) -> - fun nodes -> - mkNode SynPat_Record_Field_Equals equalsRange - :: visit pat nodes) + pats |> List.map (fun (_, _, pat) -> visit pat) let finalContinuation (nodes: TriviaNodeAssigner list list) : TriviaNodeAssigner list = mkNode SynPat_Record range diff --git a/src/Fantomas/CodePrinter.fs b/src/Fantomas/CodePrinter.fs index adf7e11a92..088070b291 100644 --- a/src/Fantomas/CodePrinter.fs +++ b/src/Fantomas/CodePrinter.fs @@ -348,7 +348,7 @@ and genModuleDecl astContext (node: SynModuleDecl) = | ModuleAbbrev (s1, s2) -> !- "module " -- s1 +> sepEq +> sepSpace -- s2 | NamespaceFragment m -> failwithf "NamespaceFragment hasn't been implemented yet: %O" m - | NestedModule (ats, px, ao, s, isRecursive, mds) -> + | NestedModule (ats, px, ao, s, isRecursive, equalsRange, mds) -> genPreXmlDoc px +> genAttributes astContext ats +> genAfterAttributesBefore @@ -358,7 +358,7 @@ and genModuleDecl astContext (node: SynModuleDecl) = +> opt sepSpace ao genAccess +> ifElse isRecursive (!- "rec ") sepNone -- s - +> sepEq + +> genEq SynModuleDecl_NestedModule_Equals equalsRange +> indent +> sepNln +> genModuleDeclList astContext mds @@ -389,7 +389,7 @@ and genSigModuleDecl astContext node = | SigVal v -> genVal astContext v | SigModuleAbbrev (s1, s2) -> !- "module " -- s1 +> sepEq +> sepSpace -- s2 | SigNamespaceFragment m -> failwithf "NamespaceFragment is not supported yet: %O" m - | SigNestedModule (ats, px, ao, s, mds) -> + | SigNestedModule (ats, px, ao, s, equalsRange, mds) -> genPreXmlDoc px +> genAttributes astContext ats +> genAfterAttributesBefore @@ -398,7 +398,7 @@ and genSigModuleDecl astContext node = -- "module " +> opt sepSpace ao genAccess -- s - +> sepEq + +> genEq SynModuleSigDecl_NestedModule_Equals equalsRange +> indent +> sepNln +> genSigModuleDeclList astContext mds @@ -510,15 +510,20 @@ and genPreXmlDoc (PreXmlDoc lines) ctx = else ctx -and genExprSepEqPrependType (astContext: ASTContext) (e: SynExpr) = +and genExprSepEqPrependType + (astContext: ASTContext) + (equalsAstType: FsAstType) + (equalsRange: range option) + (e: SynExpr) + = match e with | TypedExpr (Typed, e, t) -> sepColon +> genType astContext false t - +> sepEq + +> genEq equalsAstType equalsRange +> sepSpaceOrIndentAndNlnIfExpressionExceedsPageWidth (genExpr astContext e) | _ -> - sepEq + genEq equalsAstType equalsRange +> sepSpaceOrIndentAndNlnIfExpressionExceedsPageWidth (genExpr astContext e) and genTyparList astContext tps = @@ -658,7 +663,16 @@ and genLetBinding astContext pref b = | b -> failwithf "%O isn't a let binding" b +> leaveNodeFor (synBindingToFsAstType b) b.RangeOfBindingWithRhs -and genProperty astContext (prefix: Context -> Context) ao propertyKind ps e = +and genProperty + astContext + (prefix: Context -> Context) + ao + propertyKind + ps + (equalsAstType: FsAstType) + (equalsRange: range option) + e + = let tuplerize ps = let rec loop acc = function @@ -682,13 +696,13 @@ and genProperty astContext (prefix: Context -> Context) ao propertyKind ps e = +> sepCloseT +> sepSpace) +> genPat astContext p - +> genExprSepEqPrependType astContext e + +> genExprSepEqPrependType astContext equalsAstType equalsRange e | ps -> prefix +> opt sepSpace ao genAccess -- propertyKind +> col sepSpace ps (genPat astContext) - +> genExprSepEqPrependType astContext e + +> genExprSepEqPrependType astContext equalsAstType equalsRange e and genPropertyWithGetSet astContext (b1, b2) = match b1, b2 with @@ -706,8 +720,11 @@ and genPropertyWithGetSet astContext (b1, b2) = let ps1 = List.map snd ps1 let ps2 = List.map snd ps2 - let genGet = genProperty astContext (genPropertyKeyword pk1) ao1 "get " ps1 e1 - let genSet = genProperty astContext (genPropertyKeyword pk2) ao2 "set " ps2 e2 + let genGet = + genProperty astContext (genPropertyKeyword pk1) ao1 "get " ps1 SynBinding_Equals eqR1 e1 + + let genSet = + genProperty astContext (genPropertyKeyword pk2) ao2 "set " ps2 SynBinding_Equals eqR2 e2 let genGetSet = match pk2 with @@ -805,7 +822,7 @@ and genMemberBinding astContext b = prefix -- s +> indent +> sepNln - +> genProperty astContext genPropertyKeyword ao propertyKind ps e + +> genProperty astContext genPropertyKeyword ao propertyKind ps SynBinding_Equals equalsRange e +> unindent | p -> failwithf "Unexpected pattern: %O" p @@ -814,7 +831,7 @@ and genMemberBinding astContext b = genMemberBindingImpl astContext prefix b ats px ao isInline p equalsRange e synValInfo - | ExplicitCtor (ats, px, ao, p, e, so) -> + | ExplicitCtor (ats, px, ao, p, equalsRange, e, so) -> let prefix = let genPat ctx = match p with @@ -836,7 +853,7 @@ and genMemberBinding astContext b = // Handle special "then" block i.e. fake sequential expressions in constructors | Sequential (e1, e2, false) -> prefix - +> sepEq + +> genEq SynBinding_Equals equalsRange +> indent +> sepNln +> genExpr astContext e1 @@ -846,7 +863,7 @@ and genMemberBinding astContext b = | e -> prefix - +> sepEq + +> genEq SynBinding_Equals equalsRange +> sepSpaceOrIndentAndNlnIfExpressionExceedsPageWidth (genExpr astContext e) | b -> failwithf "%O isn't a member binding" b @@ -1004,20 +1021,24 @@ and genVal astContext (Val (ats, px, ao, s, identRange, t, vi, isInline, isMutab and genRecordFieldName astContext - (SynExprRecordField ((LongIdentWithDots s as rfn, _), equalsRange, eo, _blockSeparator) as node) + (SynExprRecordField ((LongIdentWithDots s as rfn, _), equalsRange, eo, _blockSeparator)) = let range = rfn.Range opt sepNone eo (fun e -> let expr = sepSpaceOrIndentAndNlnIfExpressionExceedsPageWidth (genExpr astContext e) - !-s +> sepEq +> expr) + !-s + +> genEq RecordField_Equals equalsRange + +> expr) |> genTriviaFor RecordField_ range -and genAnonRecordFieldName astContext (AnonRecordFieldName (r, s, e)) = +and genAnonRecordFieldName astContext (AnonRecordFieldName (s, r, equalsRange, e)) = let expr = sepSpaceOrIndentAndNlnIfExpressionExceedsPageWidth (genExpr astContext e) - genTriviaFor Ident_ r !-s +> sepEq +> expr + genTriviaFor Ident_ r !-s + +> genEq SynExpr_AnonRecd_Field_Equals equalsRange + +> expr and genTuple astContext es = let genShortExpr astContext e = @@ -1438,7 +1459,7 @@ and genExpr astContext synExpr ctx = let size = getRecordSize ctx fields isSmallExpression size smallExpression longExpression ctx - | ObjExpr (t, eio, bd, ims, range) -> + | ObjExpr (t, eio, withKeyword, bd, ims, range) -> if List.isEmpty bd then // Check the role of the second part of eio let param = opt sepNone (Option.map fst eio) (genExpr astContext) @@ -1451,8 +1472,8 @@ and genExpr astContext synExpr ctx = +> sepCloseS else ifAlignBrackets - (genObjExprAlignBrackets t eio bd ims range astContext) - (genObjExpr t eio bd ims range astContext) + (genObjExprAlignBrackets t eio withKeyword bd ims range astContext) + (genObjExpr t eio withKeyword bd ims range astContext) | While (e1, e2) -> atCurrentColumn ( @@ -1463,9 +1484,11 @@ and genExpr astContext synExpr ctx = +> unindent ) - | For (s, e1, e2, e3, isUp) -> + | For (s, equalsRange, e1, e2, e3, isUp) -> atCurrentColumn ( - !-(sprintf "for %s = " s) + !- $"for %s{s}" + +> genEq SynExpr_For_Equals equalsRange + +> sepSpace +> genExpr astContext e1 +> ifElse isUp (!- " to ") (!- " downto ") +> genExpr astContext e2 @@ -1532,25 +1555,27 @@ and genExpr astContext synExpr ctx = | LetOrUseStatement (prefix, binding) -> enterNodeFor (synBindingToFsAstType binding) binding.RangeOfBindingWithRhs +> genLetBinding astContext prefix binding - | LetOrUseBangStatement (isUse, pat, expr, r) -> + | LetOrUseBangStatement (isUse, pat, equalsRange, expr, r) -> enterNodeFor SynExpr_LetOrUseBang r // print Trivia before entire LetBang expression +> ifElse isUse (!- "use! ") (!- "let! ") +> genPat astContext pat - -- " = " + +> genEq SynExpr_LetOrUseBang_Equals equalsRange + +> sepSpace +> autoIndentAndNlnIfExpressionExceedsPageWidth (genExpr astContext expr) - | AndBangStatement (pat, expr, andRange) -> + | AndBangStatement (pat, equalsRange, expr, andRange) -> enterNodeTokenByName andRange AND_BANG +> !- "and! " +> genPat astContext pat - -- " = " + +> genEq SynExprAndBang_Equals (Some equalsRange) + +> sepSpace +> autoIndentAndNlnIfExpressionExceedsPageWidth (genExpr astContext expr) | OtherStatement expr -> genExpr astContext expr let getRangeOfCompExprStatement ces = match ces with | LetOrUseStatement (_, binding) -> binding.RangeOfBindingWithRhs - | LetOrUseBangStatement (_, _, _, r) -> r - | AndBangStatement (_, _, r) -> r + | LetOrUseBangStatement (range = r) -> r + | AndBangStatement (range = r) -> r | OtherStatement expr -> expr.Range let getSepNln ces r = @@ -1629,26 +1654,28 @@ and genExpr astContext synExpr ctx = +> genClauses astContext cs | Match (matchRange, e, withRange, cs) -> let genMatchExpr = - !- "match " - +> expressionFitsOnRestOfLine - (genExpr astContext e - +> genWithAfterMatch SynExpr_Match_With withRange) - (genExprInIfOrMatch astContext e - +> (sepNlnUnlessLastEventIsNewline - +> (genWithAfterMatch SynExpr_Match_With withRange))) + genTriviaFor SynExpr_Match_Match matchRange !- "match " + +> autoIndentAndNlnWhenWriteBeforeNewlineNotEmpty ( + expressionFitsOnRestOfLine + (genExpr astContext e + +> genWithAfterMatch SynExpr_Match_With withRange) + (genExprInIfOrMatch astContext e + +> (sepNlnUnlessLastEventIsNewline + +> (genWithAfterMatch SynExpr_Match_With withRange))) + ) atCurrentColumn (genMatchExpr +> sepNln +> genClauses astContext cs) | MatchBang (matchRange, e, withRange, cs) -> - let withRange = ctx.MkRange e.Range.Start (List.head cs).Range.Start - let genMatchExpr = - !- "match! " - +> expressionFitsOnRestOfLine - (genExpr astContext e - +> genWithAfterMatch SynExpr_MatchBang_With withRange) - (genExprInIfOrMatch astContext e - +> (sepNlnUnlessLastEventIsNewline - +> (genWithAfterMatch SynExpr_MatchBang_With withRange))) + genTriviaFor SynExpr_MatchBang_Match matchRange !- "match! " + +> autoIndentAndNlnWhenWriteBeforeNewlineNotEmpty ( + expressionFitsOnRestOfLine + (genExpr astContext e + +> genWithAfterMatch SynExpr_MatchBang_With withRange) + (genExprInIfOrMatch astContext e + +> (sepNlnUnlessLastEventIsNewline + +> (genWithAfterMatch SynExpr_MatchBang_With withRange))) + ) atCurrentColumn (genMatchExpr +> sepNln +> genClauses astContext cs) | TraitCall (tps, msg, e) -> @@ -2273,9 +2300,9 @@ and genExpr astContext synExpr ctx = atCurrentColumn (colWithNlnWhenItemIsMultilineUsingConfig items) ctx // Could customize a bit if e is single line - | TryWith (tryKeyword, e, withKeyword, mWithToLast, cs) -> + | TryWith (tryKeyword, e, withKeyword, cs) -> atCurrentColumn ( - kw TRY !- "try " + genTriviaFor SynExpr_TryWith_Try tryKeyword !- "try " +> indent +> sepNln +> genExpr astContext e @@ -3115,7 +3142,7 @@ and genMultilineAnonRecord (isStruct: bool) fields copyInfo (astContext: ASTCont atCurrentColumn (sepOpenAnonRecd - +> col sepSemiNln fields (fun (AnonRecordFieldName (r, s, e)) -> + +> col sepSemiNln fields (fun (AnonRecordFieldName (s, r, eq, e)) -> let expr = if ctx.Config.IndentSize < 3 then sepSpaceOrDoubleIndentAndNlnIfExpressionExceedsPageWidth (genExpr astContext e) @@ -3126,7 +3153,7 @@ and genMultilineAnonRecord (isStruct: bool) fields copyInfo (astContext: ASTCont // Use a double indent when using a small indent size to avoid offset warnings. addFixedSpaces targetColumn +> atCurrentColumn (genTriviaFor Ident_ r (!-s)) - +> sepEq + +> genEq SynExpr_AnonRecd_Field_Equals eq +> expr) +> sepCloseAnonRecd) ctx @@ -3165,14 +3192,16 @@ and genMultilineAnonRecordAlignBrackets (isStruct: bool) fields copyInfo astCont ifElse isStruct !- "struct " sepNone +> atCurrentColumnIndent genAnonRecord -and genObjExpr t eio bd ims range (astContext: ASTContext) = +and genObjExpr t eio withKeyword bd ims range (astContext: ASTContext) = // Check the role of the second part of eio let param = opt sepNone (Option.map fst eio) (genExpr astContext) sepOpenS +> atCurrentColumn ( - !- "new " +> genType astContext false t +> param - -- " with" + !- "new " + +> genType astContext false t + +> param + +> genTriviaForOption SynExpr_ObjExpr_With withKeyword !- " with" +> indent +> sepNln +> genMemberBindingList { astContext with InterfaceRange = Some range } bd @@ -3181,14 +3210,16 @@ and genObjExpr t eio bd ims range (astContext: ASTContext) = ) +> sepCloseS -and genObjExprAlignBrackets t eio bd ims range (astContext: ASTContext) = +and genObjExprAlignBrackets t eio withKeyword bd ims range (astContext: ASTContext) = // Check the role of the second part of eio let param = opt sepNone (Option.map fst eio) (genExpr astContext) let genObjExpr = atCurrentColumn ( - !- "new " +> genType astContext false t +> param - -- " with" + !- "new " + +> genType astContext false t + +> param + +> genTriviaForOption SynExpr_ObjExpr_With withKeyword !- " with" +> indent +> sepNln +> genMemberBindingList { astContext with InterfaceRange = Some range } bd @@ -3614,7 +3645,7 @@ and sepNlnBetweenTypeAndMembers (withKeywordRange: range option) (ms: SynMemberD and genTypeDefn astContext (isFirstTypeDefn: bool) - (TypeDef (ats, px, ao, tds, tcs, tdr, withKeyword, ms, s, preferPostfix) as node) + (TypeDef (ats, px, ao, tds, tcs, equalsRange, tdr, withKeyword, ms, s, preferPostfix) as node) = let typeName = genPreXmlDoc px @@ -3632,7 +3663,7 @@ and genTypeDefn match tdr with | Simple (TDSREnum ecs) -> typeName - +> sepEq + +> genEq SynTypeDefn_Equals equalsRange +> indent +> sepNln +> genTriviaFor @@ -3681,7 +3712,7 @@ and genTypeDefn <| ctx typeName - +> sepEq + +> genEq SynTypeDefn_Equals equalsRange +> unionCases +> onlyIf (List.isNotEmpty ms) sepNln +> sepNlnBetweenTypeAndMembers withKeyword ms @@ -3722,11 +3753,9 @@ and genTypeDefn multilineExpression ctx typeName - +> sepEq + +> genEq SynTypeDefn_Equals equalsRange +> indent - +> enterNodeFor SynTypeDefnSimpleRepr_Record tdr.Range - +> bodyExpr - +> leaveNodeFor SynTypeDefnSimpleRepr_Record tdr.Range + +> genTriviaFor SynTypeDefnSimpleRepr_Record tdr.Range bodyExpr +> unindent | Simple TDSRNone -> typeName @@ -3758,7 +3787,10 @@ and genTypeDefn autoIndentAndNlnIfExpressionExceedsPageWidth genTypeAbbrev +> genMembers - typeName +> sepEq +> sepSpace +> genTypeBody + typeName + +> genEq SynTypeDefn_Equals equalsRange + +> sepSpace + +> genTypeBody | Simple (TDSRException (ExceptionDefRepr (ats, px, ao, uc))) -> genExceptionBody astContext ats px ao uc | ObjectModel (TCSimple (TCInterface @@ -3807,7 +3839,7 @@ and genTypeDefn typeName +> opt sepNone impCtor (genMemberDefn astContext) - +> sepEq + +> genEq SynTypeDefn_Equals equalsRange +> indent +> sepNln +> genTypeDefKind tdk @@ -3821,8 +3853,9 @@ and genTypeDefn +> genMemberDefnList astContext ms +> unindent - | ObjectModel (TCSimple TCAugmentation, _, _) -> - typeName -- " with" + | ObjectModel (TCSimple (TCAugmentation withKeywordAug), _, _) -> + typeName + +> genTriviaFor SynTypeDefnKind_Augmentation_With withKeywordAug !- " with" +> indent // Remember that we use MemberDefn of parent node +> sepNln @@ -3832,7 +3865,7 @@ and genTypeDefn | ObjectModel (TCDelegate (FunType ts), _, _) -> typeName - +> sepEq + +> genEq SynTypeDefn_Equals equalsRange +> sepSpace +> !- "delegate of " +> genTypeList astContext ts @@ -3840,12 +3873,12 @@ and genTypeDefn | ObjectModel (TCSimple TCUnspecified, MemberDefnList (impCtor, others), _) when not (List.isEmpty ms) -> typeName +> opt sepNone impCtor (genMemberDefn { astContext with InterfaceRange = None }) - +> sepEq + +> genEq SynTypeDefn_Equals equalsRange +> indent +> sepNln +> genMemberDefnList { astContext with InterfaceRange = None } others +> sepNln - -- "with" + +> genTriviaForOption SynTypeDefn_With withKeyword !- "with" +> indent +> sepNln +> genMemberDefnList { astContext with InterfaceRange = None } ms @@ -3857,7 +3890,7 @@ and genTypeDefn +> opt sepNone impCtor (fun mdf -> sepSpaceBeforeClassConstructor +> genMemberDefn { astContext with InterfaceRange = None } mdf) - +> sepEq + +> genEq SynTypeDefn_Equals equalsRange +> indent +> sepNln +> genMemberDefnList { astContext with InterfaceRange = None } others @@ -3911,7 +3944,7 @@ and sepNlnBetweenSigTypeAndMembers (withKeyword: range option) (ms: SynMemberSig and genSigTypeDefn astContext (isFirstSigTypeDefn: bool) - (SigTypeDef (ats, px, ao, tds, tcs, tdr, withKeyword, ms, s, _preferPostfix, fullRange)) + (SigTypeDef (ats, px, ao, tds, tcs, equalsRange, tdr, withKeyword, ms, s, _preferPostfix, fullRange)) = let genTriviaForOnelinerAttributes f (ctx: Context) = match ats with @@ -3938,7 +3971,7 @@ and genSigTypeDefn match tdr with | SigSimple (TDSREnum ecs) -> typeName - +> sepEq + +> genEq SynTypeDefnSig_Equals equalsRange +> indent +> sepNln +> col sepNln ecs (genEnumCase astContext) @@ -3981,7 +4014,7 @@ and genSigTypeDefn ctx typeName - +> sepEq + +> genEq SynTypeDefnSig_Equals equalsRange +> unionCases +> sepNlnBetweenSigTypeAndMembers withKeyword ms +> colPre sepNln sepNln ms (genMemberSig astContext) @@ -4013,7 +4046,7 @@ and genSigTypeDefn multilineExpression ctx typeName - +> sepEq + +> genEq SynTypeDefnSig_Equals equalsRange +> indent +> genTriviaFor SynTypeDefnSimpleRepr_Record tdr.Range bodyExpr +> unindent @@ -4044,14 +4077,14 @@ and genSigTypeDefn let short = genTypeAndParam astContext s tds tcs - +> sepEq + +> genEq SynTypeDefnSig_Equals equalsRange +> sepSpace +> genTypeAbbrev let long = genTypeAndParam astContext s tds tcs +> sepSpace - +> sepEqFixed + +> genEqFixed SynTypeDefnSig_Equals equalsRange +> indent +> sepNln +> genTypeAbbrev @@ -4066,7 +4099,7 @@ and genSigTypeDefn | TCClass) as tdk, mds) -> typeName - +> sepEq + +> genEq SynTypeDefnSig_Equals equalsRange +> indent +> sepNln +> genTypeDefKind tdk @@ -4076,8 +4109,9 @@ and genSigTypeDefn ++ "end" +> unindent - | SigObjectModel (TCSimple TCAugmentation, _) -> - typeName -- " with" + | SigObjectModel (TCSimple (TCAugmentation withKeyword), _) -> + typeName + +> genTriviaFor SynTypeDefnKind_Augmentation_With withKeyword !- " with" +> indent +> sepNln // Remember that we use MemberSig of parent node @@ -4085,11 +4119,14 @@ and genSigTypeDefn +> unindent | SigObjectModel (TCDelegate (FunType ts), _) -> - typeName +> sepEq +> sepSpace -- "delegate of " + typeName + +> genEq SynTypeDefnSig_Equals equalsRange + +> sepSpace + -- "delegate of " +> genTypeList astContext ts | SigObjectModel (_, mds) -> typeName - +> sepEq + +> genEq SynTypeDefnSig_Equals equalsRange +> indent +> sepNln +> col sepNln mds (genMemberSig astContext) @@ -4215,7 +4252,7 @@ and genTypeDefKind node = | TCSimple TCUnion -> sepNone | TCSimple TCAbbrev -> sepNone | TCSimple TCOpaque -> sepNone - | TCSimple TCAugmentation -> sepNone + | TCSimple (TCAugmentation _) -> sepNone | TCSimple TCIL -> sepNone | TCDelegate _ -> sepNone @@ -4230,16 +4267,22 @@ and genException astContext (ExceptionDef (ats, px, ao, uc, withKeyword, ms) as +> ifElse ms.IsEmpty sepNone - (!- " with" + (genTriviaForOption SynExceptionDefn_With withKeyword (!- " with") +> indent +> sepNln +> genMemberDefnList { astContext with InterfaceRange = None } ms +> unindent) |> genTriviaFor SynExceptionDefn_ node.Range -and genSigException astContext (SigExceptionDef (ats, px, ao, uc, ms)) = +and genSigException astContext (SigExceptionDef (ats, px, ao, uc, withKeyword, ms)) = genExceptionBody astContext ats px ao uc - +> colPre sepNln sepNln ms (genMemberSig astContext) + +> onlyIfNot + ms.IsEmpty + (genTriviaForOption SynExceptionSig_With withKeyword (!- " with") + +> indent + +> sepNln + +> col sepNln ms (genMemberSig astContext) + +> unindent) and genUnionCase astContext (hasVerticalBar: bool) (UnionCase (ats, px, _, s, UnionCaseType fs) as node) = let shortExpr = @@ -4260,9 +4303,11 @@ and genUnionCase astContext (hasVerticalBar: bool) (UnionCase (ats, px, _, s, Un +> onlyIf (List.isNotEmpty fs) (expressionFitsOnRestOfLine shortExpr longExpr) |> genTriviaFor SynUnionCase_ node.Range -and genEnumCase astContext (EnumCase (ats, px, identInAST, c, cr, r) as node) = +and genEnumCase astContext (EnumCase (ats, px, identInAST, equalsRange, c, cr, r) as node) = let genCase = - !-identInAST +> !- " = " +> genConst c cr + (!-identInAST + +> genEq SynEnumCase_Equals (Some equalsRange) + +> autoIndentAndNlnWhenWriteBeforeNewlineNotEmpty (sepSpace +> genConst c cr)) |> genTriviaFor SynEnumCase_ r genPreXmlDoc px @@ -4592,12 +4637,13 @@ and genTypeConstraint astContext node = +> col sepComma ts (genType astContext false) -- ">" -and genInterfaceImpl astContext (InterfaceImpl (t, bs, range)) = +and genInterfaceImpl astContext (InterfaceImpl (t, withKeywordRange, bs, range)) = match bs with | [] -> !- "interface " +> genType astContext false t | bs -> - !- "interface " +> genType astContext false t - -- " with" + !- "interface " + +> genType astContext false t + +> genTriviaForOption SynInterfaceImpl_With withKeywordRange !- " with" +> indent +> sepNln +> genMemberBindingList { astContext with InterfaceRange = Some range } bs @@ -4820,17 +4866,17 @@ and genMemberDefn astContext node = colWithNlnWhenItemIsMultilineUsingConfig items - | MDInterface (t, mdo, range) -> + | MDInterface (t, withKeyword, mdo, range) -> !- "interface " +> genType astContext false t +> opt sepNone mdo (fun mds -> - !- " with" + genTriviaForOption SynMemberDefn_Interface_With withKeyword !- " with" +> indent +> sepNln +> genMemberDefnList { astContext with InterfaceRange = Some range } mds +> unindent) - | MDAutoProperty (ats, px, ao, mk, e, s, _isStatic, typeOpt, memberKindToMemberFlags) -> + | MDAutoProperty (ats, px, ao, mk, equalsRange, e, _withKeyword, s, _isStatic, typeOpt, memberKindToMemberFlags) -> let isFunctionProperty = match typeOpt with | Some (TFun _) -> true @@ -4843,7 +4889,7 @@ and genMemberDefn astContext node = +> opt sepSpace ao genAccess -- s +> optPre sepColon sepNone typeOpt (genType astContext false) - +> sepEq + +> genEq SynMemberDefn_AutoProperty_Equals (Some equalsRange) +> sepSpaceOrIndentAndNlnIfExpressionExceedsPageWidth ( genExpr astContext e -- genPropertyKind (not isFunctionProperty) mk @@ -4924,12 +4970,17 @@ and genSimplePats astContext node = +> sepColon +> genType astContext false t -and genPatRecordFieldName astContext (PatRecordFieldName (s1, s2, equalsRange, p)) = +and genPatRecordFieldName astContext (PatRecordFieldName (s1, s2, p)) = ifElse (s1 = "") (!-(sprintf "%s = " s2)) (!-(sprintf "%s.%s = " s1 s2)) +> genPat { astContext with IsInsideMatchClausePattern = false } p // see issue 1252. and genPatWithIdent astContext (ido, p) = - opt (sepEq +> sepSpace) ido (!-) + optSingle + (fun (s, eqR) -> + !-s + +> genEq SynArgPats_NamePatPairs_Equals (Some eqR) + +> sepSpace) + ido +> genPat astContext p and genPat astContext pat = @@ -5125,7 +5176,7 @@ and genSynBindingFunction (isMutable: bool) (functionName: string) (patRange: Range) - (parameters: (string option * SynPat) list) + (parameters: ((string * range) option * SynPat) list) (genericTypeParameters: SynValTyparDecls option) (equalsRange: range option) (e: SynExpr) @@ -5219,7 +5270,7 @@ and genSynBindingFunctionWithReturnType (isMutable: bool) (functionName: string) (patRange: Range) - (parameters: (string option * SynPat) list) + (parameters: ((string * range) option * SynPat) list) (genericTypeParameters: SynValTyparDecls option) (returnType: SynType) (valInfo: SynValInfo) @@ -5485,10 +5536,10 @@ and collectMultilineItemForSynExprKeepIndent else collectMultilineItemForSynExpr astContext inKeyWordTrivia e) |> List.collect id - | KeepIndentMatch (me, withRange, clauses, matchRange, matchTriviaType) -> + | KeepIndentMatch (matchKeywordRange, me, withRange, clauses, range, matchTriviaType) -> ColMultilineItem( - genKeepIndentMatch astContext me withRange clauses matchRange matchTriviaType, - sepNlnConsideringTriviaContentBeforeForMainNode matchTriviaType matchRange + genKeepIndentMatch astContext matchKeywordRange me withRange clauses range matchTriviaType, + sepNlnConsideringTriviaContentBeforeForMainNode matchTriviaType range ) |> List.singleton | KeepIndentIfThenElse (branches, elseBranch, ifElseRange) -> @@ -5512,30 +5563,36 @@ and genExprKeepIndentInBranch (astContext: ASTContext) (e: SynExpr) : Context -> and genKeepIndentMatch (astContext: ASTContext) + (matchKeyword: range) (e: SynExpr) (withRange: range) (clauses: SynMatchClause list) - (matchRange: Range) + (range: Range) (triviaType: FsAstType) : Context -> Context = let lastClauseIndex = clauses.Length - 1 let isMatchBang = triviaType = SynExpr_MatchBang - ifElse isMatchBang !- "match! " !- "match " - +> genExprInIfOrMatch astContext e - +> genWithAfterMatch - (if isMatchBang then - SynExpr_MatchBang_With - else - SynExpr_Match_With) - withRange + ifElse + isMatchBang + (genTriviaFor SynExpr_MatchBang_Match matchKeyword !- "match! ") + (genTriviaFor SynExpr_Match_Match matchKeyword !- "match ") + +> autoIndentAndNlnWhenWriteBeforeNewlineNotEmpty ( + genExprInIfOrMatch astContext e + +> genWithAfterMatch + (if isMatchBang then + SynExpr_MatchBang_With + else + SynExpr_Match_With) + withRange + ) +> sepNln +> coli sepNln clauses (fun idx -> if idx < lastClauseIndex then genClause astContext true else genLastClauseKeepIdent astContext) - |> genTriviaFor triviaType matchRange + |> genTriviaFor triviaType range and genLastClauseKeepIdent (astContext: ASTContext) (Clause (pat, whenExpr, arrowRange, expr)) = sepBar diff --git a/src/Fantomas/SourceParser.fs b/src/Fantomas/SourceParser.fs index 839d6940d3..942e76b111 100644 --- a/src/Fantomas/SourceParser.fs +++ b/src/Fantomas/SourceParser.fs @@ -328,10 +328,10 @@ let (|NestedModule|_|) = function | SynModuleDecl.NestedModule (SynComponentInfo (ats, _, _, LongIdent s, px, _, ao, _), isRecursive, - _equalsRange, + equalsRange, xs, _, - _) -> Some(ats, px, ao, s, isRecursive, xs) + _) -> Some(ats, px, ao, s, isRecursive, equalsRange, xs) | _ -> None let (|Exception|_|) = @@ -378,8 +378,8 @@ let (|SigTypes|_|) = let (|SigNestedModule|_|) = function - | SynModuleSigDecl.NestedModule (SynComponentInfo (ats, _, _, LongIdent s, px, _, ao, _), _, _equalsRange, xs, _) -> - Some(ats, px, ao, s, xs) + | SynModuleSigDecl.NestedModule (SynComponentInfo (ats, _, _, LongIdent s, px, _, ao, _), _, equalsRange, xs, _) -> + Some(ats, px, ao, s, equalsRange, xs) | _ -> None let (|SigException|_|) = @@ -403,11 +403,11 @@ let (|ExceptionDef|) let (|SigExceptionDef|) (SynExceptionSig.SynExceptionSig (SynExceptionDefnRepr.SynExceptionDefnRepr (ats, uc, _, px, ao, _), - _withKeyword, + withKeyword, ms, _)) = - (ats, px, ao, uc, ms) + (ats, px, ao, uc, withKeyword, ms) let (|UnionCase|) (SynUnionCase (ats, Ident s, uct, px, ao, _)) = (ats, px, ao, s, uct) @@ -419,7 +419,7 @@ let (|UnionCaseType|) = let (|Field|) (SynField (ats, isStatic, ido, t, isMutable, px, ao, _)) = (ats, px, ao, isStatic, isMutable, t, Option.map (|Ident|) ido) -let (|EnumCase|) (SynEnumCase (ats, Ident s, _equalsRange, c, cr, px, r)) = (ats, px, s, c, cr, r) +let (|EnumCase|) (SynEnumCase (ats, Ident s, equalsRange, c, cr, px, r)) = (ats, px, s, equalsRange, c, cr, r) // Member definitions (11 cases) @@ -470,13 +470,13 @@ let (|MDLetBindings|_|) = let (|MDAbstractSlot|_|) = function - | SynMemberDefn.AbstractSlot (SynValSig (ats, Ident s, tds, t, vi, _, _, px, ao, _, _withKeyword, _), mf, _) -> + | SynMemberDefn.AbstractSlot (SynValSig (ats, Ident s, tds, t, vi, _, _, px, ao, _, _, _), mf, _) -> Some(ats, px, ao, s, t, vi, tds, mf) | _ -> None let (|MDInterface|_|) = function - | SynMemberDefn.Interface (t, _withKeyword, mdo, range) -> Some(t, mdo, range) + | SynMemberDefn.Interface (t, withKeyword, mdo, range) -> Some(t, withKeyword, mdo, range) | _ -> None let (|MDAutoProperty|_|) = @@ -489,16 +489,17 @@ let (|MDAutoProperty|_|) = memberKindToMemberFlags, px, ao, - _equalsRange, + equalsRange, e, - _withKeyword, + withKeyword, _, - _) -> Some(ats, px, ao, mk, e, s, isStatic, typeOpt, memberKindToMemberFlags) + _) -> + Some(ats, px, ao, mk, equalsRange, e, withKeyword, s, isStatic, typeOpt, memberKindToMemberFlags) | _ -> None // Interface impl -let (|InterfaceImpl|) (SynInterfaceImpl (t, _withKeywordRange, bs, range)) = (t, bs, range) +let (|InterfaceImpl|) (SynInterfaceImpl (t, withKeywordRange, bs, range)) = (t, withKeywordRange, bs, range) // Bindings @@ -544,8 +545,8 @@ let (|MFMember|MFStaticMember|MFConstructor|MFOverride|) (mf: SynMemberFlags) = let (|DoBinding|LetBinding|MemberBinding|PropertyBinding|ExplicitCtor|) = function - | SynBinding (ao, _, _, _, ats, px, SynValData (Some MFConstructor, _, ido), pat, _, _equalsRange, expr, _, _) -> - ExplicitCtor(ats, px, ao, pat, expr, Option.map (|Ident|) ido) + | SynBinding (ao, _, _, _, ats, px, SynValData (Some MFConstructor, _, ido), pat, _, equalsRange, expr, _, _) -> + ExplicitCtor(ats, px, ao, pat, equalsRange, expr, Option.map (|Ident|) ido) | SynBinding (ao, _, isInline, @@ -561,7 +562,7 @@ let (|DoBinding|LetBinding|MemberBinding|PropertyBinding|ExplicitCtor|) = _) -> PropertyBinding(ats, px, ao, isInline, mf, pat, equalsRange, expr, synValInfo) | SynBinding (ao, _, isInline, _, ats, px, SynValData (Some mf, synValInfo, _), pat, _, equalsRange, expr, _, _) -> MemberBinding(ats, px, ao, isInline, mf, pat, equalsRange, expr, synValInfo) - | SynBinding (_, SynBindingKind.Do, _, _, ats, px, _, _, _, _equalsRange, expr, _, _) -> DoBinding(ats, px, expr) + | SynBinding (_, SynBindingKind.Do, _, _, ats, px, _, _, _, _, expr, _, _) -> DoBinding(ats, px, expr) | SynBinding (ao, _, isInline, isMutable, attrs, px, SynValData (_, valInfo, _), pat, _, equalsRange, expr, _, _) -> LetBinding(attrs, px, ao, isInline, isMutable, pat, equalsRange, expr, valInfo) @@ -641,7 +642,7 @@ let (|While|_|) = let (|For|_|) = function - | SynExpr.For (_, Ident s, _equalsRange, e1, isUp, e2, e3, _) -> Some(s, e1, e2, e3, isUp) + | SynExpr.For (_, Ident s, equalsRange, e1, isUp, e2, e3, _) -> Some(s, equalsRange, e1, e2, e3, isUp) | _ -> None let (|NullExpr|_|) = @@ -968,8 +969,8 @@ let rec (|LetOrUses|_|) = type ComputationExpressionStatement = | LetOrUseStatement of prefix: string * binding: SynBinding - | LetOrUseBangStatement of isUse: bool * SynPat * SynExpr * range - | AndBangStatement of SynPat * SynExpr * range + | LetOrUseBangStatement of isUse: bool * SynPat * equalsRange: range option * SynExpr * range: range + | AndBangStatement of SynPat * equalsRange: range * SynExpr * range: range | OtherStatement of SynExpr let rec collectComputationExpressionStatements @@ -984,13 +985,13 @@ let rec collectComputationExpressionStatements [ yield! letBindings yield! bodyStatements ] |> finalContinuation) - | SynExpr.LetOrUseBang (_, isUse, _, pat, _equalsRange, expr, andBangs, body, r) -> - let letOrUseBang = LetOrUseBangStatement(isUse, pat, expr, r) + | SynExpr.LetOrUseBang (_, isUse, _, pat, equalsRange, expr, andBangs, body, r) -> + let letOrUseBang = LetOrUseBangStatement(isUse, pat, equalsRange, expr, r) let andBangs = andBangs - |> List.map (fun (SynExprAndBang (_, _, _, ap, _equalsRange, ae, andRange)) -> - AndBangStatement(ap, ae, andRange)) + |> List.map (fun (SynExprAndBang (_, _, _, ap, equalsRange, ae, andRange)) -> + AndBangStatement(ap, equalsRange, ae, andRange)) collectComputationExpressionStatements body (fun bodyStatements -> [ letOrUseBang @@ -1132,7 +1133,7 @@ let (|AnonRecord|_|) = let (|ObjExpr|_|) = function - | SynExpr.ObjExpr (t, eio, _withKeyword, bd, ims, _, range) -> Some(t, eio, bd, ims, range) + | SynExpr.ObjExpr (t, eio, withKeyword, bd, ims, _, range) -> Some(t, eio, withKeyword, bd, ims, range) | _ -> None let (|LongIdentSet|_|) = @@ -1142,8 +1143,7 @@ let (|LongIdentSet|_|) = let (|TryWith|_|) = function - | SynExpr.TryWith (tryKeyword, e, _, withKeyword, cs, mWithToLast, _, _, _) -> - Some(tryKeyword, e, withKeyword, mWithToLast, cs) + | SynExpr.TryWith (tryKeyword, e, _, withKeyword, cs, _, _, _, _) -> Some(tryKeyword, e, withKeyword, cs) | _ -> None let (|TryFinally|_|) = @@ -1260,7 +1260,13 @@ let (|PatLongIdent|_|) = match xs with | SynArgPats.Pats ps -> Some(ao, s, propertyKeyword, List.map (fun p -> (None, p)) ps, tpso) | SynArgPats.NamePatPairs (nps, _) -> - Some(ao, s, propertyKeyword, List.map (fun (Ident ident, _equalsRange, p) -> (Some ident, p)) nps, tpso) + Some( + ao, + s, + propertyKeyword, + List.map (fun (Ident ident, equalsRange, p) -> (Some(ident, equalsRange), p)) nps, + tpso + ) | _ -> None let (|PatParen|_|) = @@ -1341,7 +1347,7 @@ and skipGeneratedMatch expr = | SynExpr.Match (_matchKeyword, _, _, - _withKeyword, + _, [ SynMatchClause.SynMatchClause (_, _, _, innerExpr, _, _) as clause ], matchRange) when matchRange.Start = clause.Range.Start -> skipGeneratedMatch innerExpr | _ -> expr @@ -1428,7 +1434,7 @@ type TypeDefnKindSingle = | TCUnion | TCAbbrev | TCOpaque - | TCAugmentation + | TCAugmentation of withKeyword: range | TCIL let (|TCSimple|TCDelegate|) = @@ -1441,30 +1447,30 @@ let (|TCSimple|TCDelegate|) = | SynTypeDefnKind.Union -> TCSimple TCUnion | SynTypeDefnKind.Abbrev -> TCSimple TCAbbrev | SynTypeDefnKind.Opaque -> TCSimple TCOpaque - | SynTypeDefnKind.Augmentation _withKeyword -> TCSimple TCAugmentation + | SynTypeDefnKind.Augmentation withKeyword -> TCSimple(TCAugmentation withKeyword) | SynTypeDefnKind.IL -> TCSimple TCIL | SynTypeDefnKind.Delegate (t, vi) -> TCDelegate(t, vi) let (|TypeDef|) (SynTypeDefn (SynComponentInfo (ats, tds, tcs, LongIdent s, px, preferPostfix, ao, _), - _equalsRange, + equalsRange, tdr, withKeyword, ms, _, _)) = - (ats, px, ao, tds, tcs, tdr, withKeyword, ms, s, preferPostfix) + (ats, px, ao, tds, tcs, equalsRange, tdr, withKeyword, ms, s, preferPostfix) let (|SigTypeDef|) (SynTypeDefnSig (SynComponentInfo (ats, tds, tcs, LongIdent s, px, preferPostfix, ao, _), - _equalsRange, + equalsRange, tdr, withKeyword, ms, range)) = - (ats, px, ao, tds, tcs, tdr, withKeyword, ms, s, preferPostfix, range) + (ats, px, ao, tds, tcs, equalsRange, tdr, withKeyword, ms, s, preferPostfix, range) let (|TyparDecl|) (SynTyparDecl (ats, tp)) = (ats, tp) @@ -1627,7 +1633,7 @@ let (|Val|) px, ao, eo, - _withKeyword, + _, range)) = (ats, px, ao, s, ident.idRange, t, vi, isInline, isMutable, typars, eo, range) @@ -1636,10 +1642,10 @@ let (|Val|) let (|RecordFieldName|) ((LongIdentWithDots s, _): RecordFieldName, eo: SynExpr option, _) = (s, eo) -let (|AnonRecordFieldName|) (ident: Ident, e: SynExpr) = (ident.idRange, ident.idText, e) +let (|AnonRecordFieldName|) (ident: Ident, eq:range option, e: SynExpr) = (ident.idText, ident.idRange, eq, e) let (|AnonRecordFieldType|) (Ident s: Ident, t: SynType) = (s, t) -let (|PatRecordFieldName|) ((LongIdent s1, Ident s2), equalsRange, p) = (s1, s2, equalsRange, p) +let (|PatRecordFieldName|) ((LongIdent s1, Ident s2), _, p) = (s1, s2, p) let (|ValInfo|) (SynValInfo (aiss, ai)) = (aiss, ai) @@ -1792,12 +1798,12 @@ let private shouldNotIndentBranch e es = && isLongElseBranch e let (|KeepIndentMatch|_|) (e: SynExpr) = - let mapClauses matchExpr withKeyword clauses range t = + let mapClauses matchKeyword matchExpr withKeyword clauses range t = match clauses with | [] -> None | [ (Clause (_, _, _, lastClause)) ] -> if shouldNotIndentBranch lastClause [] then - Some(matchExpr, withKeyword, clauses, range, t) + Some(matchKeyword, matchExpr, withKeyword, clauses, range, t) else None | clauses -> @@ -1809,15 +1815,15 @@ let (|KeepIndentMatch|_|) (e: SynExpr) = let (Clause (_, _, _, lastClause)) = List.last clauses if shouldNotIndentBranch lastClause firstClauses then - Some(matchExpr, withKeyword, clauses, range, t) + Some(matchKeyword, matchExpr, withKeyword, clauses, range, t) else None match e with - | Match (_matchKeyword, matchExpr, withKeyword, clauses) -> - mapClauses matchExpr withKeyword clauses e.Range SynExpr_Match - | MatchBang (_matchKeyword, matchExpr, withKeyword, clauses) -> - mapClauses matchExpr withKeyword clauses e.Range SynExpr_MatchBang + | Match (matchKeyword, matchExpr, withKeyword, clauses) -> + mapClauses matchKeyword matchExpr withKeyword clauses e.Range SynExpr_Match + | MatchBang (matchKeyword, matchExpr, withKeyword, clauses) -> + mapClauses matchKeyword matchExpr withKeyword clauses e.Range SynExpr_MatchBang | _ -> None let (|KeepIndentIfThenElse|_|) (e: SynExpr) = diff --git a/src/Fantomas/TriviaTypes.fs b/src/Fantomas/TriviaTypes.fs index ffa6055e20..22d7ca63e5 100644 --- a/src/Fantomas/TriviaTypes.fs +++ b/src/Fantomas/TriviaTypes.fs @@ -291,7 +291,8 @@ type FsAstType = | SynPat_Paren_ClosingParenthesis | SynPat_ArrayOrList | SynPat_Record - | SynPat_Record_Field_Equals + // comments are this equal do not lead to valid code +// | SynPat_Record_Field_Equals | SynPat_Null | SynPat_OptionalVal | SynPat_IsInst From ba4498c0e2a3aee7e374afcf829ebfb18c82700d Mon Sep 17 00:00:00 2001 From: nojaf Date: Sat, 22 Jan 2022 12:17:31 +0100 Subject: [PATCH 04/16] Remove unused tdr parameter. --- src/Fantomas/CodePrinter.fs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/Fantomas/CodePrinter.fs b/src/Fantomas/CodePrinter.fs index 088070b291..480de3c1c0 100644 --- a/src/Fantomas/CodePrinter.fs +++ b/src/Fantomas/CodePrinter.fs @@ -3732,13 +3732,12 @@ and genTypeDefn (genMultilineSimpleRecordTypeDefnAlignBrackets astContext openingBrace - tdr withKeyword ms ao' fs closingBrace) - (genMultilineSimpleRecordTypeDefn astContext openingBrace tdr withKeyword ms ao' fs closingBrace) + (genMultilineSimpleRecordTypeDefn astContext openingBrace withKeyword ms ao' fs closingBrace) let bodyExpr ctx = let size = getRecordSize ctx fs @@ -3899,7 +3898,7 @@ and genTypeDefn | ExceptionRepr (ExceptionDefRepr (ats, px, ao, uc)) -> genExceptionBody astContext ats px ao uc |> genTriviaFor SynTypeDefn_ node.Range -and genMultilineSimpleRecordTypeDefn astContext openingBrace tdr withKeyword ms ao' fs closingBrace = +and genMultilineSimpleRecordTypeDefn astContext openingBrace withKeyword ms ao' fs closingBrace = // the typeName is already printed sepNlnUnlessLastEventIsNewline +> opt (indent +> sepNln) ao' genAccess @@ -3916,7 +3915,7 @@ and genMultilineSimpleRecordTypeDefn astContext openingBrace tdr withKeyword ms +> sepNlnBetweenTypeAndMembers withKeyword ms +> genMemberDefnList { astContext with InterfaceRange = None } ms -and genMultilineSimpleRecordTypeDefnAlignBrackets astContext openingBrace tdr withKeyword ms ao' fs closingBrace = +and genMultilineSimpleRecordTypeDefnAlignBrackets astContext openingBrace withKeyword ms ao' fs closingBrace = // the typeName is already printed sepNlnUnlessLastEventIsNewline +> opt (indent +> sepNln) ao' genAccess @@ -4030,8 +4029,8 @@ and genSigTypeDefn let multilineExpression = ifAlignBrackets - (genSigSimpleRecordAlignBrackets astContext openingBrace tdr withKeyword ms ao' fs closingBrace) - (genSigSimpleRecord astContext openingBrace tdr withKeyword ms ao' fs closingBrace) + (genSigSimpleRecordAlignBrackets astContext openingBrace withKeyword ms ao' fs closingBrace) + (genSigSimpleRecord astContext openingBrace withKeyword ms ao' fs closingBrace) let bodyExpr ctx = let size = getRecordSize ctx fs @@ -4135,7 +4134,7 @@ and genSigTypeDefn | SigExceptionRepr (SigExceptionDefRepr (ats, px, ao, uc)) -> genExceptionBody astContext ats px ao uc |> genTriviaFor SynTypeDefnSig_ fullRange -and genSigSimpleRecord astContext openingBrace tdr withKeyword ms ao' fs closingBrace = +and genSigSimpleRecord astContext openingBrace withKeyword ms ao' fs closingBrace = // the typeName is already printed sepNlnUnlessLastEventIsNewline +> opt (indent +> sepNln) ao' genAccess @@ -4151,7 +4150,7 @@ and genSigSimpleRecord astContext openingBrace tdr withKeyword ms ao' fs closing +> sepNlnBetweenSigTypeAndMembers withKeyword ms +> colPre sepNln sepNln ms (genMemberSig astContext) -and genSigSimpleRecordAlignBrackets astContext openingBrace tdr withKeyword ms ao' fs closingBrace = +and genSigSimpleRecordAlignBrackets astContext openingBrace withKeyword ms ao' fs closingBrace = // the typeName is already printed sepNlnUnlessLastEventIsNewline +> opt (indent +> sepNln) ao' genAccess From 12e92bdbc0f388f8c404223c26b77969c3ea140c Mon Sep 17 00:00:00 2001 From: nojaf Date: Sat, 29 Jan 2022 10:58:36 +0100 Subject: [PATCH 05/16] Remove AND_BANG from TokenParser.fs --- src/Fantomas/AstTransformer.fs | 7 +++++-- src/Fantomas/CodePrinter.fs | 8 ++++---- src/Fantomas/SourceParser.fs | 5 +++-- src/Fantomas/TokenParser.fs | 2 -- src/Fantomas/TriviaTypes.fs | 4 +--- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Fantomas/AstTransformer.fs b/src/Fantomas/AstTransformer.fs index cd5b041d08..21a491bac9 100644 --- a/src/Fantomas/AstTransformer.fs +++ b/src/Fantomas/AstTransformer.fs @@ -675,8 +675,11 @@ module private Ast = yield! mkNodeOption SynMatchClause_Arrow arrowRange yield! visitSynExpr e2 ] - and visitSynExprAndBang (SynExprAndBang (_, _, _, pat, equalsRange, body, _range)) : TriviaNodeAssigner list = - [ // yield mkNode SynExprAndBang_ range + // TODO: revisit after https://github.com/dotnet/fsharp/issues/12619 + and visitSynExprAndBang + (SynExprAndBang (_, _, _, pat, equalsRange, body, andBangKeyword)) + : TriviaNodeAssigner list = + [ yield mkNode SynExprAndBang_ (Range.unionRanges andBangKeyword body.Range) yield! visitSynPat pat yield mkNode SynExprAndBang_Equals equalsRange yield! visitSynExpr body ] diff --git a/src/Fantomas/CodePrinter.fs b/src/Fantomas/CodePrinter.fs index 480de3c1c0..da61306531 100644 --- a/src/Fantomas/CodePrinter.fs +++ b/src/Fantomas/CodePrinter.fs @@ -1562,13 +1562,13 @@ and genExpr astContext synExpr ctx = +> genEq SynExpr_LetOrUseBang_Equals equalsRange +> sepSpace +> autoIndentAndNlnIfExpressionExceedsPageWidth (genExpr astContext expr) - | AndBangStatement (pat, equalsRange, expr, andRange) -> - enterNodeTokenByName andRange AND_BANG - +> !- "and! " + | AndBangStatement (pat, equalsRange, expr, range) -> + !- "and! " +> genPat astContext pat +> genEq SynExprAndBang_Equals (Some equalsRange) +> sepSpace +> autoIndentAndNlnIfExpressionExceedsPageWidth (genExpr astContext expr) + |> genTriviaFor SynExprAndBang_ range | OtherStatement expr -> genExpr astContext expr let getRangeOfCompExprStatement ces = @@ -1583,7 +1583,7 @@ and genExpr astContext synExpr ctx = | LetOrUseStatement (_, b) -> sepNlnConsideringTriviaContentBeforeForMainNode (synBindingToFsAstType b) r | LetOrUseBangStatement _ -> sepNlnConsideringTriviaContentBeforeForMainNode SynExpr_LetOrUseBang r - | AndBangStatement _ -> sepNlnConsideringTriviaContentBeforeForToken AND_BANG r + | AndBangStatement (_, _, _, r) -> sepNlnConsideringTriviaContentBeforeForMainNode SynExprAndBang_ r | OtherStatement e -> let t, r = synExprToFsAstType e sepNlnConsideringTriviaContentBeforeForMainNode t r diff --git a/src/Fantomas/SourceParser.fs b/src/Fantomas/SourceParser.fs index 942e76b111..595b7886ce 100644 --- a/src/Fantomas/SourceParser.fs +++ b/src/Fantomas/SourceParser.fs @@ -990,8 +990,9 @@ let rec collectComputationExpressionStatements let andBangs = andBangs - |> List.map (fun (SynExprAndBang (_, _, _, ap, equalsRange, ae, andRange)) -> - AndBangStatement(ap, equalsRange, ae, andRange)) + |> List.map (fun (SynExprAndBang (_, _, _, ap, equalsRange, ae, andBangKeyword)) -> + let range = Range.unionRanges andBangKeyword ae.Range + AndBangStatement(ap, equalsRange, ae, range)) collectComputationExpressionStatements body (fun bodyStatements -> [ letOrUseBang diff --git a/src/Fantomas/TokenParser.fs b/src/Fantomas/TokenParser.fs index 7930aba7ca..c885a3d43a 100644 --- a/src/Fantomas/TokenParser.fs +++ b/src/Fantomas/TokenParser.fs @@ -1125,14 +1125,12 @@ let private tokenNames = "TRY" "FINALLY" "MEMBER" - "AND_BANG" "IN" ] let internal getFsToken tokenName = match tokenName with | "AMP" -> AMP | "AMP_AMP" -> AMP_AMP - | "AND_BANG" -> AND_BANG | "BAR" -> BAR | "BAR_BAR" -> BAR_BAR | "COLON_COLON" -> COLON_COLON diff --git a/src/Fantomas/TriviaTypes.fs b/src/Fantomas/TriviaTypes.fs index 22d7ca63e5..60557a3905 100644 --- a/src/Fantomas/TriviaTypes.fs +++ b/src/Fantomas/TriviaTypes.fs @@ -6,7 +6,6 @@ open FSharp.Compiler.Tokenization type FsTokenType = | AMP | AMP_AMP - | AND_BANG | BAR | BAR_BAR | COLON_COLON @@ -194,8 +193,7 @@ type FsAstType = | SynExpr_YieldOrReturnFrom_YieldBang | SynExpr_LetOrUseBang | SynExpr_LetOrUseBang_Equals - // Maybe a thing after https://github.com/dotnet/fsharp/issues/12619 - // | SynExprAndBang_ + | SynExprAndBang_ | SynExprAndBang_Equals | SynExpr_MatchBang | SynExpr_MatchBang_Match From f612a600c9d975c8e4ea189ea5eef34804f6c8f1 Mon Sep 17 00:00:00 2001 From: nojaf Date: Wed, 2 Feb 2022 08:12:06 +0100 Subject: [PATCH 06/16] Process SyntaxTrivia. Remove TRY and FINALLY keywords. --- src/Fantomas/AstTransformer.fs | 38 +++++++++++++++---------- src/Fantomas/CodeFormatterImpl.fs | 18 +++--------- src/Fantomas/CodePrinter.fs | 6 ++-- src/Fantomas/SourceParser.fs | 47 +++++++++++++++---------------- src/Fantomas/SourceTransformer.fs | 2 +- src/Fantomas/TokenParser.fs | 9 +----- src/Fantomas/TriviaTypes.fs | 4 +-- 7 files changed, 56 insertions(+), 68 deletions(-) diff --git a/src/Fantomas/AstTransformer.fs b/src/Fantomas/AstTransformer.fs index 21a491bac9..e49a222380 100644 --- a/src/Fantomas/AstTransformer.fs +++ b/src/Fantomas/AstTransformer.fs @@ -210,7 +210,7 @@ module private Ast = [ yield mkNode SynExpr_ComputationExpr_OpeningBrace openingBrace yield! visit expr finalContinuation yield mkNode SynExpr_ComputationExpr_ClosingBrace closingBrace ] - | SynExpr.Lambda (_, _, args, arrowRange, body, _parsedData, range) -> + | SynExpr.Lambda (_, _, args, body, _parsedData, range, { ArrowRange = arrowRange }) -> visit body (fun nodes -> [ yield mkNode SynExpr_Lambda range yield! visitSynSimplePats args @@ -260,12 +260,18 @@ module private Ast = yield! (List.collect visitSynType typeNames) yield! mkNodeOption SynExpr_TypeApp_Greater greaterRange ] |> finalContinuation) - | SynExpr.LetOrUse (_, _, bindings, body, _) -> + | SynExpr.LetOrUse (_, _, bindings, body, _, trivia) -> visit body (fun nodes -> [ yield! (List.collect visitSynBinding bindings) yield! nodes ] |> finalContinuation) - | SynExpr.TryWith (tryKeyword, tryExpr, _, withKeyword, withCases, _, range, _, _) -> + | SynExpr.TryWith (tryExpr, + withCases, + range, + _, + _, + { TryKeyword = tryKeyword + WithKeyword = withKeyword }) -> visit tryExpr (fun nodes -> [ yield mkNode SynExpr_TryWith range yield mkNode SynExpr_TryWith_Try tryKeyword @@ -273,13 +279,15 @@ module private Ast = yield mkNode SynExpr_TryWith_With withKeyword yield! withCases |> List.collect visitSynMatchClause ] |> finalContinuation) - | SynExpr.TryFinally (tryExpr, finallyExpr, range, _, _) -> + | SynExpr.TryFinally (tryExpr, finallyExpr, range, _, _, trivia) -> let continuations: ((TriviaNodeAssigner list -> TriviaNodeAssigner list) -> TriviaNodeAssigner list) list = [ visit tryExpr; visit finallyExpr ] let finalContinuation (nodes: TriviaNodeAssigner list list) : TriviaNodeAssigner list = - mkNode SynExpr_TryFinally range - :: (List.collect id nodes) + [ yield mkNode SynExpr_TryFinally range + yield mkNode SynExpr_TryFinally_Try trivia.TryKeyword + yield mkNode SynExpr_TryFinally_Finally trivia.FinallyKeyword + yield! List.collect id nodes ] |> finalContinuation Continuation.sequence continuations finalContinuation @@ -351,7 +359,7 @@ module private Ast = Continuation.sequence continuations finalContinuation - | SynExpr.IfThenElse (ifKw, isElif, ifExpr, thenKw, thenExpr, elseKw, elseExpr, _, _, _, range) -> + | SynExpr.IfThenElse (ifExpr, thenExpr, elseExpr, _, _, range, trivia) -> let continuations: ((TriviaNodeAssigner list -> TriviaNodeAssigner list) -> TriviaNodeAssigner list) list = [ yield visit ifExpr yield visit thenExpr @@ -361,13 +369,13 @@ module private Ast = [ yield mkNode SynExpr_IfThenElse range yield mkNode - (if isElif then + (if trivia.IsElif then SynExpr_IfThenElse_Elif else SynExpr_IfThenElse_If) - ifKw - yield mkNode SynExpr_IfThenElse_Then thenKw - yield! mkNodeOption SynExpr_IfThenElse_Else elseKw + trivia.IfKeyword + yield mkNode SynExpr_IfThenElse_Then trivia.ThenKeyword + yield! mkNodeOption SynExpr_IfThenElse_Else trivia.ElseKeyword yield! (List.collect id nodes) ] |> finalContinuation @@ -667,12 +675,12 @@ module private Ast = and visitSynMatchClause (mc: SynMatchClause) : TriviaNodeAssigner list = match mc with - | SynMatchClause (pat, e1, arrowRange, e2, _range, _) -> + | SynMatchClause (pat, e1, e2, _range, _, trivia) -> 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! mkNodeOption SynMatchClause_Arrow arrowRange + yield! mkNodeOption SynMatchClause_Arrow trivia.ArrowRange yield! visitSynExpr e2 ] // TODO: revisit after https://github.com/dotnet/fsharp/issues/12619 @@ -1138,7 +1146,7 @@ module private Ast = and visitSynUnionCase (uc: SynUnionCase) : TriviaNodeAssigner list = match uc with - | SynUnionCase (attrs, _, uct, _, _, range) -> + | SynUnionCase (attrs, _, uct, _, _, range, trivia) -> [ yield mkNode SynUnionCase_ range yield! visitSynUnionCaseType uct yield! (visitSynAttributeLists attrs) ] @@ -1150,7 +1158,7 @@ module private Ast = and visitSynEnumCase (sec: SynEnumCase) : TriviaNodeAssigner list = match sec with - | SynEnumCase (attrs, ident, equalsRange, value, valueRange, _, range) -> + | SynEnumCase (attrs, ident, value, valueRange, _, range, { EqualsRange = equalsRange }) -> [ yield mkNode SynEnumCase_ range yield! (visitSynAttributeLists attrs) yield visitIdent ident diff --git a/src/Fantomas/CodeFormatterImpl.fs b/src/Fantomas/CodeFormatterImpl.fs index 7a1fe09dcb..da6853b4e0 100644 --- a/src/Fantomas/CodeFormatterImpl.fs +++ b/src/Fantomas/CodeFormatterImpl.fs @@ -179,7 +179,7 @@ let isValidAST ast = | SynExpr.ArrayOrListComputed (_, synExpr, _range) -> validateExpr synExpr | SynExpr.ComputationExpr (_, synExpr, _range) -> validateExpr synExpr - | SynExpr.Lambda (_, _, _synSimplePats, _arrow, synExpr, _parsedData, _range) -> validateExpr synExpr + | SynExpr.Lambda (body = synExpr) -> validateExpr synExpr | SynExpr.MatchLambda (_isExnMatch, _argm, synMatchClauseList, _spBind, _wholem) -> List.forall validateClause synMatchClauseList @@ -197,7 +197,7 @@ let isValidAST ast = | SynExpr.TypeApp (synExpr, _, _synTypeList, _commas, _, _, _range) -> validateExpr synExpr - | SynExpr.LetOrUse (_, _, synBindingList, synExpr, _range) -> + | SynExpr.LetOrUse (bindings = synBindingList; body = synExpr) -> List.forall validateBinding synBindingList && validateExpr synExpr @@ -205,24 +205,14 @@ let isValidAST ast = validateExpr synExpr && List.forall validateClause synMatchClauseList - | SynExpr.TryFinally (synExpr1, synExpr2, _range, _sequencePointInfoForTry, _sequencePointInfoForFinally) -> + | SynExpr.TryFinally (tryExpr = synExpr1; finallyExpr = synExpr2) -> List.forall validateExpr [ synExpr1; synExpr2 ] | SynExpr.Sequential (_sequencePointInfoForSeq, _, synExpr1, synExpr2, _range) | SynExpr.SequentialOrImplicitYield (_sequencePointInfoForSeq, synExpr1, synExpr2, _, _range) -> List.forall validateExpr [ synExpr1; synExpr2 ] - | SynExpr.IfThenElse (_, - _, - synExpr1, - _, - synExpr2, - _, - synExprOpt, - _sequencePointInfoForBinding, - _isRecovery, - _range, - _range2) -> + | SynExpr.IfThenElse (ifExpr = synExpr1; thenExpr = synExpr2; elseExpr = synExprOpt) -> match synExprOpt with | Some synExpr3 -> List.forall validateExpr [ synExpr1; synExpr2; synExpr3 ] | None -> List.forall validateExpr [ synExpr1; synExpr2 ] diff --git a/src/Fantomas/CodePrinter.fs b/src/Fantomas/CodePrinter.fs index da61306531..e1a63154c2 100644 --- a/src/Fantomas/CodePrinter.fs +++ b/src/Fantomas/CodePrinter.fs @@ -2315,14 +2315,14 @@ and genExpr astContext synExpr ctx = +> unindentOnWith ) - | TryFinally (e1, e2) -> + | TryFinally (tryKeyword, e1, finallyKeyword, e2) -> atCurrentColumn ( - kw TRY !- "try " + genTriviaFor SynExpr_TryFinally_Try tryKeyword !- "try " +> indent +> sepNln +> genExpr astContext e1 +> unindent - +> kw FINALLY !+~ "finally" + +> genTriviaFor SynExpr_TryFinally_Finally finallyKeyword !+~ "finally" +> indent +> sepNln +> genExpr astContext e2 diff --git a/src/Fantomas/SourceParser.fs b/src/Fantomas/SourceParser.fs index 595b7886ce..32ce9fc6b5 100644 --- a/src/Fantomas/SourceParser.fs +++ b/src/Fantomas/SourceParser.fs @@ -409,7 +409,7 @@ let (|SigExceptionDef|) = (ats, px, ao, uc, withKeyword, ms) -let (|UnionCase|) (SynUnionCase (ats, Ident s, uct, px, ao, _)) = (ats, px, ao, s, uct) +let (|UnionCase|) (SynUnionCase (ats, Ident s, uct, px, ao, _, trivia)) = (ats, px, ao, s, uct) let (|UnionCaseType|) = function @@ -419,7 +419,8 @@ let (|UnionCaseType|) = let (|Field|) (SynField (ats, isStatic, ido, t, isMutable, px, ao, _)) = (ats, px, ao, isStatic, isMutable, t, Option.map (|Ident|) ido) -let (|EnumCase|) (SynEnumCase (ats, Ident s, equalsRange, c, cr, px, r)) = (ats, px, s, equalsRange, c, cr, r) +let (|EnumCase|) (SynEnumCase (ats, Ident s, c, cr, px, r, trivia)) = + (ats, px, s, trivia.EqualsRange, c, cr, r) // Member definitions (11 cases) @@ -662,7 +663,7 @@ let (|ConstUnitExpr|_|) = let (|TypeApp|_|) = function - | SynExpr.TypeApp (e, lessRange, ts, _, Some greaterRange, _, range) -> Some(e, lessRange, ts, greaterRange) + | SynExpr.TypeApp (e, lessRange, ts, _, Some greaterRange, _, _range) -> Some(e, lessRange, ts, greaterRange) | _ -> None let (|Match|_|) = @@ -926,14 +927,14 @@ let (|JoinIn|_|) = let (|LetOrUse|_|) = function - | SynExpr.LetOrUse (isRec, isUse, xs, e, _) -> Some(isRec, isUse, xs, e) + | SynExpr.LetOrUse (isRec, isUse, xs, e, _, trivia) -> Some(isRec, isUse, xs, e) | _ -> None /// Unfold a list of let bindings /// Recursive and use properties have to be determined at this point let rec (|LetOrUses|_|) = function - | SynExpr.LetOrUse (isRec, isUse, xs, LetOrUses (ys, e), _) -> + | SynExpr.LetOrUse (isRec, isUse, xs, LetOrUses (ys, e), _, trivia) -> let prefix = if isUse then "use " elif isRec then "let rec " @@ -949,7 +950,7 @@ let rec (|LetOrUses|_|) = xs Some(xs' @ ys, e) - | SynExpr.LetOrUse (isRec, isUse, xs, e, _) -> + | SynExpr.LetOrUse (isRec, isUse, xs, e, _, trivia) -> let prefix = if isUse then "use " elif isRec then "let rec " @@ -1013,7 +1014,7 @@ let rec collectComputationExpressionStatements /// Matches if the SynExpr has some or of computation expression member call inside. let rec (|CompExprBody|_|) expr = match expr with - | SynExpr.LetOrUse (_, _, _, CompExprBody _, _) + | SynExpr.LetOrUse(body = CompExprBody _) | SynExpr.LetOrUseBang _ | SynExpr.Sequential _ -> Some(collectComputationExpressionStatements expr id) | _ -> None @@ -1094,27 +1095,23 @@ let (|IfThenElse|_|) = let rec (|ElIf|_|) = function - | SynExpr.IfThenElse (ifKw, - isElif, - e1, - thenKw, + | SynExpr.IfThenElse (e1, e2, - elseKw, Some (ElIf ((_, eshIfKw, eshIsElif, eshE1, eshThenKw, eshE2) :: es, elseInfo, _)), _, _, - _, - range) -> + range, + trivia) -> Some( - ((None, ifKw, isElif, e1, thenKw, e2) - :: (elseKw, eshIfKw, eshIsElif, eshE1, eshThenKw, eshE2) + ((None, trivia.IfKeyword, trivia.IsElif, e1, trivia.ThenKeyword, e2) + :: (trivia.ElseKeyword, 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) + | SynExpr.IfThenElse (e1, e2, e3, _, _, range, trivia) -> + Some([ (None, trivia.IfKeyword, trivia.IsElif, e1, trivia.ThenKeyword, e2) ], (trivia.ElseKeyword, e3), range) | _ -> None let (|Record|_|) = @@ -1144,12 +1141,12 @@ let (|LongIdentSet|_|) = let (|TryWith|_|) = function - | SynExpr.TryWith (tryKeyword, e, _, withKeyword, cs, _, _, _, _) -> Some(tryKeyword, e, withKeyword, cs) + | SynExpr.TryWith (e, cs, _, _, _, trivia) -> Some(trivia.TryKeyword, e, trivia.WithKeyword, cs) | _ -> None let (|TryFinally|_|) = function - | SynExpr.TryFinally (e1, e2, _, _, _) -> Some(e1, e2) + | SynExpr.TryFinally (e1, e2, _, _, _, trivia) -> Some(trivia.TryKeyword, e1, trivia.FinallyKeyword, e2) | _ -> None let (|ParsingError|_|) = @@ -1335,12 +1332,12 @@ let (|RecordField|) = function | SynField (ats, _, ido, _, _, px, ao, _) -> (ats, px, ao, Option.map (|Ident|) ido) -let (|Clause|) (SynMatchClause (p, eo, arrowRange, e, _, _)) = (p, eo, arrowRange, e) +let (|Clause|) (SynMatchClause (p, eo, e, _, _, trivia)) = (p, eo, trivia.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 (inLambdaSeq = true; body = bodyExpr) -> skipGeneratedLambdas bodyExpr | _ -> expr and skipGeneratedMatch expr = @@ -1349,18 +1346,18 @@ and skipGeneratedMatch expr = _, _, _, - [ SynMatchClause.SynMatchClause (_, _, _, innerExpr, _, _) as clause ], + [ SynMatchClause.SynMatchClause (resultExpr = innerExpr) as clause ], matchRange) when matchRange.Start = clause.Range.Start -> skipGeneratedMatch innerExpr | _ -> expr let (|Lambda|_|) = function - | SynExpr.Lambda (_, _, _, arrowRange, _, Some (pats, body), range) -> + | SynExpr.Lambda (_, _, _, _, Some (pats, body), range, trivia) -> let inline getLambdaBodyExpr expr = let skippedLambdas = skipGeneratedLambdas expr skipGeneratedMatch skippedLambdas - Some(pats, arrowRange, getLambdaBodyExpr body, range) + Some(pats, trivia.ArrowRange, getLambdaBodyExpr body, range) | _ -> None let (|AppWithLambda|_|) (e: SynExpr) = diff --git a/src/Fantomas/SourceTransformer.fs b/src/Fantomas/SourceTransformer.fs index 12e6ee5df7..36b65f40c6 100644 --- a/src/Fantomas/SourceTransformer.fs +++ b/src/Fantomas/SourceTransformer.fs @@ -220,7 +220,7 @@ let rec synExprToFsAstType (expr: SynExpr) : FsAstType * Range = | SynExpr.New _ -> SynExpr_New, expr.Range | SynExpr.Quote _ -> SynExpr_Quote, expr.Range | SynExpr.DotIndexedSet _ -> SynExpr_DotIndexedSet, expr.Range - | SynExpr.LetOrUse (_, _, bs, e, _) -> + | SynExpr.LetOrUse (bindings = bs; body = e) -> match bs with | [] -> synExprToFsAstType e | SynBinding (kind = kind) as b :: _ -> diff --git a/src/Fantomas/TokenParser.fs b/src/Fantomas/TokenParser.fs index c885a3d43a..5110a6e012 100644 --- a/src/Fantomas/TokenParser.fs +++ b/src/Fantomas/TokenParser.fs @@ -1120,12 +1120,7 @@ let getTriviaFromTokens (mkRange: MkRange) (tokens: Token list) = fromTokens @ newLines |> List.sortBy (fun t -> t.Range.StartLine, t.Range.StartColumn) -let private tokenNames = - [ "BAR" - "TRY" - "FINALLY" - "MEMBER" - "IN" ] +let private tokenNames = [ "BAR"; "MEMBER"; "IN" ] let internal getFsToken tokenName = match tokenName with @@ -1145,7 +1140,6 @@ let internal getFsToken tokenName = | "DOT_DOT_HAT" -> DOT_DOT_HAT | "ELIF" -> ELIF | "ELSE" -> ELSE - | "FINALLY" -> FINALLY | "GREATER" -> GREATER | "IF" -> IF | "IN" -> IN @@ -1165,7 +1159,6 @@ let internal getFsToken tokenName = | "QMARK" -> QMARK | "QMARK_QMARK" -> QMARK_QMARK | "THEN" -> THEN - | "TRY" -> TRY | _ -> failwithf "was not expecting token %s" tokenName let getTriviaNodesFromTokens (mkRange: MkRange) (tokens: Token list) = diff --git a/src/Fantomas/TriviaTypes.fs b/src/Fantomas/TriviaTypes.fs index 60557a3905..a576771a89 100644 --- a/src/Fantomas/TriviaTypes.fs +++ b/src/Fantomas/TriviaTypes.fs @@ -20,7 +20,6 @@ type FsTokenType = | DOT_DOT_HAT | ELIF | ELSE - | FINALLY | GREATER | IF | IN @@ -40,7 +39,6 @@ type FsTokenType = | QMARK | QMARK_QMARK | THEN - | TRY type Token = { TokenInfo: FSharpTokenInfo @@ -152,6 +150,8 @@ type FsAstType = | SynExpr_TryWith_Try | SynExpr_TryWith_With | SynExpr_TryFinally + | SynExpr_TryFinally_Try + | SynExpr_TryFinally_Finally | SynExpr_Lazy | SynExpr_Lazy_Lazy // | SynExpr_Sequential use first nested SynExpr From b2fce9f86bdf5768fee936173df07215e73aef54 Mon Sep 17 00:00:00 2001 From: nojaf Date: Wed, 2 Feb 2022 11:28:34 +0100 Subject: [PATCH 07/16] Use IN keyword from trivia. --- src/Fantomas.Tests/FormatAstTests.fs | 7 +- src/Fantomas/AstTransformer.fs | 10 +++ src/Fantomas/CodePrinter.fs | 118 +++++++-------------------- src/Fantomas/SourceParser.fs | 32 +++++--- src/Fantomas/TokenParser.fs | 2 +- src/Fantomas/TriviaTypes.fs | 1 + 6 files changed, 67 insertions(+), 103 deletions(-) diff --git a/src/Fantomas.Tests/FormatAstTests.fs b/src/Fantomas.Tests/FormatAstTests.fs index 4313d26173..21b16d18ac 100644 --- a/src/Fantomas.Tests/FormatAstTests.fs +++ b/src/Fantomas.Tests/FormatAstTests.fs @@ -40,12 +40,9 @@ let formatAst code = let ``format the ast works correctly with no source code`` () = formatAst "()" |> should equal "()" [] -let ``let in should not be used`` () = +let ``let in should be used`` () = formatAst "let x = 1 in ()" - |> should - equal - """let x = 1 -()""" + |> should equal """let x = 1 in ()""" [] let ``elif keyword is present in raw AST`` () = diff --git a/src/Fantomas/AstTransformer.fs b/src/Fantomas/AstTransformer.fs index e49a222380..13eb5ce314 100644 --- a/src/Fantomas/AstTransformer.fs +++ b/src/Fantomas/AstTransformer.fs @@ -261,8 +261,18 @@ module private Ast = yield! mkNodeOption SynExpr_TypeApp_Greater greaterRange ] |> finalContinuation) | SynExpr.LetOrUse (_, _, bindings, body, _, trivia) -> + let inKeyword = + match trivia.InKeyword with + | None -> None + | Some inKw -> + if Position.posEq inKw.Start body.Range.Start then + None + else + Some inKw + visit body (fun nodes -> [ yield! (List.collect visitSynBinding bindings) + yield! mkNodeOption SynExpr_LetOrUse_In inKeyword yield! nodes ] |> finalContinuation) | SynExpr.TryWith (tryExpr, diff --git a/src/Fantomas/CodePrinter.fs b/src/Fantomas/CodePrinter.fs index e1a63154c2..1fb8132f98 100644 --- a/src/Fantomas/CodePrinter.fs +++ b/src/Fantomas/CodePrinter.fs @@ -1095,8 +1095,6 @@ and genNamedArgumentExpr (astContext: ASTContext) operatorExpr e1 e2 appRange = |> genTriviaFor SynExpr_App appRange and genExpr astContext synExpr ctx = - let kw tokenName f = tokN synExpr.Range tokenName f - let expr = match synExpr with | ElmishReactWithoutChildren (identifier, openingTokenRange, isArray, children, closingTokenRange) when @@ -1552,9 +1550,10 @@ and genExpr astContext synExpr ctx = | CompExprBody statements -> let genCompExprStatement astContext ces = match ces with - | LetOrUseStatement (prefix, binding) -> + | LetOrUseStatement (prefix, binding, inKeyword) -> enterNodeFor (synBindingToFsAstType binding) binding.RangeOfBindingWithRhs +> genLetBinding astContext prefix binding + +> genTriviaForOption SynExpr_LetOrUse_In inKeyword !- " in " | LetOrUseBangStatement (isUse, pat, equalsRange, expr, r) -> enterNodeFor SynExpr_LetOrUseBang r // print Trivia before entire LetBang expression +> ifElse isUse (!- "use! ") (!- "let! ") @@ -1573,14 +1572,14 @@ and genExpr astContext synExpr ctx = let getRangeOfCompExprStatement ces = match ces with - | LetOrUseStatement (_, binding) -> binding.RangeOfBindingWithRhs + | LetOrUseStatement (_, binding, _) -> binding.RangeOfBindingWithRhs | LetOrUseBangStatement (range = r) -> r | AndBangStatement (range = r) -> r | OtherStatement expr -> expr.Range let getSepNln ces r = match ces with - | LetOrUseStatement (_, b) -> + | LetOrUseStatement (_, b, _) -> sepNlnConsideringTriviaContentBeforeForMainNode (synBindingToFsAstType b) r | LetOrUseBangStatement _ -> sepNlnConsideringTriviaContentBeforeForMainNode SynExpr_LetOrUseBang r | AndBangStatement (_, _, _, r) -> sepNlnConsideringTriviaContentBeforeForMainNode SynExprAndBang_ r @@ -2287,18 +2286,10 @@ and genExpr astContext synExpr ctx = genExpr astContext e +> genGenericTypeParameters astContext lt ts gt | LetOrUses (bs, e) -> - fun ctx -> - let items = - let inKeywords = Map.tryFindOrEmptyList IN ctx.TriviaTokenNodes + let items = + collectMultilineItemForLetOrUses astContext bs (collectMultilineItemForSynExpr astContext e) - collectMultilineItemForLetOrUses - astContext - inKeywords - bs - e - (collectMultilineItemForSynExpr astContext inKeywords e) - - atCurrentColumn (colWithNlnWhenItemIsMultilineUsingConfig items) ctx + atCurrentColumn (colWithNlnWhenItemIsMultilineUsingConfig items) // Could customize a bit if e is single line | TryWith (tryKeyword, e, withKeyword, cs) -> atCurrentColumn ( @@ -2330,12 +2321,8 @@ and genExpr astContext synExpr ctx = ) | Sequentials es -> - fun ctx -> - let inKeywords = Map.tryFindOrEmptyList IN ctx.TriviaTokenNodes - - let items = List.collect (collectMultilineItemForSynExpr astContext inKeywords) es - - atCurrentColumn (colWithNlnWhenItemIsMultilineUsingConfig items) ctx + let items = List.collect (collectMultilineItemForSynExpr astContext) es + atCurrentColumn (colWithNlnWhenItemIsMultilineUsingConfig items) // A generalization of IfThenElse | ElIf ((_, ifKw, isElif, e1, thenKw, e2) :: es, (elseKw, elseOpt), _) -> // https://docs.microsoft.com/en-us/dotnet/fsharp/style-guide/formatting#formatting-if-expressions @@ -2860,7 +2847,11 @@ and genExprInMultilineInfixExpr astContext e = match e with | LetOrUses (xs, e) -> atCurrentColumn ( - col sepNln xs (fun (pref, lb) -> genLetBinding astContext pref lb +> !- " in") + col sepNln xs (fun (pref, lb, inKeyword) -> + genLetBinding astContext pref lb + +> (match inKeyword with + | Some inKw -> genTriviaFor SynExpr_LetOrUse_In inKw !- " in" + | None -> !- " in")) +> sepNln +> expressionFitsOnRestOfLine (genExpr astContext e) @@ -3542,48 +3533,27 @@ and genAppWithParenthesis app astContext = | Choice1Of2 t -> genAppWithTupledArgument t astContext | Choice2Of2 s -> genAppWithSingleParenthesisArgument s astContext -and collectMultilineItemForSynExpr - (astContext: ASTContext) - (inKeyWordTrivia: TriviaNode list) - (e: SynExpr) - : ColMultilineItem list = +and collectMultilineItemForSynExpr (astContext: ASTContext) (e: SynExpr) : ColMultilineItem list = match e with - | LetOrUses (bs, e) -> - collectMultilineItemForLetOrUses - astContext - inKeyWordTrivia - bs - e - (collectMultilineItemForSynExpr astContext inKeyWordTrivia e) + | LetOrUses (bs, e) -> collectMultilineItemForLetOrUses astContext bs (collectMultilineItemForSynExpr astContext e) | Sequentials s -> s - |> List.collect (collectMultilineItemForSynExpr astContext inKeyWordTrivia) + |> List.collect (collectMultilineItemForSynExpr astContext) | _ -> let t, r = synExprToFsAstType e [ ColMultilineItem(genExpr astContext e, sepNlnConsideringTriviaContentBeforeForMainNode t r) ] and collectMultilineItemForLetOrUses (astContext: ASTContext) - (inKeyWordTrivia: TriviaNode list) - (bs: (string * SynBinding) list) - (e: SynExpr) + (bs: (string * SynBinding * range option) list) (itemsForExpr: ColMultilineItem list) : ColMultilineItem list = - // It be nice if the `in` keyword was part of the AST tree as suggested in - // https://github.com/dotnet/fsharp/issues/10198 - let bindingHasInKeyword (binding: SynBinding) : bool = - let inRange = - Range.mkRange binding.RangeOfBindingWithRhs.FileName binding.RangeOfBindingWithRhs.End e.Range.Start - inKeyWordTrivia - |> TriviaHelpers.``keyword token after start column and on same line`` inRange - |> List.isNotEmpty - - let multilineBinding p x = + let multilineBinding p x inKw = let expr = enterNodeFor (synBindingToFsAstType x) x.RangeOfBindingWithRhs +> genLetBinding astContext p x - +> genInKeyword x e + +> genTriviaForOption SynExpr_LetOrUse_In inKw !- " in " let range = x.RangeOfBindingWithRhs @@ -3594,11 +3564,11 @@ and collectMultilineItemForLetOrUses let multipleOrLongBs bs = bs - |> List.map (fun (p, x) -> multilineBinding p x) + |> List.map (fun (p, x, inKw) -> multilineBinding p x inKw) match bs, itemsForExpr with | [], _ -> itemsForExpr - | [ p, b ], [ ColMultilineItem (expr, sepNlnForExpr) ] -> + | [ p, b, inKeyword ], [ ColMultilineItem (expr, sepNlnForExpr) ] -> // This is a trickier case // maybe the let binding and expression are short so they form one ColMultilineItem // Something like: let a = 1 in () @@ -3608,35 +3578,19 @@ and collectMultilineItemForLetOrUses let sepNlnForBinding = sepNlnConsideringTriviaContentBeforeForMainNode (synBindingToFsAstType b) range - if bindingHasInKeyword b then + match inKeyword with + | Some inKw -> // single multiline item let expr = enterNodeFor (synBindingToFsAstType b) b.RangeOfBindingWithRhs +> genLetBinding astContext p b - +> genInKeyword b e + +> genTriviaFor SynExpr_LetOrUse_In inKw !- " in " +> expressionFitsOnRestOfLine expr (sepNln +> sepNlnForExpr +> expr) [ ColMultilineItem(expr, sepNlnForBinding) ] - else - multipleOrLongBs bs @ itemsForExpr + | None -> multipleOrLongBs bs @ itemsForExpr | bs, _ -> multipleOrLongBs bs @ itemsForExpr -and genInKeyword (binding: SynBinding) (e: SynExpr) (ctx: Context) = - let inKeyWordTrivia (binding: SynBinding) = - let inRange = ctx.MkRange binding.RangeOfBindingWithRhs.End e.Range.Start - - Map.tryFindOrEmptyList IN ctx.TriviaTokenNodes - |> TriviaHelpers.``keyword token after start column and on same line`` inRange - |> List.tryHead - - match inKeyWordTrivia binding with - | Some (_, tn) -> - (printContentBefore tn - +> !- " in " - +> printContentAfter tn) - ctx - | None -> sepNone ctx - and sepNlnBetweenTypeAndMembers (withKeywordRange: range option) (ms: SynMemberDefn list) = match List.tryHead ms with | Some m -> sepNlnTypeAndMembers SynTypeDefn_With withKeywordRange m.Range (synMemberDefnToFsAstType m) @@ -5512,28 +5466,19 @@ and genParenTupleWithIndentAndNewlines and genAfterAttributesBefore (astType: FsAstType) (r: Range option) : Context -> Context = optSingle (fun r -> genTriviaFor astType r id) r -and collectMultilineItemForSynExprKeepIndent - (astContext: ASTContext) - (inKeyWordTrivia: TriviaNode list) - (e: SynExpr) - : ColMultilineItem list = +and collectMultilineItemForSynExprKeepIndent (astContext: ASTContext) (e: SynExpr) : ColMultilineItem list = match e with | LetOrUses (bs, e) -> - collectMultilineItemForLetOrUses - astContext - inKeyWordTrivia - bs - e - (collectMultilineItemForSynExprKeepIndent astContext inKeyWordTrivia e) + collectMultilineItemForLetOrUses astContext bs (collectMultilineItemForSynExprKeepIndent astContext e) | Sequentials es -> let lastIndex = es.Length - 1 es |> List.mapi (fun idx e -> if idx = lastIndex then - collectMultilineItemForSynExprKeepIndent astContext inKeyWordTrivia e + collectMultilineItemForSynExprKeepIndent astContext e else - collectMultilineItemForSynExpr astContext inKeyWordTrivia e) + collectMultilineItemForSynExpr astContext e) |> List.collect id | KeepIndentMatch (matchKeywordRange, me, withRange, clauses, range, matchTriviaType) -> ColMultilineItem( @@ -5553,8 +5498,7 @@ and collectMultilineItemForSynExprKeepIndent and genExprKeepIndentInBranch (astContext: ASTContext) (e: SynExpr) : Context -> Context = let keepIndentExpr (ctx: Context) = - let items = - collectMultilineItemForSynExprKeepIndent astContext (Map.tryFindOrEmptyList IN ctx.TriviaTokenNodes) e + let items = collectMultilineItemForSynExprKeepIndent astContext e colWithNlnWhenItemIsMultilineUsingConfig items ctx diff --git a/src/Fantomas/SourceParser.fs b/src/Fantomas/SourceParser.fs index 32ce9fc6b5..c7f3ce1531 100644 --- a/src/Fantomas/SourceParser.fs +++ b/src/Fantomas/SourceParser.fs @@ -925,28 +925,38 @@ let (|JoinIn|_|) = | SynExpr.JoinIn (e1, _, e2, _) -> Some(e1, e2) | _ -> None -let (|LetOrUse|_|) = - function - | SynExpr.LetOrUse (isRec, isUse, xs, e, _, trivia) -> Some(isRec, isUse, xs, e) - | _ -> None +let private mkInKeyword (lastIndex: int) (index: int) (inKw: range option) (body: SynExpr) = + if index <> lastIndex then + None + else + match inKw with + | None -> None + | Some inKw -> + if Position.posEq inKw.Start body.Range.Start then + None + else + Some inKw + /// Unfold a list of let bindings /// Recursive and use properties have to be determined at this point let rec (|LetOrUses|_|) = function - | SynExpr.LetOrUse (isRec, isUse, xs, LetOrUses (ys, e), _, trivia) -> + | SynExpr.LetOrUse (isRec, isUse, xs, (LetOrUses (ys, e) as body), _, trivia) -> let prefix = if isUse then "use " elif isRec then "let rec " else "let " let xs' = + let lastIndex = xs.Length - 1 + List.mapi (fun i x -> if i = 0 then - (prefix, x) + (prefix, x, mkInKeyword lastIndex i trivia.InKeyword body) else - ("and ", x)) + ("and ", x, mkInKeyword lastIndex i trivia.InKeyword body)) xs Some(xs' @ ys, e) @@ -957,19 +967,21 @@ let rec (|LetOrUses|_|) = else "let " let xs' = + let lastIndex = xs.Length - 1 + List.mapi (fun i x -> if i = 0 then - (prefix, x) + (prefix, x, mkInKeyword lastIndex i trivia.InKeyword e) else - ("and ", x)) + ("and ", x, mkInKeyword lastIndex i trivia.InKeyword e)) xs Some(xs', e) | _ -> None type ComputationExpressionStatement = - | LetOrUseStatement of prefix: string * binding: SynBinding + | LetOrUseStatement of prefix: string * binding: SynBinding * inKeyword: range option | LetOrUseBangStatement of isUse: bool * SynPat * equalsRange: range option * SynExpr * range: range | AndBangStatement of SynPat * equalsRange: range * SynExpr * range: range | OtherStatement of SynExpr diff --git a/src/Fantomas/TokenParser.fs b/src/Fantomas/TokenParser.fs index 5110a6e012..7f63c30adf 100644 --- a/src/Fantomas/TokenParser.fs +++ b/src/Fantomas/TokenParser.fs @@ -1120,7 +1120,7 @@ let getTriviaFromTokens (mkRange: MkRange) (tokens: Token list) = fromTokens @ newLines |> List.sortBy (fun t -> t.Range.StartLine, t.Range.StartColumn) -let private tokenNames = [ "BAR"; "MEMBER"; "IN" ] +let private tokenNames = [ "BAR"; "MEMBER" ] let internal getFsToken tokenName = match tokenName with diff --git a/src/Fantomas/TriviaTypes.fs b/src/Fantomas/TriviaTypes.fs index a576771a89..26654c30a5 100644 --- a/src/Fantomas/TriviaTypes.fs +++ b/src/Fantomas/TriviaTypes.fs @@ -146,6 +146,7 @@ type FsAstType = | SynExpr_TypeApp_Less | SynExpr_TypeApp_Greater // | SynExpr_LetOrUse use first nested SynExpr + | SynExpr_LetOrUse_In | SynExpr_TryWith | SynExpr_TryWith_Try | SynExpr_TryWith_With From 78372b442f3827f3409c627b2fcddbab4e36765a Mon Sep 17 00:00:00 2001 From: nojaf Date: Fri, 4 Feb 2022 16:47:27 +0100 Subject: [PATCH 08/16] Process change of PR 12680, 12682, 12684 & 12691. --- src/Fantomas.Tests/CommentTests.fs | 2 + src/Fantomas.Tests/CompilerDirectivesTests.fs | 5 +- src/Fantomas.Tests/FormatAstTests.fs | 4 +- ...ineBlockBracketsOnSameColumnRecordTests.fs | 1 + .../NumberOfItemsRecordTests.fs | 4 +- src/Fantomas.Tests/RecordTests.fs | 5 +- src/Fantomas.Tests/SignatureTests.fs | 4 +- src/Fantomas.Tests/TestHelpers.fs | 3 +- src/Fantomas.Tests/TokenParserTests.fs | 22 --- src/Fantomas.Tests/TriviaTests.fs | 28 ++-- src/Fantomas.Tests/TypeDeclarationTests.fs | 2 +- src/Fantomas.Tests/UnionTests.fs | 12 +- src/Fantomas/AstTransformer.fs | 44 +++-- src/Fantomas/CodeFormatterImpl.fs | 2 +- src/Fantomas/CodePrinter.fs | 154 +++++++----------- src/Fantomas/SourceParser.fs | 69 ++++---- src/Fantomas/TokenParser.fs | 16 +- src/Fantomas/Trivia.fs | 40 +---- src/Fantomas/TriviaTypes.fs | 5 +- 19 files changed, 164 insertions(+), 258 deletions(-) diff --git a/src/Fantomas.Tests/CommentTests.fs b/src/Fantomas.Tests/CommentTests.fs index 26ede91311..6af6507c64 100644 --- a/src/Fantomas.Tests/CommentTests.fs +++ b/src/Fantomas.Tests/CommentTests.fs @@ -215,6 +215,7 @@ let f () = """ [] +[] let ``should keep well-aligned comments`` () = formatSourceString false @@ -245,6 +246,7 @@ let f () = """ [] +[] let ``should align mis-aligned comments`` () = formatSourceString false diff --git a/src/Fantomas.Tests/CompilerDirectivesTests.fs b/src/Fantomas.Tests/CompilerDirectivesTests.fs index 80019cd670..5642935b42 100644 --- a/src/Fantomas.Tests/CompilerDirectivesTests.fs +++ b/src/Fantomas.Tests/CompilerDirectivesTests.fs @@ -2237,10 +2237,9 @@ let getDefaultProxyFor = #if CUSTOM_WEBPROXY let result = { new IWebProxy with - member __.Credentials = null - member __.Credentials - with set _value = () + with get () = null + and set _value = () member __.GetProxy _ = null member __.IsBypassed(_host: Uri) = true } diff --git a/src/Fantomas.Tests/FormatAstTests.fs b/src/Fantomas.Tests/FormatAstTests.fs index 21b16d18ac..cf35f82ad9 100644 --- a/src/Fantomas.Tests/FormatAstTests.fs +++ b/src/Fantomas.Tests/FormatAstTests.fs @@ -88,7 +88,7 @@ type Foo = """[] type Foo = abstract foo: int - override __.foo = 1""" + default __.foo = 1""" [] let ``default implementations in abstract classes with `default` keyword should be emited as it was before from AST with origin source, 742`` @@ -130,7 +130,7 @@ let ``object expression should emit override keyword on AST formatting without o |> should equal """{ new System.IDisposable with - override __.Dispose() = () }""" + member __.Dispose() = () }""" [] let ``object expression should preserve member keyword on AST formatting with origin source, 742`` () = diff --git a/src/Fantomas.Tests/MultilineBlockBracketsOnSameColumnRecordTests.fs b/src/Fantomas.Tests/MultilineBlockBracketsOnSameColumnRecordTests.fs index 0255c9305c..462236d577 100644 --- a/src/Fantomas.Tests/MultilineBlockBracketsOnSameColumnRecordTests.fs +++ b/src/Fantomas.Tests/MultilineBlockBracketsOnSameColumnRecordTests.fs @@ -485,6 +485,7 @@ type Element = equal """ module RecordSignature + /// Represents simple XML elements. type Element = { diff --git a/src/Fantomas.Tests/NumberOfItemsRecordTests.fs b/src/Fantomas.Tests/NumberOfItemsRecordTests.fs index 282313ae1b..891e753864 100644 --- a/src/Fantomas.Tests/NumberOfItemsRecordTests.fs +++ b/src/Fantomas.Tests/NumberOfItemsRecordTests.fs @@ -437,10 +437,10 @@ type Element = equal """ module RecordSignature + /// Represents simple XML elements. type Element = - { - /// The attribute collection. + { /// The attribute collection. Attributes: IDictionary /// The children collection. diff --git a/src/Fantomas.Tests/RecordTests.fs b/src/Fantomas.Tests/RecordTests.fs index b33997e62b..e625d8e279 100644 --- a/src/Fantomas.Tests/RecordTests.fs +++ b/src/Fantomas.Tests/RecordTests.fs @@ -71,10 +71,10 @@ type Element = equal """ module RecordSignature + /// Represents simple XML elements. type Element = - { - /// The attribute collection. + { /// The attribute collection. Attributes: IDictionary; /// The children collection. @@ -824,6 +824,7 @@ type Element = equal """ module RecordSignature + /// Represents simple XML elements. type Element = { /// The attribute collection. diff --git a/src/Fantomas.Tests/SignatureTests.fs b/src/Fantomas.Tests/SignatureTests.fs index fbdee49e62..0d1fc96982 100644 --- a/src/Fantomas.Tests/SignatureTests.fs +++ b/src/Fantomas.Tests/SignatureTests.fs @@ -1352,7 +1352,7 @@ namespace Baz module Bar = [] - /// + //// val f : unit -> unit """ config @@ -1365,7 +1365,7 @@ namespace Baz module Bar = [] - /// + //// val f: unit -> unit """ diff --git a/src/Fantomas.Tests/TestHelpers.fs b/src/Fantomas.Tests/TestHelpers.fs index 03f22a529c..52a2e21bb5 100644 --- a/src/Fantomas.Tests/TestHelpers.fs +++ b/src/Fantomas.Tests/TestHelpers.fs @@ -23,8 +23,7 @@ let sharedChecker = lazy (FSharpChecker.Create()) let private safeToIgnoreWarnings = [ "This construct is deprecated: it is only for use in the F# library" - "Identifiers containing '@' are reserved for use in F# code generation" - "XML comment is not placed on a valid language element." ] + "Identifiers containing '@' are reserved for use in F# code generation" ] let private isValidAndHasNoWarnings fileName source parsingOptions = let allDefineOptions, _ = TokenParser.getDefines source diff --git a/src/Fantomas.Tests/TokenParserTests.fs b/src/Fantomas.Tests/TokenParserTests.fs index 759ae07eea..daefa0dbf2 100644 --- a/src/Fantomas.Tests/TokenParserTests.fs +++ b/src/Fantomas.Tests/TokenParserTests.fs @@ -300,28 +300,6 @@ let x = 1 | [ { Item = Newline }; { Item = Directive "#if NOT_DEFINED\n#else\n\n#endif" } ] -> pass () | _ -> Assert.Fail(sprintf "Unexpected trivia %A" triviaNodes) -[] -let ``member and override`` () = - let source = - """ -type MyLogInteface() = - interface LogInterface with - member x.Print msg = printfn "%s" msg - override x.GetLogFile environment = "..." -""" - - let triviaNodes = - tokenize source - |> getTriviaFromTokens - |> List.choose (fun { Item = item } -> - match item with - | Keyword { Content = kw } -> Some kw - | _ -> None) - - match triviaNodes with - | [ "member"; "override" ] -> pass () - | _ -> fail () - [] let ``at before string`` () = let source = "@\"foo\"" diff --git a/src/Fantomas.Tests/TriviaTests.fs b/src/Fantomas.Tests/TriviaTests.fs index 42ff2e3607..3e9ad75a6b 100644 --- a/src/Fantomas.Tests/TriviaTests.fs +++ b/src/Fantomas.Tests/TriviaTests.fs @@ -442,13 +442,13 @@ let a = b let ``multiple line comments form a single trivia`` () = let source = """ -/// Represents a long identifier with possible '.' at end. -/// -/// Typically dotms.Length = lid.Length-1, but they may be same if (incomplete) code ends in a dot, e.g. "Foo.Bar." -/// The dots mostly matter for parsing, and are typically ignored by the typechecker, but -/// if dotms.Length = lid.Length, then the parser must have reported an error, so the typechecker is allowed -/// more freedom about typechecking these expressions. -/// LongIdent can be empty list - it is used to denote that name of some AST element is absent (i.e. empty type name in inherit) +// Represents a long identifier with possible '.' at end. +// +// Typically dotms.Length = lid.Length-1, but they may be same if (incomplete) code ends in a dot, e.g. "Foo.Bar." +// The dots mostly matter for parsing, and are typically ignored by the typechecker, but +// if dotms.Length = lid.Length, then the parser must have reported an error, so the typechecker is allowed +// more freedom about typechecking these expressions. +// LongIdent can be empty list - it is used to denote that name of some AST element is absent (i.e. empty type name in inherit) type LongIdentWithDots = | LongIdentWithDots of id: LongIdent * dotms: range list """ @@ -457,13 +457,13 @@ type LongIdentWithDots = let expectedComment = String.normalizeNewLine - """/// Represents a long identifier with possible '.' at end. -/// -/// Typically dotms.Length = lid.Length-1, but they may be same if (incomplete) code ends in a dot, e.g. "Foo.Bar." -/// The dots mostly matter for parsing, and are typically ignored by the typechecker, but -/// if dotms.Length = lid.Length, then the parser must have reported an error, so the typechecker is allowed -/// more freedom about typechecking these expressions. -/// LongIdent can be empty list - it is used to denote that name of some AST element is absent (i.e. empty type name in inherit)""" + """// Represents a long identifier with possible '.' at end. +// +// Typically dotms.Length = lid.Length-1, but they may be same if (incomplete) code ends in a dot, e.g. "Foo.Bar." +// The dots mostly matter for parsing, and are typically ignored by the typechecker, but +// if dotms.Length = lid.Length, then the parser must have reported an error, so the typechecker is allowed +// more freedom about typechecking these expressions. +// LongIdent can be empty list - it is used to denote that name of some AST element is absent (i.e. empty type name in inherit)""" match trivia with | [ { ContentBefore = [ Comment (LineCommentOnSingleLine comment) ] } ] -> diff --git a/src/Fantomas.Tests/TypeDeclarationTests.fs b/src/Fantomas.Tests/TypeDeclarationTests.fs index a34a017d2d..64ac340d72 100644 --- a/src/Fantomas.Tests/TypeDeclarationTests.fs +++ b/src/Fantomas.Tests/TypeDeclarationTests.fs @@ -1093,7 +1093,7 @@ type Entity() = """ type Entity() = abstract Id: int with get, set - override val Id = 0 with get, set + default val Id = 0 with get, set """ [] diff --git a/src/Fantomas.Tests/UnionTests.fs b/src/Fantomas.Tests/UnionTests.fs index cda6fafb32..1d177ca2b5 100644 --- a/src/Fantomas.Tests/UnionTests.fs +++ b/src/Fantomas.Tests/UnionTests.fs @@ -359,7 +359,7 @@ let ``single case DU with comment above clause, 567`` () = false """type 'a MyGenericType = /// - Foo + | Foo """ config |> prepend newline @@ -368,7 +368,7 @@ let ``single case DU with comment above clause, 567`` () = """ type 'a MyGenericType = /// - Foo + | Foo """ [] @@ -648,8 +648,8 @@ let ``comment after union fields wrapped in parenthesis, 1128`` () = module Test type t = - | Beta of (unit -> unit) /// comment is gone - | Alpha of bool /// comment stays + | Beta of (unit -> unit) // comment is gone + | Alpha of bool // comment stays """ config |> prepend newline @@ -659,8 +659,8 @@ type t = module Test type t = - | Beta of (unit -> unit) /// comment is gone - | Alpha of bool /// comment stays + | Beta of (unit -> unit) // comment is gone + | Alpha of bool // comment stays """ [] diff --git a/src/Fantomas/AstTransformer.fs b/src/Fantomas/AstTransformer.fs index 13eb5ce314..8e9496a838 100644 --- a/src/Fantomas/AstTransformer.fs +++ b/src/Fantomas/AstTransformer.fs @@ -163,14 +163,15 @@ module private Ast = yield! nodes yield! visitSynType typeName ] |> finalContinuation) - | SynExpr.ObjExpr (objType, argOptions, withRange, bindings, extraImpls, _, range) -> + | SynExpr.ObjExpr (objType, argOptions, withRange, bindings, members, extraImpls, _, range) -> [ yield mkNode SynExpr_ObjExpr range yield! visitSynType objType if argOptions.IsSome then yield! visitArgsOption argOptions.Value yield! mkNodeOption SynExpr_ObjExpr_With withRange - yield! extraImpls |> List.collect visitSynInterfaceImpl - yield! bindings |> List.collect visitSynBinding ] + yield! bindings |> List.collect visitSynBinding + yield! members |> List.collect visitSynMemberDefn + yield! extraImpls |> List.collect visitSynInterfaceImpl ] |> finalContinuation | SynExpr.While (_, whileExpr, doExpr, range) -> let continuations: ((TriviaNodeAssigner list -> TriviaNodeAssigner list) -> TriviaNodeAssigner list) list = @@ -261,18 +262,9 @@ module private Ast = yield! mkNodeOption SynExpr_TypeApp_Greater greaterRange ] |> finalContinuation) | SynExpr.LetOrUse (_, _, bindings, body, _, trivia) -> - let inKeyword = - match trivia.InKeyword with - | None -> None - | Some inKw -> - if Position.posEq inKw.Start body.Range.Start then - None - else - Some inKw - visit body (fun nodes -> [ yield! (List.collect visitSynBinding bindings) - yield! mkNodeOption SynExpr_LetOrUse_In inKeyword + yield! mkNodeOption SynExpr_LetOrUse_In trivia.InKeyword yield! nodes ] |> finalContinuation) | SynExpr.TryWith (tryExpr, @@ -693,24 +685,22 @@ module private Ast = yield! mkNodeOption SynMatchClause_Arrow trivia.ArrowRange yield! visitSynExpr e2 ] - // TODO: revisit after https://github.com/dotnet/fsharp/issues/12619 - and visitSynExprAndBang - (SynExprAndBang (_, _, _, pat, equalsRange, body, andBangKeyword)) - : TriviaNodeAssigner list = - [ yield mkNode SynExprAndBang_ (Range.unionRanges andBangKeyword body.Range) + and visitSynExprAndBang (SynExprAndBang (_, _, _, pat, body, range, trivia)) : TriviaNodeAssigner list = + [ yield mkNode SynExprAndBang_ range yield! visitSynPat pat - yield mkNode SynExprAndBang_Equals equalsRange + yield mkNode SynExprAndBang_Equals trivia.EqualsRange yield! visitSynExpr body ] and visitArgsOption (expr: SynExpr, _: Ident option) = visitSynExpr expr and visitSynInterfaceImpl (ii: SynInterfaceImpl) : TriviaNodeAssigner list = match ii with - | SynInterfaceImpl (typ, withKeyword, bindings, range) -> + | SynInterfaceImpl (typ, withKeyword, bindings, members, range) -> [ yield mkNode SynInterfaceImpl_ range yield! mkNodeOption SynInterfaceImpl_With withKeyword yield! visitSynType typ - yield! (bindings |> List.collect visitSynBinding) ] + yield! (bindings |> List.collect visitSynBinding) + yield! (members |> List.collect visitSynMemberDefn) ] and visitSynTypeDefn (td: SynTypeDefn) = match td with @@ -947,7 +937,7 @@ module private Ast = yield! nodes yield! (visitSynAttributeLists attrs) ] |> finalContinuation) - | SynPat.Or (synPat, synPat2, _range) -> + | SynPat.Or (synPat, synPat2, _range, trivia) -> let continuations: ((TriviaNodeAssigner list -> TriviaNodeAssigner list) -> TriviaNodeAssigner list) list = [ visit synPat; visit synPat2 ] @@ -1359,13 +1349,19 @@ module private Ast = and visitSynModuleOrNamespaceSig (modOrNs: SynModuleOrNamespaceSig) : TriviaNodeAssigner list = match modOrNs with - | SynModuleOrNamespaceSig (longIdent, _, kind, decls, _, attrs, _, _range) -> + | SynModuleOrNamespaceSig (longIdent, _, kind, decls, _, attrs, _, range) -> let longIdentNodes = match kind, decls with | SynModuleOrNamespaceKind.AnonModule, _ :: _ -> [] | _ -> visitLongIdentIncludingFullRange longIdent - [ yield! longIdentNodes + let moduleOrNamespaceSig = + match kind with + | SynModuleOrNamespaceKind.NamedModule -> [ mkNode SynModuleOrNamespaceSig_NamedModule range ] + | _ -> [] + + [ yield! moduleOrNamespaceSig + yield! longIdentNodes yield! (visitSynAttributeLists attrs) yield! (decls |> List.collect visitSynModuleSigDecl) ] diff --git a/src/Fantomas/CodeFormatterImpl.fs b/src/Fantomas/CodeFormatterImpl.fs index da6853b4e0..255f4cca65 100644 --- a/src/Fantomas/CodeFormatterImpl.fs +++ b/src/Fantomas/CodeFormatterImpl.fs @@ -290,7 +290,7 @@ let isValidAST ast = | SynPat.As (pat1, pat2, _) -> validatePattern pat1 && validatePattern pat2 | SynPat.Typed (pat, _typ, _range) -> validatePattern pat | SynPat.Attrib (pat, _attrib, _range) -> validatePattern pat - | SynPat.Or (pat1, pat2, _range) -> validatePattern pat1 && validatePattern pat2 + | SynPat.Or (lhsPat = pat1; rhsPat = pat2) -> validatePattern pat1 && validatePattern pat2 | SynPat.Ands (pats, _range) -> List.forall validatePattern pats | SynPat.LongIdent (argPats = constructorArgs) -> validateConstructorArgs constructorArgs | SynPat.Tuple (false, pats, _range) -> List.forall validatePattern pats diff --git a/src/Fantomas/CodePrinter.fs b/src/Fantomas/CodePrinter.fs index 1fb8132f98..86efb4a40d 100644 --- a/src/Fantomas/CodePrinter.fs +++ b/src/Fantomas/CodePrinter.fs @@ -156,7 +156,7 @@ and genModuleOrNamespace astContext (ModuleOrNamespace (ats, px, ao, lids, mds, +> sepModuleAndFirstDecl +> genModuleDeclList astContext mds -and genSigModuleOrNamespace astContext (SigModuleOrNamespace (ats, px, ao, lids, mds, isRecursive, moduleKind)) = +and genSigModuleOrNamespace astContext (SigModuleOrNamespace (ats, px, ao, lids, mds, isRecursive, moduleKind, range)) = let sepModuleAndFirstDecl = let firstDecl = List.tryHead mds @@ -172,7 +172,7 @@ and genSigModuleOrNamespace astContext (SigModuleOrNamespace (ats, px, ao, lids, let lidsFullRange = match lids with - | [] -> range.Zero + | [] -> FSharp.Compiler.Text.range.Zero | (_, r) :: _ -> Range.unionRanges r (List.last lids |> snd) let moduleOrNamespace = @@ -187,6 +187,9 @@ and genSigModuleOrNamespace astContext (SigModuleOrNamespace (ats, px, ao, lids, +> ifElse (moduleKind = SynModuleOrNamespaceKind.AnonModule) sepNone moduleOrNamespace +> sepModuleAndFirstDecl +> genSigModuleDeclList astContext mds + |> (match moduleKind with + | SynModuleOrNamespaceKind.NamedModule -> genTriviaFor SynModuleOrNamespaceSig_NamedModule range + | _ -> id) and genModuleDeclList astContext e = let rec collectItems @@ -504,11 +507,8 @@ and genAttributes astContext (ats: SynAttributes) = chain ctx) sepNone -and genPreXmlDoc (PreXmlDoc lines) ctx = - if ctx.Config.StrictMode then - colPost sepNln sepNln lines (sprintf "///%s" >> (!-)) ctx - else - ctx +and genPreXmlDoc (PreXmlDoc lines) = + colPost sepNln sepNln lines (sprintf "///%s" >> (!-)) and genExprSepEqPrependType (astContext: ASTContext) @@ -711,7 +711,7 @@ and genPropertyWithGetSet astContext (b1, b2) = let prefix = genPreXmlDoc px +> genAttributes astContext ats - +> genMemberFlags astContext mf1 + +> genMemberFlags mf1 +> ifElse isInline (!- "inline ") sepNone +> opt sepSpace ao genAccess @@ -772,7 +772,7 @@ and genMemberBinding astContext b = let prefix = genPreXmlDoc px +> genAttributes astContext ats - +> genMemberFlags astContext mf + +> genMemberFlags mf +> ifElse isInline (!- "inline ") sepNone +> opt sepSpace ao genAccess @@ -827,7 +827,7 @@ and genMemberBinding astContext b = | p -> failwithf "Unexpected pattern: %O" p | MemberBinding (ats, px, ao, isInline, mf, p, equalsRange, e, synValInfo) -> - let prefix = genMemberFlagsForMemberBinding astContext mf b.RangeOfBindingWithRhs + let prefix = genMemberFlags mf genMemberBindingImpl astContext prefix b ats px ao isInline p equalsRange e synValInfo @@ -952,50 +952,17 @@ and genMemberBindingImpl equalsRange e -and genMemberFlags astContext (mf: SynMemberFlags) = - match mf with - | MFMember _ -> !- "member " - | MFStaticMember _ -> !- "static member " - | MFConstructor _ -> sepNone - | MFOverride _ -> ifElse astContext.InterfaceRange.IsSome (!- "member ") (!- "override ") - -and genMemberFlagsForMemberBinding astContext (mf: SynMemberFlags) (rangeOfBindingAndRhs: Range) = - fun ctx -> - // TODO: fix https://github.com/dotnet/fsharp/issues/11508 and get rid of this mess - let keywordFromTrivia = - [ yield! (Map.tryFindOrEmptyList SynMemberDefn_Member ctx.TriviaMainNodes) - yield! (Map.tryFindOrEmptyList SynMemberSig_Member ctx.TriviaMainNodes) - yield! (Map.tryFindOrEmptyList MEMBER ctx.TriviaTokenNodes) ] - |> List.tryFind (fun { Type = t; Range = r } -> - match t with - | MainNode SynMemberDefn_Member - | MainNode SynMemberSig_Member -> // trying to get AST trivia - RangeHelpers.``range contains`` r rangeOfBindingAndRhs - - | Token (MEMBER, _) -> // trying to get token trivia - r.StartLine = rangeOfBindingAndRhs.StartLine - // In case the member has attributes - || RangeHelpers.``range contains`` rangeOfBindingAndRhs r - - | _ -> false) - |> Option.bind (fun tn -> - tn.ContentItself - |> Option.bind (fun tc -> - match tc with - | Keyword { Content = "override" | "default" | "member" | "abstract" | "abstract member" as kw } -> - Some(!-(kw + " ")) - | _ -> None)) - - match mf with - | MFStaticMember _ - | MFConstructor _ -> genMemberFlags astContext mf - | MFMember _ -> - keywordFromTrivia - |> Option.defaultValue (genMemberFlags astContext mf) - | MFOverride _ -> - keywordFromTrivia - |> Option.defaultValue (!- "override ") - <| ctx +and genMemberFlags (mf: SynMemberFlags) = + match mf.Trivia with + | { StaticRange = Some _s + MemberRange = Some _m } -> !- "static member " + | { OverrideRange = Some _o } -> !- "override " + | { DefaultRange = Some _d } -> !- "default " + | { AbstractRange = Some _a + MemberRange = Some _m } -> !- "abstract member " + | { MemberRange = Some _m } -> !- "member " + | { AbstractRange = Some _a } -> !- "abstract " + | _ -> sepNone and genVal astContext (Val (ats, px, ao, s, identRange, t, vi, isInline, isMutable, tds, eo, range)) = let typeName = genTypeAndParam astContext s tds [] @@ -1457,8 +1424,8 @@ and genExpr astContext synExpr ctx = let size = getRecordSize ctx fields isSmallExpression size smallExpression longExpression ctx - | ObjExpr (t, eio, withKeyword, bd, ims, range) -> - if List.isEmpty bd then + | ObjExpr (t, eio, withKeyword, bd, members, ims, range) -> + if List.isEmpty bd && List.isEmpty members then // Check the role of the second part of eio let param = opt sepNone (Option.map fst eio) (genExpr astContext) @@ -1470,8 +1437,8 @@ and genExpr astContext synExpr ctx = +> sepCloseS else ifAlignBrackets - (genObjExprAlignBrackets t eio withKeyword bd ims range astContext) - (genObjExpr t eio withKeyword bd ims range astContext) + (genObjExprAlignBrackets t eio withKeyword bd members ims range astContext) + (genObjExpr t eio withKeyword bd members ims range astContext) | While (e1, e2) -> atCurrentColumn ( @@ -3183,7 +3150,7 @@ and genMultilineAnonRecordAlignBrackets (isStruct: bool) fields copyInfo astCont ifElse isStruct !- "struct " sepNone +> atCurrentColumnIndent genAnonRecord -and genObjExpr t eio withKeyword bd ims range (astContext: ASTContext) = +and genObjExpr t eio withKeyword bd members ims range (astContext: ASTContext) = // Check the role of the second part of eio let param = opt sepNone (Option.map fst eio) (genExpr astContext) @@ -3196,12 +3163,13 @@ and genObjExpr t eio withKeyword bd ims range (astContext: ASTContext) = +> indent +> sepNln +> genMemberBindingList { astContext with InterfaceRange = Some range } bd + +> genMemberDefnList astContext members +> unindent +> colPre sepNln sepNln ims (genInterfaceImpl astContext) ) +> sepCloseS -and genObjExprAlignBrackets t eio withKeyword bd ims range (astContext: ASTContext) = +and genObjExprAlignBrackets t eio withKeyword bd members ims range (astContext: ASTContext) = // Check the role of the second part of eio let param = opt sepNone (Option.map fst eio) (genExpr astContext) @@ -3214,6 +3182,7 @@ and genObjExprAlignBrackets t eio withKeyword bd ims range (astContext: ASTConte +> indent +> sepNln +> genMemberBindingList { astContext with InterfaceRange = Some range } bd + +> genMemberDefnList astContext members +> unindent +> colPre sepNln sepNln ims (genInterfaceImpl astContext) ) @@ -4145,7 +4114,7 @@ and genMemberSig astContext node = genPreXmlDoc px +> genAttributes astContext ats - +> genMemberFlagsForMemberBinding { astContext with InterfaceRange = None } mf range + +> genMemberFlags mf +> ifElse isInline (!- "inline ") sepNone +> opt sepSpace ao genAccess +> genTypeAndParam astContext (if s = "``new``" then "new" else s) tds [] @@ -4590,16 +4559,17 @@ and genTypeConstraint astContext node = +> col sepComma ts (genType astContext false) -- ">" -and genInterfaceImpl astContext (InterfaceImpl (t, withKeywordRange, bs, range)) = - match bs with - | [] -> !- "interface " +> genType astContext false t - | bs -> +and genInterfaceImpl astContext (InterfaceImpl (t, withKeywordRange, bs, members, range)) = + if bs.IsEmpty && members.IsEmpty then + !- "interface " +> genType astContext false t + else !- "interface " +> genType astContext false t +> genTriviaForOption SynInterfaceImpl_With withKeywordRange !- " with" +> indent +> sepNln +> genMemberBindingList { astContext with InterfaceRange = Some range } bs + +> genMemberDefnList astContext members +> unindent and genClause astContext hasBar (Clause (p, eo, arrowRange, e) as ce) = @@ -4723,7 +4693,7 @@ and genMemberDefn astContext node = | MDInherit (t, _) -> !- "inherit " +> genType astContext false t | MDValField f -> genField astContext "val " f - | MDImplicitCtor (ats, ao, ps, so) -> + | MDImplicitCtor (xmlDoc, ats, ao, ps, so) -> let rec simplePats ps = match ps with | SynSimplePats.SimplePats (pats, _) -> pats @@ -4746,9 +4716,12 @@ and genMemberDefn astContext node = isEmpty ps + let hasXmlDocComment = ((|PreXmlDoc|) xmlDoc).Length > 0 + let longExpr ctx = (indent +> sepNln + +> genPreXmlDoc xmlDoc +> optSingle (fun ao -> genAccess ao +> sepNln) ao +> ifElse emptyPats (sepOpenT +> sepCloseT) (fun ctx -> let shortPats = @@ -4775,12 +4748,16 @@ and genMemberDefn astContext node = +> expressionFitsOnRestOfLine shortPats longPats +> printContentAfter tn) ctx + | None when hasXmlDocComment -> expressionFitsOnRestOfLine shortPats longPats ctx | _ -> longPats ctx) +> onlyIf ctx.Config.AlternativeLongMemberDefinitions sepNln +> unindent) ctx - expressionFitsOnRestOfLine shortExpr longExpr + if hasXmlDocComment then + longExpr + else + expressionFitsOnRestOfLine shortExpr longExpr // In implicit constructor, attributes should come even before access qualifiers ifElse ats.IsEmpty sepNone (sepSpace +> genOnelinerAttributes astContext ats) @@ -4837,7 +4814,7 @@ and genMemberDefn astContext node = genPreXmlDoc px +> genAttributes astContext ats - +> genMemberFlags astContext (memberKindToMemberFlags mk) + +> genMemberFlags (memberKindToMemberFlags mk) +> str "val " +> opt sepSpace ao genAccess -- s @@ -4848,7 +4825,7 @@ and genMemberDefn astContext node = -- genPropertyKind (not isFunctionProperty) mk ) - | MDAbstractSlot (ats, px, ao, s, t, vi, ValTyparDecls (tds, _), MFMemberFlags mk) -> + | MDAbstractSlot (ats, px, ao, s, t, vi, ValTyparDecls (tds, _), mf) -> let (FunType namedArgs) = (t, vi) let isFunctionProperty = @@ -4856,32 +4833,17 @@ and genMemberDefn astContext node = | TFun _ -> true | _ -> false - let genAbstractMemberKeyword (ctx: Context) = - Map.tryFindOrEmptyList MEMBER ctx.TriviaTokenNodes - |> List.choose (fun tn -> - if tn.Range.StartLine = node.Range.StartLine then - match tn.ContentItself with - | Some (Keyword kw) -> Some kw.Content - | _ -> None - else - None) - |> List.tryHead - |> fun keywordOpt -> - match keywordOpt with - | Some kw -> sprintf "%s %s" kw s - | None -> sprintf "abstract %s" s - |> fun s -> !- s ctx - let hasGenerics = Option.isSome tds genPreXmlDoc px +> genAttributes astContext ats +> opt sepSpace ao genAccess - +> genAbstractMemberKeyword + +> genMemberFlags mf + +> !-s +> genTypeParamPostfix astContext tds +> ifElse hasGenerics sepColonWithSpacesFixed sepColon +> autoIndentAndNlnIfExpressionExceedsPageWidth (genTypeList astContext namedArgs) - -- genPropertyKind (not isFunctionProperty) mk + -- genPropertyKind (not isFunctionProperty) mf.MemberKind +> autoIndentAndNlnIfExpressionExceedsPageWidth (genConstraints astContext t vi) | md -> failwithf "Unexpected member definition: %O" md @@ -4942,12 +4904,10 @@ and genPat astContext pat = | PatAttrib (p, ats) -> genOnelinerAttributes astContext ats +> genPat astContext p - | PatOr (p1, p2) -> - let barRange (ctx: Context) = ctx.MkRange p1.Range.End p2.Range.Start - + | PatOr (p1, barRange, p2) -> genPat astContext p1 +> ifElse astContext.IsInsideMatchClausePattern sepNln sepSpace - +> fun ctx -> enterNodeTokenByName (barRange ctx) BAR ctx + +> enterNodeTokenByName barRange BAR -- "| " +> genPat astContext p2 | PatAnds ps -> col (!- " & ") ps (genPat astContext) @@ -5032,7 +4992,7 @@ and genPat astContext pat = +> sepOpenT +> atCurrentColumn (colAutoNlnSkip0 sepComma ps (genPat astContext)) +> sepCloseT - | PatSeq (patListType, [ PatOrs patOrs ]) -> + | PatSeq (patListType, [ PatOrs (patOr, patOrs) ]) -> let sepOpen, sepClose = match patListType with | PatArray -> sepOpenA, sepCloseA @@ -5040,7 +5000,9 @@ and genPat astContext pat = let short = sepOpen - +> col (sepSpace +> sepBar) patOrs (genPat astContext) + +> genPat astContext patOr + +> sepSpace + +> col sepSpace patOrs (fun (barRange, p) -> sepBar +> genPat astContext p) +> sepClose let long = @@ -5048,11 +5010,11 @@ and genPat astContext pat = +> atCurrentColumnIndent ( match patOrs with | [] -> sepNone - | hp :: pats -> - genPat astContext hp +> sepNln -- " " + | pats -> + genPat astContext patOr +> sepNln -- " " +> atCurrentColumn ( sepBar - +> col (sepNln +> sepBar) pats (genPat astContext) + +> col (sepNln +> sepBar) pats (fun (barRange, p) -> genPat astContext p) ) ) +> sepClose diff --git a/src/Fantomas/SourceParser.fs b/src/Fantomas/SourceParser.fs index c7f3ce1531..c87f2214d4 100644 --- a/src/Fantomas/SourceParser.fs +++ b/src/Fantomas/SourceParser.fs @@ -245,15 +245,16 @@ let (|ModuleOrNamespace|) (ats, px, ao, lids, mds, isRecursive, kind) let (|SigModuleOrNamespace|) - (SynModuleOrNamespaceSig.SynModuleOrNamespaceSig (LongIdentPieces lids, isRecursive, kind, mds, px, ats, ao, _)) + (SynModuleOrNamespaceSig.SynModuleOrNamespaceSig (LongIdentPieces lids, isRecursive, kind, mds, px, ats, ao, range)) = - (ats, px, ao, lids, mds, isRecursive, kind) + (ats, px, ao, lids, mds, isRecursive, kind, range) let (|EmptyFile|_|) (input: ParsedInput) = match input with | ImplFile (ParsedImplFileInput (_, [ ModuleOrNamespace (_, _, _, _, [], _, SynModuleOrNamespaceKind.AnonModule) ])) -> Some input - | SigFile (ParsedSigFileInput (_, [ SigModuleOrNamespace (_, _, _, _, [], _, SynModuleOrNamespaceKind.AnonModule) ])) -> + | SigFile (ParsedSigFileInput (_, + [ SigModuleOrNamespace (_, _, _, _, [], _, SynModuleOrNamespaceKind.AnonModule, _) ])) -> Some input | _ -> None @@ -456,7 +457,7 @@ let (|MDValField|_|) = let (|MDImplicitCtor|_|) = function - | SynMemberDefn.ImplicitCtor (ao, ats, ps, ido, _docs, _) -> Some(ats, ao, ps, Option.map (|Ident|) ido) + | SynMemberDefn.ImplicitCtor (ao, ats, ps, ido, docs, _) -> Some(docs, ats, ao, ps, Option.map (|Ident|) ido) | _ -> None let (|MDMember|_|) = @@ -500,7 +501,8 @@ let (|MDAutoProperty|_|) = // Interface impl -let (|InterfaceImpl|) (SynInterfaceImpl (t, withKeywordRange, bs, range)) = (t, withKeywordRange, bs, range) +let (|InterfaceImpl|) (SynInterfaceImpl (t, withKeywordRange, bs, members, range)) = + (t, withKeywordRange, bs, members, range) // Bindings @@ -526,8 +528,6 @@ let (|MFProperty|_|) (mf: SynMemberFlags) = | SynMemberKind.PropertyGetSet as mk -> Some mk | _ -> None -let (|MFMemberFlags|) (mf: SynMemberFlags) = mf.MemberKind - /// This pattern finds out which keyword to use let (|MFMember|MFStaticMember|MFConstructor|MFOverride|) (mf: SynMemberFlags) = match mf.MemberKind with @@ -925,19 +925,6 @@ let (|JoinIn|_|) = | SynExpr.JoinIn (e1, _, e2, _) -> Some(e1, e2) | _ -> None -let private mkInKeyword (lastIndex: int) (index: int) (inKw: range option) (body: SynExpr) = - if index <> lastIndex then - None - else - match inKw with - | None -> None - | Some inKw -> - if Position.posEq inKw.Start body.Range.Start then - None - else - Some inKw - - /// Unfold a list of let bindings /// Recursive and use properties have to be determined at this point let rec (|LetOrUses|_|) = @@ -954,9 +941,19 @@ let rec (|LetOrUses|_|) = List.mapi (fun i x -> if i = 0 then - (prefix, x, mkInKeyword lastIndex i trivia.InKeyword body) + (prefix, + x, + if i = lastIndex then + trivia.InKeyword + else + None) else - ("and ", x, mkInKeyword lastIndex i trivia.InKeyword body)) + ("and ", + x, + if i = lastIndex then + trivia.InKeyword + else + None)) xs Some(xs' @ ys, e) @@ -972,9 +969,19 @@ let rec (|LetOrUses|_|) = List.mapi (fun i x -> if i = 0 then - (prefix, x, mkInKeyword lastIndex i trivia.InKeyword e) + (prefix, + x, + if i = lastIndex then + trivia.InKeyword + else + None) else - ("and ", x, mkInKeyword lastIndex i trivia.InKeyword e)) + ("and ", + x, + if i = lastIndex then + trivia.InKeyword + else + None)) xs Some(xs', e) @@ -1003,9 +1010,8 @@ let rec collectComputationExpressionStatements let andBangs = andBangs - |> List.map (fun (SynExprAndBang (_, _, _, ap, equalsRange, ae, andBangKeyword)) -> - let range = Range.unionRanges andBangKeyword ae.Range - AndBangStatement(ap, equalsRange, ae, range)) + |> List.map (fun (SynExprAndBang (_, _, _, ap, ae, range, trivia)) -> + AndBangStatement(ap, trivia.EqualsRange, ae, range)) collectComputationExpressionStatements body (fun bodyStatements -> [ letOrUseBang @@ -1143,7 +1149,8 @@ let (|AnonRecord|_|) = let (|ObjExpr|_|) = function - | SynExpr.ObjExpr (t, eio, withKeyword, bd, ims, _, range) -> Some(t, eio, withKeyword, bd, ims, range) + | SynExpr.ObjExpr (t, eio, withKeyword, bd, members, ims, _, range) -> + Some(t, eio, withKeyword, bd, members, ims, range) | _ -> None let (|LongIdentSet|_|) = @@ -1199,13 +1206,13 @@ let (|PatAttrib|_|) = let (|PatOr|_|) = function - | SynPat.Or (p1, p2, _) -> Some(p1, p2) + | SynPat.Or (p1, p2, _, trivia) -> Some(p1, trivia.BarRange, p2) | _ -> None let rec (|PatOrs|_|) = function - | PatOr (PatOrs pats, p2) -> Some [ yield! pats; yield p2 ] - | PatOr (p1, p2) -> Some [ p1; p2 ] + | PatOr (PatOrs (p1, pats), barRange, p2) -> Some(p1, [ yield! pats; yield (barRange, p2) ]) + | PatOr (p1, barRange, p2) -> Some(p1, [ barRange, p2 ]) | _ -> None let (|PatAnds|_|) = diff --git a/src/Fantomas/TokenParser.fs b/src/Fantomas/TokenParser.fs index 7f63c30adf..519d0b22ca 100644 --- a/src/Fantomas/TokenParser.fs +++ b/src/Fantomas/TokenParser.fs @@ -450,14 +450,7 @@ let private getContentFromTokens tokens = |> List.map (fun t -> t.Content) |> String.concat String.Empty -let private keywordTrivia = - [ "OVERRIDE" - "MEMBER" - "DEFAULT" - "ABSTRACT" - "KEYWORD_STRING" - "QMARK" - "IN" ] +let private keywordTrivia = [ "KEYWORD_STRING"; "QMARK" ] let private numberTrivia = [ "UINT8" @@ -805,6 +798,10 @@ let rec private getTriviaFromTokensThemSelves foundTrivia = match tokens with + // Skip triple slash comments + | LineComments ({ Content = "///" } :: _, rest) -> + getTriviaFromTokensThemSelves mkRange lastButOneNonWhiteSpaceToken lastNonWhiteSpaceToken rest foundTrivia + | LineComments ({ LineNumber = headLineNumber } :: _ as commentTokens, rest) -> let isAfterSourceCode = match lastButOneNonWhiteSpaceToken, lastNonWhiteSpaceToken with @@ -1120,7 +1117,7 @@ let getTriviaFromTokens (mkRange: MkRange) (tokens: Token list) = fromTokens @ newLines |> List.sortBy (fun t -> t.Range.StartLine, t.Range.StartColumn) -let private tokenNames = [ "BAR"; "MEMBER" ] +let private tokenNames = [ "BAR" ] let internal getFsToken tokenName = match tokenName with @@ -1151,7 +1148,6 @@ let internal getFsToken tokenName = | "INT32_DOT_DOT" -> INT32_DOT_DOT | "LESS" -> LESS | "LPAREN_STAR_RPAREN" -> LPAREN_STAR_RPAREN - | "MEMBER" -> MEMBER | "MINUS" -> MINUS | "PERCENT_OP" -> PERCENT_OP | "PLUS_MINUS_OP" -> PLUS_MINUS_OP diff --git a/src/Fantomas/Trivia.fs b/src/Fantomas/Trivia.fs index 480e3b1f4d..0b0a895a8a 100644 --- a/src/Fantomas/Trivia.fs +++ b/src/Fantomas/Trivia.fs @@ -37,7 +37,8 @@ let inline private mainNodeIs name (t: TriviaNodeAssigner) = // so it is not an ideal candidate node to have trivia content let inline private isNotMemberKeyword (node: TriviaNodeAssigner) = match node.Type with - | Token (MEMBER, _) -> false + // TODO: probably replace with main node counterpart, or not +// | Token (MEMBER, _) -> false | _ -> true let private findFirstNodeAfterLine (nodes: TriviaNodeAssigner list) (lineNumber: int) : TriviaNodeAssigner option = @@ -75,15 +76,6 @@ let private findNodeOnLineAndColumn (nodes: TriviaNodeAssigner list) line column tn.Range.StartLine = line && tn.Range.StartColumn = column) -let private findMemberDefnMemberNodeOnLine (nodes: TriviaNodeAssigner list) line = - nodes - |> List.tryFind (fun tn -> - match tn.Type, tn.Range.StartLine = line with - | MainNode SynMemberDefn_Member, true - | MainNode SynMemberSig_Member, true - | Token (MEMBER, _), true -> true - | _ -> false) - let private findNodeBeforeLineAndColumn (nodes: TriviaNodeAssigner list) line column = let node = nodes @@ -301,34 +293,6 @@ let private addTriviaToTriviaNode (startOfSourceCode: int) (triviaNodes: TriviaN findNodeBeforeLineFromStart triviaNodes range.StartLine |> updateTriviaNode (fun tn -> tn.ContentAfter.Add(Newline)) triviaNodes - | { Item = Keyword ({ Content = keyword } as kw) - Range = range } when - (keyword = "override" - || keyword = "default" - || keyword = "member" - || keyword = "abstract") - -> - findMemberDefnMemberNodeOnLine triviaNodes range.StartLine - |> updateTriviaNode - (fun tn -> - match tn.Type, tn.ContentItself with - | TriviaNodeType.Token (MEMBER, _), Some (Keyword ({ Content = existingKeywordContent } as token)) - | MainNode SynMemberSig_Member, Some (Keyword ({ Content = existingKeywordContent } as token)) when - existingKeywordContent = "abstract" - && keyword = "member" - -> - // Combine the two tokens to appear as one - let tokenInfo = { token.TokenInfo with RightColumn = kw.TokenInfo.RightColumn } - - let combinedKeyword = - { token with - Content = "abstract member" - TokenInfo = tokenInfo } - - tn.ContentItself <- Some(Keyword(combinedKeyword)) - | _ -> tn.ContentItself <- Some(Keyword(kw))) - triviaNodes - | { Item = Keyword ({ TokenInfo = { TokenName = tn } } as kw) Range = range } when (tn = "QMARK") -> findSynConstStringNodeAfter triviaNodes range diff --git a/src/Fantomas/TriviaTypes.fs b/src/Fantomas/TriviaTypes.fs index 26654c30a5..da646986c1 100644 --- a/src/Fantomas/TriviaTypes.fs +++ b/src/Fantomas/TriviaTypes.fs @@ -31,7 +31,6 @@ type FsTokenType = | INT32_DOT_DOT | LESS | LPAREN_STAR_RPAREN - | MEMBER | MINUS | PERCENT_OP | PLUS_MINUS_OP @@ -395,11 +394,13 @@ type FsAstType = | ParsedHashDirectiveArgument_String | ParsedHashDirectiveArgument_SourceIdentifier // Modules and namespaces cannot really be trusted + // Update 2022: this is not entirely true anymore. + // TODO: investigate what the status of this is. // Their range can be influenced by non code constructs (like comments) // | SynModuleOrNamespaceSig_AnonModule // | SynModuleOrNamespaceSig_DeclaredNamespace // | SynModuleOrNamespaceSig_GlobalNamespace -// | SynModuleOrNamespaceSig_NamedModule + | SynModuleOrNamespaceSig_NamedModule | SynModuleSigDecl_ModuleAbbrev | SynModuleSigDecl_NestedModule | SynModuleSigDecl_NestedModule_AfterAttributesBeforeModuleName From aeb1832499e4bc950c25160a5cf24c1623e7fa5c Mon Sep 17 00:00:00 2001 From: nojaf Date: Fri, 4 Feb 2022 17:23:27 +0100 Subject: [PATCH 09/16] Remove FsTokenType. --- src/Fantomas.Tests/TokenParserTests.fs | 1 - src/Fantomas.Tests/TriviaTests.fs | 30 ++--- src/Fantomas/AstTransformer.fs | 15 ++- src/Fantomas/CodePrinter.fs | 22 ++-- src/Fantomas/Context.fs | 88 +------------- src/Fantomas/SourceParser.fs | 2 +- src/Fantomas/TokenParser.fs | 47 -------- src/Fantomas/Trivia.fs | 161 ++++++------------------- src/Fantomas/TriviaContext.fs | 6 - src/Fantomas/TriviaHelpers.fs | 65 ---------- src/Fantomas/TriviaTypes.fs | 46 +------ 11 files changed, 73 insertions(+), 410 deletions(-) diff --git a/src/Fantomas.Tests/TokenParserTests.fs b/src/Fantomas.Tests/TokenParserTests.fs index daefa0dbf2..9440ccf66c 100644 --- a/src/Fantomas.Tests/TokenParserTests.fs +++ b/src/Fantomas.Tests/TokenParserTests.fs @@ -27,7 +27,6 @@ let private mkRange: MkRange = (FSharp.Compiler.Text.Position.mkPos el ec) let private getTriviaFromTokens = getTriviaFromTokens mkRange -let private getTriviaNodesFromTokens = getTriviaNodesFromTokens mkRange [] let ``simple compiler directive should be found`` () = diff --git a/src/Fantomas.Tests/TriviaTests.fs b/src/Fantomas.Tests/TriviaTests.fs index 3e9ad75a6b..fbbb94bf60 100644 --- a/src/Fantomas.Tests/TriviaTests.fs +++ b/src/Fantomas.Tests/TriviaTests.fs @@ -63,7 +63,7 @@ let ``line comment on same line, is after last AST item`` () = let triviaNodes = toTrivia source |> List.head match triviaNodes with - | [ { Type = MainNode SynConst_Int32 + | [ { Type = SynConst_Int32 ContentAfter = [ Comment (LineCommentAfterSourceCode lineComment) ] } ] -> lineComment == "// should be 8" | _ -> Assert.Fail(sprintf "Unexpected trivia %A" triviaNodes) @@ -111,7 +111,7 @@ let ``comments inside record`` () = let triviaNodes = toTrivia source |> List.head match triviaNodes with - | [ { Type = TriviaNodeType.MainNode SynExpr_Record_OpeningBrace + | [ { Type = SynExpr_Record_OpeningBrace ContentAfter = [ Comment (LineCommentAfterSourceCode "// foo") ] } ] -> pass () | _ -> fail () @@ -126,7 +126,7 @@ let ``comment after all source code`` () = let triviaNodes = toTrivia source |> List.head match triviaNodes with - | [ { Type = MainNode mn + | [ { Type = mn ContentAfter = [ Comment (LineCommentOnSingleLine lineComment) ] } ] -> mn == SynModuleDecl_Types @@ -290,13 +290,13 @@ doSomething() let withoutDefine = Map.find [] triviaNodes match withoutDefine with - | [ { Type = MainNode SynModuleDecl_DoExpr + | [ { Type = SynModuleDecl_DoExpr ContentBefore = [ Directive "#if NOT_DEFINED\n#else" ] ContentAfter = [ Directive "#endif" ] } ] -> pass () | _ -> Assert.Fail(sprintf "Unexpected trivia %A" withoutDefine) match withDefine with - | [ { Type = MainNode LongIdent_ + | [ { Type = LongIdent_ ContentBefore = [ Directive "#if NOT_DEFINED"; Directive "#else"; Directive "#endif" ] ContentAfter = [] } ] -> pass () | _ -> Assert.Fail(sprintf "Unexpected trivia %A" withDefine) @@ -315,16 +315,16 @@ let x = 1 let withoutDefine = Map.find [] triviaNodes match withoutDefine with - | [ { Type = MainNode LongIdent_ + | [ { Type = LongIdent_ ContentAfter = [ Directive "#if NOT_DEFINED\n\n#endif" ] ContentBefore = [] } ] -> pass () | _ -> Assert.Fail(sprintf "Unexpected trivia %A" withoutDefine) match withDefine with - | [ { Type = MainNode LongIdent_ + | [ { Type = LongIdent_ ContentBefore = [ Directive "#if NOT_DEFINED" ] ContentAfter = [] } - { Type = MainNode SynModuleDecl_Let + { Type = SynModuleDecl_Let ContentBefore = [] ContentAfter = [ Directive "#endif" ] } ] -> pass () | _ -> Assert.Fail(sprintf "Unexpected trivia %A" withDefine) @@ -344,7 +344,7 @@ type ExtensibleDumper = A | B let trivias = Map.find [ "DEBUG" ] triviaNodes match trivias with - | [ { Type = MainNode LongIdent_ + | [ { Type = LongIdent_ ContentAfter = [ Directive "#if EXTENSIBLE_DUMPER\n#if DEBUG\n\n#endif\n#endif" ] } ] -> pass () | _ -> Assert.Fail(sprintf "Unexpected trivia %A" trivias) @@ -373,7 +373,7 @@ let foo = 42 let trivia = toTriviaWithDefines source |> Map.find [] match trivia with - | [ { Type = MainNode LongIdent_ + | [ { Type = LongIdent_ ContentAfter = [ Directive "#if SOMETHING\n\n#endif" ] } ] -> pass () | _ -> fail () @@ -393,7 +393,7 @@ with empty lines" match trivia with | [ { ContentItself = Some (StringContent sc) - Type = TriviaNodeType.MainNode SynConst_String } ] -> sc == sprintf "\"%s\"" multilineString + Type = SynConst_String } ] -> sc == sprintf "\"%s\"" multilineString | _ -> fail () [] @@ -412,7 +412,7 @@ with empty lines" match trivia with | [ { ContentItself = Some (StringContent sc) - Type = TriviaNodeType.MainNode SynConst_String } ] -> sc == sprintf "\"\"\"%s\"\"\"" multilineString + Type = SynConst_String } ] -> sc == sprintf "\"\"\"%s\"\"\"" multilineString | _ -> fail () [] @@ -422,7 +422,7 @@ let ``char content`` () = match trivia with | [ { ContentItself = Some (CharContent "\'\\u0000\'") - Type = TriviaNodeType.MainNode SynConst_Char } ] -> pass () + Type = SynConst_Char } ] -> pass () | _ -> Assert.Fail(sprintf "Unexpected trivia: %A" trivia) [] @@ -478,7 +478,7 @@ let ``number expression`` () = match trivia with | [ { ContentItself = Some (Number n) - Type = TriviaNodeType.MainNode _ } ] -> n == "2.0m" + Type = _ } ] -> n == "2.0m" | _ -> fail () [] @@ -497,6 +497,6 @@ let x = printfn "%A" trivia match trivia with - | [ { Type = TriviaNodeType.MainNode SynConst_Unit + | [ { Type = SynConst_Unit ContentBefore = [ Directive "#if DEBUG\n\n#endif" ] } ] -> pass () | _ -> Assert.Fail(sprintf "Unexpected trivia: %A" trivia) diff --git a/src/Fantomas/AstTransformer.fs b/src/Fantomas/AstTransformer.fs index 8e9496a838..3d7533b487 100644 --- a/src/Fantomas/AstTransformer.fs +++ b/src/Fantomas/AstTransformer.fs @@ -10,7 +10,7 @@ open Fantomas type Id = { Ident: string; Range: Range } module Helpers = - let mkNode (t: FsAstType) (r: range) = TriviaNodeAssigner(MainNode(t), r) + let mkNode (t: FsAstType) (r: range) = TriviaNodeAssigner(t, r) let mkNodeOption (t: FsAstType) (r: range option) : TriviaNodeAssigner list = Option.toList r |> List.map (mkNode t) module private Ast = @@ -942,7 +942,9 @@ module private Ast = [ visit synPat; visit synPat2 ] let finalContinuation (nodes: TriviaNodeAssigner list list) : TriviaNodeAssigner list = - List.collect id nodes |> finalContinuation + [ yield! List.collect id nodes + yield mkNode SynPat_Or_Bar trivia.BarRange ] + |> finalContinuation Continuation.sequence continuations finalContinuation | SynPat.Ands (pats, range) -> @@ -1141,7 +1143,7 @@ module private Ast = List.collect visitSynAttributeList attrs and visitSynAttributeList (attrs: SynAttributeList) : TriviaNodeAssigner list = - TriviaNodeAssigner(MainNode(SynAttributeList_), attrs.Range) + mkNode SynAttributeList_ attrs.Range :: (List.collect visitSynAttribute attrs.Attributes) and visitSynUnionCase (uc: SynUnionCase) : TriviaNodeAssigner list = @@ -1158,11 +1160,12 @@ module private Ast = and visitSynEnumCase (sec: SynEnumCase) : TriviaNodeAssigner list = match sec with - | SynEnumCase (attrs, ident, value, valueRange, _, range, { EqualsRange = equalsRange }) -> - [ yield mkNode SynEnumCase_ range + | SynEnumCase (attrs, ident, value, valueRange, _, range, trivia) -> + [ yield! mkNodeOption SynEnumCase_Bar trivia.BarRange + yield mkNode SynEnumCase_ range yield! (visitSynAttributeLists attrs) yield visitIdent ident - yield mkNode SynEnumCase_Equals equalsRange + yield mkNode SynEnumCase_Equals trivia.EqualsRange yield! visitSynConst valueRange value ] and visitSynField (sfield: SynField) : TriviaNodeAssigner list = diff --git a/src/Fantomas/CodePrinter.fs b/src/Fantomas/CodePrinter.fs index 86efb4a40d..b79ca3b77a 100644 --- a/src/Fantomas/CodePrinter.fs +++ b/src/Fantomas/CodePrinter.fs @@ -2596,7 +2596,7 @@ and genExpr astContext synExpr ctx = Map.tryFindOrEmptyList SynInterpolatedStringPart_String ctx.TriviaMainNodes |> List.choose (fun tn -> match tn.Type, tn.ContentItself with - | MainNode SynInterpolatedStringPart_String, Some (StringContent sc) when + | SynInterpolatedStringPart_String, Some (StringContent sc) when (RangeHelpers.rangeEq tn.Range range) -> Some sc @@ -4218,14 +4218,13 @@ and genUnionCase astContext (hasVerticalBar: bool) (UnionCase (ats, px, _, s, Un +> unindent genPreXmlDoc px - +> genTriviaBeforeClausePipe node.Range +> ifElse hasVerticalBar sepBar sepNone +> genOnelinerAttributes astContext ats -- s +> onlyIf (List.isNotEmpty fs) (expressionFitsOnRestOfLine shortExpr longExpr) |> genTriviaFor SynUnionCase_ node.Range -and genEnumCase astContext (EnumCase (ats, px, identInAST, equalsRange, c, cr, r) as node) = +and genEnumCase astContext (EnumCase (ats, barRange, px, identInAST, equalsRange, c, cr, r) as node) = let genCase = (!-identInAST +> genEq SynEnumCase_Equals (Some equalsRange) @@ -4233,8 +4232,9 @@ and genEnumCase astContext (EnumCase (ats, px, identInAST, equalsRange, c, cr, r |> genTriviaFor SynEnumCase_ r genPreXmlDoc px - +> genTriviaBeforeClausePipe node.Range - +> sepBar + +> (match barRange with + | None -> sepBar + | Some barRange -> genTriviaFor SynEnumCase_Bar barRange sepBar) +> genOnelinerAttributes astContext ats +> genCase @@ -4617,9 +4617,8 @@ and genClause astContext hasBar (Clause (p, eo, arrowRange, e) as ce) = +> autoIndentAndNlnIfExpressionExceedsPageWidth (genExpr astContext e)) ctx) - genTriviaBeforeClausePipe p.Range - +> (onlyIf hasBar sepBar +> patAndBody - |> genTriviaFor SynMatchClause_ ce.Range) + (onlyIf hasBar sepBar +> patAndBody + |> genTriviaFor SynMatchClause_ ce.Range) and genClauses astContext cs = col sepNln cs (genClause astContext true) @@ -4907,8 +4906,7 @@ and genPat astContext pat = | PatOr (p1, barRange, p2) -> genPat astContext p1 +> ifElse astContext.IsInsideMatchClausePattern sepNln sepSpace - +> enterNodeTokenByName barRange BAR - -- "| " + +> genTriviaFor SynPat_Or_Bar barRange !- "| " +> genPat astContext p2 | PatAnds ps -> col (!- " & ") ps (genPat astContext) | PatNullary PatNull -> !- "null" @@ -5647,9 +5645,7 @@ and genConst (c: SynConst) (r: Range) = let genNumber (ctx: Context) = genConstNumber c numberRange ctx - genNumber - +> measure - +> leaveNodeTokenByName r GREATER + genNumber +> measure | SynConst.SourceIdentifier (c, _, r) -> !-c |> genTriviaFor SynConst_SourceIdentifier r and genConstNumber (c: SynConst) (r: Range) = diff --git a/src/Fantomas/Context.fs b/src/Fantomas/Context.fs index fc940b78b5..9091ec2c16 100644 --- a/src/Fantomas/Context.fs +++ b/src/Fantomas/Context.fs @@ -185,7 +185,6 @@ type internal Context = /// The original source string to query as a last resort Content: string TriviaMainNodes: Map - TriviaTokenNodes: Map FileName: string } /// Initialize with a string writer and use space as delimiter @@ -197,7 +196,6 @@ type internal Context = BreakOn = (fun _ -> false) Content = "" TriviaMainNodes = Map.empty - TriviaTokenNodes = Map.empty FileName = String.Empty } static member Create @@ -223,29 +221,13 @@ type internal Context = let triviaByNodes = trivia - |> List.choose (fun tn -> - match tn.Type with - | MainNode mn -> Some(mn, tn) - | _ -> None) - |> List.groupBy fst - |> List.map (fun (k, g) -> k, List.map snd g) - |> Map.ofList - - let triviaByTokenNames = - trivia - |> List.choose (fun tn -> - match tn.Type with - | Token (tname, _) -> Some(tname, tn) - | _ -> None) - |> List.groupBy fst - |> List.map (fun (k, g) -> k, List.map snd g) + |> List.groupBy (fun t -> t.Type) |> Map.ofList { Context.Default with Config = config Content = content TriviaMainNodes = triviaByNodes - TriviaTokenNodes = triviaByTokenNames FileName = fileName } member x.WithDummy(writerCommands, ?keepPageWidth) = @@ -1200,21 +1182,6 @@ let private findTriviaOnStartFromRange nodes (range: Range) = nodes |> List.tryFind (fun n -> RangeHelpers.rangeStartEq n.Range range) -let internal findTriviaTokenFromName (tokenName: FsTokenType) (range: Range) (ctx: Context) = - Map.tryFind tokenName ctx.TriviaTokenNodes - |> Option.defaultValue [] - |> List.tryFind (fun n -> RangeHelpers.``range contains`` range n.Range) - -let internal enterNodeTokenByName (range: Range) (tokenName: FsTokenType) (ctx: Context) = - match findTriviaTokenFromName tokenName range ctx with - | Some triviaNode -> (printContentBefore triviaNode) ctx - | None -> ctx - -let internal leaveNodeTokenByName (range: Range) (tokenName: FsTokenType) (ctx: Context) = - match findTriviaTokenFromName tokenName range ctx with - | Some triviaNode -> (printContentAfter triviaNode) ctx - | None -> ctx - let internal enterNodeFor (mainNodeName: FsAstType) (range: Range) (ctx: Context) = match Map.tryFind mainNodeName ctx.TriviaMainNodes with | Some triviaNodes -> @@ -1260,21 +1227,6 @@ let private sepConsideringTriviaContentBeforeBy | Some { ContentBefore = contentBefore } when (hasPrintableContent contentBefore) -> ctx | _ -> sepF ctx -let internal sepConsideringTriviaContentBefore sepF (key: Choice) (range: Range) ctx = - let findTrivia ctx range = - match key with - | Choice1Of2 fsAstKey -> findTriviaRangeEq (Map.tryFindOrEmptyList fsAstKey ctx.TriviaMainNodes) range - | Choice2Of2 fsTokenKey -> - findTriviaOnStartFromRange (Map.tryFindOrEmptyList fsTokenKey ctx.TriviaTokenNodes) range - - sepConsideringTriviaContentBeforeBy findTrivia sepF range ctx - -let internal sepConsideringTriviaContentBeforeForToken sepF (fsTokenKey: FsTokenType) (range: Range) (ctx: Context) = - let findTrivia ctx range = - findTriviaTokenFromName fsTokenKey range ctx - - sepConsideringTriviaContentBeforeBy findTrivia sepF range ctx - let internal sepConsideringTriviaContentBeforeForMainNode sepF (mainNodeName: FsAstType) (range: Range) (ctx: Context) = let findNode ctx range = Map.tryFind mainNodeName ctx.TriviaMainNodes @@ -1283,12 +1235,6 @@ let internal sepConsideringTriviaContentBeforeForMainNode sepF (mainNodeName: Fs sepConsideringTriviaContentBeforeBy findNode sepF range ctx -let internal sepNlnConsideringTriviaContentBefore (key: Choice) (range: Range) = - sepConsideringTriviaContentBefore sepNln key range - -let internal sepNlnConsideringTriviaContentBeforeForToken (fsTokenKey: FsTokenType) (range: Range) = - sepConsideringTriviaContentBeforeForToken sepNln fsTokenKey range - let internal sepNlnConsideringTriviaContentBeforeForMainNode (mainNode: FsAstType) (range: Range) = sepConsideringTriviaContentBeforeForMainNode sepNln mainNode range @@ -1307,18 +1253,6 @@ let internal sepNlnForEmptyModule (mainNode: FsAstType) (moduleRange: Range) (ct sepNln ctx | _ -> sepNln ctx -let internal sepNlnForEmptyNamespace (namespaceRange: Range) ctx = - let emptyNamespaceRange = - mkRange namespaceRange.FileName (mkPos 0 0) namespaceRange.End - - match TriviaHelpers.findInRange (Map.tryFindOrEmptyList Ident_ ctx.TriviaMainNodes) emptyNamespaceRange with - | Some node when - hasPrintableContent node.ContentBefore - || hasPrintableContent node.ContentAfter - -> - ctx - | _ -> sepNln ctx - let internal sepNlnTypeAndMembers (withKeywordNodeType: FsAstType) (withKeywordRange: range option) @@ -1482,23 +1416,3 @@ let internal colWithNlnWhenItemIsMultilineUsingConfig (items: ColMultilineItem l colWithNlnWhenItemIsMultiline items ctx else col sepNln items (fun (ColMultilineItem (expr, _)) -> expr) ctx - -let internal genTriviaBeforeClausePipe (rangeOfClause: Range) ctx = - (Map.tryFindOrEmptyList BAR ctx.TriviaTokenNodes) - |> List.tryFind (fun t -> - t.Range.StartColumn < rangeOfClause.StartColumn - && t.Range.StartLine = rangeOfClause.StartLine) - |> fun trivia -> - match trivia with - | Some trivia -> - let containsOnlyDirectives = - trivia.ContentBefore - |> List.forall (fun tn -> - match tn with - | Directive _ -> true - | _ -> false) - - onlyIf containsOnlyDirectives sepNlnUnlessLastEventIsNewline - +> printContentBefore trivia - | None -> id - <| ctx diff --git a/src/Fantomas/SourceParser.fs b/src/Fantomas/SourceParser.fs index c87f2214d4..87f5821a47 100644 --- a/src/Fantomas/SourceParser.fs +++ b/src/Fantomas/SourceParser.fs @@ -421,7 +421,7 @@ let (|Field|) (SynField (ats, isStatic, ido, t, isMutable, px, ao, _)) = (ats, px, ao, isStatic, isMutable, t, Option.map (|Ident|) ido) let (|EnumCase|) (SynEnumCase (ats, Ident s, c, cr, px, r, trivia)) = - (ats, px, s, trivia.EqualsRange, c, cr, r) + (ats, trivia.BarRange, px, s, trivia.EqualsRange, c, cr, r) // Member definitions (11 cases) diff --git a/src/Fantomas/TokenParser.fs b/src/Fantomas/TokenParser.fs index 519d0b22ca..e737ef6604 100644 --- a/src/Fantomas/TokenParser.fs +++ b/src/Fantomas/TokenParser.fs @@ -1116,50 +1116,3 @@ let getTriviaFromTokens (mkRange: MkRange) (tokens: Token list) = fromTokens @ newLines |> List.sortBy (fun t -> t.Range.StartLine, t.Range.StartColumn) - -let private tokenNames = [ "BAR" ] - -let internal getFsToken tokenName = - match tokenName with - | "AMP" -> AMP - | "AMP_AMP" -> AMP_AMP - | "BAR" -> BAR - | "BAR_BAR" -> BAR_BAR - | "COLON_COLON" -> COLON_COLON - | "COLON_EQUALS" -> COLON_EQUALS - | "COLON_GREATER" -> COLON_GREATER - | "COLON_QMARK" -> COLON_QMARK - | "COLON_QMARK_GREATER" -> COLON_QMARK_GREATER - | "DELAYED" -> DELAYED - | "DO" -> DO - | "DOLLAR" -> DOLLAR - | "DOT_DOT" -> DOT_DOT - | "DOT_DOT_HAT" -> DOT_DOT_HAT - | "ELIF" -> ELIF - | "ELSE" -> ELSE - | "GREATER" -> GREATER - | "IF" -> IF - | "IN" -> IN - | "INFIX_AMP_OP" -> INFIX_AMP_OP - | "INFIX_BAR_OP" -> INFIX_BAR_OP - | "INFIX_COMPARE_OP" -> INFIX_COMPARE_OP - | "INFIX_STAR_DIV_MOD_OP" -> INFIX_STAR_DIV_MOD_OP - | "INFIX_STAR_STAR_OP" -> INFIX_STAR_STAR_OP - | "INT32_DOT_DOT" -> INT32_DOT_DOT - | "LESS" -> LESS - | "LPAREN_STAR_RPAREN" -> LPAREN_STAR_RPAREN - | "MINUS" -> MINUS - | "PERCENT_OP" -> PERCENT_OP - | "PLUS_MINUS_OP" -> PLUS_MINUS_OP - | "PREFIX_OP" -> PREFIX_OP - | "QMARK" -> QMARK - | "QMARK_QMARK" -> QMARK_QMARK - | "THEN" -> THEN - | _ -> failwithf "was not expecting token %s" tokenName - -let getTriviaNodesFromTokens (mkRange: MkRange) (tokens: Token list) = - tokens - |> List.filter (fun t -> List.exists (fun tn -> tn = t.TokenInfo.TokenName) tokenNames) - |> List.map (fun t -> - let range = getRangeBetween mkRange t t - TriviaNodeAssigner(TriviaNodeType.Token(getFsToken t.TokenInfo.TokenName, t), range)) diff --git a/src/Fantomas/Trivia.fs b/src/Fantomas/Trivia.fs index 0b0a895a8a..6f5c82070c 100644 --- a/src/Fantomas/Trivia.fs +++ b/src/Fantomas/Trivia.fs @@ -8,44 +8,11 @@ open Fantomas.SourceParser open Fantomas.AstTransformer open Fantomas.TriviaTypes -let isMainNode (node: TriviaNode) = - match node.Type with - | MainNode _ -> true - | _ -> false - -let inline isMainNodeFor nodeType (node: TriviaNodeAssigner) = - match node.Type with - | MainNode t when (t = nodeType) -> true - | _ -> false - -let isToken (node: TriviaNode) = - match node.Type with - | Token _ -> true - | _ -> false - -let private findFirstNodeOnLine (nodes: TriviaNode list) lineNumber : TriviaNode option = - nodes - |> List.filter (fun { Range = r } -> r.StartLine = lineNumber) - |> List.tryHead - -let inline private mainNodeIs name (t: TriviaNodeAssigner) = - match t.Type with - | MainNode mn -> mn = name - | _ -> false - -// the member keyword is not part of an AST node range -// so it is not an ideal candidate node to have trivia content -let inline private isNotMemberKeyword (node: TriviaNodeAssigner) = - match node.Type with - // TODO: probably replace with main node counterpart, or not -// | Token (MEMBER, _) -> false - | _ -> true +let inline isMainNodeFor nodeType (node: TriviaNodeAssigner) = nodeType = node.Type let private findFirstNodeAfterLine (nodes: TriviaNodeAssigner list) (lineNumber: int) : TriviaNodeAssigner option = nodes - |> List.tryFind (fun tn -> - tn.Range.StartLine > lineNumber - && isNotMemberKeyword tn) + |> List.tryFind (fun tn -> tn.Range.StartLine > lineNumber) let private findLastNodeOnLine (nodes: TriviaNodeAssigner list) lineNumber : TriviaNodeAssigner option = nodes @@ -77,29 +44,12 @@ let private findNodeOnLineAndColumn (nodes: TriviaNodeAssigner list) line column && tn.Range.StartColumn = column) let private findNodeBeforeLineAndColumn (nodes: TriviaNodeAssigner list) line column = - let node = - nodes - |> List.tryFindBack (fun tn -> - let range = tn.Range - - range.StartLine <= line - && range.StartColumn <= column) - - match node with - | Some tokenNode -> - match tokenNode.Type with - | Token (_, t) when (t.TokenInfo.CharClass = FSharpTokenCharKind.Operator) -> - // pick the matching ident instead of the token - nodes - |> List.tryFind (fun tn -> - match tn.Type with - | MainNode mn when (mn = SynExpr_Ident) -> - tn.Range.StartLine = t.LineNumber - && tn.Range.StartColumn = tn.Range.StartColumn - | _ -> false) - | _ -> node - | _ -> node + nodes + |> List.tryFindBack (fun tn -> + let range = tn.Range + range.StartLine <= line + && range.StartColumn <= column) let private findNodeBeforeLineFromStart (nodes: TriviaNodeAssigner list) line = nodes @@ -120,42 +70,30 @@ let private findConstNumberNodeOnLineAndColumn (nodes: TriviaNodeAssigner list) nodes |> List.tryFind (fun tn -> match tn.Type with - | MainNode SynConst_Byte - | MainNode SynConst_SByte - | MainNode SynConst_Int16 - | MainNode SynConst_Int32 - | MainNode SynConst_Int64 - | MainNode SynConst_UInt16 - | MainNode SynConst_UInt16s - | MainNode SynConst_UInt32 - | MainNode SynConst_UInt64 - | MainNode SynConst_Double - | MainNode SynConst_Single - | MainNode SynConst_Decimal - | MainNode SynConst_IntPtr - | MainNode SynConst_UIntPtr - | MainNode SynConst_UserNum -> + | SynConst_Byte + | SynConst_SByte + | SynConst_Int16 + | SynConst_Int32 + | SynConst_Int64 + | SynConst_UInt16 + | SynConst_UInt16s + | SynConst_UInt32 + | SynConst_UInt64 + | SynConst_Double + | SynConst_Single + | SynConst_Decimal + | SynConst_IntPtr + | SynConst_UIntPtr + | SynConst_UserNum -> constantRange.StartLine = tn.Range.StartLine && constantRange.StartColumn = tn.Range.StartColumn | _ -> false) -let private findNodeForKeywordString (nodes: TriviaNodeAssigner list) (range: Range) = - nodes - |> List.tryFind (fun tn -> - match tn.Type with - | MainNode SynConst_String -> - tn.Range.StartLine = range.StartLine - && tn.Range.StartColumn = range.StartColumn - | MainNode ParsedHashDirective_ -> - tn.Range.StartLine = range.StartLine - && tn.Range.EndColumn >= range.EndColumn - | _ -> false) - let private findSynConstStringNodeAfter (nodes: TriviaNodeAssigner list) (range: Range) = nodes |> List.tryFind (fun tn -> match tn.Type, range.StartLine = tn.Range.StartLine, range.StartColumn + 1 = tn.Range.StartColumn with - | MainNode SynConst_String, true, true -> true + | SynConst_String, true, true -> true | _ -> false) let private commentIsAfterLastTriviaNode (triviaNodes: TriviaNodeAssigner list) (range: Range) = @@ -186,9 +124,9 @@ let private findNamedPatThatStartsWith (triviaNodes: TriviaNodeAssigner list) co triviaNodes |> List.tryFind (fun t -> match t.Type with - | MainNode SynPat_Named - | MainNode SynPat_LongIdent - | MainNode SynExpr_Ident -> + | SynPat_Named + | SynPat_LongIdent + | SynExpr_Ident -> t.Range.StartColumn = column && t.Range.StartLine = line | _ -> false) @@ -197,19 +135,11 @@ let private findParsedHashOnLineAndEndswith (triviaNodes: TriviaNodeAssigner lis triviaNodes |> List.tryFind (fun t -> match t.Type with - | MainNode ParsedHashDirective_ -> + | ParsedHashDirective_ -> t.Range.StartLine = startLine && t.Range.EndColumn >= endColumn | _ -> false) -let private findASTNodeOfTypeThatContains (nodes: TriviaNodeAssigner list) typeName range = - nodes - |> List.filter (fun t -> - match t.Type with - | TriviaNodeType.MainNode mnt when (mnt = typeName) -> RangeHelpers.``range contains`` t.Range range - | _ -> false) - |> List.tryHead - let private addAllTriviaAsContentAfter (trivia: Trivia list) (singleNode: TriviaNodeAssigner) = let contentAfter = trivia @@ -298,27 +228,6 @@ let private addTriviaToTriviaNode (startOfSourceCode: int) (triviaNodes: TriviaN findSynConstStringNodeAfter triviaNodes range |> updateTriviaNode (fun tn -> tn.ContentBefore.Add(Keyword(kw))) triviaNodes - | { Item = Keyword { Content = keyword } - Range = range } when (keyword = "in") -> - // find In keyword TriviaNode - triviaNodes - |> List.tryFind (fun tn -> - match tn.Type with - | Token (IN, _) -> RangeHelpers.rangeEq range tn.Range - | _ -> false) - |> updateTriviaNode (fun tn -> tn.ContentItself <- Some trivia.Item) triviaNodes - - | { Item = Keyword { Content = keyword } - Range = range } when - (keyword = "if" - || keyword = "then" - || keyword = "else" - || keyword = "elif") - -> - findNodeOnLineAndColumn triviaNodes range.StartLine range.StartColumn - |> Option.orElseWith (fun () -> findASTNodeOfTypeThatContains triviaNodes SynExpr_IfThenElse range) - |> updateTriviaNode (fun tn -> tn.ContentItself <- Some trivia.Item) triviaNodes - | { Item = Keyword keyword Range = range } -> findNodeOnLineAndColumn triviaNodes range.StartLine range.StartColumn @@ -374,11 +283,11 @@ let private addTriviaToTriviaNode (startOfSourceCode: int) (triviaNodes: TriviaN |> List.tryFind (fun t -> let isIdent = match t.Type with - | MainNode SynExpr_Ident - | MainNode SynPat_Named - | MainNode SynPat_LongIdent - | MainNode Ident_ - | MainNode SynConst_String -> true + | SynExpr_Ident + | SynPat_Named + | SynPat_LongIdent + | Ident_ + | SynConst_String -> true | _ -> false isIdent @@ -392,7 +301,7 @@ let private addTriviaToTriviaNode (startOfSourceCode: int) (triviaNodes: TriviaN triviaNodes |> List.tryFind (fun t -> match t.Type with - | MainNode SynExpr_LibraryOnlyILAssembly -> RangeHelpers.rangeEq t.Range range + | SynExpr_LibraryOnlyILAssembly -> RangeHelpers.rangeEq t.Range range | _ -> false) |> updateTriviaNode (fun tn -> tn.ContentItself <- Some eil) triviaNodes | _ -> triviaNodes @@ -415,10 +324,8 @@ let collectTrivia (mkRange: MkRange) tokens (ast: ParsedInput) = | ParsedInput.SigFile (ParsedSigFileInput.ParsedSigFileInput (_, _, _, _, mns)) -> sigAstToNode mns - let triviaNodesFromTokens = TokenParser.getTriviaNodesFromTokens mkRange tokens - let triviaNodes = - triviaNodesFromAST @ triviaNodesFromTokens + triviaNodesFromAST |> List.sortBy (fun n -> n.Range.Start.Line, n.Range.Start.Column) let trivias = TokenParser.getTriviaFromTokens mkRange tokens diff --git a/src/Fantomas/TriviaContext.fs b/src/Fantomas/TriviaContext.fs index 5e25fe76f5..e700f19b2f 100644 --- a/src/Fantomas/TriviaContext.fs +++ b/src/Fantomas/TriviaContext.fs @@ -3,12 +3,6 @@ module internal Fantomas.TriviaContext open Fantomas open Fantomas.Context open Fantomas.TriviaTypes -open FSharp.Compiler.Text - -let tokN (range: Range) (tokenName: FsTokenType) f = - enterNodeTokenByName range tokenName - +> f - +> leaveNodeTokenByName range tokenName let getIndentBetweenTicksFromSynPat patRange fallback ctx = TriviaHelpers.getNodesForTypes [ SynPat_LongIdent; SynPat_Named ] ctx.TriviaMainNodes diff --git a/src/Fantomas/TriviaHelpers.fs b/src/Fantomas/TriviaHelpers.fs index 5e6b0cb7c2..7baadfd296 100644 --- a/src/Fantomas/TriviaHelpers.fs +++ b/src/Fantomas/TriviaHelpers.fs @@ -27,13 +27,6 @@ module internal TriviaHelpers = |> Option.map (fun t -> t.ContentBefore |> List.exists contentBefore) |> Option.defaultValue false - let ``has single line comment before`` (triviaNode: TriviaNode) = - triviaNode.ContentBefore - |> List.exists (fun tn -> - match tn with - | Comment (LineCommentOnSingleLine _) -> true - | _ -> false) - let ``has content after that ends with`` (findTrivia: TriviaNode -> bool) (contentAfterEnd: TriviaContent -> bool) @@ -46,32 +39,6 @@ module internal TriviaHelpers = |> Option.map contentAfterEnd) |> Option.defaultValue false - let ``keyword token inside range`` (range: Range) (trivia: TriviaNode list) : (Token * TriviaNode) list = - trivia - |> List.choose (fun t -> - match t.Type with - | TriviaNodeType.Token (_, tok) when (RangeHelpers.``range contains`` range t.Range) -> Some(tok, t) - | _ -> None) - - let ``keyword token after start column and on same line`` (range: Range) (trivia: TriviaNode list) = - trivia - |> List.choose (fun t -> - match t.Type with - | TriviaNodeType.Token (_, tok) when - (range.StartLine = t.Range.StartLine - && range.StartColumn < t.Range.StartColumn) - -> - Some(tok, t) - | _ -> None) - - let ``has line comment after`` triviaNode = - triviaNode.ContentAfter - |> List.filter (fun tn -> - match tn with - | Comment (LineCommentAfterSourceCode _) -> true - | _ -> false) - |> (List.isEmpty >> not) - let ``has content itself that matches`` (predicate: TriviaContent -> bool) range (triviaNodes: TriviaNode list) = triviaNodes |> List.exists (fun tn -> @@ -79,27 +46,6 @@ module internal TriviaHelpers = | true, Some t -> predicate t | _ -> false) - let ``has content itself that is multiline string`` range (triviaNodes: TriviaNode list) = - triviaNodes - |> List.choose (fun tn -> - match RangeHelpers.rangeEq tn.Range range, tn.ContentItself with - | true, Some (StringContent s) when (String.isMultiline s) -> Some s - | _ -> None) - |> List.isNotEmpty - - let private isLineComment = - function - | Comment (LineCommentAfterSourceCode _) - | Comment (LineCommentOnSingleLine _) -> true - | _ -> false - - let ``has line comments inside`` range (triviaNodes: TriviaNode list) = - triviaNodes - |> List.exists (fun tn -> - RangeHelpers.``range contains`` range tn.Range - && (List.exists isLineComment tn.ContentBefore - || List.exists isLineComment tn.ContentAfter)) - let getNodesForTypes types (dict: Map<'t, TriviaNode list>) = types |> List.map (fun t -> @@ -108,14 +54,3 @@ module internal TriviaHelpers = else List.empty) |> List.collect id - - let hasMultilineString range (triviaNodes: TriviaNode list) = - triviaNodes - |> List.exists (fun tn -> - let contentItSelfIsMultilineString () = - match tn.ContentItself with - | Some (StringContent sc) -> String.isMultiline sc - | _ -> false - - RangeHelpers.rangeEq tn.Range range - && contentItSelfIsMultilineString ()) diff --git a/src/Fantomas/TriviaTypes.fs b/src/Fantomas/TriviaTypes.fs index da646986c1..bb818080d3 100644 --- a/src/Fantomas/TriviaTypes.fs +++ b/src/Fantomas/TriviaTypes.fs @@ -3,42 +3,6 @@ module Fantomas.TriviaTypes open FSharp.Compiler.Text open FSharp.Compiler.Tokenization -type FsTokenType = - | AMP - | AMP_AMP - | BAR - | BAR_BAR - | COLON_COLON - | COLON_EQUALS - | COLON_GREATER - | COLON_QMARK - | COLON_QMARK_GREATER - | DELAYED - | DO - | DOLLAR - | DOT_DOT - | DOT_DOT_HAT - | ELIF - | ELSE - | GREATER - | IF - | IN - | INFIX_AMP_OP - | INFIX_BAR_OP - | INFIX_COMPARE_OP - | INFIX_STAR_DIV_MOD_OP - | INFIX_STAR_STAR_OP - | INT32_DOT_DOT - | LESS - | LPAREN_STAR_RPAREN - | MINUS - | PERCENT_OP - | PLUS_MINUS_OP - | PREFIX_OP - | QMARK - | QMARK_QMARK - | THEN - type Token = { TokenInfo: FSharpTokenInfo LineNumber: int @@ -279,6 +243,7 @@ type FsAstType = | SynPat_Typed | SynPat_Attrib // | SynPat_Or, use the inner patterns instead + | SynPat_Or_Bar | SynPat_Ands | SynPat_LongIdent | SynPat_LongIdent_And @@ -360,6 +325,7 @@ type FsAstType = | SynUnionCaseKind_Fields | SynUnionCaseKind_FullType | SynEnumCase_ + | SynEnumCase_Bar | SynEnumCase_Equals | SynField_ | SynField_AfterAttributesBeforeIdentifier @@ -419,18 +385,14 @@ type FsAstType = | File_ | SigFile_ -type TriviaNodeType = - | MainNode of ``type``: FsAstType - | Token of ``type``: FsTokenType * Token - type TriviaNode = - { Type: TriviaNodeType + { Type: FsAstType ContentBefore: TriviaContent list ContentItself: TriviaContent option ContentAfter: TriviaContent list Range: Range } -type TriviaNodeAssigner(nodeType: TriviaNodeType, range: Range) = +type TriviaNodeAssigner(nodeType: FsAstType, range: Range) = member this.Type = nodeType member this.Range = range member val ContentBefore = ResizeArray() with get, set From 071806a6db03677d262e66639c9ddad6afbf8f0d Mon Sep 17 00:00:00 2001 From: nojaf Date: Fri, 11 Feb 2022 09:41:39 +0100 Subject: [PATCH 10/16] Update SynTypeDefn and SynBinding trivia. --- src/Fantomas/AstTransformer.fs | 12 ++++++------ src/Fantomas/CodePrinter.fs | 21 ++++++--------------- src/Fantomas/Context.fs | 6 ++++++ src/Fantomas/SourceParser.fs | 30 ++++++++++++------------------ 4 files changed, 30 insertions(+), 39 deletions(-) diff --git a/src/Fantomas/AstTransformer.fs b/src/Fantomas/AstTransformer.fs index 3d7533b487..964c6259f6 100644 --- a/src/Fantomas/AstTransformer.fs +++ b/src/Fantomas/AstTransformer.fs @@ -650,7 +650,7 @@ module private Ast = | Some e -> visitSynExpr e | None -> []) ] - and visitAnonRecordField (_: Ident, equalsRange: range option, expr: SynExpr) = + and visitAnonRecordField (ident: Ident, equalsRange: range option, expr: SynExpr) = [ yield visitIdent ident yield! mkNodeOption SynExpr_AnonRecd_Field_Equals equalsRange yield! visitSynExpr expr ] @@ -704,7 +704,7 @@ module private Ast = and visitSynTypeDefn (td: SynTypeDefn) = match td with - | SynTypeDefn (sci, equalsRange, stdr, withKeyword, members, implicitConstructor, range) -> + | SynTypeDefn (sci, stdr, members, implicitConstructor, range, trivia) -> let afterAttributesBeforeRepr = match td.AfterAttributesBeforeComponentInfo with | None -> [] @@ -714,11 +714,11 @@ module private Ast = // TODO process implicitConstructor ?? [ yield mkNode SynTypeDefn_ range - yield! mkNodeOption SynTypeDefn_Equals equalsRange + yield! mkNodeOption SynTypeDefn_Equals trivia.EqualsRange yield! visitSynComponentInfo sci yield! afterAttributesBeforeRepr yield! visitSynTypeDefnRepr stdr - yield! mkNodeOption SynTypeDefn_With withKeyword + yield! mkNodeOption SynTypeDefn_With trivia.WithKeyword yield! (members |> List.collect visitSynMemberDefn) ] and visitSynTypeDefnSig (typeDefSig: SynTypeDefnSig) : TriviaNodeAssigner list = @@ -834,7 +834,7 @@ module private Ast = and visitSynBinding (binding: SynBinding) : TriviaNodeAssigner list = match binding with - | SynBinding (_, kind, _, _, attrs, _, valData, headPat, returnInfo, equalsRange, expr, _range, _) -> + | SynBinding (_, kind, _, _, attrs, _, valData, headPat, returnInfo, expr, _range, _, trivia) -> let t = match kind with | SynBindingKind.StandaloneExpression -> SynBindingKind_StandaloneExpression @@ -862,7 +862,7 @@ module private Ast = (match returnInfo with | Some ri -> visitSynBindingReturnInfo ri | None -> []) - yield! mkNodeOption SynBinding_Equals equalsRange + yield! mkNodeOption SynBinding_Equals trivia.EqualsRange yield! visitSynExpr expr ] and visitSynValData (svd: SynValData) : TriviaNodeAssigner list = diff --git a/src/Fantomas/CodePrinter.fs b/src/Fantomas/CodePrinter.fs index b79ca3b77a..98570a1770 100644 --- a/src/Fantomas/CodePrinter.fs +++ b/src/Fantomas/CodePrinter.fs @@ -5357,33 +5357,24 @@ and genSynBindingValue let genValueName = genPat astContext valueName let genEqualsInBinding (ctx: Context) = - let space = - match equalsRange with - | None -> sepSpace - | Some eqR -> - ctx.TriviaMainNodes - |> Map.tryFindOrEmptyList SynBinding_Equals - |> List.tryFind (fun tn -> tn.Range = eqR) - |> fun triviaNode -> - match triviaNode with - | Some tn when (List.isNotEmpty tn.ContentAfter) -> sepNone - | _ -> sepSpace - - (genEq SynBinding_Equals equalsRange +> space) ctx + (genEqFixed SynBinding_Equals equalsRange + +> sepSpaceUnlessWriteBeforeNewlineNotEmpty) + ctx let genReturnType = match returnType with | Some rt -> let hasGenerics = match valueName with - | SynPat.LongIdent (_, _, Some _, _, _, _) -> true + | SynPat.LongIdent (_, _, _, Some _, _, _, _) -> true | _ -> false ifElse hasGenerics sepColonWithSpacesFixed sepColon +> (genType astContext false rt |> genTriviaFor SynBindingReturnInfo_ rt.Range) + +> sepSpaceUnlessWriteBeforeNewlineNotEmpty +> autoIndentAndNlnWhenWriteBeforeNewlineNotEmpty genEqualsInBinding - | None -> genEqualsInBinding + | None -> sepSpace +> genEqualsInBinding genPreXmlDoc px +> genAttrIsFirstChild diff --git a/src/Fantomas/Context.fs b/src/Fantomas/Context.fs index 9091ec2c16..02ce6e4afc 100644 --- a/src/Fantomas/Context.fs +++ b/src/Fantomas/Context.fs @@ -1281,6 +1281,12 @@ let internal sepNlnWhenWriteBeforeNewlineNotEmpty fallback (ctx: Context) = else fallback ctx +let internal sepSpaceUnlessWriteBeforeNewlineNotEmpty (ctx: Context) = + if String.isNotNullOrEmpty ctx.WriterModel.WriteBeforeNewline then + ctx + else + sepSpace ctx + let internal autoIndentAndNlnWhenWriteBeforeNewlineNotEmpty (f: Context -> Context) (ctx: Context) = if String.isNotNullOrEmpty ctx.WriterModel.WriteBeforeNewline then (indent +> sepNln +> f +> unindent) ctx diff --git a/src/Fantomas/SourceParser.fs b/src/Fantomas/SourceParser.fs index 87f5821a47..30358671db 100644 --- a/src/Fantomas/SourceParser.fs +++ b/src/Fantomas/SourceParser.fs @@ -546,8 +546,8 @@ let (|MFMember|MFStaticMember|MFConstructor|MFOverride|) (mf: SynMemberFlags) = let (|DoBinding|LetBinding|MemberBinding|PropertyBinding|ExplicitCtor|) = function - | SynBinding (ao, _, _, _, ats, px, SynValData (Some MFConstructor, _, ido), pat, _, equalsRange, expr, _, _) -> - ExplicitCtor(ats, px, ao, pat, equalsRange, expr, Option.map (|Ident|) ido) + | SynBinding (ao, _, _, _, ats, px, SynValData (Some MFConstructor, _, ido), pat, _, expr, _, _, trivia) -> + ExplicitCtor(ats, px, ao, pat, trivia.EqualsRange, expr, Option.map (|Ident|) ido) | SynBinding (ao, _, isInline, @@ -557,15 +557,15 @@ let (|DoBinding|LetBinding|MemberBinding|PropertyBinding|ExplicitCtor|) = SynValData (Some (MFProperty _ as mf), synValInfo, _), pat, _, - equalsRange, expr, _, - _) -> PropertyBinding(ats, px, ao, isInline, mf, pat, equalsRange, expr, synValInfo) - | SynBinding (ao, _, isInline, _, ats, px, SynValData (Some mf, synValInfo, _), pat, _, equalsRange, expr, _, _) -> - MemberBinding(ats, px, ao, isInline, mf, pat, equalsRange, expr, synValInfo) - | SynBinding (_, SynBindingKind.Do, _, _, ats, px, _, _, _, _, expr, _, _) -> DoBinding(ats, px, expr) - | SynBinding (ao, _, isInline, isMutable, attrs, px, SynValData (_, valInfo, _), pat, _, equalsRange, expr, _, _) -> - LetBinding(attrs, px, ao, isInline, isMutable, pat, equalsRange, expr, valInfo) + _, + trivia) -> PropertyBinding(ats, px, ao, isInline, mf, pat, trivia.EqualsRange, expr, synValInfo) + | SynBinding (ao, _, isInline, _, ats, px, SynValData (Some mf, synValInfo, _), pat, _, expr, _, _, trivia) -> + MemberBinding(ats, px, ao, isInline, mf, pat, trivia.EqualsRange, expr, synValInfo) + | SynBinding (_, SynBindingKind.Do, _, _, ats, px, _, _, _, expr, _, _, trivia) -> DoBinding(ats, px, expr) + | SynBinding (ao, _, isInline, isMutable, attrs, px, SynValData (_, valInfo, _), pat, _, expr, _, _, trivia) -> + LetBinding(attrs, px, ao, isInline, isMutable, pat, trivia.EqualsRange, expr, valInfo) // Expressions (55 cases, lacking to handle 11 cases) @@ -1469,15 +1469,9 @@ let (|TCSimple|TCDelegate|) = | SynTypeDefnKind.Delegate (t, vi) -> TCDelegate(t, vi) let (|TypeDef|) - (SynTypeDefn (SynComponentInfo (ats, tds, tcs, LongIdent s, px, preferPostfix, ao, _), - equalsRange, - tdr, - withKeyword, - ms, - _, - _)) + (SynTypeDefn (SynComponentInfo (ats, tds, tcs, LongIdent s, px, preferPostfix, ao, _), tdr, ms, _, _, trivia)) = - (ats, px, ao, tds, tcs, equalsRange, tdr, withKeyword, ms, s, preferPostfix) + (ats, px, ao, tds, tcs, trivia.EqualsRange, tdr, trivia.WithKeyword, ms, s, preferPostfix) let (|SigTypeDef|) (SynTypeDefnSig (SynComponentInfo (ats, tds, tcs, LongIdent s, px, preferPostfix, ao, _), @@ -1659,7 +1653,7 @@ let (|Val|) let (|RecordFieldName|) ((LongIdentWithDots s, _): RecordFieldName, eo: SynExpr option, _) = (s, eo) -let (|AnonRecordFieldName|) (ident: Ident, eq:range option, e: SynExpr) = (ident.idText, ident.idRange, eq, e) +let (|AnonRecordFieldName|) (ident: Ident, eq: range option, e: SynExpr) = (ident.idText, ident.idRange, eq, e) let (|AnonRecordFieldType|) (Ident s: Ident, t: SynType) = (s, t) let (|PatRecordFieldName|) ((LongIdent s1, Ident s2), _, p) = (s1, s2, p) From 601e2b707d815b3f5c8854711636a391e6bd4dba Mon Sep 17 00:00:00 2001 From: nojaf Date: Fri, 11 Feb 2022 10:59:45 +0100 Subject: [PATCH 11/16] Introduce SynBinding_Let when there is trivia between xml/attributes and let binding. --- src/Fantomas.Tests/CommentTests.fs | 2 - src/Fantomas/AstExtensions.fs | 8 --- src/Fantomas/AstTransformer.fs | 49 +++++++++++++---- src/Fantomas/CodePrinter.fs | 85 ++++++++---------------------- src/Fantomas/SourceParser.fs | 16 ++++-- src/Fantomas/TokenParser.fs | 17 ++++++ src/Fantomas/TriviaTypes.fs | 1 + 7 files changed, 92 insertions(+), 86 deletions(-) diff --git a/src/Fantomas.Tests/CommentTests.fs b/src/Fantomas.Tests/CommentTests.fs index 6af6507c64..26ede91311 100644 --- a/src/Fantomas.Tests/CommentTests.fs +++ b/src/Fantomas.Tests/CommentTests.fs @@ -215,7 +215,6 @@ let f () = """ [] -[] let ``should keep well-aligned comments`` () = formatSourceString false @@ -246,7 +245,6 @@ let f () = """ [] -[] let ``should align mis-aligned comments`` () = formatSourceString false diff --git a/src/Fantomas/AstExtensions.fs b/src/Fantomas/AstExtensions.fs index 257d30817b..a3216227ef 100644 --- a/src/Fantomas/AstExtensions.fs +++ b/src/Fantomas/AstExtensions.fs @@ -22,14 +22,6 @@ let private hasLinesBetweenAttributesAndFirstNode (attributes: SynAttributes) (f else None) -type SynBinding with - /// Construct an artificial range after the attributes and before the head pattern. - /// This is to detect newline or comment trivia in that exact location. - member this.AfterAttributesBeforeHeadPattern: Range option = - match this with - | SynBinding(attributes = []) -> None - | SynBinding (attributes = attrs; headPat = pat) -> hasLinesBetweenAttributesAndFirstNode attrs pat.Range - type SynTypeDefn with member this.AfterAttributesBeforeComponentInfo: Range option = match this with diff --git a/src/Fantomas/AstTransformer.fs b/src/Fantomas/AstTransformer.fs index 964c6259f6..91bd6858d4 100644 --- a/src/Fantomas/AstTransformer.fs +++ b/src/Fantomas/AstTransformer.fs @@ -834,28 +834,59 @@ module private Ast = and visitSynBinding (binding: SynBinding) : TriviaNodeAssigner list = match binding with - | SynBinding (_, kind, _, _, attrs, _, valData, headPat, returnInfo, expr, _range, _, trivia) -> + | SynBinding (_, + kind, + _, + _, + attrs, + (SourceParser.PreXmlDoc (xml, xmlRange)), + valData, + headPat, + returnInfo, + expr, + _range, + _, + trivia) -> let t = match kind with | SynBindingKind.StandaloneExpression -> SynBindingKind_StandaloneExpression | SynBindingKind.Normal -> SynBindingKind_Normal | SynBindingKind.Do -> SynBindingKind_Do - let afterAttributesBeforeHeadPattern = - match binding.AfterAttributesBeforeHeadPattern with - | Some r -> - mkNode SynBinding_AfterAttributes_BeforeHeadPattern r - |> List.singleton - | None -> [] - let headPatNodes = match kind with | SynBindingKind.Do -> [] | _ -> visitSynPat headPat + // We only need the let keyword anchor if there are xml docs or attributes present that have space between itself and the let keyword + let letNode = + if Array.isEmpty xml && attrs.IsEmpty then + [] + else + match trivia.LetKeyword with + | None -> [] + | Some letKeyword -> + let lastLine = + let lastAttrLine = + match List.tryLast attrs with + | None -> 0 + | Some a -> a.Range.EndLine + + System.Math.Max(xmlRange.EndLine, lastAttrLine) + + if letKeyword.StartLine > lastLine + 1 then + // In this scenario there is trivia underneath the attributes or xmldoc + // f.ex.: + // [] + // // some comment + // let a = 0 + [ mkNode SynBinding_Let letKeyword ] + else + [] + [ yield mkNode t binding.RangeOfBindingWithRhs yield! visitSynAttributeLists attrs - yield! afterAttributesBeforeHeadPattern + yield! letNode yield! visitSynValData valData yield! headPatNodes yield! diff --git a/src/Fantomas/CodePrinter.fs b/src/Fantomas/CodePrinter.fs index 98570a1770..5663e10f0b 100644 --- a/src/Fantomas/CodePrinter.fs +++ b/src/Fantomas/CodePrinter.fs @@ -507,7 +507,7 @@ and genAttributes astContext (ats: SynAttributes) = chain ctx) sepNone -and genPreXmlDoc (PreXmlDoc lines) = +and genPreXmlDoc (PreXmlDoc (lines, _)) = colPost sepNln sepNln lines (sprintf "///%s" >> (!-)) and genExprSepEqPrependType @@ -565,7 +565,7 @@ and genLetBinding astContext pref b = let isRecursiveLetOrUseFunction = (pref = "and ") match b with - | LetBinding (ats, px, ao, isInline, isMutable, p, equalsRange, e, valInfo) -> + | LetBinding (ats, px, letKeyword, ao, isInline, isMutable, p, equalsRange, e, valInfo) -> match e, p with | TypedExpr (Typed, e, t), PatLongIdent (ao, s, _, ps, tpso) when (List.isNotEmpty ps) -> genSynBindingFunctionWithReturnType @@ -574,7 +574,7 @@ and genLetBinding astContext pref b = isRecursiveLetOrUseFunction px ats - b.AfterAttributesBeforeHeadPattern + letKeyword genPref ao isInline @@ -594,7 +594,7 @@ and genLetBinding astContext pref b = isRecursiveLetOrUseFunction px ats - b.AfterAttributesBeforeHeadPattern + letKeyword genPref ao isInline @@ -611,7 +611,7 @@ and genLetBinding astContext pref b = isRecursiveLetOrUseFunction px ats - b.AfterAttributesBeforeHeadPattern + letKeyword genPref ao isInline @@ -639,7 +639,7 @@ and genLetBinding astContext pref b = isRecursiveLetOrUseFunction px ats - b.AfterAttributesBeforeHeadPattern + letKeyword genPref ao isInline @@ -890,7 +890,7 @@ and genMemberBindingImpl false px ats - b.AfterAttributesBeforeHeadPattern + None prefix ao isInline @@ -904,53 +904,10 @@ and genMemberBindingImpl equalsRange e | e, PatLongIdent (ao, s, _, ps, tpso) when (List.isNotEmpty ps) -> - genSynBindingFunction - astContext - true - false - px - ats - b.AfterAttributesBeforeHeadPattern - prefix - ao - isInline - false - s - p.Range - ps - tpso - equalsRange - e + genSynBindingFunction astContext true false px ats None prefix ao isInline false s p.Range ps tpso equalsRange e | TypedExpr (Typed, e, t), pat -> - genSynBindingValue - astContext - false - px - ats - b.AfterAttributesBeforeHeadPattern - prefix - ao - isInline - false - pat - (Some t) - equalsRange - e - | _, pat -> - genSynBindingValue - astContext - false - px - ats - b.AfterAttributesBeforeHeadPattern - prefix - ao - isInline - false - pat - None - equalsRange - e + genSynBindingValue astContext false px ats None prefix ao isInline false pat (Some t) equalsRange e + | _, pat -> genSynBindingValue astContext false px ats None prefix ao isInline false pat None equalsRange e and genMemberFlags (mf: SynMemberFlags) = match mf.Trivia with @@ -4692,7 +4649,7 @@ and genMemberDefn astContext node = | MDInherit (t, _) -> !- "inherit " +> genType astContext false t | MDValField f -> genField astContext "val " f - | MDImplicitCtor (xmlDoc, ats, ao, ps, so) -> + | MDImplicitCtor ((PreXmlDoc (xmlDoc, _) as preXmlDoc), ats, ao, ps, so) -> let rec simplePats ps = match ps with | SynSimplePats.SimplePats (pats, _) -> pats @@ -4715,12 +4672,12 @@ and genMemberDefn astContext node = isEmpty ps - let hasXmlDocComment = ((|PreXmlDoc|) xmlDoc).Length > 0 + let hasXmlDocComment = xmlDoc.Length > 0 let longExpr ctx = (indent +> sepNln - +> genPreXmlDoc xmlDoc + +> genPreXmlDoc preXmlDoc +> optSingle (fun ao -> genAccess ao +> sepNln) ao +> ifElse emptyPats (sepOpenT +> sepCloseT) (fun ctx -> let shortPats = @@ -5082,7 +5039,7 @@ and genSynBindingFunction (isRecursiveLetOrUseFunction: bool) (px: PreXmlDoc) (ats: SynAttributes) - (afterAttributesBeforeHeadPattern: Range option) + (letKeyword: range option) (pref: Context -> Context) (ao: SynAccess option) (isInline: bool) @@ -5153,8 +5110,7 @@ and genSynBindingFunction +> unindent) ctx - genAfterAttributesBefore SynBinding_AfterAttributes_BeforeHeadPattern afterAttributesBeforeHeadPattern - +> expressionFitsOnRestOfLine short long + expressionFitsOnRestOfLine short long let body (ctx: Context) = genExprKeepIndentInBranch astContext e ctx @@ -5167,6 +5123,7 @@ and genSynBindingFunction (genPreXmlDoc px +> genAttrIsFirstChild + +> optSingle (enterNodeFor SynBinding_Let) letKeyword +> leadingExpressionIsMultiline genSignature genExpr) ctx @@ -5176,7 +5133,7 @@ and genSynBindingFunctionWithReturnType (isRecursiveLetOrUseFunction: bool) (px: PreXmlDoc) (ats: SynAttributes) - (afterAttributesBeforeHeadPattern: Range option) + (letKeyword: range option) (pref: Context -> Context) (ao: SynAccess option) (isInline: bool) @@ -5262,8 +5219,7 @@ and genSynBindingFunctionWithReturnType +> unindent) ctx - genAfterAttributesBefore SynBinding_AfterAttributes_BeforeHeadPattern afterAttributesBeforeHeadPattern - +> expressionFitsOnRestOfLine short long + expressionFitsOnRestOfLine short long let body = genExprKeepIndentInBranch astContext e @@ -5275,6 +5231,7 @@ and genSynBindingFunctionWithReturnType (genPreXmlDoc px +> genAttrIsFirstChild + +> optSingle (enterNodeFor SynBinding_Let) letKeyword +> leadingExpressionIsMultiline genSignature genExpr) ctx @@ -5330,7 +5287,7 @@ and genSynBindingValue (isRecursiveLetOrUseFunction: bool) (px: PreXmlDoc) (ats: SynAttributes) - (afterAttributesBeforeHeadPattern: Range option) + (letKeyword: range option) (pref: Context -> Context) (ao: SynAccess option) (isInline: bool) @@ -5378,7 +5335,7 @@ and genSynBindingValue genPreXmlDoc px +> genAttrIsFirstChild - +> genAfterAttributesBefore SynBinding_AfterAttributes_BeforeHeadPattern afterAttributesBeforeHeadPattern + +> optSingle (enterNodeFor SynBinding_Let) letKeyword +> genPref +> (fun ctx -> let prefix = diff --git a/src/Fantomas/SourceParser.fs b/src/Fantomas/SourceParser.fs index 30358671db..d8d6cf60db 100644 --- a/src/Fantomas/SourceParser.fs +++ b/src/Fantomas/SourceParser.fs @@ -271,7 +271,8 @@ let (|Access|) = | SynAccess.Private -> "private" let (|PreXmlDoc|) (px: PreXmlDoc) = - px.ToXmlDoc(false, None).UnprocessedLines + let xmlDoc = px.ToXmlDoc(false, None) + xmlDoc.UnprocessedLines, xmlDoc.Range // Module declarations (11 cases) let (|Open|_|) = @@ -565,7 +566,7 @@ let (|DoBinding|LetBinding|MemberBinding|PropertyBinding|ExplicitCtor|) = MemberBinding(ats, px, ao, isInline, mf, pat, trivia.EqualsRange, expr, synValInfo) | SynBinding (_, SynBindingKind.Do, _, _, ats, px, _, _, _, expr, _, _, trivia) -> DoBinding(ats, px, expr) | SynBinding (ao, _, isInline, isMutable, attrs, px, SynValData (_, valInfo, _), pat, _, expr, _, _, trivia) -> - LetBinding(attrs, px, ao, isInline, isMutable, pat, trivia.EqualsRange, expr, valInfo) + LetBinding(attrs, px, trivia.LetKeyword, ao, isInline, isMutable, pat, trivia.EqualsRange, expr, valInfo) // Expressions (55 cases, lacking to handle 11 cases) @@ -1679,7 +1680,16 @@ let (|FunType|) (t, ValInfo (argTypes, returnType)) = /// Probably we should use lexing information to improve its accuracy let (|Extern|_|) = function - | Let (LetBinding (ats, px, ao, _, _, PatLongIdent (_, s, _, [ _, PatTuple ps ], _), _, TypedExpr (Typed, _, t), _)) -> + | Let (LetBinding (ats, + px, + _, + ao, + _, + _, + PatLongIdent (_, s, _, [ _, PatTuple ps ], _), + _, + TypedExpr (Typed, _, t), + _)) -> let hasDllImportAttr = ats |> List.exists (fun { Attributes = attrs } -> diff --git a/src/Fantomas/TokenParser.fs b/src/Fantomas/TokenParser.fs index e737ef6604..fbd977ac47 100644 --- a/src/Fantomas/TokenParser.fs +++ b/src/Fantomas/TokenParser.fs @@ -702,6 +702,19 @@ let private (|LineComments|_|) (tokens: Token list) = Some(commentTokens, rest) | _ -> None +let private (|TripleSlashLineComment|_|) (tokens: Token list) = + let rec collect (tokens: Token list) (lineNumber: int) : Token list = + match tokens with + | LineCommentToken lc :: rest when (lc.LineNumber = lineNumber) -> collect rest lc.LineNumber + | _ -> tokens + + match tokens with + | LineCommentToken { Content = ("///" | "///<") + LineNumber = ln } :: _ -> + let rest = collect tokens ln + Some(rest) + | _ -> None + let private collectComment (commentTokens: Token list) = commentTokens |> List.groupBy (fun t -> t.LineNumber) @@ -798,6 +811,10 @@ let rec private getTriviaFromTokensThemSelves foundTrivia = match tokens with + // Skip triple slash comments + | TripleSlashLineComment (rest) -> + getTriviaFromTokensThemSelves mkRange lastButOneNonWhiteSpaceToken lastNonWhiteSpaceToken rest foundTrivia + // Skip triple slash comments | LineComments ({ Content = "///" } :: _, rest) -> getTriviaFromTokensThemSelves mkRange lastButOneNonWhiteSpaceToken lastNonWhiteSpaceToken rest foundTrivia diff --git a/src/Fantomas/TriviaTypes.fs b/src/Fantomas/TriviaTypes.fs index bb818080d3..1ff4037eaa 100644 --- a/src/Fantomas/TriviaTypes.fs +++ b/src/Fantomas/TriviaTypes.fs @@ -227,6 +227,7 @@ type FsAstType = | SynBindingKind_Normal | SynBindingKind_Do | SynBinding_AfterAttributes_BeforeHeadPattern + | SynBinding_Let | SynBinding_Equals | SynBindingReturnInfo_ | SynTyparDecls_PostfixList From e57068660a6a31cae1da93c5cd86690c2283c94e Mon Sep 17 00:00:00 2001 From: nojaf Date: Fri, 11 Feb 2022 11:13:06 +0100 Subject: [PATCH 12/16] Introduce SynTypeDefn_Type when there is trivia between xml/attributes and let binding. --- src/Fantomas/AstExtensions.fs | 7 --- src/Fantomas/AstTransformer.fs | 87 ++++++++++++++++------------------ src/Fantomas/CodePrinter.fs | 6 +-- src/Fantomas/SourceParser.fs | 2 +- src/Fantomas/TriviaTypes.fs | 2 +- 5 files changed, 46 insertions(+), 58 deletions(-) diff --git a/src/Fantomas/AstExtensions.fs b/src/Fantomas/AstExtensions.fs index a3216227ef..ded6bc6749 100644 --- a/src/Fantomas/AstExtensions.fs +++ b/src/Fantomas/AstExtensions.fs @@ -22,13 +22,6 @@ let private hasLinesBetweenAttributesAndFirstNode (attributes: SynAttributes) (f else None) -type SynTypeDefn with - member this.AfterAttributesBeforeComponentInfo: Range option = - match this with - | SynTypeDefn(typeInfo = SynComponentInfo(attributes = [])) -> None - | SynTypeDefn(typeInfo = SynComponentInfo (attributes = attrs; range = compRange)) -> - hasLinesBetweenAttributesAndFirstNode attrs compRange - type SynField with member this.AfterAttributesBeforeIdentifier: Range option = match this with diff --git a/src/Fantomas/AstTransformer.fs b/src/Fantomas/AstTransformer.fs index 91bd6858d4..551e676ae7 100644 --- a/src/Fantomas/AstTransformer.fs +++ b/src/Fantomas/AstTransformer.fs @@ -13,6 +13,37 @@ module Helpers = let mkNode (t: FsAstType) (r: range) = TriviaNodeAssigner(t, r) let mkNodeOption (t: FsAstType) (r: range option) : TriviaNodeAssigner list = Option.toList r |> List.map (mkNode t) + // We only need the let/type keyword anchor if there are xml docs or attributes present that have space between itself and the let/type keyword + let mkNodeForKeywordAfterXmlAndAttributes + (t: FsAstType) + (SourceParser.PreXmlDoc (xml, xmlRange)) + (attrs: SynAttributeList list) + (keywordRange: range option) + : TriviaNodeAssigner list = + if Array.isEmpty xml && attrs.IsEmpty then + [] + else + match keywordRange with + | None -> [] + | Some keyword -> + let lastLine = + let lastAttrLine = + match List.tryLast attrs with + | None -> 0 + | Some a -> a.Range.EndLine + + System.Math.Max(xmlRange.EndLine, lastAttrLine) + + if keyword.StartLine > lastLine + 1 then + // In this scenario there is trivia underneath the attributes or xmldoc + // f.ex.: + // [] + // // some comment + // let a = 0 + [ mkNode t keyword ] + else + [] + module private Ast = open Helpers @@ -704,19 +735,20 @@ module private Ast = and visitSynTypeDefn (td: SynTypeDefn) = match td with - | SynTypeDefn (sci, stdr, members, implicitConstructor, range, trivia) -> - let afterAttributesBeforeRepr = - match td.AfterAttributesBeforeComponentInfo with - | None -> [] - | Some r -> - mkNode SynTypeDefn_AfterAttributesBeforeComponentInfo r - |> List.singleton + | SynTypeDefn (SynComponentInfo (xmlDoc = preXmlDoc; attributes = attrs) as sci, + stdr, + members, + implicitConstructor, + range, + trivia) -> + let typeKeyword = + mkNodeForKeywordAfterXmlAndAttributes SynTypeDefn_Type preXmlDoc attrs trivia.TypeKeyword // TODO process implicitConstructor ?? [ yield mkNode SynTypeDefn_ range + yield! typeKeyword yield! mkNodeOption SynTypeDefn_Equals trivia.EqualsRange yield! visitSynComponentInfo sci - yield! afterAttributesBeforeRepr yield! visitSynTypeDefnRepr stdr yield! mkNodeOption SynTypeDefn_With trivia.WithKeyword yield! (members |> List.collect visitSynMemberDefn) ] @@ -834,19 +866,7 @@ module private Ast = and visitSynBinding (binding: SynBinding) : TriviaNodeAssigner list = match binding with - | SynBinding (_, - kind, - _, - _, - attrs, - (SourceParser.PreXmlDoc (xml, xmlRange)), - valData, - headPat, - returnInfo, - expr, - _range, - _, - trivia) -> + | SynBinding (_, kind, _, _, attrs, preXml, valData, headPat, returnInfo, expr, _range, _, trivia) -> let t = match kind with | SynBindingKind.StandaloneExpression -> SynBindingKind_StandaloneExpression @@ -858,31 +878,8 @@ module private Ast = | SynBindingKind.Do -> [] | _ -> visitSynPat headPat - // We only need the let keyword anchor if there are xml docs or attributes present that have space between itself and the let keyword let letNode = - if Array.isEmpty xml && attrs.IsEmpty then - [] - else - match trivia.LetKeyword with - | None -> [] - | Some letKeyword -> - let lastLine = - let lastAttrLine = - match List.tryLast attrs with - | None -> 0 - | Some a -> a.Range.EndLine - - System.Math.Max(xmlRange.EndLine, lastAttrLine) - - if letKeyword.StartLine > lastLine + 1 then - // In this scenario there is trivia underneath the attributes or xmldoc - // f.ex.: - // [] - // // some comment - // let a = 0 - [ mkNode SynBinding_Let letKeyword ] - else - [] + mkNodeForKeywordAfterXmlAndAttributes SynBinding_Let preXml attrs trivia.LetKeyword [ yield mkNode t binding.RangeOfBindingWithRhs yield! visitSynAttributeLists attrs diff --git a/src/Fantomas/CodePrinter.fs b/src/Fantomas/CodePrinter.fs index 5663e10f0b..999e3698fa 100644 --- a/src/Fantomas/CodePrinter.fs +++ b/src/Fantomas/CodePrinter.fs @@ -3525,16 +3525,14 @@ and sepNlnBetweenTypeAndMembers (withKeywordRange: range option) (ms: SynMemberD and genTypeDefn astContext (isFirstTypeDefn: bool) - (TypeDef (ats, px, ao, tds, tcs, equalsRange, tdr, withKeyword, ms, s, preferPostfix) as node) + (TypeDef (ats, px, typeKeyword, ao, tds, tcs, equalsRange, tdr, withKeyword, ms, s, preferPostfix) as node) = let typeName = genPreXmlDoc px +> ifElse isFirstTypeDefn (genAttributes astContext ats - +> genAfterAttributesBefore - SynTypeDefn_AfterAttributesBeforeComponentInfo - node.AfterAttributesBeforeComponentInfo + +> optSingle (enterNodeFor SynTypeDefn_Type) typeKeyword -- "type ") (!- "and " +> genOnelinerAttributes astContext ats) +> opt sepSpace ao genAccess diff --git a/src/Fantomas/SourceParser.fs b/src/Fantomas/SourceParser.fs index d8d6cf60db..9631f83cdf 100644 --- a/src/Fantomas/SourceParser.fs +++ b/src/Fantomas/SourceParser.fs @@ -1472,7 +1472,7 @@ let (|TCSimple|TCDelegate|) = let (|TypeDef|) (SynTypeDefn (SynComponentInfo (ats, tds, tcs, LongIdent s, px, preferPostfix, ao, _), tdr, ms, _, _, trivia)) = - (ats, px, ao, tds, tcs, trivia.EqualsRange, tdr, trivia.WithKeyword, ms, s, preferPostfix) + (ats, px, trivia.TypeKeyword, ao, tds, tcs, trivia.EqualsRange, tdr, trivia.WithKeyword, ms, s, preferPostfix) let (|SigTypeDef|) (SynTypeDefnSig (SynComponentInfo (ats, tds, tcs, LongIdent s, px, preferPostfix, ao, _), diff --git a/src/Fantomas/TriviaTypes.fs b/src/Fantomas/TriviaTypes.fs index 1ff4037eaa..30457bc9f2 100644 --- a/src/Fantomas/TriviaTypes.fs +++ b/src/Fantomas/TriviaTypes.fs @@ -195,7 +195,7 @@ type FsAstType = | SynInterfaceImpl_ | SynInterfaceImpl_With | SynTypeDefn_ - | SynTypeDefn_AfterAttributesBeforeComponentInfo + | SynTypeDefn_Type | SynTypeDefn_Equals | SynTypeDefn_With | SynTypeDefnSig_ From caa46e3553d3a4698a3398135d6377f5faf00c73 Mon Sep 17 00:00:00 2001 From: nojaf Date: Fri, 11 Feb 2022 11:29:26 +0100 Subject: [PATCH 13/16] Introduce SynField_IdentifierAndType when there is trivia between xml/attributes and SynField. --- src/Fantomas/AstExtensions.fs | 7 ------- src/Fantomas/AstTransformer.fs | 25 +++++++++++++------------ src/Fantomas/CodePrinter.fs | 10 +++------- src/Fantomas/SourceParser.fs | 8 ++++++-- src/Fantomas/TriviaTypes.fs | 2 +- 5 files changed, 23 insertions(+), 29 deletions(-) diff --git a/src/Fantomas/AstExtensions.fs b/src/Fantomas/AstExtensions.fs index ded6bc6749..185c90677b 100644 --- a/src/Fantomas/AstExtensions.fs +++ b/src/Fantomas/AstExtensions.fs @@ -22,13 +22,6 @@ let private hasLinesBetweenAttributesAndFirstNode (attributes: SynAttributes) (f else None) -type SynField with - member this.AfterAttributesBeforeIdentifier: Range option = - match this with - | SynField(attributes = []) -> None - | SynField (attributes = _ :: _; idOpt = None) -> None - | SynField (attributes = attrs; idOpt = Some ident) -> hasLinesBetweenAttributesAndFirstNode attrs ident.idRange - type SynModuleDecl with member this.AfterAttributesBeforeNestedModuleName: Range option = match this with diff --git a/src/Fantomas/AstTransformer.fs b/src/Fantomas/AstTransformer.fs index 551e676ae7..e262b21bc4 100644 --- a/src/Fantomas/AstTransformer.fs +++ b/src/Fantomas/AstTransformer.fs @@ -14,16 +14,16 @@ module Helpers = let mkNodeOption (t: FsAstType) (r: range option) : TriviaNodeAssigner list = Option.toList r |> List.map (mkNode t) // We only need the let/type keyword anchor if there are xml docs or attributes present that have space between itself and the let/type keyword - let mkNodeForKeywordAfterXmlAndAttributes + let mkNodeForRangeAfterXmlAndAttributes (t: FsAstType) (SourceParser.PreXmlDoc (xml, xmlRange)) (attrs: SynAttributeList list) - (keywordRange: range option) + (r: range option) : TriviaNodeAssigner list = if Array.isEmpty xml && attrs.IsEmpty then [] else - match keywordRange with + match r with | None -> [] | Some keyword -> let lastLine = @@ -742,7 +742,7 @@ module private Ast = range, trivia) -> let typeKeyword = - mkNodeForKeywordAfterXmlAndAttributes SynTypeDefn_Type preXmlDoc attrs trivia.TypeKeyword + mkNodeForRangeAfterXmlAndAttributes SynTypeDefn_Type preXmlDoc attrs trivia.TypeKeyword // TODO process implicitConstructor ?? [ yield mkNode SynTypeDefn_ range @@ -879,7 +879,7 @@ module private Ast = | _ -> visitSynPat headPat let letNode = - mkNodeForKeywordAfterXmlAndAttributes SynBinding_Let preXml attrs trivia.LetKeyword + mkNodeForRangeAfterXmlAndAttributes SynBinding_Let preXml attrs trivia.LetKeyword [ yield mkNode t binding.RangeOfBindingWithRhs yield! visitSynAttributeLists attrs @@ -1198,17 +1198,18 @@ module private Ast = and visitSynField (sfield: SynField) : TriviaNodeAssigner list = match sfield with - | SynField (attrs, _, _ident, typ, _, _, _, range) -> - let afterAttributesBeforeIdentifier = - match sfield.AfterAttributesBeforeIdentifier with + | SynField (attrs, _, ident, typ, _, preXmlDoc, _, range) -> + let innerNode = + match ident with | None -> [] - | Some r -> - mkNode SynField_AfterAttributesBeforeIdentifier r - |> List.singleton + | Some ident -> + Range.unionRanges ident.idRange typ.Range + |> Some + |> mkNodeForRangeAfterXmlAndAttributes SynField_IdentifierAndType preXmlDoc attrs [ yield mkNode SynField_ range yield! (visitSynAttributeLists attrs) - yield! afterAttributesBeforeIdentifier + yield! innerNode yield! visitSynType typ ] and visitSynType (st: SynType) = diff --git a/src/Fantomas/CodePrinter.fs b/src/Fantomas/CodePrinter.fs index 999e3698fa..bb7ac4a717 100644 --- a/src/Fantomas/CodePrinter.fs +++ b/src/Fantomas/CodePrinter.fs @@ -4193,22 +4193,18 @@ and genEnumCase astContext (EnumCase (ats, barRange, px, identInAST, equalsRange +> genOnelinerAttributes astContext ats +> genCase -and genField astContext prefix (Field (ats, px, ao, isStatic, isMutable, t, so) as node) = - let range = - match node with - | SynField (_, _, _, _, _, _, _, range) -> range +and genField astContext prefix (Field (ats, px, ao, isStatic, isMutable, t, so, innerRange, range)) = // Being protective on union case declaration let t = genType astContext astContext.IsUnionField t genPreXmlDoc px +> genAttributes astContext ats - +> genAfterAttributesBefore SynField_AfterAttributesBeforeIdentifier node.AfterAttributesBeforeIdentifier +> ifElse isStatic (!- "static ") sepNone -- prefix +> ifElse isMutable (!- "mutable ") sepNone +> opt sepSpace ao genAccess - +> opt sepColon so (!-) - +> t + +> (opt sepColon so (!-) +> t + |> optSingle (genTriviaFor SynField_IdentifierAndType) innerRange) |> genTriviaFor SynField_ range and genType astContext outerBracket t = diff --git a/src/Fantomas/SourceParser.fs b/src/Fantomas/SourceParser.fs index 9631f83cdf..2e44027aa3 100644 --- a/src/Fantomas/SourceParser.fs +++ b/src/Fantomas/SourceParser.fs @@ -418,8 +418,12 @@ let (|UnionCaseType|) = | SynUnionCaseKind.Fields fs -> fs | SynUnionCaseKind.FullType _ -> failwith "UnionCaseFullType should be used internally only." -let (|Field|) (SynField (ats, isStatic, ido, t, isMutable, px, ao, _)) = - (ats, px, ao, isStatic, isMutable, t, Option.map (|Ident|) ido) +let (|Field|) (SynField (ats, isStatic, ido, t, isMutable, px, ao, range)) = + let innerRange = + ido + |> Option.map (fun i -> Range.unionRanges i.idRange t.Range) + + (ats, px, ao, isStatic, isMutable, t, Option.map (|Ident|) ido, innerRange, range) let (|EnumCase|) (SynEnumCase (ats, Ident s, c, cr, px, r, trivia)) = (ats, trivia.BarRange, px, s, trivia.EqualsRange, c, cr, r) diff --git a/src/Fantomas/TriviaTypes.fs b/src/Fantomas/TriviaTypes.fs index 30457bc9f2..4bcf6d7ff1 100644 --- a/src/Fantomas/TriviaTypes.fs +++ b/src/Fantomas/TriviaTypes.fs @@ -329,7 +329,7 @@ type FsAstType = | SynEnumCase_Bar | SynEnumCase_Equals | SynField_ - | SynField_AfterAttributesBeforeIdentifier + | SynField_IdentifierAndType | SynType_LongIdent | SynType_App | SynType_App_Less From ffae77ac18de62425b84164abce52d61ec99309b Mon Sep 17 00:00:00 2001 From: nojaf Date: Fri, 11 Feb 2022 13:44:04 +0100 Subject: [PATCH 14/16] Introduce NestedModule_AfterAttributesBeforeModuleName when there is trivia between xml/attributes and nested module. --- src/Fantomas/AstExtensions.fs | 39 -------------------------- src/Fantomas/AstTransformer.fs | 51 ++++++++++++++++++++++------------ src/Fantomas/CodePrinter.fs | 18 +++--------- src/Fantomas/Fantomas.fsproj | 1 - src/Fantomas/SourceParser.fs | 12 +++----- src/Fantomas/TriviaTypes.fs | 4 +-- 6 files changed, 44 insertions(+), 81 deletions(-) delete mode 100644 src/Fantomas/AstExtensions.fs diff --git a/src/Fantomas/AstExtensions.fs b/src/Fantomas/AstExtensions.fs deleted file mode 100644 index 185c90677b..0000000000 --- a/src/Fantomas/AstExtensions.fs +++ /dev/null @@ -1,39 +0,0 @@ -module Fantomas.AstExtensions - -open FSharp.Compiler.Syntax -open FSharp.Compiler.Text -open FSharp.Compiler.Text.Range - -let longIdentFullRange (li: LongIdent) : Range = - match li with - | [] -> range.Zero - | h :: _ -> unionRanges h.idRange (List.last li).idRange - -let private hasLinesBetweenAttributesAndFirstNode (attributes: SynAttributes) (firstNodeRange: Range) : Range option = - let fileName = firstNodeRange.FileName - - List.tryLast attributes - |> Option.bind (fun lastAttribute -> - if lastAttribute.Range.EndLine + 1 < firstNodeRange.StartLine - && firstNodeRange.Start.Column > 0 then - let pos = Position.mkPos firstNodeRange.StartLine 0 - - mkRange fileName pos pos |> Some - else - None) - -type SynModuleDecl with - member this.AfterAttributesBeforeNestedModuleName: Range option = - match this with - | SynModuleDecl.NestedModule(moduleInfo = SynComponentInfo(attributes = [])) -> None - | SynModuleDecl.NestedModule(moduleInfo = SynComponentInfo (attributes = attrs; longId = lid :: _)) -> - hasLinesBetweenAttributesAndFirstNode attrs lid.idRange - | _ -> None - -type SynModuleSigDecl with - member this.AfterAttributesBeforeNestedModuleName: Range option = - match this with - | SynModuleSigDecl.NestedModule(moduleInfo = SynComponentInfo(attributes = [])) -> None - | SynModuleSigDecl.NestedModule(moduleInfo = SynComponentInfo (attributes = attrs; longId = lid :: _)) -> - hasLinesBetweenAttributesAndFirstNode attrs lid.idRange - | _ -> None diff --git a/src/Fantomas/AstTransformer.fs b/src/Fantomas/AstTransformer.fs index e262b21bc4..d7a89bc483 100644 --- a/src/Fantomas/AstTransformer.fs +++ b/src/Fantomas/AstTransformer.fs @@ -3,7 +3,6 @@ module Fantomas.AstTransformer open FSharp.Compiler.Text open FSharp.Compiler.Syntax open Fantomas.TriviaTypes -open Fantomas.AstExtensions open Fantomas.RangePatterns open Fantomas @@ -68,20 +67,27 @@ module private Ast = | SynModuleDecl.ModuleAbbrev (_, _, range) -> [ mkNode SynModuleDecl_ModuleAbbrev range ] |> finalContinuation - | SynModuleDecl.NestedModule (sci, _, equalsRange, decls, _, range) -> + | SynModuleDecl.NestedModule (SynComponentInfo (xmlDoc = preXmlDoc; attributes = attrs) as sci, + _, + decls, + _, + range, + trivia) -> let continuations: ((TriviaNodeAssigner list -> TriviaNodeAssigner list) -> TriviaNodeAssigner list) list = decls |> List.map visit - let finalContinuation (nodes: TriviaNodeAssigner list list) : TriviaNodeAssigner list = - let afterAttributesBeforeNestedModule = - mkNodeOption - SynModuleDecl_NestedModule_AfterAttributesBeforeModuleName - ast.AfterAttributesBeforeNestedModuleName + let moduleNode = + mkNodeForRangeAfterXmlAndAttributes + SynModuleDecl_NestedModule_Module + preXmlDoc + attrs + trivia.ModuleKeyword + let finalContinuation (nodes: TriviaNodeAssigner list list) : TriviaNodeAssigner list = [ mkNode SynModuleDecl_NestedModule range - yield! afterAttributesBeforeNestedModule + yield! moduleNode yield! visitSynComponentInfo sci - yield! mkNodeOption SynModuleDecl_NestedModule_Equals equalsRange + yield! mkNodeOption SynModuleDecl_NestedModule_Equals trivia.EqualsRange yield! (List.collect id nodes) ] |> finalContinuation @@ -1407,20 +1413,26 @@ module private Ast = mkNode SynModuleSigDecl_ModuleAbbrev range |> List.singleton |> finalContinuation - | SynModuleSigDecl.NestedModule (sci, _, equalsRange, decls, range) -> + | SynModuleSigDecl.NestedModule (SynComponentInfo (xmlDoc = preXmlDoc; attributes = attrs) as sci, + _, + decls, + range, + trivia) -> let continuations: ((TriviaNodeAssigner list -> TriviaNodeAssigner list) -> TriviaNodeAssigner list) list = List.map visit decls - let finalContinuation (nodes: TriviaNodeAssigner list list) : TriviaNodeAssigner list = - let afterAttributesBeforeNestedModule = - mkNodeOption - SynModuleSigDecl_NestedModule_AfterAttributesBeforeModuleName - ast.AfterAttributesBeforeNestedModuleName + let moduleKeyword = + mkNodeForRangeAfterXmlAndAttributes + SynModuleSigDecl_NestedModule_Module + preXmlDoc + attrs + trivia.ModuleKeyword + let finalContinuation (nodes: TriviaNodeAssigner list list) : TriviaNodeAssigner list = [ yield mkNode SynModuleSigDecl_NestedModule range - yield! afterAttributesBeforeNestedModule + yield! moduleKeyword yield! visitSynComponentInfo sci - yield! mkNodeOption SynModuleSigDecl_NestedModule_Equals equalsRange + yield! mkNodeOption SynModuleSigDecl_NestedModule_Equals trivia.EqualsRange yield! (List.collect id nodes) ] |> finalContinuation @@ -1470,6 +1482,11 @@ module private Ast = and visitLongIdentIncludingFullRange (li: LongIdent) : TriviaNodeAssigner list = // LongIdent is a bit of an artificial AST node // meant to be used as namespace or module identifier + let longIdentFullRange (li: LongIdent) : Range = + match li with + | [] -> range.Zero + | h :: _ -> Range.unionRanges h.idRange (List.last li).idRange + mkNode LongIdent_ (longIdentFullRange li) :: List.map visitIdent li diff --git a/src/Fantomas/CodePrinter.fs b/src/Fantomas/CodePrinter.fs index bb7ac4a717..a601ef6e3a 100644 --- a/src/Fantomas/CodePrinter.fs +++ b/src/Fantomas/CodePrinter.fs @@ -12,7 +12,6 @@ open Fantomas.SourceTransformer open Fantomas.Context open Fantomas.TriviaTypes open Fantomas.TriviaContext -open Fantomas.AstExtensions /// This type consists of contextual information which is important for formatting /// Please avoid using this record as it can be the cause of unexpected behavior when used incorrectly @@ -351,13 +350,10 @@ and genModuleDecl astContext (node: SynModuleDecl) = | ModuleAbbrev (s1, s2) -> !- "module " -- s1 +> sepEq +> sepSpace -- s2 | NamespaceFragment m -> failwithf "NamespaceFragment hasn't been implemented yet: %O" m - | NestedModule (ats, px, ao, s, isRecursive, equalsRange, mds) -> + | NestedModule (ats, px, moduleKeyword, ao, s, isRecursive, equalsRange, mds) -> genPreXmlDoc px +> genAttributes astContext ats - +> genAfterAttributesBefore - SynModuleDecl_NestedModule_AfterAttributesBeforeModuleName - node.AfterAttributesBeforeNestedModuleName - +> (!- "module ") + +> genTriviaForOption SynModuleDecl_NestedModule_Module moduleKeyword (!- "module ") +> opt sepSpace ao genAccess +> ifElse isRecursive (!- "rec ") sepNone -- s @@ -392,13 +388,10 @@ and genSigModuleDecl astContext node = | SigVal v -> genVal astContext v | SigModuleAbbrev (s1, s2) -> !- "module " -- s1 +> sepEq +> sepSpace -- s2 | SigNamespaceFragment m -> failwithf "NamespaceFragment is not supported yet: %O" m - | SigNestedModule (ats, px, ao, s, equalsRange, mds) -> + | SigNestedModule (ats, px, moduleKeyword, ao, s, equalsRange, mds) -> genPreXmlDoc px +> genAttributes astContext ats - +> genAfterAttributesBefore - SynModuleSigDecl_NestedModule_AfterAttributesBeforeModuleName - node.AfterAttributesBeforeNestedModuleName - -- "module " + +> genTriviaForOption SynModuleSigDecl_NestedModule_Module moduleKeyword !- "module " +> opt sepSpace ao genAccess -- s +> genEq SynModuleSigDecl_NestedModule_Equals equalsRange @@ -5365,9 +5358,6 @@ and genParenTupleWithIndentAndNewlines +> genTriviaFor SynPat_Paren_ClosingParenthesis rpr sepCloseT |> genTriviaFor SynPat_Paren pr -and genAfterAttributesBefore (astType: FsAstType) (r: Range option) : Context -> Context = - optSingle (fun r -> genTriviaFor astType r id) r - and collectMultilineItemForSynExprKeepIndent (astContext: ASTContext) (e: SynExpr) : ColMultilineItem list = match e with | LetOrUses (bs, e) -> diff --git a/src/Fantomas/Fantomas.fsproj b/src/Fantomas/Fantomas.fsproj index 7ea0b548a0..35cf2979b5 100644 --- a/src/Fantomas/Fantomas.fsproj +++ b/src/Fantomas/Fantomas.fsproj @@ -12,7 +12,6 @@ - diff --git a/src/Fantomas/SourceParser.fs b/src/Fantomas/SourceParser.fs index 2e44027aa3..1ae8e8c4ac 100644 --- a/src/Fantomas/SourceParser.fs +++ b/src/Fantomas/SourceParser.fs @@ -328,12 +328,8 @@ let (|Types|_|) = let (|NestedModule|_|) = function - | SynModuleDecl.NestedModule (SynComponentInfo (ats, _, _, LongIdent s, px, _, ao, _), - isRecursive, - equalsRange, - xs, - _, - _) -> Some(ats, px, ao, s, isRecursive, equalsRange, xs) + | SynModuleDecl.NestedModule (SynComponentInfo (ats, _, _, LongIdent s, px, _, ao, _), isRecursive, xs, _, _, trivia) -> + Some(ats, px, trivia.ModuleKeyword, ao, s, isRecursive, trivia.EqualsRange, xs) | _ -> None let (|Exception|_|) = @@ -380,8 +376,8 @@ let (|SigTypes|_|) = let (|SigNestedModule|_|) = function - | SynModuleSigDecl.NestedModule (SynComponentInfo (ats, _, _, LongIdent s, px, _, ao, _), _, equalsRange, xs, _) -> - Some(ats, px, ao, s, equalsRange, xs) + | SynModuleSigDecl.NestedModule (SynComponentInfo (ats, _, _, LongIdent s, px, _, ao, _), _, xs, _, trivia) -> + Some(ats, px, trivia.ModuleKeyword, ao, s, trivia.EqualsRange, xs) | _ -> None let (|SigException|_|) = diff --git a/src/Fantomas/TriviaTypes.fs b/src/Fantomas/TriviaTypes.fs index 4bcf6d7ff1..4a97798401 100644 --- a/src/Fantomas/TriviaTypes.fs +++ b/src/Fantomas/TriviaTypes.fs @@ -55,7 +55,7 @@ type FsAstType = // | SynModuleOrNamespace_NamedModule | SynModuleDecl_ModuleAbbrev | SynModuleDecl_NestedModule - | SynModuleDecl_NestedModule_AfterAttributesBeforeModuleName + | SynModuleDecl_NestedModule_Module | SynModuleDecl_NestedModule_Equals | SynModuleDecl_Let | SynModuleDecl_DoExpr @@ -370,7 +370,7 @@ type FsAstType = | SynModuleOrNamespaceSig_NamedModule | SynModuleSigDecl_ModuleAbbrev | SynModuleSigDecl_NestedModule - | SynModuleSigDecl_NestedModule_AfterAttributesBeforeModuleName + | SynModuleSigDecl_NestedModule_Module | SynModuleSigDecl_NestedModule_Equals | SynModuleSigDecl_Types | SynModuleSigDecl_Open From d874e3edddcb3af41bf2b6cf7e1a663c1689e662 Mon Sep 17 00:00:00 2001 From: nojaf Date: Fri, 4 Mar 2022 10:52:11 +0100 Subject: [PATCH 15/16] Process SynExpr.DebugPoint changes. --- src/Fantomas/AstTransformer.fs | 5 +++-- src/Fantomas/CodeFormatterImpl.fs | 3 ++- src/Fantomas/CodePrinter.fs | 3 +++ src/Fantomas/SourceParser.fs | 10 +++++----- src/Fantomas/SourceTransformer.fs | 1 + 5 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/Fantomas/AstTransformer.fs b/src/Fantomas/AstTransformer.fs index d7a89bc483..c2bcfdb140 100644 --- a/src/Fantomas/AstTransformer.fs +++ b/src/Fantomas/AstTransformer.fs @@ -220,7 +220,7 @@ module private Ast = |> finalContinuation Continuation.sequence continuations finalContinuation - | SynExpr.For (_, _, equalsRange, identBody, _, toBody, doBody, range) -> + | SynExpr.For (_, _, _, equalsRange, identBody, _, toBody, doBody, range) -> let continuations: ((TriviaNodeAssigner list -> TriviaNodeAssigner list) -> TriviaNodeAssigner list) list = [ visit identBody visit toBody @@ -233,7 +233,7 @@ module private Ast = |> finalContinuation Continuation.sequence continuations finalContinuation - | SynExpr.ForEach (_, SeqExprOnly _, _, pat, enumExpr, bodyExpr, range) -> + | SynExpr.ForEach (_, _, SeqExprOnly _, _, pat, enumExpr, bodyExpr, range) -> let continuations: ((TriviaNodeAssigner list -> TriviaNodeAssigner list) -> TriviaNodeAssigner list) list = [ visit enumExpr; visit bodyExpr ] @@ -667,6 +667,7 @@ module private Ast = | SynExpr.IndexFromEnd (e, range) -> [ yield mkNode SynExpr_IndexFromEnd range yield! visitSynExpr e ] + | SynExpr.DebugPoint _ -> [] visit synExpr id diff --git a/src/Fantomas/CodeFormatterImpl.fs b/src/Fantomas/CodeFormatterImpl.fs index 255f4cca65..28d8f0ae9f 100644 --- a/src/Fantomas/CodeFormatterImpl.fs +++ b/src/Fantomas/CodeFormatterImpl.fs @@ -170,7 +170,7 @@ let isValidAST ast = | SynExpr.While (_sequencePointInfoForWhileLoop, synExpr1, synExpr2, _range) -> List.forall validateExpr [ synExpr1; synExpr2 ] - | SynExpr.ForEach (_sequencePointInfoForForLoop, _seqExprOnly, _isFromSource, synPat, synExpr1, synExpr2, _range) -> + | SynExpr.ForEach (pat = synPat; enumExpr = synExpr1; bodyExpr = synExpr2) -> List.forall validateExpr [ synExpr1; synExpr2 ] && validatePattern synPat @@ -280,6 +280,7 @@ let isValidAST ast = defaultArg (Option.map validateExpr e1) true && defaultArg (Option.map validateExpr e2) true | SynExpr.IndexFromEnd (e, _) -> validateExpr e + | SynExpr.DebugPoint (innerExpr = e) -> validateExpr e and validatePattern = function diff --git a/src/Fantomas/CodePrinter.fs b/src/Fantomas/CodePrinter.fs index a601ef6e3a..319aef4372 100644 --- a/src/Fantomas/CodePrinter.fs +++ b/src/Fantomas/CodePrinter.fs @@ -2708,6 +2708,9 @@ and genExpr astContext synExpr ctx = id | SynExpr.Typed _ -> // child nodes contain trivia + id + | SynExpr.DebugPoint _ -> + // I don't believe the parser will ever return this node id) expr ctx diff --git a/src/Fantomas/SourceParser.fs b/src/Fantomas/SourceParser.fs index 1ae8e8c4ac..412d1c553c 100644 --- a/src/Fantomas/SourceParser.fs +++ b/src/Fantomas/SourceParser.fs @@ -144,7 +144,7 @@ let (|OpNameFullInPattern|) (x: Identifier) = || IsPrefixOperator s || IsTernaryOperator s || s = "op_Dynamic" then - /// Use two spaces for symmetry + // Use two spaces for symmetry if String.startsWithOrdinal "*" s' && s' <> "*" then sprintf "( %s )" s' else @@ -168,7 +168,7 @@ let (|OpNameFull|) (x: Identifier) = || IsPrefixOperator s || IsTernaryOperator s || s = "op_Dynamic" then - /// Use two spaces for symmetry + // Use two spaces for symmetry if String.startsWithOrdinal "*" s' && s' <> "*" then sprintf " %s " s' else @@ -644,7 +644,7 @@ let (|While|_|) = let (|For|_|) = function - | SynExpr.For (_, Ident s, equalsRange, e1, isUp, e2, e3, _) -> Some(s, equalsRange, e1, e2, e3, isUp) + | SynExpr.For (_, _, Ident s, equalsRange, e1, isUp, e2, e3, _) -> Some(s, equalsRange, e1, e2, e3, isUp) | _ -> None let (|NullExpr|_|) = @@ -1040,8 +1040,8 @@ let rec (|CompExprBody|_|) expr = let (|ForEach|_|) = function - | SynExpr.ForEach (_, SeqExprOnly true, _, pat, e1, SingleExpr (Yield _, e2), _) -> Some(pat, e1, e2, true) - | SynExpr.ForEach (_, SeqExprOnly isArrow, _, pat, e1, e2, _) -> Some(pat, e1, e2, isArrow) + | SynExpr.ForEach (_, _, SeqExprOnly true, _, pat, e1, SingleExpr (Yield _, e2), _) -> Some(pat, e1, e2, true) + | SynExpr.ForEach (_, _, SeqExprOnly isArrow, _, pat, e1, e2, _) -> Some(pat, e1, e2, isArrow) | _ -> None let (|DotIndexedSet|_|) = diff --git a/src/Fantomas/SourceTransformer.fs b/src/Fantomas/SourceTransformer.fs index 36b65f40c6..f42c38d0f0 100644 --- a/src/Fantomas/SourceTransformer.fs +++ b/src/Fantomas/SourceTransformer.fs @@ -273,6 +273,7 @@ let rec synExprToFsAstType (expr: SynExpr) : FsAstType * Range = | SynExpr.Sequential (_, _, e, _, _) -> synExprToFsAstType e | SynExpr.IndexRange _ -> SynExpr_IndexRange, expr.Range | SynExpr.IndexFromEnd _ -> SynExpr_IndexFromEnd, expr.Range + | SynExpr.DebugPoint (innerExpr = e) -> synExprToFsAstType e let synModuleSigDeclToFsAstType = function From fac554e857ed60ab6f352073ddd8e8aa9faa3b02 Mon Sep 17 00:00:00 2001 From: nojaf Date: Fri, 4 Mar 2022 11:00:31 +0100 Subject: [PATCH 16/16] Add changelog information. --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 74b9568d89..f75ab699c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [Unreleased] + +### Changed +* Always add a space for multiple curried args invocation. [#2087](https://github.com/fsprojects/fantomas/issues/2087) +* Update FCS to 41.0.3 + ## [4.6.6] - 2022-03-04 ### Changed