<commit_before>﻿module internal Fantomas.CodePrinter

open System.Collections.Generic
open Fantomas.FormatConfig
open Fantomas.SourceParser
open Fantomas.SourceTransformer

let sortAndDedup by l =
    l |> Seq.distinctBy by |> Seq.sortBy by |> List.ofSeq

let rec genParsedInput = function
    | ImplFile im -> genImpFile im
    | SigFile si -> genSigFile si

and genImpFile(ParsedImplFileInput(hs, mns)) = 
    col sepNln hs genParsedHashDirective
    +> col sepNln mns genModuleOrNamespace

and genSigFile(ParsedSigFileInput(hs, mns)) =
    col sepNln hs genParsedHashDirective
    +> col sepNln mns genSigModuleOrNamespace

and genParsedHashDirective(ParsedHashDirective(s1, s2)) =
    // print strings with quotes
    !- "#" -- s1 +> sepSpace +> ifElse (s2 = "") sepNone (!- (sprintf "\"%O\"" s2))

and genModuleOrNamespace(ModuleOrNamespace(ats, px, ao, s, mds, isModule)) =
    genPreXmlDoc px
    +> colPost sepNln sepNln ats genAttribute
    // Checking for Tmp is a bit fragile
    +> ifElse (s = "Tmp") sepNone (ifElse isModule (!- "module ") (!- "namespace ")
            +> opt sepSpace ao genAccess +> ifElse (s = "") (!- "global") (!- s) +> rep 2 sepNln)
    +> genModuleDeclList mds

and genSigModuleOrNamespace(SigModuleOrNamespace(ats, px, ao, s, mds, isModule)) =
    genPreXmlDoc px
    +> colPost sepNln sepNln ats genAttribute
    +> ifElse (s = "Tmp") sepNone (ifElse isModule (!- "module ") (!- "namespace ")
    +> opt sepSpace ao genAccess -- s +> rep 2 sepNln)
    +> genSigModuleDeclList mds

and genModuleDeclList = function
    | [x] -> genModuleDecl x

    | DoExprAttributesL(xs, ys) 
    | HashDirectiveL(xs, ys) 
    | ModuleAbbrevL(xs, ys) 
    | OpenL(xs, ys) 
    | OneLinerLetL(xs, ys) ->
        let xs = xs |> sortAndDedup ((|Open|_|) >> Option.get)
        match ys with
        | [] -> col sepNln xs genModuleDecl
        | _ -> col sepNln xs genModuleDecl +> rep 2 sepNln +> genModuleDeclList ys

    | MultilineModuleDeclL(xs, ys) ->
        match ys with
        | [] -> col (rep 2 sepNln) xs genModuleDecl
        | _ -> col (rep 2 sepNln) xs genModuleDecl +> rep 2 sepNln +> genModuleDeclList ys
    | _ -> sepNone    

and genModuleDecl = function
    | Attributes(ats) ->
        col sepNln ats genAttribute
    | DoExpr(e) ->
        genExpr e
    | Exception(ex) ->
        genException ex
    | HashDirective(p) -> 
        genParsedHashDirective p
    // Add a new line after module-level let bindings
    | Let(b) ->
        genLetBinding true "let " b
    | LetRec(b::bs) -> 
        genLetBinding true "let rec " b 
        +> colPre (rep 2 sepNln) (rep 2 sepNln) bs (genLetBinding false "and ")

    | ModuleAbbrev(s1, s2) ->
        !- "module " -- s1 +> sepEq -- s2
    | NamespaceFragment(m) ->
        failwithf "NamespaceFragment hasn't been implemented yet: %O" m
    | NestedModule(ats, px, ao, s, mds) -> 
        genPreXmlDoc px
        +> colPost sepNln sepNln ats genAttribute -- "module " +> opt sepSpace ao genAccess -- s +> sepEq
        +> indent +> sepNln +> genModuleDeclList mds +> unindent

    | Open(s) ->
        !- (sprintf "open %s" s)
    // There is no nested types and they are recursive if there are more than one definition
    | Types(t::ts) ->
        genTypeDefn true t +> colPre (rep 2 sepNln) (rep 2 sepNln) ts (genTypeDefn false)
    | md ->
        failwithf "Unexpected module declaration: %O" md

