mirror of
https://github.com/Smaug123/WoofWare.Whippet
synced 2025-10-05 15:58:39 +00:00
Some checks are pending
.NET / build (Debug) (push) Waiting to run
.NET / build (Release) (push) Waiting to run
.NET / analyzers (push) Waiting to run
.NET / check-dotnet-format (push) Waiting to run
.NET / check-nix-format (push) Waiting to run
.NET / Check links (push) Waiting to run
.NET / Check flake (push) Waiting to run
.NET / nuget-pack (push) Waiting to run
.NET / expected-pack (push) Blocked by required conditions
.NET / check-accurate-generations (push) Waiting to run
.NET / all-required-checks-complete (push) Blocked by required conditions
.NET / nuget-publish (push) Blocked by required conditions
.NET / nuget-publish-fantomas (push) Blocked by required conditions
.NET / nuget-publish-json-plugin (push) Blocked by required conditions
.NET / nuget-publish-json-attrs (push) Blocked by required conditions
.NET / nuget-publish-argparser-plugin (push) Blocked by required conditions
.NET / nuget-publish-argparser-attrs (push) Blocked by required conditions
127 lines
5.1 KiB
Forth
127 lines
5.1 KiB
Forth
namespace WoofWare.Whippet.Fantomas
|
|
|
|
open Fantomas.Core
|
|
open Fantomas.FCS.Syntax
|
|
open Fantomas.FCS.SyntaxTrivia
|
|
|
|
/// Helper methods to convert between source code and FCS ASTs.
|
|
[<RequireQualifiedAccess>]
|
|
module Ast =
|
|
|
|
/// Given the contents of an F# source file, parse it into an AST. This is sync-over-async internally, which is
|
|
/// naughty.
|
|
let parse (fileContents : string) : ParsedInput =
|
|
CodeFormatter.ParseAsync (false, fileContents)
|
|
|> Async.RunSynchronously
|
|
|> Array.head
|
|
|> fst
|
|
|
|
/// Concatenate the input modules/namespaces and render them as a single F# source file.
|
|
///
|
|
/// This can return `None`, if the input was empty.
|
|
/// This is sync-over-async internally, which is naughty.
|
|
let render (contents : SynModuleOrNamespace list) : string option =
|
|
if contents.IsEmpty then
|
|
None
|
|
else
|
|
|
|
let parseTree =
|
|
ParsedInput.ImplFile (
|
|
ParsedImplFileInput.ParsedImplFileInput (
|
|
"file.fs",
|
|
false,
|
|
QualifiedNameOfFile.QualifiedNameOfFile (Ident.create "file"),
|
|
[],
|
|
[],
|
|
contents,
|
|
(false, false),
|
|
{
|
|
ParsedImplFileInputTrivia.CodeComments = []
|
|
ConditionalDirectives = []
|
|
},
|
|
Set.empty
|
|
)
|
|
)
|
|
|
|
let cfg = FormatConfig.Default
|
|
|
|
let output = CodeFormatter.FormatASTAsync (parseTree, cfg) |> Async.RunSynchronously
|
|
Some output
|
|
|
|
/// For each namespace in the AST, returns the types defined therein.
|
|
let getTypes (ast : ParsedInput) : (LongIdent * SynTypeDefn list) list =
|
|
match ast with
|
|
| ParsedInput.SigFile psfi -> failwith "Signature files not supported"
|
|
| ParsedInput.ImplFile pifi ->
|
|
pifi.Contents
|
|
|> List.collect (fun (SynModuleOrNamespace.SynModuleOrNamespace (ns, _, _, decls, _, _, _, _, _)) ->
|
|
decls
|
|
|> List.collect (fun decl ->
|
|
match decl with
|
|
| SynModuleDecl.Types (defns, _) -> defns |> List.map (fun defn -> ns, defn)
|
|
| _ -> []
|
|
)
|
|
)
|
|
|> List.map (fun (li, ty) -> (li |> List.map _.idText), (ty, li))
|
|
|> List.groupBy fst
|
|
|> List.map (fun (_name, data) ->
|
|
let ns = snd (snd data.[0])
|
|
let data = data |> List.map (fun (_, (ty, _)) -> ty)
|
|
ns, data
|
|
)
|
|
|
|
/// For each namespace in the AST, returns the records contained therein.
|
|
let getRecords (ast : ParsedInput) : (LongIdent * RecordType list) list =
|
|
match ast with
|
|
| ParsedInput.SigFile psfi ->
|
|
psfi.Contents
|
|
|> List.collect (fun (SynModuleOrNamespaceSig.SynModuleOrNamespaceSig (ns, _, _, decls, _, _, _, _, _)) ->
|
|
decls
|
|
|> List.collect (fun decl ->
|
|
match decl with
|
|
| SynModuleSigDecl.Types (defns, _) ->
|
|
defns
|
|
|> List.choose (fun defn ->
|
|
match defn with
|
|
| SynTypeDefnSig.SynTypeDefnSig (sci, typeRepr, members, _, _) ->
|
|
match typeRepr with
|
|
| SynTypeDefnSigRepr.Simple (SynTypeDefnSimpleRepr.Record (access, fields, _), _) ->
|
|
(ns,
|
|
RecordType.OfRecord
|
|
sci
|
|
(failwith "Signature files not yet supported")
|
|
access
|
|
fields)
|
|
|> Some
|
|
| _ -> None
|
|
)
|
|
| _ -> []
|
|
)
|
|
)
|
|
| ParsedInput.ImplFile pifi ->
|
|
pifi.Contents
|
|
|> List.collect (fun (SynModuleOrNamespace.SynModuleOrNamespace (ns, _, _, decls, _, _, _, _, _)) ->
|
|
decls
|
|
|> List.collect (fun decl ->
|
|
match decl with
|
|
| SynModuleDecl.Types (defns, _) ->
|
|
defns
|
|
|> List.choose (fun defn ->
|
|
match defn with
|
|
| SynTypeDefn.SynTypeDefn (sci, typeRepr, smd, _, _, _) ->
|
|
match typeRepr with
|
|
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Record (access, fields, _), _) ->
|
|
(ns, RecordType.OfRecord sci smd access fields) |> Some
|
|
| _ -> None
|
|
)
|
|
| _ -> []
|
|
)
|
|
)
|
|
|> List.map (fun (li, ty) -> (li |> List.map _.idText), (ty, li))
|
|
|> List.groupBy fst
|
|
|> List.map (fun (_name, data) ->
|
|
let ns = snd (snd data.[0])
|
|
let data = data |> List.map (fun (_, (ty, _)) -> ty)
|
|
ns, data
|
|
)
|