and genSigModuleDeclList = function
    | [x] -> genSigModuleDecl x

    | SigOpenL(xs, ys) ->
        let xs = xs |> sortAndDedup ((|SigOpen|_|) >> Option.get)
        match ys with
        | [] -> col sepNln xs genSigModuleDecl
        | _ -> col sepNln xs genSigModuleDecl +> rep 2 sepNln +> genSigModuleDeclList ys

    | xs -> col sepNln xs genSigModuleDecl

and genSigModuleDecl = function
    | SigException(ex) ->
        genSigException ex
    | SigHashDirective(p) -> 
        genParsedHashDirective p
    | SigVal(v) ->
        genVal v
    | SigModuleAbbrev(s1, s2) ->
        !- "module " -- s1 +> sepEq -- s2
    | SigNamespaceFragment(m) ->
        failwithf "NamespaceFragment is not supported yet: %O" m
    | SigNestedModule(ats, px, ao, s, mds) -> 
        genPreXmlDoc px
        +> colPost sepNln sepNln ats genAttribute -- "module " +> opt sepSpace ao genAccess -- s +> sepEq
        +> indent +> sepNln +> genSigModuleDeclList mds +> unindent

    | SigOpen(s) ->
        !- (sprintf "open %s" s)
    | SigTypes(t::ts) ->
        genSigTypeDefn true t +> colPre (rep 2 sepNln) (rep 2 sepNln) ts (genSigTypeDefn false)
    | md -><commit_msg>Sort open declarations<commit_after>﻿module internal Fantomas.CodePrinter

open System.Collections.Generic
open Fantomas.FormatConfig
open Fantomas.SourceParser
open Fantomas.SourceTransformer

let sortAndDedup by l =
    l |> Seq.distinctBy by |> Seq.sortBy by |> List.ofSeq

let rec genParsedInput = function
    | ImplFile im -> genImpFile im
    | SigFile si -> genSigFile si

and genImpFile(ParsedImplFileInput(hs, mns)) = 
    col sepNln hs genParsedHashDirective
    +> col sepNln mns genModuleOrNamespace

and genSigFile(ParsedSigFileInput(hs, mns)) =
    col sepNln hs genParsedHashDirective
    +> col sepNln mns genSigModuleOrNamespace

and genParsedHashDirective(ParsedHashDirective(s1, s2)) =
    // print strings with quotes
    !- "#" -- s1 +> sepSpace +> ifElse (s2 = "") sepNone (!- (sprintf "\"%O\"" s2))

and genModuleOrNamespace(ModuleOrNamespace(ats, px, ao, s, mds, isModule)) =
    genPreXmlDoc px
    +> colPost sepNln sepNln ats genAttribute
    // Checking for Tmp is a bit fragile
    +> ifElse (s = "Tmp") sepNone (ifElse isModule (!- "module ") (!- "namespace ")
            +> opt sepSpace ao genAccess +> ifElse (s = "") (!- "global") (!- s) +> rep 2 sepNln)
    +> genModuleDeclList mds

and genSigModuleOrNamespace(SigModuleOrNamespace(ats, px, ao, s, mds, isModule)) =
    genPreXmlDoc px
    +> colPost sepNln sepNln ats genAttribute
    +> ifElse (s = "Tmp") sepNone (ifElse isModule (!- "module ") (!- "namespace ")
    +> opt sepSpace ao genAccess -- s +> rep 2 sepNln)
    +> genSigModuleDeclList mds

and genModuleDeclList = function
    | [x] -> genModuleDecl x

    | DoExprAttributesL(xs, ys) 
    | HashDirectiveL(xs, ys) 
    | ModuleAbbrevL(xs, ys) 
    | OpenL(xs, ys) 
    | OneLinerLetL(xs, ys) ->
        let xs = xs |> sortAndDedup ((|Open|_|) >> Option.get)
        match ys with
        | [] -> col sepNln xs genModuleDecl
        | _ -> col sepNln xs genModuleDecl +> rep 2 sepNln +> genModuleDeclList ys

    | MultilineModuleDeclL(xs, ys) ->
        match ys with
        | [] -> col (rep 2 sepNln) xs genModuleDecl
        | _ -> col (rep 2 sepNln) xs genModuleDecl +> rep 2 sepNln +> genModuleDeclList ys
    | _ -> sepNone    

and genModuleDecl = function
    | Attributes(ats) ->
        col sepNln ats genAttribute
    | DoExpr(e) ->
        genExpr e
    | Exception(ex) ->
        genException ex
    | HashDirective(p) -> 
        genParsedHashDirective p
    // Add a new line after module-level let bindings
    | Let(b) ->
        genLetBinding true "let " b
    | LetRec(b::bs) -> 
        genLetBinding true "let rec " b 
        +> colPre (rep 2 sepNln) (rep 2 sepNln) bs (genLetBinding false "and ")

    | ModuleAbbrev(s1, s2) ->
        !- "module " -- s1 +> sepEq -- s2
    | NamespaceFragment(m) ->
        failwithf "NamespaceFragment hasn't been implemented yet: %O" m
    | NestedModule(ats, px, ao, s, mds) -> 
        genPreXmlDoc px
        +> colPost sepNln sepNln ats genAttribute -- "module " +> opt sepSpace ao genAccess -- s +> sepEq
        +> indent +> sepNln +> genModuleDeclList mds +> unindent

    | Open(s) ->
        !- (sprintf "open %s" s)
    // There is no nested types and they are recursive if there are more than one definition
    | Types(t::ts) ->
        genTypeDefn true t +> colPre (rep 2 sepNln) (rep 2 sepNln) ts (genTypeDefn false)
    | md ->
        failwithf "Unexpected module declaration: %O" md

and genSigModuleDeclList = function
    | [x] -> genSigModuleDecl x

    | SigHashDirectiveL(xs, ys) 
    | SigModuleAbbrevL(xs, ys) 
    | SigOpenL(xs, ys) ->
        let xs = xs |> sortAndDedup ((|SigOpen|_|) >> Option.get)
        match ys with
        | [] -> col sepNln xs genSigModuleDecl
        | _ -> col sepNln xs genSigModuleDecl +> rep 2 sepNln +> genSigModuleDeclList ys

    | SigMultilineModuleDeclL(xs, ys) ->
        match ys with
        | [] -> col (rep 2 sepNln) xs genSigModuleDecl
        | _ -> col (rep 2 sepNln) xs genSigModuleDecl +> rep 2 sepNln +> genSigModuleDeclList ys

    | _ -> sepNone

and genSigModuleDecl = function
    | SigException(ex) ->
        genSigException ex
    | SigHashDirective(p) -> 
        genParsedHashDirective p
    | SigVal(v) ->
        genVal v
    | SigModuleAbbrev(s1, s2) ->
        !- "module " -- s1 +> sepEq -- s2
    | SigNamespaceFragment(m) ->
        failwithf "NamespaceFragment is not supported yet: %O" m
    | SigNestedModule(ats, px, ao, s, mds) -> 
        genPreXmlDoc px
        +> colPost sepNln sepNln ats genAttribute -- "module " +> opt sepSpace ao genAccess -- s +> sepEq
        +> indent +> sepNln +> genSigModuleDeclList mds +> unindent

    | SigOpen(s) ->
        !- (sprintf "open %s" s)
    | SigTypes(t::ts) ->
        genSigTypeDefn true t +> colPre (rep 2 sepNln) (rep 2 sepNln) ts (genSigTypeDefn false)
    | md ->
{'fraction_non_alphanumeric': 0.11796075085324233, 'fraction_numerical': 0.005866040955631399, 'mean_word_length': 2.6037663335895465, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 178, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3598410', 'n_tokens_mistral': 3349, 'n_tokens_neox': 3229, 'n_words': 902}